summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/bind/core_bind.cpp454
-rw-r--r--core/bind/core_bind.h97
-rw-r--r--core/callable_method_pointer.h36
-rw-r--r--core/class_db.cpp18
-rw-r--r--core/color.cpp2
-rw-r--r--core/cowdata.h6
-rw-r--r--core/crypto/aes_context.cpp116
-rw-r--r--core/crypto/aes_context.h68
-rw-r--r--core/crypto/crypto.cpp43
-rw-r--r--core/crypto/crypto.h19
-rw-r--r--core/crypto/crypto_core.cpp10
-rw-r--r--core/crypto/crypto_core.h2
-rw-r--r--core/debugger/remote_debugger.cpp22
-rw-r--r--core/debugger/remote_debugger_peer.cpp6
-rw-r--r--core/engine.cpp4
-rw-r--r--core/error_macros.h8
-rw-r--r--core/hash_map.h18
-rw-r--r--core/image.cpp54
-rw-r--r--core/input/gamecontrollerdb.txt57
-rw-r--r--core/input/input.cpp26
-rw-r--r--core/input/input_map.cpp8
-rw-r--r--core/input/input_map.h4
-rw-r--r--core/io/dtls_server.cpp5
-rw-r--r--core/io/file_access_buffered.h10
-rw-r--r--core/io/file_access_buffered_fa.h20
-rw-r--r--core/io/file_access_memory.cpp2
-rw-r--r--core/io/file_access_pack.cpp14
-rw-r--r--core/io/file_access_pack.h2
-rw-r--r--core/io/ip.cpp2
-rw-r--r--core/io/ip_address.cpp40
-rw-r--r--core/io/json.cpp18
-rw-r--r--core/io/marshalls.h2
-rw-r--r--core/io/packet_peer.cpp4
-rw-r--r--core/io/packet_peer_dtls.cpp5
-rw-r--r--core/io/pck_packer.cpp32
-rw-r--r--core/io/xml_parser.cpp6
-rw-r--r--core/io/zip_io.cpp2
-rw-r--r--core/list.h60
-rw-r--r--core/local_vector.h14
-rw-r--r--core/make_binders.py6
-rw-r--r--core/map.h10
-rw-r--r--core/math/a_star.cpp18
-rw-r--r--core/math/aabb.h2
-rw-r--r--core/math/basis.cpp216
-rw-r--r--core/math/basis.h13
-rw-r--r--core/math/camera_matrix.cpp18
-rw-r--r--core/math/expression.cpp52
-rw-r--r--core/math/face3.cpp6
-rw-r--r--core/math/geometry_2d.cpp384
-rw-r--r--core/math/geometry_2d.h398
-rw-r--r--core/math/geometry_3d.cpp (renamed from core/math/geometry.cpp)393
-rw-r--r--core/math/geometry_3d.h (renamed from core/math/geometry.h)382
-rw-r--r--core/math/octree.h4
-rw-r--r--core/math/quick_hull.cpp18
-rw-r--r--core/math/quick_hull.h6
-rw-r--r--core/math/rect2.h4
-rw-r--r--core/math/transform_2d.cpp7
-rw-r--r--core/math/triangulate.cpp2
-rw-r--r--core/math/vector2.cpp13
-rw-r--r--core/math/vector2.h13
-rw-r--r--core/message_queue.cpp15
-rw-r--r--core/message_queue.h1
-rw-r--r--core/oa_hash_map.h89
-rw-r--r--core/object.cpp20
-rw-r--r--core/object.h1
-rw-r--r--core/ordered_hash_map.h16
-rw-r--r--core/os/dir_access.cpp8
-rw-r--r--core/os/file_access.cpp22
-rw-r--r--core/os/os.cpp34
-rw-r--r--core/os/os.h11
-rw-r--r--core/os/thread.cpp2
-rw-r--r--core/os/thread_dummy.cpp8
-rw-r--r--core/packed_data_container.cpp12
-rw-r--r--core/pool_allocator.cpp8
-rw-r--r--core/project_settings.cpp83
-rw-r--r--core/register_core_types.cpp20
-rw-r--r--core/resource.cpp17
-rw-r--r--core/ring_buffer.h48
-rw-r--r--core/safe_refcount.cpp32
-rw-r--r--core/translation.cpp4
-rw-r--r--core/undo_redo.cpp2
-rw-r--r--core/ustring.cpp82
-rw-r--r--core/variant.cpp52
-rw-r--r--core/variant.h4
-rw-r--r--core/variant_call.cpp29
-rw-r--r--core/variant_op.cpp31
-rw-r--r--core/variant_parser.cpp105
-rw-r--r--core/vector.h4
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);
}