diff options
Diffstat (limited to 'core')
88 files changed, 2343 insertions, 1698 deletions
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index 607e17eae4..cb82dc7f8f 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -35,7 +35,8 @@ #include "core/io/file_access_encrypted.h" #include "core/io/json.h" #include "core/io/marshalls.h" -#include "core/math/geometry.h" +#include "core/math/geometry_2d.h" +#include "core/math/geometry_3d.h" #include "core/os/keyboard.h" #include "core/os/os.h" #include "core/project_settings.h" @@ -117,7 +118,7 @@ PackedStringArray _ResourceLoader::get_dependencies(const String &p_path) { } return ret; -}; +} bool _ResourceLoader::has_cached(const String &p_path) { String local_path = ProjectSettings::get_singleton()->localize_path(p_path); @@ -224,7 +225,7 @@ Error _OS::shell_open(String p_uri) { WARN_PRINT("Attempting to open an URL with the \"user://\" protocol. Use `ProjectSettings.globalize_path()` to convert a Godot-specific path to a system path before opening it with `OS.shell_open()`."); } return OS::get_singleton()->shell_open(p_uri); -}; +} int _OS::execute(const String &p_path, const Vector<String> &p_arguments, bool p_blocking, Array p_output, bool p_read_stderr) { OS::ProcessID pid = -2; @@ -252,7 +253,7 @@ Error _OS::kill(int p_pid) { int _OS::get_process_id() const { return OS::get_singleton()->get_process_id(); -}; +} bool _OS::has_environment(const String &p_var) const { return OS::get_singleton()->has_environment(p_var); @@ -286,7 +287,7 @@ String _OS::get_model_name() const { Error _OS::set_thread_name(const String &p_name) { return Thread::set_name(p_name); -}; +} bool _OS::has_feature(const String &p_feature) const { return OS::get_singleton()->has_feature(p_feature); @@ -453,7 +454,7 @@ Dictionary _OS::get_datetime_from_unix_time(int64_t unix_time_val) const { } else { dayno = (unix_time_val - SECS_DAY + 1) / SECS_DAY; dayclock = unix_time_val - dayno * SECS_DAY; - date.weekday = static_cast<OS::Weekday>((dayno - 3) % 7 + 7); + date.weekday = static_cast<OS::Weekday>(((dayno % 7) + 11) % 7); do { year--; dayno += YEARSIZE(year); @@ -497,18 +498,10 @@ Dictionary _OS::get_time_zone_info() const { return infod; } -uint64_t _OS::get_unix_time() const { +double _OS::get_unix_time() const { return OS::get_singleton()->get_unix_time(); } -uint64_t _OS::get_system_time_secs() const { - return OS::get_singleton()->get_system_time_secs(); -} - -uint64_t _OS::get_system_time_msecs() const { - return OS::get_singleton()->get_system_time_msecs(); -} - void _OS::delay_usec(uint32_t p_usec) const { OS::get_singleton()->delay_usec(p_usec); } @@ -620,7 +613,7 @@ void _OS::print_resources_by_type(const Vector<String> &p_types) { type_count[r->get_class()]++; } -}; +} void _OS::print_all_resources(const String &p_to_file) { OS::get_singleton()->print_all_resources(p_to_file); @@ -636,7 +629,7 @@ void _OS::dump_resources_to_file(const String &p_file) { String _OS::get_user_data_dir() const { return OS::get_singleton()->get_user_data_dir(); -}; +} bool _OS::is_debug_build() const { #ifdef DEBUG_ENABLED @@ -678,6 +671,22 @@ String _OS::get_unique_id() const { return OS::get_singleton()->get_unique_id(); } +int _OS::get_tablet_driver_count() const { + return OS::get_singleton()->get_tablet_driver_count(); +} + +String _OS::get_tablet_driver_name(int p_driver) const { + return OS::get_singleton()->get_tablet_driver_name(p_driver); +} + +String _OS::get_current_tablet_driver() const { + return OS::get_singleton()->get_current_tablet_driver(); +} + +void _OS::set_current_tablet_driver(const String &p_driver) { + OS::get_singleton()->set_current_tablet_driver(p_driver); +} + _OS *_OS::singleton = nullptr; void _OS::_bind_methods() { @@ -712,8 +721,6 @@ void _OS::_bind_methods() { ClassDB::bind_method(D_METHOD("get_unix_time"), &_OS::get_unix_time); ClassDB::bind_method(D_METHOD("get_datetime_from_unix_time", "unix_time_val"), &_OS::get_datetime_from_unix_time); ClassDB::bind_method(D_METHOD("get_unix_time_from_datetime", "datetime"), &_OS::get_unix_time_from_datetime); - ClassDB::bind_method(D_METHOD("get_system_time_secs"), &_OS::get_system_time_secs); - ClassDB::bind_method(D_METHOD("get_system_time_msecs"), &_OS::get_system_time_msecs); ClassDB::bind_method(D_METHOD("get_exit_code"), &_OS::get_exit_code); ClassDB::bind_method(D_METHOD("set_exit_code", "code"), &_OS::set_exit_code); @@ -762,9 +769,15 @@ void _OS::_bind_methods() { ClassDB::bind_method(D_METHOD("request_permissions"), &_OS::request_permissions); ClassDB::bind_method(D_METHOD("get_granted_permissions"), &_OS::get_granted_permissions); + ClassDB::bind_method(D_METHOD("get_tablet_driver_count"), &_OS::get_tablet_driver_count); + ClassDB::bind_method(D_METHOD("get_tablet_driver_name", "idx"), &_OS::get_tablet_driver_name); + ClassDB::bind_method(D_METHOD("get_current_tablet_driver"), &_OS::get_current_tablet_driver); + ClassDB::bind_method(D_METHOD("set_current_tablet_driver", "name"), &_OS::set_current_tablet_driver); + ADD_PROPERTY(PropertyInfo(Variant::INT, "exit_code"), "set_exit_code", "get_exit_code"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "low_processor_usage_mode"), "set_low_processor_usage_mode", "is_in_low_processor_usage_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "low_processor_usage_mode_sleep_usec"), "set_low_processor_usage_mode_sleep_usec", "get_low_processor_usage_mode_sleep_usec"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "tablet_driver"), "set_current_tablet_driver", "get_current_tablet_driver"); // Those default values need to be specified for the docs generator, // to avoid using values from the documentation writer's own OS instance. @@ -806,55 +819,43 @@ void _OS::_bind_methods() { BIND_ENUM_CONSTANT(SYSTEM_DIR_RINGTONES); } -////// _Geometry ////// +////// _Geometry2D ////// -_Geometry *_Geometry::singleton = nullptr; +_Geometry2D *_Geometry2D::singleton = nullptr; -_Geometry *_Geometry::get_singleton() { +_Geometry2D *_Geometry2D::get_singleton() { return singleton; } -Vector<Plane> _Geometry::build_box_planes(const Vector3 &p_extents) { - return Geometry::build_box_planes(p_extents); -} - -Vector<Plane> _Geometry::build_cylinder_planes(float p_radius, float p_height, int p_sides, Vector3::Axis p_axis) { - return Geometry::build_cylinder_planes(p_radius, p_height, p_sides, p_axis); -} - -Vector<Plane> _Geometry::build_capsule_planes(float p_radius, float p_height, int p_sides, int p_lats, Vector3::Axis p_axis) { - return Geometry::build_capsule_planes(p_radius, p_height, p_sides, p_lats, p_axis); +bool _Geometry2D::is_point_in_circle(const Vector2 &p_point, const Vector2 &p_circle_pos, real_t p_circle_radius) { + return Geometry2D::is_point_in_circle(p_point, p_circle_pos, p_circle_radius); } -bool _Geometry::is_point_in_circle(const Vector2 &p_point, const Vector2 &p_circle_pos, real_t p_circle_radius) { - return Geometry::is_point_in_circle(p_point, p_circle_pos, p_circle_radius); +real_t _Geometry2D::segment_intersects_circle(const Vector2 &p_from, const Vector2 &p_to, const Vector2 &p_circle_pos, real_t p_circle_radius) { + return Geometry2D::segment_intersects_circle(p_from, p_to, p_circle_pos, p_circle_radius); } -real_t _Geometry::segment_intersects_circle(const Vector2 &p_from, const Vector2 &p_to, const Vector2 &p_circle_pos, real_t p_circle_radius) { - return Geometry::segment_intersects_circle(p_from, p_to, p_circle_pos, p_circle_radius); -} - -Variant _Geometry::segment_intersects_segment_2d(const Vector2 &p_from_a, const Vector2 &p_to_a, const Vector2 &p_from_b, const Vector2 &p_to_b) { +Variant _Geometry2D::segment_intersects_segment(const Vector2 &p_from_a, const Vector2 &p_to_a, const Vector2 &p_from_b, const Vector2 &p_to_b) { Vector2 result; - if (Geometry::segment_intersects_segment_2d(p_from_a, p_to_a, p_from_b, p_to_b, &result)) { + if (Geometry2D::segment_intersects_segment(p_from_a, p_to_a, p_from_b, p_to_b, &result)) { return result; } else { return Variant(); - }; -}; + } +} -Variant _Geometry::line_intersects_line_2d(const Vector2 &p_from_a, const Vector2 &p_dir_a, const Vector2 &p_from_b, const Vector2 &p_dir_b) { +Variant _Geometry2D::line_intersects_line(const Vector2 &p_from_a, const Vector2 &p_dir_a, const Vector2 &p_from_b, const Vector2 &p_dir_b) { Vector2 result; - if (Geometry::line_intersects_line_2d(p_from_a, p_dir_a, p_from_b, p_dir_b, result)) { + if (Geometry2D::line_intersects_line(p_from_a, p_dir_a, p_from_b, p_dir_b, result)) { return result; } else { return Variant(); } } -Vector<Vector2> _Geometry::get_closest_points_between_segments_2d(const Vector2 &p1, const Vector2 &q1, const Vector2 &p2, const Vector2 &q2) { +Vector<Vector2> _Geometry2D::get_closest_points_between_segments(const Vector2 &p1, const Vector2 &q1, const Vector2 &p2, const Vector2 &q2) { Vector2 r1, r2; - Geometry::get_closest_points_between_segments(p1, q1, p2, q2, r1, r2); + Geometry2D::get_closest_points_between_segments(p1, q1, p2, q2, r1, r2); Vector<Vector2> r; r.resize(2); r.set(0, r1); @@ -862,123 +863,42 @@ Vector<Vector2> _Geometry::get_closest_points_between_segments_2d(const Vector2 return r; } -Vector<Vector3> _Geometry::get_closest_points_between_segments(const Vector3 &p1, const Vector3 &p2, const Vector3 &q1, const Vector3 &q2) { - Vector3 r1, r2; - Geometry::get_closest_points_between_segments(p1, p2, q1, q2, r1, r2); - Vector<Vector3> r; - r.resize(2); - r.set(0, r1); - r.set(1, r2); - return r; -} - -Vector2 _Geometry::get_closest_point_to_segment_2d(const Vector2 &p_point, const Vector2 &p_a, const Vector2 &p_b) { +Vector2 _Geometry2D::get_closest_point_to_segment(const Vector2 &p_point, const Vector2 &p_a, const Vector2 &p_b) { Vector2 s[2] = { p_a, p_b }; - return Geometry::get_closest_point_to_segment_2d(p_point, s); -} - -Vector3 _Geometry::get_closest_point_to_segment(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b) { - Vector3 s[2] = { p_a, p_b }; - return Geometry::get_closest_point_to_segment(p_point, s); + return Geometry2D::get_closest_point_to_segment(p_point, s); } -Vector2 _Geometry::get_closest_point_to_segment_uncapped_2d(const Vector2 &p_point, const Vector2 &p_a, const Vector2 &p_b) { +Vector2 _Geometry2D::get_closest_point_to_segment_uncapped(const Vector2 &p_point, const Vector2 &p_a, const Vector2 &p_b) { Vector2 s[2] = { p_a, p_b }; - return Geometry::get_closest_point_to_segment_uncapped_2d(p_point, s); -} - -Vector3 _Geometry::get_closest_point_to_segment_uncapped(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b) { - Vector3 s[2] = { p_a, p_b }; - return Geometry::get_closest_point_to_segment_uncapped(p_point, s); -} - -Variant _Geometry::ray_intersects_triangle(const Vector3 &p_from, const Vector3 &p_dir, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2) { - Vector3 res; - if (Geometry::ray_intersects_triangle(p_from, p_dir, p_v0, p_v1, p_v2, &res)) { - return res; - } else { - return Variant(); - } -} - -Variant _Geometry::segment_intersects_triangle(const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2) { - Vector3 res; - if (Geometry::segment_intersects_triangle(p_from, p_to, p_v0, p_v1, p_v2, &res)) { - return res; - } else { - return Variant(); - } -} - -bool _Geometry::point_is_inside_triangle(const Vector2 &s, const Vector2 &a, const Vector2 &b, const Vector2 &c) const { - return Geometry::is_point_in_triangle(s, a, b, c); -} - -Vector<Vector3> _Geometry::segment_intersects_sphere(const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_sphere_pos, real_t p_sphere_radius) { - Vector<Vector3> r; - Vector3 res, norm; - if (!Geometry::segment_intersects_sphere(p_from, p_to, p_sphere_pos, p_sphere_radius, &res, &norm)) { - return r; - } - - r.resize(2); - r.set(0, res); - r.set(1, norm); - return r; -} - -Vector<Vector3> _Geometry::segment_intersects_cylinder(const Vector3 &p_from, const Vector3 &p_to, float p_height, float p_radius) { - Vector<Vector3> r; - Vector3 res, norm; - if (!Geometry::segment_intersects_cylinder(p_from, p_to, p_height, p_radius, &res, &norm)) { - return r; - } - - r.resize(2); - r.set(0, res); - r.set(1, norm); - return r; -} - -Vector<Vector3> _Geometry::segment_intersects_convex(const Vector3 &p_from, const Vector3 &p_to, const Vector<Plane> &p_planes) { - Vector<Vector3> r; - Vector3 res, norm; - if (!Geometry::segment_intersects_convex(p_from, p_to, p_planes.ptr(), p_planes.size(), &res, &norm)) { - return r; - } - - r.resize(2); - r.set(0, res); - r.set(1, norm); - return r; + return Geometry2D::get_closest_point_to_segment_uncapped(p_point, s); } -bool _Geometry::is_polygon_clockwise(const Vector<Vector2> &p_polygon) { - return Geometry::is_polygon_clockwise(p_polygon); +bool _Geometry2D::point_is_inside_triangle(const Vector2 &s, const Vector2 &a, const Vector2 &b, const Vector2 &c) const { + return Geometry2D::is_point_in_triangle(s, a, b, c); } -bool _Geometry::is_point_in_polygon(const Point2 &p_point, const Vector<Vector2> &p_polygon) { - return Geometry::is_point_in_polygon(p_point, p_polygon); +bool _Geometry2D::is_polygon_clockwise(const Vector<Vector2> &p_polygon) { + return Geometry2D::is_polygon_clockwise(p_polygon); } -Vector<int> _Geometry::triangulate_polygon(const Vector<Vector2> &p_polygon) { - return Geometry::triangulate_polygon(p_polygon); +bool _Geometry2D::is_point_in_polygon(const Point2 &p_point, const Vector<Vector2> &p_polygon) { + return Geometry2D::is_point_in_polygon(p_point, p_polygon); } -Vector<int> _Geometry::triangulate_delaunay_2d(const Vector<Vector2> &p_points) { - return Geometry::triangulate_delaunay_2d(p_points); +Vector<int> _Geometry2D::triangulate_polygon(const Vector<Vector2> &p_polygon) { + return Geometry2D::triangulate_polygon(p_polygon); } -Vector<Point2> _Geometry::convex_hull_2d(const Vector<Point2> &p_points) { - return Geometry::convex_hull_2d(p_points); +Vector<int> _Geometry2D::triangulate_delaunay(const Vector<Vector2> &p_points) { + return Geometry2D::triangulate_delaunay(p_points); } -Vector<Vector3> _Geometry::clip_polygon(const Vector<Vector3> &p_points, const Plane &p_plane) { - return Geometry::clip_polygon(p_points, p_plane); +Vector<Point2> _Geometry2D::convex_hull(const Vector<Point2> &p_points) { + return Geometry2D::convex_hull(p_points); } -Array _Geometry::merge_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) { - Vector<Vector<Point2>> polys = Geometry::merge_polygons_2d(p_polygon_a, p_polygon_b); +Array _Geometry2D::merge_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) { + Vector<Vector<Point2>> polys = Geometry2D::merge_polygons(p_polygon_a, p_polygon_b); Array ret; @@ -988,8 +908,8 @@ Array _Geometry::merge_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vec return ret; } -Array _Geometry::clip_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) { - Vector<Vector<Point2>> polys = Geometry::clip_polygons_2d(p_polygon_a, p_polygon_b); +Array _Geometry2D::clip_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) { + Vector<Vector<Point2>> polys = Geometry2D::clip_polygons(p_polygon_a, p_polygon_b); Array ret; @@ -999,8 +919,8 @@ Array _Geometry::clip_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vect return ret; } -Array _Geometry::intersect_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) { - Vector<Vector<Point2>> polys = Geometry::intersect_polygons_2d(p_polygon_a, p_polygon_b); +Array _Geometry2D::intersect_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) { + Vector<Vector<Point2>> polys = Geometry2D::intersect_polygons(p_polygon_a, p_polygon_b); Array ret; @@ -1010,8 +930,8 @@ Array _Geometry::intersect_polygons_2d(const Vector<Vector2> &p_polygon_a, const return ret; } -Array _Geometry::exclude_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) { - Vector<Vector<Point2>> polys = Geometry::exclude_polygons_2d(p_polygon_a, p_polygon_b); +Array _Geometry2D::exclude_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) { + Vector<Vector<Point2>> polys = Geometry2D::exclude_polygons(p_polygon_a, p_polygon_b); Array ret; @@ -1021,8 +941,8 @@ Array _Geometry::exclude_polygons_2d(const Vector<Vector2> &p_polygon_a, const V return ret; } -Array _Geometry::clip_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) { - Vector<Vector<Point2>> polys = Geometry::clip_polyline_with_polygon_2d(p_polyline, p_polygon); +Array _Geometry2D::clip_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) { + Vector<Vector<Point2>> polys = Geometry2D::clip_polyline_with_polygon(p_polyline, p_polygon); Array ret; @@ -1032,8 +952,8 @@ Array _Geometry::clip_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline return ret; } -Array _Geometry::intersect_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) { - Vector<Vector<Point2>> polys = Geometry::intersect_polyline_with_polygon_2d(p_polyline, p_polygon); +Array _Geometry2D::intersect_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) { + Vector<Vector<Point2>> polys = Geometry2D::intersect_polyline_with_polygon(p_polyline, p_polygon); Array ret; @@ -1043,8 +963,8 @@ Array _Geometry::intersect_polyline_with_polygon_2d(const Vector<Vector2> &p_pol return ret; } -Array _Geometry::offset_polygon_2d(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type) { - Vector<Vector<Point2>> polys = Geometry::offset_polygon_2d(p_polygon, p_delta, Geometry::PolyJoinType(p_join_type)); +Array _Geometry2D::offset_polygon(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type) { + Vector<Vector<Point2>> polys = Geometry2D::offset_polygon(p_polygon, p_delta, Geometry2D::PolyJoinType(p_join_type)); Array ret; @@ -1054,8 +974,8 @@ Array _Geometry::offset_polygon_2d(const Vector<Vector2> &p_polygon, real_t p_de return ret; } -Array _Geometry::offset_polyline_2d(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) { - Vector<Vector<Point2>> polys = Geometry::offset_polyline_2d(p_polygon, p_delta, Geometry::PolyJoinType(p_join_type), Geometry::PolyEndType(p_end_type)); +Array _Geometry2D::offset_polyline(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) { + Vector<Vector<Point2>> polys = Geometry2D::offset_polyline(p_polygon, p_delta, Geometry2D::PolyJoinType(p_join_type), Geometry2D::PolyEndType(p_end_type)); Array ret; @@ -1065,81 +985,62 @@ Array _Geometry::offset_polyline_2d(const Vector<Vector2> &p_polygon, real_t p_d return ret; } -Dictionary _Geometry::make_atlas(const Vector<Size2> &p_rects) { +Dictionary _Geometry2D::make_atlas(const Vector<Size2> &p_rects) { Dictionary ret; Vector<Size2i> rects; for (int i = 0; i < p_rects.size(); i++) { rects.push_back(p_rects[i]); - }; + } Vector<Point2i> result; Size2i size; - Geometry::make_atlas(rects, result, size); + Geometry2D::make_atlas(rects, result, size); Size2 r_size = size; Vector<Point2> r_result; for (int i = 0; i < result.size(); i++) { r_result.push_back(result[i]); - }; + } ret["points"] = r_result; ret["size"] = r_size; return ret; -}; - -int _Geometry::get_uv84_normal_bit(const Vector3 &p_vector) { - return Geometry::get_uv84_normal_bit(p_vector); } -void _Geometry::_bind_methods() { - ClassDB::bind_method(D_METHOD("build_box_planes", "extents"), &_Geometry::build_box_planes); - ClassDB::bind_method(D_METHOD("build_cylinder_planes", "radius", "height", "sides", "axis"), &_Geometry::build_cylinder_planes, DEFVAL(Vector3::AXIS_Z)); - ClassDB::bind_method(D_METHOD("build_capsule_planes", "radius", "height", "sides", "lats", "axis"), &_Geometry::build_capsule_planes, DEFVAL(Vector3::AXIS_Z)); - ClassDB::bind_method(D_METHOD("is_point_in_circle", "point", "circle_position", "circle_radius"), &_Geometry::is_point_in_circle); - ClassDB::bind_method(D_METHOD("segment_intersects_circle", "segment_from", "segment_to", "circle_position", "circle_radius"), &_Geometry::segment_intersects_circle); - ClassDB::bind_method(D_METHOD("segment_intersects_segment_2d", "from_a", "to_a", "from_b", "to_b"), &_Geometry::segment_intersects_segment_2d); - ClassDB::bind_method(D_METHOD("line_intersects_line_2d", "from_a", "dir_a", "from_b", "dir_b"), &_Geometry::line_intersects_line_2d); +void _Geometry2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("is_point_in_circle", "point", "circle_position", "circle_radius"), &_Geometry2D::is_point_in_circle); + ClassDB::bind_method(D_METHOD("segment_intersects_segment", "from_a", "to_a", "from_b", "to_b"), &_Geometry2D::segment_intersects_segment); + ClassDB::bind_method(D_METHOD("line_intersects_line", "from_a", "dir_a", "from_b", "dir_b"), &_Geometry2D::line_intersects_line); - ClassDB::bind_method(D_METHOD("get_closest_points_between_segments_2d", "p1", "q1", "p2", "q2"), &_Geometry::get_closest_points_between_segments_2d); - ClassDB::bind_method(D_METHOD("get_closest_points_between_segments", "p1", "p2", "q1", "q2"), &_Geometry::get_closest_points_between_segments); + ClassDB::bind_method(D_METHOD("get_closest_points_between_segments", "p1", "q1", "p2", "q2"), &_Geometry2D::get_closest_points_between_segments); - ClassDB::bind_method(D_METHOD("get_closest_point_to_segment_2d", "point", "s1", "s2"), &_Geometry::get_closest_point_to_segment_2d); - ClassDB::bind_method(D_METHOD("get_closest_point_to_segment", "point", "s1", "s2"), &_Geometry::get_closest_point_to_segment); + ClassDB::bind_method(D_METHOD("get_closest_point_to_segment", "point", "s1", "s2"), &_Geometry2D::get_closest_point_to_segment); - ClassDB::bind_method(D_METHOD("get_closest_point_to_segment_uncapped_2d", "point", "s1", "s2"), &_Geometry::get_closest_point_to_segment_uncapped_2d); - ClassDB::bind_method(D_METHOD("get_closest_point_to_segment_uncapped", "point", "s1", "s2"), &_Geometry::get_closest_point_to_segment_uncapped); + ClassDB::bind_method(D_METHOD("get_closest_point_to_segment_uncapped", "point", "s1", "s2"), &_Geometry2D::get_closest_point_to_segment_uncapped); - ClassDB::bind_method(D_METHOD("get_uv84_normal_bit", "normal"), &_Geometry::get_uv84_normal_bit); + ClassDB::bind_method(D_METHOD("point_is_inside_triangle", "point", "a", "b", "c"), &_Geometry2D::point_is_inside_triangle); - ClassDB::bind_method(D_METHOD("ray_intersects_triangle", "from", "dir", "a", "b", "c"), &_Geometry::ray_intersects_triangle); - ClassDB::bind_method(D_METHOD("segment_intersects_triangle", "from", "to", "a", "b", "c"), &_Geometry::segment_intersects_triangle); - ClassDB::bind_method(D_METHOD("segment_intersects_sphere", "from", "to", "sphere_position", "sphere_radius"), &_Geometry::segment_intersects_sphere); - ClassDB::bind_method(D_METHOD("segment_intersects_cylinder", "from", "to", "height", "radius"), &_Geometry::segment_intersects_cylinder); - ClassDB::bind_method(D_METHOD("segment_intersects_convex", "from", "to", "planes"), &_Geometry::segment_intersects_convex); - ClassDB::bind_method(D_METHOD("point_is_inside_triangle", "point", "a", "b", "c"), &_Geometry::point_is_inside_triangle); + ClassDB::bind_method(D_METHOD("is_polygon_clockwise", "polygon"), &_Geometry2D::is_polygon_clockwise); + ClassDB::bind_method(D_METHOD("is_point_in_polygon", "point", "polygon"), &_Geometry2D::is_point_in_polygon); + ClassDB::bind_method(D_METHOD("triangulate_polygon", "polygon"), &_Geometry2D::triangulate_polygon); + ClassDB::bind_method(D_METHOD("triangulate_delaunay", "points"), &_Geometry2D::triangulate_delaunay); + ClassDB::bind_method(D_METHOD("convex_hull", "points"), &_Geometry2D::convex_hull); - ClassDB::bind_method(D_METHOD("is_polygon_clockwise", "polygon"), &_Geometry::is_polygon_clockwise); - ClassDB::bind_method(D_METHOD("is_point_in_polygon", "point", "polygon"), &_Geometry::is_point_in_polygon); - ClassDB::bind_method(D_METHOD("triangulate_polygon", "polygon"), &_Geometry::triangulate_polygon); - ClassDB::bind_method(D_METHOD("triangulate_delaunay_2d", "points"), &_Geometry::triangulate_delaunay_2d); - ClassDB::bind_method(D_METHOD("convex_hull_2d", "points"), &_Geometry::convex_hull_2d); - ClassDB::bind_method(D_METHOD("clip_polygon", "points", "plane"), &_Geometry::clip_polygon); + ClassDB::bind_method(D_METHOD("merge_polygons", "polygon_a", "polygon_b"), &_Geometry2D::merge_polygons); + ClassDB::bind_method(D_METHOD("clip_polygons", "polygon_a", "polygon_b"), &_Geometry2D::clip_polygons); + ClassDB::bind_method(D_METHOD("intersect_polygons", "polygon_a", "polygon_b"), &_Geometry2D::intersect_polygons); + ClassDB::bind_method(D_METHOD("exclude_polygons", "polygon_a", "polygon_b"), &_Geometry2D::exclude_polygons); - ClassDB::bind_method(D_METHOD("merge_polygons_2d", "polygon_a", "polygon_b"), &_Geometry::merge_polygons_2d); - ClassDB::bind_method(D_METHOD("clip_polygons_2d", "polygon_a", "polygon_b"), &_Geometry::clip_polygons_2d); - ClassDB::bind_method(D_METHOD("intersect_polygons_2d", "polygon_a", "polygon_b"), &_Geometry::intersect_polygons_2d); - ClassDB::bind_method(D_METHOD("exclude_polygons_2d", "polygon_a", "polygon_b"), &_Geometry::exclude_polygons_2d); + ClassDB::bind_method(D_METHOD("clip_polyline_with_polygon", "polyline", "polygon"), &_Geometry2D::clip_polyline_with_polygon); + ClassDB::bind_method(D_METHOD("intersect_polyline_with_polygon", "polyline", "polygon"), &_Geometry2D::intersect_polyline_with_polygon); - ClassDB::bind_method(D_METHOD("clip_polyline_with_polygon_2d", "polyline", "polygon"), &_Geometry::clip_polyline_with_polygon_2d); - ClassDB::bind_method(D_METHOD("intersect_polyline_with_polygon_2d", "polyline", "polygon"), &_Geometry::intersect_polyline_with_polygon_2d); + ClassDB::bind_method(D_METHOD("offset_polygon", "polygon", "delta", "join_type"), &_Geometry2D::offset_polygon, DEFVAL(JOIN_SQUARE)); + ClassDB::bind_method(D_METHOD("offset_polyline", "polyline", "delta", "join_type", "end_type"), &_Geometry2D::offset_polyline, DEFVAL(JOIN_SQUARE), DEFVAL(END_SQUARE)); - ClassDB::bind_method(D_METHOD("offset_polygon_2d", "polygon", "delta", "join_type"), &_Geometry::offset_polygon_2d, DEFVAL(JOIN_SQUARE)); - ClassDB::bind_method(D_METHOD("offset_polyline_2d", "polyline", "delta", "join_type", "end_type"), &_Geometry::offset_polyline_2d, DEFVAL(JOIN_SQUARE), DEFVAL(END_SQUARE)); - - ClassDB::bind_method(D_METHOD("make_atlas", "sizes"), &_Geometry::make_atlas); + ClassDB::bind_method(D_METHOD("make_atlas", "sizes"), &_Geometry2D::make_atlas); BIND_ENUM_CONSTANT(OPERATION_UNION); BIND_ENUM_CONSTANT(OPERATION_DIFFERENCE); @@ -1157,6 +1058,133 @@ void _Geometry::_bind_methods() { BIND_ENUM_CONSTANT(END_ROUND); } +////// _Geometry3D ////// + +_Geometry3D *_Geometry3D::singleton = nullptr; + +_Geometry3D *_Geometry3D::get_singleton() { + return singleton; +} + +Vector<Plane> _Geometry3D::build_box_planes(const Vector3 &p_extents) { + return Geometry3D::build_box_planes(p_extents); +} + +Vector<Plane> _Geometry3D::build_cylinder_planes(float p_radius, float p_height, int p_sides, Vector3::Axis p_axis) { + return Geometry3D::build_cylinder_planes(p_radius, p_height, p_sides, p_axis); +} + +Vector<Plane> _Geometry3D::build_capsule_planes(float p_radius, float p_height, int p_sides, int p_lats, Vector3::Axis p_axis) { + return Geometry3D::build_capsule_planes(p_radius, p_height, p_sides, p_lats, p_axis); +} + +Vector<Vector3> _Geometry3D::get_closest_points_between_segments(const Vector3 &p1, const Vector3 &p2, const Vector3 &q1, const Vector3 &q2) { + Vector3 r1, r2; + Geometry3D::get_closest_points_between_segments(p1, p2, q1, q2, r1, r2); + Vector<Vector3> r; + r.resize(2); + r.set(0, r1); + r.set(1, r2); + return r; +} + +Vector3 _Geometry3D::get_closest_point_to_segment(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b) { + Vector3 s[2] = { p_a, p_b }; + return Geometry3D::get_closest_point_to_segment(p_point, s); +} + +Vector3 _Geometry3D::get_closest_point_to_segment_uncapped(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b) { + Vector3 s[2] = { p_a, p_b }; + return Geometry3D::get_closest_point_to_segment_uncapped(p_point, s); +} + +Variant _Geometry3D::ray_intersects_triangle(const Vector3 &p_from, const Vector3 &p_dir, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2) { + Vector3 res; + if (Geometry3D::ray_intersects_triangle(p_from, p_dir, p_v0, p_v1, p_v2, &res)) { + return res; + } else { + return Variant(); + } +} + +Variant _Geometry3D::segment_intersects_triangle(const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2) { + Vector3 res; + if (Geometry3D::segment_intersects_triangle(p_from, p_to, p_v0, p_v1, p_v2, &res)) { + return res; + } else { + return Variant(); + } +} + +Vector<Vector3> _Geometry3D::segment_intersects_sphere(const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_sphere_pos, real_t p_sphere_radius) { + Vector<Vector3> r; + Vector3 res, norm; + if (!Geometry3D::segment_intersects_sphere(p_from, p_to, p_sphere_pos, p_sphere_radius, &res, &norm)) { + return r; + } + + r.resize(2); + r.set(0, res); + r.set(1, norm); + return r; +} + +Vector<Vector3> _Geometry3D::segment_intersects_cylinder(const Vector3 &p_from, const Vector3 &p_to, float p_height, float p_radius) { + Vector<Vector3> r; + Vector3 res, norm; + if (!Geometry3D::segment_intersects_cylinder(p_from, p_to, p_height, p_radius, &res, &norm)) { + return r; + } + + r.resize(2); + r.set(0, res); + r.set(1, norm); + return r; +} + +Vector<Vector3> _Geometry3D::segment_intersects_convex(const Vector3 &p_from, const Vector3 &p_to, const Vector<Plane> &p_planes) { + Vector<Vector3> r; + Vector3 res, norm; + if (!Geometry3D::segment_intersects_convex(p_from, p_to, p_planes.ptr(), p_planes.size(), &res, &norm)) { + return r; + } + + r.resize(2); + r.set(0, res); + r.set(1, norm); + return r; +} + +Vector<Vector3> _Geometry3D::clip_polygon(const Vector<Vector3> &p_points, const Plane &p_plane) { + return Geometry3D::clip_polygon(p_points, p_plane); +} + +int _Geometry3D::get_uv84_normal_bit(const Vector3 &p_vector) { + return Geometry3D::get_uv84_normal_bit(p_vector); +} + +void _Geometry3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("build_box_planes", "extents"), &_Geometry3D::build_box_planes); + ClassDB::bind_method(D_METHOD("build_cylinder_planes", "radius", "height", "sides", "axis"), &_Geometry3D::build_cylinder_planes, DEFVAL(Vector3::AXIS_Z)); + ClassDB::bind_method(D_METHOD("build_capsule_planes", "radius", "height", "sides", "lats", "axis"), &_Geometry3D::build_capsule_planes, DEFVAL(Vector3::AXIS_Z)); + + ClassDB::bind_method(D_METHOD("get_closest_points_between_segments", "p1", "p2", "q1", "q2"), &_Geometry3D::get_closest_points_between_segments); + + ClassDB::bind_method(D_METHOD("get_closest_point_to_segment", "point", "s1", "s2"), &_Geometry3D::get_closest_point_to_segment); + + ClassDB::bind_method(D_METHOD("get_closest_point_to_segment_uncapped", "point", "s1", "s2"), &_Geometry3D::get_closest_point_to_segment_uncapped); + + ClassDB::bind_method(D_METHOD("get_uv84_normal_bit", "normal"), &_Geometry3D::get_uv84_normal_bit); + + ClassDB::bind_method(D_METHOD("ray_intersects_triangle", "from", "dir", "a", "b", "c"), &_Geometry3D::ray_intersects_triangle); + ClassDB::bind_method(D_METHOD("segment_intersects_triangle", "from", "to", "a", "b", "c"), &_Geometry3D::segment_intersects_triangle); + ClassDB::bind_method(D_METHOD("segment_intersects_sphere", "from", "to", "sphere_position", "sphere_radius"), &_Geometry3D::segment_intersects_sphere); + ClassDB::bind_method(D_METHOD("segment_intersects_cylinder", "from", "to", "height", "radius"), &_Geometry3D::segment_intersects_cylinder); + ClassDB::bind_method(D_METHOD("segment_intersects_convex", "from", "to", "planes"), &_Geometry3D::segment_intersects_convex); + + ClassDB::bind_method(D_METHOD("clip_polygon", "points", "plane"), &_Geometry3D::clip_polygon); +} + ////// _File ////// Error _File::open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key) { @@ -1436,13 +1464,13 @@ void _File::store_pascal_string(const String &p_string) { ERR_FAIL_COND_MSG(!f, "File must be opened before use."); f->store_pascal_string(p_string); -}; +} String _File::get_pascal_string() { ERR_FAIL_COND_V_MSG(!f, "", "File must be opened before use."); return f->get_pascal_string(); -}; +} void _File::store_line(const String &p_string) { ERR_FAIL_COND_MSG(!f, "File must be opened before use."); @@ -1784,7 +1812,7 @@ String _Marshalls::variant_to_base64(const Variant &p_var, bool p_full_objects) ERR_FAIL_COND_V(ret == "", ret); return ret; -}; +} Variant _Marshalls::base64_to_variant(const String &p_str, bool p_allow_objects) { int strlen = p_str.length(); @@ -1802,13 +1830,13 @@ Variant _Marshalls::base64_to_variant(const String &p_str, bool p_allow_objects) ERR_FAIL_COND_V_MSG(err != OK, Variant(), "Error when trying to decode Variant."); return v; -}; +} String _Marshalls::raw_to_base64(const Vector<uint8_t> &p_arr) { String ret = CryptoCore::b64_encode_str(p_arr.ptr(), p_arr.size()); ERR_FAIL_COND_V(ret == "", ret); return ret; -}; +} Vector<uint8_t> _Marshalls::base64_to_raw(const String &p_str) { int strlen = p_str.length(); @@ -1825,14 +1853,14 @@ Vector<uint8_t> _Marshalls::base64_to_raw(const String &p_str) { buf.resize(arr_len); return buf; -}; +} String _Marshalls::utf8_to_base64(const String &p_str) { CharString cstr = p_str.utf8(); String ret = CryptoCore::b64_encode_str((unsigned char *)cstr.get_data(), cstr.length()); ERR_FAIL_COND_V(ret == "", ret); return ret; -}; +} String _Marshalls::base64_to_utf8(const String &p_str) { int strlen = p_str.length(); @@ -1849,7 +1877,7 @@ String _Marshalls::base64_to_utf8(const String &p_str) { String ret = String::utf8((char *)&w[0]); return ret; -}; +} void _Marshalls::_bind_methods() { ClassDB::bind_method(D_METHOD("variant_to_base64", "variant", "full_objects"), &_Marshalls::variant_to_base64, DEFVAL(false)); @@ -1860,7 +1888,7 @@ void _Marshalls::_bind_methods() { ClassDB::bind_method(D_METHOD("utf8_to_base64", "utf8_str"), &_Marshalls::utf8_to_base64); ClassDB::bind_method(D_METHOD("base64_to_utf8", "base64_str"), &_Marshalls::base64_to_utf8); -}; +} ////// _Semaphore ////// diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index 32ddcf2c74..f9f5a4e7d7 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -199,9 +199,7 @@ public: Dictionary get_datetime_from_unix_time(int64_t unix_time_val) const; int64_t get_unix_time_from_datetime(Dictionary datetime) const; Dictionary get_time_zone_info() const; - uint64_t get_unix_time() const; - uint64_t get_system_time_secs() const; - uint64_t get_system_time_msecs() const; + double get_unix_time() const; uint64_t get_static_memory_usage() const; uint64_t get_static_memory_peak_usage() const; @@ -243,6 +241,11 @@ public: bool request_permissions(); Vector<String> get_granted_permissions() const; + int get_tablet_driver_count() const; + String get_tablet_driver_name(int p_driver) const; + String get_current_tablet_driver() const; + void set_current_tablet_driver(const String &p_driver); + static _OS *get_singleton() { return singleton; } _OS() { singleton = this; } @@ -253,44 +256,31 @@ VARIANT_ENUM_CAST(_OS::Weekday); VARIANT_ENUM_CAST(_OS::Month); VARIANT_ENUM_CAST(_OS::SystemDir); -class _Geometry : public Object { - GDCLASS(_Geometry, Object); +class _Geometry2D : public Object { + GDCLASS(_Geometry2D, Object); - static _Geometry *singleton; + static _Geometry2D *singleton; protected: static void _bind_methods(); public: - static _Geometry *get_singleton(); - Vector<Plane> build_box_planes(const Vector3 &p_extents); - Vector<Plane> build_cylinder_planes(float p_radius, float p_height, int p_sides, Vector3::Axis p_axis = Vector3::AXIS_Z); - Vector<Plane> build_capsule_planes(float p_radius, float p_height, int p_sides, int p_lats, Vector3::Axis p_axis = Vector3::AXIS_Z); - Variant segment_intersects_segment_2d(const Vector2 &p_from_a, const Vector2 &p_to_a, const Vector2 &p_from_b, const Vector2 &p_to_b); - Variant line_intersects_line_2d(const Vector2 &p_from_a, const Vector2 &p_dir_a, const Vector2 &p_from_b, const Vector2 &p_dir_b); - Vector<Vector2> get_closest_points_between_segments_2d(const Vector2 &p1, const Vector2 &q1, const Vector2 &p2, const Vector2 &q2); - Vector<Vector3> get_closest_points_between_segments(const Vector3 &p1, const Vector3 &p2, const Vector3 &q1, const Vector3 &q2); - Vector2 get_closest_point_to_segment_2d(const Vector2 &p_point, const Vector2 &p_a, const Vector2 &p_b); - Vector3 get_closest_point_to_segment(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b); - Vector2 get_closest_point_to_segment_uncapped_2d(const Vector2 &p_point, const Vector2 &p_a, const Vector2 &p_b); - Vector3 get_closest_point_to_segment_uncapped(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b); - Variant ray_intersects_triangle(const Vector3 &p_from, const Vector3 &p_dir, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2); - Variant segment_intersects_triangle(const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2); + static _Geometry2D *get_singleton(); + Variant segment_intersects_segment(const Vector2 &p_from_a, const Vector2 &p_to_a, const Vector2 &p_from_b, const Vector2 &p_to_b); + Variant line_intersects_line(const Vector2 &p_from_a, const Vector2 &p_dir_a, const Vector2 &p_from_b, const Vector2 &p_dir_b); + Vector<Vector2> get_closest_points_between_segments(const Vector2 &p1, const Vector2 &q1, const Vector2 &p2, const Vector2 &q2); + Vector2 get_closest_point_to_segment(const Vector2 &p_point, const Vector2 &p_a, const Vector2 &p_b); + Vector2 get_closest_point_to_segment_uncapped(const Vector2 &p_point, const Vector2 &p_a, const Vector2 &p_b); bool point_is_inside_triangle(const Vector2 &s, const Vector2 &a, const Vector2 &b, const Vector2 &c) const; - Vector<Vector3> segment_intersects_sphere(const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_sphere_pos, real_t p_sphere_radius); - Vector<Vector3> segment_intersects_cylinder(const Vector3 &p_from, const Vector3 &p_to, float p_height, float p_radius); - Vector<Vector3> segment_intersects_convex(const Vector3 &p_from, const Vector3 &p_to, const Vector<Plane> &p_planes); bool is_point_in_circle(const Vector2 &p_point, const Vector2 &p_circle_pos, real_t p_circle_radius); real_t segment_intersects_circle(const Vector2 &p_from, const Vector2 &p_to, const Vector2 &p_circle_pos, real_t p_circle_radius); - int get_uv84_normal_bit(const Vector3 &p_vector); bool is_polygon_clockwise(const Vector<Vector2> &p_polygon); bool is_point_in_polygon(const Point2 &p_point, const Vector<Vector2> &p_polygon); Vector<int> triangulate_polygon(const Vector<Vector2> &p_polygon); - Vector<int> triangulate_delaunay_2d(const Vector<Vector2> &p_points); - Vector<Point2> convex_hull_2d(const Vector<Point2> &p_points); - Vector<Vector3> clip_polygon(const Vector<Vector3> &p_points, const Plane &p_plane); + Vector<int> triangulate_delaunay(const Vector<Vector2> &p_points); + Vector<Point2> convex_hull(const Vector<Point2> &p_points); enum PolyBooleanOperation { OPERATION_UNION, @@ -299,14 +289,14 @@ public: OPERATION_XOR }; // 2D polygon boolean operations. - Array merge_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Union (add). - Array clip_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Difference (subtract). - Array intersect_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Common area (multiply). - Array exclude_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // All but common area (xor). + Array merge_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Union (add). + Array clip_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Difference (subtract). + Array intersect_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Common area (multiply). + Array exclude_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // All but common area (xor). // 2D polyline vs polygon operations. - Array clip_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // Cut. - Array intersect_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // Chop. + Array clip_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // Cut. + Array intersect_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // Chop. // 2D offset polygons/polylines. enum PolyJoinType { @@ -321,17 +311,46 @@ public: END_SQUARE, END_ROUND }; - Array offset_polygon_2d(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type = JOIN_SQUARE); - Array offset_polyline_2d(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type = JOIN_SQUARE, PolyEndType p_end_type = END_SQUARE); + Array offset_polygon(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type = JOIN_SQUARE); + Array offset_polyline(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type = JOIN_SQUARE, PolyEndType p_end_type = END_SQUARE); Dictionary make_atlas(const Vector<Size2> &p_rects); - _Geometry() { singleton = this; } + _Geometry2D() { singleton = this; } }; -VARIANT_ENUM_CAST(_Geometry::PolyBooleanOperation); -VARIANT_ENUM_CAST(_Geometry::PolyJoinType); -VARIANT_ENUM_CAST(_Geometry::PolyEndType); +VARIANT_ENUM_CAST(_Geometry2D::PolyBooleanOperation); +VARIANT_ENUM_CAST(_Geometry2D::PolyJoinType); +VARIANT_ENUM_CAST(_Geometry2D::PolyEndType); + +class _Geometry3D : public Object { + GDCLASS(_Geometry3D, Object); + + static _Geometry3D *singleton; + +protected: + static void _bind_methods(); + +public: + static _Geometry3D *get_singleton(); + Vector<Plane> build_box_planes(const Vector3 &p_extents); + Vector<Plane> build_cylinder_planes(float p_radius, float p_height, int p_sides, Vector3::Axis p_axis = Vector3::AXIS_Z); + Vector<Plane> build_capsule_planes(float p_radius, float p_height, int p_sides, int p_lats, Vector3::Axis p_axis = Vector3::AXIS_Z); + Vector<Vector3> get_closest_points_between_segments(const Vector3 &p1, const Vector3 &p2, const Vector3 &q1, const Vector3 &q2); + Vector3 get_closest_point_to_segment(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b); + Vector3 get_closest_point_to_segment_uncapped(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b); + Variant ray_intersects_triangle(const Vector3 &p_from, const Vector3 &p_dir, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2); + Variant segment_intersects_triangle(const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2); + + Vector<Vector3> segment_intersects_sphere(const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_sphere_pos, real_t p_sphere_radius); + Vector<Vector3> segment_intersects_cylinder(const Vector3 &p_from, const Vector3 &p_to, float p_height, float p_radius); + Vector<Vector3> segment_intersects_convex(const Vector3 &p_from, const Vector3 &p_to, const Vector<Plane> &p_planes); + int get_uv84_normal_bit(const Vector3 &p_vector); + + Vector<Vector3> clip_polygon(const Vector<Vector3> &p_points, const Plane &p_plane); + + _Geometry3D() { singleton = this; } +}; class _File : public Reference { GDCLASS(_File, Reference); diff --git a/core/callable_method_pointer.h b/core/callable_method_pointer.h index 3b0503e259..22db7d1c82 100644 --- a/core/callable_method_pointer.h +++ b/core/callable_method_pointer.h @@ -161,19 +161,35 @@ template <class T, class... P> class CallableCustomMethodPointer : public CallableCustomMethodPointerBase { struct Data { T *instance; +#ifdef DEBUG_ENABLED + uint64_t object_id; +#endif void (T::*method)(P...); } data; public: - virtual ObjectID get_object() const { return data.instance->get_instance_id(); } + virtual ObjectID get_object() const { +#ifdef DEBUG_ENABLED + if (ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr) { + return ObjectID(); + } +#endif + return data.instance->get_instance_id(); + } virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const { +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr, "Invalid Object id '" + uitos(data.object_id) + "', can't call method."); +#endif call_with_variant_args(data.instance, data.method, p_arguments, p_argcount, r_call_error); } CallableCustomMethodPointer(T *p_instance, void (T::*p_method)(P...)) { zeromem(&data, sizeof(Data)); // Clear beforehand, may have padding bytes. data.instance = p_instance; +#ifdef DEBUG_ENABLED + data.object_id = p_instance->get_instance_id(); +#endif data.method = p_method; _setup((uint32_t *)&data, sizeof(Data)); } @@ -242,20 +258,36 @@ template <class T, class R, class... P> class CallableCustomMethodPointerRet : public CallableCustomMethodPointerBase { struct Data { T *instance; +#ifdef DEBUG_ENABLED + uint64_t object_id; +#endif R(T::*method) (P...); } data; public: - virtual ObjectID get_object() const { return data.instance->get_instance_id(); } + virtual ObjectID get_object() const { +#ifdef DEBUG_ENABLED + if (ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr) { + return ObjectID(); + } +#endif + return data.instance->get_instance_id(); + } virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const { +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr, "Invalid Object id '" + uitos(data.object_id) + "', can't call method."); +#endif call_with_variant_args_ret(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error); } CallableCustomMethodPointerRet(T *p_instance, R (T::*p_method)(P...)) { zeromem(&data, sizeof(Data)); // Clear beforehand, may have padding bytes. data.instance = p_instance; +#ifdef DEBUG_ENABLED + data.object_id = p_instance->get_instance_id(); +#endif data.method = p_method; _setup((uint32_t *)&data, sizeof(Data)); } diff --git a/core/class_db.cpp b/core/class_db.cpp index eed9ec17cb..05c9850c39 100644 --- a/core/class_db.cpp +++ b/core/class_db.cpp @@ -1386,7 +1386,23 @@ Variant ClassDB::class_get_default_property_value(const StringName &p_class, con if (r_valid != nullptr) { *r_valid = true; } - return default_values[p_class][p_property]; + + Variant var = default_values[p_class][p_property]; + +#ifdef DEBUG_ENABLED + // Some properties may have an instantiated Object as default value, + // (like Path2D's `curve` used to have), but that's not a good practice. + // Instead, those properties should use PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT + // to be auto-instantiated when created in the editor. + if (var.get_type() == Variant::OBJECT) { + Object *obj = var.get_validated_object(); + if (obj) { + WARN_PRINT(vformat("Instantiated %s used as default value for %s's \"%s\" property.", obj->get_class(), p_class, p_property)); + } + } +#endif + + return var; } RWLock *ClassDB::lock = nullptr; diff --git a/core/color.cpp b/core/color.cpp index fa3f6475d4..27a2d0af5c 100644 --- a/core/color.cpp +++ b/core/color.cpp @@ -588,7 +588,7 @@ void Color::operator/=(const real_t &rvalue) { b = b / rvalue; a = a / rvalue; } -}; +} Color Color::operator-() const { return Color( diff --git a/core/cowdata.h b/core/cowdata.h index 3f72362e29..82daefb5bd 100644 --- a/core/cowdata.h +++ b/core/cowdata.h @@ -161,10 +161,10 @@ public: int len = size(); for (int i = p_index; i < len - 1; i++) { p[i] = p[i + 1]; - }; + } resize(len - 1); - }; + } Error insert(int p_pos, const T &p_val) { ERR_FAIL_INDEX_V(p_pos, size() + 1, ERR_INVALID_PARAMETER); @@ -175,7 +175,7 @@ public: set(p_pos, p_val); return OK; - }; + } int find(const T &p_val, int p_from = 0) const; diff --git a/core/crypto/aes_context.cpp b/core/crypto/aes_context.cpp new file mode 100644 index 0000000000..8ef1f4f1d4 --- /dev/null +++ b/core/crypto/aes_context.cpp @@ -0,0 +1,116 @@ +/*************************************************************************/ +/* aes_context.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "core/crypto/aes_context.h" + +Error AESContext::start(Mode p_mode, PackedByteArray p_key, PackedByteArray p_iv) { + ERR_FAIL_COND_V_MSG(mode != MODE_MAX, ERR_ALREADY_IN_USE, "AESContext already started. Call 'finish' before starting a new one."); + ERR_FAIL_COND_V_MSG(p_mode < 0 || p_mode >= MODE_MAX, ERR_INVALID_PARAMETER, "Invalid mode requested."); + // Key check. + int key_bits = p_key.size() << 3; + ERR_FAIL_COND_V_MSG(key_bits != 128 && key_bits != 256, ERR_INVALID_PARAMETER, "AES key must be either 16 or 32 bytes"); + // Initialization vector. + if (p_mode == MODE_CBC_ENCRYPT || p_mode == MODE_CBC_DECRYPT) { + ERR_FAIL_COND_V_MSG(p_iv.size() != 16, ERR_INVALID_PARAMETER, "The initialization vector (IV) must be exactly 16 bytes."); + iv.resize(0); + iv.append_array(p_iv); + } + // Encryption/decryption key. + if (p_mode == MODE_CBC_ENCRYPT || p_mode == MODE_ECB_ENCRYPT) { + ctx.set_encode_key(p_key.ptr(), key_bits); + } else { + ctx.set_decode_key(p_key.ptr(), key_bits); + } + mode = p_mode; + return OK; +} + +PackedByteArray AESContext::update(PackedByteArray p_src) { + ERR_FAIL_COND_V_MSG(mode < 0 || mode >= MODE_MAX, PackedByteArray(), "AESContext not started. Call 'start' before calling 'update'."); + int len = p_src.size(); + ERR_FAIL_COND_V_MSG(len % 16, PackedByteArray(), "The number of bytes to be encrypted must be multiple of 16. Add padding if needed"); + PackedByteArray out; + out.resize(len); + const uint8_t *src_ptr = p_src.ptr(); + uint8_t *out_ptr = out.ptrw(); + switch (mode) { + case MODE_ECB_ENCRYPT: { + for (int i = 0; i < len; i += 16) { + Error err = ctx.encrypt_ecb(src_ptr + i, out_ptr + i); + ERR_FAIL_COND_V(err != OK, PackedByteArray()); + } + } break; + case MODE_ECB_DECRYPT: { + for (int i = 0; i < len; i += 16) { + Error err = ctx.decrypt_ecb(src_ptr + i, out_ptr + i); + ERR_FAIL_COND_V(err != OK, PackedByteArray()); + } + } break; + case MODE_CBC_ENCRYPT: { + Error err = ctx.encrypt_cbc(len, iv.ptrw(), p_src.ptr(), out.ptrw()); + ERR_FAIL_COND_V(err != OK, PackedByteArray()); + } break; + case MODE_CBC_DECRYPT: { + Error err = ctx.decrypt_cbc(len, iv.ptrw(), p_src.ptr(), out.ptrw()); + ERR_FAIL_COND_V(err != OK, PackedByteArray()); + } break; + default: + ERR_FAIL_V_MSG(PackedByteArray(), "Bug!"); + } + return out; +} + +PackedByteArray AESContext::get_iv_state() { + ERR_FAIL_COND_V_MSG(mode != MODE_CBC_ENCRYPT && mode != MODE_CBC_DECRYPT, PackedByteArray(), "Calling 'get_iv_state' only makes sense when the context is started in CBC mode."); + PackedByteArray out; + out.append_array(iv); + return out; +} + +void AESContext::finish() { + mode = MODE_MAX; + iv.resize(0); +} + +void AESContext::_bind_methods() { + ClassDB::bind_method(D_METHOD("start", "mode", "key", "iv"), &AESContext::start, DEFVAL(PackedByteArray())); + ClassDB::bind_method(D_METHOD("update", "src"), &AESContext::update); + ClassDB::bind_method(D_METHOD("get_iv_state"), &AESContext::get_iv_state); + ClassDB::bind_method(D_METHOD("finish"), &AESContext::finish); + BIND_ENUM_CONSTANT(MODE_ECB_ENCRYPT); + BIND_ENUM_CONSTANT(MODE_ECB_DECRYPT); + BIND_ENUM_CONSTANT(MODE_CBC_ENCRYPT); + BIND_ENUM_CONSTANT(MODE_CBC_DECRYPT); + BIND_ENUM_CONSTANT(MODE_MAX); +} + +AESContext::AESContext() { + mode = MODE_MAX; +} diff --git a/core/crypto/aes_context.h b/core/crypto/aes_context.h new file mode 100644 index 0000000000..006ecee2ad --- /dev/null +++ b/core/crypto/aes_context.h @@ -0,0 +1,68 @@ +/*************************************************************************/ +/* aes_context.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef AES_CONTEXT_H +#define AES_CONTEXT_H + +#include "core/crypto/crypto_core.h" +#include "core/reference.h" + +class AESContext : public Reference { + GDCLASS(AESContext, Reference); + +public: + enum Mode { + MODE_ECB_ENCRYPT, + MODE_ECB_DECRYPT, + MODE_CBC_ENCRYPT, + MODE_CBC_DECRYPT, + MODE_MAX + }; + +private: + Mode mode; + CryptoCore::AESContext ctx; + PackedByteArray iv; + +protected: + static void _bind_methods(); + +public: + Error start(Mode p_mode, PackedByteArray p_key, PackedByteArray p_iv = PackedByteArray()); + PackedByteArray update(PackedByteArray p_src); + PackedByteArray get_iv_state(); + void finish(); + + AESContext(); +}; + +VARIANT_ENUM_CAST(AESContext::Mode); + +#endif // AES_CONTEXT_H diff --git a/core/crypto/crypto.cpp b/core/crypto/crypto.cpp index eb942c60c9..29d02e11df 100644 --- a/core/crypto/crypto.cpp +++ b/core/crypto/crypto.cpp @@ -45,8 +45,11 @@ CryptoKey *CryptoKey::create() { } void CryptoKey::_bind_methods() { - ClassDB::bind_method(D_METHOD("save", "path"), &CryptoKey::save); - ClassDB::bind_method(D_METHOD("load", "path"), &CryptoKey::load); + ClassDB::bind_method(D_METHOD("save", "path", "public_only"), &CryptoKey::save, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("load", "path", "public_only"), &CryptoKey::load, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("is_public_only"), &CryptoKey::is_public_only); + ClassDB::bind_method(D_METHOD("save_to_string", "public_only"), &CryptoKey::save_to_string, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("load_from_string", "string_key", "public_only"), &CryptoKey::load_from_string, DEFVAL(false)); } X509Certificate *(*X509Certificate::_create)() = nullptr; @@ -70,7 +73,7 @@ Crypto *Crypto::create() { if (_create) { return _create(); } - return memnew(Crypto); + ERR_FAIL_V_MSG(nullptr, "Crypto is not available when the mbedtls module is disabled."); } void Crypto::load_default_certificates(String p_path) { @@ -83,18 +86,10 @@ void Crypto::_bind_methods() { ClassDB::bind_method(D_METHOD("generate_random_bytes", "size"), &Crypto::generate_random_bytes); ClassDB::bind_method(D_METHOD("generate_rsa", "size"), &Crypto::generate_rsa); ClassDB::bind_method(D_METHOD("generate_self_signed_certificate", "key", "issuer_name", "not_before", "not_after"), &Crypto::generate_self_signed_certificate, DEFVAL("CN=myserver,O=myorganisation,C=IT"), DEFVAL("20140101000000"), DEFVAL("20340101000000")); -} - -PackedByteArray Crypto::generate_random_bytes(int p_bytes) { - ERR_FAIL_V_MSG(PackedByteArray(), "generate_random_bytes is not available when mbedtls module is disabled."); -} - -Ref<CryptoKey> Crypto::generate_rsa(int p_bytes) { - ERR_FAIL_V_MSG(nullptr, "generate_rsa is not available when mbedtls module is disabled."); -} - -Ref<X509Certificate> Crypto::generate_self_signed_certificate(Ref<CryptoKey> p_key, String p_issuer_name, String p_not_before, String p_not_after) { - ERR_FAIL_V_MSG(nullptr, "generate_self_signed_certificate is not available when mbedtls module is disabled."); + ClassDB::bind_method(D_METHOD("sign", "hash_type", "hash", "key"), &Crypto::sign); + ClassDB::bind_method(D_METHOD("verify", "hash_type", "hash", "signature", "key"), &Crypto::verify); + ClassDB::bind_method(D_METHOD("encrypt", "key", "plaintext"), &Crypto::encrypt); + ClassDB::bind_method(D_METHOD("decrypt", "key", "ciphertext"), &Crypto::decrypt); } /// Resource loader/saver @@ -110,9 +105,14 @@ RES ResourceFormatLoaderCrypto::load(const String &p_path, const String &p_origi } else if (el == "key") { CryptoKey *key = CryptoKey::create(); if (key) { - key->load(p_path); + key->load(p_path, false); } return key; + } else if (el == "pub") { + CryptoKey *key = CryptoKey::create(); + if (key) + key->load(p_path, true); + return key; } return nullptr; } @@ -120,6 +120,7 @@ RES ResourceFormatLoaderCrypto::load(const String &p_path, const String &p_origi void ResourceFormatLoaderCrypto::get_recognized_extensions(List<String> *p_extensions) const { p_extensions->push_back("crt"); p_extensions->push_back("key"); + p_extensions->push_back("pub"); } bool ResourceFormatLoaderCrypto::handles_type(const String &p_type) const { @@ -130,7 +131,7 @@ String ResourceFormatLoaderCrypto::get_resource_type(const String &p_path) const String el = p_path.get_extension().to_lower(); if (el == "crt") { return "X509Certificate"; - } else if (el == "key") { + } else if (el == "key" || el == "pub") { return "CryptoKey"; } return ""; @@ -143,7 +144,8 @@ Error ResourceFormatSaverCrypto::save(const String &p_path, const RES &p_resourc if (cert.is_valid()) { err = cert->save(p_path); } else if (key.is_valid()) { - err = key->save(p_path); + String el = p_path.get_extension().to_lower(); + err = key->save(p_path, el == "pub"); } else { ERR_FAIL_V(ERR_INVALID_PARAMETER); } @@ -158,7 +160,10 @@ void ResourceFormatSaverCrypto::get_recognized_extensions(const RES &p_resource, p_extensions->push_back("crt"); } if (key) { - p_extensions->push_back("key"); + if (!key->is_public_only()) { + p_extensions->push_back("key"); + } + p_extensions->push_back("pub"); } } diff --git a/core/crypto/crypto.h b/core/crypto/crypto.h index cf21648a4a..916f7798eb 100644 --- a/core/crypto/crypto.h +++ b/core/crypto/crypto.h @@ -31,6 +31,7 @@ #ifndef CRYPTO_H #define CRYPTO_H +#include "core/crypto/hashing_context.h" #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" #include "core/reference.h" @@ -45,8 +46,11 @@ protected: public: static CryptoKey *create(); - virtual Error load(String p_path) = 0; - virtual Error save(String p_path) = 0; + virtual Error load(String p_path, bool p_public_only = false) = 0; + virtual Error save(String p_path, bool p_public_only = false) = 0; + virtual String save_to_string(bool p_public_only = false) = 0; + virtual Error load_from_string(String p_string_key, bool p_public_only = false) = 0; + virtual bool is_public_only() const = 0; }; class X509Certificate : public Resource { @@ -75,9 +79,14 @@ public: static Crypto *create(); static void load_default_certificates(String p_path); - virtual PackedByteArray generate_random_bytes(int p_bytes); - virtual Ref<CryptoKey> generate_rsa(int p_bytes); - virtual Ref<X509Certificate> generate_self_signed_certificate(Ref<CryptoKey> p_key, String p_issuer_name, String p_not_before, String p_not_after); + virtual PackedByteArray generate_random_bytes(int p_bytes) = 0; + virtual Ref<CryptoKey> generate_rsa(int p_bytes) = 0; + virtual Ref<X509Certificate> generate_self_signed_certificate(Ref<CryptoKey> p_key, String p_issuer_name, String p_not_before, String p_not_after) = 0; + + virtual Vector<uint8_t> sign(HashingContext::HashType p_hash_type, Vector<uint8_t> p_hash, Ref<CryptoKey> p_key) = 0; + virtual bool verify(HashingContext::HashType p_hash_type, Vector<uint8_t> p_hash, Vector<uint8_t> p_signature, Ref<CryptoKey> p_key) = 0; + virtual Vector<uint8_t> encrypt(Ref<CryptoKey> p_key, Vector<uint8_t> p_plaintext) = 0; + virtual Vector<uint8_t> decrypt(Ref<CryptoKey> p_key, Vector<uint8_t> p_ciphertext) = 0; Crypto() {} }; diff --git a/core/crypto/crypto_core.cpp b/core/crypto/crypto_core.cpp index ec25ee0d38..b0dc47e655 100644 --- a/core/crypto/crypto_core.cpp +++ b/core/crypto/crypto_core.cpp @@ -145,6 +145,16 @@ Error CryptoCore::AESContext::decrypt_ecb(const uint8_t p_src[16], uint8_t r_dst return ret ? FAILED : OK; } +Error CryptoCore::AESContext::encrypt_cbc(size_t p_length, uint8_t r_iv[16], const uint8_t *p_src, uint8_t *r_dst) { + int ret = mbedtls_aes_crypt_cbc((mbedtls_aes_context *)ctx, MBEDTLS_AES_ENCRYPT, p_length, r_iv, p_src, r_dst); + return ret ? FAILED : OK; +} + +Error CryptoCore::AESContext::decrypt_cbc(size_t p_length, uint8_t r_iv[16], const uint8_t *p_src, uint8_t *r_dst) { + int ret = mbedtls_aes_crypt_cbc((mbedtls_aes_context *)ctx, MBEDTLS_AES_DECRYPT, p_length, r_iv, p_src, r_dst); + return ret ? FAILED : OK; +} + // CryptoCore String CryptoCore::b64_encode_str(const uint8_t *p_src, int p_src_len) { int b64len = p_src_len / 3 * 4 + 4 + 1; diff --git a/core/crypto/crypto_core.h b/core/crypto/crypto_core.h index 36d8ace723..82df9c23a8 100644 --- a/core/crypto/crypto_core.h +++ b/core/crypto/crypto_core.h @@ -86,6 +86,8 @@ public: Error set_decode_key(const uint8_t *p_key, size_t p_bits); Error encrypt_ecb(const uint8_t p_src[16], uint8_t r_dst[16]); Error decrypt_ecb(const uint8_t p_src[16], uint8_t r_dst[16]); + Error encrypt_cbc(size_t p_length, uint8_t r_iv[16], const uint8_t *p_src, uint8_t *r_dst); + Error decrypt_cbc(size_t p_length, uint8_t r_iv[16], const uint8_t *p_src, uint8_t *r_dst); }; static String b64_encode_str(const uint8_t *p_src, int p_src_len); diff --git a/core/debugger/remote_debugger.cpp b/core/debugger/remote_debugger.cpp index 62f600c5e5..9d55e1312e 100644 --- a/core/debugger/remote_debugger.cpp +++ b/core/debugger/remote_debugger.cpp @@ -373,6 +373,7 @@ struct RemoteDebugger::VisualProfiler { struct RemoteDebugger::PerformanceProfiler { Object *performance = nullptr; int last_perf_time = 0; + uint64_t last_monitor_modification_time = 0; void toggle(bool p_enable, const Array &p_opts) {} void add(const Array &p_data) {} @@ -386,12 +387,31 @@ struct RemoteDebugger::PerformanceProfiler { return; } last_perf_time = pt; + + Array custom_monitor_names = performance->call("get_custom_monitor_names"); + + uint64_t monitor_modification_time = performance->call("get_monitor_modification_time"); + if (monitor_modification_time > last_monitor_modification_time) { + last_monitor_modification_time = monitor_modification_time; + EngineDebugger::get_singleton()->send_message("performance:profile_names", custom_monitor_names); + } + int max = performance->get("MONITOR_MAX"); Array arr; - arr.resize(max); + arr.resize(max + custom_monitor_names.size()); for (int i = 0; i < max; i++) { arr[i] = performance->call("get_monitor", i); } + + for (int i = 0; i < custom_monitor_names.size(); i++) { + Variant monitor_value = performance->call("get_custom_monitor", custom_monitor_names[i]); + if (!monitor_value.is_num()) { + ERR_PRINT("Value of custom monitor '" + String(custom_monitor_names[i]) + "' is not a number"); + arr[i + max] = Variant(); + } + arr[i + max] = monitor_value; + } + EngineDebugger::get_singleton()->send_message("performance:profile_frame", arr); } diff --git a/core/debugger/remote_debugger_peer.cpp b/core/debugger/remote_debugger_peer.cpp index fd1eee0654..faa3a75fda 100644 --- a/core/debugger/remote_debugger_peer.cpp +++ b/core/debugger/remote_debugger_peer.cpp @@ -178,13 +178,13 @@ Error RemoteDebuggerPeerTCP::connect_to_host(const String &p_host, uint16_t p_po const int ms = waits[i]; OS::get_singleton()->delay_usec(ms * 1000); print_verbose("Remote Debugger: Connection failed with status: '" + String::num(tcp_client->get_status()) + "', retrying in " + String::num(ms) + " msec."); - }; - }; + } + } if (tcp_client->get_status() != StreamPeerTCP::STATUS_CONNECTED) { ERR_PRINT("Remote Debugger: Unable to connect. Status: " + String::num(tcp_client->get_status()) + "."); return FAILED; - }; + } connected = true; #ifndef NO_THREADS running = true; diff --git a/core/engine.cpp b/core/engine.cpp index 43c5766431..c8bfffd020 100644 --- a/core/engine.cpp +++ b/core/engine.cpp @@ -188,11 +188,11 @@ Object *Engine::get_singleton_object(const String &p_name) const { const Map<StringName, Object *>::Element *E = singleton_ptrs.find(p_name); ERR_FAIL_COND_V_MSG(!E, nullptr, "Failed to retrieve non-existent singleton '" + p_name + "'."); return E->get(); -}; +} bool Engine::has_singleton(const String &p_name) const { return singleton_ptrs.has(p_name); -}; +} void Engine::get_singletons(List<Singleton> *p_singletons) { for (List<Singleton>::Element *E = singletons.front(); E; E = E->next()) { diff --git a/core/error_macros.h b/core/error_macros.h index 46a1623115..d7366be453 100644 --- a/core/error_macros.h +++ b/core/error_macros.h @@ -285,7 +285,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * If it is null, the current function returns. */ #define ERR_FAIL_NULL(m_param) \ - if (unlikely(!m_param)) { \ + if (unlikely(m_param == nullptr)) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null."); \ return; \ } else \ @@ -296,7 +296,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * If it is null, prints `m_msg` and the current function returns. */ #define ERR_FAIL_NULL_MSG(m_param, m_msg) \ - if (unlikely(!m_param)) { \ + if (unlikely(m_param == nullptr)) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", DEBUG_STR(m_msg)); \ return; \ } else \ @@ -310,7 +310,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * If it is null, the current function returns `m_retval`. */ #define ERR_FAIL_NULL_V(m_param, m_retval) \ - if (unlikely(!m_param)) { \ + if (unlikely(m_param == nullptr)) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null."); \ return m_retval; \ } else \ @@ -321,7 +321,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * If it is null, prints `m_msg` and the current function returns `m_retval`. */ #define ERR_FAIL_NULL_V_MSG(m_param, m_retval, m_msg) \ - if (unlikely(!m_param)) { \ + if (unlikely(m_param == nullptr)) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", DEBUG_STR(m_msg)); \ return m_retval; \ } else \ diff --git a/core/hash_map.h b/core/hash_map.h index 78592f8d82..843430d082 100644 --- a/core/hash_map.h +++ b/core/hash_map.h @@ -524,28 +524,14 @@ public: copy_from(p_table); } - void get_key_value_ptr_array(const Pair **p_pairs) const { + void get_key_list(List<TKey> *r_keys) const { if (unlikely(!hash_table)) { return; } for (int i = 0; i < (1 << hash_table_power); i++) { Element *e = hash_table[i]; while (e) { - *p_pairs = &e->pair; - p_pairs++; - e = e->next; - } - } - } - - void get_key_list(List<TKey> *p_keys) const { - if (unlikely(!hash_table)) { - return; - } - for (int i = 0; i < (1 << hash_table_power); i++) { - Element *e = hash_table[i]; - while (e) { - p_keys->push_back(e->pair.key); + r_keys->push_back(e->pair.key); e = e->next; } } diff --git a/core/image.cpp b/core/image.cpp index 2857530675..e2b184fcde 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -679,34 +679,35 @@ static void _scale_bilinear(const uint8_t *__restrict p_src, uint8_t *__restrict enum { FRAC_BITS = 8, FRAC_LEN = (1 << FRAC_BITS), + FRAC_HALF = (FRAC_LEN >> 1), FRAC_MASK = FRAC_LEN - 1 - }; for (uint32_t i = 0; i < p_dst_height; i++) { - uint32_t src_yofs_up_fp = (i * p_src_height * FRAC_LEN / p_dst_height); - uint32_t src_yofs_frac = src_yofs_up_fp & FRAC_MASK; - uint32_t src_yofs_up = src_yofs_up_fp >> FRAC_BITS; - - uint32_t src_yofs_down = (i + 1) * p_src_height / p_dst_height; + // Add 0.5 in order to interpolate based on pixel center + uint32_t src_yofs_up_fp = (i + 0.5) * p_src_height * FRAC_LEN / p_dst_height; + // Calculate nearest src pixel center above current, and truncate to get y index + uint32_t src_yofs_up = src_yofs_up_fp >= FRAC_HALF ? (src_yofs_up_fp - FRAC_HALF) >> FRAC_BITS : 0; + uint32_t src_yofs_down = (src_yofs_up_fp + FRAC_HALF) >> FRAC_BITS; if (src_yofs_down >= p_src_height) { src_yofs_down = p_src_height - 1; } - - //src_yofs_up*=CC; - //src_yofs_down*=CC; + // Calculate distance to pixel center of src_yofs_up + uint32_t src_yofs_frac = src_yofs_up_fp & FRAC_MASK; + src_yofs_frac = src_yofs_frac >= FRAC_HALF ? src_yofs_frac - FRAC_HALF : src_yofs_frac + FRAC_HALF; uint32_t y_ofs_up = src_yofs_up * p_src_width * CC; uint32_t y_ofs_down = src_yofs_down * p_src_width * CC; for (uint32_t j = 0; j < p_dst_width; j++) { - uint32_t src_xofs_left_fp = (j * p_src_width * FRAC_LEN / p_dst_width); - uint32_t src_xofs_frac = src_xofs_left_fp & FRAC_MASK; - uint32_t src_xofs_left = src_xofs_left_fp >> FRAC_BITS; - uint32_t src_xofs_right = (j + 1) * p_src_width / p_dst_width; + uint32_t src_xofs_left_fp = (j + 0.5) * p_src_width * FRAC_LEN / p_dst_width; + uint32_t src_xofs_left = src_xofs_left_fp >= FRAC_HALF ? (src_xofs_left_fp - FRAC_HALF) >> FRAC_BITS : 0; + uint32_t src_xofs_right = (src_xofs_left_fp + FRAC_HALF) >> FRAC_BITS; if (src_xofs_right >= p_src_width) { src_xofs_right = p_src_width - 1; } + uint32_t src_xofs_frac = src_xofs_left_fp & FRAC_MASK; + src_xofs_frac = src_xofs_frac >= FRAC_HALF ? src_xofs_frac - FRAC_HALF : src_xofs_frac + FRAC_HALF; src_xofs_left *= CC; src_xofs_right *= CC; @@ -1400,7 +1401,7 @@ int Image::_get_dst_image_size(int p_width, int p_height, Format p_format, int & h = MAX(minh, h >> 1); } mm++; - }; + } r_mipmaps = mm; return size; @@ -2032,7 +2033,7 @@ void Image::create(const char **p_xpm) { case 5: col_b |= v; break; - }; + } } // magenta mask @@ -2540,12 +2541,11 @@ void Image::blend_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const P int dst_y = dest_rect.position.y + i; Color sc = img->get_pixel(src_x, src_y); - Color dc = get_pixel(dst_x, dst_y); - dc.r = (double)(sc.a * sc.r + dc.a * (1.0 - sc.a) * dc.r); - dc.g = (double)(sc.a * sc.g + dc.a * (1.0 - sc.a) * dc.g); - dc.b = (double)(sc.a * sc.b + dc.a * (1.0 - sc.a) * dc.b); - dc.a = (double)(sc.a + dc.a * (1.0 - sc.a)); - set_pixel(dst_x, dst_y, dc); + if (sc.a != 0) { + Color dc = get_pixel(dst_x, dst_y); + dc = dc.blend(sc); + set_pixel(dst_x, dst_y, dc); + } } } } @@ -2595,12 +2595,11 @@ void Image::blend_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, c int dst_y = dest_rect.position.y + i; Color sc = img->get_pixel(src_x, src_y); - Color dc = get_pixel(dst_x, dst_y); - dc.r = (double)(sc.a * sc.r + dc.a * (1.0 - sc.a) * dc.r); - dc.g = (double)(sc.a * sc.g + dc.a * (1.0 - sc.a) * dc.g); - dc.b = (double)(sc.a * sc.b + dc.a * (1.0 - sc.a) * dc.b); - dc.a = (double)(sc.a + dc.a * (1.0 - sc.a)); - set_pixel(dst_x, dst_y, dc); + if (sc.a != 0) { + Color dc = get_pixel(dst_x, dst_y); + dc = dc.blend(sc); + set_pixel(dst_x, dst_y, dc); + } } } } @@ -3020,6 +3019,7 @@ void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("load", "path"), &Image::load); ClassDB::bind_method(D_METHOD("save_png", "path"), &Image::save_png); + ClassDB::bind_method(D_METHOD("save_png_to_buffer"), &Image::save_png_to_buffer); ClassDB::bind_method(D_METHOD("save_exr", "path", "grayscale"), &Image::save_exr, DEFVAL(false)); ClassDB::bind_method(D_METHOD("detect_alpha"), &Image::detect_alpha); diff --git a/core/input/gamecontrollerdb.txt b/core/input/gamecontrollerdb.txt index 90d309c1c8..7b5abdd61b 100644 --- a/core/input/gamecontrollerdb.txt +++ b/core/input/gamecontrollerdb.txt @@ -4,37 +4,38 @@ # Windows 03000000fa2d00000100000000000000,3DRUDDER,leftx:a0,lefty:a1,rightx:a5,righty:a2,platform:Windows, 03000000c82d00002038000000000000,8bitdo,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, -03000000c82d000011ab000000000000,8BitDo F30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d000011ab000000000000,8BitDo F30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00001038000000000000,8BitDo F30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000090000000000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000650000000000000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows, 03000000c82d00000310000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows, 03000000c82d00002028000000000000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00008010000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows, -03000000c82d00000190000000000000,8BitDo N30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, -03000000c82d00001590000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, -03000000c82d00006528000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000190000000000000,8BitDo N30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00001590000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00006528000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00015900000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00065280000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, 03000000022000000090000000000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, 03000000203800000900000000000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000130000000000000,8BitDo SF30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, -03000000c82d00000060000000000000,8Bitdo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, -03000000c82d00000061000000000000,8Bitdo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000060000000000000,8Bitdo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000061000000000000,8Bitdo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d000021ab000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, 03000000102800000900000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00003028000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000030000000000000,8BitDo SN30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000351000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, -03000000c82d00001290000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00001290000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d000020ab000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00004028000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, -03000000c82d00006228000000000000,8BitDo SN30 GP,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, -03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, -03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00006228000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000260000000000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000261000000000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000031000000000000,8BitDo Wireless Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00003032000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, 03000000a00500003232000000000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows, 030000008f0e00001200000000000000,Acme GA-02,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows, 03000000fa190000f0ff000000000000,Acteck AGJ-3200,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, @@ -73,6 +74,7 @@ 03000000260900008888000000000000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a4,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Windows, 03000000a306000022f6000000000000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows, 03000000451300000830000000000000,Defender Game Racer X7,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000007d0400000840000000000000,Destroyer Tiltpad,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,x:b0,y:b3,platform:Windows, 03000000791d00000103000000000000,Dual Box WII,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 03000000bd12000002e0000000000000,Dual USB Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows, 030000006f0e00003001000000000000,EA SPORTS PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, @@ -88,7 +90,6 @@ 030000000d0f00008800000000000000,Fighting Stick mini 4,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows, 030000000d0f00002700000000000000,FIGHTING STICK V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, 78696e70757403000000000000000000,Fightstick TES,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Windows, -03000000790000000600000000000000,G-Shark GS-GP702,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows, 03000000790000002201000000000000,Game Controller for PC,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 0300000066f700000100000000000000,Game VIB Joystick,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows, 03000000260900002625000000000000,Gamecube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,lefttrigger:a4,leftx:a0,lefty:a1,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Windows, @@ -98,6 +99,7 @@ 03000000ac0500004d04000000000000,GameSir,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 03000000ffff00000000000000000000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, 030000006f0e00000102000000007801,GameStop Xbox 360 Wired Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000009b2800003200000000000000,GC/N64 to USB v3.4,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows, 030000008305000009a0000000000000,Genius,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, 030000008305000031b0000000000000,Genius Maxfire Blaze 3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, 03000000451300000010000000000000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, @@ -146,6 +148,8 @@ 030000007e0500000720000000000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows, 030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows, 03000000bd12000003c0000000000000,JY-P70UR,a:b1,b:b0,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b11,righttrigger:b9,rightx:a3,righty:a2,start:b4,x:b3,y:b2,platform:Windows, +03000000242f00002d00000000000000,JYS Wireless Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000242f00008a00000000000000,JYS Wireless Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows, 03000000790000000200000000000000,King PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows, 030000006d040000d1ca000000000000,Logitech ChillStream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000006d040000d2ca000000000000,Logitech Cordless Precision,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, @@ -302,6 +306,7 @@ 03000000790000001a18000000000000,Venom,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000790000001b18000000000000,Venom Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, 030000006f0e00000302000000000000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +0300000034120000adbe000000000000,vJoy Device,a:b0,b:b1,back:b15,dpdown:b6,dpleft:b7,dpright:b8,dpup:b5,guide:b16,leftshoulder:b9,leftstick:b13,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b14,righttrigger:b12,rightx:+a3,righty:+a4,start:b4,x:b2,y:b3,platform:Windows, 030000005e0400000a0b000000000000,Xbox Adaptive Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000341a00000608000000000000,Xeox,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, 03000000450c00002043000000000000,XEOX Gamepad SL-6556-BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, @@ -310,7 +315,7 @@ 03000000786901006e70000000000000,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000790000004f18000000000000,ZD-T Android,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, -03000000c82d00003032000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, +030000009b2800006000000000000000,GC/N64 to USB v3.6,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows, # Mac OS X 030000008f0e00000300000009010000,2In1 USB Joystick,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, @@ -330,7 +335,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000008305000031b0000000000000,Cideko AK08b,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Mac OS X, 03000000a306000022f6000001030000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X, -03000000790000000600000000000000,G-Shark GP-702,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Mac OS X, 03000000ad1b000001f9000000000000,Gamestop BB-070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, 030000006f0e00000102000000000000,GameStop Xbox 360 Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, @@ -351,6 +355,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000830500006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X, 030000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Mac OS X, 030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Mac OS X, +03000000242f00002d00000007010000,JYS Wireless Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, 030000006d04000016c2000000020000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 030000006d04000016c2000000030000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 030000006d04000016c2000014040000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, @@ -406,6 +411,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 0300000000f00000f100000000000000,SNES RetroPort,a:b2,b:b3,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,rightshoulder:b7,start:b6,x:b0,y:b1,platform:Mac OS X, 030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, 030000004c050000a00b000000000000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000d11800000094000000010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X, 030000005e0400008e02000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 03000000110100002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,platform:Mac OS X, 03000000110100002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X, @@ -455,12 +461,13 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000c82d00000160000011010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, 03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux, 03000000c82d00001290000011010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux, -05000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, 05000000c82d00006228000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, 03000000c82d00000260000011010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, 05000000c82d00000261000000010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, 030000005e0400008e02000020010000,8BitDo Wireless Adapter,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000c82d00000031000011010000,8BitDo Wireless Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, 05000000a00500003232000001000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux, 05000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux, 030000006f0e00001302000000010000,Afterglow,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, @@ -499,6 +506,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 06000000adde0000efbe000002010000,Hidromancer Game Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000d81400000862000011010000,HitBox (PS3/PC) Analog Mode,a:b1,b:b2,back:b8,guide:b9,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,y:b3,platform:Linux, 03000000c9110000f055000011010000,HJC Game GAMEPAD,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +03000000632500002605000010010000,HJD-X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 030000000d0f00000d00000000010000,hori,a:b0,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftx:b4,lefty:b5,rightshoulder:b7,start:b9,x:b1,y:b2,platform:Linux, 030000000d0f00001000000011010000,HORI CO. LTD. FIGHTING STICK 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, 030000000d0f0000c100000011010000,HORI CO. LTD. HORIPAD S,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, @@ -529,6 +537,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 050000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Linux, 030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Linux, 050000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Linux, +03000000242f00002d00000011010000,JYS Wireless Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000242f00008a00000011010000,JYS Wireless Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux, 030000006f0e00000103000000020000,Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000006d04000016c2000010010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, @@ -581,6 +591,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000250900006688000000010000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux, 030000000d0f00000900000010010000,Natec Genesis P44,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Linux, +060000007e0500000820000000000000,Nintendo Combined Joy-Cons (joycond),a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, +050000007e0500000920000001800000,Nintendo Switch Pro Controller (joycond),a:b0,b:b1,x:b3,y:b2,back:b9,guide:b11,start:b10,leftstick:b12,rightstick:b13,leftshoulder:b5,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b7,righttrigger:b8,platform:Linux, +030000007e0500000920000011810000,Nintendo Switch Pro Controller Wired (joycond),a:b0,b:b1,x:b3,y:b2,back:b9,guide:b11,start:b10,leftstick:b12,rightstick:b13,leftshoulder:b5,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b7,righttrigger:b8,platform:Linux, 030000007e0500003703000000016800,Nintendo GameCube Controller,a:b0,b:b2,dpdown:b6,dpleft:b4,dpright:b5,dpup:b7,lefttrigger:a4,leftx:a0,lefty:a1~,rightshoulder:b9,righttrigger:a5,rightx:a2,righty:a3~,start:b8,x:b1,y:b3,platform:Linux, 050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 050000007e0500003003000001000000,Nintendo Wii Remote Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux, @@ -593,9 +606,11 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000005e0400000202000000010000,Old Xbox pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux, 05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux, 05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux, +03000000830500005020000010010000,Padix Co. Ltd. Rockfire PSX/USB Bridge,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,platform:Linux, 03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, 030000006f0e00006401000001010000,PDP Battlefield One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006f0e00003101000000010000,PDP EA Sports Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e0000c802000012010000,PDP Kingdom Hearts Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006f0e0000a802000023020000,PDP Wired Controller for Xbox One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 030000004c050000da0c000011010000,Playstation Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, 03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, @@ -629,6 +644,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 050000004c050000cc09000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, 050000004c050000cc09000001800000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, 03000000300f00001211000011010000,QanBa Arcade JoyStick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,platform:Linux, +030000009b2800003200000001010000,Raphnet Technologies GC/N64 to USB v3.4,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux, 030000009b2800000300000001010000,raphnet.net 4nes4snes v1.5,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux, 030000008916000001fd000024010000,Razer Onza Classic Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000008916000000fd000024010000,Razer Onza Tournament Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, @@ -650,9 +666,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000006f0e00001e01000011010000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000006f0e00004601000001010000,Rock Candy Xbox One Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux, +03000000a30600001005000000010000,Saitek Saitek P150,platform:Linux,a:b0,b:b1,y:b4,x:b3,leftshoulder:b7,rightshoulder:b2,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,lefttrigger:b6,righttrigger:b5, 03000000a30600000cff000010010000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,platform:Linux, 03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b12,x:b0,y:b3,platform:Linux, -03000000300f00001201000010010000,Saitek P380,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a1,righty:a2,start:b9,x:b0,y:b1,platform:Linux, +03000000300f00001201000010010000,Saitek P380,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux, 03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,platform:Linux, 03000000a30600000b04000000010000,Saitek P990 Dual Analog Pad,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Linux, 03000000a306000018f5000010010000,Saitek PLC Saitek P3200 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux, @@ -667,6 +684,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux, 030000005e0400008e02000073050000,Speedlink TORID Wireless Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d11800000094000011010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, 03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, 03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, 03000000de2800004211000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, @@ -679,16 +697,21 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000381000003114000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 05000000110100001914000009010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 03000000ad1b000038f0000090040000,Street Fighter IV FightStick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000003b07000004a1000000010000,Suncom SFX Plus for USB,a:b0,b:b2,x:b1,y:b3,back:b7,start:b8,leftshoulder:b6,rightshoulder:b9,leftx:a0,lefty:a1,lefttrigger:b4,righttrigger:b5,platform:Linux, 03000000666600000488000000010000,Super Joy Box 5 Pro,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux, 0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux, +03000000457500002211000010010000,SZMY-POWER CO. LTD. GAMEPAD,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000008f0e00000d31000010010000,SZMY-POWER CO. LTD. GAMEPAD 3 TURBO,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux, 030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux, 030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000b50700000399000000010000,Thrustmaster Firestorm Digital 2,a:b2,b:b4,x:b3,y:b5,back:b11,start:b1,leftstick:b10,rightstick:b0,leftshoulder:b6,rightshoulder:b8,leftx:a0,lefty:a1,lefttrigger:b7,righttrigger:b9,platform:Linux, 030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Linux, 030000004f04000026b3000002040000,Thrustmaster Gamepad GP XID,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000c6240000025b000002020000,Thrustmaster GPX Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, 030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000004f04000007d0000000010000,Thrustmaster T Mini Wireless,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000004f04000012b3000010010000,Thrustmaster vibrating gamepad,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux, 03000000bd12000015d0000010010000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux, 03000000d814000007cd000011010000,Toodles 2008 Chimp PC/PS3,a:b0,b:b1,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux, @@ -721,8 +744,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 05000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux, 03000000c0160000e105000001010000,Xin-Mo Xin-Mo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux, xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -05000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, 03000000120c0000100e000011010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000005e0400008e02000000010000,xbox360 Wireless EasySMX,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, +030000009b2800006000000001010000,Raphnet Technologies GC/N64 to USB v3.6,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux, # Android 05000000bc20000000550000ffff3f00,GameSir G3w,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, @@ -748,6 +772,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 050000005e040000fd020000ffff3f00,Xbox One Wireless Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 050000005e04000091020000ff073f00,Xbox Wireless Controller,a:b0,b:b1,back:b4,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android, 34356136633366613530316338376136,Xbox Wireless Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,x:b17,y:b2,platform:Android, +7573622067616d657061642020202020,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Android, # iOS 05000000ac0500000100000000006d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,platform:iOS, diff --git a/core/input/input.cpp b/core/input/input.cpp index dc1c207524..4d152c1ac4 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -339,7 +339,7 @@ float Input::get_joy_axis(int p_device, int p_axis) const { String Input::get_joy_name(int p_idx) { _THREAD_SAFE_METHOD_ return joy_names[p_idx].name; -}; +} Vector2 Input::get_joy_vibration_strength(int p_device) { if (joy_vibration.has(p_device)) { @@ -374,7 +374,7 @@ static String _hex_str(uint8_t p_byte) { ret[1] = dict[p_byte & 0xf]; return ret; -}; +} void Input::joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid) { _THREAD_SAFE_METHOD_ @@ -388,8 +388,8 @@ void Input::joy_connection_changed(int p_idx, bool p_connected, String p_name, S int uidlen = MIN(p_name.length(), 16); for (int i = 0; i < uidlen; i++) { uidname = uidname + _hex_str(p_name[i]); - }; - }; + } + } js.uid = uidname; js.connected = true; int mapping = fallback_mapping; @@ -397,8 +397,8 @@ void Input::joy_connection_changed(int p_idx, bool p_connected, String p_name, S if (js.uid == map_db[i].uid) { mapping = i; js.name = map_db[i].name; - }; - }; + } + } js.mapping = mapping; } else { js.connected = false; @@ -409,11 +409,11 @@ void Input::joy_connection_changed(int p_idx, bool p_connected, String p_name, S for (int i = 0; i < JOY_AXIS_MAX; i++) { set_joy_axis(p_idx, i, 0.0f); } - }; + } joy_names[p_idx] = js; emit_signal("joy_connection_changed", p_idx, p_connected); -}; +} Vector3 Input::get_gravity() const { _THREAD_SAFE_METHOD_ @@ -918,7 +918,7 @@ void Input::joy_axis(int p_device, int p_axis, const JoyAxis &p_value) { if (joy.mapping == -1) { _axis_event(p_device, p_axis, val); return; - }; + } JoyEvent map = _get_mapped_axis_event(map_db[joy.mapping], p_axis, p_value); @@ -1003,7 +1003,7 @@ void Input::joy_hat(int p_device, int p_val) { if (joy.mapping != -1) { _get_mapped_hat_events(map_db[joy.mapping], 0, map); - }; + } int cur_val = joy_names[p_device].hat_current; @@ -1042,7 +1042,7 @@ void Input::_axis_event(int p_device, int p_axis, float p_value) { ievent->set_axis_value(p_value); parse_input_event(ievent); -}; +} Input::JoyEvent Input::_get_mapped_button_event(const JoyDeviceMapping &mapping, int p_button) { JoyEvent event; @@ -1274,10 +1274,10 @@ void Input::parse_mapping(String p_mapping) { } mapping.bindings.push_back(binding); - }; + } map_db.push_back(mapping); -}; +} void Input::add_joy_mapping(String p_mapping, bool p_update_existing) { parse_mapping(p_mapping); diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp index 3cb4b43a26..ac032b7d10 100644 --- a/core/input/input_map.cpp +++ b/core/input/input_map.cpp @@ -48,7 +48,7 @@ void InputMap::_bind_methods() { ClassDB::bind_method(D_METHOD("action_has_event", "action", "event"), &InputMap::action_has_event); ClassDB::bind_method(D_METHOD("action_erase_event", "action", "event"), &InputMap::action_erase_event); ClassDB::bind_method(D_METHOD("action_erase_events", "action"), &InputMap::action_erase_events); - ClassDB::bind_method(D_METHOD("get_action_list", "action"), &InputMap::_get_action_list); + ClassDB::bind_method(D_METHOD("action_get_events", "action"), &InputMap::_action_get_events); ClassDB::bind_method(D_METHOD("event_is_action", "event", "action"), &InputMap::event_is_action); ClassDB::bind_method(D_METHOD("load_from_globals"), &InputMap::load_from_globals); } @@ -152,9 +152,9 @@ void InputMap::action_erase_events(const StringName &p_action) { input_map[p_action].inputs.clear(); } -Array InputMap::_get_action_list(const StringName &p_action) { +Array InputMap::_action_get_events(const StringName &p_action) { Array ret; - const List<Ref<InputEvent>> *al = get_action_list(p_action); + const List<Ref<InputEvent>> *al = action_get_events(p_action); if (al) { for (const List<Ref<InputEvent>>::Element *E = al->front(); E; E = E->next()) { ret.push_back(E->get()); @@ -164,7 +164,7 @@ Array InputMap::_get_action_list(const StringName &p_action) { return ret; } -const List<Ref<InputEvent>> *InputMap::get_action_list(const StringName &p_action) { +const List<Ref<InputEvent>> *InputMap::action_get_events(const StringName &p_action) { const Map<StringName, Action>::Element *E = input_map.find(p_action); if (!E) { return nullptr; diff --git a/core/input/input_map.h b/core/input/input_map.h index 3abc224ccf..548553ed31 100644 --- a/core/input/input_map.h +++ b/core/input/input_map.h @@ -56,7 +56,7 @@ private: List<Ref<InputEvent>>::Element *_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool *p_pressed = nullptr, float *p_strength = nullptr) const; - Array _get_action_list(const StringName &p_action); + Array _action_get_events(const StringName &p_action); Array _get_actions(); protected: @@ -76,7 +76,7 @@ public: void action_erase_event(const StringName &p_action, const Ref<InputEvent> &p_event); void action_erase_events(const StringName &p_action); - const List<Ref<InputEvent>> *get_action_list(const StringName &p_action); + const List<Ref<InputEvent>> *action_get_events(const StringName &p_action); bool event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action) const; bool event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool *p_pressed = nullptr, float *p_strength = nullptr) const; diff --git a/core/io/dtls_server.cpp b/core/io/dtls_server.cpp index 0278027c50..e43b1f5385 100644 --- a/core/io/dtls_server.cpp +++ b/core/io/dtls_server.cpp @@ -37,7 +37,10 @@ DTLSServer *(*DTLSServer::_create)() = nullptr; bool DTLSServer::available = false; DTLSServer *DTLSServer::create() { - return _create(); + if (_create) { + return _create(); + } + return nullptr; } bool DTLSServer::is_available() { diff --git a/core/io/file_access_buffered.h b/core/io/file_access_buffered.h index 61c0fa7489..99d5ce903d 100644 --- a/core/io/file_access_buffered.h +++ b/core/io/file_access_buffered.h @@ -51,16 +51,16 @@ protected: Error set_error(Error p_error) const; mutable struct File { - bool open; - int size; - int offset; + bool open = false; + int size = 0; + int offset = 0; String name; - int access_flags; + int access_flags = 0; } file; mutable struct Cache { Vector<uint8_t> buffer; - int offset; + int offset = 0; } cache; virtual int read_data_block(int p_offset, int p_size, uint8_t *p_dest = nullptr) const = 0; diff --git a/core/io/file_access_buffered_fa.h b/core/io/file_access_buffered_fa.h index 3ea98584a4..f22e54e154 100644 --- a/core/io/file_access_buffered_fa.h +++ b/core/io/file_access_buffered_fa.h @@ -58,35 +58,35 @@ class FileAccessBufferedFA : public FileAccessBuffered { f.get_buffer(cache.buffer.ptrw(), p_size); return p_size; - }; - }; + } + } static FileAccess *create() { return memnew(FileAccessBufferedFA<T>()); - }; + } protected: virtual void _set_access_type(AccessType p_access) { f._set_access_type(p_access); FileAccessBuffered::_set_access_type(p_access); - }; + } public: void flush() { f.flush(); - }; + } void store_8(uint8_t p_dest) { f.store_8(p_dest); - }; + } void store_buffer(const uint8_t *p_src, int p_length) { f.store_buffer(p_src, p_length); - }; + } bool file_exists(const String &p_name) { return f.file_exists(p_name); - }; + } Error _open(const String &p_path, int p_mode_flags) { close(); @@ -106,7 +106,7 @@ public: cache.offset = 0; return set_error(OK); - }; + } void close() { f.close(); @@ -119,7 +119,7 @@ public: cache.buffer.resize(0); cache.offset = 0; set_error(OK); - }; + } virtual uint64_t _get_modified_time(const String &p_file) { return f._get_modified_time(p_file); diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp index 3c5f846941..a65ff92a89 100644 --- a/core/io/file_access_memory.cpp +++ b/core/io/file_access_memory.cpp @@ -145,7 +145,7 @@ int FileAccessMemory::get_buffer(uint8_t *p_dst, int p_length) const { if (read < p_length) { WARN_PRINT("Reading less data than requested"); - }; + } copymem(p_dst, &data[pos], read); pos += p_length; diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp index 00c4e76efe..37240f234a 100644 --- a/core/io/file_access_pack.cpp +++ b/core/io/file_access_pack.cpp @@ -38,11 +38,11 @@ Error PackedData::add_pack(const String &p_path, bool p_replace_files) { for (int i = 0; i < sources.size(); i++) { if (sources[i]->try_open_pack(p_path, p_replace_files)) { return OK; - }; - }; + } + } return ERR_FILE_UNRECOGNIZED; -}; +} void PackedData::add_path(const String &pkg_path, const String &path, uint64_t ofs, uint64_t size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files) { PathMD5 pmd5(path.md5_buffer()); @@ -96,7 +96,7 @@ void PackedData::add_pack_source(PackSource *p_source) { if (p_source != nullptr) { sources.push_back(p_source); } -}; +} PackedData *PackedData::singleton = nullptr; @@ -192,16 +192,16 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files) uint8_t md5[16]; f->get_buffer(md5, 16); PackedData::get_singleton()->add_path(p_path, path, ofs, size, md5, this, p_replace_files); - }; + } f->close(); memdelete(f); return true; -}; +} FileAccess *PackedSourcePCK::get_file(const String &p_path, PackedData::PackedFile *p_file) { return memnew(FileAccessPack(p_path, *p_file)); -}; +} ////////////////////////////////////////////////////////////////// diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h index 320a6cb216..348bc0c450 100644 --- a/core/io/file_access_pack.h +++ b/core/io/file_access_pack.h @@ -79,7 +79,7 @@ private: bool operator==(const PathMD5 &p_md5) const { return a == p_md5.a && b == p_md5.b; - }; + } PathMD5() {} diff --git a/core/io/ip.cpp b/core/io/ip.cpp index 653959b393..24b8ec7cc1 100644 --- a/core/io/ip.cpp +++ b/core/io/ip.cpp @@ -54,7 +54,7 @@ struct _IP_ResolverPrivate { QueueItem() { clear(); - }; + } }; QueueItem queue[IP::RESOLVER_MAX_QUERIES]; diff --git a/core/io/ip_address.cpp b/core/io/ip_address.cpp index 89b317bf93..c7a0ae5605 100644 --- a/core/io/ip_address.cpp +++ b/core/io/ip_address.cpp @@ -58,7 +58,7 @@ IP_Address::operator String() const { } uint16_t num = (field8[i * 2] << 8) + field8[i * 2 + 1]; ret = ret + String::num_int64(num, 16); - }; + } return ret; } @@ -68,7 +68,7 @@ static void _parse_hex(const String &p_string, int p_start, uint8_t *p_dst) { for (int i = p_start; i < p_start + 4; i++) { if (i >= p_string.length()) { break; - }; + } int n = 0; CharType c = p_string[i]; @@ -82,14 +82,14 @@ static void _parse_hex(const String &p_string, int p_start, uint8_t *p_dst) { break; } else { ERR_FAIL_MSG("Invalid character in IPv6 address: " + p_string + "."); - }; + } ret = ret << 4; ret += n; - }; + } p_dst[0] = ret >> 8; p_dst[1] = ret & 0xff; -}; +} void IP_Address::_parse_ipv6(const String &p_string) { static const int parts_total = 8; @@ -105,11 +105,11 @@ void IP_Address::_parse_ipv6(const String &p_string) { if (c == ':') { if (i == 0) { continue; // next must be a ":" - }; + } if (!part_found) { part_skip = true; parts[parts_idx++] = -1; - }; + } part_found = false; } else if (c == '.') { part_ipv4 = true; @@ -119,33 +119,33 @@ void IP_Address::_parse_ipv6(const String &p_string) { parts[parts_idx++] = i; part_found = true; ++parts_count; - }; + } } else { ERR_FAIL_MSG("Invalid character in IPv6 address: " + p_string + "."); - }; - }; + } + } int parts_extra = 0; if (part_skip) { parts_extra = parts_total - parts_count; - }; + } int idx = 0; for (int i = 0; i < parts_idx; i++) { if (parts[i] == -1) { for (int j = 0; j < parts_extra; j++) { field16[idx++] = 0; - }; + } continue; - }; + } if (part_ipv4 && i == parts_idx - 1) { _parse_ipv4(p_string, parts[i], (uint8_t *)&field16[idx]); // should be the last one } else { _parse_hex(p_string, parts[i], (uint8_t *)&(field16[idx++])); - }; - }; -}; + } + } +} void IP_Address::_parse_ipv4(const String &p_string, int p_start, uint8_t *p_ret) { String ip; @@ -153,20 +153,20 @@ void IP_Address::_parse_ipv4(const String &p_string, int p_start, uint8_t *p_ret ip = p_string.substr(p_start, p_string.length() - p_start); } else { ip = p_string; - }; + } int slices = ip.get_slice_count("."); ERR_FAIL_COND_MSG(slices != 4, "Invalid IP address string: " + ip + "."); for (int i = 0; i < 4; i++) { p_ret[i] = ip.get_slicec('.', i).to_int(); } -}; +} void IP_Address::clear() { memset(&field8[0], 0, sizeof(field8)); valid = false; wildcard = false; -}; +} bool IP_Address::is_ipv4() const { return (field32[0] == 0 && field32[1] == 0 && field16[4] == 0 && field16[5] == 0xffff); @@ -224,7 +224,7 @@ _FORCE_INLINE_ static void _32_to_buf(uint8_t *p_dst, uint32_t p_n) { p_dst[1] = (p_n >> 16) & 0xff; p_dst[2] = (p_n >> 8) & 0xff; p_dst[3] = (p_n >> 0) & 0xff; -}; +} IP_Address::IP_Address(uint32_t p_a, uint32_t p_b, uint32_t p_c, uint32_t p_d, bool is_v6) { clear(); diff --git a/core/io/json.cpp b/core/io/json.cpp index 03f4e65220..1c603865ad 100644 --- a/core/io/json.cpp +++ b/core/io/json.cpp @@ -91,7 +91,7 @@ String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_ } s += end_statement + _make_indent(p_indent, p_cur_indent) + "]"; return s; - }; + } case Variant::DICTIONARY: { String s = "{"; s += end_statement; @@ -115,7 +115,7 @@ String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_ s += end_statement + _make_indent(p_indent, p_cur_indent) + "}"; return s; - }; + } default: return "\"" + String(p_var).json_escape() + "\""; } @@ -132,7 +132,7 @@ Error JSON::_get_token(const CharType *p_str, int &index, int p_len, Token &r_to line++; index++; break; - }; + } case 0: { r_token.type = TK_EOF; return OK; @@ -141,32 +141,32 @@ Error JSON::_get_token(const CharType *p_str, int &index, int p_len, Token &r_to r_token.type = TK_CURLY_BRACKET_OPEN; index++; return OK; - }; + } case '}': { r_token.type = TK_CURLY_BRACKET_CLOSE; index++; return OK; - }; + } case '[': { r_token.type = TK_BRACKET_OPEN; index++; return OK; - }; + } case ']': { r_token.type = TK_BRACKET_CLOSE; index++; return OK; - }; + } case ':': { r_token.type = TK_COLON; index++; return OK; - }; + } case ',': { r_token.type = TK_COMMA; index++; return OK; - }; + } case '"': { index++; String str; diff --git a/core/io/marshalls.h b/core/io/marshalls.h index c21a97ac8a..c8ed497528 100644 --- a/core/io/marshalls.h +++ b/core/io/marshalls.h @@ -106,7 +106,7 @@ static inline int encode_cstring(const char *p_string, uint8_t *p_data) { } p_string++; len++; - }; + } if (p_data) { *p_data = 0; diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp index 6d37d95994..dacd548a3e 100644 --- a/core/io/packet_peer.cpp +++ b/core/io/packet_peer.cpp @@ -147,7 +147,7 @@ void PacketPeer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_encode_buffer_max_size", "max_size"), &PacketPeer::set_encode_buffer_max_size); ADD_PROPERTY(PropertyInfo(Variant::INT, "encode_buffer_max_size"), "set_encode_buffer_max_size", "get_encode_buffer_max_size"); -}; +} /***************/ @@ -267,7 +267,7 @@ void PacketPeerStream::set_stream_peer(const Ref<StreamPeer> &p_peer) { if (p_peer.ptr() != peer.ptr()) { ring_buffer.advance_read(ring_buffer.data_left()); // reset the ring buffer - }; + } peer = p_peer; } diff --git a/core/io/packet_peer_dtls.cpp b/core/io/packet_peer_dtls.cpp index 67579c339a..632f86a9f6 100644 --- a/core/io/packet_peer_dtls.cpp +++ b/core/io/packet_peer_dtls.cpp @@ -36,7 +36,10 @@ PacketPeerDTLS *(*PacketPeerDTLS::_create)() = nullptr; bool PacketPeerDTLS::available = false; PacketPeerDTLS *PacketPeerDTLS::create() { - return _create(); + if (_create) { + return _create(); + } + return nullptr; } bool PacketPeerDTLS::is_available() { diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp index 06d22ce897..374b2a5e07 100644 --- a/core/io/pck_packer.cpp +++ b/core/io/pck_packer.cpp @@ -45,19 +45,19 @@ static uint64_t _align(uint64_t p_n, int p_alignment) { } else { return p_n + (p_alignment - rest); } -}; +} static void _pad(FileAccess *p_file, int p_bytes) { for (int i = 0; i < p_bytes; i++) { p_file->store_8(0); - }; -}; + } +} void PCKPacker::_bind_methods() { ClassDB::bind_method(D_METHOD("pck_start", "pck_name", "alignment"), &PCKPacker::pck_start, DEFVAL(0)); ClassDB::bind_method(D_METHOD("add_file", "pck_path", "source_path"), &PCKPacker::add_file); ClassDB::bind_method(D_METHOD("flush", "verbose"), &PCKPacker::flush, DEFVAL(false)); -}; +} Error PCKPacker::pck_start(const String &p_file, int p_alignment) { if (file != nullptr) { @@ -78,18 +78,18 @@ Error PCKPacker::pck_start(const String &p_file, int p_alignment) { for (int i = 0; i < 16; i++) { file->store_32(0); // reserved - }; + } files.clear(); return OK; -}; +} Error PCKPacker::add_file(const String &p_file, const String &p_src) { FileAccess *f = FileAccess::open(p_src, FileAccess::READ); if (!f) { return ERR_FILE_CANT_OPEN; - }; + } File pf; pf.path = p_file; @@ -103,7 +103,7 @@ Error PCKPacker::add_file(const String &p_file, const String &p_src) { memdelete(f); return OK; -}; +} Error PCKPacker::flush(bool p_verbose) { ERR_FAIL_COND_V_MSG(!file, ERR_INVALID_PARAMETER, "File must be opened before use."); @@ -123,7 +123,7 @@ Error PCKPacker::flush(bool p_verbose) { file->store_32(0); file->store_32(0); file->store_32(0); - }; + } uint64_t ofs = file->get_position(); ofs = _align(ofs, alignment); @@ -141,7 +141,7 @@ Error PCKPacker::flush(bool p_verbose) { int read = src->get_buffer(buf, MIN(to_write, buf_max)); file->store_buffer(buf, read); to_write -= read; - }; + } uint64_t pos = file->get_position(); file->seek(files[i].offset_offset); // go back to store the file's offset @@ -158,9 +158,9 @@ Error PCKPacker::flush(bool p_verbose) { if (count % 100 == 0) { printf("%i/%i (%.2f)\r", count, files.size(), float(count) / files.size() * 100); fflush(stdout); - }; - }; - }; + } + } + } if (p_verbose) { printf("\n"); @@ -170,11 +170,11 @@ Error PCKPacker::flush(bool p_verbose) { memdelete_arr(buf); return OK; -}; +} PCKPacker::~PCKPacker() { if (file != nullptr) { memdelete(file); - }; + } file = nullptr; -}; +} diff --git a/core/io/xml_parser.cpp b/core/io/xml_parser.cpp index 11f82fef9d..b11267b60f 100644 --- a/core/io/xml_parser.cpp +++ b/core/io/xml_parser.cpp @@ -361,7 +361,7 @@ void XMLParser::_parse_current_node() { uint64_t XMLParser::get_node_offset() const { return node_offset; -}; +} Error XMLParser::seek(uint64_t p_pos) { ERR_FAIL_COND_V(!data, ERR_FILE_EOF); @@ -370,7 +370,7 @@ Error XMLParser::seek(uint64_t p_pos) { P = data + p_pos; return read(); -}; +} void XMLParser::_bind_methods() { ClassDB::bind_method(D_METHOD("read"), &XMLParser::read); @@ -398,7 +398,7 @@ void XMLParser::_bind_methods() { BIND_ENUM_CONSTANT(NODE_COMMENT); BIND_ENUM_CONSTANT(NODE_CDATA); BIND_ENUM_CONSTANT(NODE_UNKNOWN); -}; +} Error XMLParser::read() { // if not end reached, parse the node diff --git a/core/io/zip_io.cpp b/core/io/zip_io.cpp index 1979e91b8c..b8e7fd34d0 100644 --- a/core/io/zip_io.cpp +++ b/core/io/zip_io.cpp @@ -80,7 +80,7 @@ long zipio_seek(voidpf opaque, voidpf stream, uLong offset, int origin) { break; default: break; - }; + } f->seek(pos); return 0; diff --git a/core/list.h b/core/list.h index 86e4a45036..6052a619fb 100644 --- a/core/list.h +++ b/core/list.h @@ -63,70 +63,70 @@ public: */ _FORCE_INLINE_ const Element *next() const { return next_ptr; - }; + } /** * Get NEXT Element iterator, */ _FORCE_INLINE_ Element *next() { return next_ptr; - }; + } /** * Get PREV Element iterator, for constant lists. */ _FORCE_INLINE_ const Element *prev() const { return prev_ptr; - }; + } /** * Get PREV Element iterator, */ _FORCE_INLINE_ Element *prev() { return prev_ptr; - }; + } /** * * operator, for using as *iterator, when iterators are defined on stack. */ _FORCE_INLINE_ const T &operator*() const { return value; - }; + } /** * operator->, for using as iterator->, when iterators are defined on stack, for constant lists. */ _FORCE_INLINE_ const T *operator->() const { return &value; - }; + } /** * * operator, for using as *iterator, when iterators are defined on stack, */ _FORCE_INLINE_ T &operator*() { return value; - }; + } /** * operator->, for using as iterator->, when iterators are defined on stack, for constant lists. */ _FORCE_INLINE_ T *operator->() { return &value; - }; + } /** * get the value stored in this element. */ _FORCE_INLINE_ T &get() { return value; - }; + } /** * get the value stored in this element, for constant lists */ _FORCE_INLINE_ const T &get() const { return value; - }; + } /** * set the value stored in this element. */ _FORCE_INLINE_ void set(const T &p_value) { value = (T &)p_value; - }; + } void erase() { data->erase(this); @@ -147,7 +147,7 @@ private: if (first == p_I) { first = p_I->next_ptr; - }; + } if (last == p_I) { last = p_I->prev_ptr; @@ -176,28 +176,28 @@ public: */ _FORCE_INLINE_ const Element *front() const { return _data ? _data->first : nullptr; - }; + } /** * 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. */ _FORCE_INLINE_ const Element *back() const { return _data ? _data->last : nullptr; - }; + } /** * return an iterator to the last member of the list. */ _FORCE_INLINE_ Element *back() { return _data ? _data->last : nullptr; - }; + } /** * store a new element at the end of the list @@ -230,7 +230,7 @@ public: _data->size_cache++; return n; - }; + } void pop_back() { if (_data && _data->last) { @@ -268,7 +268,7 @@ public: _data->size_cache++; return n; - }; + } void pop_front() { if (_data && _data->first) { @@ -339,10 +339,10 @@ public: return it; } it = it->next(); - }; + } return nullptr; - }; + } /** * erase an element in the list, by iterator pointing to it. Return true if it was found/erased. @@ -360,7 +360,7 @@ public: } return false; - }; + } /** * erase the first element in the list, that contains value @@ -368,7 +368,7 @@ public: bool erase(const T &value) { Element *I = find(value); return erase(I); - }; + } /** * return whether the list is empty @@ -383,8 +383,8 @@ public: void clear() { while (front()) { erase(front()); - }; - }; + } + } _FORCE_INLINE_ int size() const { return _data ? _data->size_cache : 0; @@ -464,7 +464,7 @@ public: if (_data->first == p_I) { _data->first = p_I->next_ptr; - }; + } if (_data->last == p_I) { _data->last = p_I->prev_ptr; @@ -501,7 +501,7 @@ public: if (_data->first == p_I) { _data->first = p_I->next_ptr; - }; + } if (_data->last == p_I) { _data->last = p_I->prev_ptr; @@ -536,7 +536,7 @@ public: value->prev_ptr = _data->last; _data->last = value; return; - }; + } value->prev_ptr = where->prev_ptr; @@ -544,10 +544,10 @@ public: where->prev_ptr->next_ptr = value; } else { _data->first = value; - }; + } where->prev_ptr = value; - }; + } /** * simple insertion sort @@ -672,7 +672,7 @@ public: ERR_FAIL_COND(_data->size_cache); memdelete_allocator<_Data, A>(_data); } - }; + } }; #endif // LIST_H diff --git a/core/local_vector.h b/core/local_vector.h index c8abb32bf5..d97f3330dc 100644 --- a/core/local_vector.h +++ b/core/local_vector.h @@ -45,6 +45,14 @@ private: T *data = nullptr; public: + T *ptr() { + return data; + } + + const T *ptr() const { + return data; + } + _FORCE_INLINE_ void push_back(T p_elem) { if (unlikely(count == capacity)) { if (capacity == 0) { @@ -75,7 +83,7 @@ public: } void erase(const T &p_val) { - U idx = find(p_val); + int64_t idx = find(p_val); if (idx >= 0) { remove(idx); } @@ -185,8 +193,8 @@ public: for (i = 0; i < count; i++) { if (p_val < data[i]) { break; - }; - }; + } + } insert(i, p_val); } diff --git a/core/make_binders.py b/core/make_binders.py index 94bee95bfb..7d0d08cde6 100644 --- a/core/make_binders.py +++ b/core/make_binders.py @@ -75,7 +75,7 @@ public: #endif $ifret _set_returns(true); $ - }; + } }; template<class T $ifret ,class R$ $ifargs ,$ $arg, class P@$> @@ -170,7 +170,7 @@ public: $ifret _set_returns(true); $ - }; + } }; template<class T $ifret ,class R$ $ifargs ,$ $arg, class P@$> @@ -266,7 +266,7 @@ public: #endif $ifret _set_returns(true); $ - }; + } }; template<class T $ifret ,class R$ $ifargs ,$ $arg, class P@$> diff --git a/core/map.h b/core/map.h index 4861d6a026..fd4f500556 100644 --- a/core/map.h +++ b/core/map.h @@ -74,19 +74,19 @@ public: } const K &key() const { return _key; - }; + } V &value() { return _value; - }; + } const V &value() const { return _value; - }; + } V &get() { return _value; - }; + } const V &get() const { return _value; - }; + } Element() {} }; diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp index 45c4a207c3..30f712b2c3 100644 --- a/core/math/a_star.cpp +++ b/core/math/a_star.cpp @@ -30,7 +30,7 @@ #include "a_star.h" -#include "core/math/geometry.h" +#include "core/math/geometry_3d.h" #include "core/script_language.h" #include "scene/scene_string_names.h" @@ -280,10 +280,16 @@ int AStar::get_closest_point(const Vector3 &p_point, bool p_include_disabled) co continue; // Disabled points should not be considered. } + // Keep the closest point's ID, and in case of multiple closest IDs, + // the smallest one (makes it deterministic). real_t d = p_point.distance_squared_to((*it.value)->pos); - if (closest_id < 0 || d < closest_dist) { + int id = *(it.key); + if (d <= closest_dist) { + if (d == closest_dist && id > closest_id) { // Keep lowest ID. + continue; + } closest_dist = d; - closest_id = *(it.key); + closest_id = id; } } @@ -291,7 +297,6 @@ int AStar::get_closest_point(const Vector3 &p_point, bool p_include_disabled) co } Vector3 AStar::get_closest_position_in_segment(const Vector3 &p_point) const { - bool found = false; real_t closest_dist = 1e20; Vector3 closest_point; @@ -309,12 +314,11 @@ Vector3 AStar::get_closest_position_in_segment(const Vector3 &p_point) const { to_point->pos, }; - Vector3 p = Geometry::get_closest_point_to_segment(p_point, segment); + Vector3 p = Geometry3D::get_closest_point_to_segment(p_point, segment); real_t d = p_point.distance_squared_to(p); - if (!found || d < closest_dist) { + if (d < closest_dist) { closest_point = p; closest_dist = d; - found = true; } } diff --git a/core/math/aabb.h b/core/math/aabb.h index 9bbedfe59c..4106fbb93c 100644 --- a/core/math/aabb.h +++ b/core/math/aabb.h @@ -198,7 +198,7 @@ Vector3 AABB::get_endpoint(int p_point) const { return Vector3(position.x + size.x, position.y + size.y, position.z); case 7: return Vector3(position.x + size.x, position.y + size.y, position.z + size.z); - }; + } ERR_FAIL_V(Vector3()); } diff --git a/core/math/basis.cpp b/core/math/basis.cpp index cbfd09810c..dd38e25bb1 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -428,12 +428,9 @@ Vector3 Basis::get_euler_xyz() const { // -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy Vector3 euler; -#ifdef MATH_CHECKS - ERR_FAIL_COND_V(!is_rotation(), euler); -#endif real_t sy = elements[0][2]; - if (sy < 1.0) { - if (sy > -1.0) { + 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) @@ -446,12 +443,12 @@ Vector3 Basis::get_euler_xyz() const { euler.z = Math::atan2(-elements[0][1], elements[0][0]); } } else { - euler.x = -Math::atan2(elements[0][1], elements[1][1]); + 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[0][1], elements[1][1]); + euler.x = Math::atan2(elements[2][1], elements[1][1]); euler.y = Math_PI / 2.0; euler.z = 0.0; } @@ -481,15 +478,106 @@ void Basis::set_euler_xyz(const Vector3 &p_euler) { *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 { - /* checking this is a bad idea, because obtaining from scaled transform is a valid use case -#ifdef MATH_CHECKS - ERR_FAIL_COND(!is_rotation()); -#endif -*/ // Euler angles in YXZ convention. // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix // @@ -501,8 +589,8 @@ Vector3 Basis::get_euler_yxz() const { real_t m12 = elements[1][2]; - if (m12 < 1) { - if (m12 > -1) { + 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) @@ -516,12 +604,12 @@ Vector3 Basis::get_euler_yxz() const { } } else { // m12 == -1 euler.x = Math_PI * 0.5; - euler.y = -atan2(-elements[0][1], elements[0][0]); + 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.y = -atan2(elements[0][1], elements[0][0]); euler.z = 0; } @@ -551,6 +639,100 @@ void Basis::set_euler_yxz(const Vector3 &p_euler) { *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; + } + } 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 { return elements[0].is_equal_approx(p_basis.elements[0]) && elements[1].is_equal_approx(p_basis.elements[1]) && elements[2].is_equal_approx(p_basis.elements[2]); } @@ -591,7 +773,7 @@ Basis::operator String() const { mtx += ", "; } - mtx += rtos(elements[i][j]); + mtx += rtos(elements[j][i]); //matrix is stored transposed for performance, so print it transposed } } diff --git a/core/math/basis.h b/core/math/basis.h index d870a6b099..985fb0e44f 100644 --- a/core/math/basis.h +++ b/core/math/basis.h @@ -88,9 +88,22 @@ public: 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); + Quat get_quat() const; void set_quat(const Quat &p_quat); diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp index 81c602d8fe..22ab83f358 100644 --- a/core/math/camera_matrix.cpp +++ b/core/math/camera_matrix.cpp @@ -116,18 +116,18 @@ void CameraMatrix::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_ left = -xmax + frustumshift; right = xmax + frustumshift; modeltranslation = p_intraocular_dist / 2.0; - }; break; + } break; case 2: { // right eye left = -xmax - frustumshift; right = xmax - frustumshift; modeltranslation = -p_intraocular_dist / 2.0; - }; break; + } break; default: { // mono, should give the same result as set_perspective(p_fovy_degrees,p_aspect,p_z_near,p_z_far,p_flip_fov) left = -xmax; right = xmax; modeltranslation = 0.0; - }; break; - }; + } break; + } set_frustum(left, right, -ymax, ymax, p_z_near, p_z_far); @@ -157,14 +157,14 @@ void CameraMatrix::set_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_ switch (p_eye) { case 1: { // left eye set_frustum(-f2 * p_z_near, f1 * p_z_near, -f3 * p_z_near, f3 * p_z_near, p_z_near, p_z_far); - }; break; + } break; case 2: { // right eye set_frustum(-f1 * p_z_near, f2 * p_z_near, -f3 * p_z_near, f3 * p_z_near, p_z_near, p_z_far); - }; break; + } break; default: { // mono, does not apply here! - }; break; - }; -}; + } break; + } +} void CameraMatrix::set_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar) { set_identity(); diff --git a/core/math/expression.cpp b/core/math/expression.cpp index 81c1e7f564..6421606ca2 100644 --- a/core/math/expression.cpp +++ b/core/math/expression.cpp @@ -753,39 +753,39 @@ Error Expression::_get_token(Token &r_token) { case 0: { r_token.type = TK_EOF; return OK; - }; + } case '{': { r_token.type = TK_CURLY_BRACKET_OPEN; return OK; - }; + } case '}': { r_token.type = TK_CURLY_BRACKET_CLOSE; return OK; - }; + } case '[': { r_token.type = TK_BRACKET_OPEN; return OK; - }; + } case ']': { r_token.type = TK_BRACKET_CLOSE; return OK; - }; + } case '(': { r_token.type = TK_PARENTHESIS_OPEN; return OK; - }; + } case ')': { r_token.type = TK_PARENTHESIS_CLOSE; return OK; - }; + } case ',': { r_token.type = TK_COMMA; return OK; - }; + } case ':': { r_token.type = TK_COLON; return OK; - }; + } case '$': { r_token.type = TK_INPUT; int index = 0; @@ -803,7 +803,7 @@ Error Expression::_get_token(Token &r_token) { r_token.value = index; return OK; - }; + } case '=': { cchar = GET_CHAR(); if (cchar == '=') { @@ -814,7 +814,7 @@ Error Expression::_get_token(Token &r_token) { return ERR_PARSE_ERROR; } return OK; - }; + } case '!': { if (expression[str_ofs] == '=') { r_token.type = TK_OP_NOT_EQUAL; @@ -823,7 +823,7 @@ Error Expression::_get_token(Token &r_token) { r_token.type = TK_OP_NOT; } return OK; - }; + } case '>': { if (expression[str_ofs] == '=') { r_token.type = TK_OP_GREATER_EQUAL; @@ -835,7 +835,7 @@ Error Expression::_get_token(Token &r_token) { r_token.type = TK_OP_GREATER; } return OK; - }; + } case '<': { if (expression[str_ofs] == '=') { r_token.type = TK_OP_LESS_EQUAL; @@ -847,27 +847,27 @@ Error Expression::_get_token(Token &r_token) { r_token.type = TK_OP_LESS; } return OK; - }; + } case '+': { r_token.type = TK_OP_ADD; return OK; - }; + } case '-': { r_token.type = TK_OP_SUB; return OK; - }; + } case '/': { r_token.type = TK_OP_DIV; return OK; - }; + } case '*': { r_token.type = TK_OP_MUL; return OK; - }; + } case '%': { r_token.type = TK_OP_MOD; return OK; - }; + } case '&': { if (expression[str_ofs] == '&') { r_token.type = TK_OP_AND; @@ -876,7 +876,7 @@ Error Expression::_get_token(Token &r_token) { r_token.type = TK_OP_BIT_AND; } return OK; - }; + } case '|': { if (expression[str_ofs] == '|') { r_token.type = TK_OP_OR; @@ -885,17 +885,18 @@ Error Expression::_get_token(Token &r_token) { r_token.type = TK_OP_BIT_OR; } return OK; - }; + } case '^': { r_token.type = TK_OP_BIT_XOR; return OK; - }; + } case '~': { r_token.type = TK_OP_BIT_INVERT; return OK; - }; + } + case '\'': case '"': { String str; while (true) { @@ -905,7 +906,8 @@ Error Expression::_get_token(Token &r_token) { _set_error("Unterminated String"); r_token.type = TK_ERROR; return ERR_PARSE_ERROR; - } else if (ch == '"') { + } else if (ch == cchar) { + // cchar contain a corresponding quote symbol break; } else if (ch == '\\') { //escaped characters... @@ -1666,7 +1668,7 @@ Expression::ENode *Expression::_parse_expression() { op = Variant::OP_BIT_NEGATE; break; default: { - }; + } } if (op == Variant::OP_MAX) { //stop appending stuff diff --git a/core/math/face3.cpp b/core/math/face3.cpp index 6d76e116be..db2bfaa58b 100644 --- a/core/math/face3.cpp +++ b/core/math/face3.cpp @@ -30,7 +30,7 @@ #include "face3.h" -#include "core/math/geometry.h" +#include "core/math/geometry_3d.h" int Face3::split_by_plane(const Plane &p_plane, Face3 p_res[3], bool p_is_point_over[3]) const { ERR_FAIL_COND_V(is_degenerate(), 0); @@ -108,11 +108,11 @@ int Face3::split_by_plane(const Plane &p_plane, Face3 p_res[3], bool p_is_point_ } bool Face3::intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *p_intersection) const { - return Geometry::ray_intersects_triangle(p_from, p_dir, vertex[0], vertex[1], vertex[2], p_intersection); + return Geometry3D::ray_intersects_triangle(p_from, p_dir, vertex[0], vertex[1], vertex[2], p_intersection); } bool Face3::intersects_segment(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *p_intersection) const { - return Geometry::segment_intersects_triangle(p_from, p_dir, vertex[0], vertex[1], vertex[2], p_intersection); + return Geometry3D::segment_intersects_triangle(p_from, p_dir, vertex[0], vertex[1], vertex[2], p_intersection); } bool Face3::is_degenerate() const { diff --git a/core/math/geometry_2d.cpp b/core/math/geometry_2d.cpp new file mode 100644 index 0000000000..4636e1c774 --- /dev/null +++ b/core/math/geometry_2d.cpp @@ -0,0 +1,384 @@ +/*************************************************************************/ +/* geometry_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "geometry_2d.h" + +#include "thirdparty/misc/clipper.hpp" +#include "thirdparty/misc/triangulator.h" +#define STB_RECT_PACK_IMPLEMENTATION +#include "thirdparty/misc/stb_rect_pack.h" + +#define SCALE_FACTOR 100000.0 // Based on CMP_EPSILON. + +Vector<Vector<Vector2>> Geometry2D::decompose_polygon_in_convex(Vector<Point2> polygon) { + Vector<Vector<Vector2>> decomp; + List<TriangulatorPoly> in_poly, out_poly; + + TriangulatorPoly inp; + inp.Init(polygon.size()); + for (int i = 0; i < polygon.size(); i++) { + inp.GetPoint(i) = polygon[i]; + } + inp.SetOrientation(TRIANGULATOR_CCW); + in_poly.push_back(inp); + TriangulatorPartition tpart; + if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { // Failed. + ERR_PRINT("Convex decomposing failed!"); + return decomp; + } + + decomp.resize(out_poly.size()); + int idx = 0; + for (List<TriangulatorPoly>::Element *I = out_poly.front(); I; I = I->next()) { + TriangulatorPoly &tp = I->get(); + + decomp.write[idx].resize(tp.GetNumPoints()); + + for (int64_t i = 0; i < tp.GetNumPoints(); i++) { + decomp.write[idx].write[i] = tp.GetPoint(i); + } + + idx++; + } + + return decomp; +} + +struct _AtlasWorkRect { + Size2i s; + Point2i p; + int idx; + _FORCE_INLINE_ bool operator<(const _AtlasWorkRect &p_r) const { return s.width > p_r.s.width; }; +}; + +struct _AtlasWorkRectResult { + Vector<_AtlasWorkRect> result; + int max_w; + int max_h; +}; + +void Geometry2D::make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_result, Size2i &r_size) { + // Super simple, almost brute force scanline stacking fitter. + // It's pretty basic for now, but it tries to make sure that the aspect ratio of the + // resulting atlas is somehow square. This is necessary because video cards have limits. + // On texture size (usually 2048 or 4096), so the more square a texture, the more chances. + // It will work in every hardware. + // For example, it will prioritize a 1024x1024 atlas (works everywhere) instead of a + // 256x8192 atlas (won't work anywhere). + + ERR_FAIL_COND(p_rects.size() == 0); + + Vector<_AtlasWorkRect> wrects; + wrects.resize(p_rects.size()); + for (int i = 0; i < p_rects.size(); i++) { + wrects.write[i].s = p_rects[i]; + wrects.write[i].idx = i; + } + wrects.sort(); + int widest = wrects[0].s.width; + + Vector<_AtlasWorkRectResult> results; + + for (int i = 0; i <= 12; i++) { + int w = 1 << i; + int max_h = 0; + int max_w = 0; + if (w < widest) { + continue; + } + + Vector<int> hmax; + hmax.resize(w); + for (int j = 0; j < w; j++) { + hmax.write[j] = 0; + } + + // Place them. + int ofs = 0; + int limit_h = 0; + for (int j = 0; j < wrects.size(); j++) { + if (ofs + wrects[j].s.width > w) { + ofs = 0; + } + + int from_y = 0; + for (int k = 0; k < wrects[j].s.width; k++) { + if (hmax[ofs + k] > from_y) { + from_y = hmax[ofs + k]; + } + } + + wrects.write[j].p.x = ofs; + wrects.write[j].p.y = from_y; + int end_h = from_y + wrects[j].s.height; + int end_w = ofs + wrects[j].s.width; + if (ofs == 0) { + limit_h = end_h; + } + + for (int k = 0; k < wrects[j].s.width; k++) { + hmax.write[ofs + k] = end_h; + } + + if (end_h > max_h) { + max_h = end_h; + } + + if (end_w > max_w) { + max_w = end_w; + } + + if (ofs == 0 || end_h > limit_h) { // While h limit not reached, keep stacking. + ofs += wrects[j].s.width; + } + } + + _AtlasWorkRectResult result; + result.result = wrects; + result.max_h = max_h; + result.max_w = max_w; + results.push_back(result); + } + + // Find the result with the best aspect ratio. + + int best = -1; + real_t best_aspect = 1e20; + + for (int i = 0; i < results.size(); i++) { + real_t h = next_power_of_2(results[i].max_h); + real_t w = next_power_of_2(results[i].max_w); + real_t aspect = h > w ? h / w : w / h; + if (aspect < best_aspect) { + best = i; + best_aspect = aspect; + } + } + + r_result.resize(p_rects.size()); + + for (int i = 0; i < p_rects.size(); i++) { + r_result.write[results[best].result[i].idx] = results[best].result[i].p; + } + + r_size = Size2(results[best].max_w, results[best].max_h); +} + +Vector<Vector<Point2>> Geometry2D::_polypaths_do_operation(PolyBooleanOperation p_op, const Vector<Point2> &p_polypath_a, const Vector<Point2> &p_polypath_b, bool is_a_open) { + using namespace ClipperLib; + + ClipType op = ctUnion; + + switch (p_op) { + case OPERATION_UNION: + op = ctUnion; + break; + case OPERATION_DIFFERENCE: + op = ctDifference; + break; + case OPERATION_INTERSECTION: + op = ctIntersection; + break; + case OPERATION_XOR: + op = ctXor; + break; + } + Path path_a, path_b; + + // Need to scale points (Clipper's requirement for robust computation). + for (int i = 0; i != p_polypath_a.size(); ++i) { + path_a << IntPoint(p_polypath_a[i].x * SCALE_FACTOR, p_polypath_a[i].y * SCALE_FACTOR); + } + for (int i = 0; i != p_polypath_b.size(); ++i) { + path_b << IntPoint(p_polypath_b[i].x * SCALE_FACTOR, p_polypath_b[i].y * SCALE_FACTOR); + } + Clipper clp; + clp.AddPath(path_a, ptSubject, !is_a_open); // Forward compatible with Clipper 10.0.0. + clp.AddPath(path_b, ptClip, true); // Polylines cannot be set as clip. + + Paths paths; + + if (is_a_open) { + PolyTree tree; // Needed to populate polylines. + clp.Execute(op, tree); + OpenPathsFromPolyTree(tree, paths); + } else { + clp.Execute(op, paths); // Works on closed polygons only. + } + // Have to scale points down now. + Vector<Vector<Point2>> polypaths; + + for (Paths::size_type i = 0; i < paths.size(); ++i) { + Vector<Vector2> polypath; + + const Path &scaled_path = paths[i]; + + for (Paths::size_type j = 0; j < scaled_path.size(); ++j) { + polypath.push_back(Point2( + static_cast<real_t>(scaled_path[j].X) / SCALE_FACTOR, + static_cast<real_t>(scaled_path[j].Y) / SCALE_FACTOR)); + } + polypaths.push_back(polypath); + } + return polypaths; +} + +Vector<Vector<Point2>> Geometry2D::_polypath_offset(const Vector<Point2> &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) { + using namespace ClipperLib; + + JoinType jt = jtSquare; + + switch (p_join_type) { + case JOIN_SQUARE: + jt = jtSquare; + break; + case JOIN_ROUND: + jt = jtRound; + break; + case JOIN_MITER: + jt = jtMiter; + break; + } + + EndType et = etClosedPolygon; + + switch (p_end_type) { + case END_POLYGON: + et = etClosedPolygon; + break; + case END_JOINED: + et = etClosedLine; + break; + case END_BUTT: + et = etOpenButt; + break; + case END_SQUARE: + et = etOpenSquare; + break; + case END_ROUND: + et = etOpenRound; + break; + } + ClipperOffset co(2.0, 0.25 * SCALE_FACTOR); // Defaults from ClipperOffset. + Path path; + + // Need to scale points (Clipper's requirement for robust computation). + for (int i = 0; i != p_polypath.size(); ++i) { + path << IntPoint(p_polypath[i].x * SCALE_FACTOR, p_polypath[i].y * SCALE_FACTOR); + } + co.AddPath(path, jt, et); + + Paths paths; + co.Execute(paths, p_delta * SCALE_FACTOR); // Inflate/deflate. + + // Have to scale points down now. + Vector<Vector<Point2>> polypaths; + + for (Paths::size_type i = 0; i < paths.size(); ++i) { + Vector<Vector2> polypath; + + const Path &scaled_path = paths[i]; + + for (Paths::size_type j = 0; j < scaled_path.size(); ++j) { + polypath.push_back(Point2( + static_cast<real_t>(scaled_path[j].X) / SCALE_FACTOR, + static_cast<real_t>(scaled_path[j].Y) / SCALE_FACTOR)); + } + polypaths.push_back(polypath); + } + return polypaths; +} + +Vector<Point2i> Geometry2D::pack_rects(const Vector<Size2i> &p_sizes, const Size2i &p_atlas_size) { + Vector<stbrp_node> nodes; + nodes.resize(p_atlas_size.width); + + stbrp_context context; + stbrp_init_target(&context, p_atlas_size.width, p_atlas_size.height, nodes.ptrw(), p_atlas_size.width); + + Vector<stbrp_rect> rects; + rects.resize(p_sizes.size()); + + for (int i = 0; i < p_sizes.size(); i++) { + rects.write[i].id = 0; + rects.write[i].w = p_sizes[i].width; + rects.write[i].h = p_sizes[i].height; + rects.write[i].x = 0; + rects.write[i].y = 0; + rects.write[i].was_packed = 0; + } + + int res = stbrp_pack_rects(&context, rects.ptrw(), rects.size()); + if (res == 0) { //pack failed + return Vector<Point2i>(); + } + + Vector<Point2i> ret; + ret.resize(p_sizes.size()); + + for (int i = 0; i < p_sizes.size(); i++) { + Point2i r(rects[i].x, rects[i].y); + ret.write[i] = r; + } + + return ret; +} + +Vector<Vector3i> Geometry2D::partial_pack_rects(const Vector<Vector2i> &p_sizes, const Size2i &p_atlas_size) { + Vector<stbrp_node> nodes; + nodes.resize(p_atlas_size.width); + zeromem(nodes.ptrw(), sizeof(stbrp_node) * nodes.size()); + + stbrp_context context; + stbrp_init_target(&context, p_atlas_size.width, p_atlas_size.height, nodes.ptrw(), p_atlas_size.width); + + Vector<stbrp_rect> rects; + rects.resize(p_sizes.size()); + + for (int i = 0; i < p_sizes.size(); i++) { + rects.write[i].id = i; + rects.write[i].w = p_sizes[i].width; + rects.write[i].h = p_sizes[i].height; + rects.write[i].x = 0; + rects.write[i].y = 0; + rects.write[i].was_packed = 0; + } + + stbrp_pack_rects(&context, rects.ptrw(), rects.size()); + + Vector<Vector3i> ret; + ret.resize(p_sizes.size()); + + for (int i = 0; i < p_sizes.size(); i++) { + ret.write[rects[i].id] = Vector3i(rects[i].x, rects[i].y, rects[i].was_packed != 0 ? 1 : 0); + } + + return ret; +} diff --git a/core/math/geometry_2d.h b/core/math/geometry_2d.h new file mode 100644 index 0000000000..cfd7abfacb --- /dev/null +++ b/core/math/geometry_2d.h @@ -0,0 +1,398 @@ +/*************************************************************************/ +/* geometry_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef GEOMETRY_2D_H +#define GEOMETRY_2D_H + +#include "core/math/delaunay_2d.h" +#include "core/math/rect2.h" +#include "core/math/triangulate.h" +#include "core/object.h" +#include "core/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. + Vector2 d2 = q2 - p2; // Direction vector of segment S2. + Vector2 r = p1 - p2; + real_t a = d1.dot(d1); // Squared length of segment S1, always nonnegative. + real_t e = d2.dot(d2); // Squared length of segment S2, always nonnegative. + real_t f = d2.dot(r); + real_t s, t; + // Check if either or both segments degenerate into points. + if (a <= CMP_EPSILON && e <= CMP_EPSILON) { + // Both segments degenerate into points. + c1 = p1; + c2 = p2; + return Math::sqrt((c1 - c2).dot(c1 - c2)); + } + if (a <= CMP_EPSILON) { + // First segment degenerates into a point. + s = 0.0; + t = f / e; // s = 0 => t = (b*s + f) / e = f / e + t = CLAMP(t, 0.0, 1.0); + } else { + real_t c = d1.dot(r); + if (e <= CMP_EPSILON) { + // Second segment degenerates into a point. + t = 0.0; + s = CLAMP(-c / a, 0.0, 1.0); // t = 0 => s = (b*t - c) / a = -c / a + } else { + // The general nondegenerate case starts here. + real_t b = d1.dot(d2); + real_t denom = a * e - b * b; // Always nonnegative. + // If segments not parallel, compute closest point on L1 to L2 and + // clamp to segment S1. Else pick arbitrary s (here 0). + if (denom != 0.0) { + s = CLAMP((b * f - c * e) / denom, 0.0, 1.0); + } else { + s = 0.0; + } + // Compute point on L2 closest to S1(s) using + // t = Dot((P1 + D1*s) - P2,D2) / Dot(D2,D2) = (b*s + f) / e + t = (b * s + f) / e; + + //If t in [0,1] done. Else clamp t, recompute s for the new value + // of t using s = Dot((P2 + D2*t) - P1,D1) / Dot(D1,D1)= (t*b - c) / a + // and clamp s to [0, 1]. + if (t < 0.0) { + t = 0.0; + s = CLAMP(-c / a, 0.0, 1.0); + } else if (t > 1.0) { + t = 1.0; + s = CLAMP((b - c) / a, 0.0, 1.0); + } + } + } + c1 = p1 + d1 * s; + c2 = p2 + d2 * t; + return Math::sqrt((c1 - c2).dot(c1 - c2)); + } + + static Vector2 get_closest_point_to_segment(const Vector2 &p_point, const Vector2 *p_segment) { + Vector2 p = p_point - p_segment[0]; + Vector2 n = p_segment[1] - p_segment[0]; + real_t l2 = n.length_squared(); + if (l2 < 1e-20) { + return p_segment[0]; // Both points are the same, just give any. + } + + real_t d = n.dot(p) / l2; + + if (d <= 0.0) { + return p_segment[0]; // Before first point. + } else if (d >= 1.0) { + return p_segment[1]; // After first point. + } else { + return p_segment[0] + n * d; // Inside. + } + } + + static bool is_point_in_triangle(const Vector2 &s, const Vector2 &a, const Vector2 &b, const Vector2 &c) { + Vector2 an = a - s; + Vector2 bn = b - s; + Vector2 cn = c - s; + + bool orientation = an.cross(bn) > 0; + + if ((bn.cross(cn) > 0) != orientation) { + return false; + } + + return (cn.cross(an) > 0) == orientation; + } + + static Vector2 get_closest_point_to_segment_uncapped(const Vector2 &p_point, const Vector2 *p_segment) { + Vector2 p = p_point - p_segment[0]; + Vector2 n = p_segment[1] - p_segment[0]; + real_t l2 = n.length_squared(); + if (l2 < 1e-20) { + return p_segment[0]; // Both points are the same, just give any. + } + + real_t d = n.dot(p) / l2; + + return p_segment[0] + n * d; // Inside. + } + + static bool line_intersects_line(const Vector2 &p_from_a, const Vector2 &p_dir_a, const Vector2 &p_from_b, const Vector2 &p_dir_b, Vector2 &r_result) { + // See http://paulbourke.net/geometry/pointlineplane/ + + const real_t denom = p_dir_b.y * p_dir_a.x - p_dir_b.x * p_dir_a.y; + if (Math::is_zero_approx(denom)) { // Parallel? + return false; + } + + const Vector2 v = p_from_a - p_from_b; + const real_t t = (p_dir_b.x * v.y - p_dir_b.y * v.x) / denom; + r_result = p_from_a + t * p_dir_a; + return true; + } + + static bool segment_intersects_segment(const Vector2 &p_from_a, const Vector2 &p_to_a, const Vector2 &p_from_b, const Vector2 &p_to_b, Vector2 *r_result) { + Vector2 B = p_to_a - p_from_a; + Vector2 C = p_from_b - p_from_a; + Vector2 D = p_to_b - p_from_a; + + real_t ABlen = B.dot(B); + if (ABlen <= 0) { + return false; + } + Vector2 Bn = B / ABlen; + C = Vector2(C.x * Bn.x + C.y * Bn.y, C.y * Bn.x - C.x * Bn.y); + D = Vector2(D.x * Bn.x + D.y * Bn.y, D.y * Bn.x - D.x * Bn.y); + + if ((C.y < 0 && D.y < 0) || (C.y >= 0 && D.y >= 0)) { + return false; + } + + real_t ABpos = D.x + (C.x - D.x) * D.y / (D.y - C.y); + + // Fail if segment C-D crosses line A-B outside of segment A-B. + if (ABpos < 0 || ABpos > 1.0) { + return false; + } + + // (4) Apply the discovered position to line A-B in the original coordinate system. + if (r_result) { + *r_result = p_from_a + B * ABpos; + } + + return true; + } + + static inline bool is_point_in_circle(const Vector2 &p_point, const Vector2 &p_circle_pos, real_t p_circle_radius) { + return p_point.distance_squared_to(p_circle_pos) <= p_circle_radius * p_circle_radius; + } + + static real_t segment_intersects_circle(const Vector2 &p_from, const Vector2 &p_to, const Vector2 &p_circle_pos, real_t p_circle_radius) { + Vector2 line_vec = p_to - p_from; + Vector2 vec_to_line = p_from - p_circle_pos; + + // Create a quadratic formula of the form ax^2 + bx + c = 0 + real_t a, b, c; + + a = line_vec.dot(line_vec); + b = 2 * vec_to_line.dot(line_vec); + c = vec_to_line.dot(vec_to_line) - p_circle_radius * p_circle_radius; + + // Solve for t. + real_t sqrtterm = b * b - 4 * a * c; + + // If the term we intend to square root is less than 0 then the answer won't be real, + // so it definitely won't be t in the range 0 to 1. + if (sqrtterm < 0) { + return -1; + } + + // If we can assume that the line segment starts outside the circle (e.g. for continuous time collision detection) + // then the following can be skipped and we can just return the equivalent of res1. + sqrtterm = Math::sqrt(sqrtterm); + real_t res1 = (-b - sqrtterm) / (2 * a); + real_t res2 = (-b + sqrtterm) / (2 * a); + + if (res1 >= 0 && res1 <= 1) { + return res1; + } + if (res2 >= 0 && res2 <= 1) { + return res2; + } + return -1; + } + + enum PolyBooleanOperation { + OPERATION_UNION, + OPERATION_DIFFERENCE, + OPERATION_INTERSECTION, + OPERATION_XOR + }; + enum PolyJoinType { + JOIN_SQUARE, + JOIN_ROUND, + JOIN_MITER + }; + enum PolyEndType { + END_POLYGON, + END_JOINED, + END_BUTT, + END_SQUARE, + END_ROUND + }; + + static Vector<Vector<Point2>> merge_polygons(const Vector<Point2> &p_polygon_a, const Vector<Point2> &p_polygon_b) { + return _polypaths_do_operation(OPERATION_UNION, p_polygon_a, p_polygon_b); + } + + static Vector<Vector<Point2>> clip_polygons(const Vector<Point2> &p_polygon_a, const Vector<Point2> &p_polygon_b) { + return _polypaths_do_operation(OPERATION_DIFFERENCE, p_polygon_a, p_polygon_b); + } + + static Vector<Vector<Point2>> intersect_polygons(const Vector<Point2> &p_polygon_a, const Vector<Point2> &p_polygon_b) { + return _polypaths_do_operation(OPERATION_INTERSECTION, p_polygon_a, p_polygon_b); + } + + static Vector<Vector<Point2>> exclude_polygons(const Vector<Point2> &p_polygon_a, const Vector<Point2> &p_polygon_b) { + return _polypaths_do_operation(OPERATION_XOR, p_polygon_a, p_polygon_b); + } + + static Vector<Vector<Point2>> clip_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) { + return _polypaths_do_operation(OPERATION_DIFFERENCE, p_polyline, p_polygon, true); + } + + static Vector<Vector<Point2>> intersect_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) { + return _polypaths_do_operation(OPERATION_INTERSECTION, p_polyline, p_polygon, true); + } + + static Vector<Vector<Point2>> offset_polygon(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type) { + return _polypath_offset(p_polygon, p_delta, p_join_type, END_POLYGON); + } + + static Vector<Vector<Point2>> offset_polyline(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) { + ERR_FAIL_COND_V_MSG(p_end_type == END_POLYGON, Vector<Vector<Point2>>(), "Attempt to offset a polyline like a polygon (use offset_polygon instead)."); + + return _polypath_offset(p_polygon, p_delta, p_join_type, p_end_type); + } + + static Vector<int> triangulate_delaunay(const Vector<Vector2> &p_points) { + Vector<Delaunay2D::Triangle> tr = Delaunay2D::triangulate(p_points); + Vector<int> triangles; + + for (int i = 0; i < tr.size(); i++) { + triangles.push_back(tr[i].points[0]); + triangles.push_back(tr[i].points[1]); + triangles.push_back(tr[i].points[2]); + } + return triangles; + } + + static Vector<int> triangulate_polygon(const Vector<Vector2> &p_polygon) { + Vector<int> triangles; + if (!Triangulate::triangulate(p_polygon, triangles)) { + return Vector<int>(); //fail + } + return triangles; + } + + static bool is_polygon_clockwise(const Vector<Vector2> &p_polygon) { + int c = p_polygon.size(); + if (c < 3) { + return false; + } + const Vector2 *p = p_polygon.ptr(); + real_t sum = 0; + for (int i = 0; i < c; i++) { + const Vector2 &v1 = p[i]; + const Vector2 &v2 = p[(i + 1) % c]; + sum += (v2.x - v1.x) * (v2.y + v1.y); + } + + return sum > 0.0f; + } + + // Alternate implementation that should be faster. + static bool is_point_in_polygon(const Vector2 &p_point, const Vector<Vector2> &p_polygon) { + int c = p_polygon.size(); + if (c < 3) { + return false; + } + const Vector2 *p = p_polygon.ptr(); + Vector2 further_away(-1e20, -1e20); + Vector2 further_away_opposite(1e20, 1e20); + + for (int i = 0; i < c; i++) { + further_away.x = MAX(p[i].x, further_away.x); + further_away.y = MAX(p[i].y, further_away.y); + further_away_opposite.x = MIN(p[i].x, further_away_opposite.x); + further_away_opposite.y = MIN(p[i].y, further_away_opposite.y); + } + + // Make point outside that won't intersect with points in segment from p_point. + further_away += (further_away - further_away_opposite) * Vector2(1.221313, 1.512312); + + int intersections = 0; + for (int i = 0; i < c; i++) { + const Vector2 &v1 = p[i]; + const Vector2 &v2 = p[(i + 1) % c]; + if (segment_intersects_segment(v1, v2, p_point, further_away, nullptr)) { + intersections++; + } + } + + return (intersections & 1); + } + + static real_t vec2_cross(const Point2 &O, const Point2 &A, const Point2 &B) { + return (real_t)(A.x - O.x) * (B.y - O.y) - (real_t)(A.y - O.y) * (B.x - O.x); + } + + // Returns a list of points on the convex hull in counter-clockwise order. + // Note: the last point in the returned list is the same as the first one. + static Vector<Point2> convex_hull(Vector<Point2> P) { + int n = P.size(), k = 0; + Vector<Point2> H; + H.resize(2 * n); + + // Sort points lexicographically. + P.sort(); + + // Build lower hull. + for (int i = 0; i < n; ++i) { + while (k >= 2 && vec2_cross(H[k - 2], H[k - 1], P[i]) <= 0) { + k--; + } + H.write[k++] = P[i]; + } + + // Build upper hull. + for (int i = n - 2, t = k + 1; i >= 0; i--) { + while (k >= t && vec2_cross(H[k - 2], H[k - 1], P[i]) <= 0) { + k--; + } + H.write[k++] = P[i]; + } + + H.resize(k); + return H; + } + static Vector<Vector<Vector2>> decompose_polygon_in_convex(Vector<Point2> polygon); + + static void make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_result, Size2i &r_size); + static Vector<Point2i> pack_rects(const Vector<Size2i> &p_sizes, const Size2i &p_atlas_size); + static Vector<Vector3i> partial_pack_rects(const Vector<Vector2i> &p_sizes, const Size2i &p_atlas_size); + +private: + static Vector<Vector<Point2>> _polypaths_do_operation(PolyBooleanOperation p_op, const Vector<Point2> &p_polypath_a, const Vector<Point2> &p_polypath_b, bool is_a_open = false); + static Vector<Vector<Point2>> _polypath_offset(const Vector<Point2> &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type); +}; + +#endif // GEOMETRY_2D_H diff --git a/core/math/geometry.cpp b/core/math/geometry_3d.cpp index f6f22e1db2..7807ab19a7 100644 --- a/core/math/geometry.cpp +++ b/core/math/geometry_3d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* geometry.cpp */ +/* geometry_3d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,33 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "geometry.h" +#include "geometry_3d.h" #include "core/print_string.h" #include "thirdparty/misc/clipper.hpp" #include "thirdparty/misc/triangulator.h" -#define STB_RECT_PACK_IMPLEMENTATION -#include "thirdparty/misc/stb_rect_pack.h" -#define SCALE_FACTOR 100000.0 // Based on CMP_EPSILON. - -// This implementation is very inefficient, commenting unless bugs happen. See the other one. -/* -bool Geometry::is_point_in_polygon(const Vector2 &p_point, const Vector<Vector2> &p_polygon) { - - Vector<int> indices = Geometry::triangulate_polygon(p_polygon); - for (int j = 0; j + 3 <= indices.size(); j += 3) { - int i1 = indices[j], i2 = indices[j + 1], i3 = indices[j + 2]; - if (Geometry::is_point_in_triangle(p_point, p_polygon[i1], p_polygon[i2], p_polygon[i3])) - return true; - } - return false; -} - -*/ - -void Geometry::MeshData::optimize_vertices() { +void Geometry3D::MeshData::optimize_vertices() { Map<int, int> vtx_remap; for (int i = 0; i < faces.size(); i++) { @@ -201,7 +182,7 @@ static bool _group_face(_FaceClassify *p_faces, int len, int p_index, int p_grou return true; } -Vector<Vector<Face3>> Geometry::separate_objects(Vector<Face3> p_array) { +Vector<Vector<Face3>> Geometry3D::separate_objects(Vector<Face3> p_array) { Vector<Vector<Face3>> objects; int len = p_array.size(); @@ -511,7 +492,7 @@ static inline void _build_faces(uint8_t ***p_cell_status, int x, int y, int z, i } } -Vector<Face3> Geometry::wrap_geometry(Vector<Face3> p_array, real_t *p_error) { +Vector<Face3> Geometry3D::wrap_geometry(Vector<Face3> p_array, real_t *p_error) { #define _MIN_SIZE 1.0 #define _MAX_LENGTH 20 @@ -647,41 +628,7 @@ Vector<Face3> Geometry::wrap_geometry(Vector<Face3> p_array, real_t *p_error) { return wrapped_faces; } -Vector<Vector<Vector2>> Geometry::decompose_polygon_in_convex(Vector<Point2> polygon) { - Vector<Vector<Vector2>> decomp; - List<TriangulatorPoly> in_poly, out_poly; - - TriangulatorPoly inp; - inp.Init(polygon.size()); - for (int i = 0; i < polygon.size(); i++) { - inp.GetPoint(i) = polygon[i]; - } - inp.SetOrientation(TRIANGULATOR_CCW); - in_poly.push_back(inp); - TriangulatorPartition tpart; - if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { // Failed. - ERR_PRINT("Convex decomposing failed!"); - return decomp; - } - - decomp.resize(out_poly.size()); - int idx = 0; - for (List<TriangulatorPoly>::Element *I = out_poly.front(); I; I = I->next()) { - TriangulatorPoly &tp = I->get(); - - decomp.write[idx].resize(tp.GetNumPoints()); - - for (int64_t i = 0; i < tp.GetNumPoints(); i++) { - decomp.write[idx].write[i] = tp.GetPoint(i); - } - - idx++; - } - - return decomp; -} - -Geometry::MeshData Geometry::build_convex_mesh(const Vector<Plane> &p_planes) { +Geometry3D::MeshData Geometry3D::build_convex_mesh(const Vector<Plane> &p_planes) { MeshData mesh; #define SUBPLANE_SIZE 1024.0 @@ -816,7 +763,7 @@ Geometry::MeshData Geometry::build_convex_mesh(const Vector<Plane> &p_planes) { return mesh; } -Vector<Plane> Geometry::build_box_planes(const Vector3 &p_extents) { +Vector<Plane> Geometry3D::build_box_planes(const Vector3 &p_extents) { Vector<Plane> planes; planes.push_back(Plane(Vector3(1, 0, 0), p_extents.x)); @@ -829,7 +776,7 @@ Vector<Plane> Geometry::build_box_planes(const Vector3 &p_extents) { return planes; } -Vector<Plane> Geometry::build_cylinder_planes(real_t p_radius, real_t p_height, int p_sides, Vector3::Axis p_axis) { +Vector<Plane> Geometry3D::build_cylinder_planes(real_t p_radius, real_t p_height, int p_sides, Vector3::Axis p_axis) { Vector<Plane> planes; for (int i = 0; i < p_sides; i++) { @@ -849,7 +796,7 @@ Vector<Plane> Geometry::build_cylinder_planes(real_t p_radius, real_t p_height, return planes; } -Vector<Plane> Geometry::build_sphere_planes(real_t p_radius, int p_lats, int p_lons, Vector3::Axis p_axis) { +Vector<Plane> Geometry3D::build_sphere_planes(real_t p_radius, int p_lats, int p_lons, Vector3::Axis p_axis) { Vector<Plane> planes; Vector3 axis; @@ -879,7 +826,7 @@ Vector<Plane> Geometry::build_sphere_planes(real_t p_radius, int p_lats, int p_l return planes; } -Vector<Plane> Geometry::build_capsule_planes(real_t p_radius, real_t p_height, int p_sides, int p_lats, Vector3::Axis p_axis) { +Vector<Plane> Geometry3D::build_capsule_planes(real_t p_radius, real_t p_height, int p_sides, int p_lats, Vector3::Axis p_axis) { Vector<Plane> planes; Vector3 axis; @@ -908,252 +855,7 @@ Vector<Plane> Geometry::build_capsule_planes(real_t p_radius, real_t p_height, i return planes; } -struct _AtlasWorkRect { - Size2i s; - Point2i p; - int idx; - _FORCE_INLINE_ bool operator<(const _AtlasWorkRect &p_r) const { return s.width > p_r.s.width; }; -}; - -struct _AtlasWorkRectResult { - Vector<_AtlasWorkRect> result; - int max_w; - int max_h; -}; - -void Geometry::make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_result, Size2i &r_size) { - // Super simple, almost brute force scanline stacking fitter. - // It's pretty basic for now, but it tries to make sure that the aspect ratio of the - // resulting atlas is somehow square. This is necessary because video cards have limits. - // On texture size (usually 2048 or 4096), so the more square a texture, the more chances. - // It will work in every hardware. - // For example, it will prioritize a 1024x1024 atlas (works everywhere) instead of a - // 256x8192 atlas (won't work anywhere). - - ERR_FAIL_COND(p_rects.size() == 0); - - Vector<_AtlasWorkRect> wrects; - wrects.resize(p_rects.size()); - for (int i = 0; i < p_rects.size(); i++) { - wrects.write[i].s = p_rects[i]; - wrects.write[i].idx = i; - } - wrects.sort(); - int widest = wrects[0].s.width; - - Vector<_AtlasWorkRectResult> results; - - for (int i = 0; i <= 12; i++) { - int w = 1 << i; - int max_h = 0; - int max_w = 0; - if (w < widest) { - continue; - } - - Vector<int> hmax; - hmax.resize(w); - for (int j = 0; j < w; j++) { - hmax.write[j] = 0; - } - - // Place them. - int ofs = 0; - int limit_h = 0; - for (int j = 0; j < wrects.size(); j++) { - if (ofs + wrects[j].s.width > w) { - ofs = 0; - } - - int from_y = 0; - for (int k = 0; k < wrects[j].s.width; k++) { - if (hmax[ofs + k] > from_y) { - from_y = hmax[ofs + k]; - } - } - - wrects.write[j].p.x = ofs; - wrects.write[j].p.y = from_y; - int end_h = from_y + wrects[j].s.height; - int end_w = ofs + wrects[j].s.width; - if (ofs == 0) { - limit_h = end_h; - } - - for (int k = 0; k < wrects[j].s.width; k++) { - hmax.write[ofs + k] = end_h; - } - - if (end_h > max_h) { - max_h = end_h; - } - - if (end_w > max_w) { - max_w = end_w; - } - - if (ofs == 0 || end_h > limit_h) { // While h limit not reached, keep stacking. - ofs += wrects[j].s.width; - } - } - - _AtlasWorkRectResult result; - result.result = wrects; - result.max_h = max_h; - result.max_w = max_w; - results.push_back(result); - } - - // Find the result with the best aspect ratio. - - int best = -1; - real_t best_aspect = 1e20; - - for (int i = 0; i < results.size(); i++) { - real_t h = next_power_of_2(results[i].max_h); - real_t w = next_power_of_2(results[i].max_w); - real_t aspect = h > w ? h / w : w / h; - if (aspect < best_aspect) { - best = i; - best_aspect = aspect; - } - } - - r_result.resize(p_rects.size()); - - for (int i = 0; i < p_rects.size(); i++) { - r_result.write[results[best].result[i].idx] = results[best].result[i].p; - } - - r_size = Size2(results[best].max_w, results[best].max_h); -} - -Vector<Vector<Point2>> Geometry::_polypaths_do_operation(PolyBooleanOperation p_op, const Vector<Point2> &p_polypath_a, const Vector<Point2> &p_polypath_b, bool is_a_open) { - using namespace ClipperLib; - - ClipType op = ctUnion; - - switch (p_op) { - case OPERATION_UNION: - op = ctUnion; - break; - case OPERATION_DIFFERENCE: - op = ctDifference; - break; - case OPERATION_INTERSECTION: - op = ctIntersection; - break; - case OPERATION_XOR: - op = ctXor; - break; - } - Path path_a, path_b; - - // Need to scale points (Clipper's requirement for robust computation). - for (int i = 0; i != p_polypath_a.size(); ++i) { - path_a << IntPoint(p_polypath_a[i].x * SCALE_FACTOR, p_polypath_a[i].y * SCALE_FACTOR); - } - for (int i = 0; i != p_polypath_b.size(); ++i) { - path_b << IntPoint(p_polypath_b[i].x * SCALE_FACTOR, p_polypath_b[i].y * SCALE_FACTOR); - } - Clipper clp; - clp.AddPath(path_a, ptSubject, !is_a_open); // Forward compatible with Clipper 10.0.0. - clp.AddPath(path_b, ptClip, true); // Polylines cannot be set as clip. - - Paths paths; - - if (is_a_open) { - PolyTree tree; // Needed to populate polylines. - clp.Execute(op, tree); - OpenPathsFromPolyTree(tree, paths); - } else { - clp.Execute(op, paths); // Works on closed polygons only. - } - // Have to scale points down now. - Vector<Vector<Point2>> polypaths; - - for (Paths::size_type i = 0; i < paths.size(); ++i) { - Vector<Vector2> polypath; - - const Path &scaled_path = paths[i]; - - for (Paths::size_type j = 0; j < scaled_path.size(); ++j) { - polypath.push_back(Point2( - static_cast<real_t>(scaled_path[j].X) / SCALE_FACTOR, - static_cast<real_t>(scaled_path[j].Y) / SCALE_FACTOR)); - } - polypaths.push_back(polypath); - } - return polypaths; -} - -Vector<Vector<Point2>> Geometry::_polypath_offset(const Vector<Point2> &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) { - using namespace ClipperLib; - - JoinType jt = jtSquare; - - switch (p_join_type) { - case JOIN_SQUARE: - jt = jtSquare; - break; - case JOIN_ROUND: - jt = jtRound; - break; - case JOIN_MITER: - jt = jtMiter; - break; - } - - EndType et = etClosedPolygon; - - switch (p_end_type) { - case END_POLYGON: - et = etClosedPolygon; - break; - case END_JOINED: - et = etClosedLine; - break; - case END_BUTT: - et = etOpenButt; - break; - case END_SQUARE: - et = etOpenSquare; - break; - case END_ROUND: - et = etOpenRound; - break; - } - ClipperOffset co(2.0, 0.25 * SCALE_FACTOR); // Defaults from ClipperOffset. - Path path; - - // Need to scale points (Clipper's requirement for robust computation). - for (int i = 0; i != p_polypath.size(); ++i) { - path << IntPoint(p_polypath[i].x * SCALE_FACTOR, p_polypath[i].y * SCALE_FACTOR); - } - co.AddPath(path, jt, et); - - Paths paths; - co.Execute(paths, p_delta * SCALE_FACTOR); // Inflate/deflate. - - // Have to scale points down now. - Vector<Vector<Point2>> polypaths; - - for (Paths::size_type i = 0; i < paths.size(); ++i) { - Vector<Vector2> polypath; - - const Path &scaled_path = paths[i]; - - for (Paths::size_type j = 0; j < scaled_path.size(); ++j) { - polypath.push_back(Point2( - static_cast<real_t>(scaled_path[j].X) / SCALE_FACTOR, - static_cast<real_t>(scaled_path[j].Y) / SCALE_FACTOR)); - } - polypaths.push_back(polypath); - } - return polypaths; -} - -Vector<Vector3> Geometry::compute_convex_mesh_points(const Plane *p_planes, int p_plane_count) { +Vector<Vector3> Geometry3D::compute_convex_mesh_points(const Plane *p_planes, int p_plane_count) { Vector<Vector3> points; // Iterate through every unique combination of any three planes. @@ -1189,73 +891,6 @@ Vector<Vector3> Geometry::compute_convex_mesh_points(const Plane *p_planes, int return points; } -Vector<Point2i> Geometry::pack_rects(const Vector<Size2i> &p_sizes, const Size2i &p_atlas_size) { - Vector<stbrp_node> nodes; - nodes.resize(p_atlas_size.width); - - stbrp_context context; - stbrp_init_target(&context, p_atlas_size.width, p_atlas_size.height, nodes.ptrw(), p_atlas_size.width); - - Vector<stbrp_rect> rects; - rects.resize(p_sizes.size()); - - for (int i = 0; i < p_sizes.size(); i++) { - rects.write[i].id = 0; - rects.write[i].w = p_sizes[i].width; - rects.write[i].h = p_sizes[i].height; - rects.write[i].x = 0; - rects.write[i].y = 0; - rects.write[i].was_packed = 0; - } - - int res = stbrp_pack_rects(&context, rects.ptrw(), rects.size()); - if (res == 0) { //pack failed - return Vector<Point2i>(); - } - - Vector<Point2i> ret; - ret.resize(p_sizes.size()); - - for (int i = 0; i < p_sizes.size(); i++) { - Point2i r(rects[i].x, rects[i].y); - ret.write[i] = r; - } - - return ret; -} - -Vector<Vector3i> Geometry::partial_pack_rects(const Vector<Vector2i> &p_sizes, const Size2i &p_atlas_size) { - Vector<stbrp_node> nodes; - nodes.resize(p_atlas_size.width); - zeromem(nodes.ptrw(), sizeof(stbrp_node) * nodes.size()); - - stbrp_context context; - stbrp_init_target(&context, p_atlas_size.width, p_atlas_size.height, nodes.ptrw(), p_atlas_size.width); - - Vector<stbrp_rect> rects; - rects.resize(p_sizes.size()); - - for (int i = 0; i < p_sizes.size(); i++) { - rects.write[i].id = i; - rects.write[i].w = p_sizes[i].width; - rects.write[i].h = p_sizes[i].height; - rects.write[i].x = 0; - rects.write[i].y = 0; - rects.write[i].was_packed = 0; - } - - stbrp_pack_rects(&context, rects.ptrw(), rects.size()); - - Vector<Vector3i> ret; - ret.resize(p_sizes.size()); - - for (int i = 0; i < p_sizes.size(); i++) { - ret.write[rects[i].id] = Vector3i(rects[i].x, rects[i].y, rects[i].was_packed != 0 ? 1 : 0); - } - - return ret; -} - #define square(m_s) ((m_s) * (m_s)) #define INF 1e20 @@ -1297,7 +932,7 @@ static void edt(float *f, int stride, int n) { #undef square -Vector<uint32_t> Geometry::generate_edf(const Vector<bool> &p_voxels, const Vector3i &p_size, bool p_negative) { +Vector<uint32_t> Geometry3D::generate_edf(const Vector<bool> &p_voxels, const Vector3i &p_size, bool p_negative) { uint32_t float_count = p_size.x * p_size.y * p_size.z; ERR_FAIL_COND_V((uint32_t)p_voxels.size() != float_count, Vector<uint32_t>()); @@ -1358,10 +993,12 @@ Vector<uint32_t> Geometry::generate_edf(const Vector<bool> &p_voxels, const Vect } } + memdelete_arr(work_memory); + return ret; } -Vector<int8_t> Geometry::generate_sdf8(const Vector<uint32_t> &p_positive, const Vector<uint32_t> &p_negative) { +Vector<int8_t> Geometry3D::generate_sdf8(const Vector<uint32_t> &p_positive, const Vector<uint32_t> &p_negative) { ERR_FAIL_COND_V(p_positive.size() != p_negative.size(), Vector<int8_t>()); Vector<int8_t> sdf8; int s = p_positive.size(); diff --git a/core/math/geometry.h b/core/math/geometry_3d.h index a61bf20c4c..6bbf518141 100644 --- a/core/math/geometry.h +++ b/core/math/geometry_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* geometry.h */ +/* geometry_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,80 +28,17 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef GEOMETRY_H -#define GEOMETRY_H +#ifndef GEOMETRY_3D_H +#define GEOMETRY_3D_H -#include "core/math/delaunay_2d.h" #include "core/math/face3.h" -#include "core/math/rect2.h" -#include "core/math/triangulate.h" -#include "core/math/vector3.h" #include "core/object.h" -#include "core/print_string.h" #include "core/vector.h" -class Geometry { - Geometry(); +class Geometry3D { + Geometry3D(); 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. - Vector2 d2 = q2 - p2; // Direction vector of segment S2. - Vector2 r = p1 - p2; - real_t a = d1.dot(d1); // Squared length of segment S1, always nonnegative. - real_t e = d2.dot(d2); // Squared length of segment S2, always nonnegative. - real_t f = d2.dot(r); - real_t s, t; - // Check if either or both segments degenerate into points. - if (a <= CMP_EPSILON && e <= CMP_EPSILON) { - // Both segments degenerate into points. - c1 = p1; - c2 = p2; - return Math::sqrt((c1 - c2).dot(c1 - c2)); - } - if (a <= CMP_EPSILON) { - // First segment degenerates into a point. - s = 0.0; - t = f / e; // s = 0 => t = (b*s + f) / e = f / e - t = CLAMP(t, 0.0, 1.0); - } else { - real_t c = d1.dot(r); - if (e <= CMP_EPSILON) { - // Second segment degenerates into a point. - t = 0.0; - s = CLAMP(-c / a, 0.0, 1.0); // t = 0 => s = (b*t - c) / a = -c / a - } else { - // The general nondegenerate case starts here. - real_t b = d1.dot(d2); - real_t denom = a * e - b * b; // Always nonnegative. - // If segments not parallel, compute closest point on L1 to L2 and - // clamp to segment S1. Else pick arbitrary s (here 0). - if (denom != 0.0) { - s = CLAMP((b * f - c * e) / denom, 0.0, 1.0); - } else { - s = 0.0; - } - // Compute point on L2 closest to S1(s) using - // t = Dot((P1 + D1*s) - P2,D2) / Dot(D2,D2) = (b*s + f) / e - t = (b * s + f) / e; - - //If t in [0,1] done. Else clamp t, recompute s for the new value - // of t using s = Dot((P2 + D2*t) - P1,D1) / Dot(D1,D1)= (t*b - c) / a - // and clamp s to [0, 1]. - if (t < 0.0) { - t = 0.0; - s = CLAMP(-c / a, 0.0, 1.0); - } else if (t > 1.0) { - t = 1.0; - s = CLAMP((b - c) / a, 0.0, 1.0); - } - } - } - c1 = p1 + d1 * s; - c2 = p2 + d2 * t; - return Math::sqrt((c1 - c2).dot(c1 - c2)); - } - 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 is is dot product of some sort. #define d_of(m, n, o, p) ((m.x - n.x) * (o.x - p.x) + (m.y - n.y) * (o.y - p.y) + (m.z - n.z) * (o.z - p.z)) @@ -501,98 +438,6 @@ public: return p_segment[0] + n * d; // Inside. } - static Vector2 get_closest_point_to_segment_2d(const Vector2 &p_point, const Vector2 *p_segment) { - Vector2 p = p_point - p_segment[0]; - Vector2 n = p_segment[1] - p_segment[0]; - real_t l2 = n.length_squared(); - if (l2 < 1e-20) { - return p_segment[0]; // Both points are the same, just give any. - } - - real_t d = n.dot(p) / l2; - - if (d <= 0.0) { - return p_segment[0]; // Before first point. - } else if (d >= 1.0) { - return p_segment[1]; // After first point. - } else { - return p_segment[0] + n * d; // Inside. - } - } - - static bool is_point_in_triangle(const Vector2 &s, const Vector2 &a, const Vector2 &b, const Vector2 &c) { - Vector2 an = a - s; - Vector2 bn = b - s; - Vector2 cn = c - s; - - bool orientation = an.cross(bn) > 0; - - if ((bn.cross(cn) > 0) != orientation) { - return false; - } - - return (cn.cross(an) > 0) == orientation; - } - - static Vector2 get_closest_point_to_segment_uncapped_2d(const Vector2 &p_point, const Vector2 *p_segment) { - Vector2 p = p_point - p_segment[0]; - Vector2 n = p_segment[1] - p_segment[0]; - real_t l2 = n.length_squared(); - if (l2 < 1e-20) { - return p_segment[0]; // Both points are the same, just give any. - } - - real_t d = n.dot(p) / l2; - - return p_segment[0] + n * d; // Inside. - } - - static bool line_intersects_line_2d(const Vector2 &p_from_a, const Vector2 &p_dir_a, const Vector2 &p_from_b, const Vector2 &p_dir_b, Vector2 &r_result) { - // See http://paulbourke.net/geometry/pointlineplane/ - - const real_t denom = p_dir_b.y * p_dir_a.x - p_dir_b.x * p_dir_a.y; - if (Math::is_zero_approx(denom)) { // Parallel? - return false; - } - - const Vector2 v = p_from_a - p_from_b; - const real_t t = (p_dir_b.x * v.y - p_dir_b.y * v.x) / denom; - r_result = p_from_a + t * p_dir_a; - return true; - } - - static bool segment_intersects_segment_2d(const Vector2 &p_from_a, const Vector2 &p_to_a, const Vector2 &p_from_b, const Vector2 &p_to_b, Vector2 *r_result) { - Vector2 B = p_to_a - p_from_a; - Vector2 C = p_from_b - p_from_a; - Vector2 D = p_to_b - p_from_a; - - real_t ABlen = B.dot(B); - if (ABlen <= 0) { - return false; - } - Vector2 Bn = B / ABlen; - C = Vector2(C.x * Bn.x + C.y * Bn.y, C.y * Bn.x - C.x * Bn.y); - D = Vector2(D.x * Bn.x + D.y * Bn.y, D.y * Bn.x - D.x * Bn.y); - - if ((C.y < 0 && D.y < 0) || (C.y >= 0 && D.y >= 0)) { - return false; - } - - real_t ABpos = D.x + (C.x - D.x) * D.y / (D.y - C.y); - - // Fail if segment C-D crosses line A-B outside of segment A-B. - if (ABpos < 0 || ABpos > 1.0) { - return false; - } - - // (4) Apply the discovered position to line A-B in the original coordinate system. - if (r_result) { - *r_result = p_from_a + B * ABpos; - } - - return true; - } - static inline bool point_in_projected_triangle(const Vector3 &p_point, const Vector3 &p_v1, const Vector3 &p_v2, const Vector3 &p_v3) { Vector3 face_n = (p_v1 - p_v3).cross(p_v1 - p_v2); @@ -629,7 +474,7 @@ public: /** 2nd) TEST INSIDE TRIANGLE **/ - if (Geometry::point_in_projected_triangle(contact, p_triangle[0], p_triangle[1], p_triangle[2])) { + if (Geometry3D::point_in_projected_triangle(contact, p_triangle[0], p_triangle[1], p_triangle[2])) { r_triangle_contact = contact; r_sphere_contact = p_sphere_pos - p_normal * p_sphere_radius; //printf("solved inside triangle\n"); @@ -695,45 +540,6 @@ public: return false; } - static inline bool is_point_in_circle(const Vector2 &p_point, const Vector2 &p_circle_pos, real_t p_circle_radius) { - return p_point.distance_squared_to(p_circle_pos) <= p_circle_radius * p_circle_radius; - } - - static real_t segment_intersects_circle(const Vector2 &p_from, const Vector2 &p_to, const Vector2 &p_circle_pos, real_t p_circle_radius) { - Vector2 line_vec = p_to - p_from; - Vector2 vec_to_line = p_from - p_circle_pos; - - // Create a quadratic formula of the form ax^2 + bx + c = 0 - real_t a, b, c; - - a = line_vec.dot(line_vec); - b = 2 * vec_to_line.dot(line_vec); - c = vec_to_line.dot(vec_to_line) - p_circle_radius * p_circle_radius; - - // Solve for t. - real_t sqrtterm = b * b - 4 * a * c; - - // If the term we intend to square root is less than 0 then the answer won't be real, - // so it definitely won't be t in the range 0 to 1. - if (sqrtterm < 0) { - return -1; - } - - // If we can assume that the line segment starts outside the circle (e.g. for continuous time collision detection) - // then the following can be skipped and we can just return the equivalent of res1. - sqrtterm = Math::sqrt(sqrtterm); - real_t res1 = (-b - sqrtterm) / (2 * a); - real_t res2 = (-b + sqrtterm) / (2 * a); - - if (res1 >= 0 && res1 <= 1) { - return res1; - } - if (res2 >= 0 && res2 <= 1) { - return res2; - } - return -1; - } - static inline Vector<Vector3> clip_polygon(const Vector<Vector3> &polygon, const Plane &p_plane) { enum LocationCache { LOC_INSIDE = 1, @@ -806,127 +612,6 @@ public: return clipped; } - enum PolyBooleanOperation { - OPERATION_UNION, - OPERATION_DIFFERENCE, - OPERATION_INTERSECTION, - OPERATION_XOR - }; - enum PolyJoinType { - JOIN_SQUARE, - JOIN_ROUND, - JOIN_MITER - }; - enum PolyEndType { - END_POLYGON, - END_JOINED, - END_BUTT, - END_SQUARE, - END_ROUND - }; - - static Vector<Vector<Point2>> merge_polygons_2d(const Vector<Point2> &p_polygon_a, const Vector<Point2> &p_polygon_b) { - return _polypaths_do_operation(OPERATION_UNION, p_polygon_a, p_polygon_b); - } - - static Vector<Vector<Point2>> clip_polygons_2d(const Vector<Point2> &p_polygon_a, const Vector<Point2> &p_polygon_b) { - return _polypaths_do_operation(OPERATION_DIFFERENCE, p_polygon_a, p_polygon_b); - } - - static Vector<Vector<Point2>> intersect_polygons_2d(const Vector<Point2> &p_polygon_a, const Vector<Point2> &p_polygon_b) { - return _polypaths_do_operation(OPERATION_INTERSECTION, p_polygon_a, p_polygon_b); - } - - static Vector<Vector<Point2>> exclude_polygons_2d(const Vector<Point2> &p_polygon_a, const Vector<Point2> &p_polygon_b) { - return _polypaths_do_operation(OPERATION_XOR, p_polygon_a, p_polygon_b); - } - - static Vector<Vector<Point2>> clip_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) { - return _polypaths_do_operation(OPERATION_DIFFERENCE, p_polyline, p_polygon, true); - } - - static Vector<Vector<Point2>> intersect_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) { - return _polypaths_do_operation(OPERATION_INTERSECTION, p_polyline, p_polygon, true); - } - - static Vector<Vector<Point2>> offset_polygon_2d(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type) { - return _polypath_offset(p_polygon, p_delta, p_join_type, END_POLYGON); - } - - static Vector<Vector<Point2>> offset_polyline_2d(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) { - ERR_FAIL_COND_V_MSG(p_end_type == END_POLYGON, Vector<Vector<Point2>>(), "Attempt to offset a polyline like a polygon (use offset_polygon_2d instead)."); - - return _polypath_offset(p_polygon, p_delta, p_join_type, p_end_type); - } - - static Vector<int> triangulate_delaunay_2d(const Vector<Vector2> &p_points) { - Vector<Delaunay2D::Triangle> tr = Delaunay2D::triangulate(p_points); - Vector<int> triangles; - - for (int i = 0; i < tr.size(); i++) { - triangles.push_back(tr[i].points[0]); - triangles.push_back(tr[i].points[1]); - triangles.push_back(tr[i].points[2]); - } - return triangles; - } - - static Vector<int> triangulate_polygon(const Vector<Vector2> &p_polygon) { - Vector<int> triangles; - if (!Triangulate::triangulate(p_polygon, triangles)) { - return Vector<int>(); //fail - } - return triangles; - } - - static bool is_polygon_clockwise(const Vector<Vector2> &p_polygon) { - int c = p_polygon.size(); - if (c < 3) { - return false; - } - const Vector2 *p = p_polygon.ptr(); - real_t sum = 0; - for (int i = 0; i < c; i++) { - const Vector2 &v1 = p[i]; - const Vector2 &v2 = p[(i + 1) % c]; - sum += (v2.x - v1.x) * (v2.y + v1.y); - } - - return sum > 0.0f; - } - - // Alternate implementation that should be faster. - static bool is_point_in_polygon(const Vector2 &p_point, const Vector<Vector2> &p_polygon) { - int c = p_polygon.size(); - if (c < 3) { - return false; - } - const Vector2 *p = p_polygon.ptr(); - Vector2 further_away(-1e20, -1e20); - Vector2 further_away_opposite(1e20, 1e20); - - for (int i = 0; i < c; i++) { - further_away.x = MAX(p[i].x, further_away.x); - further_away.y = MAX(p[i].y, further_away.y); - further_away_opposite.x = MIN(p[i].x, further_away_opposite.x); - further_away_opposite.y = MIN(p[i].y, further_away_opposite.y); - } - - // Make point outside that won't intersect with points in segment from p_point. - further_away += (further_away - further_away_opposite) * Vector2(1.221313, 1.512312); - - int intersections = 0; - for (int i = 0; i < c; i++) { - const Vector2 &v1 = p[i]; - const Vector2 &v2 = p[(i + 1) % c]; - if (segment_intersects_segment_2d(v1, v2, p_point, further_away, nullptr)) { - intersections++; - } - } - - return (intersections & 1); - } - static Vector<Vector<Face3>> separate_objects(Vector<Face3> p_array); // Create a "wrap" that encloses the given geometry. @@ -999,50 +684,12 @@ public: return ret; } } - - static real_t vec2_cross(const Point2 &O, const Point2 &A, const Point2 &B) { - return (real_t)(A.x - O.x) * (B.y - O.y) - (real_t)(A.y - O.y) * (B.x - O.x); - } - - // Returns a list of points on the convex hull in counter-clockwise order. - // Note: the last point in the returned list is the same as the first one. - static Vector<Point2> convex_hull_2d(Vector<Point2> P) { - int n = P.size(), k = 0; - Vector<Point2> H; - H.resize(2 * n); - - // Sort points lexicographically. - P.sort(); - - // Build lower hull. - for (int i = 0; i < n; ++i) { - while (k >= 2 && vec2_cross(H[k - 2], H[k - 1], P[i]) <= 0) { - k--; - } - H.write[k++] = P[i]; - } - - // Build upper hull. - for (int i = n - 2, t = k + 1; i >= 0; i--) { - while (k >= t && vec2_cross(H[k - 2], H[k - 1], P[i]) <= 0) { - k--; - } - H.write[k++] = P[i]; - } - - H.resize(k); - return H; - } - static Vector<Vector<Vector2>> decompose_polygon_in_convex(Vector<Point2> polygon); - static MeshData build_convex_mesh(const Vector<Plane> &p_planes); static Vector<Plane> build_sphere_planes(real_t p_radius, int p_lats, int p_lons, Vector3::Axis p_axis = Vector3::AXIS_Z); static Vector<Plane> build_box_planes(const Vector3 &p_extents); static Vector<Plane> build_cylinder_planes(real_t p_radius, real_t p_height, int p_sides, Vector3::Axis p_axis = Vector3::AXIS_Z); static Vector<Plane> build_capsule_planes(real_t p_radius, real_t p_height, int p_sides, int p_lats, Vector3::Axis p_axis = Vector3::AXIS_Z); - static void make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_result, Size2i &r_size); - static Vector<Vector3> compute_convex_mesh_points(const Plane *p_planes, int p_plane_count); #define FINDMINMAX(x0, x1, x2, min, max) \ @@ -1255,9 +902,6 @@ public: return planeBoxOverlap(normal, d, boxhalfsize); /* if true, box and triangle overlaps */ } - static Vector<Point2i> pack_rects(const Vector<Size2i> &p_sizes, const Size2i &p_atlas_size); - static Vector<Vector3i> partial_pack_rects(const Vector<Vector2i> &p_sizes, const Size2i &p_atlas_size); - static Vector<uint32_t> generate_edf(const Vector<bool> &p_voxels, const Vector3i &p_size, bool p_negative); static Vector<int8_t> generate_sdf8(const Vector<uint32_t> &p_positive, const Vector<uint32_t> &p_negative); @@ -1302,9 +946,15 @@ public: #undef STP } -private: - static Vector<Vector<Point2>> _polypaths_do_operation(PolyBooleanOperation p_op, const Vector<Point2> &p_polypath_a, const Vector<Point2> &p_polypath_b, bool is_a_open = false); - static Vector<Vector<Point2>> _polypath_offset(const Vector<Point2> &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type); + _FORCE_INLINE_ static Vector3 octahedron_map_decode(const Vector2 &p_uv) { + // https://twitter.com/Stubbesaurus/status/937994790553227264 + Vector2 f = p_uv * 2.0 - Vector2(1.0, 1.0); + Vector3 n = Vector3(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(); + } }; -#endif // GEOMETRY_H +#endif // GEOMETRY_3D_H diff --git a/core/math/octree.h b/core/math/octree.h index c05fc4e9ed..5d9688d442 100644 --- a/core/math/octree.h +++ b/core/math/octree.h @@ -34,7 +34,7 @@ #include "core/list.h" #include "core/map.h" #include "core/math/aabb.h" -#include "core/math/geometry.h" +#include "core/math/geometry_3d.h" #include "core/math/vector3.h" #include "core/print_string.h" #include "core/variant.h" @@ -1201,7 +1201,7 @@ int Octree<T, use_pairs, AL>::cull_convex(const Vector<Plane> &p_convex, T **p_r return 0; } - Vector<Vector3> convex_points = Geometry::compute_convex_mesh_points(&p_convex[0], p_convex.size()); + Vector<Vector3> convex_points = Geometry3D::compute_convex_mesh_points(&p_convex[0], p_convex.size()); if (convex_points.size() == 0) { return 0; } diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp index fe16904448..8ba1ba9286 100644 --- a/core/math/quick_hull.cpp +++ b/core/math/quick_hull.cpp @@ -34,7 +34,7 @@ uint32_t QuickHull::debug_stop_after = 0xFFFFFFFF; -Error QuickHull::build(const Vector<Vector3> &p_points, Geometry::MeshData &r_mesh) { +Error QuickHull::build(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_mesh) { /* CREATE AABB VOLUME */ AABB aabb; @@ -334,17 +334,17 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry::MeshData &r_me //make a map of edges again Map<Edge, RetFaceConnect> ret_edges; - List<Geometry::MeshData::Face> ret_faces; + List<Geometry3D::MeshData::Face> ret_faces; for (List<Face>::Element *E = faces.front(); E; E = E->next()) { - Geometry::MeshData::Face f; + Geometry3D::MeshData::Face f; f.plane = E->get().plane; for (int i = 0; i < 3; i++) { f.indices.push_back(E->get().vertices[i]); } - List<Geometry::MeshData::Face>::Element *F = ret_faces.push_back(f); + List<Geometry3D::MeshData::Face>::Element *F = ret_faces.push_back(f); for (int i = 0; i < 3; i++) { uint32_t a = E->get().vertices[i]; @@ -366,8 +366,8 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry::MeshData &r_me //fill faces - for (List<Geometry::MeshData::Face>::Element *E = ret_faces.front(); E; E = E->next()) { - Geometry::MeshData::Face &f = E->get(); + for (List<Geometry3D::MeshData::Face>::Element *E = ret_faces.front(); E; E = E->next()) { + Geometry3D::MeshData::Face &f = E->get(); for (int i = 0; i < f.indices.size(); i++) { int a = E->get().indices[i]; @@ -377,7 +377,7 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry::MeshData &r_me Map<Edge, RetFaceConnect>::Element *F = ret_edges.find(e); ERR_CONTINUE(!F); - List<Geometry::MeshData::Face>::Element *O = F->get().left == E ? F->get().right : F->get().left; + List<Geometry3D::MeshData::Face>::Element *O = F->get().left == E ? F->get().right : F->get().left; ERR_CONTINUE(O == E); ERR_CONTINUE(O == nullptr); @@ -439,13 +439,13 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry::MeshData &r_me r_mesh.faces.resize(ret_faces.size()); int idx = 0; - for (List<Geometry::MeshData::Face>::Element *E = ret_faces.front(); E; E = E->next()) { + for (List<Geometry3D::MeshData::Face>::Element *E = ret_faces.front(); E; E = E->next()) { r_mesh.faces.write[idx++] = E->get(); } r_mesh.edges.resize(ret_edges.size()); idx = 0; for (Map<Edge, RetFaceConnect>::Element *E = ret_edges.front(); E; E = E->next()) { - Geometry::MeshData::Edge e; + Geometry3D::MeshData::Edge e; e.a = E->key().vertices[0]; e.b = E->key().vertices[1]; r_mesh.edges.write[idx++] = e; diff --git a/core/math/quick_hull.h b/core/math/quick_hull.h index 29f709febe..cac8e58d23 100644 --- a/core/math/quick_hull.h +++ b/core/math/quick_hull.h @@ -33,7 +33,7 @@ #include "core/list.h" #include "core/math/aabb.h" -#include "core/math/geometry.h" +#include "core/math/geometry_3d.h" #include "core/set.h" class QuickHull { @@ -74,13 +74,13 @@ private: FaceConnect() {} }; struct RetFaceConnect { - List<Geometry::MeshData::Face>::Element *left, *right = nullptr; + List<Geometry3D::MeshData::Face>::Element *left, *right = nullptr; RetFaceConnect() {} }; public: static uint32_t debug_stop_after; - static Error build(const Vector<Vector3> &p_points, Geometry::MeshData &r_mesh); + static Error build(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_mesh); }; #endif // QUICK_HULL_H diff --git a/core/math/rect2.h b/core/math/rect2.h index 1b86dbd49a..14393325ec 100644 --- a/core/math/rect2.h +++ b/core/math/rect2.h @@ -156,7 +156,7 @@ struct Rect2 { new_rect.size = new_rect.size - new_rect.position; //make relative again return new_rect; - }; + } inline bool has_point(const Point2 &p_point) const { if (p_point.x < position.x) { return false; @@ -323,7 +323,7 @@ struct Rect2i { new_rect.size = new_rect.size - new_rect.position; //make relative again return new_rect; - }; + } bool has_point(const Point2 &p_point) const { if (p_point.x < position.x) { return false; diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp index dee1b3b23e..180aeaa0af 100644 --- a/core/math/transform_2d.cpp +++ b/core/math/transform_2d.cpp @@ -78,12 +78,7 @@ void Transform2D::set_skew(float p_angle) { } real_t Transform2D::get_rotation() const { - real_t det = basis_determinant(); - Transform2D m = orthonormalized(); - if (det < 0) { - m.scale_basis(Size2(1, -1)); // convention to separate rotation and reflection for 2D is to absorb a flip along y into scaling. - } - return Math::atan2(m[0].y, m[0].x); + return Math::atan2(elements[0].y, elements[0].x); } void Transform2D::set_rotation(real_t p_rot) { diff --git a/core/math/triangulate.cpp b/core/math/triangulate.cpp index 7fab36ff50..12bd384c6a 100644 --- a/core/math/triangulate.cpp +++ b/core/math/triangulate.cpp @@ -79,7 +79,7 @@ bool Triangulate::is_inside_triangle(real_t Ax, real_t Ay, } else { return ((aCROSSbp >= 0.0) && (bCROSScp >= 0.0) && (cCROSSap >= 0.0)); } -}; +} bool Triangulate::snip(const Vector<Vector2> &p_contour, int u, int v, int w, int n, const Vector<int> &V, bool relaxed) { int p; diff --git a/core/math/vector2.cpp b/core/math/vector2.cpp index 7f264ce119..233421e070 100644 --- a/core/math/vector2.cpp +++ b/core/math/vector2.cpp @@ -209,28 +209,29 @@ void Vector2i::operator-=(const Vector2i &p_v) { Vector2i Vector2i::operator*(const Vector2i &p_v1) const { return Vector2i(x * p_v1.x, y * p_v1.y); -}; +} Vector2i Vector2i::operator*(const int &rvalue) const { return Vector2i(x * rvalue, y * rvalue); -}; +} + void Vector2i::operator*=(const int &rvalue) { x *= rvalue; y *= rvalue; -}; +} Vector2i Vector2i::operator/(const Vector2i &p_v1) const { return Vector2i(x / p_v1.x, y / p_v1.y); -}; +} Vector2i Vector2i::operator/(const int &rvalue) const { return Vector2i(x / rvalue, y / rvalue); -}; +} void Vector2i::operator/=(const int &rvalue) { x /= rvalue; y /= rvalue; -}; +} Vector2i Vector2i::operator-() const { return Vector2i(-x, -y); diff --git a/core/math/vector2.h b/core/math/vector2.h index e5774f1d55..8a08d3bf64 100644 --- a/core/math/vector2.h +++ b/core/math/vector2.h @@ -174,28 +174,29 @@ _FORCE_INLINE_ void Vector2::operator-=(const Vector2 &p_v) { _FORCE_INLINE_ Vector2 Vector2::operator*(const Vector2 &p_v1) const { return Vector2(x * p_v1.x, y * p_v1.y); -}; +} _FORCE_INLINE_ Vector2 Vector2::operator*(const real_t &rvalue) const { return Vector2(x * rvalue, y * rvalue); -}; +} + _FORCE_INLINE_ void Vector2::operator*=(const real_t &rvalue) { x *= rvalue; y *= rvalue; -}; +} _FORCE_INLINE_ Vector2 Vector2::operator/(const Vector2 &p_v1) const { return Vector2(x / p_v1.x, y / p_v1.y); -}; +} _FORCE_INLINE_ Vector2 Vector2::operator/(const real_t &rvalue) const { return Vector2(x / rvalue, y / rvalue); -}; +} _FORCE_INLINE_ void Vector2::operator/=(const real_t &rvalue) { x /= rvalue; y /= rvalue; -}; +} _FORCE_INLINE_ Vector2 Vector2::operator-() const { return Vector2(-x, -y); diff --git a/core/message_queue.cpp b/core/message_queue.cpp index 8c71f760b2..6dcf24e7ed 100644 --- a/core/message_queue.cpp +++ b/core/message_queue.cpp @@ -155,6 +155,21 @@ Error MessageQueue::push_callable(const Callable &p_callable, const Variant **p_ return OK; } +Error MessageQueue::push_callable(const Callable &p_callable, VARIANT_ARG_DECLARE) { + VARIANT_ARGPTRS; + + int argc = 0; + + for (int i = 0; i < VARIANT_ARG_MAX; i++) { + if (argptr[i]->get_type() == Variant::NIL) { + break; + } + argc++; + } + + return push_callable(p_callable, argptr, argc); +} + void MessageQueue::statistics() { Map<StringName, int> set_count; Map<int, int> notify_count; diff --git a/core/message_queue.h b/core/message_queue.h index 8e50f1b2b7..7d13e26208 100644 --- a/core/message_queue.h +++ b/core/message_queue.h @@ -79,6 +79,7 @@ public: Error push_notification(ObjectID p_id, int p_notification); Error push_set(ObjectID p_id, const StringName &p_prop, const Variant &p_value); Error push_callable(const Callable &p_callable, const Variant **p_args, int p_argcount, bool p_show_error = false); + Error push_callable(const Callable &p_callable, VARIANT_ARG_LIST); Error push_call(Object *p_object, const StringName &p_method, VARIANT_ARG_LIST); Error push_notification(Object *p_object, int p_notification); diff --git a/core/oa_hash_map.h b/core/oa_hash_map.h index e411ced044..775e17fdb5 100644 --- a/core/oa_hash_map.h +++ b/core/oa_hash_map.h @@ -45,17 +45,22 @@ * * The entries are stored inplace, so huge keys or values might fill cache lines * a lot faster. + * + * Only used keys and values are constructed. For free positions there's space + * in the arrays for each, but that memory is kept uninitialized. + * + * The assignment operator copy the pairs from one map to the other. */ template <class TKey, class TValue, class Hasher = HashMapHasherDefault, class Comparator = HashMapComparatorDefault<TKey>> class OAHashMap { private: - TValue *values; - TKey *keys; - uint32_t *hashes; + TValue *values = nullptr; + TKey *keys = nullptr; + uint32_t *hashes = nullptr; - uint32_t capacity; + uint32_t capacity = 0; uint32_t num_elements = 0; @@ -139,32 +144,42 @@ private: void _resize_and_rehash(uint32_t p_new_capacity) { uint32_t old_capacity = capacity; - capacity = p_new_capacity; + + // Capacity can't be 0. + capacity = MAX(1, p_new_capacity); TKey *old_keys = keys; TValue *old_values = values; uint32_t *old_hashes = hashes; num_elements = 0; - keys = memnew_arr(TKey, capacity); - values = memnew_arr(TValue, capacity); - hashes = memnew_arr(uint32_t, capacity); + keys = static_cast<TKey *>(Memory::alloc_static(sizeof(TKey) * capacity)); + values = static_cast<TValue *>(Memory::alloc_static(sizeof(TValue) * capacity)); + hashes = static_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity)); for (uint32_t i = 0; i < capacity; i++) { hashes[i] = 0; } + if (old_capacity == 0) { + // Nothing to do. + return; + } + for (uint32_t i = 0; i < old_capacity; i++) { if (old_hashes[i] == EMPTY_HASH) { continue; } _insert_with_hash(old_hashes[i], old_keys[i], old_values[i]); + + old_keys[i].~TKey(); + old_values[i].~TValue(); } - memdelete_arr(old_keys); - memdelete_arr(old_values); - memdelete_arr(old_hashes); + Memory::free_static(old_keys); + Memory::free_static(old_values); + Memory::free_static(old_hashes); } void _resize_and_rehash() { @@ -208,8 +223,7 @@ public: bool exists = _lookup_pos(p_key, pos); if (exists) { - values[pos].~TValue(); - memnew_placement(&values[pos], TValue(p_data)); + values[pos] = p_data; } else { insert(p_key, p_data); } @@ -226,8 +240,7 @@ public: bool exists = _lookup_pos(p_key, pos); if (exists) { - r_data.~TValue(); - memnew_placement(&r_data, TValue(values[pos])); + r_data = values[pos]; return true; } @@ -294,7 +307,7 @@ public: bool valid; const TKey *key; - const TValue *value; + TValue *value; private: uint32_t pos; @@ -337,25 +350,49 @@ public: return it; } - OAHashMap(const OAHashMap &) = delete; // Delete the copy constructor so we don't get unexpected copies and dangling pointers. - OAHashMap &operator=(const OAHashMap &) = delete; // Same for assignment operator. + OAHashMap(const OAHashMap &p_other) { + (*this) = p_other; + } + + OAHashMap &operator=(const OAHashMap &p_other) { + if (capacity != 0) { + clear(); + } + + _resize_and_rehash(p_other.capacity); + + for (Iterator it = p_other.iter(); it.valid; it = p_other.next_iter(it)) { + set(*it.key, *it.value); + } + return *this; + } OAHashMap(uint32_t p_initial_capacity = 64) { - capacity = p_initial_capacity; + // Capacity can't be 0. + capacity = MAX(1, p_initial_capacity); - keys = memnew_arr(TKey, p_initial_capacity); - values = memnew_arr(TValue, p_initial_capacity); - hashes = memnew_arr(uint32_t, p_initial_capacity); + keys = static_cast<TKey *>(Memory::alloc_static(sizeof(TKey) * capacity)); + values = static_cast<TValue *>(Memory::alloc_static(sizeof(TValue) * capacity)); + hashes = static_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity)); - for (uint32_t i = 0; i < p_initial_capacity; i++) { + for (uint32_t i = 0; i < capacity; i++) { hashes[i] = EMPTY_HASH; } } ~OAHashMap() { - memdelete_arr(keys); - memdelete_arr(values); - memdelete_arr(hashes); + for (uint32_t i = 0; i < capacity; i++) { + if (hashes[i] == EMPTY_HASH) { + continue; + } + + values[i].~TValue(); + keys[i].~TKey(); + } + + Memory::free_static(keys); + Memory::free_static(values); + Memory::free_static(hashes); } }; diff --git a/core/object.cpp b/core/object.cpp index 0a4e8a5890..8abea9ca7e 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -1000,7 +1000,7 @@ void Object::set_meta(const String &p_name, const Variant &p_value) { if (p_value.get_type() == Variant::NIL) { metadata.erase(p_name); return; - }; + } metadata[p_name] = p_value; } @@ -2038,23 +2038,31 @@ void ObjectDB::cleanup() { if (slot_count > 0) { spin_lock.lock(); - WARN_PRINT("ObjectDB Instances still exist!"); + WARN_PRINT("ObjectDB instances leaked at exit (run with --verbose for details)."); if (OS::get_singleton()->is_stdout_verbose()) { + // Ensure calling the native classes because if a leaked instance has a script + // that overrides any of those methods, it'd not be OK to call them at this point, + // now the scripting languages have already been terminated. + MethodBind *node_get_name = ClassDB::get_method("Node", "get_name"); + MethodBind *resource_get_path = ClassDB::get_method("Resource", "get_path"); + Callable::CallError call_error; + for (uint32_t i = 0; i < slot_count; i++) { uint32_t slot = object_slots[i].next_free; Object *obj = object_slots[slot].object; - String node_name; + String extra_info; if (obj->is_class("Node")) { - node_name = " - Node name: " + String(obj->call("get_name")); + extra_info = " - Node name: " + String(node_get_name->call(obj, nullptr, 0, call_error)); } if (obj->is_class("Resource")) { - node_name = " - Resource name: " + String(obj->call("get_name")) + " Path: " + String(obj->call("get_path")); + extra_info = " - Resource path: " + String(resource_get_path->call(obj, nullptr, 0, call_error)); } uint64_t id = uint64_t(slot) | (uint64_t(object_slots[slot].validator) << OBJECTDB_VALIDATOR_BITS) | (object_slots[slot].is_reference ? OBJECTDB_REFERENCE_BIT : 0); - print_line("Leaked instance: " + String(obj->get_class()) + ":" + itos(id) + node_name); + print_line("Leaked instance: " + String(obj->get_class()) + ":" + itos(id) + extra_info); } + print_line("Hint: Leaked instances typically happen when nodes are removed from the scene tree (with `remove_child()`) but not freed (with `free()` or `queue_free()`)."); } spin_lock.unlock(); } diff --git a/core/object.h b/core/object.h index 95662f6208..5b46a0f93a 100644 --- a/core/object.h +++ b/core/object.h @@ -124,6 +124,7 @@ enum PropertyUsageFlags { PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT = 1 << 24, PROPERTY_USAGE_KEYING_INCREMENTS = 1 << 25, // Used in inspector to increment property when keyed in animation player PROPERTY_USAGE_DEFERRED_SET_RESOURCE = 1 << 26, // when loading, the resource for this property can be set at the end of loading + PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT = 1 << 27, // For Object properties, instantiate them when creating in editor. PROPERTY_USAGE_DEFAULT = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK, PROPERTY_USAGE_DEFAULT_INTL = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK | PROPERTY_USAGE_INTERNATIONALIZED, diff --git a/core/ordered_hash_map.h b/core/ordered_hash_map.h index 1f1be71741..e6a6340a2f 100644 --- a/core/ordered_hash_map.h +++ b/core/ordered_hash_map.h @@ -106,27 +106,27 @@ public: const K &key() const { CRASH_COND(!list_element); return *(list_element->get().first); - }; + } V &value() { CRASH_COND(!list_element); return list_element->get().second; - }; + } const V &value() const { CRASH_COND(!list_element); return list_element->get().second; - }; + } V &get() { CRASH_COND(!list_element); return list_element->get().second; - }; + } const V &get() const { CRASH_COND(!list_element); return list_element->get().second; - }; + } }; class ConstElement { @@ -172,17 +172,17 @@ public: const K &key() const { CRASH_COND(!list_element); return *(list_element->get().first); - }; + } const V &value() const { CRASH_COND(!list_element); return list_element->get().second; - }; + } const V &get() const { CRASH_COND(!list_element); return list_element->get().second; - }; + } }; ConstElement find(const K &p_key) const { diff --git a/core/os/dir_access.cpp b/core/os/dir_access.cpp index 9f2672e038..5e1cb8ea29 100644 --- a/core/os/dir_access.cpp +++ b/core/os/dir_access.cpp @@ -131,7 +131,7 @@ Error DirAccess::erase_contents_recursive() { Error DirAccess::make_dir_recursive(String p_dir) { if (p_dir.length() < 1) { return OK; - }; + } String full_dir; @@ -185,7 +185,7 @@ String DirAccess::fix_path(String p_path) const { String resource_path = ProjectSettings::get_singleton()->get_resource_path(); if (resource_path != "") { return p_path.replace_first("res:/", resource_path); - }; + } return p_path.replace_first("res://", ""); } } @@ -196,7 +196,7 @@ String DirAccess::fix_path(String p_path) const { String data_dir = OS::get_singleton()->get_user_data_dir(); if (data_dir != "") { return p_path.replace_first("user:/", data_dir); - }; + } return p_path.replace_first("user://", ""); } @@ -249,7 +249,7 @@ DirAccess *DirAccess::create(AccessType p_access) { } return da; -}; +} String DirAccess::get_full_path(const String &p_path, AccessType p_access) { DirAccess *d = DirAccess::create(p_access); diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp index f9ba8ff2d2..20b3435911 100644 --- a/core/os/file_access.cpp +++ b/core/os/file_access.cpp @@ -65,7 +65,7 @@ bool FileAccess::exists(const String &p_name) { void FileAccess::_set_access_type(AccessType p_access) { _access_type = p_access; -}; +} FileAccess *FileAccess::create_for_path(const String &p_path) { FileAccess *ret = nullptr; @@ -83,7 +83,7 @@ FileAccess *FileAccess::create_for_path(const String &p_path) { Error FileAccess::reopen(const String &p_path, int p_mode_flags) { return _open(p_path, p_mode_flags); -}; +} FileAccess *FileAccess::open(const String &p_path, int p_mode_flags, Error *r_error) { //try packed data first @@ -115,7 +115,7 @@ FileAccess *FileAccess::open(const String &p_path, int p_mode_flags, Error *r_er FileAccess::CreateFunc FileAccess::get_create_func(AccessType p_access) { return create_func[p_access]; -}; +} String FileAccess::fix_path(const String &p_path) const { //helper used by file accesses that use a single filesystem @@ -129,7 +129,7 @@ String FileAccess::fix_path(const String &p_path) const { String resource_path = ProjectSettings::get_singleton()->get_resource_path(); if (resource_path != "") { return r_path.replace("res:/", resource_path); - }; + } return r_path.replace("res://", ""); } } @@ -140,7 +140,7 @@ String FileAccess::fix_path(const String &p_path) const { String data_dir = OS::get_singleton()->get_user_data_dir(); if (data_dir != "") { return r_path.replace("user:/", data_dir); - }; + } return r_path.replace("user://", ""); } @@ -215,7 +215,7 @@ float FileAccess::get_float() const { MarshallFloat m; m.i = get_32(); return m.f; -}; +} real_t FileAccess::get_real() const { if (real_is_double) { @@ -229,7 +229,7 @@ double FileAccess::get_double() const { MarshallDouble m; m.l = get_64(); return m.d; -}; +} String FileAccess::get_token() const { CharString token; @@ -447,13 +447,13 @@ void FileAccess::store_float(float p_dest) { MarshallFloat m; m.f = p_dest; store_32(m.i); -}; +} void FileAccess::store_double(double p_dest) { MarshallDouble m; m.d = p_dest; store_64(m.l); -}; +} uint64_t FileAccess::get_modified_time(const String &p_file) { if (PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled() && PackedData::get_singleton()->has_path(p_file)) { @@ -503,7 +503,7 @@ void FileAccess::store_pascal_string(const String &p_string) { CharString cs = p_string.utf8(); store_32(cs.length()); store_buffer((uint8_t *)&cs[0], cs.length()); -}; +} String FileAccess::get_pascal_string() { uint32_t sl = get_32(); @@ -516,7 +516,7 @@ String FileAccess::get_pascal_string() { ret.parse_utf8(cs.ptr()); return ret; -}; +} void FileAccess::store_line(const String &p_line) { store_string(p_line); diff --git a/core/os/os.cpp b/core/os/os.cpp index da9dabd401..c842be333c 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -83,21 +83,13 @@ uint64_t OS::get_splash_tick_msec() const { return _msec_splash; } -uint64_t OS::get_unix_time() const { - return 0; -}; -uint64_t OS::get_system_time_secs() const { - return 0; -} - -uint64_t OS::get_system_time_msecs() const { +double OS::get_unix_time() const { return 0; } -void OS::debug_break(){ - +void OS::debug_break() { // something -}; +} void OS::_set_logger(CompositeLogger *p_logger) { if (_logger) { @@ -127,7 +119,7 @@ void OS::print(const char *p_format, ...) { _logger->logv(p_format, argp, false); va_end(argp); -}; +} void OS::printerr(const char *p_format, ...) { va_list argp; @@ -136,7 +128,7 @@ void OS::printerr(const char *p_format, ...) { _logger->logv(p_format, argp, true); va_end(argp); -}; +} void OS::set_low_processor_usage_mode(bool p_enabled) { low_processor_usage_mode = p_enabled; @@ -160,7 +152,7 @@ String OS::get_executable_path() const { int OS::get_process_id() const { return -1; -}; +} void OS::vibrate_handheld(int p_duration_ms) { WARN_PRINT("vibrate_handheld() only works with Android and iOS"); @@ -282,12 +274,12 @@ String OS::get_cache_path() const { // Path to macOS .app bundle resources String OS::get_bundle_resource_dir() const { return "."; -}; +} // OS specific path for user:// String OS::get_user_data_dir() const { return "."; -}; +} // Absolute path to res:// String OS::get_resource_dir() const { @@ -301,7 +293,7 @@ String OS::get_system_dir(SystemDir p_dir) const { Error OS::shell_open(String p_uri) { return ERR_UNAVAILABLE; -}; +} // implement these with the canvas? @@ -346,7 +338,7 @@ String OS::get_model_name() const { void OS::set_cmdline(const char *p_execpath, const List<String> &p_args) { _execpath = p_execpath; _cmdline = p_args; -}; +} String OS::get_unique_id() const { ERR_FAIL_V(""); @@ -457,18 +449,22 @@ PackedStringArray OS::get_connected_midi_inputs() { } PackedStringArray list; - return list; + ERR_FAIL_V_MSG(list, vformat("MIDI input isn't supported on %s.", OS::get_singleton()->get_name())); } void OS::open_midi_inputs() { if (MIDIDriver::get_singleton()) { MIDIDriver::get_singleton()->open(); + } else { + ERR_PRINT(vformat("MIDI input isn't supported on %s.", OS::get_singleton()->get_name())); } } void OS::close_midi_inputs() { if (MIDIDriver::get_singleton()) { MIDIDriver::get_singleton()->close(); + } else { + ERR_PRINT(vformat("MIDI input isn't supported on %s.", OS::get_singleton()->get_name())); } } diff --git a/core/os/os.h b/core/os/os.h index 9296e17bb2..04e10518dc 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -58,7 +58,6 @@ class OS { bool _allow_layered = false; bool _use_vsync; bool _vsync_via_compositor; - bool _disable_wintab; char *last_error; @@ -148,7 +147,11 @@ public: bool is_layered_allowed() const { return _allow_layered; } bool is_hidpi_allowed() const { return _allow_hidpi; } - bool is_wintab_disabled() const { return _disable_wintab; } + + virtual int get_tablet_driver_count() const { return 0; }; + virtual String get_tablet_driver_name(int p_driver) const { return ""; }; + virtual String get_current_tablet_driver() const { return ""; }; + virtual void set_current_tablet_driver(const String &p_driver){}; void ensure_user_data_dir(); @@ -206,9 +209,7 @@ public: virtual Time get_time(bool local = false) const = 0; virtual TimeZoneInfo get_time_zone_info() const = 0; virtual String get_iso_date_time(bool local = false) const; - virtual uint64_t get_unix_time() const; - virtual uint64_t get_system_time_secs() const; - virtual uint64_t get_system_time_msecs() const; + virtual double get_unix_time() const; virtual void delay_usec(uint32_t p_usec) const = 0; virtual uint64_t get_ticks_usec() const = 0; diff --git a/core/os/thread.cpp b/core/os/thread.cpp index 70f960ed2a..fc0ce3c9b4 100644 --- a/core/os/thread.cpp +++ b/core/os/thread.cpp @@ -63,4 +63,4 @@ Error Thread::set_name(const String &p_name) { } return ERR_UNAVAILABLE; -}; +} diff --git a/core/os/thread_dummy.cpp b/core/os/thread_dummy.cpp index 9dcddcae11..2672cd7ad9 100644 --- a/core/os/thread_dummy.cpp +++ b/core/os/thread_dummy.cpp @@ -34,16 +34,16 @@ Thread *ThreadDummy::create(ThreadCreateCallback p_callback, void *p_user, const Thread::Settings &p_settings) { return memnew(ThreadDummy); -}; +} void ThreadDummy::make_default() { Thread::create_func = &ThreadDummy::create; -}; +} RWLock *RWLockDummy::create() { return memnew(RWLockDummy); -}; +} void RWLockDummy::make_default() { RWLock::create_func = &RWLockDummy::create; -}; +} diff --git a/core/packed_data_container.cpp b/core/packed_data_container.cpp index b5aefd6f2c..e335ec0daa 100644 --- a/core/packed_data_container.cpp +++ b/core/packed_data_container.cpp @@ -44,7 +44,7 @@ Variant PackedDataContainer::getvar(const Variant &p_key, bool *r_valid) const { int PackedDataContainer::size() const { return _size(0); -}; +} Variant PackedDataContainer::_iter_init_ofs(const Array &p_iter, uint32_t p_offset) { Array ref = p_iter; @@ -124,7 +124,7 @@ uint32_t PackedDataContainer::_type_at_ofs(uint32_t p_ofs) const { uint32_t type = decode_uint32(r); return type; -}; +} int PackedDataContainer::_size(uint32_t p_ofs) const { const uint8_t *rd = data.ptr(); @@ -139,10 +139,10 @@ int PackedDataContainer::_size(uint32_t p_ofs) const { } else if (type == TYPE_DICT) { uint32_t len = decode_uint32(r + 4); return len; - }; + } return -1; -}; +} Variant PackedDataContainer::_key_at_ofs(uint32_t p_ofs, const Variant &p_key, bool &err) const { const uint8_t *rd = data.ptr(); @@ -368,7 +368,7 @@ Variant PackedDataContainerRef::_iter_get(const Variant &p_iter) { bool PackedDataContainerRef::_is_dictionary() const { return from->_type_at_ofs(offset) == PackedDataContainer::TYPE_DICT; -}; +} void PackedDataContainerRef::_bind_methods() { ClassDB::bind_method(D_METHOD("size"), &PackedDataContainerRef::size); @@ -389,4 +389,4 @@ Variant PackedDataContainerRef::getvar(const Variant &p_key, bool *r_valid) cons int PackedDataContainerRef::size() const { return from->_size(offset); -}; +} diff --git a/core/pool_allocator.cpp b/core/pool_allocator.cpp index 1dd215a787..b222c20a00 100644 --- a/core/pool_allocator.cpp +++ b/core/pool_allocator.cpp @@ -341,7 +341,7 @@ Error PoolAllocator::resize(ID p_mem, int p_new_size) { if (uint32_t(_free + aligned(e->len)) < alloc_size) { mt_unlock(); ERR_FAIL_V(ERR_OUT_OF_MEMORY); - }; + } EntryIndicesPos entry_indices_pos; @@ -358,7 +358,7 @@ Error PoolAllocator::resize(ID p_mem, int p_new_size) { next_pos = pool_size; // - static_area_size; } else { next_pos = entry_array[entry_indices[entry_indices_pos + 1]].pos; - }; + } if ((next_pos - e->pos) > alloc_size) { free_mem += aligned(e->len); @@ -564,8 +564,8 @@ PoolAllocator::PoolAllocator(void *p_mem, int p_size, int p_align, bool p_needs_ mem8 += p_align - (ofs % p_align); p_size -= dif; p_mem = (void *)mem8; - }; - }; + } + } create_pool(p_mem, p_size, p_max_entries); needs_locking = p_needs_locking; diff --git a/core/project_settings.cpp b/core/project_settings.cpp index cedc7f731f..5247f6da40 100644 --- a/core/project_settings.cpp +++ b/core/project_settings.cpp @@ -51,7 +51,7 @@ ProjectSettings *ProjectSettings::get_singleton() { String ProjectSettings::get_resource_path() const { return resource_path; -}; +} String ProjectSettings::localize_path(const String &p_path) const { if (resource_path == "") { @@ -87,7 +87,7 @@ String ProjectSettings::localize_path(const String &p_path) const { if (!cwd.begins_with(res_path)) { return p_path; - }; + } return cwd.replace_first(res_path, "res://"); } else { @@ -96,20 +96,20 @@ String ProjectSettings::localize_path(const String &p_path) const { int sep = path.find_last("/"); if (sep == -1) { return "res://" + path; - }; + } String parent = path.substr(0, sep); String plocal = localize_path(parent); if (plocal == "") { return ""; - }; + } // Only strip the starting '/' from 'path' if its parent ('plocal') ends with '/' if (plocal[plocal.length() - 1] == '/') { sep += 1; } return plocal + path.substr(sep, path.size() - sep); - }; + } } void ProjectSettings::set_initial_value(const String &p_name, const Variant &p_value) { @@ -126,13 +126,13 @@ String ProjectSettings::globalize_path(const String &p_path) const { if (p_path.begins_with("res://")) { if (resource_path != "") { return p_path.replace("res:/", resource_path); - }; + } return p_path.replace("res://", ""); } else if (p_path.begins_with("user://")) { String data_dir = OS::get_singleton()->get_user_data_dir(); if (data_dir != "") { return p_path.replace("user:/", data_dir); - }; + } return p_path.replace("user://", ""); } @@ -295,10 +295,16 @@ void ProjectSettings::_convert_to_last_version(int p_from_version) { * using the following merit order: * - If using NetworkClient, try to lookup project file or fail. * - If --main-pack was passed by the user (`p_main_pack`), load it or fail. - * - Search for .pck file matching binary name. There are two possibilities: - * o exec_path.get_basename() + '.pck' (e.g. 'win_game.exe' -> 'win_game.pck') - * o exec_path + '.pck' (e.g. 'linux_game' -> 'linux_game.pck') - * For each tentative, if the file exists, load it or fail. + * - Search for project PCKs automatically. For each step we try loading a potential + * PCK, and if it doesn't work, we proceed to the next step. If any step succeeds, + * we try loading the project settings, and abort if it fails. Steps: + * o Bundled PCK in the executable. + * o [macOS only] PCK with same basename as the binary in the .app resource dir. + * o PCK with same basename as the binary in the binary's directory. We handle both + * changing the extension to '.pck' (e.g. 'win_game.exe' -> 'win_game.pck') and + * appending '.pck' to the binary name (e.g. 'linux_game' -> 'linux_game.pck'). + * o PCK with the same basename as the binary in the current working directory. + * Same as above for the two possible PCK file names. * - On relevant platforms (Android/iOS), lookup project file in OS resource path. * If found, load it or fail. * - Lookup project file in passed `p_path` (--path passed by the user), i.e. we @@ -339,65 +345,68 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b String exec_path = OS::get_singleton()->get_executable_path(); if (exec_path != "") { - // Attempt with exec_name.pck - // (This is the usual case when distributing a Godot game.) + // We do several tests sequentially until one succeeds to find a PCK, + // and if so we attempt loading it at the end. - // Based on the OS, it can be the exec path + '.pck' (Linux w/o extension, macOS in .app bundle) - // or the exec path's basename + '.pck' (Windows). - // We need to test both possibilities as extensions for Linux binaries are optional - // (so both 'mygame.bin' and 'mygame' should be able to find 'mygame.pck'). + // Attempt with PCK bundled into executable. + bool found = _load_resource_pack(exec_path); + // Attempt with exec_name.pck. + // (This is the usual case when distributing a Godot game.) String exec_dir = exec_path.get_base_dir(); String exec_filename = exec_path.get_file(); String exec_basename = exec_filename.get_basename(); - // Attempt with PCK bundled into executable - bool found = _load_resource_pack(exec_path); + // Based on the OS, it can be the exec path + '.pck' (Linux w/o extension, macOS in .app bundle) + // or the exec path's basename + '.pck' (Windows). + // We need to test both possibilities as extensions for Linux binaries are optional + // (so both 'mygame.bin' and 'mygame' should be able to find 'mygame.pck'). #ifdef OSX_ENABLED if (!found) { - // Attempt to load PCK from macOS .app bundle resources + // Attempt to load PCK from macOS .app bundle resources. found = _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().plus_file(exec_basename + ".pck")); } #endif if (!found) { - // Try to load data pack at the location of the executable - // As mentioned above, we have two potential names to attempt + // Try to load data pack at the location of the executable. + // As mentioned above, we have two potential names to attempt. found = _load_resource_pack(exec_dir.plus_file(exec_basename + ".pck")) || _load_resource_pack(exec_dir.plus_file(exec_filename + ".pck")); + } - if (!found) { - // If we couldn't find them next to the executable, we attempt - // the current working directory. Same story, two tests. - found = _load_resource_pack(exec_basename + ".pck") || _load_resource_pack(exec_filename + ".pck"); - } + if (!found) { + // If we couldn't find them next to the executable, we attempt + // the current working directory. Same story, two tests. + found = _load_resource_pack(exec_basename + ".pck") || _load_resource_pack(exec_filename + ".pck"); } - // If we opened our package, try and load our project + // If we opened our package, try and load our project. if (found) { Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary"); if (err == OK) { - // Load override from location of executable - // Optional, we don't mind if it fails + // Load override from location of the executable. + // Optional, we don't mind if it fails. _load_settings_text(exec_path.get_base_dir().plus_file("override.cfg")); } return err; } } - // Try to use the filesystem for files, according to OS. (only Android -when reading from pck- and iOS use this) + // Try to use the filesystem for files, according to OS. + // (Only Android -when reading from pck- and iOS use this.) if (OS::get_singleton()->get_resource_dir() != "") { // OS will call ProjectSettings->get_resource_path which will be empty if not overridden! // If the OS would rather use a specific location, then it will not be empty. resource_path = OS::get_singleton()->get_resource_dir().replace("\\", "/"); if (resource_path != "" && resource_path[resource_path.length() - 1] == '/') { - resource_path = resource_path.substr(0, resource_path.length() - 1); // chop end + resource_path = resource_path.substr(0, resource_path.length() - 1); // Chop end. } Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary"); if (err == OK) { - // Optional, we don't mind if it fails + // Optional, we don't mind if it fails. _load_settings_text("res://override.cfg"); } return err; @@ -418,7 +427,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b while (true) { err = _load_settings_text_or_binary(current_dir.plus_file("project.godot"), current_dir.plus_file("project.binary")); if (err == OK) { - // Optional, we don't mind if it fails + // Optional, we don't mind if it fails. _load_settings_text(current_dir.plus_file("override.cfg")); candidate = current_dir; found = true; @@ -438,7 +447,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b } resource_path = candidate; - resource_path = resource_path.replace("\\", "/"); // windows path to unix path just in case + resource_path = resource_path.replace("\\", "/"); // Windows path to Unix path just in case. memdelete(d); if (!found) { @@ -446,7 +455,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b } if (resource_path.length() && resource_path[resource_path.length() - 1] == '/') { - resource_path = resource_path.substr(0, resource_path.length() - 1); // chop end + resource_path = resource_path.substr(0, resource_path.length() - 1); // Chop end. } return OK; @@ -759,7 +768,7 @@ Error ProjectSettings::_save_settings_text(const String &p_file, const Map<Strin Error ProjectSettings::_save_custom_bnd(const String &p_file) { // add other params as dictionary and array? return save_custom(p_file); -}; +} Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_custom, const Vector<String> &p_custom_features, bool p_merge_with_current) { ERR_FAIL_COND_V_MSG(p_path == "", ERR_INVALID_PARAMETER, "Project settings save path cannot be empty."); diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index 3870141ecf..5dac42cacb 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -34,6 +34,7 @@ #include "core/class_db.h" #include "core/compressed_translation.h" #include "core/core_string_names.h" +#include "core/crypto/aes_context.h" #include "core/crypto/crypto.h" #include "core/crypto/hashing_context.h" #include "core/engine.h" @@ -60,7 +61,8 @@ #include "core/io/xml_parser.h" #include "core/math/a_star.h" #include "core/math/expression.h" -#include "core/math/geometry.h" +#include "core/math/geometry_2d.h" +#include "core/math/geometry_3d.h" #include "core/math/random_number_generator.h" #include "core/math/triangle_mesh.h" #include "core/os/main_loop.h" @@ -87,7 +89,8 @@ static _JSON *_json = nullptr; static IP *ip = nullptr; -static _Geometry *_geometry = nullptr; +static _Geometry2D *_geometry_2d = nullptr; +static _Geometry3D *_geometry_3d = nullptr; extern Mutex _global_mutex; @@ -163,6 +166,7 @@ void register_core_types() { // Crypto ClassDB::register_class<HashingContext>(); + ClassDB::register_class<AESContext>(); ClassDB::register_custom_instance_class<X509Certificate>(); ClassDB::register_custom_instance_class<CryptoKey>(); ClassDB::register_custom_instance_class<Crypto>(); @@ -213,7 +217,8 @@ void register_core_types() { ip = IP::create(); - _geometry = memnew(_Geometry); + _geometry_2d = memnew(_Geometry2D); + _geometry_3d = memnew(_Geometry3D); _resource_loader = memnew(_ResourceLoader); _resource_saver = memnew(_ResourceSaver); @@ -238,7 +243,8 @@ void register_core_settings() { void register_core_singletons() { ClassDB::register_class<ProjectSettings>(); ClassDB::register_virtual_class<IP>(); - ClassDB::register_class<_Geometry>(); + ClassDB::register_class<_Geometry2D>(); + ClassDB::register_class<_Geometry3D>(); ClassDB::register_class<_ResourceLoader>(); ClassDB::register_class<_ResourceSaver>(); ClassDB::register_class<_OS>(); @@ -253,7 +259,8 @@ void register_core_singletons() { Engine::get_singleton()->add_singleton(Engine::Singleton("ProjectSettings", ProjectSettings::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("IP", IP::get_singleton())); - Engine::get_singleton()->add_singleton(Engine::Singleton("Geometry", _Geometry::get_singleton())); + Engine::get_singleton()->add_singleton(Engine::Singleton("Geometry2D", _Geometry2D::get_singleton())); + Engine::get_singleton()->add_singleton(Engine::Singleton("Geometry3D", _Geometry3D::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("ResourceLoader", _ResourceLoader::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("ResourceSaver", _ResourceSaver::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("OS", _OS::get_singleton())); @@ -275,7 +282,8 @@ void unregister_core_types() { memdelete(_marshalls); memdelete(_json); - memdelete(_geometry); + memdelete(_geometry_2d); + memdelete(_geometry_3d); ResourceLoader::remove_resource_format_loader(resource_format_image); resource_format_image.unref(); diff --git a/core/resource.cpp b/core/resource.cpp index 0af8c9c2b3..3b589793ef 100644 --- a/core/resource.cpp +++ b/core/resource.cpp @@ -33,6 +33,7 @@ #include "core/core_string_names.h" #include "core/io/resource_loader.h" #include "core/os/file_access.h" +#include "core/os/os.h" #include "core/script_language.h" #include "scene/main/node.h" //only so casting works @@ -431,7 +432,14 @@ void ResourceCache::setup() { void ResourceCache::clear() { if (resources.size()) { - ERR_PRINT("Resources Still in use at Exit!"); + ERR_PRINT("Resources still in use at exit (run with --verbose for details)."); + if (OS::get_singleton()->is_stdout_verbose()) { + const String *K = nullptr; + while ((K = resources.next(K))) { + Resource *r = resources[*K]; + print_line(vformat("Resource still in use: %s (%s)", *K, r->get_class())); + } + } } resources.clear(); @@ -442,12 +450,6 @@ void ResourceCache::clear() { } void ResourceCache::reload_externals() { - /* - const String *K=nullptr; - while ((K=resources.next(K))) { - resources[*K]->reload_external_data(); - } - */ } bool ResourceCache::has(const String &p_path) { @@ -530,6 +532,5 @@ void ResourceCache::dump(const char *p_file, bool p_short) { } lock->read_unlock(); - #endif } diff --git a/core/ring_buffer.h b/core/ring_buffer.h index 2fd622b86f..6b71d12cf3 100644 --- a/core/ring_buffer.h +++ b/core/ring_buffer.h @@ -45,13 +45,13 @@ class RingBuffer { p_var += p_size; p_var = p_var & size_mask; return ret; - }; + } public: T read() { ERR_FAIL_COND_V(space_left() < 1, T()); return data.ptr()[inc(read_pos, 1)]; - }; + } int read(T *p_buf, int p_size, bool p_advance = true) { int left = data_left(); @@ -66,15 +66,15 @@ public: const T *read = data.ptr(); for (int i = 0; i < total; i++) { p_buf[dst++] = read[pos + i]; - }; + } to_read -= total; pos = 0; - }; + } if (p_advance) { inc(read_pos, p_size); - }; + } return p_size; - }; + } int copy(T *p_buf, int p_offset, int p_size) const { int left = data_left(); @@ -95,12 +95,12 @@ public: int total = end - pos; for (int i = 0; i < total; i++) { p_buf[dst++] = data[pos + i]; - }; + } to_read -= total; pos = 0; - }; + } return p_size; - }; + } int find(const T &t, int p_offset, int p_max_size) const { int left = data_left(); @@ -122,7 +122,7 @@ public: if (data[pos + i] == t) { return i + (p_max_size - to_read); } - }; + } to_read -= total; pos = 0; } @@ -133,7 +133,7 @@ public: p_n = MIN(p_n, data_left()); inc(read_pos, p_n); return p_n; - }; + } inline int decrease_write(int p_n) { p_n = MIN(p_n, data_left()); @@ -145,7 +145,7 @@ public: ERR_FAIL_COND_V(space_left() < 1, FAILED); data.write[inc(write_pos, 1)] = p_v; return OK; - }; + } int write(const T *p_buf, int p_size) { int left = space_left(); @@ -161,32 +161,32 @@ public: for (int i = 0; i < total; i++) { data.write[pos + i] = p_buf[src++]; - }; + } to_write -= total; pos = 0; - }; + } inc(write_pos, p_size); return p_size; - }; + } inline int space_left() const { int left = read_pos - write_pos; if (left < 0) { return size() + left - 1; - }; + } if (left == 0) { return size() - 1; - }; + } return left - 1; - }; + } inline int data_left() const { return size() - space_left() - 1; - }; + } inline int size() const { return data.size(); - }; + } inline void clear() { read_pos = 0; @@ -201,19 +201,19 @@ public: if (old_size < new_size && read_pos > write_pos) { for (int i = 0; i < write_pos; i++) { data.write[(old_size + i) & mask] = data[i]; - }; + } write_pos = (old_size + write_pos) & mask; } else { read_pos = read_pos & mask; write_pos = write_pos & mask; - }; + } size_mask = mask; - }; + } RingBuffer<T>(int p_power = 0) { resize(p_power); - }; + } ~RingBuffer<T>() {} }; diff --git a/core/safe_refcount.cpp b/core/safe_refcount.cpp index 22b9ff9741..d5ee778ef7 100644 --- a/core/safe_refcount.cpp +++ b/core/safe_refcount.cpp @@ -42,24 +42,27 @@ /* taken from boost */ \ while (true) { \ m_cpp_type tmp = static_cast<m_cpp_type const volatile &>(*(m_pw)); \ - if (tmp == 0) \ + if (tmp == 0) { \ return 0; /* if zero, can't add to it anymore */ \ - if (m_win_cmpxchg((m_win_type volatile *)(m_pw), tmp + 1, tmp) == tmp) \ + } \ + if (m_win_cmpxchg((m_win_type volatile *)(m_pw), tmp + 1, tmp) == tmp) { \ return tmp + 1; \ + } \ } #define ATOMIC_EXCHANGE_IF_GREATER_BODY(m_pw, m_val, m_win_type, m_win_cmpxchg, m_cpp_type) \ while (true) { \ m_cpp_type tmp = static_cast<m_cpp_type const volatile &>(*(m_pw)); \ - if (tmp >= m_val) \ + if (tmp >= m_val) { \ return tmp; /* already greater, or equal */ \ - if (m_win_cmpxchg((m_win_type volatile *)(m_pw), m_val, tmp) == tmp) \ + } \ + if (m_win_cmpxchg((m_win_type volatile *)(m_pw), m_val, tmp) == tmp) { \ return m_val; \ + } \ } -_ALWAYS_INLINE_ uint32_t _atomic_conditional_increment_impl(volatile uint32_t *pw){ - - ATOMIC_CONDITIONAL_INCREMENT_BODY(pw, LONG, InterlockedCompareExchange, uint32_t) +_ALWAYS_INLINE_ uint32_t _atomic_conditional_increment_impl(volatile uint32_t *pw) { + ATOMIC_CONDITIONAL_INCREMENT_BODY(pw, LONG, InterlockedCompareExchange, uint32_t); } _ALWAYS_INLINE_ uint32_t _atomic_decrement_impl(volatile uint32_t *pw) { @@ -78,14 +81,12 @@ _ALWAYS_INLINE_ uint32_t _atomic_add_impl(volatile uint32_t *pw, volatile uint32 return InterlockedAdd((LONG volatile *)pw, val); } -_ALWAYS_INLINE_ uint32_t _atomic_exchange_if_greater_impl(volatile uint32_t *pw, volatile uint32_t val){ - - ATOMIC_EXCHANGE_IF_GREATER_BODY(pw, val, LONG, InterlockedCompareExchange, uint32_t) +_ALWAYS_INLINE_ uint32_t _atomic_exchange_if_greater_impl(volatile uint32_t *pw, volatile uint32_t val) { + ATOMIC_EXCHANGE_IF_GREATER_BODY(pw, val, LONG, InterlockedCompareExchange, uint32_t); } -_ALWAYS_INLINE_ uint64_t _atomic_conditional_increment_impl(volatile uint64_t *pw){ - - ATOMIC_CONDITIONAL_INCREMENT_BODY(pw, LONGLONG, InterlockedCompareExchange64, uint64_t) +_ALWAYS_INLINE_ uint64_t _atomic_conditional_increment_impl(volatile uint64_t *pw) { + ATOMIC_CONDITIONAL_INCREMENT_BODY(pw, LONGLONG, InterlockedCompareExchange64, uint64_t); } _ALWAYS_INLINE_ uint64_t _atomic_decrement_impl(volatile uint64_t *pw) { @@ -104,9 +105,8 @@ _ALWAYS_INLINE_ uint64_t _atomic_add_impl(volatile uint64_t *pw, volatile uint64 return InterlockedAdd64((LONGLONG volatile *)pw, val); } -_ALWAYS_INLINE_ uint64_t _atomic_exchange_if_greater_impl(volatile uint64_t *pw, volatile uint64_t val){ - - ATOMIC_EXCHANGE_IF_GREATER_BODY(pw, val, LONGLONG, InterlockedCompareExchange64, uint64_t) +_ALWAYS_INLINE_ uint64_t _atomic_exchange_if_greater_impl(volatile uint64_t *pw, volatile uint64_t val) { + ATOMIC_EXCHANGE_IF_GREATER_BODY(pw, val, LONGLONG, InterlockedCompareExchange64, uint64_t); } // The actual advertised functions; they'll call the right implementation diff --git a/core/translation.cpp b/core/translation.cpp index f3c1489ce4..4f835bd7b4 100644 --- a/core/translation.cpp +++ b/core/translation.cpp @@ -873,7 +873,7 @@ void Translation::get_message_list(List<StringName> *r_messages) const { int Translation::get_message_count() const { return translation_map.size(); -}; +} void Translation::_bind_methods() { ClassDB::bind_method(D_METHOD("set_locale", "locale"), &Translation::set_locale); @@ -1022,7 +1022,7 @@ void TranslationServer::remove_translation(const Ref<Translation> &p_translation void TranslationServer::clear() { translations.clear(); -}; +} StringName TranslationServer::translate(const StringName &p_message) const { // Match given message against the translation catalog for the project locale. diff --git a/core/undo_redo.cpp b/core/undo_redo.cpp index 90750f2c6e..1dcbb0cd6b 100644 --- a/core/undo_redo.cpp +++ b/core/undo_redo.cpp @@ -435,6 +435,7 @@ Variant UndoRedo::_add_do_method(const Variant **p_args, int p_argcount, Callabl v[i] = *p_args[i + 2]; } + static_assert(VARIANT_ARG_MAX == 5, "This code needs to be updated if VARIANT_ARG_MAX != 5"); add_do_method(object, method, v[0], v[1], v[2], v[3], v[4]); return Variant(); } @@ -471,6 +472,7 @@ Variant UndoRedo::_add_undo_method(const Variant **p_args, int p_argcount, Calla v[i] = *p_args[i + 2]; } + static_assert(VARIANT_ARG_MAX == 5, "This code needs to be updated if VARIANT_ARG_MAX != 5"); add_undo_method(object, method, v[0], v[1], v[2], v[3], v[4]); return Variant(); } diff --git a/core/ustring.cpp b/core/ustring.cpp index ed096bd475..444338d5ae 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -247,15 +247,6 @@ String String::operator+(const String &p_str) const { return res; } -/* -String String::operator+(CharType p_chr) const { - - String res=*this; - res+=p_chr; - return res; -} - -*/ String &String::operator+=(const String &p_str) { if (empty()) { *this = p_str; @@ -1371,7 +1362,7 @@ String String::utf8(const char *p_utf8, int p_len) { ret.parse_utf8(p_utf8, p_len); return ret; -}; +} bool String::parse_utf8(const char *p_utf8, int p_len) { #define _UNICERROR(m_err) print_line("Unicode parsing error: " + String(m_err) + ". Is the string valid UTF-8?"); @@ -1608,6 +1599,7 @@ String::String(CharType p_char) { copy_from(p_char); } + */ String::String(const char *p_str) { @@ -1833,7 +1825,7 @@ int String::to_int(const char *p_str, int p_len) { bool String::is_numeric() const { if (length() == 0) { return false; - }; + } int s = 0; if (operator[](0) == '-') { @@ -1845,16 +1837,16 @@ bool String::is_numeric() const { if (c == '.') { if (dot) { return false; - }; + } dot = true; } if (c < '0' || c > '9') { return false; - }; - }; + } + } return true; // TODO: Use the parser below for this instead -}; +} template <class C> static double built_in_strtod(const C *string, /* A decimal ASCII floating-point number, @@ -2278,7 +2270,7 @@ Vector<uint8_t> String::md5_buffer() const { ret.write[i] = hash[i]; } return ret; -}; +} Vector<uint8_t> String::sha1_buffer() const { CharString cs = utf8(); @@ -2387,7 +2379,7 @@ int String::find(const String &p_str, int p_from) const { if (read_pos >= len) { ERR_PRINT("read_pos>=len"); return -1; - }; + } if (src[read_pos] != str[j]) { found = false; @@ -2439,7 +2431,7 @@ int String::find(const char *p_str, int p_from) const { if (read_pos >= len) { ERR_PRINT("read_pos>=len"); return -1; - }; + } if (src[read_pos] != p_str[j]) { found = false; @@ -2495,7 +2487,7 @@ int String::findmk(const Vector<String> &p_keys, int p_from, int *r_key) const { if (read_pos >= len) { found = false; break; - }; + } if (src[read_pos] != cmp[j]) { found = false; @@ -2536,7 +2528,7 @@ int String::findn(const String &p_str, int p_from) const { if (read_pos >= length()) { ERR_PRINT("read_pos>=length()"); return -1; - }; + } CharType src = _find_lower(srcd[read_pos]); CharType dst = _find_lower(p_str[j]); @@ -2586,7 +2578,7 @@ int String::rfind(const String &p_str, int p_from) const { if (read_pos >= len) { ERR_PRINT("read_pos>=len"); return -1; - }; + } if (src[read_pos] != p_str[j]) { found = false; @@ -2633,7 +2625,7 @@ int String::rfindn(const String &p_str, int p_from) const { if (read_pos >= len) { ERR_PRINT("read_pos>=len"); return -1; - }; + } CharType srcc = _find_lower(src[read_pos]); CharType dstc = _find_lower(p_str[j]); @@ -3691,7 +3683,7 @@ bool String::is_valid_hex_number(bool p_with_prefix) const { } return true; -}; +} bool String::is_valid_float() const { int len = length(); @@ -3851,11 +3843,11 @@ bool String::is_valid_ip_address() const { return false; } continue; - }; + } if (!n.is_valid_ip_address()) { return false; } - }; + } } else { Vector<String> ip = split("."); @@ -3872,7 +3864,7 @@ bool String::is_valid_ip_address() const { return false; } } - }; + } return true; } @@ -4151,27 +4143,40 @@ String String::sprintf(const Array &values, bool *error) const { } double value = values[value_index]; - String str = String::num(value, min_decimals); + bool is_negative = (value < 0); + String str = String::num(ABS(value), min_decimals); // Pad decimals out. str = str.pad_decimals(min_decimals); - // Show sign - if (show_sign && str.left(1) != "-") { - str = str.insert(0, "+"); - } + int initial_len = str.length(); - // Padding + // Padding. Leave room for sign later if required. + int pad_chars_count = (is_negative || show_sign) ? min_chars - 1 : min_chars; + String pad_char = pad_with_zeroes ? String("0") : String(" "); if (left_justified) { - str = str.rpad(min_chars); + if (pad_with_zeroes) { + return "left justification cannot be used with zeros as the padding"; + } else { + str = str.rpad(pad_chars_count, pad_char); + } } else { - str = str.lpad(min_chars); + str = str.lpad(pad_chars_count, pad_char); + } + + // Add sign if needed. + if (show_sign || is_negative) { + String sign_char = is_negative ? "-" : "+"; + if (left_justified) { + str = str.insert(0, sign_char); + } else { + str = str.insert(pad_with_zeroes ? 0 : str.length() - initial_len, sign_char); + } } formatted += str; ++value_index; in_format = false; - break; } case 's': { // String @@ -4346,13 +4351,14 @@ String TTR(const String &p_text) { } String DTR(const String &p_text) { + // Comes straight from the XML, so remove indentation and any trailing whitespace. + const String text = p_text.dedent().strip_edges(); + if (TranslationServer::get_singleton()) { - // Comes straight from the XML, so remove indentation and any trailing whitespace. - const String text = p_text.dedent().strip_edges(); return TranslationServer::get_singleton()->doc_translate(text); } - return p_text; + return text; } #endif diff --git a/core/variant.cpp b/core/variant.cpp index 62d710e493..21aaa0fe9e 100644 --- a/core/variant.cpp +++ b/core/variant.cpp @@ -191,7 +191,7 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) { if (p_type_from == NIL) { return (p_type_to == OBJECT); - }; + } const Type *valid_types = nullptr; const Type *invalid_types = nullptr; @@ -498,7 +498,7 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type if (p_type_from == NIL) { return (p_type_to == OBJECT); - }; + } const Type *valid_types = nullptr; @@ -870,11 +870,6 @@ bool Variant::is_zero() const { return *reinterpret_cast<const Plane *>(_data._mem) == Plane(); } break; - /* - case QUAT: { - - - } break;*/ case AABB: { return *_data._aabb == ::AABB(); } break; @@ -1284,7 +1279,7 @@ void Variant::clear() { COLOR, VECTOR2, RECT2 - */ + */ case TRANSFORM2D: { memdelete(_data._transform2d); } break; @@ -1421,26 +1416,6 @@ Variant::operator int64_t() const { } } -/* -Variant::operator long unsigned int() const { - - switch( type ) { - - case NIL: return 0; - case BOOL: return _data._bool ? 1 : 0; - case INT: return _data._int; - case FLOAT: return _data._real; - case STRING: return operator String().to_int(); - default: { - - return 0; - } - } - - return 0; -}; -*/ - Variant::operator uint64_t() const { switch (type) { case NIL: @@ -1488,7 +1463,7 @@ Variant::operator signed long() const { } return 0; -}; +} Variant::operator unsigned long() const { switch (type) { @@ -1508,7 +1483,7 @@ Variant::operator unsigned long() const { } return 0; -}; +} #endif Variant::operator signed short() const { @@ -1858,7 +1833,7 @@ String Variant::stringify(List<const void *> &stack) const { if (_get_obj().obj) { if (!_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) { return "[Freed Object]"; - }; + } return _get_obj().obj->to_string(); } else { @@ -2075,7 +2050,7 @@ Variant::operator RID() const { #ifdef DEBUG_ENABLED if (EngineDebugger::is_active()) { ERR_FAIL_COND_V_MSG(ObjectDB::get_instance(_get_obj().id) == nullptr, RID(), "Invalid pointer (object was freed)."); - }; + } #endif Callable::CallError ce; Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->get_rid, nullptr, 0, ce); @@ -2387,14 +2362,6 @@ Variant::Variant(bool p_bool) { _data._bool = p_bool; } -/* -Variant::Variant(long unsigned int p_long) { - - type=INT; - _data._int=p_long; -}; -*/ - Variant::Variant(signed int p_int) { type = INT; _data._int = p_int; @@ -2939,11 +2906,6 @@ uint32_t Variant::hash() const { return hash_djb2_one_float(reinterpret_cast<const Plane *>(_data._mem)->d, hash); } break; - /* - case QUAT: { - - - } break;*/ case AABB: { uint32_t hash = 5831; for (int i = 0; i < 3; i++) { diff --git a/core/variant.h b/core/variant.h index b24cf968de..50b7a21eda 100644 --- a/core/variant.h +++ b/core/variant.h @@ -219,10 +219,10 @@ public: bool is_ref() const; _FORCE_INLINE_ bool is_num() const { return type == INT || type == FLOAT; - }; + } _FORCE_INLINE_ bool is_array() const { return type >= ARRAY; - }; + } bool is_shared() const; bool is_zero() const; bool is_one() const; diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 82b1f29805..a8beac1e44 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -923,6 +923,18 @@ struct _VariantCall { VCALL_PTR1R(Basis, scaled); VCALL_PTR0R(Basis, get_scale); VCALL_PTR0R(Basis, get_euler); + VCALL_PTR0R(Basis, get_euler_xyz); + VCALL_PTR1(Basis, set_euler_xyz); + VCALL_PTR0R(Basis, get_euler_xzy); + VCALL_PTR1(Basis, set_euler_xzy); + VCALL_PTR0R(Basis, get_euler_yzx); + VCALL_PTR1(Basis, set_euler_yzx); + VCALL_PTR0R(Basis, get_euler_yxz); + VCALL_PTR1(Basis, set_euler_yxz); + VCALL_PTR0R(Basis, get_euler_zxy); + VCALL_PTR1(Basis, set_euler_zxy); + VCALL_PTR0R(Basis, get_euler_zyx); + VCALL_PTR1(Basis, set_euler_zyx); VCALL_PTR1R(Basis, tdotx); VCALL_PTR1R(Basis, tdoty); VCALL_PTR1R(Basis, tdotz); @@ -1174,6 +1186,9 @@ struct _VariantCall { List<StringName> value_ordered; #endif Map<StringName, Variant> variant_value; +#ifdef DEBUG_ENABLED + List<StringName> variant_value_ordered; +#endif }; static ConstantData *constant_data; @@ -1187,6 +1202,9 @@ struct _VariantCall { static void add_variant_constant(int p_type, StringName p_constant_name, const Variant &p_constant_value) { constant_data[p_type].variant_value[p_constant_name] = p_constant_value; +#ifdef DEBUG_ENABLED + constant_data[p_type].variant_value_ordered.push_back(p_constant_name); +#endif } }; @@ -1290,10 +1308,16 @@ Variant Variant::construct(const Variant::Type p_type, const Variant **p_args, i // math types case VECTOR2: return Vector2(); + case VECTOR2I: + return Vector2i(); case RECT2: return Rect2(); + case RECT2I: + return Rect2i(); case VECTOR3: return Vector3(); + case VECTOR3I: + return Vector3i(); case TRANSFORM2D: return Transform2D(); case PLANE: @@ -1652,8 +1676,13 @@ void Variant::get_constants_for_type(Variant::Type p_type, List<StringName> *p_c #endif } +#ifdef DEBUG_ENABLED + for (List<StringName>::Element *E = cd.variant_value_ordered.front(); E; E = E->next()) { + p_constants->push_back(E->get()); +#else for (Map<StringName, Variant>::Element *E = cd.variant_value.front(); E; E = E->next()) { p_constants->push_back(E->key()); +#endif } } diff --git a/core/variant_op.cpp b/core/variant_op.cpp index 8641187f97..0c9a4a992a 100644 --- a/core/variant_op.cpp +++ b/core/variant_op.cpp @@ -189,7 +189,7 @@ bool Variant::booleanize() const { _RETURN(p_a._data.m_type m_op p_b._data._float); \ \ _RETURN_FAIL \ - }; + } #define DEFAULT_OP_NUM_NULL(m_prefix, m_op_name, m_name, m_op, m_type) \ CASE_TYPE(m_prefix, m_op_name, m_name) { \ @@ -201,7 +201,7 @@ bool Variant::booleanize() const { _RETURN(!(p_b.type m_op NIL)); \ \ _RETURN_FAIL \ - }; + } #ifdef DEBUG_ENABLED #define DEFAULT_OP_NUM_DIV(m_prefix, m_op_name, m_name, m_type) \ @@ -222,7 +222,7 @@ bool Variant::booleanize() const { } \ \ _RETURN_FAIL \ - }; + } #else #define DEFAULT_OP_NUM_DIV(m_prefix, m_op_name, m_name, m_type) \ CASE_TYPE(m_prefix, m_op_name, m_name) { \ @@ -232,18 +232,18 @@ bool Variant::booleanize() const { _RETURN(p_a._data.m_type / p_b._data._float); \ \ _RETURN_FAIL \ - }; + } #endif #define DEFAULT_OP_NUM_NEG(m_prefix, m_op_name, m_name, m_type) \ CASE_TYPE(m_prefix, m_op_name, m_name) { \ _RETURN(-p_a._data.m_type); \ - }; + } #define DEFAULT_OP_NUM_POS(m_prefix, m_op_name, m_name, m_type) \ CASE_TYPE(m_prefix, m_op_name, m_name) { \ _RETURN(p_a._data.m_type); \ - }; + } #define DEFAULT_OP_NUM_VEC(m_prefix, m_op_name, m_name, m_op, m_type) \ CASE_TYPE(m_prefix, m_op_name, m_name) { \ @@ -261,7 +261,7 @@ bool Variant::booleanize() const { _RETURN(p_a._data.m_type m_op *reinterpret_cast<const Vector3 *>(p_b._data._mem)); \ \ _RETURN_FAIL \ - }; + } #define DEFAULT_OP_STR_REV(m_prefix, m_op_name, m_name, m_op, m_type) \ CASE_TYPE(m_prefix, m_op_name, m_name) { \ @@ -273,7 +273,7 @@ bool Variant::booleanize() const { _RETURN(*reinterpret_cast<const m_type *>(p_b._data._mem) m_op *reinterpret_cast<const NodePath *>(p_a._data._mem)); \ \ _RETURN_FAIL \ - }; + } #define DEFAULT_OP_STR(m_prefix, m_op_name, m_name, m_op, m_type) \ CASE_TYPE(m_prefix, m_op_name, m_name) { \ @@ -285,7 +285,7 @@ bool Variant::booleanize() const { _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const NodePath *>(p_b._data._mem)); \ \ _RETURN_FAIL \ - }; + } #define DEFAULT_OP_STR_NULL(m_prefix, m_op_name, m_name, m_op, m_type) \ CASE_TYPE(m_prefix, m_op_name, m_name) { \ @@ -299,7 +299,7 @@ bool Variant::booleanize() const { _RETURN(!(p_b.type m_op NIL)); \ \ _RETURN_FAIL \ - }; + } #define DEFAULT_OP_STR_NULL_NP(m_prefix, m_op_name, m_name, m_op, m_type) \ CASE_TYPE(m_prefix, m_op_name, m_name) { \ @@ -311,7 +311,7 @@ bool Variant::booleanize() const { _RETURN(!(p_b.type m_op NIL)); \ \ _RETURN_FAIL \ - }; + } #define DEFAULT_OP_STR_NULL_SN(m_prefix, m_op_name, m_name, m_op, m_type) \ CASE_TYPE(m_prefix, m_op_name, m_name) { \ @@ -323,7 +323,7 @@ bool Variant::booleanize() const { _RETURN(!(p_b.type m_op NIL)); \ \ _RETURN_FAIL \ - }; + } #define DEFAULT_OP_LOCALMEM_REV(m_prefix, m_op_name, m_name, m_op, m_type) \ CASE_TYPE(m_prefix, m_op_name, m_name) { \ @@ -331,7 +331,7 @@ bool Variant::booleanize() const { _RETURN(*reinterpret_cast<const m_type *>(p_b._data._mem) m_op *reinterpret_cast<const m_type *>(p_a._data._mem)); \ \ _RETURN_FAIL \ - }; + } #define DEFAULT_OP_LOCALMEM(m_prefix, m_op_name, m_name, m_op, m_type) \ CASE_TYPE(m_prefix, m_op_name, m_name) { \ @@ -339,7 +339,7 @@ bool Variant::booleanize() const { _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const m_type *>(p_b._data._mem)); \ \ _RETURN_FAIL \ - }; + } #define DEFAULT_OP_LOCALMEM_NULL(m_prefix, m_op_name, m_name, m_op, m_type) \ CASE_TYPE(m_prefix, m_op_name, m_name) { \ @@ -349,7 +349,7 @@ bool Variant::booleanize() const { _RETURN(!(p_b.type m_op NIL)); \ \ _RETURN_FAIL \ - }; + } #define DEFAULT_OP_LOCALMEM_NEG(m_prefix, m_op_name, m_name, m_type) \ CASE_TYPE(m_prefix, m_op_name, m_name) { \ @@ -1786,6 +1786,7 @@ Variant Variant::get_named(const StringName &p_index, bool *r_valid) const { if (r_valid) { *r_valid = true; } + switch (type) { case VECTOR2: { const Vector2 *v = reinterpret_cast<const Vector2 *>(_data._mem); diff --git a/core/variant_parser.cpp b/core/variant_parser.cpp index 9fe98265dd..74f4f32c0e 100644 --- a/core/variant_parser.cpp +++ b/core/variant_parser.cpp @@ -110,7 +110,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri case '\n': { line++; break; - }; + } case 0: { r_token.type = TK_EOF; return OK; @@ -118,31 +118,31 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri case '{': { r_token.type = TK_CURLY_BRACKET_OPEN; return OK; - }; + } case '}': { r_token.type = TK_CURLY_BRACKET_CLOSE; return OK; - }; + } case '[': { r_token.type = TK_BRACKET_OPEN; return OK; - }; + } case ']': { r_token.type = TK_BRACKET_CLOSE; return OK; - }; + } case '(': { r_token.type = TK_PARENTHESIS_OPEN; return OK; - }; + } case ')': { r_token.type = TK_PARENTHESIS_CLOSE; return OK; - }; + } case ':': { r_token.type = TK_COLON; return OK; - }; + } case ';': { while (true) { CharType ch = p_stream->get_char(); @@ -156,19 +156,19 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri } break; - }; + } case ',': { r_token.type = TK_COMMA; return OK; - }; + } case '.': { r_token.type = TK_PERIOD; return OK; - }; + } case '=': { r_token.type = TK_EQUAL; return OK; - }; + } case '#': { StringBuffer<> color_str; color_str += '#'; @@ -189,7 +189,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri r_token.value = Color::html(color_str.as_string()); r_token.type = TK_COLOR; return OK; - }; + } case '@': { cchar = p_stream->get_char(); if (cchar != '"') { @@ -479,12 +479,6 @@ Error VariantParser::_parse_construct(Stream *p_stream, Vector<T> &r_construct, } Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser) { - /* { - Error err = get_token(p_stream,token,line,r_err_str); - if (err) - return err; - }*/ - if (token.type == TK_CURLY_BRACKET_OPEN) { Dictionary d; Error err = _parse_dictionary(d, p_stream, line, r_err_str, p_res_parser); @@ -501,7 +495,6 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, } value = a; return OK; - } else if (token.type == TK_IDENTIFIER) { String id = token.value; if (id == "true") { @@ -523,10 +516,10 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, if (args.size() != 2) { r_err_str = "Expected 2 arguments for constructor"; + return ERR_PARSE_ERROR; } value = Vector2(args[0], args[1]); - return OK; } else if (id == "Vector2i") { Vector<int32_t> args; Error err = _parse_construct<int32_t>(p_stream, args, line, r_err_str); @@ -536,10 +529,10 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, if (args.size() != 2) { r_err_str = "Expected 2 arguments for constructor"; + return ERR_PARSE_ERROR; } value = Vector2i(args[0], args[1]); - return OK; } else if (id == "Rect2") { Vector<float> args; Error err = _parse_construct<float>(p_stream, args, line, r_err_str); @@ -549,10 +542,10 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, if (args.size() != 4) { r_err_str = "Expected 4 arguments for constructor"; + return ERR_PARSE_ERROR; } value = Rect2(args[0], args[1], args[2], args[3]); - return OK; } else if (id == "Rect2i") { Vector<int32_t> args; Error err = _parse_construct<int32_t>(p_stream, args, line, r_err_str); @@ -562,10 +555,10 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, if (args.size() != 4) { r_err_str = "Expected 4 arguments for constructor"; + return ERR_PARSE_ERROR; } value = Rect2i(args[0], args[1], args[2], args[3]); - return OK; } else if (id == "Vector3") { Vector<float> args; Error err = _parse_construct<float>(p_stream, args, line, r_err_str); @@ -575,10 +568,10 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, if (args.size() != 3) { r_err_str = "Expected 3 arguments for constructor"; + return ERR_PARSE_ERROR; } value = Vector3(args[0], args[1], args[2]); - return OK; } else if (id == "Vector3i") { Vector<int32_t> args; Error err = _parse_construct<int32_t>(p_stream, args, line, r_err_str); @@ -588,12 +581,11 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, if (args.size() != 3) { r_err_str = "Expected 3 arguments for constructor"; + return ERR_PARSE_ERROR; } value = Vector3i(args[0], args[1], args[2]); - return OK; } else if (id == "Transform2D" || id == "Matrix32") { //compatibility - Vector<float> args; Error err = _parse_construct<float>(p_stream, args, line, r_err_str); if (err) { @@ -602,13 +594,14 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, if (args.size() != 6) { r_err_str = "Expected 6 arguments for constructor"; + return ERR_PARSE_ERROR; } + Transform2D m; m[0] = Vector2(args[0], args[1]); m[1] = Vector2(args[2], args[3]); m[2] = Vector2(args[4], args[5]); value = m; - return OK; } else if (id == "Plane") { Vector<float> args; Error err = _parse_construct<float>(p_stream, args, line, r_err_str); @@ -618,10 +611,10 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, if (args.size() != 4) { r_err_str = "Expected 4 arguments for constructor"; + return ERR_PARSE_ERROR; } value = Plane(args[0], args[1], args[2], args[3]); - return OK; } else if (id == "Quat") { Vector<float> args; Error err = _parse_construct<float>(p_stream, args, line, r_err_str); @@ -631,11 +624,10 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, if (args.size() != 4) { r_err_str = "Expected 4 arguments for constructor"; + return ERR_PARSE_ERROR; } value = Quat(args[0], args[1], args[2], args[3]); - return OK; - } else if (id == "AABB" || id == "Rect3") { Vector<float> args; Error err = _parse_construct<float>(p_stream, args, line, r_err_str); @@ -645,13 +637,11 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, if (args.size() != 6) { r_err_str = "Expected 6 arguments for constructor"; + return ERR_PARSE_ERROR; } value = AABB(Vector3(args[0], args[1], args[2]), Vector3(args[3], args[4], args[5])); - return OK; - } else if (id == "Basis" || id == "Matrix3") { //compatibility - Vector<float> args; Error err = _parse_construct<float>(p_stream, args, line, r_err_str); if (err) { @@ -660,10 +650,10 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, if (args.size() != 9) { r_err_str = "Expected 9 arguments for constructor"; + return ERR_PARSE_ERROR; } value = Basis(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); - return OK; } else if (id == "Transform") { Vector<float> args; Error err = _parse_construct<float>(p_stream, args, line, r_err_str); @@ -673,11 +663,10 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, if (args.size() != 12) { r_err_str = "Expected 12 arguments for constructor"; + return ERR_PARSE_ERROR; } value = Transform(Basis(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]), Vector3(args[9], args[10], args[11])); - return OK; - } else if (id == "Color") { Vector<float> args; Error err = _parse_construct<float>(p_stream, args, line, r_err_str); @@ -687,11 +676,10 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, if (args.size() != 4) { r_err_str = "Expected 4 arguments for constructor"; + return ERR_PARSE_ERROR; } value = Color(args[0], args[1], args[2], args[3]); - return OK; - } else if (id == "NodePath") { get_token(p_stream, token, line, r_err_str); if (token.type != TK_PARENTHESIS_OPEN) { @@ -712,7 +700,6 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, r_err_str = "Expected ')'"; return ERR_PARSE_ERROR; } - } else if (id == "RID") { get_token(p_stream, token, line, r_err_str); if (token.type != TK_PARENTHESIS_OPEN) { @@ -733,8 +720,6 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, r_err_str = "Expected ')'"; return ERR_PARSE_ERROR; } - - return OK; } else if (id == "Object") { get_token(p_stream, token, line, r_err_str); if (token.type != TK_PARENTHESIS_OPEN) { @@ -834,7 +819,6 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, at_key = true; } } - } else if (id == "Resource" || id == "SubResource" || id == "ExtResource") { get_token(p_stream, token, line, r_err_str); if (token.type != TK_PARENTHESIS_OPEN) { @@ -850,8 +834,6 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, } value = res; - - return OK; } else if (p_res_parser && id == "ExtResource" && p_res_parser->ext_func) { RES res; Error err = p_res_parser->ext_func(p_res_parser->userdata, p_stream, res, line, r_err_str); @@ -860,8 +842,6 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, } value = res; - - return OK; } else if (p_res_parser && id == "SubResource" && p_res_parser->sub_func) { RES res; Error err = p_res_parser->sub_func(p_res_parser->userdata, p_stream, res, line, r_err_str); @@ -870,8 +850,6 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, } value = res; - - return OK; } else { get_token(p_stream, token, line, r_err_str); if (token.type == TK_STRING) { @@ -889,14 +867,11 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, } value = res; - return OK; - } else { r_err_str = "Expected string as argument for Resource()."; return ERR_PARSE_ERROR; } } - } else if (id == "PackedByteArray" || id == "PoolByteArray" || id == "ByteArray") { Vector<uint8_t> args; Error err = _parse_construct<uint8_t>(p_stream, args, line, r_err_str); @@ -915,9 +890,6 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, } value = arr; - - return OK; - } else if (id == "PackedInt32Array" || id == "PackedIntArray" || id == "PoolIntArray" || id == "IntArray") { Vector<int32_t> args; Error err = _parse_construct<int32_t>(p_stream, args, line, r_err_str); @@ -936,9 +908,6 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, } value = arr; - - return OK; - } else if (id == "PackedInt64Array") { Vector<int64_t> args; Error err = _parse_construct<int64_t>(p_stream, args, line, r_err_str); @@ -957,9 +926,6 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, } value = arr; - - return OK; - } else if (id == "PackedFloat32Array" || id == "PackedRealArray" || id == "PoolRealArray" || id == "FloatArray") { Vector<float> args; Error err = _parse_construct<float>(p_stream, args, line, r_err_str); @@ -978,8 +944,6 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, } value = arr; - - return OK; } else if (id == "PackedFloat64Array") { Vector<double> args; Error err = _parse_construct<double>(p_stream, args, line, r_err_str); @@ -998,8 +962,6 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, } value = arr; - - return OK; } else if (id == "PackedStringArray" || id == "PoolStringArray" || id == "StringArray") { get_token(p_stream, token, line, r_err_str); if (token.type != TK_PARENTHESIS_OPEN) { @@ -1046,9 +1008,6 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, } value = arr; - - return OK; - } else if (id == "PackedVector2Array" || id == "PoolVector2Array" || id == "Vector2Array") { Vector<float> args; Error err = _parse_construct<float>(p_stream, args, line, r_err_str); @@ -1067,9 +1026,6 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, } value = arr; - - return OK; - } else if (id == "PackedVector3Array" || id == "PoolVector3Array" || id == "Vector3Array") { Vector<float> args; Error err = _parse_construct<float>(p_stream, args, line, r_err_str); @@ -1088,9 +1044,6 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, } value = arr; - - return OK; - } else if (id == "PackedColorArray" || id == "PoolColorArray" || id == "ColorArray") { Vector<float> args; Error err = _parse_construct<float>(p_stream, args, line, r_err_str); @@ -1109,15 +1062,13 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, } value = arr; - - return OK; } else { r_err_str = "Unexpected identifier: '" + id + "'."; return ERR_PARSE_ERROR; } + // All above branches end up here unless they had an early return. return OK; - } else if (token.type == TK_NUMBER) { value = token.value; return OK; diff --git a/core/vector.h b/core/vector.h index 696984ac28..4c152fb084 100644 --- a/core/vector.h +++ b/core/vector.h @@ -113,8 +113,8 @@ public: for (i = 0; i < _cowdata.size(); i++) { if (p_val < operator[](i)) { break; - }; - }; + } + } insert(i, p_val); } |