summaryrefslogtreecommitdiff
path: root/servers/physics_2d
diff options
context:
space:
mode:
Diffstat (limited to 'servers/physics_2d')
-rw-r--r--servers/physics_2d/area_2d_sw.cpp292
-rw-r--r--servers/physics_2d/area_pair_2d_sw.cpp158
-rw-r--r--servers/physics_2d/body_2d_sw.cpp705
-rw-r--r--servers/physics_2d/broad_phase_2d_basic.cpp174
-rw-r--r--servers/physics_2d/broad_phase_2d_basic.h103
-rw-r--r--servers/physics_2d/broad_phase_2d_hash_grid.cpp735
-rw-r--r--servers/physics_2d/broad_phase_2d_hash_grid.h187
-rw-r--r--servers/physics_2d/godot_area_2d.cpp325
-rw-r--r--servers/physics_2d/godot_area_2d.h (renamed from servers/physics_2d/area_2d_sw.h)145
-rw-r--r--servers/physics_2d/godot_area_pair_2d.cpp200
-rw-r--r--servers/physics_2d/godot_area_pair_2d.h (renamed from servers/physics_2d/step_2d_sw.h)58
-rw-r--r--servers/physics_2d/godot_body_2d.cpp757
-rw-r--r--servers/physics_2d/godot_body_2d.h (renamed from servers/physics_2d/body_2d_sw.h)329
-rw-r--r--servers/physics_2d/godot_body_direct_state_2d.cpp219
-rw-r--r--servers/physics_2d/godot_body_direct_state_2d.h103
-rw-r--r--servers/physics_2d/godot_body_pair_2d.cpp (renamed from servers/physics_2d/body_pair_2d_sw.cpp)388
-rw-r--r--servers/physics_2d/godot_body_pair_2d.h (renamed from servers/physics_2d/body_pair_2d_sw.h)72
-rw-r--r--servers/physics_2d/godot_broad_phase_2d.cpp (renamed from servers/physics_2d/broad_phase_2d_sw.cpp)12
-rw-r--r--servers/physics_2d/godot_broad_phase_2d.h (renamed from servers/physics_2d/broad_phase_2d_sw.h)32
-rw-r--r--servers/physics_2d/godot_broad_phase_2d_bvh.cpp123
-rw-r--r--servers/physics_2d/godot_broad_phase_2d_bvh.h101
-rw-r--r--servers/physics_2d/godot_collision_object_2d.cpp (renamed from servers/physics_2d/collision_object_2d_sw.cpp)97
-rw-r--r--servers/physics_2d/godot_collision_object_2d.h (renamed from servers/physics_2d/collision_object_2d_sw.h)94
-rw-r--r--servers/physics_2d/godot_collision_solver_2d.cpp (renamed from servers/physics_2d/collision_solver_2d_sw.cpp)120
-rw-r--r--servers/physics_2d/godot_collision_solver_2d.h (renamed from servers/physics_2d/collision_solver_2d_sw.h)26
-rw-r--r--servers/physics_2d/godot_collision_solver_2d_sat.cpp (renamed from servers/physics_2d/collision_solver_2d_sat.cpp)281
-rw-r--r--servers/physics_2d/godot_collision_solver_2d_sat.h (renamed from servers/physics_2d/collision_solver_2d_sat.h)16
-rw-r--r--servers/physics_2d/godot_constraint_2d.h (renamed from servers/physics_2d/constraint_2d_sw.h)39
-rw-r--r--servers/physics_2d/godot_joints_2d.cpp (renamed from servers/physics_2d/joints_2d_sw.cpp)198
-rw-r--r--servers/physics_2d/godot_joints_2d.h (renamed from servers/physics_2d/joints_2d_sw.h)118
-rw-r--r--servers/physics_2d/godot_physics_server_2d.cpp1353
-rw-r--r--servers/physics_2d/godot_physics_server_2d.h (renamed from servers/physics_2d/physics_server_2d_sw.h)135
-rw-r--r--servers/physics_2d/godot_shape_2d.cpp (renamed from servers/physics_2d/shape_2d_sw.cpp)209
-rw-r--r--servers/physics_2d/godot_shape_2d.h (renamed from servers/physics_2d/shape_2d_sw.h)291
-rw-r--r--servers/physics_2d/godot_space_2d.cpp1242
-rw-r--r--servers/physics_2d/godot_space_2d.h214
-rw-r--r--servers/physics_2d/godot_step_2d.cpp305
-rw-r--r--servers/physics_2d/godot_step_2d.h (renamed from servers/physics_2d/area_pair_2d_sw.h)57
-rw-r--r--servers/physics_2d/physics_server_2d_sw.cpp1368
-rw-r--r--servers/physics_2d/physics_server_2d_wrap_mt.cpp139
-rw-r--r--servers/physics_2d/physics_server_2d_wrap_mt.h336
-rw-r--r--servers/physics_2d/space_2d_sw.cpp1411
-rw-r--r--servers/physics_2d/space_2d_sw.h208
-rw-r--r--servers/physics_2d/step_2d_sw.cpp304
44 files changed, 6351 insertions, 7428 deletions
diff --git a/servers/physics_2d/area_2d_sw.cpp b/servers/physics_2d/area_2d_sw.cpp
deleted file mode 100644
index 6485c8d1e9..0000000000
--- a/servers/physics_2d/area_2d_sw.cpp
+++ /dev/null
@@ -1,292 +0,0 @@
-/*************************************************************************/
-/* area_2d_sw.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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 "area_2d_sw.h"
-#include "body_2d_sw.h"
-#include "space_2d_sw.h"
-
-Area2DSW::BodyKey::BodyKey(Body2DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {
- rid = p_body->get_self();
- instance_id = p_body->get_instance_id();
- body_shape = p_body_shape;
- area_shape = p_area_shape;
-}
-
-Area2DSW::BodyKey::BodyKey(Area2DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {
- rid = p_body->get_self();
- instance_id = p_body->get_instance_id();
- body_shape = p_body_shape;
- area_shape = p_area_shape;
-}
-
-void Area2DSW::_shapes_changed() {
- if (!moved_list.in_list() && get_space()) {
- get_space()->area_add_to_moved_list(&moved_list);
- }
-}
-
-void Area2DSW::set_transform(const Transform2D &p_transform) {
- if (!moved_list.in_list() && get_space()) {
- get_space()->area_add_to_moved_list(&moved_list);
- }
-
- _set_transform(p_transform);
- _set_inv_transform(p_transform.affine_inverse());
-}
-
-void Area2DSW::set_space(Space2DSW *p_space) {
- if (get_space()) {
- if (monitor_query_list.in_list()) {
- get_space()->area_remove_from_monitor_query_list(&monitor_query_list);
- }
- if (moved_list.in_list()) {
- get_space()->area_remove_from_moved_list(&moved_list);
- }
- }
-
- monitored_bodies.clear();
- monitored_areas.clear();
-
- _set_space(p_space);
-}
-
-void Area2DSW::set_monitor_callback(ObjectID p_id, const StringName &p_method) {
- if (p_id == monitor_callback_id) {
- monitor_callback_method = p_method;
- return;
- }
-
- _unregister_shapes();
-
- monitor_callback_id = p_id;
- monitor_callback_method = p_method;
-
- monitored_bodies.clear();
- monitored_areas.clear();
-
- _shape_changed();
-
- if (!moved_list.in_list() && get_space()) {
- get_space()->area_add_to_moved_list(&moved_list);
- }
-}
-
-void Area2DSW::set_area_monitor_callback(ObjectID p_id, const StringName &p_method) {
- if (p_id == area_monitor_callback_id) {
- area_monitor_callback_method = p_method;
- return;
- }
-
- _unregister_shapes();
-
- area_monitor_callback_id = p_id;
- area_monitor_callback_method = p_method;
-
- monitored_bodies.clear();
- monitored_areas.clear();
-
- _shape_changed();
-
- if (!moved_list.in_list() && get_space()) {
- get_space()->area_add_to_moved_list(&moved_list);
- }
-}
-
-void Area2DSW::set_space_override_mode(PhysicsServer2D::AreaSpaceOverrideMode p_mode) {
- bool do_override = p_mode != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED;
- if (do_override == (space_override_mode != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED)) {
- return;
- }
- _unregister_shapes();
- space_override_mode = p_mode;
- _shape_changed();
-}
-
-void Area2DSW::set_param(PhysicsServer2D::AreaParameter p_param, const Variant &p_value) {
- switch (p_param) {
- case PhysicsServer2D::AREA_PARAM_GRAVITY:
- gravity = p_value;
- break;
- case PhysicsServer2D::AREA_PARAM_GRAVITY_VECTOR:
- gravity_vector = p_value;
- break;
- case PhysicsServer2D::AREA_PARAM_GRAVITY_IS_POINT:
- gravity_is_point = p_value;
- break;
- case PhysicsServer2D::AREA_PARAM_GRAVITY_DISTANCE_SCALE:
- gravity_distance_scale = p_value;
- break;
- case PhysicsServer2D::AREA_PARAM_GRAVITY_POINT_ATTENUATION:
- point_attenuation = p_value;
- break;
- case PhysicsServer2D::AREA_PARAM_LINEAR_DAMP:
- linear_damp = p_value;
- break;
- case PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP:
- angular_damp = p_value;
- break;
- case PhysicsServer2D::AREA_PARAM_PRIORITY:
- priority = p_value;
- break;
- }
-}
-
-Variant Area2DSW::get_param(PhysicsServer2D::AreaParameter p_param) const {
- switch (p_param) {
- case PhysicsServer2D::AREA_PARAM_GRAVITY:
- return gravity;
- case PhysicsServer2D::AREA_PARAM_GRAVITY_VECTOR:
- return gravity_vector;
- case PhysicsServer2D::AREA_PARAM_GRAVITY_IS_POINT:
- return gravity_is_point;
- case PhysicsServer2D::AREA_PARAM_GRAVITY_DISTANCE_SCALE:
- return gravity_distance_scale;
- case PhysicsServer2D::AREA_PARAM_GRAVITY_POINT_ATTENUATION:
- return point_attenuation;
- case PhysicsServer2D::AREA_PARAM_LINEAR_DAMP:
- return linear_damp;
- case PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP:
- return angular_damp;
- case PhysicsServer2D::AREA_PARAM_PRIORITY:
- return priority;
- }
-
- return Variant();
-}
-
-void Area2DSW::_queue_monitor_update() {
- ERR_FAIL_COND(!get_space());
-
- if (!monitor_query_list.in_list()) {
- get_space()->area_add_to_monitor_query_list(&monitor_query_list);
- }
-}
-
-void Area2DSW::set_monitorable(bool p_monitorable) {
- if (monitorable == p_monitorable) {
- return;
- }
-
- monitorable = p_monitorable;
- _set_static(!monitorable);
-}
-
-void Area2DSW::call_queries() {
- if (monitor_callback_id.is_valid() && !monitored_bodies.is_empty()) {
- Variant res[5];
- Variant *resptr[5];
- for (int i = 0; i < 5; i++) {
- resptr[i] = &res[i];
- }
-
- Object *obj = ObjectDB::get_instance(monitor_callback_id);
- if (!obj) {
- monitored_bodies.clear();
- monitor_callback_id = ObjectID();
- return;
- }
-
- for (Map<BodyKey, BodyState>::Element *E = monitored_bodies.front(); E;) {
- if (E->get().state == 0) { // Nothing happened
- E = E->next();
- continue;
- }
-
- res[0] = E->get().state > 0 ? PhysicsServer2D::AREA_BODY_ADDED : PhysicsServer2D::AREA_BODY_REMOVED;
- res[1] = E->key().rid;
- res[2] = E->key().instance_id;
- res[3] = E->key().body_shape;
- res[4] = E->key().area_shape;
-
- Map<BodyKey, BodyState>::Element *next = E->next();
- monitored_bodies.erase(E);
- E = next;
-
- Callable::CallError ce;
- obj->call(monitor_callback_method, (const Variant **)resptr, 5, ce);
- }
- }
-
- if (area_monitor_callback_id.is_valid() && !monitored_areas.is_empty()) {
- Variant res[5];
- Variant *resptr[5];
- for (int i = 0; i < 5; i++) {
- resptr[i] = &res[i];
- }
-
- Object *obj = ObjectDB::get_instance(area_monitor_callback_id);
- if (!obj) {
- monitored_areas.clear();
- area_monitor_callback_id = ObjectID();
- return;
- }
-
- for (Map<BodyKey, BodyState>::Element *E = monitored_areas.front(); E;) {
- if (E->get().state == 0) { // Nothing happened
- E = E->next();
- continue;
- }
-
- res[0] = E->get().state > 0 ? PhysicsServer2D::AREA_BODY_ADDED : PhysicsServer2D::AREA_BODY_REMOVED;
- res[1] = E->key().rid;
- res[2] = E->key().instance_id;
- res[3] = E->key().body_shape;
- res[4] = E->key().area_shape;
-
- Map<BodyKey, BodyState>::Element *next = E->next();
- monitored_areas.erase(E);
- E = next;
-
- Callable::CallError ce;
- obj->call(area_monitor_callback_method, (const Variant **)resptr, 5, ce);
- }
- }
-}
-
-Area2DSW::Area2DSW() :
- CollisionObject2DSW(TYPE_AREA),
- monitor_query_list(this),
- moved_list(this) {
- _set_static(true); //areas are not active by default
- space_override_mode = PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED;
- gravity = 9.80665;
- gravity_vector = Vector2(0, -1);
- gravity_is_point = false;
- gravity_distance_scale = 0;
- point_attenuation = 1;
-
- angular_damp = 1.0;
- linear_damp = 0.1;
- priority = 0;
- monitorable = false;
-}
-
-Area2DSW::~Area2DSW() {
-}
diff --git a/servers/physics_2d/area_pair_2d_sw.cpp b/servers/physics_2d/area_pair_2d_sw.cpp
deleted file mode 100644
index 21ad57e344..0000000000
--- a/servers/physics_2d/area_pair_2d_sw.cpp
+++ /dev/null
@@ -1,158 +0,0 @@
-/*************************************************************************/
-/* area_pair_2d_sw.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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 "area_pair_2d_sw.h"
-#include "collision_solver_2d_sw.h"
-
-bool AreaPair2DSW::setup(real_t p_step) {
- bool result = false;
-
- if (area->is_shape_set_as_disabled(area_shape) || body->is_shape_set_as_disabled(body_shape)) {
- result = false;
- } else if (area->test_collision_mask(body) && CollisionSolver2DSW::solve(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), Vector2(), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), Vector2(), nullptr, this)) {
- result = true;
- }
-
- if (result != colliding) {
- if (result) {
- if (area->get_space_override_mode() != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) {
- body->add_area(area);
- }
- if (area->has_monitor_callback()) {
- area->add_body_to_query(body, body_shape, area_shape);
- }
-
- } else {
- if (area->get_space_override_mode() != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) {
- body->remove_area(area);
- }
- if (area->has_monitor_callback()) {
- area->remove_body_from_query(body, body_shape, area_shape);
- }
- }
-
- colliding = result;
- }
-
- return false; //never do any post solving
-}
-
-void AreaPair2DSW::solve(real_t p_step) {
-}
-
-AreaPair2DSW::AreaPair2DSW(Body2DSW *p_body, int p_body_shape, Area2DSW *p_area, int p_area_shape) {
- body = p_body;
- area = p_area;
- body_shape = p_body_shape;
- area_shape = p_area_shape;
- colliding = false;
- body->add_constraint(this, 0);
- area->add_constraint(this);
- if (p_body->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) { //need to be active to process pair
- p_body->set_active(true);
- }
-}
-
-AreaPair2DSW::~AreaPair2DSW() {
- if (colliding) {
- if (area->get_space_override_mode() != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) {
- body->remove_area(area);
- }
- if (area->has_monitor_callback()) {
- area->remove_body_from_query(body, body_shape, area_shape);
- }
- }
- body->remove_constraint(this, 0);
- area->remove_constraint(this);
-}
-
-//////////////////////////////////
-
-bool Area2Pair2DSW::setup(real_t p_step) {
- bool result = false;
- if (area_a->is_shape_set_as_disabled(shape_a) || area_b->is_shape_set_as_disabled(shape_b)) {
- result = false;
- } else if (area_a->test_collision_mask(area_b) && CollisionSolver2DSW::solve(area_a->get_shape(shape_a), area_a->get_transform() * area_a->get_shape_transform(shape_a), Vector2(), area_b->get_shape(shape_b), area_b->get_transform() * area_b->get_shape_transform(shape_b), Vector2(), nullptr, this)) {
- result = true;
- }
-
- if (result != colliding) {
- if (result) {
- if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) {
- area_b->add_area_to_query(area_a, shape_a, shape_b);
- }
-
- if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) {
- area_a->add_area_to_query(area_b, shape_b, shape_a);
- }
-
- } else {
- if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) {
- area_b->remove_area_from_query(area_a, shape_a, shape_b);
- }
-
- if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) {
- area_a->remove_area_from_query(area_b, shape_b, shape_a);
- }
- }
-
- colliding = result;
- }
-
- return false; //never do any post solving
-}
-
-void Area2Pair2DSW::solve(real_t p_step) {
-}
-
-Area2Pair2DSW::Area2Pair2DSW(Area2DSW *p_area_a, int p_shape_a, Area2DSW *p_area_b, int p_shape_b) {
- area_a = p_area_a;
- area_b = p_area_b;
- shape_a = p_shape_a;
- shape_b = p_shape_b;
- colliding = false;
- area_a->add_constraint(this);
- area_b->add_constraint(this);
-}
-
-Area2Pair2DSW::~Area2Pair2DSW() {
- if (colliding) {
- if (area_b->has_area_monitor_callback()) {
- area_b->remove_area_from_query(area_a, shape_a, shape_b);
- }
-
- if (area_a->has_area_monitor_callback()) {
- area_a->remove_area_from_query(area_b, shape_b, shape_a);
- }
- }
-
- area_a->remove_constraint(this);
- area_b->remove_constraint(this);
-}
diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp
deleted file mode 100644
index d0636047b7..0000000000
--- a/servers/physics_2d/body_2d_sw.cpp
+++ /dev/null
@@ -1,705 +0,0 @@
-/*************************************************************************/
-/* body_2d_sw.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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 "body_2d_sw.h"
-#include "area_2d_sw.h"
-#include "physics_server_2d_sw.h"
-#include "space_2d_sw.h"
-
-void Body2DSW::_update_inertia() {
- if (!user_inertia && get_space() && !inertia_update_list.in_list()) {
- get_space()->body_add_to_inertia_update_list(&inertia_update_list);
- }
-}
-
-void Body2DSW::update_inertias() {
- //update shapes and motions
-
- switch (mode) {
- case PhysicsServer2D::BODY_MODE_RIGID: {
- if (user_inertia) {
- _inv_inertia = inertia > 0 ? (1.0 / inertia) : 0;
- break;
- }
- //update tensor for allshapes, not the best way but should be somehow OK. (inspired from bullet)
- real_t total_area = 0;
-
- for (int i = 0; i < get_shape_count(); i++) {
- total_area += get_shape_aabb(i).get_area();
- }
-
- inertia = 0;
-
- for (int i = 0; i < get_shape_count(); i++) {
- if (is_shape_disabled(i)) {
- continue;
- }
-
- const Shape2DSW *shape = get_shape(i);
-
- real_t area = get_shape_aabb(i).get_area();
-
- real_t mass = area * this->mass / total_area;
-
- Transform2D mtx = get_shape_transform(i);
- Vector2 scale = mtx.get_scale();
- inertia += shape->get_moment_of_inertia(mass, scale) + mass * mtx.get_origin().length_squared();
- }
-
- _inv_inertia = inertia > 0 ? (1.0 / inertia) : 0;
-
- if (mass) {
- _inv_mass = 1.0 / mass;
- } else {
- _inv_mass = 0;
- }
-
- } break;
- case PhysicsServer2D::BODY_MODE_KINEMATIC:
- case PhysicsServer2D::BODY_MODE_STATIC: {
- _inv_inertia = 0;
- _inv_mass = 0;
- } break;
- case PhysicsServer2D::BODY_MODE_CHARACTER: {
- _inv_inertia = 0;
- _inv_mass = 1.0 / mass;
-
- } break;
- }
- //_update_inertia_tensor();
-
- //_update_shapes();
-}
-
-void Body2DSW::set_active(bool p_active) {
- if (active == p_active) {
- return;
- }
-
- active = p_active;
- if (!p_active) {
- if (get_space()) {
- get_space()->body_remove_from_active_list(&active_list);
- }
- } else {
- if (mode == PhysicsServer2D::BODY_MODE_STATIC) {
- return; //static bodies can't become active
- }
- if (get_space()) {
- get_space()->body_add_to_active_list(&active_list);
- }
-
- //still_time=0;
- }
- /*
- if (!space)
- return;
-
- for(int i=0;i<get_shape_count();i++) {
- Shape &s=shapes[i];
- if (s.bpid>0) {
- get_space()->get_broadphase()->set_active(s.bpid,active);
- }
- }
-*/
-}
-
-void Body2DSW::set_param(PhysicsServer2D::BodyParameter p_param, real_t p_value) {
- switch (p_param) {
- case PhysicsServer2D::BODY_PARAM_BOUNCE: {
- bounce = p_value;
- } break;
- case PhysicsServer2D::BODY_PARAM_FRICTION: {
- friction = p_value;
- } break;
- case PhysicsServer2D::BODY_PARAM_MASS: {
- ERR_FAIL_COND(p_value <= 0);
- mass = p_value;
- _update_inertia();
-
- } break;
- case PhysicsServer2D::BODY_PARAM_INERTIA: {
- if (p_value <= 0) {
- user_inertia = false;
- _update_inertia();
- } else {
- user_inertia = true;
- inertia = p_value;
- _inv_inertia = 1.0 / p_value;
- }
- } break;
- case PhysicsServer2D::BODY_PARAM_GRAVITY_SCALE: {
- gravity_scale = p_value;
- } break;
- case PhysicsServer2D::BODY_PARAM_LINEAR_DAMP: {
- linear_damp = p_value;
- } break;
- case PhysicsServer2D::BODY_PARAM_ANGULAR_DAMP: {
- angular_damp = p_value;
- } break;
- default: {
- }
- }
-}
-
-real_t Body2DSW::get_param(PhysicsServer2D::BodyParameter p_param) const {
- switch (p_param) {
- case PhysicsServer2D::BODY_PARAM_BOUNCE: {
- return bounce;
- }
- case PhysicsServer2D::BODY_PARAM_FRICTION: {
- return friction;
- }
- case PhysicsServer2D::BODY_PARAM_MASS: {
- return mass;
- }
- case PhysicsServer2D::BODY_PARAM_INERTIA: {
- return inertia;
- }
- case PhysicsServer2D::BODY_PARAM_GRAVITY_SCALE: {
- return gravity_scale;
- }
- case PhysicsServer2D::BODY_PARAM_LINEAR_DAMP: {
- return linear_damp;
- }
- case PhysicsServer2D::BODY_PARAM_ANGULAR_DAMP: {
- return angular_damp;
- }
- default: {
- }
- }
-
- return 0;
-}
-
-void Body2DSW::set_mode(PhysicsServer2D::BodyMode p_mode) {
- PhysicsServer2D::BodyMode prev = mode;
- mode = p_mode;
-
- switch (p_mode) {
- //CLEAR UP EVERYTHING IN CASE IT NOT WORKS!
- case PhysicsServer2D::BODY_MODE_STATIC:
- case PhysicsServer2D::BODY_MODE_KINEMATIC: {
- _set_inv_transform(get_transform().affine_inverse());
- _inv_mass = 0;
- _inv_inertia = 0;
- _set_static(p_mode == PhysicsServer2D::BODY_MODE_STATIC);
- set_active(p_mode == PhysicsServer2D::BODY_MODE_KINEMATIC && contacts.size());
- linear_velocity = Vector2();
- angular_velocity = 0;
- if (mode == PhysicsServer2D::BODY_MODE_KINEMATIC && prev != mode) {
- first_time_kinematic = true;
- }
- } break;
- case PhysicsServer2D::BODY_MODE_RIGID: {
- _inv_mass = mass > 0 ? (1.0 / mass) : 0;
- _inv_inertia = inertia > 0 ? (1.0 / inertia) : 0;
- _set_static(false);
- set_active(true);
-
- } break;
- case PhysicsServer2D::BODY_MODE_CHARACTER: {
- _inv_mass = mass > 0 ? (1.0 / mass) : 0;
- _inv_inertia = 0;
- _set_static(false);
- set_active(true);
- angular_velocity = 0;
- } break;
- }
- if (p_mode == PhysicsServer2D::BODY_MODE_RIGID && _inv_inertia == 0) {
- _update_inertia();
- }
- /*
- if (get_space())
- _update_queries();
- */
-}
-
-PhysicsServer2D::BodyMode Body2DSW::get_mode() const {
- return mode;
-}
-
-void Body2DSW::_shapes_changed() {
- _update_inertia();
- wakeup_neighbours();
-}
-
-void Body2DSW::set_state(PhysicsServer2D::BodyState p_state, const Variant &p_variant) {
- switch (p_state) {
- case PhysicsServer2D::BODY_STATE_TRANSFORM: {
- if (mode == PhysicsServer2D::BODY_MODE_KINEMATIC) {
- new_transform = p_variant;
- //wakeup_neighbours();
- set_active(true);
- if (first_time_kinematic) {
- _set_transform(p_variant);
- _set_inv_transform(get_transform().affine_inverse());
- first_time_kinematic = false;
- }
- } else if (mode == PhysicsServer2D::BODY_MODE_STATIC) {
- _set_transform(p_variant);
- _set_inv_transform(get_transform().affine_inverse());
- wakeup_neighbours();
- } else {
- Transform2D t = p_variant;
- t.orthonormalize();
- new_transform = get_transform(); //used as old to compute motion
- if (t == new_transform) {
- break;
- }
- _set_transform(t);
- _set_inv_transform(get_transform().inverse());
- }
- wakeup();
-
- } break;
- case PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY: {
- /*
- if (mode==PhysicsServer2D::BODY_MODE_STATIC)
- break;
- */
- linear_velocity = p_variant;
- wakeup();
-
- } break;
- case PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY: {
- /*
- if (mode!=PhysicsServer2D::BODY_MODE_RIGID)
- break;
- */
- angular_velocity = p_variant;
- wakeup();
-
- } break;
- case PhysicsServer2D::BODY_STATE_SLEEPING: {
- //?
- if (mode == PhysicsServer2D::BODY_MODE_STATIC || mode == PhysicsServer2D::BODY_MODE_KINEMATIC) {
- break;
- }
- bool do_sleep = p_variant;
- if (do_sleep) {
- linear_velocity = Vector2();
- //biased_linear_velocity=Vector3();
- angular_velocity = 0;
- //biased_angular_velocity=Vector3();
- set_active(false);
- } else {
- if (mode != PhysicsServer2D::BODY_MODE_STATIC) {
- set_active(true);
- }
- }
- } break;
- case PhysicsServer2D::BODY_STATE_CAN_SLEEP: {
- can_sleep = p_variant;
- if (mode == PhysicsServer2D::BODY_MODE_RIGID && !active && !can_sleep) {
- set_active(true);
- }
-
- } break;
- }
-}
-
-Variant Body2DSW::get_state(PhysicsServer2D::BodyState p_state) const {
- switch (p_state) {
- case PhysicsServer2D::BODY_STATE_TRANSFORM: {
- return get_transform();
- }
- case PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY: {
- return linear_velocity;
- }
- case PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY: {
- return angular_velocity;
- }
- case PhysicsServer2D::BODY_STATE_SLEEPING: {
- return !is_active();
- }
- case PhysicsServer2D::BODY_STATE_CAN_SLEEP: {
- return can_sleep;
- }
- }
-
- return Variant();
-}
-
-void Body2DSW::set_space(Space2DSW *p_space) {
- if (get_space()) {
- wakeup_neighbours();
-
- if (inertia_update_list.in_list()) {
- get_space()->body_remove_from_inertia_update_list(&inertia_update_list);
- }
- if (active_list.in_list()) {
- get_space()->body_remove_from_active_list(&active_list);
- }
- if (direct_state_query_list.in_list()) {
- get_space()->body_remove_from_state_query_list(&direct_state_query_list);
- }
- }
-
- _set_space(p_space);
-
- if (get_space()) {
- _update_inertia();
- if (active) {
- get_space()->body_add_to_active_list(&active_list);
- }
- /*
- _update_queries();
- if (is_active()) {
- active=false;
- set_active(true);
- }
- */
- }
-
- first_integration = false;
-}
-
-void Body2DSW::_compute_area_gravity_and_dampenings(const Area2DSW *p_area) {
- if (p_area->is_gravity_point()) {
- if (p_area->get_gravity_distance_scale() > 0) {
- Vector2 v = p_area->get_transform().xform(p_area->get_gravity_vector()) - get_transform().get_origin();
- gravity += v.normalized() * (p_area->get_gravity() / Math::pow(v.length() * p_area->get_gravity_distance_scale() + 1, 2));
- } else {
- gravity += (p_area->get_transform().xform(p_area->get_gravity_vector()) - get_transform().get_origin()).normalized() * p_area->get_gravity();
- }
- } else {
- gravity += p_area->get_gravity_vector() * p_area->get_gravity();
- }
-
- area_linear_damp += p_area->get_linear_damp();
- area_angular_damp += p_area->get_angular_damp();
-}
-
-void Body2DSW::integrate_forces(real_t p_step) {
- if (mode == PhysicsServer2D::BODY_MODE_STATIC) {
- return;
- }
-
- Area2DSW *def_area = get_space()->get_default_area();
- // Area2DSW *damp_area = def_area;
- ERR_FAIL_COND(!def_area);
-
- int ac = areas.size();
- bool stopped = false;
- gravity = Vector2(0, 0);
- area_angular_damp = 0;
- area_linear_damp = 0;
- if (ac) {
- areas.sort();
- const AreaCMP *aa = &areas[0];
- // damp_area = aa[ac-1].area;
- for (int i = ac - 1; i >= 0 && !stopped; i--) {
- PhysicsServer2D::AreaSpaceOverrideMode mode = aa[i].area->get_space_override_mode();
- switch (mode) {
- case PhysicsServer2D::AREA_SPACE_OVERRIDE_COMBINE:
- case PhysicsServer2D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: {
- _compute_area_gravity_and_dampenings(aa[i].area);
- stopped = mode == PhysicsServer2D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE;
- } break;
- case PhysicsServer2D::AREA_SPACE_OVERRIDE_REPLACE:
- case PhysicsServer2D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: {
- gravity = Vector2(0, 0);
- area_angular_damp = 0;
- area_linear_damp = 0;
- _compute_area_gravity_and_dampenings(aa[i].area);
- stopped = mode == PhysicsServer2D::AREA_SPACE_OVERRIDE_REPLACE;
- } break;
- default: {
- }
- }
- }
- }
- if (!stopped) {
- _compute_area_gravity_and_dampenings(def_area);
- }
- gravity *= gravity_scale;
-
- // If less than 0, override dampenings with that of the Body2D
- if (angular_damp >= 0) {
- area_angular_damp = angular_damp;
- }
- /*
- else
- area_angular_damp=damp_area->get_angular_damp();
- */
-
- if (linear_damp >= 0) {
- area_linear_damp = linear_damp;
- }
- /*
- else
- area_linear_damp=damp_area->get_linear_damp();
- */
-
- Vector2 motion;
- bool do_motion = false;
-
- if (mode == PhysicsServer2D::BODY_MODE_KINEMATIC) {
- //compute motion, angular and etc. velocities from prev transform
- motion = new_transform.get_origin() - get_transform().get_origin();
- linear_velocity = motion / p_step;
-
- real_t rot = new_transform.get_rotation() - get_transform().get_rotation();
- angular_velocity = remainder(rot, 2.0 * Math_PI) / p_step;
-
- do_motion = true;
-
- /*
- for(int i=0;i<get_shape_count();i++) {
- set_shape_kinematic_advance(i,Vector2());
- set_shape_kinematic_retreat(i,0);
- }
- */
-
- } else {
- if (!omit_force_integration && !first_integration) {
- //overridden by direct state query
-
- Vector2 force = gravity * mass;
- force += applied_force;
- real_t torque = applied_torque;
-
- real_t damp = 1.0 - p_step * area_linear_damp;
-
- if (damp < 0) { // reached zero in the given time
- damp = 0;
- }
-
- real_t angular_damp = 1.0 - p_step * area_angular_damp;
-
- if (angular_damp < 0) { // reached zero in the given time
- angular_damp = 0;
- }
-
- linear_velocity *= damp;
- angular_velocity *= angular_damp;
-
- linear_velocity += _inv_mass * force * p_step;
- angular_velocity += _inv_inertia * torque * p_step;
- }
-
- if (continuous_cd_mode != PhysicsServer2D::CCD_MODE_DISABLED) {
- motion = linear_velocity * p_step;
- do_motion = true;
- }
- }
-
- //motion=linear_velocity*p_step;
-
- first_integration = false;
- biased_angular_velocity = 0;
- biased_linear_velocity = Vector2();
-
- if (do_motion) { //shapes temporarily extend for raycast
- _update_shapes_with_motion(motion);
- }
-
- // damp_area=nullptr; // clear the area, so it is set in the next frame
- def_area = nullptr; // clear the area, so it is set in the next frame
- contact_count = 0;
-}
-
-void Body2DSW::integrate_velocities(real_t p_step) {
- if (mode == PhysicsServer2D::BODY_MODE_STATIC) {
- return;
- }
-
- if (fi_callback) {
- get_space()->body_add_to_state_query_list(&direct_state_query_list);
- }
-
- if (mode == PhysicsServer2D::BODY_MODE_KINEMATIC) {
- _set_transform(new_transform, false);
- _set_inv_transform(new_transform.affine_inverse());
- if (contacts.size() == 0 && linear_velocity == Vector2() && angular_velocity == 0) {
- set_active(false); //stopped moving, deactivate
- }
- return;
- }
-
- real_t total_angular_velocity = angular_velocity + biased_angular_velocity;
- Vector2 total_linear_velocity = linear_velocity + biased_linear_velocity;
-
- real_t angle = get_transform().get_rotation() + total_angular_velocity * p_step;
- Vector2 pos = get_transform().get_origin() + total_linear_velocity * p_step;
-
- _set_transform(Transform2D(angle, pos), continuous_cd_mode == PhysicsServer2D::CCD_MODE_DISABLED);
- _set_inv_transform(get_transform().inverse());
-
- if (continuous_cd_mode != PhysicsServer2D::CCD_MODE_DISABLED) {
- new_transform = get_transform();
- }
-
- //_update_inertia_tensor();
-}
-
-void Body2DSW::wakeup_neighbours() {
- for (List<Pair<Constraint2DSW *, int>>::Element *E = constraint_list.front(); E; E = E->next()) {
- const Constraint2DSW *c = E->get().first;
- Body2DSW **n = c->get_body_ptr();
- int bc = c->get_body_count();
-
- for (int i = 0; i < bc; i++) {
- if (i == E->get().second) {
- continue;
- }
- Body2DSW *b = n[i];
- if (b->mode != PhysicsServer2D::BODY_MODE_RIGID) {
- continue;
- }
-
- if (!b->is_active()) {
- b->set_active(true);
- }
- }
- }
-}
-
-void Body2DSW::call_queries() {
- if (fi_callback) {
- PhysicsDirectBodyState2DSW *dbs = PhysicsDirectBodyState2DSW::singleton;
- dbs->body = this;
-
- Variant v = dbs;
- const Variant *vp[2] = { &v, &fi_callback->callback_udata };
-
- Object *obj = ObjectDB::get_instance(fi_callback->id);
- if (!obj) {
- set_force_integration_callback(ObjectID(), StringName());
- } else {
- Callable::CallError ce;
- if (fi_callback->callback_udata.get_type() != Variant::NIL) {
- obj->call(fi_callback->method, vp, 2, ce);
-
- } else {
- obj->call(fi_callback->method, vp, 1, ce);
- }
- }
- }
-}
-
-bool Body2DSW::sleep_test(real_t p_step) {
- if (mode == PhysicsServer2D::BODY_MODE_STATIC || mode == PhysicsServer2D::BODY_MODE_KINEMATIC) {
- return true; //
- } else if (mode == PhysicsServer2D::BODY_MODE_CHARACTER) {
- return !active; // characters and kinematic bodies don't sleep unless asked to sleep
- } else if (!can_sleep) {
- return false;
- }
-
- if (Math::abs(angular_velocity) < get_space()->get_body_angular_velocity_sleep_threshold() && Math::abs(linear_velocity.length_squared()) < get_space()->get_body_linear_velocity_sleep_threshold() * get_space()->get_body_linear_velocity_sleep_threshold()) {
- still_time += p_step;
-
- return still_time > get_space()->get_body_time_to_sleep();
- } else {
- still_time = 0; //maybe this should be set to 0 on set_active?
- return false;
- }
-}
-
-void Body2DSW::set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata) {
- if (fi_callback) {
- memdelete(fi_callback);
- fi_callback = nullptr;
- }
-
- if (p_id.is_valid()) {
- fi_callback = memnew(ForceIntegrationCallback);
- fi_callback->id = p_id;
- fi_callback->method = p_method;
- fi_callback->callback_udata = p_udata;
- }
-}
-
-Body2DSW::Body2DSW() :
- CollisionObject2DSW(TYPE_BODY),
- active_list(this),
- inertia_update_list(this),
- direct_state_query_list(this) {
- mode = PhysicsServer2D::BODY_MODE_RIGID;
- active = true;
- angular_velocity = 0;
- biased_angular_velocity = 0;
- mass = 1;
- inertia = 0;
- user_inertia = false;
- _inv_inertia = 0;
- _inv_mass = 1;
- bounce = 0;
- friction = 1;
- omit_force_integration = false;
- applied_torque = 0;
- island_step = 0;
- island_next = nullptr;
- island_list_next = nullptr;
- _set_static(false);
- first_time_kinematic = false;
- linear_damp = -1;
- angular_damp = -1;
- area_angular_damp = 0;
- area_linear_damp = 0;
- contact_count = 0;
- gravity_scale = 1.0;
- first_integration = false;
-
- still_time = 0;
- continuous_cd_mode = PhysicsServer2D::CCD_MODE_DISABLED;
- can_sleep = true;
- fi_callback = nullptr;
-}
-
-Body2DSW::~Body2DSW() {
- if (fi_callback) {
- memdelete(fi_callback);
- }
-}
-
-PhysicsDirectBodyState2DSW *PhysicsDirectBodyState2DSW::singleton = nullptr;
-
-PhysicsDirectSpaceState2D *PhysicsDirectBodyState2DSW::get_space_state() {
- return body->get_space()->get_direct_state();
-}
-
-Variant PhysicsDirectBodyState2DSW::get_contact_collider_shape_metadata(int p_contact_idx) const {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Variant());
-
- if (!PhysicsServer2DSW::singletonsw->body_owner.owns(body->contacts[p_contact_idx].collider)) {
- return Variant();
- }
- Body2DSW *other = PhysicsServer2DSW::singletonsw->body_owner.getornull(body->contacts[p_contact_idx].collider);
-
- int sidx = body->contacts[p_contact_idx].collider_shape;
- if (sidx < 0 || sidx >= other->get_shape_count()) {
- return Variant();
- }
-
- return other->get_shape_metadata(sidx);
-}
diff --git a/servers/physics_2d/broad_phase_2d_basic.cpp b/servers/physics_2d/broad_phase_2d_basic.cpp
deleted file mode 100644
index 17424629a9..0000000000
--- a/servers/physics_2d/broad_phase_2d_basic.cpp
+++ /dev/null
@@ -1,174 +0,0 @@
-/*************************************************************************/
-/* broad_phase_2d_basic.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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 "broad_phase_2d_basic.h"
-
-BroadPhase2DBasic::ID BroadPhase2DBasic::create(CollisionObject2DSW *p_object_, int p_subindex) {
- current++;
-
- Element e;
- e.owner = p_object_;
- e._static = false;
- e.subindex = p_subindex;
-
- element_map[current] = e;
- return current;
-}
-
-void BroadPhase2DBasic::move(ID p_id, const Rect2 &p_aabb) {
- Map<ID, Element>::Element *E = element_map.find(p_id);
- ERR_FAIL_COND(!E);
- E->get().aabb = p_aabb;
-}
-
-void BroadPhase2DBasic::set_static(ID p_id, bool p_static) {
- Map<ID, Element>::Element *E = element_map.find(p_id);
- ERR_FAIL_COND(!E);
- E->get()._static = p_static;
-}
-
-void BroadPhase2DBasic::remove(ID p_id) {
- Map<ID, Element>::Element *E = element_map.find(p_id);
- ERR_FAIL_COND(!E);
- element_map.erase(E);
-}
-
-CollisionObject2DSW *BroadPhase2DBasic::get_object(ID p_id) const {
- const Map<ID, Element>::Element *E = element_map.find(p_id);
- ERR_FAIL_COND_V(!E, nullptr);
- return E->get().owner;
-}
-
-bool BroadPhase2DBasic::is_static(ID p_id) const {
- const Map<ID, Element>::Element *E = element_map.find(p_id);
- ERR_FAIL_COND_V(!E, false);
- return E->get()._static;
-}
-
-int BroadPhase2DBasic::get_subindex(ID p_id) const {
- const Map<ID, Element>::Element *E = element_map.find(p_id);
- ERR_FAIL_COND_V(!E, -1);
- return E->get().subindex;
-}
-
-int BroadPhase2DBasic::cull_segment(const Vector2 &p_from, const Vector2 &p_to, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices) {
- int rc = 0;
-
- for (Map<ID, Element>::Element *E = element_map.front(); E; E = E->next()) {
- const Rect2 aabb = E->get().aabb;
- if (aabb.intersects_segment(p_from, p_to)) {
- p_results[rc] = E->get().owner;
- p_result_indices[rc] = E->get().subindex;
- rc++;
- if (rc >= p_max_results) {
- break;
- }
- }
- }
-
- return rc;
-}
-
-int BroadPhase2DBasic::cull_aabb(const Rect2 &p_aabb, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices) {
- int rc = 0;
-
- for (Map<ID, Element>::Element *E = element_map.front(); E; E = E->next()) {
- const Rect2 aabb = E->get().aabb;
- if (aabb.intersects(p_aabb)) {
- p_results[rc] = E->get().owner;
- p_result_indices[rc] = E->get().subindex;
- rc++;
- if (rc >= p_max_results) {
- break;
- }
- }
- }
-
- return rc;
-}
-
-void BroadPhase2DBasic::set_pair_callback(PairCallback p_pair_callback, void *p_userdata) {
- pair_userdata = p_userdata;
- pair_callback = p_pair_callback;
-}
-
-void BroadPhase2DBasic::set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) {
- unpair_userdata = p_userdata;
- unpair_callback = p_unpair_callback;
-}
-
-void BroadPhase2DBasic::update() {
- // recompute pairs
- for (Map<ID, Element>::Element *I = element_map.front(); I; I = I->next()) {
- for (Map<ID, Element>::Element *J = I->next(); J; J = J->next()) {
- Element *elem_A = &I->get();
- Element *elem_B = &J->get();
-
- if (elem_A->owner == elem_B->owner) {
- continue;
- }
-
- bool pair_ok = elem_A->aabb.intersects(elem_B->aabb) && (!elem_A->_static || !elem_B->_static);
-
- PairKey key(I->key(), J->key());
-
- Map<PairKey, void *>::Element *E = pair_map.find(key);
-
- if (!pair_ok && E) {
- if (unpair_callback) {
- unpair_callback(elem_A->owner, elem_A->subindex, elem_B->owner, elem_B->subindex, E->get(), unpair_userdata);
- }
- pair_map.erase(key);
- }
-
- if (pair_ok && !E) {
- void *data = nullptr;
- if (pair_callback) {
- data = pair_callback(elem_A->owner, elem_A->subindex, elem_B->owner, elem_B->subindex, unpair_userdata);
- if (data) {
- pair_map.insert(key, data);
- }
- }
- }
- }
- }
-}
-
-BroadPhase2DSW *BroadPhase2DBasic::_create() {
- return memnew(BroadPhase2DBasic);
-}
-
-BroadPhase2DBasic::BroadPhase2DBasic() {
- current = 1;
- unpair_callback = nullptr;
- unpair_userdata = nullptr;
- pair_callback = nullptr;
- pair_userdata = nullptr;
-}
diff --git a/servers/physics_2d/broad_phase_2d_basic.h b/servers/physics_2d/broad_phase_2d_basic.h
deleted file mode 100644
index ca1db360fb..0000000000
--- a/servers/physics_2d/broad_phase_2d_basic.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*************************************************************************/
-/* broad_phase_2d_basic.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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 BROAD_PHASE_2D_BASIC_H
-#define BROAD_PHASE_2D_BASIC_H
-
-#include "core/templates/map.h"
-#include "space_2d_sw.h"
-class BroadPhase2DBasic : public BroadPhase2DSW {
- struct Element {
- CollisionObject2DSW *owner;
- bool _static;
- Rect2 aabb;
- int subindex;
- };
-
- Map<ID, Element> element_map;
-
- ID current;
-
- struct PairKey {
- union {
- struct {
- ID a;
- ID b;
- };
- uint64_t key;
- };
-
- _FORCE_INLINE_ bool operator<(const PairKey &p_key) const {
- return key < p_key.key;
- }
-
- PairKey() { key = 0; }
- PairKey(ID p_a, ID p_b) {
- if (p_a > p_b) {
- a = p_b;
- b = p_a;
- } else {
- a = p_a;
- b = p_b;
- }
- }
- };
-
- Map<PairKey, void *> pair_map;
-
- PairCallback pair_callback;
- void *pair_userdata;
- UnpairCallback unpair_callback;
- void *unpair_userdata;
-
-public:
- // 0 is an invalid ID
- virtual ID create(CollisionObject2DSW *p_object_, int p_subindex = 0);
- virtual void move(ID p_id, const Rect2 &p_aabb);
- virtual void set_static(ID p_id, bool p_static);
- virtual void remove(ID p_id);
-
- virtual CollisionObject2DSW *get_object(ID p_id) const;
- virtual bool is_static(ID p_id) const;
- virtual int get_subindex(ID p_id) const;
-
- virtual int cull_segment(const Vector2 &p_from, const Vector2 &p_to, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices = nullptr);
- virtual int cull_aabb(const Rect2 &p_aabb, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices = nullptr);
-
- virtual void set_pair_callback(PairCallback p_pair_callback, void *p_userdata);
- virtual void set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata);
-
- virtual void update();
-
- static BroadPhase2DSW *_create();
- BroadPhase2DBasic();
-};
-
-#endif // BROAD_PHASE_2D_BASIC_H
diff --git a/servers/physics_2d/broad_phase_2d_hash_grid.cpp b/servers/physics_2d/broad_phase_2d_hash_grid.cpp
deleted file mode 100644
index 6cfe6908d1..0000000000
--- a/servers/physics_2d/broad_phase_2d_hash_grid.cpp
+++ /dev/null
@@ -1,735 +0,0 @@
-/*************************************************************************/
-/* broad_phase_2d_hash_grid.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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 "broad_phase_2d_hash_grid.h"
-#include "collision_object_2d_sw.h"
-#include "core/config/project_settings.h"
-
-#define LARGE_ELEMENT_FI 1.01239812
-
-void BroadPhase2DHashGrid::_pair_attempt(Element *p_elem, Element *p_with) {
- Map<Element *, PairData *>::Element *E = p_elem->paired.find(p_with);
-
- ERR_FAIL_COND(p_elem->_static && p_with->_static);
-
- if (!E) {
- PairData *pd = memnew(PairData);
- p_elem->paired[p_with] = pd;
- p_with->paired[p_elem] = pd;
- } else {
- E->get()->rc++;
- }
-}
-
-void BroadPhase2DHashGrid::_unpair_attempt(Element *p_elem, Element *p_with) {
- Map<Element *, PairData *>::Element *E = p_elem->paired.find(p_with);
-
- ERR_FAIL_COND(!E); //this should really be paired..
-
- E->get()->rc--;
-
- if (E->get()->rc == 0) {
- if (E->get()->colliding) {
- //uncollide
- if (unpair_callback) {
- unpair_callback(p_elem->owner, p_elem->subindex, p_with->owner, p_with->subindex, E->get()->ud, unpair_userdata);
- }
- }
-
- memdelete(E->get());
- p_elem->paired.erase(E);
- p_with->paired.erase(p_elem);
- }
-}
-
-void BroadPhase2DHashGrid::_check_motion(Element *p_elem) {
- for (Map<Element *, PairData *>::Element *E = p_elem->paired.front(); E; E = E->next()) {
- bool physical_collision = p_elem->aabb.intersects(E->key()->aabb);
- bool logical_collision = p_elem->owner->test_collision_mask(E->key()->owner);
-
- if (physical_collision) {
- if (!E->get()->colliding || (logical_collision && !E->get()->ud && pair_callback)) {
- E->get()->ud = pair_callback(p_elem->owner, p_elem->subindex, E->key()->owner, E->key()->subindex, pair_userdata);
- } else if (E->get()->colliding && !logical_collision && E->get()->ud && unpair_callback) {
- unpair_callback(p_elem->owner, p_elem->subindex, E->key()->owner, E->key()->subindex, E->get()->ud, unpair_userdata);
- E->get()->ud = nullptr;
- }
- E->get()->colliding = true;
- } else { // No physcial_collision
- if (E->get()->colliding && unpair_callback) {
- unpair_callback(p_elem->owner, p_elem->subindex, E->key()->owner, E->key()->subindex, E->get()->ud, unpair_userdata);
- }
- E->get()->colliding = false;
- }
- }
-}
-
-void BroadPhase2DHashGrid::_enter_grid(Element *p_elem, const Rect2 &p_rect, bool p_static) {
- Vector2 sz = (p_rect.size / cell_size * LARGE_ELEMENT_FI); //use magic number to avoid floating point issues
- if (sz.width * sz.height > large_object_min_surface) {
- //large object, do not use grid, must check against all elements
- for (Map<ID, Element>::Element *E = element_map.front(); E; E = E->next()) {
- if (E->key() == p_elem->self) {
- continue; // do not pair against itself
- }
- if (E->get().owner == p_elem->owner) {
- continue;
- }
- if (E->get()._static && p_static) {
- continue;
- }
-
- _pair_attempt(p_elem, &E->get());
- }
-
- large_elements[p_elem].inc();
- return;
- }
-
- Point2i from = (p_rect.position / cell_size).floor();
- Point2i to = ((p_rect.position + p_rect.size) / cell_size).floor();
-
- for (int i = from.x; i <= to.x; i++) {
- for (int j = from.y; j <= to.y; j++) {
- PosKey pk;
- pk.x = i;
- pk.y = j;
-
- uint32_t idx = pk.hash() % hash_table_size;
- PosBin *pb = hash_table[idx];
-
- while (pb) {
- if (pb->key == pk) {
- break;
- }
-
- pb = pb->next;
- }
-
- bool entered = false;
-
- if (!pb) {
- //does not exist, create!
- pb = memnew(PosBin);
- pb->key = pk;
- pb->next = hash_table[idx];
- hash_table[idx] = pb;
- }
-
- if (p_static) {
- if (pb->static_object_set[p_elem].inc() == 1) {
- entered = true;
- }
- } else {
- if (pb->object_set[p_elem].inc() == 1) {
- entered = true;
- }
- }
-
- if (entered) {
- for (Map<Element *, RC>::Element *E = pb->object_set.front(); E; E = E->next()) {
- if (E->key()->owner == p_elem->owner) {
- continue;
- }
- _pair_attempt(p_elem, E->key());
- }
-
- if (!p_static) {
- for (Map<Element *, RC>::Element *E = pb->static_object_set.front(); E; E = E->next()) {
- if (E->key()->owner == p_elem->owner) {
- continue;
- }
- _pair_attempt(p_elem, E->key());
- }
- }
- }
- }
- }
-
- //pair separatedly with large elements
-
- for (Map<Element *, RC>::Element *E = large_elements.front(); E; E = E->next()) {
- if (E->key() == p_elem) {
- continue; // do not pair against itself
- }
- if (E->key()->owner == p_elem->owner) {
- continue;
- }
- if (E->key()->_static && p_static) {
- continue;
- }
-
- _pair_attempt(E->key(), p_elem);
- }
-}
-
-void BroadPhase2DHashGrid::_exit_grid(Element *p_elem, const Rect2 &p_rect, bool p_static) {
- Vector2 sz = (p_rect.size / cell_size * LARGE_ELEMENT_FI);
- if (sz.width * sz.height > large_object_min_surface) {
- //unpair all elements, instead of checking all, just check what is already paired, so we at least save from checking static vs static
- Map<Element *, PairData *>::Element *E = p_elem->paired.front();
- while (E) {
- Map<Element *, PairData *>::Element *next = E->next();
- _unpair_attempt(p_elem, E->key());
- E = next;
- }
-
- if (large_elements[p_elem].dec() == 0) {
- large_elements.erase(p_elem);
- }
- return;
- }
-
- Point2i from = (p_rect.position / cell_size).floor();
- Point2i to = ((p_rect.position + p_rect.size) / cell_size).floor();
-
- for (int i = from.x; i <= to.x; i++) {
- for (int j = from.y; j <= to.y; j++) {
- PosKey pk;
- pk.x = i;
- pk.y = j;
-
- uint32_t idx = pk.hash() % hash_table_size;
- PosBin *pb = hash_table[idx];
-
- while (pb) {
- if (pb->key == pk) {
- break;
- }
-
- pb = pb->next;
- }
-
- ERR_CONTINUE(!pb); //should exist!!
-
- bool exited = false;
-
- if (p_static) {
- if (pb->static_object_set[p_elem].dec() == 0) {
- pb->static_object_set.erase(p_elem);
- exited = true;
- }
- } else {
- if (pb->object_set[p_elem].dec() == 0) {
- pb->object_set.erase(p_elem);
- exited = true;
- }
- }
-
- if (exited) {
- for (Map<Element *, RC>::Element *E = pb->object_set.front(); E; E = E->next()) {
- if (E->key()->owner == p_elem->owner) {
- continue;
- }
- _unpair_attempt(p_elem, E->key());
- }
-
- if (!p_static) {
- for (Map<Element *, RC>::Element *E = pb->static_object_set.front(); E; E = E->next()) {
- if (E->key()->owner == p_elem->owner) {
- continue;
- }
- _unpair_attempt(p_elem, E->key());
- }
- }
- }
-
- if (pb->object_set.is_empty() && pb->static_object_set.is_empty()) {
- if (hash_table[idx] == pb) {
- hash_table[idx] = pb->next;
- } else {
- PosBin *px = hash_table[idx];
-
- while (px) {
- if (px->next == pb) {
- px->next = pb->next;
- break;
- }
-
- px = px->next;
- }
-
- ERR_CONTINUE(!px);
- }
-
- memdelete(pb);
- }
- }
- }
-
- for (Map<Element *, RC>::Element *E = large_elements.front(); E; E = E->next()) {
- if (E->key() == p_elem) {
- continue; // do not pair against itself
- }
- if (E->key()->owner == p_elem->owner) {
- continue;
- }
- if (E->key()->_static && p_static) {
- continue;
- }
-
- //unpair from large elements
- _unpair_attempt(p_elem, E->key());
- }
-}
-
-BroadPhase2DHashGrid::ID BroadPhase2DHashGrid::create(CollisionObject2DSW *p_object, int p_subindex) {
- current++;
-
- Element e;
- e.owner = p_object;
- e._static = false;
- e.subindex = p_subindex;
- e.self = current;
- e.pass = 0;
-
- element_map[current] = e;
- return current;
-}
-
-void BroadPhase2DHashGrid::move(ID p_id, const Rect2 &p_aabb) {
- Map<ID, Element>::Element *E = element_map.find(p_id);
- ERR_FAIL_COND(!E);
-
- Element &e = E->get();
-
- if (p_aabb != e.aabb) {
- if (p_aabb != Rect2()) {
- _enter_grid(&e, p_aabb, e._static);
- }
- if (e.aabb != Rect2()) {
- _exit_grid(&e, e.aabb, e._static);
- }
- e.aabb = p_aabb;
- }
-
- _check_motion(&e);
-}
-
-void BroadPhase2DHashGrid::set_static(ID p_id, bool p_static) {
- Map<ID, Element>::Element *E = element_map.find(p_id);
- ERR_FAIL_COND(!E);
-
- Element &e = E->get();
-
- if (e._static == p_static) {
- return;
- }
-
- if (e.aabb != Rect2()) {
- _exit_grid(&e, e.aabb, e._static);
- }
-
- e._static = p_static;
-
- if (e.aabb != Rect2()) {
- _enter_grid(&e, e.aabb, e._static);
- _check_motion(&e);
- }
-}
-
-void BroadPhase2DHashGrid::remove(ID p_id) {
- Map<ID, Element>::Element *E = element_map.find(p_id);
- ERR_FAIL_COND(!E);
-
- Element &e = E->get();
-
- if (e.aabb != Rect2()) {
- _exit_grid(&e, e.aabb, e._static);
- }
-
- element_map.erase(p_id);
-}
-
-CollisionObject2DSW *BroadPhase2DHashGrid::get_object(ID p_id) const {
- const Map<ID, Element>::Element *E = element_map.find(p_id);
- ERR_FAIL_COND_V(!E, nullptr);
- return E->get().owner;
-}
-
-bool BroadPhase2DHashGrid::is_static(ID p_id) const {
- const Map<ID, Element>::Element *E = element_map.find(p_id);
- ERR_FAIL_COND_V(!E, false);
- return E->get()._static;
-}
-
-int BroadPhase2DHashGrid::get_subindex(ID p_id) const {
- const Map<ID, Element>::Element *E = element_map.find(p_id);
- ERR_FAIL_COND_V(!E, -1);
- return E->get().subindex;
-}
-
-template <bool use_aabb, bool use_segment>
-void BroadPhase2DHashGrid::_cull(const Point2i p_cell, const Rect2 &p_aabb, const Point2 &p_from, const Point2 &p_to, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices, int &index) {
- PosKey pk;
- pk.x = p_cell.x;
- pk.y = p_cell.y;
-
- uint32_t idx = pk.hash() % hash_table_size;
- PosBin *pb = hash_table[idx];
-
- while (pb) {
- if (pb->key == pk) {
- break;
- }
-
- pb = pb->next;
- }
-
- if (!pb) {
- return;
- }
-
- for (Map<Element *, RC>::Element *E = pb->object_set.front(); E; E = E->next()) {
- if (index >= p_max_results) {
- break;
- }
- if (E->key()->pass == pass) {
- continue;
- }
-
- E->key()->pass = pass;
-
- if (use_aabb && !p_aabb.intersects(E->key()->aabb)) {
- continue;
- }
-
- if (use_segment && !E->key()->aabb.intersects_segment(p_from, p_to)) {
- continue;
- }
-
- p_results[index] = E->key()->owner;
- p_result_indices[index] = E->key()->subindex;
- index++;
- }
-
- for (Map<Element *, RC>::Element *E = pb->static_object_set.front(); E; E = E->next()) {
- if (index >= p_max_results) {
- break;
- }
- if (E->key()->pass == pass) {
- continue;
- }
-
- if (use_aabb && !p_aabb.intersects(E->key()->aabb)) {
- continue;
- }
-
- if (use_segment && !E->key()->aabb.intersects_segment(p_from, p_to)) {
- continue;
- }
-
- E->key()->pass = pass;
- p_results[index] = E->key()->owner;
- p_result_indices[index] = E->key()->subindex;
- index++;
- }
-}
-
-int BroadPhase2DHashGrid::cull_segment(const Vector2 &p_from, const Vector2 &p_to, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices) {
- pass++;
-
- Vector2 dir = (p_to - p_from);
- if (dir == Vector2()) {
- return 0;
- }
- //avoid divisions by zero
- dir.normalize();
- if (dir.x == 0.0) {
- dir.x = 0.000001;
- }
- if (dir.y == 0.0) {
- dir.y = 0.000001;
- }
- Vector2 delta = dir.abs();
-
- delta.x = cell_size / delta.x;
- delta.y = cell_size / delta.y;
-
- Point2i pos = (p_from / cell_size).floor();
- Point2i end = (p_to / cell_size).floor();
-
- Point2i step = Vector2(SGN(dir.x), SGN(dir.y));
-
- Vector2 max;
-
- if (dir.x < 0) {
- max.x = (Math::floor((double)pos.x) * cell_size - p_from.x) / dir.x;
- } else {
- max.x = (Math::floor((double)pos.x + 1) * cell_size - p_from.x) / dir.x;
- }
-
- if (dir.y < 0) {
- max.y = (Math::floor((double)pos.y) * cell_size - p_from.y) / dir.y;
- } else {
- max.y = (Math::floor((double)pos.y + 1) * cell_size - p_from.y) / dir.y;
- }
-
- int cullcount = 0;
- _cull<false, true>(pos, Rect2(), p_from, p_to, p_results, p_max_results, p_result_indices, cullcount);
-
- bool reached_x = false;
- bool reached_y = false;
-
- while (true) {
- if (max.x < max.y) {
- max.x += delta.x;
- pos.x += step.x;
- } else {
- max.y += delta.y;
- pos.y += step.y;
- }
-
- if (step.x > 0) {
- if (pos.x >= end.x) {
- reached_x = true;
- }
- } else if (pos.x <= end.x) {
- reached_x = true;
- }
-
- if (step.y > 0) {
- if (pos.y >= end.y) {
- reached_y = true;
- }
- } else if (pos.y <= end.y) {
- reached_y = true;
- }
-
- _cull<false, true>(pos, Rect2(), p_from, p_to, p_results, p_max_results, p_result_indices, cullcount);
-
- if (reached_x && reached_y) {
- break;
- }
- }
-
- for (Map<Element *, RC>::Element *E = large_elements.front(); E; E = E->next()) {
- if (cullcount >= p_max_results) {
- break;
- }
- if (E->key()->pass == pass) {
- continue;
- }
-
- E->key()->pass = pass;
-
- /*
- if (use_aabb && !p_aabb.intersects(E->key()->aabb))
- continue;
- */
-
- if (!E->key()->aabb.intersects_segment(p_from, p_to)) {
- continue;
- }
-
- p_results[cullcount] = E->key()->owner;
- p_result_indices[cullcount] = E->key()->subindex;
- cullcount++;
- }
-
- return cullcount;
-}
-
-int BroadPhase2DHashGrid::cull_aabb(const Rect2 &p_aabb, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices) {
- pass++;
-
- Point2i from = (p_aabb.position / cell_size).floor();
- Point2i to = ((p_aabb.position + p_aabb.size) / cell_size).floor();
- int cullcount = 0;
-
- for (int i = from.x; i <= to.x; i++) {
- for (int j = from.y; j <= to.y; j++) {
- _cull<true, false>(Point2i(i, j), p_aabb, Point2(), Point2(), p_results, p_max_results, p_result_indices, cullcount);
- }
- }
-
- for (Map<Element *, RC>::Element *E = large_elements.front(); E; E = E->next()) {
- if (cullcount >= p_max_results) {
- break;
- }
- if (E->key()->pass == pass) {
- continue;
- }
-
- E->key()->pass = pass;
-
- if (!p_aabb.intersects(E->key()->aabb)) {
- continue;
- }
-
- /*
- if (!E->key()->aabb.intersects_segment(p_from,p_to))
- continue;
- */
-
- p_results[cullcount] = E->key()->owner;
- p_result_indices[cullcount] = E->key()->subindex;
- cullcount++;
- }
- return cullcount;
-}
-
-void BroadPhase2DHashGrid::set_pair_callback(PairCallback p_pair_callback, void *p_userdata) {
- pair_callback = p_pair_callback;
- pair_userdata = p_userdata;
-}
-
-void BroadPhase2DHashGrid::set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) {
- unpair_callback = p_unpair_callback;
- unpair_userdata = p_userdata;
-}
-
-void BroadPhase2DHashGrid::update() {
-}
-
-BroadPhase2DSW *BroadPhase2DHashGrid::_create() {
- return memnew(BroadPhase2DHashGrid);
-}
-
-BroadPhase2DHashGrid::BroadPhase2DHashGrid() {
- hash_table_size = GLOBAL_DEF("physics/2d/bp_hash_table_size", 4096);
- ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/bp_hash_table_size", PropertyInfo(Variant::INT, "physics/2d/bp_hash_table_size", PROPERTY_HINT_RANGE, "0,8192,1,or_greater"));
- hash_table_size = Math::larger_prime(hash_table_size);
- hash_table = memnew_arr(PosBin *, hash_table_size);
-
- cell_size = GLOBAL_DEF("physics/2d/cell_size", 128);
- ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/cell_size", PropertyInfo(Variant::INT, "physics/2d/cell_size", PROPERTY_HINT_RANGE, "0,512,1,or_greater"));
-
- large_object_min_surface = GLOBAL_DEF("physics/2d/large_object_surface_threshold_in_cells", 512);
- ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/large_object_surface_threshold_in_cells", PropertyInfo(Variant::INT, "physics/2d/large_object_surface_threshold_in_cells", PROPERTY_HINT_RANGE, "0,1024,1,or_greater"));
-
- for (uint32_t i = 0; i < hash_table_size; i++) {
- hash_table[i] = nullptr;
- }
- pass = 1;
-
- current = 0;
-}
-
-BroadPhase2DHashGrid::~BroadPhase2DHashGrid() {
- for (uint32_t i = 0; i < hash_table_size; i++) {
- while (hash_table[i]) {
- PosBin *pb = hash_table[i];
- hash_table[i] = pb->next;
- memdelete(pb);
- }
- }
-
- memdelete_arr(hash_table);
-}
-
-/* 3D version of voxel traversal:
-
-public IEnumerable<Point3D> GetCellsOnRay(Ray ray, int maxDepth)
-{
- // Implementation is based on:
- // "A Fast Voxel Traversal Algorithm for Ray Tracing"
- // John Amanatides, Andrew Woo
- // http://www.cse.yorku.ca/~amana/research/grid.pdf
- // https://web.archive.org/web/20100616193049/http://www.devmaster.net/articles/raytracing_series/A%20faster%20voxel%20traversal%20algorithm%20for%20ray%20tracing.pdf
-
- // NOTES:
- // * This code assumes that the ray's position and direction are in 'cell coordinates', which means
- // that one unit equals one cell in all directions.
- // * When the ray doesn't start within the voxel grid, calculate the first position at which the
- // ray could enter the grid. If it never enters the grid, there is nothing more to do here.
- // * Also, it is important to test when the ray exits the voxel grid when the grid isn't infinite.
- // * The Point3D structure is a simple structure having three integer fields (X, Y and Z).
-
- // The cell in which the ray starts.
- Point3D start = GetCellAt(ray.Position); // Rounds the position's X, Y and Z down to the nearest integer values.
- int x = start.X;
- int y = start.Y;
- int z = start.Z;
-
- // Determine which way we go.
- int stepX = Math.Sign(ray.Direction.X);
- int stepY = Math.Sign(ray.Direction.Y);
- int stepZ = Math.Sign(ray.Direction.Z);
-
- // Calculate cell boundaries. When the step (i.e. direction sign) is positive,
- // the next boundary is AFTER our current position, meaning that we have to add 1.
- // Otherwise, it is BEFORE our current position, in which case we add nothing.
- Point3D cellBoundary = new Point3D(
- x + (stepX > 0 ? 1 : 0),
- y + (stepY > 0 ? 1 : 0),
- z + (stepZ > 0 ? 1 : 0));
-
- // NOTE: For the following calculations, the result will be Single.PositiveInfinity
- // when ray.Direction.X, Y or Z equals zero, which is OK. However, when the left-hand
- // value of the division also equals zero, the result is Single.NaN, which is not OK.
-
- // Determine how far we can travel along the ray before we hit a voxel boundary.
- Vector3 tMax = new Vector3(
- (cellBoundary.X - ray.Position.X) / ray.Direction.X, // Boundary is a plane on the YZ axis.
- (cellBoundary.Y - ray.Position.Y) / ray.Direction.Y, // Boundary is a plane on the XZ axis.
- (cellBoundary.Z - ray.Position.Z) / ray.Direction.Z); // Boundary is a plane on the XY axis.
- if (Single.IsNaN(tMax.X)) tMax.X = Single.PositiveInfinity;
- if (Single.IsNaN(tMax.Y)) tMax.Y = Single.PositiveInfinity;
- if (Single.IsNaN(tMax.Z)) tMax.Z = Single.PositiveInfinity;
-
- // Determine how far we must travel along the ray before we have crossed a gridcell.
- Vector3 tDelta = new Vector3(
- stepX / ray.Direction.X, // Crossing the width of a cell.
- stepY / ray.Direction.Y, // Crossing the height of a cell.
- stepZ / ray.Direction.Z); // Crossing the depth of a cell.
- if (Single.IsNaN(tDelta.X)) tDelta.X = Single.PositiveInfinity;
- if (Single.IsNaN(tDelta.Y)) tDelta.Y = Single.PositiveInfinity;
- if (Single.IsNaN(tDelta.Z)) tDelta.Z = Single.PositiveInfinity;
-
- // For each step, determine which distance to the next voxel boundary is lowest (i.e.
- // which voxel boundary is nearest) and walk that way.
- for (int i = 0; i < maxDepth; i++)
- {
- // Return it.
- yield return new Point3D(x, y, z);
-
- // Do the next step.
- if (tMax.X < tMax.Y && tMax.X < tMax.Z)
- {
- // tMax.X is the lowest, an YZ cell boundary plane is nearest.
- x += stepX;
- tMax.X += tDelta.X;
- }
- else if (tMax.Y < tMax.Z)
- {
- // tMax.Y is the lowest, an XZ cell boundary plane is nearest.
- y += stepY;
- tMax.Y += tDelta.Y;
- }
- else
- {
- // tMax.Z is the lowest, an XY cell boundary plane is nearest.
- z += stepZ;
- tMax.Z += tDelta.Z;
- }
- }
-
- */
diff --git a/servers/physics_2d/broad_phase_2d_hash_grid.h b/servers/physics_2d/broad_phase_2d_hash_grid.h
deleted file mode 100644
index eb7c8879ac..0000000000
--- a/servers/physics_2d/broad_phase_2d_hash_grid.h
+++ /dev/null
@@ -1,187 +0,0 @@
-/*************************************************************************/
-/* broad_phase_2d_hash_grid.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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 BROAD_PHASE_2D_HASH_GRID_H
-#define BROAD_PHASE_2D_HASH_GRID_H
-
-#include "broad_phase_2d_sw.h"
-#include "core/templates/map.h"
-
-class BroadPhase2DHashGrid : public BroadPhase2DSW {
- struct PairData {
- bool colliding;
- int rc;
- void *ud;
- PairData() {
- colliding = false;
- rc = 1;
- ud = nullptr;
- }
- };
-
- struct Element {
- ID self;
- CollisionObject2DSW *owner;
- bool _static;
- Rect2 aabb;
- int subindex;
- uint64_t pass;
- Map<Element *, PairData *> paired;
- };
-
- struct RC {
- int ref;
-
- _FORCE_INLINE_ int inc() {
- ref++;
- return ref;
- }
- _FORCE_INLINE_ int dec() {
- ref--;
- return ref;
- }
-
- _FORCE_INLINE_ RC() {
- ref = 0;
- }
- };
-
- Map<ID, Element> element_map;
- Map<Element *, RC> large_elements;
-
- ID current;
-
- uint64_t pass;
-
- struct PairKey {
- union {
- struct {
- ID a;
- ID b;
- };
- uint64_t key;
- };
-
- _FORCE_INLINE_ bool operator<(const PairKey &p_key) const {
- return key < p_key.key;
- }
-
- PairKey() { key = 0; }
- PairKey(ID p_a, ID p_b) {
- if (p_a > p_b) {
- a = p_b;
- b = p_a;
- } else {
- a = p_a;
- b = p_b;
- }
- }
- };
-
- Map<PairKey, PairData> pair_map;
-
- int cell_size;
- int large_object_min_surface;
-
- PairCallback pair_callback;
- void *pair_userdata;
- UnpairCallback unpair_callback;
- void *unpair_userdata;
-
- void _enter_grid(Element *p_elem, const Rect2 &p_rect, bool p_static);
- void _exit_grid(Element *p_elem, const Rect2 &p_rect, bool p_static);
- template <bool use_aabb, bool use_segment>
- _FORCE_INLINE_ void _cull(const Point2i p_cell, const Rect2 &p_aabb, const Point2 &p_from, const Point2 &p_to, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices, int &index);
-
- struct PosKey {
- union {
- struct {
- int32_t x;
- int32_t y;
- };
- uint64_t key;
- };
-
- _FORCE_INLINE_ uint32_t hash() const {
- uint64_t k = key;
- k = (~k) + (k << 18); // k = (k << 18) - k - 1;
- k = k ^ (k >> 31);
- k = k * 21; // k = (k + (k << 2)) + (k << 4);
- k = k ^ (k >> 11);
- k = k + (k << 6);
- k = k ^ (k >> 22);
- return k;
- }
-
- bool operator==(const PosKey &p_key) const { return key == p_key.key; }
- _FORCE_INLINE_ bool operator<(const PosKey &p_key) const {
- return key < p_key.key;
- }
- };
-
- struct PosBin {
- PosKey key;
- Map<Element *, RC> object_set;
- Map<Element *, RC> static_object_set;
- PosBin *next;
- };
-
- uint32_t hash_table_size;
- PosBin **hash_table;
-
- void _pair_attempt(Element *p_elem, Element *p_with);
- void _unpair_attempt(Element *p_elem, Element *p_with);
- void _check_motion(Element *p_elem);
-
-public:
- virtual ID create(CollisionObject2DSW *p_object, int p_subindex = 0);
- virtual void move(ID p_id, const Rect2 &p_aabb);
- virtual void set_static(ID p_id, bool p_static);
- virtual void remove(ID p_id);
-
- virtual CollisionObject2DSW *get_object(ID p_id) const;
- virtual bool is_static(ID p_id) const;
- virtual int get_subindex(ID p_id) const;
-
- virtual int cull_segment(const Vector2 &p_from, const Vector2 &p_to, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices = nullptr);
- virtual int cull_aabb(const Rect2 &p_aabb, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices = nullptr);
-
- virtual void set_pair_callback(PairCallback p_pair_callback, void *p_userdata);
- virtual void set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata);
-
- virtual void update();
-
- static BroadPhase2DSW *_create();
-
- BroadPhase2DHashGrid();
- ~BroadPhase2DHashGrid();
-};
-
-#endif // BROAD_PHASE_2D_HASH_GRID_H
diff --git a/servers/physics_2d/godot_area_2d.cpp b/servers/physics_2d/godot_area_2d.cpp
new file mode 100644
index 0000000000..11208f2d5b
--- /dev/null
+++ b/servers/physics_2d/godot_area_2d.cpp
@@ -0,0 +1,325 @@
+/*************************************************************************/
+/* godot_area_2d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 "godot_area_2d.h"
+#include "godot_body_2d.h"
+#include "godot_space_2d.h"
+
+GodotArea2D::BodyKey::BodyKey(GodotBody2D *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {
+ rid = p_body->get_self();
+ instance_id = p_body->get_instance_id();
+ body_shape = p_body_shape;
+ area_shape = p_area_shape;
+}
+
+GodotArea2D::BodyKey::BodyKey(GodotArea2D *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {
+ rid = p_body->get_self();
+ instance_id = p_body->get_instance_id();
+ body_shape = p_body_shape;
+ area_shape = p_area_shape;
+}
+
+void GodotArea2D::_shapes_changed() {
+ if (!moved_list.in_list() && get_space()) {
+ get_space()->area_add_to_moved_list(&moved_list);
+ }
+}
+
+void GodotArea2D::set_transform(const Transform2D &p_transform) {
+ if (!moved_list.in_list() && get_space()) {
+ get_space()->area_add_to_moved_list(&moved_list);
+ }
+
+ _set_transform(p_transform);
+ _set_inv_transform(p_transform.affine_inverse());
+}
+
+void GodotArea2D::set_space(GodotSpace2D *p_space) {
+ if (get_space()) {
+ if (monitor_query_list.in_list()) {
+ get_space()->area_remove_from_monitor_query_list(&monitor_query_list);
+ }
+ if (moved_list.in_list()) {
+ get_space()->area_remove_from_moved_list(&moved_list);
+ }
+ }
+
+ monitored_bodies.clear();
+ monitored_areas.clear();
+
+ _set_space(p_space);
+}
+
+void GodotArea2D::set_monitor_callback(const Callable &p_callback) {
+ ObjectID id = p_callback.get_object_id();
+
+ if (id == monitor_callback.get_object_id()) {
+ monitor_callback = p_callback;
+ return;
+ }
+
+ _unregister_shapes();
+
+ monitor_callback = p_callback;
+
+ monitored_bodies.clear();
+ monitored_areas.clear();
+
+ _shape_changed();
+
+ if (!moved_list.in_list() && get_space()) {
+ get_space()->area_add_to_moved_list(&moved_list);
+ }
+}
+
+void GodotArea2D::set_area_monitor_callback(const Callable &p_callback) {
+ ObjectID id = p_callback.get_object_id();
+
+ if (id == area_monitor_callback.get_object_id()) {
+ area_monitor_callback = p_callback;
+ return;
+ }
+
+ _unregister_shapes();
+
+ area_monitor_callback = p_callback;
+
+ monitored_bodies.clear();
+ monitored_areas.clear();
+
+ _shape_changed();
+
+ if (!moved_list.in_list() && get_space()) {
+ get_space()->area_add_to_moved_list(&moved_list);
+ }
+}
+
+void GodotArea2D::_set_space_override_mode(PhysicsServer2D::AreaSpaceOverrideMode &r_mode, PhysicsServer2D::AreaSpaceOverrideMode p_new_mode) {
+ bool do_override = p_new_mode != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED;
+ if (do_override == (r_mode != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED)) {
+ return;
+ }
+ _unregister_shapes();
+ r_mode = p_new_mode;
+ _shape_changed();
+}
+
+void GodotArea2D::set_param(PhysicsServer2D::AreaParameter p_param, const Variant &p_value) {
+ switch (p_param) {
+ case PhysicsServer2D::AREA_PARAM_GRAVITY_OVERRIDE_MODE:
+ _set_space_override_mode(gravity_override_mode, (PhysicsServer2D::AreaSpaceOverrideMode)(int)p_value);
+ break;
+ case PhysicsServer2D::AREA_PARAM_GRAVITY:
+ gravity = p_value;
+ break;
+ case PhysicsServer2D::AREA_PARAM_GRAVITY_VECTOR:
+ gravity_vector = p_value;
+ break;
+ case PhysicsServer2D::AREA_PARAM_GRAVITY_IS_POINT:
+ gravity_is_point = p_value;
+ break;
+ case PhysicsServer2D::AREA_PARAM_GRAVITY_DISTANCE_SCALE:
+ gravity_distance_scale = p_value;
+ break;
+ case PhysicsServer2D::AREA_PARAM_GRAVITY_POINT_ATTENUATION:
+ point_attenuation = p_value;
+ break;
+ case PhysicsServer2D::AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE:
+ _set_space_override_mode(linear_damping_override_mode, (PhysicsServer2D::AreaSpaceOverrideMode)(int)p_value);
+ break;
+ case PhysicsServer2D::AREA_PARAM_LINEAR_DAMP:
+ linear_damp = p_value;
+ break;
+ case PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP_OVERRIDE_MODE:
+ _set_space_override_mode(angular_damping_override_mode, (PhysicsServer2D::AreaSpaceOverrideMode)(int)p_value);
+ break;
+ case PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP:
+ angular_damp = p_value;
+ break;
+ case PhysicsServer2D::AREA_PARAM_PRIORITY:
+ priority = p_value;
+ break;
+ }
+}
+
+Variant GodotArea2D::get_param(PhysicsServer2D::AreaParameter p_param) const {
+ switch (p_param) {
+ case PhysicsServer2D::AREA_PARAM_GRAVITY_OVERRIDE_MODE:
+ return gravity_override_mode;
+ case PhysicsServer2D::AREA_PARAM_GRAVITY:
+ return gravity;
+ case PhysicsServer2D::AREA_PARAM_GRAVITY_VECTOR:
+ return gravity_vector;
+ case PhysicsServer2D::AREA_PARAM_GRAVITY_IS_POINT:
+ return gravity_is_point;
+ case PhysicsServer2D::AREA_PARAM_GRAVITY_DISTANCE_SCALE:
+ return gravity_distance_scale;
+ case PhysicsServer2D::AREA_PARAM_GRAVITY_POINT_ATTENUATION:
+ return point_attenuation;
+ case PhysicsServer2D::AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE:
+ return linear_damping_override_mode;
+ case PhysicsServer2D::AREA_PARAM_LINEAR_DAMP:
+ return linear_damp;
+ case PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP_OVERRIDE_MODE:
+ return angular_damping_override_mode;
+ case PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP:
+ return angular_damp;
+ case PhysicsServer2D::AREA_PARAM_PRIORITY:
+ return priority;
+ }
+
+ return Variant();
+}
+
+void GodotArea2D::_queue_monitor_update() {
+ ERR_FAIL_COND(!get_space());
+
+ if (!monitor_query_list.in_list()) {
+ get_space()->area_add_to_monitor_query_list(&monitor_query_list);
+ }
+}
+
+void GodotArea2D::set_monitorable(bool p_monitorable) {
+ if (monitorable == p_monitorable) {
+ return;
+ }
+
+ monitorable = p_monitorable;
+ _set_static(!monitorable);
+ _shapes_changed();
+}
+
+void GodotArea2D::call_queries() {
+ if (!monitor_callback.is_null() && !monitored_bodies.is_empty()) {
+ if (monitor_callback.is_valid()) {
+ Variant res[5];
+ Variant *resptr[5];
+ for (int i = 0; i < 5; i++) {
+ resptr[i] = &res[i];
+ }
+
+ for (HashMap<BodyKey, BodyState, BodyKey>::Iterator E = monitored_bodies.begin(); E;) {
+ if (E->value.state == 0) { // Nothing happened
+ HashMap<BodyKey, BodyState, BodyKey>::Iterator next = E;
+ ++next;
+ monitored_bodies.remove(E);
+ E = next;
+ continue;
+ }
+
+ res[0] = E->value.state > 0 ? PhysicsServer2D::AREA_BODY_ADDED : PhysicsServer2D::AREA_BODY_REMOVED;
+ res[1] = E->key.rid;
+ res[2] = E->key.instance_id;
+ res[3] = E->key.body_shape;
+ res[4] = E->key.area_shape;
+
+ HashMap<BodyKey, BodyState, BodyKey>::Iterator next = E;
+ ++next;
+ monitored_bodies.remove(E);
+ E = next;
+
+ Callable::CallError ce;
+ Variant ret;
+ monitor_callback.call((const Variant **)resptr, 5, ret, ce);
+ }
+ } else {
+ monitored_bodies.clear();
+ monitor_callback = Callable();
+ }
+ }
+
+ if (!area_monitor_callback.is_null() && !monitored_areas.is_empty()) {
+ if (area_monitor_callback.is_valid()) {
+ Variant res[5];
+ Variant *resptr[5];
+ for (int i = 0; i < 5; i++) {
+ resptr[i] = &res[i];
+ }
+
+ for (HashMap<BodyKey, BodyState, BodyKey>::Iterator E = monitored_areas.begin(); E;) {
+ if (E->value.state == 0) { // Nothing happened
+ HashMap<BodyKey, BodyState, BodyKey>::Iterator next = E;
+ ++next;
+ monitored_areas.remove(E);
+ E = next;
+ continue;
+ }
+
+ res[0] = E->value.state > 0 ? PhysicsServer2D::AREA_BODY_ADDED : PhysicsServer2D::AREA_BODY_REMOVED;
+ res[1] = E->key.rid;
+ res[2] = E->key.instance_id;
+ res[3] = E->key.body_shape;
+ res[4] = E->key.area_shape;
+
+ HashMap<BodyKey, BodyState, BodyKey>::Iterator next = E;
+ ++next;
+ monitored_areas.remove(E);
+ E = next;
+
+ Callable::CallError ce;
+ Variant ret;
+ area_monitor_callback.call((const Variant **)resptr, 5, ret, ce);
+ }
+ } else {
+ monitored_areas.clear();
+ area_monitor_callback = Callable();
+ }
+ }
+}
+
+void GodotArea2D::compute_gravity(const Vector2 &p_position, Vector2 &r_gravity) const {
+ if (is_gravity_point()) {
+ const real_t gravity_distance_scale = get_gravity_distance_scale();
+ Vector2 v = get_transform().xform(get_gravity_vector()) - p_position;
+ if (gravity_distance_scale > 0) {
+ const real_t v_length = v.length();
+ if (v_length > 0) {
+ const real_t v_scaled = v_length * gravity_distance_scale;
+ r_gravity = (v.normalized() * (get_gravity() / (v_scaled * v_scaled)));
+ } else {
+ r_gravity = Vector2();
+ }
+ } else {
+ r_gravity = v.normalized() * get_gravity();
+ }
+ } else {
+ r_gravity = get_gravity_vector() * get_gravity();
+ }
+}
+
+GodotArea2D::GodotArea2D() :
+ GodotCollisionObject2D(TYPE_AREA),
+ monitor_query_list(this),
+ moved_list(this) {
+ _set_static(true); //areas are not active by default
+}
+
+GodotArea2D::~GodotArea2D() {
+}
diff --git a/servers/physics_2d/area_2d_sw.h b/servers/physics_2d/godot_area_2d.h
index 3bf603b30d..221982cf78 100644
--- a/servers/physics_2d/area_2d_sw.h
+++ b/servers/physics_2d/godot_area_2d.h
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* area_2d_sw.h */
+/* godot_area_2d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -28,101 +28,94 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef AREA_2D_SW_H
-#define AREA_2D_SW_H
+#ifndef GODOT_AREA_2D_H
+#define GODOT_AREA_2D_H
+
+#include "godot_collision_object_2d.h"
-#include "collision_object_2d_sw.h"
#include "core/templates/self_list.h"
#include "servers/physics_server_2d.h"
-//#include "servers/physics_3d/query_sw.h"
-class Space2DSW;
-class Body2DSW;
-class Constraint2DSW;
+class GodotSpace2D;
+class GodotBody2D;
+class GodotConstraint2D;
+
+class GodotArea2D : public GodotCollisionObject2D {
+ PhysicsServer2D::AreaSpaceOverrideMode gravity_override_mode = PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED;
+ PhysicsServer2D::AreaSpaceOverrideMode linear_damping_override_mode = PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED;
+ PhysicsServer2D::AreaSpaceOverrideMode angular_damping_override_mode = PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED;
-class Area2DSW : public CollisionObject2DSW {
- PhysicsServer2D::AreaSpaceOverrideMode space_override_mode;
- real_t gravity;
- Vector2 gravity_vector;
- bool gravity_is_point;
- real_t gravity_distance_scale;
- real_t point_attenuation;
- real_t linear_damp;
- real_t angular_damp;
- int priority;
- bool monitorable;
+ real_t gravity = 9.80665;
+ Vector2 gravity_vector = Vector2(0, -1);
+ bool gravity_is_point = false;
+ real_t gravity_distance_scale = 0.0;
+ real_t point_attenuation = 1.0;
+ real_t linear_damp = 0.1;
+ real_t angular_damp = 1.0;
+ int priority = 0;
+ bool monitorable = false;
- ObjectID monitor_callback_id;
- StringName monitor_callback_method;
+ Callable monitor_callback;
- ObjectID area_monitor_callback_id;
- StringName area_monitor_callback_method;
+ Callable area_monitor_callback;
- SelfList<Area2DSW> monitor_query_list;
- SelfList<Area2DSW> moved_list;
+ SelfList<GodotArea2D> monitor_query_list;
+ SelfList<GodotArea2D> moved_list;
struct BodyKey {
RID rid;
ObjectID instance_id;
- uint32_t body_shape;
- uint32_t area_shape;
-
- _FORCE_INLINE_ bool operator<(const BodyKey &p_key) const {
- if (rid == p_key.rid) {
- if (body_shape == p_key.body_shape) {
- return area_shape < p_key.area_shape;
- } else {
- return body_shape < p_key.body_shape;
- }
- } else {
- return rid < p_key.rid;
- }
+ uint32_t body_shape = 0;
+ uint32_t area_shape = 0;
+
+ static uint32_t hash(const BodyKey &p_key) {
+ uint32_t h = hash_one_uint64(p_key.rid.get_id());
+ h = hash_murmur3_one_64(p_key.instance_id, h);
+ h = hash_murmur3_one_32(p_key.area_shape, h);
+ return hash_fmix32(hash_murmur3_one_32(p_key.body_shape, h));
+ }
+
+ _FORCE_INLINE_ bool operator==(const BodyKey &p_key) const {
+ return rid == p_key.rid && instance_id == p_key.instance_id && body_shape == p_key.body_shape && area_shape == p_key.area_shape;
}
_FORCE_INLINE_ BodyKey() {}
- BodyKey(Body2DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
- BodyKey(Area2DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
+ BodyKey(GodotBody2D *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
+ BodyKey(GodotArea2D *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
};
struct BodyState {
- int state;
+ int state = 0;
_FORCE_INLINE_ void inc() { state++; }
_FORCE_INLINE_ void dec() { state--; }
- _FORCE_INLINE_ BodyState() { state = 0; }
};
- Map<BodyKey, BodyState> monitored_bodies;
- Map<BodyKey, BodyState> monitored_areas;
+ HashMap<BodyKey, BodyState, BodyKey> monitored_bodies;
+ HashMap<BodyKey, BodyState, BodyKey> monitored_areas;
- //virtual void shape_changed_notify(Shape2DSW *p_shape);
- //virtual void shape_deleted_notify(Shape2DSW *p_shape);
- Set<Constraint2DSW *> constraints;
+ HashSet<GodotConstraint2D *> constraints;
- virtual void _shapes_changed();
+ virtual void _shapes_changed() override;
void _queue_monitor_update();
-public:
- //_FORCE_INLINE_ const Matrix32& get_inverse_transform() const { return inverse_transform; }
- //_FORCE_INLINE_ SpaceSW* get_owner() { return owner; }
+ void _set_space_override_mode(PhysicsServer2D::AreaSpaceOverrideMode &r_mode, PhysicsServer2D::AreaSpaceOverrideMode p_new_mode);
- void set_monitor_callback(ObjectID p_id, const StringName &p_method);
- _FORCE_INLINE_ bool has_monitor_callback() const { return monitor_callback_id.is_valid(); }
+public:
+ void set_monitor_callback(const Callable &p_callback);
+ _FORCE_INLINE_ bool has_monitor_callback() const { return !monitor_callback.is_null(); }
- void set_area_monitor_callback(ObjectID p_id, const StringName &p_method);
- _FORCE_INLINE_ bool has_area_monitor_callback() const { return area_monitor_callback_id.is_valid(); }
+ void set_area_monitor_callback(const Callable &p_callback);
+ _FORCE_INLINE_ bool has_area_monitor_callback() const { return !area_monitor_callback.is_null(); }
- _FORCE_INLINE_ void add_body_to_query(Body2DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
- _FORCE_INLINE_ void remove_body_from_query(Body2DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
+ _FORCE_INLINE_ void add_body_to_query(GodotBody2D *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
+ _FORCE_INLINE_ void remove_body_from_query(GodotBody2D *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
- _FORCE_INLINE_ void add_area_to_query(Area2DSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape);
- _FORCE_INLINE_ void remove_area_from_query(Area2DSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape);
+ _FORCE_INLINE_ void add_area_to_query(GodotArea2D *p_area, uint32_t p_area_shape, uint32_t p_self_shape);
+ _FORCE_INLINE_ void remove_area_from_query(GodotArea2D *p_area, uint32_t p_area_shape, uint32_t p_self_shape);
void set_param(PhysicsServer2D::AreaParameter p_param, const Variant &p_value);
Variant get_param(PhysicsServer2D::AreaParameter p_param) const;
- void set_space_override_mode(PhysicsServer2D::AreaSpaceOverrideMode p_mode);
- PhysicsServer2D::AreaSpaceOverrideMode get_space_override_mode() const { return space_override_mode; }
-
_FORCE_INLINE_ void set_gravity(real_t p_gravity) { gravity = p_gravity; }
_FORCE_INLINE_ real_t get_gravity() const { return gravity; }
@@ -147,9 +140,9 @@ public:
_FORCE_INLINE_ void set_priority(int p_priority) { priority = p_priority; }
_FORCE_INLINE_ int get_priority() const { return priority; }
- _FORCE_INLINE_ void add_constraint(Constraint2DSW *p_constraint) { constraints.insert(p_constraint); }
- _FORCE_INLINE_ void remove_constraint(Constraint2DSW *p_constraint) { constraints.erase(p_constraint); }
- _FORCE_INLINE_ const Set<Constraint2DSW *> &get_constraints() const { return constraints; }
+ _FORCE_INLINE_ void add_constraint(GodotConstraint2D *p_constraint) { constraints.insert(p_constraint); }
+ _FORCE_INLINE_ void remove_constraint(GodotConstraint2D *p_constraint) { constraints.erase(p_constraint); }
+ _FORCE_INLINE_ const HashSet<GodotConstraint2D *> &get_constraints() const { return constraints; }
_FORCE_INLINE_ void clear_constraints() { constraints.clear(); }
void set_monitorable(bool p_monitorable);
@@ -157,15 +150,17 @@ public:
void set_transform(const Transform2D &p_transform);
- void set_space(Space2DSW *p_space);
+ void set_space(GodotSpace2D *p_space) override;
void call_queries();
- Area2DSW();
- ~Area2DSW();
+ void compute_gravity(const Vector2 &p_position, Vector2 &r_gravity) const;
+
+ GodotArea2D();
+ ~GodotArea2D();
};
-void Area2DSW::add_body_to_query(Body2DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {
+void GodotArea2D::add_body_to_query(GodotBody2D *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {
BodyKey bk(p_body, p_body_shape, p_area_shape);
monitored_bodies[bk].inc();
if (!monitor_query_list.in_list()) {
@@ -173,7 +168,7 @@ void Area2DSW::add_body_to_query(Body2DSW *p_body, uint32_t p_body_shape, uint32
}
}
-void Area2DSW::remove_body_from_query(Body2DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {
+void GodotArea2D::remove_body_from_query(GodotBody2D *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {
BodyKey bk(p_body, p_body_shape, p_area_shape);
monitored_bodies[bk].dec();
if (!monitor_query_list.in_list()) {
@@ -181,7 +176,7 @@ void Area2DSW::remove_body_from_query(Body2DSW *p_body, uint32_t p_body_shape, u
}
}
-void Area2DSW::add_area_to_query(Area2DSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape) {
+void GodotArea2D::add_area_to_query(GodotArea2D *p_area, uint32_t p_area_shape, uint32_t p_self_shape) {
BodyKey bk(p_area, p_area_shape, p_self_shape);
monitored_areas[bk].inc();
if (!monitor_query_list.in_list()) {
@@ -189,7 +184,7 @@ void Area2DSW::add_area_to_query(Area2DSW *p_area, uint32_t p_area_shape, uint32
}
}
-void Area2DSW::remove_area_from_query(Area2DSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape) {
+void GodotArea2D::remove_area_from_query(GodotArea2D *p_area, uint32_t p_area_shape, uint32_t p_self_shape) {
BodyKey bk(p_area, p_area_shape, p_self_shape);
monitored_areas[bk].dec();
if (!monitor_query_list.in_list()) {
@@ -197,4 +192,4 @@ void Area2DSW::remove_area_from_query(Area2DSW *p_area, uint32_t p_area_shape, u
}
}
-#endif // AREA_2D_SW_H
+#endif // GODOT_AREA_2D_H
diff --git a/servers/physics_2d/godot_area_pair_2d.cpp b/servers/physics_2d/godot_area_pair_2d.cpp
new file mode 100644
index 0000000000..72208d7dff
--- /dev/null
+++ b/servers/physics_2d/godot_area_pair_2d.cpp
@@ -0,0 +1,200 @@
+/*************************************************************************/
+/* godot_area_pair_2d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 "godot_area_pair_2d.h"
+#include "godot_collision_solver_2d.h"
+
+bool GodotAreaPair2D::setup(real_t p_step) {
+ bool result = false;
+ if (area->collides_with(body) && GodotCollisionSolver2D::solve(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), Vector2(), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), Vector2(), nullptr, this)) {
+ result = true;
+ }
+
+ process_collision = false;
+ has_space_override = false;
+ if (result != colliding) {
+ if ((int)area->get_param(PhysicsServer2D::AREA_PARAM_GRAVITY_OVERRIDE_MODE) != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) {
+ has_space_override = true;
+ } else if ((int)area->get_param(PhysicsServer2D::AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE) != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) {
+ has_space_override = true;
+ } else if ((int)area->get_param(PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP_OVERRIDE_MODE) != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) {
+ has_space_override = true;
+ }
+ process_collision = has_space_override;
+
+ if (area->has_monitor_callback()) {
+ process_collision = true;
+ }
+
+ colliding = result;
+ }
+
+ return process_collision;
+}
+
+bool GodotAreaPair2D::pre_solve(real_t p_step) {
+ if (!process_collision) {
+ return false;
+ }
+
+ if (colliding) {
+ if (has_space_override) {
+ body->add_area(area);
+ }
+
+ if (area->has_monitor_callback()) {
+ area->add_body_to_query(body, body_shape, area_shape);
+ }
+ } else {
+ if (has_space_override) {
+ body->remove_area(area);
+ }
+
+ if (area->has_monitor_callback()) {
+ area->remove_body_from_query(body, body_shape, area_shape);
+ }
+ }
+
+ return false; // Never do any post solving.
+}
+
+void GodotAreaPair2D::solve(real_t p_step) {
+ // Nothing to do.
+}
+
+GodotAreaPair2D::GodotAreaPair2D(GodotBody2D *p_body, int p_body_shape, GodotArea2D *p_area, int p_area_shape) {
+ body = p_body;
+ area = p_area;
+ body_shape = p_body_shape;
+ area_shape = p_area_shape;
+ body->add_constraint(this, 0);
+ area->add_constraint(this);
+ if (p_body->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) { //need to be active to process pair
+ p_body->set_active(true);
+ }
+}
+
+GodotAreaPair2D::~GodotAreaPair2D() {
+ if (colliding) {
+ if (has_space_override) {
+ body->remove_area(area);
+ }
+ if (area->has_monitor_callback()) {
+ area->remove_body_from_query(body, body_shape, area_shape);
+ }
+ }
+ body->remove_constraint(this, 0);
+ area->remove_constraint(this);
+}
+
+//////////////////////////////////
+
+bool GodotArea2Pair2D::setup(real_t p_step) {
+ bool result_a = area_a->collides_with(area_b);
+ bool result_b = area_b->collides_with(area_a);
+ if ((result_a || result_b) && !GodotCollisionSolver2D::solve(area_a->get_shape(shape_a), area_a->get_transform() * area_a->get_shape_transform(shape_a), Vector2(), area_b->get_shape(shape_b), area_b->get_transform() * area_b->get_shape_transform(shape_b), Vector2(), nullptr, this)) {
+ result_a = false;
+ result_b = false;
+ }
+
+ bool process_collision = false;
+
+ process_collision_a = false;
+ if (result_a != colliding_a) {
+ if (area_a->has_area_monitor_callback() && area_b_monitorable) {
+ process_collision_a = true;
+ process_collision = true;
+ }
+ colliding_a = result_a;
+ }
+
+ process_collision_b = false;
+ if (result_b != colliding_b) {
+ if (area_b->has_area_monitor_callback() && area_a_monitorable) {
+ process_collision_b = true;
+ process_collision = true;
+ }
+ colliding_b = result_b;
+ }
+
+ return process_collision;
+}
+
+bool GodotArea2Pair2D::pre_solve(real_t p_step) {
+ if (process_collision_a) {
+ if (colliding_a) {
+ area_a->add_area_to_query(area_b, shape_b, shape_a);
+ } else {
+ area_a->remove_area_from_query(area_b, shape_b, shape_a);
+ }
+ }
+
+ if (process_collision_b) {
+ if (colliding_b) {
+ area_b->add_area_to_query(area_a, shape_a, shape_b);
+ } else {
+ area_b->remove_area_from_query(area_a, shape_a, shape_b);
+ }
+ }
+
+ return false; // Never do any post solving.
+}
+
+void GodotArea2Pair2D::solve(real_t p_step) {
+ // Nothing to do.
+}
+
+GodotArea2Pair2D::GodotArea2Pair2D(GodotArea2D *p_area_a, int p_shape_a, GodotArea2D *p_area_b, int p_shape_b) {
+ area_a = p_area_a;
+ area_b = p_area_b;
+ shape_a = p_shape_a;
+ shape_b = p_shape_b;
+ area_a_monitorable = area_a->is_monitorable();
+ area_b_monitorable = area_b->is_monitorable();
+ area_a->add_constraint(this);
+ area_b->add_constraint(this);
+}
+
+GodotArea2Pair2D::~GodotArea2Pair2D() {
+ if (colliding_a) {
+ if (area_a->has_area_monitor_callback() && area_b_monitorable) {
+ area_a->remove_area_from_query(area_b, shape_b, shape_a);
+ }
+ }
+
+ if (colliding_b) {
+ if (area_b->has_area_monitor_callback() && area_a_monitorable) {
+ area_b->remove_area_from_query(area_a, shape_a, shape_b);
+ }
+ }
+
+ area_a->remove_constraint(this);
+ area_b->remove_constraint(this);
+}
diff --git a/servers/physics_2d/step_2d_sw.h b/servers/physics_2d/godot_area_pair_2d.h
index 83b9130608..ef6c774bc3 100644
--- a/servers/physics_2d/step_2d_sw.h
+++ b/servers/physics_2d/godot_area_pair_2d.h
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* step_2d_sw.h */
+/* godot_area_pair_2d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -28,22 +28,50 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef STEP_2D_SW_H
-#define STEP_2D_SW_H
+#ifndef GODOT_AREA_PAIR_2D_H
+#define GODOT_AREA_PAIR_2D_H
-#include "space_2d_sw.h"
+#include "godot_area_2d.h"
+#include "godot_body_2d.h"
+#include "godot_constraint_2d.h"
-class Step2DSW {
- uint64_t _step;
+class GodotAreaPair2D : public GodotConstraint2D {
+ GodotBody2D *body = nullptr;
+ GodotArea2D *area = nullptr;
+ int body_shape = 0;
+ int area_shape = 0;
+ bool colliding = false;
+ bool has_space_override = false;
+ bool process_collision = false;
- void _populate_island(Body2DSW *p_body, Body2DSW **p_island, Constraint2DSW **p_constraint_island);
- bool _setup_island(Constraint2DSW *p_island, real_t p_delta);
- void _solve_island(Constraint2DSW *p_island, int p_iterations, real_t p_delta);
- void _check_suspend(Body2DSW *p_island, real_t p_delta);
+public:
+ virtual bool setup(real_t p_step) override;
+ virtual bool pre_solve(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
+
+ GodotAreaPair2D(GodotBody2D *p_body, int p_body_shape, GodotArea2D *p_area, int p_area_shape);
+ ~GodotAreaPair2D();
+};
+
+class GodotArea2Pair2D : public GodotConstraint2D {
+ GodotArea2D *area_a = nullptr;
+ GodotArea2D *area_b = nullptr;
+ int shape_a = 0;
+ int shape_b = 0;
+ bool colliding_a = false;
+ bool colliding_b = false;
+ bool process_collision_a = false;
+ bool process_collision_b = false;
+ bool area_a_monitorable;
+ bool area_b_monitorable;
public:
- void step(Space2DSW *p_space, real_t p_delta, int p_iterations);
- Step2DSW();
+ virtual bool setup(real_t p_step) override;
+ virtual bool pre_solve(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
+
+ GodotArea2Pair2D(GodotArea2D *p_area_a, int p_shape_a, GodotArea2D *p_area_b, int p_shape_b);
+ ~GodotArea2Pair2D();
};
-#endif // STEP_2D_SW_H
+#endif // GODOT_AREA_PAIR_2D_H
diff --git a/servers/physics_2d/godot_body_2d.cpp b/servers/physics_2d/godot_body_2d.cpp
new file mode 100644
index 0000000000..6873504f70
--- /dev/null
+++ b/servers/physics_2d/godot_body_2d.cpp
@@ -0,0 +1,757 @@
+/*************************************************************************/
+/* godot_body_2d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 "godot_body_2d.h"
+
+#include "godot_area_2d.h"
+#include "godot_body_direct_state_2d.h"
+#include "godot_space_2d.h"
+
+void GodotBody2D::_mass_properties_changed() {
+ if (get_space() && !mass_properties_update_list.in_list() && (calculate_inertia || calculate_center_of_mass)) {
+ get_space()->body_add_to_mass_properties_update_list(&mass_properties_update_list);
+ }
+}
+
+void GodotBody2D::update_mass_properties() {
+ //update shapes and motions
+
+ switch (mode) {
+ case PhysicsServer2D::BODY_MODE_DYNAMIC: {
+ real_t total_area = 0;
+ for (int i = 0; i < get_shape_count(); i++) {
+ if (is_shape_disabled(i)) {
+ continue;
+ }
+ total_area += get_shape_aabb(i).get_area();
+ }
+
+ if (calculate_center_of_mass) {
+ // We have to recompute the center of mass.
+ center_of_mass_local = Vector2();
+
+ if (total_area != 0.0) {
+ for (int i = 0; i < get_shape_count(); i++) {
+ if (is_shape_disabled(i)) {
+ continue;
+ }
+
+ real_t area = get_shape_aabb(i).get_area();
+
+ real_t mass = area * this->mass / total_area;
+
+ // NOTE: we assume that the shape origin is also its center of mass.
+ center_of_mass_local += mass * get_shape_transform(i).get_origin();
+ }
+
+ center_of_mass_local /= mass;
+ }
+ }
+
+ if (calculate_inertia) {
+ inertia = 0;
+
+ for (int i = 0; i < get_shape_count(); i++) {
+ if (is_shape_disabled(i)) {
+ continue;
+ }
+
+ const GodotShape2D *shape = get_shape(i);
+
+ real_t area = get_shape_aabb(i).get_area();
+ if (area == 0.0) {
+ continue;
+ }
+
+ real_t mass = area * this->mass / total_area;
+
+ Transform2D mtx = get_shape_transform(i);
+ Vector2 scale = mtx.get_scale();
+ Vector2 shape_origin = mtx.get_origin() - center_of_mass_local;
+ inertia += shape->get_moment_of_inertia(mass, scale) + mass * shape_origin.length_squared();
+ }
+ }
+
+ _inv_inertia = inertia > 0.0 ? (1.0 / inertia) : 0.0;
+
+ if (mass) {
+ _inv_mass = 1.0 / mass;
+ } else {
+ _inv_mass = 0;
+ }
+
+ } break;
+ case PhysicsServer2D::BODY_MODE_KINEMATIC:
+ case PhysicsServer2D::BODY_MODE_STATIC: {
+ _inv_inertia = 0;
+ _inv_mass = 0;
+ } break;
+ case PhysicsServer2D::BODY_MODE_DYNAMIC_LINEAR: {
+ _inv_inertia = 0;
+ _inv_mass = 1.0 / mass;
+
+ } break;
+ }
+
+ _update_transform_dependent();
+}
+
+void GodotBody2D::reset_mass_properties() {
+ calculate_inertia = true;
+ calculate_center_of_mass = true;
+ _mass_properties_changed();
+}
+
+void GodotBody2D::set_active(bool p_active) {
+ if (active == p_active) {
+ return;
+ }
+
+ active = p_active;
+
+ if (active) {
+ if (mode == PhysicsServer2D::BODY_MODE_STATIC) {
+ // Static bodies can't be active.
+ active = false;
+ } else if (get_space()) {
+ get_space()->body_add_to_active_list(&active_list);
+ }
+ } else if (get_space()) {
+ get_space()->body_remove_from_active_list(&active_list);
+ }
+}
+
+void GodotBody2D::set_param(PhysicsServer2D::BodyParameter p_param, const Variant &p_value) {
+ switch (p_param) {
+ case PhysicsServer2D::BODY_PARAM_BOUNCE: {
+ bounce = p_value;
+ } break;
+ case PhysicsServer2D::BODY_PARAM_FRICTION: {
+ friction = p_value;
+ } break;
+ case PhysicsServer2D::BODY_PARAM_MASS: {
+ real_t mass_value = p_value;
+ ERR_FAIL_COND(mass_value <= 0);
+ mass = mass_value;
+ if (mode >= PhysicsServer2D::BODY_MODE_DYNAMIC) {
+ _mass_properties_changed();
+ }
+ } break;
+ case PhysicsServer2D::BODY_PARAM_INERTIA: {
+ real_t inertia_value = p_value;
+ if (inertia_value <= 0.0) {
+ calculate_inertia = true;
+ if (mode == PhysicsServer2D::BODY_MODE_DYNAMIC) {
+ _mass_properties_changed();
+ }
+ } else {
+ calculate_inertia = false;
+ inertia = inertia_value;
+ if (mode == PhysicsServer2D::BODY_MODE_DYNAMIC) {
+ _inv_inertia = 1.0 / inertia;
+ }
+ }
+ } break;
+ case PhysicsServer2D::BODY_PARAM_CENTER_OF_MASS: {
+ calculate_center_of_mass = false;
+ center_of_mass_local = p_value;
+ _update_transform_dependent();
+ } break;
+ case PhysicsServer2D::BODY_PARAM_GRAVITY_SCALE: {
+ if (Math::is_zero_approx(gravity_scale)) {
+ wakeup();
+ }
+ gravity_scale = p_value;
+ } break;
+ case PhysicsServer2D::BODY_PARAM_LINEAR_DAMP_MODE: {
+ int mode_value = p_value;
+ linear_damp_mode = (PhysicsServer2D::BodyDampMode)mode_value;
+ } break;
+ case PhysicsServer2D::BODY_PARAM_ANGULAR_DAMP_MODE: {
+ int mode_value = p_value;
+ angular_damp_mode = (PhysicsServer2D::BodyDampMode)mode_value;
+ } break;
+ case PhysicsServer2D::BODY_PARAM_LINEAR_DAMP: {
+ linear_damp = p_value;
+ } break;
+ case PhysicsServer2D::BODY_PARAM_ANGULAR_DAMP: {
+ angular_damp = p_value;
+ } break;
+ default: {
+ }
+ }
+}
+
+Variant GodotBody2D::get_param(PhysicsServer2D::BodyParameter p_param) const {
+ switch (p_param) {
+ case PhysicsServer2D::BODY_PARAM_BOUNCE: {
+ return bounce;
+ }
+ case PhysicsServer2D::BODY_PARAM_FRICTION: {
+ return friction;
+ }
+ case PhysicsServer2D::BODY_PARAM_MASS: {
+ return mass;
+ }
+ case PhysicsServer2D::BODY_PARAM_INERTIA: {
+ return inertia;
+ }
+ case PhysicsServer2D::BODY_PARAM_CENTER_OF_MASS: {
+ return center_of_mass_local;
+ }
+ case PhysicsServer2D::BODY_PARAM_GRAVITY_SCALE: {
+ return gravity_scale;
+ }
+ case PhysicsServer2D::BODY_PARAM_LINEAR_DAMP_MODE: {
+ return linear_damp_mode;
+ }
+ case PhysicsServer2D::BODY_PARAM_ANGULAR_DAMP_MODE: {
+ return angular_damp_mode;
+ }
+ case PhysicsServer2D::BODY_PARAM_LINEAR_DAMP: {
+ return linear_damp;
+ }
+ case PhysicsServer2D::BODY_PARAM_ANGULAR_DAMP: {
+ return angular_damp;
+ }
+ default: {
+ }
+ }
+
+ return 0;
+}
+
+void GodotBody2D::set_mode(PhysicsServer2D::BodyMode p_mode) {
+ PhysicsServer2D::BodyMode prev = mode;
+ mode = p_mode;
+
+ switch (p_mode) {
+ //CLEAR UP EVERYTHING IN CASE IT NOT WORKS!
+ case PhysicsServer2D::BODY_MODE_STATIC:
+ case PhysicsServer2D::BODY_MODE_KINEMATIC: {
+ _set_inv_transform(get_transform().affine_inverse());
+ _inv_mass = 0;
+ _inv_inertia = 0;
+ _set_static(p_mode == PhysicsServer2D::BODY_MODE_STATIC);
+ set_active(p_mode == PhysicsServer2D::BODY_MODE_KINEMATIC && contacts.size());
+ linear_velocity = Vector2();
+ angular_velocity = 0;
+ if (mode == PhysicsServer2D::BODY_MODE_KINEMATIC && prev != mode) {
+ first_time_kinematic = true;
+ }
+ } break;
+ case PhysicsServer2D::BODY_MODE_DYNAMIC: {
+ _inv_mass = mass > 0 ? (1.0 / mass) : 0;
+ if (!calculate_inertia) {
+ _inv_inertia = 1.0 / inertia;
+ }
+ _mass_properties_changed();
+ _set_static(false);
+ set_active(true);
+
+ } break;
+ case PhysicsServer2D::BODY_MODE_DYNAMIC_LINEAR: {
+ _inv_mass = mass > 0 ? (1.0 / mass) : 0;
+ _inv_inertia = 0;
+ angular_velocity = 0;
+ _set_static(false);
+ set_active(true);
+ }
+ }
+}
+
+PhysicsServer2D::BodyMode GodotBody2D::get_mode() const {
+ return mode;
+}
+
+void GodotBody2D::_shapes_changed() {
+ _mass_properties_changed();
+ wakeup();
+ wakeup_neighbours();
+}
+
+void GodotBody2D::set_state(PhysicsServer2D::BodyState p_state, const Variant &p_variant) {
+ switch (p_state) {
+ case PhysicsServer2D::BODY_STATE_TRANSFORM: {
+ if (mode == PhysicsServer2D::BODY_MODE_KINEMATIC) {
+ new_transform = p_variant;
+ //wakeup_neighbours();
+ set_active(true);
+ if (first_time_kinematic) {
+ _set_transform(p_variant);
+ _set_inv_transform(get_transform().affine_inverse());
+ first_time_kinematic = false;
+ }
+ } else if (mode == PhysicsServer2D::BODY_MODE_STATIC) {
+ _set_transform(p_variant);
+ _set_inv_transform(get_transform().affine_inverse());
+ wakeup_neighbours();
+ } else {
+ Transform2D t = p_variant;
+ t.orthonormalize();
+ new_transform = get_transform(); //used as old to compute motion
+ if (t == new_transform) {
+ break;
+ }
+ _set_transform(t);
+ _set_inv_transform(get_transform().inverse());
+ _update_transform_dependent();
+ }
+ wakeup();
+
+ } break;
+ case PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY: {
+ linear_velocity = p_variant;
+ constant_linear_velocity = linear_velocity;
+ wakeup();
+
+ } break;
+ case PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY: {
+ angular_velocity = p_variant;
+ constant_angular_velocity = angular_velocity;
+ wakeup();
+
+ } break;
+ case PhysicsServer2D::BODY_STATE_SLEEPING: {
+ if (mode == PhysicsServer2D::BODY_MODE_STATIC || mode == PhysicsServer2D::BODY_MODE_KINEMATIC) {
+ break;
+ }
+ bool do_sleep = p_variant;
+ if (do_sleep) {
+ linear_velocity = Vector2();
+ //biased_linear_velocity=Vector3();
+ angular_velocity = 0;
+ //biased_angular_velocity=Vector3();
+ set_active(false);
+ } else {
+ if (mode != PhysicsServer2D::BODY_MODE_STATIC) {
+ set_active(true);
+ }
+ }
+ } break;
+ case PhysicsServer2D::BODY_STATE_CAN_SLEEP: {
+ can_sleep = p_variant;
+ if (mode >= PhysicsServer2D::BODY_MODE_DYNAMIC && !active && !can_sleep) {
+ set_active(true);
+ }
+
+ } break;
+ }
+}
+
+Variant GodotBody2D::get_state(PhysicsServer2D::BodyState p_state) const {
+ switch (p_state) {
+ case PhysicsServer2D::BODY_STATE_TRANSFORM: {
+ return get_transform();
+ }
+ case PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY: {
+ return linear_velocity;
+ }
+ case PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY: {
+ return angular_velocity;
+ }
+ case PhysicsServer2D::BODY_STATE_SLEEPING: {
+ return !is_active();
+ }
+ case PhysicsServer2D::BODY_STATE_CAN_SLEEP: {
+ return can_sleep;
+ }
+ }
+
+ return Variant();
+}
+
+void GodotBody2D::set_space(GodotSpace2D *p_space) {
+ if (get_space()) {
+ wakeup_neighbours();
+
+ if (mass_properties_update_list.in_list()) {
+ get_space()->body_remove_from_mass_properties_update_list(&mass_properties_update_list);
+ }
+ if (active_list.in_list()) {
+ get_space()->body_remove_from_active_list(&active_list);
+ }
+ if (direct_state_query_list.in_list()) {
+ get_space()->body_remove_from_state_query_list(&direct_state_query_list);
+ }
+ }
+
+ _set_space(p_space);
+
+ if (get_space()) {
+ _mass_properties_changed();
+ if (active) {
+ get_space()->body_add_to_active_list(&active_list);
+ }
+ }
+}
+
+void GodotBody2D::_update_transform_dependent() {
+ center_of_mass = get_transform().basis_xform(center_of_mass_local);
+}
+
+void GodotBody2D::integrate_forces(real_t p_step) {
+ if (mode == PhysicsServer2D::BODY_MODE_STATIC) {
+ return;
+ }
+
+ ERR_FAIL_COND(!get_space());
+
+ int ac = areas.size();
+
+ bool gravity_done = false;
+ bool linear_damp_done = false;
+ bool angular_damp_done = false;
+
+ bool stopped = false;
+
+ gravity = Vector2(0, 0);
+
+ total_linear_damp = 0.0;
+ total_angular_damp = 0.0;
+
+ // Combine gravity and damping from overlapping areas in priority order.
+ if (ac) {
+ areas.sort();
+ const AreaCMP *aa = &areas[0];
+ for (int i = ac - 1; i >= 0 && !stopped; i--) {
+ if (!gravity_done) {
+ PhysicsServer2D::AreaSpaceOverrideMode area_gravity_mode = (PhysicsServer2D::AreaSpaceOverrideMode)(int)aa[i].area->get_param(PhysicsServer2D::AREA_PARAM_GRAVITY_OVERRIDE_MODE);
+ if (area_gravity_mode != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) {
+ Vector2 area_gravity;
+ aa[i].area->compute_gravity(get_transform().get_origin(), area_gravity);
+ switch (area_gravity_mode) {
+ case PhysicsServer2D::AREA_SPACE_OVERRIDE_COMBINE:
+ case PhysicsServer2D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: {
+ gravity += area_gravity;
+ gravity_done = area_gravity_mode == PhysicsServer2D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE;
+ } break;
+ case PhysicsServer2D::AREA_SPACE_OVERRIDE_REPLACE:
+ case PhysicsServer2D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: {
+ gravity = area_gravity;
+ gravity_done = area_gravity_mode == PhysicsServer2D::AREA_SPACE_OVERRIDE_REPLACE;
+ } break;
+ default: {
+ }
+ }
+ }
+ }
+ if (!linear_damp_done) {
+ PhysicsServer2D::AreaSpaceOverrideMode area_linear_damp_mode = (PhysicsServer2D::AreaSpaceOverrideMode)(int)aa[i].area->get_param(PhysicsServer2D::AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE);
+ if (area_linear_damp_mode != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) {
+ real_t area_linear_damp = aa[i].area->get_linear_damp();
+ switch (area_linear_damp_mode) {
+ case PhysicsServer2D::AREA_SPACE_OVERRIDE_COMBINE:
+ case PhysicsServer2D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: {
+ total_linear_damp += area_linear_damp;
+ linear_damp_done = area_linear_damp_mode == PhysicsServer2D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE;
+ } break;
+ case PhysicsServer2D::AREA_SPACE_OVERRIDE_REPLACE:
+ case PhysicsServer2D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: {
+ total_linear_damp = area_linear_damp;
+ linear_damp_done = area_linear_damp_mode == PhysicsServer2D::AREA_SPACE_OVERRIDE_REPLACE;
+ } break;
+ default: {
+ }
+ }
+ }
+ }
+ if (!angular_damp_done) {
+ PhysicsServer2D::AreaSpaceOverrideMode area_angular_damp_mode = (PhysicsServer2D::AreaSpaceOverrideMode)(int)aa[i].area->get_param(PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP_OVERRIDE_MODE);
+ if (area_angular_damp_mode != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) {
+ real_t area_angular_damp = aa[i].area->get_angular_damp();
+ switch (area_angular_damp_mode) {
+ case PhysicsServer2D::AREA_SPACE_OVERRIDE_COMBINE:
+ case PhysicsServer2D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: {
+ total_angular_damp += area_angular_damp;
+ angular_damp_done = area_angular_damp_mode == PhysicsServer2D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE;
+ } break;
+ case PhysicsServer2D::AREA_SPACE_OVERRIDE_REPLACE:
+ case PhysicsServer2D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: {
+ total_angular_damp = area_angular_damp;
+ angular_damp_done = area_angular_damp_mode == PhysicsServer2D::AREA_SPACE_OVERRIDE_REPLACE;
+ } break;
+ default: {
+ }
+ }
+ }
+ }
+ stopped = gravity_done && linear_damp_done && angular_damp_done;
+ }
+ }
+
+ // Add default gravity and damping from space area.
+ if (!stopped) {
+ GodotArea2D *default_area = get_space()->get_default_area();
+ ERR_FAIL_COND(!default_area);
+
+ if (!gravity_done) {
+ Vector2 default_gravity;
+ default_area->compute_gravity(get_transform().get_origin(), default_gravity);
+ gravity += default_gravity;
+ }
+
+ if (!linear_damp_done) {
+ total_linear_damp += default_area->get_linear_damp();
+ }
+
+ if (!angular_damp_done) {
+ total_angular_damp += default_area->get_angular_damp();
+ }
+ }
+
+ // Override linear damping with body's value.
+ switch (linear_damp_mode) {
+ case PhysicsServer2D::BODY_DAMP_MODE_COMBINE: {
+ total_linear_damp += linear_damp;
+ } break;
+ case PhysicsServer2D::BODY_DAMP_MODE_REPLACE: {
+ total_linear_damp = linear_damp;
+ } break;
+ }
+
+ // Override angular damping with body's value.
+ switch (angular_damp_mode) {
+ case PhysicsServer2D::BODY_DAMP_MODE_COMBINE: {
+ total_angular_damp += angular_damp;
+ } break;
+ case PhysicsServer2D::BODY_DAMP_MODE_REPLACE: {
+ total_angular_damp = angular_damp;
+ } break;
+ }
+
+ gravity *= gravity_scale;
+
+ prev_linear_velocity = linear_velocity;
+ prev_angular_velocity = angular_velocity;
+
+ Vector2 motion;
+ bool do_motion = false;
+
+ if (mode == PhysicsServer2D::BODY_MODE_KINEMATIC) {
+ //compute motion, angular and etc. velocities from prev transform
+ motion = new_transform.get_origin() - get_transform().get_origin();
+ linear_velocity = constant_linear_velocity + motion / p_step;
+
+ real_t rot = new_transform.get_rotation() - get_transform().get_rotation();
+ angular_velocity = constant_angular_velocity + remainder(rot, 2.0 * Math_PI) / p_step;
+
+ do_motion = true;
+
+ } else {
+ if (!omit_force_integration) {
+ //overridden by direct state query
+
+ Vector2 force = gravity * mass + applied_force + constant_force;
+ real_t torque = applied_torque + constant_torque;
+
+ real_t damp = 1.0 - p_step * total_linear_damp;
+
+ if (damp < 0) { // reached zero in the given time
+ damp = 0;
+ }
+
+ real_t angular_damp = 1.0 - p_step * total_angular_damp;
+
+ if (angular_damp < 0) { // reached zero in the given time
+ angular_damp = 0;
+ }
+
+ linear_velocity *= damp;
+ angular_velocity *= angular_damp;
+
+ linear_velocity += _inv_mass * force * p_step;
+ angular_velocity += _inv_inertia * torque * p_step;
+ }
+
+ if (continuous_cd_mode != PhysicsServer2D::CCD_MODE_DISABLED) {
+ motion = linear_velocity * p_step;
+ do_motion = true;
+ }
+ }
+
+ applied_force = Vector2();
+ applied_torque = 0.0;
+
+ biased_angular_velocity = 0.0;
+ biased_linear_velocity = Vector2();
+
+ if (do_motion) { //shapes temporarily extend for raycast
+ _update_shapes_with_motion(motion);
+ }
+
+ contact_count = 0;
+}
+
+void GodotBody2D::integrate_velocities(real_t p_step) {
+ if (mode == PhysicsServer2D::BODY_MODE_STATIC) {
+ return;
+ }
+
+ if (fi_callback_data || body_state_callback) {
+ get_space()->body_add_to_state_query_list(&direct_state_query_list);
+ }
+
+ if (mode == PhysicsServer2D::BODY_MODE_KINEMATIC) {
+ _set_transform(new_transform, false);
+ _set_inv_transform(new_transform.affine_inverse());
+ if (contacts.size() == 0 && linear_velocity == Vector2() && angular_velocity == 0) {
+ set_active(false); //stopped moving, deactivate
+ }
+ return;
+ }
+
+ real_t total_angular_velocity = angular_velocity + biased_angular_velocity;
+ Vector2 total_linear_velocity = linear_velocity + biased_linear_velocity;
+
+ real_t angle_delta = total_angular_velocity * p_step;
+ real_t angle = get_transform().get_rotation() + angle_delta;
+ Vector2 pos = get_transform().get_origin() + total_linear_velocity * p_step;
+
+ if (center_of_mass.length_squared() > CMP_EPSILON2) {
+ // Calculate displacement due to center of mass offset.
+ pos += center_of_mass - center_of_mass.rotated(angle_delta);
+ }
+
+ _set_transform(Transform2D(angle, pos), continuous_cd_mode == PhysicsServer2D::CCD_MODE_DISABLED);
+ _set_inv_transform(get_transform().inverse());
+
+ if (continuous_cd_mode != PhysicsServer2D::CCD_MODE_DISABLED) {
+ new_transform = get_transform();
+ }
+
+ _update_transform_dependent();
+}
+
+void GodotBody2D::wakeup_neighbours() {
+ for (const Pair<GodotConstraint2D *, int> &E : constraint_list) {
+ const GodotConstraint2D *c = E.first;
+ GodotBody2D **n = c->get_body_ptr();
+ int bc = c->get_body_count();
+
+ for (int i = 0; i < bc; i++) {
+ if (i == E.second) {
+ continue;
+ }
+ GodotBody2D *b = n[i];
+ if (b->mode < PhysicsServer2D::BODY_MODE_DYNAMIC) {
+ continue;
+ }
+
+ if (!b->is_active()) {
+ b->set_active(true);
+ }
+ }
+ }
+}
+
+void GodotBody2D::call_queries() {
+ if (fi_callback_data) {
+ if (!fi_callback_data->callable.get_object()) {
+ set_force_integration_callback(Callable());
+ } else {
+ Variant direct_state_variant = get_direct_state();
+ const Variant *vp[2] = { &direct_state_variant, &fi_callback_data->udata };
+
+ Callable::CallError ce;
+ Variant rv;
+ if (fi_callback_data->udata.get_type() != Variant::NIL) {
+ fi_callback_data->callable.call(vp, 2, rv, ce);
+
+ } else {
+ fi_callback_data->callable.call(vp, 1, rv, ce);
+ }
+ }
+ }
+
+ if (body_state_callback) {
+ (body_state_callback)(body_state_callback_instance, get_direct_state());
+ }
+}
+
+bool GodotBody2D::sleep_test(real_t p_step) {
+ if (mode == PhysicsServer2D::BODY_MODE_STATIC || mode == PhysicsServer2D::BODY_MODE_KINEMATIC) {
+ return true;
+ } else if (!can_sleep) {
+ return false;
+ }
+
+ if (Math::abs(angular_velocity) < get_space()->get_body_angular_velocity_sleep_threshold() && Math::abs(linear_velocity.length_squared()) < get_space()->get_body_linear_velocity_sleep_threshold() * get_space()->get_body_linear_velocity_sleep_threshold()) {
+ still_time += p_step;
+
+ return still_time > get_space()->get_body_time_to_sleep();
+ } else {
+ still_time = 0; //maybe this should be set to 0 on set_active?
+ return false;
+ }
+}
+
+void GodotBody2D::set_state_sync_callback(void *p_instance, PhysicsServer2D::BodyStateCallback p_callback) {
+ body_state_callback_instance = p_instance;
+ body_state_callback = p_callback;
+}
+
+void GodotBody2D::set_force_integration_callback(const Callable &p_callable, const Variant &p_udata) {
+ if (p_callable.get_object()) {
+ if (!fi_callback_data) {
+ fi_callback_data = memnew(ForceIntegrationCallbackData);
+ }
+ fi_callback_data->callable = p_callable;
+ fi_callback_data->udata = p_udata;
+ } else if (fi_callback_data) {
+ memdelete(fi_callback_data);
+ fi_callback_data = nullptr;
+ }
+}
+
+GodotPhysicsDirectBodyState2D *GodotBody2D::get_direct_state() {
+ if (!direct_state) {
+ direct_state = memnew(GodotPhysicsDirectBodyState2D);
+ direct_state->body = this;
+ }
+ return direct_state;
+}
+
+GodotBody2D::GodotBody2D() :
+ GodotCollisionObject2D(TYPE_BODY),
+ active_list(this),
+ mass_properties_update_list(this),
+ direct_state_query_list(this) {
+ _set_static(false);
+}
+
+GodotBody2D::~GodotBody2D() {
+ if (fi_callback_data) {
+ memdelete(fi_callback_data);
+ }
+ if (direct_state) {
+ memdelete(direct_state);
+ }
+}
diff --git a/servers/physics_2d/body_2d_sw.h b/servers/physics_2d/godot_body_2d.h
index 60d55ab8bd..4b87a69d5c 100644
--- a/servers/physics_2d/body_2d_sw.h
+++ b/servers/physics_2d/godot_body_2d.h
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* body_2d_sw.h */
+/* godot_body_2d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -28,72 +28,93 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef BODY_2D_SW_H
-#define BODY_2D_SW_H
+#ifndef GODOT_BODY_2D_H
+#define GODOT_BODY_2D_H
+
+#include "godot_area_2d.h"
+#include "godot_collision_object_2d.h"
-#include "area_2d_sw.h"
-#include "collision_object_2d_sw.h"
#include "core/templates/list.h"
#include "core/templates/pair.h"
#include "core/templates/vset.h"
-class Constraint2DSW;
+class GodotConstraint2D;
+class GodotPhysicsDirectBodyState2D;
-class Body2DSW : public CollisionObject2DSW {
- PhysicsServer2D::BodyMode mode;
+class GodotBody2D : public GodotCollisionObject2D {
+ PhysicsServer2D::BodyMode mode = PhysicsServer2D::BODY_MODE_DYNAMIC;
Vector2 biased_linear_velocity;
- real_t biased_angular_velocity;
+ real_t biased_angular_velocity = 0.0;
Vector2 linear_velocity;
- real_t angular_velocity;
+ real_t angular_velocity = 0.0;
+
+ Vector2 prev_linear_velocity;
+ real_t prev_angular_velocity = 0.0;
+
+ Vector2 constant_linear_velocity;
+ real_t constant_angular_velocity = 0.0;
+
+ PhysicsServer2D::BodyDampMode linear_damp_mode = PhysicsServer2D::BODY_DAMP_MODE_COMBINE;
+ PhysicsServer2D::BodyDampMode angular_damp_mode = PhysicsServer2D::BODY_DAMP_MODE_COMBINE;
+
+ real_t linear_damp = 0.0;
+ real_t angular_damp = 0.0;
- real_t linear_damp;
- real_t angular_damp;
- real_t gravity_scale;
+ real_t total_linear_damp = 0.0;
+ real_t total_angular_damp = 0.0;
- real_t mass;
- real_t inertia;
- real_t bounce;
- real_t friction;
+ real_t gravity_scale = 1.0;
- real_t _inv_mass;
- real_t _inv_inertia;
- bool user_inertia;
+ real_t bounce = 0.0;
+ real_t friction = 1.0;
+
+ real_t mass = 1.0;
+ real_t _inv_mass = 1.0;
+
+ real_t inertia = 0.0;
+ real_t _inv_inertia = 0.0;
+
+ Vector2 center_of_mass_local;
+ Vector2 center_of_mass;
+
+ bool calculate_inertia = true;
+ bool calculate_center_of_mass = true;
Vector2 gravity;
- real_t area_linear_damp;
- real_t area_angular_damp;
- real_t still_time;
+ real_t still_time = 0.0;
Vector2 applied_force;
- real_t applied_torque;
+ real_t applied_torque = 0.0;
+
+ Vector2 constant_force;
+ real_t constant_torque = 0.0;
- SelfList<Body2DSW> active_list;
- SelfList<Body2DSW> inertia_update_list;
- SelfList<Body2DSW> direct_state_query_list;
+ SelfList<GodotBody2D> active_list;
+ SelfList<GodotBody2D> mass_properties_update_list;
+ SelfList<GodotBody2D> direct_state_query_list;
VSet<RID> exceptions;
- PhysicsServer2D::CCDMode continuous_cd_mode;
- bool omit_force_integration;
- bool active;
- bool can_sleep;
- bool first_time_kinematic;
- bool first_integration;
- void _update_inertia();
- virtual void _shapes_changed();
+ PhysicsServer2D::CCDMode continuous_cd_mode = PhysicsServer2D::CCD_MODE_DISABLED;
+ bool omit_force_integration = false;
+ bool active = true;
+ bool can_sleep = true;
+ bool first_time_kinematic = false;
+ void _mass_properties_changed();
+ virtual void _shapes_changed() override;
Transform2D new_transform;
- List<Pair<Constraint2DSW *, int>> constraint_list;
+ List<Pair<GodotConstraint2D *, int>> constraint_list;
struct AreaCMP {
- Area2DSW *area;
- int refCount;
+ GodotArea2D *area = nullptr;
+ int refCount = 0;
_FORCE_INLINE_ bool operator==(const AreaCMP &p_cmp) const { return area->get_self() == p_cmp.area->get_self(); }
_FORCE_INLINE_ bool operator<(const AreaCMP &p_cmp) const { return area->get_priority() < p_cmp.area->get_priority(); }
_FORCE_INLINE_ AreaCMP() {}
- _FORCE_INLINE_ AreaCMP(Area2DSW *p_area) {
+ _FORCE_INLINE_ AreaCMP(GodotArea2D *p_area) {
area = p_area;
refCount = 1;
}
@@ -104,38 +125,43 @@ class Body2DSW : public CollisionObject2DSW {
struct Contact {
Vector2 local_pos;
Vector2 local_normal;
- real_t depth;
- int local_shape;
+ real_t depth = 0.0;
+ int local_shape = 0;
Vector2 collider_pos;
- int collider_shape;
+ int collider_shape = 0;
ObjectID collider_instance_id;
RID collider;
Vector2 collider_velocity_at_pos;
};
Vector<Contact> contacts; //no contacts by default
- int contact_count;
+ int contact_count = 0;
- struct ForceIntegrationCallback {
- ObjectID id;
- StringName method;
- Variant callback_udata;
+ void *body_state_callback_instance = nullptr;
+ PhysicsServer2D::BodyStateCallback body_state_callback = nullptr;
+
+ struct ForceIntegrationCallbackData {
+ Callable callable;
+ Variant udata;
};
- ForceIntegrationCallback *fi_callback;
+ ForceIntegrationCallbackData *fi_callback_data = nullptr;
+
+ GodotPhysicsDirectBodyState2D *direct_state = nullptr;
- uint64_t island_step;
- Body2DSW *island_next;
- Body2DSW *island_list_next;
+ uint64_t island_step = 0;
- _FORCE_INLINE_ void _compute_area_gravity_and_dampenings(const Area2DSW *p_area);
+ void _update_transform_dependent();
- friend class PhysicsDirectBodyState2DSW; // i give up, too many functions to expose
+ friend class GodotPhysicsDirectBodyState2D; // i give up, too many functions to expose
public:
- void set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata = Variant());
+ void set_state_sync_callback(void *p_instance, PhysicsServer2D::BodyStateCallback p_callback);
+ void set_force_integration_callback(const Callable &p_callable, const Variant &p_udata = Variant());
+
+ GodotPhysicsDirectBodyState2D *get_direct_state();
- _FORCE_INLINE_ void add_area(Area2DSW *p_area) {
+ _FORCE_INLINE_ void add_area(GodotArea2D *p_area) {
int index = areas.find(AreaCMP(p_area));
if (index > -1) {
areas.write[index].refCount += 1;
@@ -144,12 +170,12 @@ public:
}
}
- _FORCE_INLINE_ void remove_area(Area2DSW *p_area) {
+ _FORCE_INLINE_ void remove_area(GodotArea2D *p_area) {
int index = areas.find(AreaCMP(p_area));
if (index > -1) {
areas.write[index].refCount -= 1;
if (areas[index].refCount < 1) {
- areas.remove(index);
+ areas.remove_at(index);
}
}
}
@@ -175,15 +201,9 @@ public:
_FORCE_INLINE_ uint64_t get_island_step() const { return island_step; }
_FORCE_INLINE_ void set_island_step(uint64_t p_step) { island_step = p_step; }
- _FORCE_INLINE_ Body2DSW *get_island_next() const { return island_next; }
- _FORCE_INLINE_ void set_island_next(Body2DSW *p_next) { island_next = p_next; }
-
- _FORCE_INLINE_ Body2DSW *get_island_list_next() const { return island_list_next; }
- _FORCE_INLINE_ void set_island_list_next(Body2DSW *p_next) { island_list_next = p_next; }
-
- _FORCE_INLINE_ void add_constraint(Constraint2DSW *p_constraint, int p_pos) { constraint_list.push_back({ p_constraint, p_pos }); }
- _FORCE_INLINE_ void remove_constraint(Constraint2DSW *p_constraint, int p_pos) { constraint_list.erase({ p_constraint, p_pos }); }
- const List<Pair<Constraint2DSW *, int>> &get_constraint_list() const { return constraint_list; }
+ _FORCE_INLINE_ void add_constraint(GodotConstraint2D *p_constraint, int p_pos) { constraint_list.push_back({ p_constraint, p_pos }); }
+ _FORCE_INLINE_ void remove_constraint(GodotConstraint2D *p_constraint, int p_pos) { constraint_list.erase({ p_constraint, p_pos }); }
+ const List<Pair<GodotConstraint2D *, int>> &get_constraint_list() const { return constraint_list; }
_FORCE_INLINE_ void clear_constraint_list() { constraint_list.clear(); }
_FORCE_INLINE_ void set_omit_force_integration(bool p_omit_force_integration) { omit_force_integration = p_omit_force_integration; }
@@ -195,6 +215,9 @@ public:
_FORCE_INLINE_ void set_angular_velocity(real_t p_velocity) { angular_velocity = p_velocity; }
_FORCE_INLINE_ real_t get_angular_velocity() const { return angular_velocity; }
+ _FORCE_INLINE_ Vector2 get_prev_linear_velocity() const { return prev_linear_velocity; }
+ _FORCE_INLINE_ real_t get_prev_angular_velocity() const { return prev_angular_velocity; }
+
_FORCE_INLINE_ void set_biased_linear_velocity(const Vector2 &p_velocity) { biased_linear_velocity = p_velocity; }
_FORCE_INLINE_ Vector2 get_biased_linear_velocity() const { return biased_linear_velocity; }
@@ -207,18 +230,56 @@ public:
_FORCE_INLINE_ void apply_impulse(const Vector2 &p_impulse, const Vector2 &p_position = Vector2()) {
linear_velocity += p_impulse * _inv_mass;
- angular_velocity += _inv_inertia * p_position.cross(p_impulse);
+ angular_velocity += _inv_inertia * (p_position - center_of_mass).cross(p_impulse);
}
_FORCE_INLINE_ void apply_torque_impulse(real_t p_torque) {
angular_velocity += _inv_inertia * p_torque;
}
- _FORCE_INLINE_ void apply_bias_impulse(const Vector2 &p_impulse, const Vector2 &p_position = Vector2()) {
+ _FORCE_INLINE_ void apply_bias_impulse(const Vector2 &p_impulse, const Vector2 &p_position = Vector2(), real_t p_max_delta_av = -1.0) {
biased_linear_velocity += p_impulse * _inv_mass;
- biased_angular_velocity += _inv_inertia * p_position.cross(p_impulse);
+ if (p_max_delta_av != 0.0) {
+ real_t delta_av = _inv_inertia * (p_position - center_of_mass).cross(p_impulse);
+ if (p_max_delta_av > 0 && delta_av > p_max_delta_av) {
+ delta_av = p_max_delta_av;
+ }
+ biased_angular_velocity += delta_av;
+ }
}
+ _FORCE_INLINE_ void apply_central_force(const Vector2 &p_force) {
+ applied_force += p_force;
+ }
+
+ _FORCE_INLINE_ void apply_force(const Vector2 &p_force, const Vector2 &p_position = Vector2()) {
+ applied_force += p_force;
+ applied_torque += (p_position - center_of_mass).cross(p_force);
+ }
+
+ _FORCE_INLINE_ void apply_torque(real_t p_torque) {
+ applied_torque += p_torque;
+ }
+
+ _FORCE_INLINE_ void add_constant_central_force(const Vector2 &p_force) {
+ constant_force += p_force;
+ }
+
+ _FORCE_INLINE_ void add_constant_force(const Vector2 &p_force, const Vector2 &p_position = Vector2()) {
+ constant_force += p_force;
+ constant_torque += (p_position - center_of_mass).cross(p_force);
+ }
+
+ _FORCE_INLINE_ void add_constant_torque(real_t p_torque) {
+ constant_torque += p_torque;
+ }
+
+ void set_constant_force(const Vector2 &p_force) { constant_force = p_force; }
+ Vector2 get_constant_force() const { return constant_force; }
+
+ void set_constant_torque(real_t p_torque) { constant_torque = p_torque; }
+ real_t get_constant_torque() const { return constant_torque; }
+
void set_active(bool p_active);
_FORCE_INLINE_ bool is_active() const { return active; }
@@ -229,8 +290,8 @@ public:
set_active(true);
}
- void set_param(PhysicsServer2D::BodyParameter p_param, real_t);
- real_t get_param(PhysicsServer2D::BodyParameter p_param) const;
+ void set_param(PhysicsServer2D::BodyParameter p_param, const Variant &p_value);
+ Variant get_param(PhysicsServer2D::BodyParameter p_param) const;
void set_mode(PhysicsServer2D::BodyMode p_mode);
PhysicsServer2D::BodyMode get_mode() const;
@@ -238,43 +299,28 @@ public:
void set_state(PhysicsServer2D::BodyState p_state, const Variant &p_variant);
Variant get_state(PhysicsServer2D::BodyState p_state) const;
- void set_applied_force(const Vector2 &p_force) { applied_force = p_force; }
- Vector2 get_applied_force() const { return applied_force; }
-
- void set_applied_torque(real_t p_torque) { applied_torque = p_torque; }
- real_t get_applied_torque() const { return applied_torque; }
-
- _FORCE_INLINE_ void add_central_force(const Vector2 &p_force) {
- applied_force += p_force;
- }
-
- _FORCE_INLINE_ void add_force(const Vector2 &p_force, const Vector2 &p_position = Vector2()) {
- applied_force += p_force;
- applied_torque += p_position.cross(p_force);
- }
-
- _FORCE_INLINE_ void add_torque(real_t p_torque) {
- applied_torque += p_torque;
- }
-
_FORCE_INLINE_ void set_continuous_collision_detection_mode(PhysicsServer2D::CCDMode p_mode) { continuous_cd_mode = p_mode; }
_FORCE_INLINE_ PhysicsServer2D::CCDMode get_continuous_collision_detection_mode() const { return continuous_cd_mode; }
- void set_space(Space2DSW *p_space);
+ void set_space(GodotSpace2D *p_space) override;
- void update_inertias();
+ void update_mass_properties();
+ void reset_mass_properties();
+ _FORCE_INLINE_ const Vector2 &get_center_of_mass() const { return center_of_mass; }
+ _FORCE_INLINE_ const Vector2 &get_center_of_mass_local() const { return center_of_mass_local; }
_FORCE_INLINE_ real_t get_inv_mass() const { return _inv_mass; }
_FORCE_INLINE_ real_t get_inv_inertia() const { return _inv_inertia; }
_FORCE_INLINE_ real_t get_friction() const { return friction; }
- _FORCE_INLINE_ Vector2 get_gravity() const { return gravity; }
_FORCE_INLINE_ real_t get_bounce() const { return bounce; }
- _FORCE_INLINE_ real_t get_linear_damp() const { return linear_damp; }
- _FORCE_INLINE_ real_t get_angular_damp() const { return angular_damp; }
void integrate_forces(real_t p_step);
void integrate_velocities(real_t p_step);
+ _FORCE_INLINE_ Vector2 get_velocity_in_local_point(const Vector2 &rel_pos) const {
+ return linear_velocity + Vector2(-angular_velocity * rel_pos.y, angular_velocity * rel_pos.x);
+ }
+
_FORCE_INLINE_ Vector2 get_motion() const {
if (mode > PhysicsServer2D::BODY_MODE_KINEMATIC) {
return new_transform.get_origin() - get_transform().get_origin();
@@ -289,13 +335,13 @@ public:
bool sleep_test(real_t p_step);
- Body2DSW();
- ~Body2DSW();
+ GodotBody2D();
+ ~GodotBody2D();
};
//add contact inline
-void Body2DSW::add_contact(const Vector2 &p_local_pos, const Vector2 &p_local_normal, real_t p_depth, int p_local_shape, const Vector2 &p_collider_pos, int p_collider_shape, ObjectID p_collider_instance_id, const RID &p_collider, const Vector2 &p_collider_velocity_at_pos) {
+void GodotBody2D::add_contact(const Vector2 &p_local_pos, const Vector2 &p_local_normal, real_t p_depth, int p_local_shape, const Vector2 &p_collider_pos, int p_collider_shape, ObjectID p_collider_instance_id, const RID &p_collider, const Vector2 &p_collider_velocity_at_pos) {
int c_max = contacts.size();
if (c_max == 0) {
@@ -337,85 +383,4 @@ void Body2DSW::add_contact(const Vector2 &p_local_pos, const Vector2 &p_local_no
c[idx].collider_velocity_at_pos = p_collider_velocity_at_pos;
}
-class PhysicsDirectBodyState2DSW : public PhysicsDirectBodyState2D {
- GDCLASS(PhysicsDirectBodyState2DSW, PhysicsDirectBodyState2D);
-
-public:
- static PhysicsDirectBodyState2DSW *singleton;
- Body2DSW *body;
- real_t step;
-
- virtual Vector2 get_total_gravity() const override { return body->gravity; } // get gravity vector working on this body space/area
- virtual real_t get_total_angular_damp() const override { return body->area_angular_damp; } // get density of this body space/area
- virtual real_t get_total_linear_damp() const override { return body->area_linear_damp; } // get density of this body space/area
-
- virtual real_t get_inverse_mass() const override { return body->get_inv_mass(); } // get the mass
- virtual real_t get_inverse_inertia() const override { return body->get_inv_inertia(); } // get density of this body space
-
- virtual void set_linear_velocity(const Vector2 &p_velocity) override { body->set_linear_velocity(p_velocity); }
- virtual Vector2 get_linear_velocity() const override { return body->get_linear_velocity(); }
-
- virtual void set_angular_velocity(real_t p_velocity) override { body->set_angular_velocity(p_velocity); }
- virtual real_t get_angular_velocity() const override { return body->get_angular_velocity(); }
-
- virtual void set_transform(const Transform2D &p_transform) override { body->set_state(PhysicsServer2D::BODY_STATE_TRANSFORM, p_transform); }
- virtual Transform2D get_transform() const override { return body->get_transform(); }
-
- virtual void add_central_force(const Vector2 &p_force) override { body->add_central_force(p_force); }
- virtual void add_force(const Vector2 &p_force, const Vector2 &p_position = Vector2()) override { body->add_force(p_force, p_position); }
- virtual void add_torque(real_t p_torque) override { body->add_torque(p_torque); }
- virtual void apply_central_impulse(const Vector2 &p_impulse) override { body->apply_central_impulse(p_impulse); }
- virtual void apply_impulse(const Vector2 &p_impulse, const Vector2 &p_position = Vector2()) override { body->apply_impulse(p_impulse, p_position); }
- virtual void apply_torque_impulse(real_t p_torque) override { body->apply_torque_impulse(p_torque); }
-
- virtual void set_sleep_state(bool p_enable) override { body->set_active(!p_enable); }
- virtual bool is_sleeping() const override { return !body->is_active(); }
-
- virtual int get_contact_count() const override { return body->contact_count; }
-
- virtual Vector2 get_contact_local_position(int p_contact_idx) const override {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector2());
- return body->contacts[p_contact_idx].local_pos;
- }
- virtual Vector2 get_contact_local_normal(int p_contact_idx) const override {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector2());
- return body->contacts[p_contact_idx].local_normal;
- }
- virtual int get_contact_local_shape(int p_contact_idx) const override {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, -1);
- return body->contacts[p_contact_idx].local_shape;
- }
-
- virtual RID get_contact_collider(int p_contact_idx) const override {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, RID());
- return body->contacts[p_contact_idx].collider;
- }
- virtual Vector2 get_contact_collider_position(int p_contact_idx) const override {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector2());
- return body->contacts[p_contact_idx].collider_pos;
- }
- virtual ObjectID get_contact_collider_id(int p_contact_idx) const override {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, ObjectID());
- return body->contacts[p_contact_idx].collider_instance_id;
- }
- virtual int get_contact_collider_shape(int p_contact_idx) const override {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, 0);
- return body->contacts[p_contact_idx].collider_shape;
- }
- virtual Variant get_contact_collider_shape_metadata(int p_contact_idx) const override;
-
- virtual Vector2 get_contact_collider_velocity_at_position(int p_contact_idx) const override {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector2());
- return body->contacts[p_contact_idx].collider_velocity_at_pos;
- }
-
- virtual PhysicsDirectSpaceState2D *get_space_state() override;
-
- virtual real_t get_step() const override { return step; }
- PhysicsDirectBodyState2DSW() {
- singleton = this;
- body = nullptr;
- }
-};
-
-#endif // BODY_2D_SW_H
+#endif // GODOT_BODY_2D_H
diff --git a/servers/physics_2d/godot_body_direct_state_2d.cpp b/servers/physics_2d/godot_body_direct_state_2d.cpp
new file mode 100644
index 0000000000..cde6e8c991
--- /dev/null
+++ b/servers/physics_2d/godot_body_direct_state_2d.cpp
@@ -0,0 +1,219 @@
+/*************************************************************************/
+/* godot_body_direct_state_2d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 "godot_body_direct_state_2d.h"
+
+#include "godot_body_2d.h"
+#include "godot_physics_server_2d.h"
+#include "godot_space_2d.h"
+
+Vector2 GodotPhysicsDirectBodyState2D::get_total_gravity() const {
+ return body->gravity;
+}
+
+real_t GodotPhysicsDirectBodyState2D::get_total_angular_damp() const {
+ return body->total_angular_damp;
+}
+
+real_t GodotPhysicsDirectBodyState2D::get_total_linear_damp() const {
+ return body->total_linear_damp;
+}
+
+Vector2 GodotPhysicsDirectBodyState2D::get_center_of_mass() const {
+ return body->get_center_of_mass();
+}
+
+Vector2 GodotPhysicsDirectBodyState2D::get_center_of_mass_local() const {
+ return body->get_center_of_mass_local();
+}
+
+real_t GodotPhysicsDirectBodyState2D::get_inverse_mass() const {
+ return body->get_inv_mass();
+}
+
+real_t GodotPhysicsDirectBodyState2D::get_inverse_inertia() const {
+ return body->get_inv_inertia();
+}
+
+void GodotPhysicsDirectBodyState2D::set_linear_velocity(const Vector2 &p_velocity) {
+ body->wakeup();
+ body->set_linear_velocity(p_velocity);
+}
+
+Vector2 GodotPhysicsDirectBodyState2D::get_linear_velocity() const {
+ return body->get_linear_velocity();
+}
+
+void GodotPhysicsDirectBodyState2D::set_angular_velocity(real_t p_velocity) {
+ body->wakeup();
+ body->set_angular_velocity(p_velocity);
+}
+
+real_t GodotPhysicsDirectBodyState2D::get_angular_velocity() const {
+ return body->get_angular_velocity();
+}
+
+void GodotPhysicsDirectBodyState2D::set_transform(const Transform2D &p_transform) {
+ body->set_state(PhysicsServer2D::BODY_STATE_TRANSFORM, p_transform);
+}
+
+Transform2D GodotPhysicsDirectBodyState2D::get_transform() const {
+ return body->get_transform();
+}
+
+Vector2 GodotPhysicsDirectBodyState2D::get_velocity_at_local_position(const Vector2 &p_position) const {
+ return body->get_velocity_in_local_point(p_position);
+}
+
+void GodotPhysicsDirectBodyState2D::apply_central_impulse(const Vector2 &p_impulse) {
+ body->wakeup();
+ body->apply_central_impulse(p_impulse);
+}
+
+void GodotPhysicsDirectBodyState2D::apply_impulse(const Vector2 &p_impulse, const Vector2 &p_position) {
+ body->wakeup();
+ body->apply_impulse(p_impulse, p_position);
+}
+
+void GodotPhysicsDirectBodyState2D::apply_torque_impulse(real_t p_torque) {
+ body->wakeup();
+ body->apply_torque_impulse(p_torque);
+}
+
+void GodotPhysicsDirectBodyState2D::apply_central_force(const Vector2 &p_force) {
+ body->wakeup();
+ body->apply_central_force(p_force);
+}
+
+void GodotPhysicsDirectBodyState2D::apply_force(const Vector2 &p_force, const Vector2 &p_position) {
+ body->wakeup();
+ body->apply_force(p_force, p_position);
+}
+
+void GodotPhysicsDirectBodyState2D::apply_torque(real_t p_torque) {
+ body->wakeup();
+ body->apply_torque(p_torque);
+}
+
+void GodotPhysicsDirectBodyState2D::add_constant_central_force(const Vector2 &p_force) {
+ body->wakeup();
+ body->add_constant_central_force(p_force);
+}
+
+void GodotPhysicsDirectBodyState2D::add_constant_force(const Vector2 &p_force, const Vector2 &p_position) {
+ body->wakeup();
+ body->add_constant_force(p_force, p_position);
+}
+
+void GodotPhysicsDirectBodyState2D::add_constant_torque(real_t p_torque) {
+ body->wakeup();
+ body->add_constant_torque(p_torque);
+}
+
+void GodotPhysicsDirectBodyState2D::set_constant_force(const Vector2 &p_force) {
+ if (!p_force.is_equal_approx(Vector2())) {
+ body->wakeup();
+ }
+ body->set_constant_force(p_force);
+}
+
+Vector2 GodotPhysicsDirectBodyState2D::get_constant_force() const {
+ return body->get_constant_force();
+}
+
+void GodotPhysicsDirectBodyState2D::set_constant_torque(real_t p_torque) {
+ if (!Math::is_zero_approx(p_torque)) {
+ body->wakeup();
+ }
+ body->set_constant_torque(p_torque);
+}
+
+real_t GodotPhysicsDirectBodyState2D::get_constant_torque() const {
+ return body->get_constant_torque();
+}
+
+void GodotPhysicsDirectBodyState2D::set_sleep_state(bool p_enable) {
+ body->set_active(!p_enable);
+}
+
+bool GodotPhysicsDirectBodyState2D::is_sleeping() const {
+ return !body->is_active();
+}
+
+int GodotPhysicsDirectBodyState2D::get_contact_count() const {
+ return body->contact_count;
+}
+
+Vector2 GodotPhysicsDirectBodyState2D::get_contact_local_position(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector2());
+ return body->contacts[p_contact_idx].local_pos;
+}
+
+Vector2 GodotPhysicsDirectBodyState2D::get_contact_local_normal(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector2());
+ return body->contacts[p_contact_idx].local_normal;
+}
+
+int GodotPhysicsDirectBodyState2D::get_contact_local_shape(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, -1);
+ return body->contacts[p_contact_idx].local_shape;
+}
+
+RID GodotPhysicsDirectBodyState2D::get_contact_collider(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, RID());
+ return body->contacts[p_contact_idx].collider;
+}
+Vector2 GodotPhysicsDirectBodyState2D::get_contact_collider_position(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector2());
+ return body->contacts[p_contact_idx].collider_pos;
+}
+
+ObjectID GodotPhysicsDirectBodyState2D::get_contact_collider_id(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, ObjectID());
+ return body->contacts[p_contact_idx].collider_instance_id;
+}
+
+int GodotPhysicsDirectBodyState2D::get_contact_collider_shape(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, 0);
+ return body->contacts[p_contact_idx].collider_shape;
+}
+
+Vector2 GodotPhysicsDirectBodyState2D::get_contact_collider_velocity_at_position(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector2());
+ return body->contacts[p_contact_idx].collider_velocity_at_pos;
+}
+
+PhysicsDirectSpaceState2D *GodotPhysicsDirectBodyState2D::get_space_state() {
+ return body->get_space()->get_direct_state();
+}
+
+real_t GodotPhysicsDirectBodyState2D::get_step() const {
+ return body->get_space()->get_last_step();
+}
diff --git a/servers/physics_2d/godot_body_direct_state_2d.h b/servers/physics_2d/godot_body_direct_state_2d.h
new file mode 100644
index 0000000000..a2c0a87989
--- /dev/null
+++ b/servers/physics_2d/godot_body_direct_state_2d.h
@@ -0,0 +1,103 @@
+/*************************************************************************/
+/* godot_body_direct_state_2d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 GODOT_BODY_DIRECT_STATE_2D_H
+#define GODOT_BODY_DIRECT_STATE_2D_H
+
+#include "servers/physics_server_2d.h"
+
+class GodotBody2D;
+
+class GodotPhysicsDirectBodyState2D : public PhysicsDirectBodyState2D {
+ GDCLASS(GodotPhysicsDirectBodyState2D, PhysicsDirectBodyState2D);
+
+public:
+ GodotBody2D *body = nullptr;
+
+ virtual Vector2 get_total_gravity() const override;
+ virtual real_t get_total_angular_damp() const override;
+ virtual real_t get_total_linear_damp() const override;
+
+ virtual Vector2 get_center_of_mass() const override;
+ virtual Vector2 get_center_of_mass_local() const override;
+ virtual real_t get_inverse_mass() const override;
+ virtual real_t get_inverse_inertia() const override;
+
+ virtual void set_linear_velocity(const Vector2 &p_velocity) override;
+ virtual Vector2 get_linear_velocity() const override;
+
+ virtual void set_angular_velocity(real_t p_velocity) override;
+ virtual real_t get_angular_velocity() const override;
+
+ virtual void set_transform(const Transform2D &p_transform) override;
+ virtual Transform2D get_transform() const override;
+
+ virtual Vector2 get_velocity_at_local_position(const Vector2 &p_position) const override;
+
+ virtual void apply_central_impulse(const Vector2 &p_impulse) override;
+ virtual void apply_impulse(const Vector2 &p_impulse, const Vector2 &p_position = Vector2()) override;
+ virtual void apply_torque_impulse(real_t p_torque) override;
+
+ virtual void apply_central_force(const Vector2 &p_force) override;
+ virtual void apply_force(const Vector2 &p_force, const Vector2 &p_position = Vector2()) override;
+ virtual void apply_torque(real_t p_torque) override;
+
+ virtual void add_constant_central_force(const Vector2 &p_force) override;
+ virtual void add_constant_force(const Vector2 &p_force, const Vector2 &p_position = Vector2()) override;
+ virtual void add_constant_torque(real_t p_torque) override;
+
+ virtual void set_constant_force(const Vector2 &p_force) override;
+ virtual Vector2 get_constant_force() const override;
+
+ virtual void set_constant_torque(real_t p_torque) override;
+ virtual real_t get_constant_torque() const override;
+
+ virtual void set_sleep_state(bool p_enable) override;
+ virtual bool is_sleeping() const override;
+
+ virtual int get_contact_count() const override;
+
+ virtual Vector2 get_contact_local_position(int p_contact_idx) const override;
+ virtual Vector2 get_contact_local_normal(int p_contact_idx) const override;
+ virtual int get_contact_local_shape(int p_contact_idx) const override;
+
+ virtual RID get_contact_collider(int p_contact_idx) const override;
+ virtual Vector2 get_contact_collider_position(int p_contact_idx) const override;
+ virtual ObjectID get_contact_collider_id(int p_contact_idx) const override;
+ virtual int get_contact_collider_shape(int p_contact_idx) const override;
+
+ virtual Vector2 get_contact_collider_velocity_at_position(int p_contact_idx) const override;
+
+ virtual PhysicsDirectSpaceState2D *get_space_state() override;
+
+ virtual real_t get_step() const override;
+};
+
+#endif // GODOT_BODY_DIRECT_STATE_2D_H
diff --git a/servers/physics_2d/body_pair_2d_sw.cpp b/servers/physics_2d/godot_body_pair_2d.cpp
index feced36a2b..2f2af15da7 100644
--- a/servers/physics_2d/body_pair_2d_sw.cpp
+++ b/servers/physics_2d/godot_body_pair_2d.cpp
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* body_pair_2d_sw.cpp */
+/* godot_body_pair_2d.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -28,22 +28,23 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "body_pair_2d_sw.h"
-#include "collision_solver_2d_sw.h"
-#include "space_2d_sw.h"
+#include "godot_body_pair_2d.h"
+
+#include "godot_collision_solver_2d.h"
+#include "godot_space_2d.h"
-#define POSITION_CORRECTION
#define ACCUMULATE_IMPULSES
-void BodyPair2DSW::_add_contact(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_self) {
- BodyPair2DSW *self = (BodyPair2DSW *)p_self;
+#define MIN_VELOCITY 0.001
+#define MAX_BIAS_ROTATION (Math_PI / 8)
+
+void GodotBodyPair2D::_add_contact(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_self) {
+ GodotBodyPair2D *self = static_cast<GodotBodyPair2D *>(p_self);
self->_contact_added_callback(p_point_A, p_point_B);
}
-void BodyPair2DSW::_contact_added_callback(const Vector2 &p_point_A, const Vector2 &p_point_B) {
- // check if we already have the contact
-
+void GodotBodyPair2D::_contact_added_callback(const Vector2 &p_point_A, const Vector2 &p_point_B) {
Vector2 local_A = A->get_inv_transform().basis_xform(p_point_A);
Vector2 local_B = B->get_inv_transform().basis_xform(p_point_B - offset_B);
@@ -52,45 +53,50 @@ void BodyPair2DSW::_contact_added_callback(const Vector2 &p_point_A, const Vecto
ERR_FAIL_COND(new_index >= (MAX_CONTACTS + 1));
Contact contact;
-
- contact.acc_normal_impulse = 0;
- contact.acc_bias_impulse = 0;
- contact.acc_tangent_impulse = 0;
contact.local_A = local_A;
contact.local_B = local_B;
- contact.reused = true;
contact.normal = (p_point_A - p_point_B).normalized();
- contact.mass_normal = 0; // will be computed in setup()
-
- // attempt to determine if the contact will be reused
+ contact.used = true;
+ // Attempt to determine if the contact will be reused.
real_t recycle_radius_2 = space->get_contact_recycle_radius() * space->get_contact_recycle_radius();
for (int i = 0; i < contact_count; i++) {
Contact &c = contacts[i];
- if (
- c.local_A.distance_squared_to(local_A) < (recycle_radius_2) &&
+ if (c.local_A.distance_squared_to(local_A) < (recycle_radius_2) &&
c.local_B.distance_squared_to(local_B) < (recycle_radius_2)) {
contact.acc_normal_impulse = c.acc_normal_impulse;
contact.acc_tangent_impulse = c.acc_tangent_impulse;
contact.acc_bias_impulse = c.acc_bias_impulse;
- new_index = i;
- break;
+ contact.acc_bias_impulse_center_of_mass = c.acc_bias_impulse_center_of_mass;
+ c = contact;
+ return;
}
}
- // figure out if the contact amount must be reduced to fit the new contact
-
+ // Figure out if the contact amount must be reduced to fit the new contact.
if (new_index == MAX_CONTACTS) {
- // remove the contact with the minimum depth
+ // Remove the contact with the minimum depth.
+
+ const Transform2D &transform_A = A->get_transform();
+ const Transform2D &transform_B = B->get_transform();
int least_deep = -1;
- real_t min_depth = 1e10;
+ real_t min_depth;
+
+ // Start with depth for new contact.
+ {
+ Vector2 global_A = transform_A.basis_xform(contact.local_A);
+ Vector2 global_B = transform_B.basis_xform(contact.local_B) + offset_B;
+
+ Vector2 axis = global_A - global_B;
+ min_depth = axis.dot(contact.normal);
+ }
- for (int i = 0; i <= contact_count; i++) {
- Contact &c = (i == contact_count) ? contact : contacts[i];
- Vector2 global_A = A->get_transform().basis_xform(c.local_A);
- Vector2 global_B = B->get_transform().basis_xform(c.local_B) + offset_B;
+ for (int i = 0; i < contact_count; i++) {
+ const Contact &c = contacts[i];
+ Vector2 global_A = transform_A.basis_xform(c.local_A);
+ Vector2 global_B = transform_B.basis_xform(c.local_B) + offset_B;
Vector2 axis = global_A - global_B;
real_t depth = axis.dot(c.normal);
@@ -101,10 +107,8 @@ void BodyPair2DSW::_contact_added_callback(const Vector2 &p_point_A, const Vecto
}
}
- ERR_FAIL_COND(least_deep == -1);
-
- if (least_deep < contact_count) { //replace the last deep contact by the new one
-
+ if (least_deep > -1) {
+ // Replace the least deep contact by the new one.
contacts[least_deep] = contact;
}
@@ -112,30 +116,29 @@ void BodyPair2DSW::_contact_added_callback(const Vector2 &p_point_A, const Vecto
}
contacts[new_index] = contact;
-
- if (new_index == contact_count) {
- contact_count++;
- }
+ contact_count++;
}
-void BodyPair2DSW::_validate_contacts() {
- //make sure to erase contacts that are no longer valid
-
+void GodotBodyPair2D::_validate_contacts() {
+ // Make sure to erase contacts that are no longer valid.
real_t max_separation = space->get_contact_max_separation();
real_t max_separation2 = max_separation * max_separation;
+ const Transform2D &transform_A = A->get_transform();
+ const Transform2D &transform_B = B->get_transform();
+
for (int i = 0; i < contact_count; i++) {
Contact &c = contacts[i];
bool erase = false;
- if (!c.reused) {
- //was left behind in previous frame
+ if (!c.used) {
+ // Was left behind in previous frame.
erase = true;
} else {
- c.reused = false;
+ c.used = false;
- Vector2 global_A = A->get_transform().basis_xform(c.local_A);
- Vector2 global_B = B->get_transform().basis_xform(c.local_B) + offset_B;
+ Vector2 global_A = transform_A.basis_xform(c.local_A);
+ Vector2 global_B = transform_B.basis_xform(c.local_B) + offset_B;
Vector2 axis = global_A - global_B;
real_t depth = axis.dot(c.normal);
@@ -145,10 +148,10 @@ void BodyPair2DSW::_validate_contacts() {
}
if (erase) {
- // contact no longer needed, remove
+ // Contact no longer needed, remove.
if ((i + 1) < contact_count) {
- // swap with the last one
+ // Swap with the last one.
SWAP(contacts[i], contacts[contact_count - 1]);
}
@@ -158,7 +161,7 @@ void BodyPair2DSW::_validate_contacts() {
}
}
-bool BodyPair2DSW::_test_ccd(real_t p_step, Body2DSW *p_A, int p_shape_A, const Transform2D &p_xform_A, Body2DSW *p_B, int p_shape_B, const Transform2D &p_xform_B, bool p_swap_result) {
+bool GodotBodyPair2D::_test_ccd(real_t p_step, GodotBody2D *p_A, int p_shape_A, const Transform2D &p_xform_A, GodotBody2D *p_B, int p_shape_B, const Transform2D &p_xform_B) {
Vector2 motion = p_A->get_linear_velocity() * p_step;
real_t mlen = motion.length();
if (mlen < CMP_EPSILON) {
@@ -169,14 +172,18 @@ bool BodyPair2DSW::_test_ccd(real_t p_step, Body2DSW *p_A, int p_shape_A, const
real_t min, max;
p_A->get_shape(p_shape_A)->project_rangev(mnormal, p_xform_A, min, max);
- bool fast_object = mlen > (max - min) * 0.3; //going too fast in that direction
- if (!fast_object) { //did it move enough in this direction to even attempt raycast? let's say it should move more than 1/3 the size of the object in that axis
+ // Did it move enough in this direction to even attempt raycast?
+ // Let's say it should move more than 1/3 the size of the object in that axis.
+ bool fast_object = mlen > (max - min) * 0.3;
+ if (!fast_object) {
return false;
}
- //cast a segment from support in motion normal, in the same direction of motion by motion length
- //support is the worst case collision point, so real collision happened before
+ // Going too fast in that direction.
+
+ // Cast a segment from support in motion normal, in the same direction of motion by motion length.
+ // Support is the worst case collision point, so real collision happened before.
int a;
Vector2 s[2];
p_A->get_shape(p_shape_A)->get_supports(p_xform_A.basis_xform(mnormal).normalized(), s, a);
@@ -185,7 +192,8 @@ bool BodyPair2DSW::_test_ccd(real_t p_step, Body2DSW *p_A, int p_shape_A, const
Transform2D from_inv = p_xform_B.affine_inverse();
- Vector2 local_from = from_inv.xform(from - mnormal * mlen * 0.1); //start from a little inside the bounding box
+ // Start from a little inside the bounding box.
+ Vector2 local_from = from_inv.xform(from - mnormal * mlen * 0.1);
Vector2 local_to = from_inv.xform(to);
Vector2 rpos, rnorm;
@@ -193,42 +201,53 @@ bool BodyPair2DSW::_test_ccd(real_t p_step, Body2DSW *p_A, int p_shape_A, const
return false;
}
- //ray hit something
+ // Check one-way collision based on motion direction.
+ if (p_A->get_shape(p_shape_A)->allows_one_way_collision() && p_B->is_shape_set_as_one_way_collision(p_shape_B)) {
+ Vector2 direction = p_xform_B.columns[1].normalized();
+ if (direction.dot(mnormal) < CMP_EPSILON) {
+ collided = false;
+ oneway_disabled = true;
+ return false;
+ }
+ }
+ // Shorten the linear velocity so it does not hit, but gets close enough,
+ // next frame will hit softly or soft enough.
Vector2 hitpos = p_xform_B.xform(rpos);
- Vector2 contact_A = to;
- Vector2 contact_B = hitpos;
-
- //create a contact
-
- if (p_swap_result) {
- _contact_added_callback(contact_B, contact_A);
- } else {
- _contact_added_callback(contact_A, contact_B);
- }
+ real_t newlen = hitpos.distance_to(from) - (max - min) * 0.01;
+ p_A->set_linear_velocity(mnormal * (newlen / p_step));
return true;
}
-real_t combine_bounce(Body2DSW *A, Body2DSW *B) {
+real_t combine_bounce(GodotBody2D *A, GodotBody2D *B) {
return CLAMP(A->get_bounce() + B->get_bounce(), 0, 1);
}
-real_t combine_friction(Body2DSW *A, Body2DSW *B) {
+real_t combine_friction(GodotBody2D *A, GodotBody2D *B) {
return ABS(MIN(A->get_friction(), B->get_friction()));
}
-bool BodyPair2DSW::setup(real_t p_step) {
- //cannot collide
- if (!A->test_collision_mask(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self()) || (A->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC && B->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC && A->get_max_contacts_reported() == 0 && B->get_max_contacts_reported() == 0)) {
+bool GodotBodyPair2D::setup(real_t p_step) {
+ check_ccd = false;
+
+ if (!A->interacts_with(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self())) {
collided = false;
return false;
}
- if (A->is_shape_set_as_disabled(shape_A) || B->is_shape_set_as_disabled(shape_B)) {
- collided = false;
- return false;
+ collide_A = (A->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC) && A->collides_with(B);
+ collide_B = (B->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC) && B->collides_with(A);
+
+ report_contacts_only = false;
+ if (!collide_A && !collide_B) {
+ if ((A->get_max_contacts_reported() > 0) || (B->get_max_contacts_reported() > 0)) {
+ report_contacts_only = true;
+ } else {
+ collided = false;
+ return false;
+ }
}
//use local A coordinates to avoid numerical issues on collision detection
@@ -236,16 +255,16 @@ bool BodyPair2DSW::setup(real_t p_step) {
_validate_contacts();
- Vector2 offset_A = A->get_transform().get_origin();
+ const Vector2 &offset_A = A->get_transform().get_origin();
Transform2D xform_Au = A->get_transform().untranslated();
Transform2D xform_A = xform_Au * A->get_shape_transform(shape_A);
Transform2D xform_Bu = B->get_transform();
- xform_Bu.elements[2] -= A->get_transform().get_origin();
+ xform_Bu.columns[2] -= offset_A;
Transform2D xform_B = xform_Bu * B->get_shape_transform(shape_B);
- Shape2DSW *shape_A_ptr = A->get_shape(shape_A);
- Shape2DSW *shape_B_ptr = B->get_shape(shape_B);
+ GodotShape2D *shape_A_ptr = A->get_shape(shape_A);
+ GodotShape2D *shape_B_ptr = B->get_shape(shape_B);
Vector2 motion_A, motion_B;
@@ -258,26 +277,21 @@ bool BodyPair2DSW::setup(real_t p_step) {
bool prev_collided = collided;
- collided = CollisionSolver2DSW::solve(shape_A_ptr, xform_A, motion_A, shape_B_ptr, xform_B, motion_B, _add_contact, this, &sep_axis);
+ collided = GodotCollisionSolver2D::solve(shape_A_ptr, xform_A, motion_A, shape_B_ptr, xform_B, motion_B, _add_contact, this, &sep_axis);
if (!collided) {
- //test ccd (currently just a raycast)
+ oneway_disabled = false;
- if (A->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_RAY && A->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC) {
- if (_test_ccd(p_step, A, shape_A, xform_A, B, shape_B, xform_B)) {
- collided = true;
- }
+ if (A->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_RAY && collide_A) {
+ check_ccd = true;
+ return true;
}
- if (B->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_RAY && B->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC) {
- if (_test_ccd(p_step, B, shape_B, xform_B, A, shape_A, xform_A, true)) {
- collided = true;
- }
+ if (B->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_RAY && collide_B) {
+ check_ccd = true;
+ return true;
}
- if (!collided) {
- oneway_disabled = false;
- return false;
- }
+ return false;
}
if (oneway_disabled) {
@@ -285,15 +299,12 @@ bool BodyPair2DSW::setup(real_t p_step) {
}
if (!prev_collided) {
- if (A->is_shape_set_as_one_way_collision(shape_A)) {
- Vector2 direction = xform_A.get_axis(1).normalized();
+ if (shape_B_ptr->allows_one_way_collision() && A->is_shape_set_as_one_way_collision(shape_A)) {
+ Vector2 direction = xform_A.columns[1].normalized();
bool valid = false;
for (int i = 0; i < contact_count; i++) {
Contact &c = contacts[i];
- if (!c.reused) {
- continue;
- }
- if (c.normal.dot(direction) > -CMP_EPSILON) { //greater (normal inverted)
+ if (c.normal.dot(direction) > -CMP_EPSILON) { // Greater (normal inverted).
continue;
}
valid = true;
@@ -306,15 +317,12 @@ bool BodyPair2DSW::setup(real_t p_step) {
}
}
- if (B->is_shape_set_as_one_way_collision(shape_B)) {
- Vector2 direction = xform_B.get_axis(1).normalized();
+ if (shape_A_ptr->allows_one_way_collision() && B->is_shape_set_as_one_way_collision(shape_B)) {
+ Vector2 direction = xform_B.columns[1].normalized();
bool valid = false;
for (int i = 0; i < contact_count; i++) {
Contact &c = contacts[i];
- if (!c.reused) {
- continue;
- }
- if (c.normal.dot(direction) < CMP_EPSILON) { //less (normal ok)
+ if (c.normal.dot(direction) < CMP_EPSILON) { // Less (normal ok).
continue;
}
valid = true;
@@ -328,9 +336,43 @@ bool BodyPair2DSW::setup(real_t p_step) {
}
}
+ return true;
+}
+
+bool GodotBodyPair2D::pre_solve(real_t p_step) {
+ if (oneway_disabled) {
+ return false;
+ }
+
+ if (!collided) {
+ if (check_ccd) {
+ const Vector2 &offset_A = A->get_transform().get_origin();
+ Transform2D xform_Au = A->get_transform().untranslated();
+ Transform2D xform_A = xform_Au * A->get_shape_transform(shape_A);
+
+ Transform2D xform_Bu = B->get_transform();
+ xform_Bu.columns[2] -= offset_A;
+ Transform2D xform_B = xform_Bu * B->get_shape_transform(shape_B);
+
+ if (A->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_RAY && collide_A) {
+ _test_ccd(p_step, A, shape_A, xform_A, B, shape_B, xform_B);
+ }
+
+ if (B->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_RAY && collide_B) {
+ _test_ccd(p_step, B, shape_B, xform_B, A, shape_A, xform_A);
+ }
+ }
+
+ return false;
+ }
+
real_t max_penetration = space->get_contact_max_allowed_penetration();
- real_t bias = 0.3;
+ real_t bias = space->get_contact_bias();
+
+ GodotShape2D *shape_A_ptr = A->get_shape(shape_A);
+ GodotShape2D *shape_B_ptr = B->get_shape(shape_B);
+
if (shape_A_ptr->get_custom_bias() || shape_B_ptr->get_custom_bias()) {
if (shape_A_ptr->get_custom_bias() == 0) {
bias = shape_B_ptr->get_custom_bias();
@@ -341,56 +383,55 @@ bool BodyPair2DSW::setup(real_t p_step) {
}
}
- cc = 0;
-
real_t inv_dt = 1.0 / p_step;
bool do_process = false;
+ const Vector2 &offset_A = A->get_transform().get_origin();
+ const Transform2D &transform_A = A->get_transform();
+ const Transform2D &transform_B = B->get_transform();
+
+ real_t inv_inertia_A = collide_A ? A->get_inv_inertia() : 0.0;
+ real_t inv_inertia_B = collide_B ? B->get_inv_inertia() : 0.0;
+
+ real_t inv_mass_A = collide_A ? A->get_inv_mass() : 0.0;
+ real_t inv_mass_B = collide_B ? B->get_inv_mass() : 0.0;
+
for (int i = 0; i < contact_count; i++) {
Contact &c = contacts[i];
+ c.active = false;
- Vector2 global_A = xform_Au.xform(c.local_A);
- Vector2 global_B = xform_Bu.xform(c.local_B);
+ Vector2 global_A = transform_A.basis_xform(c.local_A);
+ Vector2 global_B = transform_B.basis_xform(c.local_B) + offset_B;
- real_t depth = c.normal.dot(global_A - global_B);
+ Vector2 axis = global_A - global_B;
+ real_t depth = axis.dot(c.normal);
- if (depth <= 0 || !c.reused) {
- c.active = false;
+ if (depth <= 0.0) {
continue;
}
- c.active = true;
#ifdef DEBUG_ENABLED
if (space->is_debugging_contacts()) {
space->add_debug_contact(global_A + offset_A);
space->add_debug_contact(global_B + offset_A);
}
#endif
- int gather_A = A->can_report_contacts();
- int gather_B = B->can_report_contacts();
-
- c.rA = global_A;
- c.rB = global_B - offset_B;
- if (gather_A | gather_B) {
- //Vector2 crB( -B->get_angular_velocity() * c.rB.y, B->get_angular_velocity() * c.rB.x );
+ c.rA = global_A - A->get_center_of_mass();
+ c.rB = global_B - B->get_center_of_mass() - offset_B;
- global_A += offset_A;
- global_B += offset_A;
+ if (A->can_report_contacts()) {
+ Vector2 crB(-B->get_angular_velocity() * c.rB.y, B->get_angular_velocity() * c.rB.x);
+ A->add_contact(global_A + offset_A, -c.normal, depth, shape_A, global_B + offset_A, shape_B, B->get_instance_id(), B->get_self(), crB + B->get_linear_velocity());
+ }
- if (gather_A) {
- Vector2 crB(-B->get_angular_velocity() * c.rB.y, B->get_angular_velocity() * c.rB.x);
- A->add_contact(global_A, -c.normal, depth, shape_A, global_B, shape_B, B->get_instance_id(), B->get_self(), crB + B->get_linear_velocity());
- }
- if (gather_B) {
- Vector2 crA(-A->get_angular_velocity() * c.rA.y, A->get_angular_velocity() * c.rA.x);
- B->add_contact(global_B, c.normal, depth, shape_B, global_A, shape_A, A->get_instance_id(), A->get_self(), crA + A->get_linear_velocity());
- }
+ if (B->can_report_contacts()) {
+ Vector2 crA(-A->get_angular_velocity() * c.rA.y, A->get_angular_velocity() * c.rA.x);
+ B->add_contact(global_B + offset_A, c.normal, depth, shape_B, global_A + offset_A, shape_A, A->get_instance_id(), A->get_self(), crA + A->get_linear_velocity());
}
- if ((A->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC && B->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC)) {
- c.active = false;
+ if (report_contacts_only) {
collided = false;
continue;
}
@@ -398,53 +439,61 @@ bool BodyPair2DSW::setup(real_t p_step) {
// Precompute normal mass, tangent mass, and bias.
real_t rnA = c.rA.dot(c.normal);
real_t rnB = c.rB.dot(c.normal);
- real_t kNormal = A->get_inv_mass() + B->get_inv_mass();
- kNormal += A->get_inv_inertia() * (c.rA.dot(c.rA) - rnA * rnA) + B->get_inv_inertia() * (c.rB.dot(c.rB) - rnB * rnB);
+ real_t kNormal = inv_mass_A + inv_mass_B;
+ kNormal += inv_inertia_A * (c.rA.dot(c.rA) - rnA * rnA) + inv_inertia_B * (c.rB.dot(c.rB) - rnB * rnB);
c.mass_normal = 1.0f / kNormal;
Vector2 tangent = c.normal.orthogonal();
real_t rtA = c.rA.dot(tangent);
real_t rtB = c.rB.dot(tangent);
- real_t kTangent = A->get_inv_mass() + B->get_inv_mass();
- kTangent += A->get_inv_inertia() * (c.rA.dot(c.rA) - rtA * rtA) + B->get_inv_inertia() * (c.rB.dot(c.rB) - rtB * rtB);
+ real_t kTangent = inv_mass_A + inv_mass_B;
+ kTangent += inv_inertia_A * (c.rA.dot(c.rA) - rtA * rtA) + inv_inertia_B * (c.rB.dot(c.rB) - rtB * rtB);
c.mass_tangent = 1.0f / kTangent;
c.bias = -bias * inv_dt * MIN(0.0f, -depth + max_penetration);
c.depth = depth;
- //c.acc_bias_impulse=0;
#ifdef ACCUMULATE_IMPULSES
{
// Apply normal + friction impulse
Vector2 P = c.acc_normal_impulse * c.normal + c.acc_tangent_impulse * tangent;
- A->apply_impulse(-P, c.rA);
- B->apply_impulse(P, c.rB);
+ if (collide_A) {
+ A->apply_impulse(-P, c.rA + A->get_center_of_mass());
+ }
+ if (collide_B) {
+ B->apply_impulse(P, c.rB + B->get_center_of_mass());
+ }
}
#endif
c.bounce = combine_bounce(A, B);
if (c.bounce) {
- Vector2 crA(-A->get_angular_velocity() * c.rA.y, A->get_angular_velocity() * c.rA.x);
- Vector2 crB(-B->get_angular_velocity() * c.rB.y, B->get_angular_velocity() * c.rB.x);
- Vector2 dv = B->get_linear_velocity() + crB - A->get_linear_velocity() - crA;
+ Vector2 crA(-A->get_prev_angular_velocity() * c.rA.y, A->get_prev_angular_velocity() * c.rA.x);
+ Vector2 crB(-B->get_prev_angular_velocity() * c.rB.y, B->get_prev_angular_velocity() * c.rB.x);
+ Vector2 dv = B->get_prev_linear_velocity() + crB - A->get_prev_linear_velocity() - crA;
c.bounce = c.bounce * dv.dot(c.normal);
}
+ c.active = true;
do_process = true;
}
return do_process;
}
-void BodyPair2DSW::solve(real_t p_step) {
- if (!collided) {
+void GodotBodyPair2D::solve(real_t p_step) {
+ if (!collided || oneway_disabled) {
return;
}
+ const real_t max_bias_av = MAX_BIAS_ROTATION / p_step;
+
+ real_t inv_mass_A = collide_A ? A->get_inv_mass() : 0.0;
+ real_t inv_mass_B = collide_B ? B->get_inv_mass() : 0.0;
+
for (int i = 0; i < contact_count; ++i) {
Contact &c = contacts[i];
- cc++;
if (!c.active) {
continue;
@@ -462,6 +511,7 @@ void BodyPair2DSW::solve(real_t p_step) {
real_t vn = dv.dot(c.normal);
real_t vbn = dbv.dot(c.normal);
+
Vector2 tangent = c.normal.orthogonal();
real_t vt = dv.dot(tangent);
@@ -471,8 +521,33 @@ void BodyPair2DSW::solve(real_t p_step) {
Vector2 jb = c.normal * (c.acc_bias_impulse - jbnOld);
- A->apply_bias_impulse(-jb, c.rA);
- B->apply_bias_impulse(jb, c.rB);
+ if (collide_A) {
+ A->apply_bias_impulse(-jb, c.rA + A->get_center_of_mass(), max_bias_av);
+ }
+ if (collide_B) {
+ B->apply_bias_impulse(jb, c.rB + B->get_center_of_mass(), max_bias_av);
+ }
+
+ crbA = Vector2(-A->get_biased_angular_velocity() * c.rA.y, A->get_biased_angular_velocity() * c.rA.x);
+ crbB = Vector2(-B->get_biased_angular_velocity() * c.rB.y, B->get_biased_angular_velocity() * c.rB.x);
+ dbv = B->get_biased_linear_velocity() + crbB - A->get_biased_linear_velocity() - crbA;
+
+ vbn = dbv.dot(c.normal);
+
+ if (Math::abs(-vbn + c.bias) > MIN_VELOCITY) {
+ real_t jbn_com = (-vbn + c.bias) / (inv_mass_A + inv_mass_B);
+ real_t jbnOld_com = c.acc_bias_impulse_center_of_mass;
+ c.acc_bias_impulse_center_of_mass = MAX(jbnOld_com + jbn_com, 0.0f);
+
+ Vector2 jb_com = c.normal * (c.acc_bias_impulse_center_of_mass - jbnOld_com);
+
+ if (collide_A) {
+ A->apply_bias_impulse(-jb_com, A->get_center_of_mass(), 0.0f);
+ }
+ if (collide_B) {
+ B->apply_bias_impulse(jb_com, B->get_center_of_mass(), 0.0f);
+ }
+ }
real_t jn = -(c.bounce + vn) * c.mass_normal;
real_t jnOld = c.acc_normal_impulse;
@@ -487,13 +562,17 @@ void BodyPair2DSW::solve(real_t p_step) {
Vector2 j = c.normal * (c.acc_normal_impulse - jnOld) + tangent * (c.acc_tangent_impulse - jtOld);
- A->apply_impulse(-j, c.rA);
- B->apply_impulse(j, c.rB);
+ if (collide_A) {
+ A->apply_impulse(-j, c.rA + A->get_center_of_mass());
+ }
+ if (collide_B) {
+ B->apply_impulse(j, c.rB + B->get_center_of_mass());
+ }
}
}
-BodyPair2DSW::BodyPair2DSW(Body2DSW *p_A, int p_shape_A, Body2DSW *p_B, int p_shape_B) :
- Constraint2DSW(_arr, 2) {
+GodotBodyPair2D::GodotBodyPair2D(GodotBody2D *p_A, int p_shape_A, GodotBody2D *p_B, int p_shape_B) :
+ GodotConstraint2D(_arr, 2) {
A = p_A;
B = p_B;
shape_A = p_shape_A;
@@ -501,12 +580,9 @@ BodyPair2DSW::BodyPair2DSW(Body2DSW *p_A, int p_shape_A, Body2DSW *p_B, int p_sh
space = A->get_space();
A->add_constraint(this, 0);
B->add_constraint(this, 1);
- contact_count = 0;
- collided = false;
- oneway_disabled = false;
}
-BodyPair2DSW::~BodyPair2DSW() {
+GodotBodyPair2D::~GodotBodyPair2D() {
A->remove_constraint(this, 0);
B->remove_constraint(this, 1);
}
diff --git a/servers/physics_2d/body_pair_2d_sw.h b/servers/physics_2d/godot_body_pair_2d.h
index 31ab9b9017..1c0f61be26 100644
--- a/servers/physics_2d/body_pair_2d_sw.h
+++ b/servers/physics_2d/godot_body_pair_2d.h
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* body_pair_2d_sw.h */
+/* godot_body_pair_2d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -28,67 +28,73 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef BODY_PAIR_2D_SW_H
-#define BODY_PAIR_2D_SW_H
+#ifndef GODOT_BODY_PAIR_2D_H
+#define GODOT_BODY_PAIR_2D_H
-#include "body_2d_sw.h"
-#include "constraint_2d_sw.h"
+#include "godot_body_2d.h"
+#include "godot_constraint_2d.h"
-class BodyPair2DSW : public Constraint2DSW {
+class GodotBodyPair2D : public GodotConstraint2D {
enum {
MAX_CONTACTS = 2
};
union {
struct {
- Body2DSW *A;
- Body2DSW *B;
+ GodotBody2D *A;
+ GodotBody2D *B;
};
- Body2DSW *_arr[2];
+ GodotBody2D *_arr[2] = { nullptr, nullptr };
};
- int shape_A;
- int shape_B;
+ int shape_A = 0;
+ int shape_B = 0;
- Space2DSW *space;
+ bool collide_A = false;
+ bool collide_B = false;
+
+ GodotSpace2D *space = nullptr;
struct Contact {
Vector2 position;
Vector2 normal;
Vector2 local_A, local_B;
- real_t acc_normal_impulse; // accumulated normal impulse (Pn)
- real_t acc_tangent_impulse; // accumulated tangent impulse (Pt)
- real_t acc_bias_impulse; // accumulated normal impulse for position bias (Pnb)
- real_t mass_normal, mass_tangent;
- real_t bias;
+ real_t acc_normal_impulse = 0.0; // accumulated normal impulse (Pn)
+ real_t acc_tangent_impulse = 0.0; // accumulated tangent impulse (Pt)
+ real_t acc_bias_impulse = 0.0; // accumulated normal impulse for position bias (Pnb)
+ real_t acc_bias_impulse_center_of_mass = 0.0; // accumulated normal impulse for position bias applied to com
+ real_t mass_normal, mass_tangent = 0.0;
+ real_t bias = 0.0;
- real_t depth;
- bool active;
+ real_t depth = 0.0;
+ bool active = false;
+ bool used = false;
Vector2 rA, rB;
- bool reused;
- real_t bounce;
+ real_t bounce = 0.0;
};
Vector2 offset_B; //use local A coordinates to avoid numerical issues on collision detection
Vector2 sep_axis;
Contact contacts[MAX_CONTACTS];
- int contact_count;
- bool collided;
- bool oneway_disabled;
- int cc;
+ int contact_count = 0;
+ bool collided = false;
+ bool check_ccd = false;
+ bool oneway_disabled = false;
+ bool report_contacts_only = false;
- bool _test_ccd(real_t p_step, Body2DSW *p_A, int p_shape_A, const Transform2D &p_xform_A, Body2DSW *p_B, int p_shape_B, const Transform2D &p_xform_B, bool p_swap_result = false);
+ bool _test_ccd(real_t p_step, GodotBody2D *p_A, int p_shape_A, const Transform2D &p_xform_A, GodotBody2D *p_B, int p_shape_B, const Transform2D &p_xform_B);
void _validate_contacts();
static void _add_contact(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_self);
_FORCE_INLINE_ void _contact_added_callback(const Vector2 &p_point_A, const Vector2 &p_point_B);
public:
- bool setup(real_t p_step);
- void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual bool pre_solve(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
- BodyPair2DSW(Body2DSW *p_A, int p_shape_A, Body2DSW *p_B, int p_shape_B);
- ~BodyPair2DSW();
+ GodotBodyPair2D(GodotBody2D *p_A, int p_shape_A, GodotBody2D *p_B, int p_shape_B);
+ ~GodotBodyPair2D();
};
-#endif // BODY_PAIR_2D_SW_H
+#endif // GODOT_BODY_PAIR_2D_H
diff --git a/servers/physics_2d/broad_phase_2d_sw.cpp b/servers/physics_2d/godot_broad_phase_2d.cpp
index 7f0af48b1f..e734c24f88 100644
--- a/servers/physics_2d/broad_phase_2d_sw.cpp
+++ b/servers/physics_2d/godot_broad_phase_2d.cpp
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* broad_phase_2d_sw.cpp */
+/* godot_broad_phase_2d.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -28,9 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "broad_phase_2d_sw.h"
+#include "godot_broad_phase_2d.h"
-BroadPhase2DSW::CreateFunction BroadPhase2DSW::create_func = nullptr;
+GodotBroadPhase2D::CreateFunction GodotBroadPhase2D::create_func = nullptr;
-BroadPhase2DSW::~BroadPhase2DSW() {
+GodotBroadPhase2D::~GodotBroadPhase2D() {
}
diff --git a/servers/physics_2d/broad_phase_2d_sw.h b/servers/physics_2d/godot_broad_phase_2d.h
index d17ee6e2d6..abab087045 100644
--- a/servers/physics_2d/broad_phase_2d_sw.h
+++ b/servers/physics_2d/godot_broad_phase_2d.h
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* broad_phase_2d_sw.h */
+/* godot_broad_phase_2d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -28,44 +28,44 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef BROAD_PHASE_2D_SW_H
-#define BROAD_PHASE_2D_SW_H
+#ifndef GODOT_BROAD_PHASE_2D_H
+#define GODOT_BROAD_PHASE_2D_H
#include "core/math/math_funcs.h"
#include "core/math/rect2.h"
-class CollisionObject2DSW;
+class GodotCollisionObject2D;
-class BroadPhase2DSW {
+class GodotBroadPhase2D {
public:
- typedef BroadPhase2DSW *(*CreateFunction)();
+ typedef GodotBroadPhase2D *(*CreateFunction)();
static CreateFunction create_func;
typedef uint32_t ID;
- typedef void *(*PairCallback)(CollisionObject2DSW *A, int p_subindex_A, CollisionObject2DSW *B, int p_subindex_B, void *p_userdata);
- typedef void (*UnpairCallback)(CollisionObject2DSW *A, int p_subindex_A, CollisionObject2DSW *B, int p_subindex_B, void *p_data, void *p_userdata);
+ typedef void *(*PairCallback)(GodotCollisionObject2D *A, int p_subindex_A, GodotCollisionObject2D *B, int p_subindex_B, void *p_userdata);
+ typedef void (*UnpairCallback)(GodotCollisionObject2D *A, int p_subindex_A, GodotCollisionObject2D *B, int p_subindex_B, void *p_data, void *p_userdata);
// 0 is an invalid ID
- virtual ID create(CollisionObject2DSW *p_object_, int p_subindex = 0) = 0;
+ virtual ID create(GodotCollisionObject2D *p_object_, int p_subindex = 0, const Rect2 &p_aabb = Rect2(), bool p_static = false) = 0;
virtual void move(ID p_id, const Rect2 &p_aabb) = 0;
virtual void set_static(ID p_id, bool p_static) = 0;
virtual void remove(ID p_id) = 0;
- virtual CollisionObject2DSW *get_object(ID p_id) const = 0;
+ virtual GodotCollisionObject2D *get_object(ID p_id) const = 0;
virtual bool is_static(ID p_id) const = 0;
virtual int get_subindex(ID p_id) const = 0;
- virtual int cull_segment(const Vector2 &p_from, const Vector2 &p_to, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices = nullptr) = 0;
- virtual int cull_aabb(const Rect2 &p_aabb, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices = nullptr) = 0;
+ virtual int cull_segment(const Vector2 &p_from, const Vector2 &p_to, GodotCollisionObject2D **p_results, int p_max_results, int *p_result_indices = nullptr) = 0;
+ virtual int cull_aabb(const Rect2 &p_aabb, GodotCollisionObject2D **p_results, int p_max_results, int *p_result_indices = nullptr) = 0;
virtual void set_pair_callback(PairCallback p_pair_callback, void *p_userdata) = 0;
virtual void set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) = 0;
virtual void update() = 0;
- virtual ~BroadPhase2DSW();
+ virtual ~GodotBroadPhase2D();
};
-#endif // BROAD_PHASE_2D_SW_H
+#endif // GODOT_BROAD_PHASE_2D_H
diff --git a/servers/physics_2d/godot_broad_phase_2d_bvh.cpp b/servers/physics_2d/godot_broad_phase_2d_bvh.cpp
new file mode 100644
index 0000000000..c545fec113
--- /dev/null
+++ b/servers/physics_2d/godot_broad_phase_2d_bvh.cpp
@@ -0,0 +1,123 @@
+/*************************************************************************/
+/* godot_broad_phase_2d_bvh.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 "godot_broad_phase_2d_bvh.h"
+#include "godot_collision_object_2d.h"
+
+GodotBroadPhase2D::ID GodotBroadPhase2DBVH::create(GodotCollisionObject2D *p_object, int p_subindex, const Rect2 &p_aabb, bool p_static) {
+ uint32_t tree_id = p_static ? TREE_STATIC : TREE_DYNAMIC;
+ uint32_t tree_collision_mask = p_static ? TREE_FLAG_DYNAMIC : (TREE_FLAG_STATIC | TREE_FLAG_DYNAMIC);
+ ID oid = bvh.create(p_object, true, tree_id, tree_collision_mask, p_aabb, p_subindex); // Pair everything, don't care?
+ return oid + 1;
+}
+
+void GodotBroadPhase2DBVH::move(ID p_id, const Rect2 &p_aabb) {
+ ERR_FAIL_COND(!p_id);
+ bvh.move(p_id - 1, p_aabb);
+}
+
+void GodotBroadPhase2DBVH::set_static(ID p_id, bool p_static) {
+ ERR_FAIL_COND(!p_id);
+ uint32_t tree_id = p_static ? TREE_STATIC : TREE_DYNAMIC;
+ uint32_t tree_collision_mask = p_static ? TREE_FLAG_DYNAMIC : (TREE_FLAG_STATIC | TREE_FLAG_DYNAMIC);
+ bvh.set_tree(p_id - 1, tree_id, tree_collision_mask, false);
+}
+
+void GodotBroadPhase2DBVH::remove(ID p_id) {
+ ERR_FAIL_COND(!p_id);
+ bvh.erase(p_id - 1);
+}
+
+GodotCollisionObject2D *GodotBroadPhase2DBVH::get_object(ID p_id) const {
+ ERR_FAIL_COND_V(!p_id, nullptr);
+ GodotCollisionObject2D *it = bvh.get(p_id - 1);
+ ERR_FAIL_COND_V(!it, nullptr);
+ return it;
+}
+
+bool GodotBroadPhase2DBVH::is_static(ID p_id) const {
+ ERR_FAIL_COND_V(!p_id, false);
+ uint32_t tree_id = bvh.get_tree_id(p_id - 1);
+ return tree_id == 0;
+}
+
+int GodotBroadPhase2DBVH::get_subindex(ID p_id) const {
+ ERR_FAIL_COND_V(!p_id, 0);
+ return bvh.get_subindex(p_id - 1);
+}
+
+int GodotBroadPhase2DBVH::cull_segment(const Vector2 &p_from, const Vector2 &p_to, GodotCollisionObject2D **p_results, int p_max_results, int *p_result_indices) {
+ return bvh.cull_segment(p_from, p_to, p_results, p_max_results, nullptr, 0xFFFFFFFF, p_result_indices);
+}
+
+int GodotBroadPhase2DBVH::cull_aabb(const Rect2 &p_aabb, GodotCollisionObject2D **p_results, int p_max_results, int *p_result_indices) {
+ return bvh.cull_aabb(p_aabb, p_results, p_max_results, nullptr, 0xFFFFFFFF, p_result_indices);
+}
+
+void *GodotBroadPhase2DBVH::_pair_callback(void *self, uint32_t p_A, GodotCollisionObject2D *p_object_A, int subindex_A, uint32_t p_B, GodotCollisionObject2D *p_object_B, int subindex_B) {
+ GodotBroadPhase2DBVH *bpo = static_cast<GodotBroadPhase2DBVH *>(self);
+ if (!bpo->pair_callback) {
+ return nullptr;
+ }
+
+ return bpo->pair_callback(p_object_A, subindex_A, p_object_B, subindex_B, bpo->pair_userdata);
+}
+
+void GodotBroadPhase2DBVH::_unpair_callback(void *self, uint32_t p_A, GodotCollisionObject2D *p_object_A, int subindex_A, uint32_t p_B, GodotCollisionObject2D *p_object_B, int subindex_B, void *pairdata) {
+ GodotBroadPhase2DBVH *bpo = static_cast<GodotBroadPhase2DBVH *>(self);
+ if (!bpo->unpair_callback) {
+ return;
+ }
+
+ bpo->unpair_callback(p_object_A, subindex_A, p_object_B, subindex_B, pairdata, bpo->unpair_userdata);
+}
+
+void GodotBroadPhase2DBVH::set_pair_callback(PairCallback p_pair_callback, void *p_userdata) {
+ pair_callback = p_pair_callback;
+ pair_userdata = p_userdata;
+}
+
+void GodotBroadPhase2DBVH::set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) {
+ unpair_callback = p_unpair_callback;
+ unpair_userdata = p_userdata;
+}
+
+void GodotBroadPhase2DBVH::update() {
+ bvh.update();
+}
+
+GodotBroadPhase2D *GodotBroadPhase2DBVH::_create() {
+ return memnew(GodotBroadPhase2DBVH);
+}
+
+GodotBroadPhase2DBVH::GodotBroadPhase2DBVH() {
+ bvh.set_pair_callback(_pair_callback, this);
+ bvh.set_unpair_callback(_unpair_callback, this);
+}
diff --git a/servers/physics_2d/godot_broad_phase_2d_bvh.h b/servers/physics_2d/godot_broad_phase_2d_bvh.h
new file mode 100644
index 0000000000..512111f948
--- /dev/null
+++ b/servers/physics_2d/godot_broad_phase_2d_bvh.h
@@ -0,0 +1,101 @@
+/*************************************************************************/
+/* godot_broad_phase_2d_bvh.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 GODOT_BROAD_PHASE_2D_BVH_H
+#define GODOT_BROAD_PHASE_2D_BVH_H
+
+#include "godot_broad_phase_2d.h"
+
+#include "core/math/bvh.h"
+#include "core/math/rect2.h"
+#include "core/math/vector2.h"
+
+class GodotBroadPhase2DBVH : public GodotBroadPhase2D {
+ template <class T>
+ class UserPairTestFunction {
+ public:
+ static bool user_pair_check(const T *p_a, const T *p_b) {
+ // return false if no collision, decided by masks etc
+ return p_a->interacts_with(p_b);
+ }
+ };
+
+ template <class T>
+ class UserCullTestFunction {
+ public:
+ static bool user_cull_check(const T *p_a, const T *p_b) {
+ return true;
+ }
+ };
+
+ enum Tree {
+ TREE_STATIC = 0,
+ TREE_DYNAMIC = 1,
+ };
+
+ enum TreeFlag {
+ TREE_FLAG_STATIC = 1 << TREE_STATIC,
+ TREE_FLAG_DYNAMIC = 1 << TREE_DYNAMIC,
+ };
+
+ BVH_Manager<GodotCollisionObject2D, 2, true, 128, UserPairTestFunction<GodotCollisionObject2D>, UserCullTestFunction<GodotCollisionObject2D>, Rect2, Vector2> bvh;
+
+ static void *_pair_callback(void *, uint32_t, GodotCollisionObject2D *, int, uint32_t, GodotCollisionObject2D *, int);
+ static void _unpair_callback(void *, uint32_t, GodotCollisionObject2D *, int, uint32_t, GodotCollisionObject2D *, int, void *);
+
+ PairCallback pair_callback = nullptr;
+ void *pair_userdata = nullptr;
+ UnpairCallback unpair_callback = nullptr;
+ void *unpair_userdata = nullptr;
+
+public:
+ // 0 is an invalid ID
+ virtual ID create(GodotCollisionObject2D *p_object, int p_subindex = 0, const Rect2 &p_aabb = Rect2(), bool p_static = false) override;
+ virtual void move(ID p_id, const Rect2 &p_aabb) override;
+ virtual void set_static(ID p_id, bool p_static) override;
+ virtual void remove(ID p_id) override;
+
+ virtual GodotCollisionObject2D *get_object(ID p_id) const override;
+ virtual bool is_static(ID p_id) const override;
+ virtual int get_subindex(ID p_id) const override;
+
+ virtual int cull_segment(const Vector2 &p_from, const Vector2 &p_to, GodotCollisionObject2D **p_results, int p_max_results, int *p_result_indices = nullptr) override;
+ virtual int cull_aabb(const Rect2 &p_aabb, GodotCollisionObject2D **p_results, int p_max_results, int *p_result_indices = nullptr) override;
+
+ virtual void set_pair_callback(PairCallback p_pair_callback, void *p_userdata) override;
+ virtual void set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) override;
+
+ virtual void update() override;
+
+ static GodotBroadPhase2D *_create();
+ GodotBroadPhase2DBVH();
+};
+
+#endif // GODOT_BROAD_PHASE_2D_BVH_H
diff --git a/servers/physics_2d/collision_object_2d_sw.cpp b/servers/physics_2d/godot_collision_object_2d.cpp
index 7a2f312263..35027e0f69 100644
--- a/servers/physics_2d/collision_object_2d_sw.cpp
+++ b/servers/physics_2d/godot_collision_object_2d.cpp
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* collision_object_2d_sw.cpp */
+/* godot_collision_object_2d.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -28,11 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "collision_object_2d_sw.h"
-#include "servers/physics_2d/physics_server_2d_sw.h"
-#include "space_2d_sw.h"
+#include "godot_collision_object_2d.h"
+#include "godot_physics_server_2d.h"
+#include "godot_space_2d.h"
-void CollisionObject2DSW::add_shape(Shape2DSW *p_shape, const Transform2D &p_transform, bool p_disabled) {
+void GodotCollisionObject2D::add_shape(GodotShape2D *p_shape, const Transform2D &p_transform, bool p_disabled) {
Shape s;
s.shape = p_shape;
s.xform = p_transform;
@@ -45,13 +45,11 @@ void CollisionObject2DSW::add_shape(Shape2DSW *p_shape, const Transform2D &p_tra
p_shape->add_owner(this);
if (!pending_shape_update_list.in_list()) {
- PhysicsServer2DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list);
+ GodotPhysicsServer2D::godot_singleton->pending_shape_update_list.add(&pending_shape_update_list);
}
- // _update_shapes();
- // _shapes_changed();
}
-void CollisionObject2DSW::set_shape(int p_index, Shape2DSW *p_shape) {
+void GodotCollisionObject2D::set_shape(int p_index, GodotShape2D *p_shape) {
ERR_FAIL_INDEX(p_index, shapes.size());
shapes[p_index].shape->remove_owner(this);
shapes.write[p_index].shape = p_shape;
@@ -59,34 +57,25 @@ void CollisionObject2DSW::set_shape(int p_index, Shape2DSW *p_shape) {
p_shape->add_owner(this);
if (!pending_shape_update_list.in_list()) {
- PhysicsServer2DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list);
+ GodotPhysicsServer2D::godot_singleton->pending_shape_update_list.add(&pending_shape_update_list);
}
- // _update_shapes();
- // _shapes_changed();
-}
-
-void CollisionObject2DSW::set_shape_metadata(int p_index, const Variant &p_metadata) {
- ERR_FAIL_INDEX(p_index, shapes.size());
- shapes.write[p_index].metadata = p_metadata;
}
-void CollisionObject2DSW::set_shape_transform(int p_index, const Transform2D &p_transform) {
+void GodotCollisionObject2D::set_shape_transform(int p_index, const Transform2D &p_transform) {
ERR_FAIL_INDEX(p_index, shapes.size());
shapes.write[p_index].xform = p_transform;
shapes.write[p_index].xform_inv = p_transform.affine_inverse();
if (!pending_shape_update_list.in_list()) {
- PhysicsServer2DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list);
+ GodotPhysicsServer2D::godot_singleton->pending_shape_update_list.add(&pending_shape_update_list);
}
- // _update_shapes();
- // _shapes_changed();
}
-void CollisionObject2DSW::set_shape_as_disabled(int p_idx, bool p_disabled) {
+void GodotCollisionObject2D::set_shape_disabled(int p_idx, bool p_disabled) {
ERR_FAIL_INDEX(p_idx, shapes.size());
- CollisionObject2DSW::Shape &shape = shapes.write[p_idx];
+ GodotCollisionObject2D::Shape &shape = shapes.write[p_idx];
if (shape.disabled == p_disabled) {
return;
}
@@ -101,18 +90,16 @@ void CollisionObject2DSW::set_shape_as_disabled(int p_idx, bool p_disabled) {
space->get_broadphase()->remove(shape.bpid);
shape.bpid = 0;
if (!pending_shape_update_list.in_list()) {
- PhysicsServer2DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list);
+ GodotPhysicsServer2D::godot_singleton->pending_shape_update_list.add(&pending_shape_update_list);
}
- //_update_shapes();
} else if (!p_disabled && shape.bpid == 0) {
if (!pending_shape_update_list.in_list()) {
- PhysicsServer2DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list);
+ GodotPhysicsServer2D::godot_singleton->pending_shape_update_list.add(&pending_shape_update_list);
}
- //_update_shapes(); // automatically adds shape with bpid == 0
}
}
-void CollisionObject2DSW::remove_shape(Shape2DSW *p_shape) {
+void GodotCollisionObject2D::remove_shape(GodotShape2D *p_shape) {
//remove a shape, all the times it appears
for (int i = 0; i < shapes.size(); i++) {
if (shapes[i].shape == p_shape) {
@@ -122,7 +109,7 @@ void CollisionObject2DSW::remove_shape(Shape2DSW *p_shape) {
}
}
-void CollisionObject2DSW::remove_shape(int p_index) {
+void GodotCollisionObject2D::remove_shape(int p_index) {
//remove anything from shape to be erased to end, so subindices don't change
ERR_FAIL_INDEX(p_index, shapes.size());
for (int i = p_index; i < shapes.size(); i++) {
@@ -134,16 +121,16 @@ void CollisionObject2DSW::remove_shape(int p_index) {
shapes.write[i].bpid = 0;
}
shapes[p_index].shape->remove_owner(this);
- shapes.remove(p_index);
+ shapes.remove_at(p_index);
if (!pending_shape_update_list.in_list()) {
- PhysicsServer2DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list);
+ GodotPhysicsServer2D::godot_singleton->pending_shape_update_list.add(&pending_shape_update_list);
}
// _update_shapes();
// _shapes_changed();
}
-void CollisionObject2DSW::_set_static(bool p_static) {
+void GodotCollisionObject2D::_set_static(bool p_static) {
if (_static == p_static) {
return;
}
@@ -160,7 +147,7 @@ void CollisionObject2DSW::_set_static(bool p_static) {
}
}
-void CollisionObject2DSW::_unregister_shapes() {
+void GodotCollisionObject2D::_unregister_shapes() {
for (int i = 0; i < shapes.size(); i++) {
Shape &s = shapes.write[i];
if (s.bpid > 0) {
@@ -170,35 +157,34 @@ void CollisionObject2DSW::_unregister_shapes() {
}
}
-void CollisionObject2DSW::_update_shapes() {
+void GodotCollisionObject2D::_update_shapes() {
if (!space) {
return;
}
for (int i = 0; i < shapes.size(); i++) {
Shape &s = shapes.write[i];
-
if (s.disabled) {
continue;
}
- if (s.bpid == 0) {
- s.bpid = space->get_broadphase()->create(this, i);
- space->get_broadphase()->set_static(s.bpid, _static);
- }
-
//not quite correct, should compute the next matrix..
Rect2 shape_aabb = s.shape->get_aabb();
Transform2D xform = transform * s.xform;
shape_aabb = xform.xform(shape_aabb);
+ shape_aabb.grow_by((s.aabb_cache.size.x + s.aabb_cache.size.y) * 0.5 * 0.05);
s.aabb_cache = shape_aabb;
- s.aabb_cache = s.aabb_cache.grow((s.aabb_cache.size.x + s.aabb_cache.size.y) * 0.5 * 0.05);
- space->get_broadphase()->move(s.bpid, s.aabb_cache);
+ if (s.bpid == 0) {
+ s.bpid = space->get_broadphase()->create(this, i, shape_aabb, _static);
+ space->get_broadphase()->set_static(s.bpid, _static);
+ }
+
+ space->get_broadphase()->move(s.bpid, shape_aabb);
}
}
-void CollisionObject2DSW::_update_shapes_with_motion(const Vector2 &p_motion) {
+void GodotCollisionObject2D::_update_shapes_with_motion(const Vector2 &p_motion) {
if (!space) {
return;
}
@@ -209,11 +195,6 @@ void CollisionObject2DSW::_update_shapes_with_motion(const Vector2 &p_motion) {
continue;
}
- if (s.bpid == 0) {
- s.bpid = space->get_broadphase()->create(this, i);
- space->get_broadphase()->set_static(s.bpid, _static);
- }
-
//not quite correct, should compute the next matrix..
Rect2 shape_aabb = s.shape->get_aabb();
Transform2D xform = transform * s.xform;
@@ -221,11 +202,16 @@ void CollisionObject2DSW::_update_shapes_with_motion(const Vector2 &p_motion) {
shape_aabb = shape_aabb.merge(Rect2(shape_aabb.position + p_motion, shape_aabb.size)); //use motion
s.aabb_cache = shape_aabb;
+ if (s.bpid == 0) {
+ s.bpid = space->get_broadphase()->create(this, i, shape_aabb, _static);
+ space->get_broadphase()->set_static(s.bpid, _static);
+ }
+
space->get_broadphase()->move(s.bpid, shape_aabb);
}
}
-void CollisionObject2DSW::_set_space(Space2DSW *p_space) {
+void GodotCollisionObject2D::_set_space(GodotSpace2D *p_space) {
if (space) {
space->remove_object(this);
@@ -246,17 +232,12 @@ void CollisionObject2DSW::_set_space(Space2DSW *p_space) {
}
}
-void CollisionObject2DSW::_shape_changed() {
+void GodotCollisionObject2D::_shape_changed() {
_update_shapes();
_shapes_changed();
}
-CollisionObject2DSW::CollisionObject2DSW(Type p_type) :
+GodotCollisionObject2D::GodotCollisionObject2D(Type p_type) :
pending_shape_update_list(this) {
- _static = true;
type = p_type;
- space = nullptr;
- collision_mask = 1;
- collision_layer = 1;
- pickable = true;
}
diff --git a/servers/physics_2d/collision_object_2d_sw.h b/servers/physics_2d/godot_collision_object_2d.h
index 2db3961f41..1a683a7b0f 100644
--- a/servers/physics_2d/collision_object_2d_sw.h
+++ b/servers/physics_2d/godot_collision_object_2d.h
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* collision_object_2d_sw.h */
+/* godot_collision_object_2d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -28,17 +28,18 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef COLLISION_OBJECT_2D_SW_H
-#define COLLISION_OBJECT_2D_SW_H
+#ifndef GODOT_COLLISION_OBJECT_2D_H
+#define GODOT_COLLISION_OBJECT_2D_H
+
+#include "godot_broad_phase_2d.h"
+#include "godot_shape_2d.h"
-#include "broad_phase_2d_sw.h"
#include "core/templates/self_list.h"
#include "servers/physics_server_2d.h"
-#include "shape_2d_sw.h"
-class Space2DSW;
+class GodotSpace2D;
-class CollisionObject2DSW : public ShapeOwner2DSW {
+class GodotCollisionObject2D : public GodotShapeOwner2D {
public:
enum Type {
TYPE_AREA,
@@ -50,34 +51,28 @@ private:
RID self;
ObjectID instance_id;
ObjectID canvas_instance_id;
- bool pickable;
+ bool pickable = true;
struct Shape {
Transform2D xform;
Transform2D xform_inv;
- BroadPhase2DSW::ID bpid;
+ GodotBroadPhase2D::ID bpid = 0;
Rect2 aabb_cache; //for rayqueries
- Shape2DSW *shape;
- Variant metadata;
- bool disabled;
- bool one_way_collision;
- real_t one_way_collision_margin;
- Shape() {
- disabled = false;
- one_way_collision = false;
- one_way_collision_margin = 0;
- }
+ GodotShape2D *shape = nullptr;
+ bool disabled = false;
+ bool one_way_collision = false;
+ real_t one_way_collision_margin = 0.0;
};
Vector<Shape> shapes;
- Space2DSW *space;
+ GodotSpace2D *space = nullptr;
Transform2D transform;
Transform2D inv_transform;
- uint32_t collision_mask;
- uint32_t collision_layer;
- bool _static;
+ uint32_t collision_mask = 1;
+ uint32_t collision_layer = 1;
+ bool _static = true;
- SelfList<CollisionObject2DSW> pending_shape_update_list;
+ SelfList<GodotCollisionObject2D> pending_shape_update_list;
void _update_shapes();
@@ -95,9 +90,9 @@ protected:
void _set_static(bool p_static);
virtual void _shapes_changed() = 0;
- void _set_space(Space2DSW *p_space);
+ void _set_space(GodotSpace2D *p_space);
- CollisionObject2DSW(Type p_type);
+ GodotCollisionObject2D(Type p_type);
public:
_FORCE_INLINE_ void set_self(const RID &p_self) { self = p_self; }
@@ -109,20 +104,15 @@ public:
_FORCE_INLINE_ void set_canvas_instance_id(const ObjectID &p_canvas_instance_id) { canvas_instance_id = p_canvas_instance_id; }
_FORCE_INLINE_ ObjectID get_canvas_instance_id() const { return canvas_instance_id; }
- void _shape_changed();
+ void _shape_changed() override;
_FORCE_INLINE_ Type get_type() const { return type; }
- void add_shape(Shape2DSW *p_shape, const Transform2D &p_transform = Transform2D(), bool p_disabled = false);
- void set_shape(int p_index, Shape2DSW *p_shape);
+ void add_shape(GodotShape2D *p_shape, const Transform2D &p_transform = Transform2D(), bool p_disabled = false);
+ void set_shape(int p_index, GodotShape2D *p_shape);
void set_shape_transform(int p_index, const Transform2D &p_transform);
- void set_shape_metadata(int p_index, const Variant &p_metadata);
_FORCE_INLINE_ int get_shape_count() const { return shapes.size(); }
- _FORCE_INLINE_ bool is_shape_disabled(int p_index) const {
- CRASH_BAD_INDEX(p_index, shapes.size());
- return shapes[p_index].disabled;
- }
- _FORCE_INLINE_ Shape2DSW *get_shape(int p_index) const {
+ _FORCE_INLINE_ GodotShape2D *get_shape(int p_index) const {
CRASH_BAD_INDEX(p_index, shapes.size());
return shapes[p_index].shape;
}
@@ -138,18 +128,14 @@ public:
CRASH_BAD_INDEX(p_index, shapes.size());
return shapes[p_index].aabb_cache;
}
- _FORCE_INLINE_ const Variant &get_shape_metadata(int p_index) const {
- CRASH_BAD_INDEX(p_index, shapes.size());
- return shapes[p_index].metadata;
- }
- _FORCE_INLINE_ Transform2D get_transform() const { return transform; }
- _FORCE_INLINE_ Transform2D get_inv_transform() const { return inv_transform; }
- _FORCE_INLINE_ Space2DSW *get_space() const { return space; }
+ _FORCE_INLINE_ const Transform2D &get_transform() const { return transform; }
+ _FORCE_INLINE_ const Transform2D &get_inv_transform() const { return inv_transform; }
+ _FORCE_INLINE_ GodotSpace2D *get_space() const { return space; }
- void set_shape_as_disabled(int p_idx, bool p_disabled);
- _FORCE_INLINE_ bool is_shape_set_as_disabled(int p_idx) const {
- CRASH_BAD_INDEX(p_idx, shapes.size());
+ void set_shape_disabled(int p_idx, bool p_disabled);
+ _FORCE_INLINE_ bool is_shape_disabled(int p_idx) const {
+ ERR_FAIL_INDEX_V(p_idx, shapes.size(), false);
return shapes[p_idx].disabled;
}
@@ -180,21 +166,25 @@ public:
}
_FORCE_INLINE_ uint32_t get_collision_layer() const { return collision_layer; }
- void remove_shape(Shape2DSW *p_shape);
+ void remove_shape(GodotShape2D *p_shape) override;
void remove_shape(int p_index);
- virtual void set_space(Space2DSW *p_space) = 0;
+ virtual void set_space(GodotSpace2D *p_space) = 0;
_FORCE_INLINE_ bool is_static() const { return _static; }
void set_pickable(bool p_pickable) { pickable = p_pickable; }
_FORCE_INLINE_ bool is_pickable() const { return pickable; }
- _FORCE_INLINE_ bool test_collision_mask(CollisionObject2DSW *p_other) const {
+ _FORCE_INLINE_ bool collides_with(GodotCollisionObject2D *p_other) const {
+ return p_other->collision_layer & collision_mask;
+ }
+
+ _FORCE_INLINE_ bool interacts_with(const GodotCollisionObject2D *p_other) const {
return collision_layer & p_other->collision_mask || p_other->collision_layer & collision_mask;
}
- virtual ~CollisionObject2DSW() {}
+ virtual ~GodotCollisionObject2D() {}
};
-#endif // COLLISION_OBJECT_2D_SW_H
+#endif // GODOT_COLLISION_OBJECT_2D_H
diff --git a/servers/physics_2d/collision_solver_2d_sw.cpp b/servers/physics_2d/godot_collision_solver_2d.cpp
index 5bd4d498c6..0d7b42b80d 100644
--- a/servers/physics_2d/collision_solver_2d_sw.cpp
+++ b/servers/physics_2d/godot_collision_solver_2d.cpp
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* collision_solver_2d_sw.cpp */
+/* godot_collision_solver_2d.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -28,20 +28,20 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "collision_solver_2d_sw.h"
-#include "collision_solver_2d_sat.h"
+#include "godot_collision_solver_2d.h"
+#include "godot_collision_solver_2d_sat.h"
#define collision_solver sat_2d_calculate_penetration
//#define collision_solver gjk_epa_calculate_penetration
-bool CollisionSolver2DSW::solve_static_line(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) {
- const LineShape2DSW *line = static_cast<const LineShape2DSW *>(p_shape_A);
- if (p_shape_B->get_type() == PhysicsServer2D::SHAPE_LINE) {
+bool GodotCollisionSolver2D::solve_static_world_boundary(const GodotShape2D *p_shape_A, const Transform2D &p_transform_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) {
+ const GodotWorldBoundaryShape2D *world_boundary = static_cast<const GodotWorldBoundaryShape2D *>(p_shape_A);
+ if (p_shape_B->get_type() == PhysicsServer2D::SHAPE_WORLD_BOUNDARY) {
return false;
}
- Vector2 n = p_transform_A.basis_xform(line->get_normal()).normalized();
- Vector2 p = p_transform_A.xform(line->get_normal() * line->get_d());
+ Vector2 n = p_transform_A.basis_xform(world_boundary->get_normal()).normalized();
+ Vector2 p = p_transform_A.xform(world_boundary->get_normal() * world_boundary->get_d());
real_t d = n.dot(p);
Vector2 supports[2];
@@ -73,14 +73,14 @@ bool CollisionSolver2DSW::solve_static_line(const Shape2DSW *p_shape_A, const Tr
return found;
}
-bool CollisionSolver2DSW::solve_raycast(const Shape2DSW *p_shape_A, const Vector2 &p_motion_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *sep_axis) {
- const RayShape2DSW *ray = static_cast<const RayShape2DSW *>(p_shape_A);
- if (p_shape_B->get_type() == PhysicsServer2D::SHAPE_RAY) {
+bool GodotCollisionSolver2D::solve_separation_ray(const GodotShape2D *p_shape_A, const Vector2 &p_motion_A, const Transform2D &p_transform_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *r_sep_axis, real_t p_margin) {
+ const GodotSeparationRayShape2D *ray = static_cast<const GodotSeparationRayShape2D *>(p_shape_A);
+ if (p_shape_B->get_type() == PhysicsServer2D::SHAPE_SEPARATION_RAY) {
return false;
}
Vector2 from = p_transform_A.get_origin();
- Vector2 to = from + p_transform_A[1] * ray->get_length();
+ Vector2 to = from + p_transform_A[1] * (ray->get_length() + p_margin);
if (p_motion_A != Vector2()) {
//not the best but should be enough
Vector2 normal = (to - from).normalized();
@@ -94,14 +94,30 @@ bool CollisionSolver2DSW::solve_raycast(const Shape2DSW *p_shape_A, const Vector
Vector2 p, n;
if (!p_shape_B->intersect_segment(from, to, p, n)) {
- if (sep_axis) {
- *sep_axis = p_transform_A[1].normalized();
+ if (r_sep_axis) {
+ *r_sep_axis = p_transform_A[1].normalized();
+ }
+ return false;
+ }
+
+ // Discard contacts when the ray is fully contained inside the shape.
+ if (n == Vector2()) {
+ if (r_sep_axis) {
+ *r_sep_axis = p_transform_A[1].normalized();
+ }
+ return false;
+ }
+
+ // Discard contacts in the wrong direction.
+ if (n.dot(from - to) < CMP_EPSILON) {
+ if (r_sep_axis) {
+ *r_sep_axis = p_transform_A[1].normalized();
}
return false;
}
Vector2 support_B = p_transform_B.xform(p);
- if (ray->get_slips_on_slope()) {
+ if (ray->get_slide_on_slope()) {
Vector2 global_n = invb.basis_xform_inv(n).normalized();
support_B = support_A + (support_B - support_A).length() * global_n;
}
@@ -117,40 +133,40 @@ bool CollisionSolver2DSW::solve_raycast(const Shape2DSW *p_shape_A, const Vector
}
struct _ConcaveCollisionInfo2D {
- const Transform2D *transform_A;
- const Shape2DSW *shape_A;
- const Transform2D *transform_B;
+ const Transform2D *transform_A = nullptr;
+ const GodotShape2D *shape_A = nullptr;
+ const Transform2D *transform_B = nullptr;
Vector2 motion_A;
Vector2 motion_B;
- real_t margin_A;
- real_t margin_B;
- CollisionSolver2DSW::CallbackResult result_callback;
- void *userdata;
- bool swap_result;
- bool collided;
- int aabb_tests;
- int collisions;
- Vector2 *sep_axis;
+ real_t margin_A = 0.0;
+ real_t margin_B = 0.0;
+ GodotCollisionSolver2D::CallbackResult result_callback = nullptr;
+ void *userdata = nullptr;
+ bool swap_result = false;
+ bool collided = false;
+ int aabb_tests = 0;
+ int collisions = 0;
+ Vector2 *sep_axis = nullptr;
};
-void CollisionSolver2DSW::concave_callback(void *p_userdata, Shape2DSW *p_convex) {
- _ConcaveCollisionInfo2D &cinfo = *(_ConcaveCollisionInfo2D *)(p_userdata);
+bool GodotCollisionSolver2D::concave_callback(void *p_userdata, GodotShape2D *p_convex) {
+ _ConcaveCollisionInfo2D &cinfo = *(static_cast<_ConcaveCollisionInfo2D *>(p_userdata));
cinfo.aabb_tests++;
- if (!cinfo.result_callback && cinfo.collided) {
- return; //already collided and no contacts requested, don't test anymore
- }
bool collided = collision_solver(cinfo.shape_A, *cinfo.transform_A, cinfo.motion_A, p_convex, *cinfo.transform_B, cinfo.motion_B, cinfo.result_callback, cinfo.userdata, cinfo.swap_result, cinfo.sep_axis, cinfo.margin_A, cinfo.margin_B);
if (!collided) {
- return;
+ return false;
}
cinfo.collided = true;
cinfo.collisions++;
+
+ // Stop at first collision if contacts are not needed.
+ return !cinfo.result_callback;
}
-bool CollisionSolver2DSW::solve_concave(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *sep_axis, real_t p_margin_A, real_t p_margin_B) {
- const ConcaveShape2DSW *concave_B = static_cast<const ConcaveShape2DSW *>(p_shape_B);
+bool GodotCollisionSolver2D::solve_concave(const GodotShape2D *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *r_sep_axis, real_t p_margin_A, real_t p_margin_B) {
+ const GodotConcaveShape2D *concave_B = static_cast<const GodotConcaveShape2D *>(p_shape_B);
_ConcaveCollisionInfo2D cinfo;
cinfo.transform_A = &p_transform_A;
@@ -162,20 +178,20 @@ bool CollisionSolver2DSW::solve_concave(const Shape2DSW *p_shape_A, const Transf
cinfo.swap_result = p_swap_result;
cinfo.collided = false;
cinfo.collisions = 0;
- cinfo.sep_axis = sep_axis;
+ cinfo.sep_axis = r_sep_axis;
cinfo.margin_A = p_margin_A;
cinfo.margin_B = p_margin_B;
cinfo.aabb_tests = 0;
Transform2D rel_transform = p_transform_A;
- rel_transform.elements[2] -= p_transform_B.get_origin();
+ rel_transform.columns[2] -= p_transform_B.get_origin();
//quickly compute a local Rect2
Rect2 local_aabb;
for (int i = 0; i < 2; i++) {
- Vector2 axis(p_transform_B.elements[i]);
+ Vector2 axis(p_transform_B.columns[i]);
real_t axis_scale = 1.0 / axis.length();
axis *= axis_scale;
@@ -193,7 +209,7 @@ bool CollisionSolver2DSW::solve_concave(const Shape2DSW *p_shape_A, const Transf
return cinfo.collided;
}
-bool CollisionSolver2DSW::solve(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, Vector2 *sep_axis, real_t p_margin_A, real_t p_margin_B) {
+bool GodotCollisionSolver2D::solve(const GodotShape2D *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, Vector2 *r_sep_axis, real_t p_margin_A, real_t p_margin_B) {
PhysicsServer2D::ShapeType type_A = p_shape_A->get_type();
PhysicsServer2D::ShapeType type_B = p_shape_B->get_type();
bool concave_A = p_shape_A->is_concave();
@@ -209,26 +225,26 @@ bool CollisionSolver2DSW::solve(const Shape2DSW *p_shape_A, const Transform2D &p
swap = true;
}
- if (type_A == PhysicsServer2D::SHAPE_LINE) {
- if (type_B == PhysicsServer2D::SHAPE_LINE || type_B == PhysicsServer2D::SHAPE_RAY) {
+ if (type_A == PhysicsServer2D::SHAPE_WORLD_BOUNDARY) {
+ if (type_B == PhysicsServer2D::SHAPE_WORLD_BOUNDARY) {
return false;
}
if (swap) {
- return solve_static_line(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true);
+ return solve_static_world_boundary(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true);
} else {
- return solve_static_line(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false);
+ return solve_static_world_boundary(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false);
}
- } else if (type_A == PhysicsServer2D::SHAPE_RAY) {
- if (type_B == PhysicsServer2D::SHAPE_RAY) {
+ } else if (type_A == PhysicsServer2D::SHAPE_SEPARATION_RAY) {
+ if (type_B == PhysicsServer2D::SHAPE_SEPARATION_RAY) {
return false; //no ray-ray
}
if (swap) {
- return solve_raycast(p_shape_B, p_motion_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true, sep_axis);
+ return solve_separation_ray(p_shape_B, p_motion_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true, r_sep_axis, p_margin_B);
} else {
- return solve_raycast(p_shape_A, p_motion_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false, sep_axis);
+ return solve_separation_ray(p_shape_A, p_motion_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false, r_sep_axis, p_margin_A);
}
} else if (concave_B) {
@@ -237,12 +253,12 @@ bool CollisionSolver2DSW::solve(const Shape2DSW *p_shape_A, const Transform2D &p
}
if (!swap) {
- return solve_concave(p_shape_A, p_transform_A, p_motion_A, p_shape_B, p_transform_B, p_motion_B, p_result_callback, p_userdata, false, sep_axis, margin_A, margin_B);
+ return solve_concave(p_shape_A, p_transform_A, p_motion_A, p_shape_B, p_transform_B, p_motion_B, p_result_callback, p_userdata, false, r_sep_axis, margin_A, margin_B);
} else {
- return solve_concave(p_shape_B, p_transform_B, p_motion_B, p_shape_A, p_transform_A, p_motion_A, p_result_callback, p_userdata, true, sep_axis, margin_A, margin_B);
+ return solve_concave(p_shape_B, p_transform_B, p_motion_B, p_shape_A, p_transform_A, p_motion_A, p_result_callback, p_userdata, true, r_sep_axis, margin_A, margin_B);
}
} else {
- return collision_solver(p_shape_A, p_transform_A, p_motion_A, p_shape_B, p_transform_B, p_motion_B, p_result_callback, p_userdata, false, sep_axis, margin_A, margin_B);
+ return collision_solver(p_shape_A, p_transform_A, p_motion_A, p_shape_B, p_transform_B, p_motion_B, p_result_callback, p_userdata, false, r_sep_axis, margin_A, margin_B);
}
}
diff --git a/servers/physics_2d/collision_solver_2d_sw.h b/servers/physics_2d/godot_collision_solver_2d.h
index 4f12ca9e88..bd90641f04 100644
--- a/servers/physics_2d/collision_solver_2d_sw.h
+++ b/servers/physics_2d/godot_collision_solver_2d.h
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* collision_solver_2d_sw.h */
+/* godot_collision_solver_2d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -28,23 +28,23 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef COLLISION_SOLVER_2D_SW_H
-#define COLLISION_SOLVER_2D_SW_H
+#ifndef GODOT_COLLISION_SOLVER_2D_H
+#define GODOT_COLLISION_SOLVER_2D_H
-#include "shape_2d_sw.h"
+#include "godot_shape_2d.h"
-class CollisionSolver2DSW {
+class GodotCollisionSolver2D {
public:
typedef void (*CallbackResult)(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_userdata);
private:
- static bool solve_static_line(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
- static void concave_callback(void *p_userdata, Shape2DSW *p_convex);
- static bool solve_concave(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *sep_axis = nullptr, real_t p_margin_A = 0, real_t p_margin_B = 0);
- static bool solve_raycast(const Shape2DSW *p_shape_A, const Vector2 &p_motion_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *sep_axis = nullptr);
+ static bool solve_static_world_boundary(const GodotShape2D *p_shape_A, const Transform2D &p_transform_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
+ static bool concave_callback(void *p_userdata, GodotShape2D *p_convex);
+ static bool solve_concave(const GodotShape2D *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *r_sep_axis = nullptr, real_t p_margin_A = 0, real_t p_margin_B = 0);
+ static bool solve_separation_ray(const GodotShape2D *p_shape_A, const Vector2 &p_motion_A, const Transform2D &p_transform_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *r_sep_axis = nullptr, real_t p_margin = 0);
public:
- static bool solve(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, Vector2 *sep_axis = nullptr, real_t p_margin_A = 0, real_t p_margin_B = 0);
+ static bool solve(const GodotShape2D *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, Vector2 *r_sep_axis = nullptr, real_t p_margin_A = 0, real_t p_margin_B = 0);
};
-#endif // COLLISION_SOLVER_2D_SW_H
+#endif // GODOT_COLLISION_SOLVER_2D_H
diff --git a/servers/physics_2d/collision_solver_2d_sat.cpp b/servers/physics_2d/godot_collision_solver_2d_sat.cpp
index 29242a554b..77186d3810 100644
--- a/servers/physics_2d/collision_solver_2d_sat.cpp
+++ b/servers/physics_2d/godot_collision_solver_2d_sat.cpp
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* collision_solver_2d_sat.cpp */
+/* godot_collision_solver_2d_sat.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -28,23 +28,19 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "collision_solver_2d_sat.h"
+#include "godot_collision_solver_2d_sat.h"
#include "core/math/geometry_2d.h"
struct _CollectorCallback2D {
- CollisionSolver2DSW::CallbackResult callback;
- void *userdata;
- bool swap;
- bool collided;
+ GodotCollisionSolver2D::CallbackResult callback = nullptr;
+ void *userdata = nullptr;
+ bool swap = false;
+ bool collided = false;
Vector2 normal;
- Vector2 *sep_axis;
+ Vector2 *sep_axis = nullptr;
_FORCE_INLINE_ void call(const Vector2 &p_point_A, const Vector2 &p_point_B) {
- /*
- if (normal.dot(p_point_A) >= normal.dot(p_point_B))
- return;
- */
if (swap) {
callback(p_point_B, p_point_A, userdata);
} else {
@@ -75,9 +71,9 @@ _FORCE_INLINE_ static void _generate_contacts_point_edge(const Vector2 *p_points
}
struct _generate_contacts_Pair {
- bool a;
- int idx;
- real_t d;
+ bool a = false;
+ int idx = 0;
+ real_t d = 0.0;
_FORCE_INLINE_ bool operator<(const _generate_contacts_Pair &l) const { return d < l.d; }
};
@@ -146,10 +142,10 @@ static void _generate_contacts_from_supports(const Vector2 *p_points_A, int p_po
}
};
- int pointcount_B;
- int pointcount_A;
- const Vector2 *points_A;
- const Vector2 *points_B;
+ int pointcount_B = 0;
+ int pointcount_A = 0;
+ const Vector2 *points_A = nullptr;
+ const Vector2 *points_B = nullptr;
if (p_point_count_A > p_point_count_B) {
//swap
@@ -177,18 +173,20 @@ static void _generate_contacts_from_supports(const Vector2 *p_points_A, int p_po
template <class ShapeA, class ShapeB, bool castA = false, bool castB = false, bool withMargin = false>
class SeparatorAxisTest2D {
- const ShapeA *shape_A;
- const ShapeB *shape_B;
- const Transform2D *transform_A;
- const Transform2D *transform_B;
- real_t best_depth;
+ const ShapeA *shape_A = nullptr;
+ const ShapeB *shape_B = nullptr;
+ const Transform2D *transform_A = nullptr;
+ const Transform2D *transform_B = nullptr;
+ real_t best_depth = 1e15;
Vector2 best_axis;
- int best_axis_count;
- int best_axis_index;
+#ifdef DEBUG_ENABLED
+ int best_axis_count = 0;
+ int best_axis_index = -1;
+#endif
Vector2 motion_A;
Vector2 motion_B;
- real_t margin_A;
- real_t margin_B;
+ real_t margin_A = 0.0;
+ real_t margin_B = 0.0;
_CollectorCallback2D *callback;
public:
@@ -364,19 +362,13 @@ public:
_FORCE_INLINE_ SeparatorAxisTest2D(const ShapeA *p_shape_A, const Transform2D &p_transform_a, const ShapeB *p_shape_B, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_A = Vector2(), const Vector2 &p_motion_B = Vector2(), real_t p_margin_A = 0, real_t p_margin_B = 0) {
margin_A = p_margin_A;
margin_B = p_margin_B;
- best_depth = 1e15;
shape_A = p_shape_A;
shape_B = p_shape_B;
transform_A = &p_transform_a;
transform_B = &p_transform_b;
motion_A = p_motion_A;
motion_B = p_motion_B;
-
callback = p_collector;
-#ifdef DEBUG_ENABLED
- best_axis_count = 0;
- best_axis_index = -1;
-#endif
}
};
@@ -388,14 +380,14 @@ public:
(castB && !separator.test_axis(((m_a) - ((m_b) + p_motion_b)).normalized())) || \
(castA && castB && !separator.test_axis(((m_a) + p_motion_a - ((m_b) + p_motion_b)).normalized())))
-typedef void (*CollisionFunc)(const Shape2DSW *, const Transform2D &, const Shape2DSW *, const Transform2D &, _CollectorCallback2D *p_collector, const Vector2 &, const Vector2 &, real_t, real_t);
+typedef void (*CollisionFunc)(const GodotShape2D *, const Transform2D &, const GodotShape2D *, const Transform2D &, _CollectorCallback2D *p_collector, const Vector2 &, const Vector2 &, real_t, real_t);
template <bool castA, bool castB, bool withMargin>
-static void _collision_segment_segment(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
- const SegmentShape2DSW *segment_A = static_cast<const SegmentShape2DSW *>(p_a);
- const SegmentShape2DSW *segment_B = static_cast<const SegmentShape2DSW *>(p_b);
+static void _collision_segment_segment(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
+ const GodotSegmentShape2D *segment_A = static_cast<const GodotSegmentShape2D *>(p_a);
+ const GodotSegmentShape2D *segment_B = static_cast<const GodotSegmentShape2D *>(p_b);
- SeparatorAxisTest2D<SegmentShape2DSW, SegmentShape2DSW, castA, castB, withMargin> separator(segment_A, p_transform_a, segment_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
+ SeparatorAxisTest2D<GodotSegmentShape2D, GodotSegmentShape2D, castA, castB, withMargin> separator(segment_A, p_transform_a, segment_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
if (!separator.test_previous_axis()) {
return;
@@ -434,11 +426,11 @@ static void _collision_segment_segment(const Shape2DSW *p_a, const Transform2D &
}
template <bool castA, bool castB, bool withMargin>
-static void _collision_segment_circle(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
- const SegmentShape2DSW *segment_A = static_cast<const SegmentShape2DSW *>(p_a);
- const CircleShape2DSW *circle_B = static_cast<const CircleShape2DSW *>(p_b);
+static void _collision_segment_circle(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
+ const GodotSegmentShape2D *segment_A = static_cast<const GodotSegmentShape2D *>(p_a);
+ const GodotCircleShape2D *circle_B = static_cast<const GodotCircleShape2D *>(p_b);
- SeparatorAxisTest2D<SegmentShape2DSW, CircleShape2DSW, castA, castB, withMargin> separator(segment_A, p_transform_a, circle_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
+ SeparatorAxisTest2D<GodotSegmentShape2D, GodotCircleShape2D, castA, castB, withMargin> separator(segment_A, p_transform_a, circle_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
if (!separator.test_previous_axis()) {
return;
@@ -467,11 +459,11 @@ static void _collision_segment_circle(const Shape2DSW *p_a, const Transform2D &p
}
template <bool castA, bool castB, bool withMargin>
-static void _collision_segment_rectangle(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
- const SegmentShape2DSW *segment_A = static_cast<const SegmentShape2DSW *>(p_a);
- const RectangleShape2DSW *rectangle_B = static_cast<const RectangleShape2DSW *>(p_b);
+static void _collision_segment_rectangle(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
+ const GodotSegmentShape2D *segment_A = static_cast<const GodotSegmentShape2D *>(p_a);
+ const GodotRectangleShape2D *rectangle_B = static_cast<const GodotRectangleShape2D *>(p_b);
- SeparatorAxisTest2D<SegmentShape2DSW, RectangleShape2DSW, castA, castB, withMargin> separator(segment_A, p_transform_a, rectangle_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
+ SeparatorAxisTest2D<GodotSegmentShape2D, GodotRectangleShape2D, castA, castB, withMargin> separator(segment_A, p_transform_a, rectangle_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
if (!separator.test_previous_axis()) {
return;
@@ -485,11 +477,11 @@ static void _collision_segment_rectangle(const Shape2DSW *p_a, const Transform2D
return;
}
- if (!separator.test_axis(p_transform_b.elements[0].normalized())) {
+ if (!separator.test_axis(p_transform_b.columns[0].normalized())) {
return;
}
- if (!separator.test_axis(p_transform_b.elements[1].normalized())) {
+ if (!separator.test_axis(p_transform_b.columns[1].normalized())) {
return;
}
@@ -538,11 +530,11 @@ static void _collision_segment_rectangle(const Shape2DSW *p_a, const Transform2D
}
template <bool castA, bool castB, bool withMargin>
-static void _collision_segment_capsule(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
- const SegmentShape2DSW *segment_A = static_cast<const SegmentShape2DSW *>(p_a);
- const CapsuleShape2DSW *capsule_B = static_cast<const CapsuleShape2DSW *>(p_b);
+static void _collision_segment_capsule(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
+ const GodotSegmentShape2D *segment_A = static_cast<const GodotSegmentShape2D *>(p_a);
+ const GodotCapsuleShape2D *capsule_B = static_cast<const GodotCapsuleShape2D *>(p_b);
- SeparatorAxisTest2D<SegmentShape2DSW, CapsuleShape2DSW, castA, castB, withMargin> separator(segment_A, p_transform_a, capsule_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
+ SeparatorAxisTest2D<GodotSegmentShape2D, GodotCapsuleShape2D, castA, castB, withMargin> separator(segment_A, p_transform_a, capsule_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
if (!separator.test_previous_axis()) {
return;
@@ -556,20 +548,22 @@ static void _collision_segment_capsule(const Shape2DSW *p_a, const Transform2D &
return;
}
- if (!separator.test_axis(p_transform_b.elements[0].normalized())) {
+ if (!separator.test_axis(p_transform_b.columns[0].normalized())) {
return;
}
- if (TEST_POINT(p_transform_a.xform(segment_A->get_a()), (p_transform_b.get_origin() + p_transform_b.elements[1] * capsule_B->get_height() * 0.5))) {
+ real_t capsule_dir = capsule_B->get_height() * 0.5 - capsule_B->get_radius();
+
+ if (TEST_POINT(p_transform_a.xform(segment_A->get_a()), (p_transform_b.get_origin() + p_transform_b.columns[1] * capsule_dir))) {
return;
}
- if (TEST_POINT(p_transform_a.xform(segment_A->get_a()), (p_transform_b.get_origin() + p_transform_b.elements[1] * capsule_B->get_height() * -0.5))) {
+ if (TEST_POINT(p_transform_a.xform(segment_A->get_a()), (p_transform_b.get_origin() - p_transform_b.columns[1] * capsule_dir))) {
return;
}
- if (TEST_POINT(p_transform_a.xform(segment_A->get_b()), (p_transform_b.get_origin() + p_transform_b.elements[1] * capsule_B->get_height() * 0.5))) {
+ if (TEST_POINT(p_transform_a.xform(segment_A->get_b()), (p_transform_b.get_origin() + p_transform_b.columns[1] * capsule_dir))) {
return;
}
- if (TEST_POINT(p_transform_a.xform(segment_A->get_b()), (p_transform_b.get_origin() + p_transform_b.elements[1] * capsule_B->get_height() * -0.5))) {
+ if (TEST_POINT(p_transform_a.xform(segment_A->get_b()), (p_transform_b.get_origin() - p_transform_b.columns[1] * capsule_dir))) {
return;
}
@@ -577,11 +571,11 @@ static void _collision_segment_capsule(const Shape2DSW *p_a, const Transform2D &
}
template <bool castA, bool castB, bool withMargin>
-static void _collision_segment_convex_polygon(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
- const SegmentShape2DSW *segment_A = static_cast<const SegmentShape2DSW *>(p_a);
- const ConvexPolygonShape2DSW *convex_B = static_cast<const ConvexPolygonShape2DSW *>(p_b);
+static void _collision_segment_convex_polygon(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
+ const GodotSegmentShape2D *segment_A = static_cast<const GodotSegmentShape2D *>(p_a);
+ const GodotConvexPolygonShape2D *convex_B = static_cast<const GodotConvexPolygonShape2D *>(p_b);
- SeparatorAxisTest2D<SegmentShape2DSW, ConvexPolygonShape2DSW, castA, castB, withMargin> separator(segment_A, p_transform_a, convex_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
+ SeparatorAxisTest2D<GodotSegmentShape2D, GodotConvexPolygonShape2D, castA, castB, withMargin> separator(segment_A, p_transform_a, convex_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
if (!separator.test_previous_axis()) {
return;
@@ -616,11 +610,11 @@ static void _collision_segment_convex_polygon(const Shape2DSW *p_a, const Transf
/////////
template <bool castA, bool castB, bool withMargin>
-static void _collision_circle_circle(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
- const CircleShape2DSW *circle_A = static_cast<const CircleShape2DSW *>(p_a);
- const CircleShape2DSW *circle_B = static_cast<const CircleShape2DSW *>(p_b);
+static void _collision_circle_circle(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
+ const GodotCircleShape2D *circle_A = static_cast<const GodotCircleShape2D *>(p_a);
+ const GodotCircleShape2D *circle_B = static_cast<const GodotCircleShape2D *>(p_b);
- SeparatorAxisTest2D<CircleShape2DSW, CircleShape2DSW, castA, castB, withMargin> separator(circle_A, p_transform_a, circle_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
+ SeparatorAxisTest2D<GodotCircleShape2D, GodotCircleShape2D, castA, castB, withMargin> separator(circle_A, p_transform_a, circle_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
if (!separator.test_previous_axis()) {
return;
@@ -638,11 +632,11 @@ static void _collision_circle_circle(const Shape2DSW *p_a, const Transform2D &p_
}
template <bool castA, bool castB, bool withMargin>
-static void _collision_circle_rectangle(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
- const CircleShape2DSW *circle_A = static_cast<const CircleShape2DSW *>(p_a);
- const RectangleShape2DSW *rectangle_B = static_cast<const RectangleShape2DSW *>(p_b);
+static void _collision_circle_rectangle(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
+ const GodotCircleShape2D *circle_A = static_cast<const GodotCircleShape2D *>(p_a);
+ const GodotRectangleShape2D *rectangle_B = static_cast<const GodotRectangleShape2D *>(p_b);
- SeparatorAxisTest2D<CircleShape2DSW, RectangleShape2DSW, castA, castB, withMargin> separator(circle_A, p_transform_a, rectangle_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
+ SeparatorAxisTest2D<GodotCircleShape2D, GodotRectangleShape2D, castA, castB, withMargin> separator(circle_A, p_transform_a, rectangle_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
if (!separator.test_previous_axis()) {
return;
@@ -652,8 +646,8 @@ static void _collision_circle_rectangle(const Shape2DSW *p_a, const Transform2D
return;
}
- const Vector2 &sphere = p_transform_a.elements[2];
- const Vector2 *axis = &p_transform_b.elements[0];
+ const Vector2 &sphere = p_transform_a.columns[2];
+ const Vector2 *axis = &p_transform_b.columns[0];
//const Vector2& half_extents = rectangle_B->get_half_extents();
if (!separator.test_axis(axis[0].normalized())) {
@@ -696,11 +690,11 @@ static void _collision_circle_rectangle(const Shape2DSW *p_a, const Transform2D
}
template <bool castA, bool castB, bool withMargin>
-static void _collision_circle_capsule(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
- const CircleShape2DSW *circle_A = static_cast<const CircleShape2DSW *>(p_a);
- const CapsuleShape2DSW *capsule_B = static_cast<const CapsuleShape2DSW *>(p_b);
+static void _collision_circle_capsule(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
+ const GodotCircleShape2D *circle_A = static_cast<const GodotCircleShape2D *>(p_a);
+ const GodotCapsuleShape2D *capsule_B = static_cast<const GodotCapsuleShape2D *>(p_b);
- SeparatorAxisTest2D<CircleShape2DSW, CapsuleShape2DSW, castA, castB, withMargin> separator(circle_A, p_transform_a, capsule_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
+ SeparatorAxisTest2D<GodotCircleShape2D, GodotCapsuleShape2D, castA, castB, withMargin> separator(circle_A, p_transform_a, capsule_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
if (!separator.test_previous_axis()) {
return;
@@ -711,15 +705,17 @@ static void _collision_circle_capsule(const Shape2DSW *p_a, const Transform2D &p
}
//capsule axis
- if (!separator.test_axis(p_transform_b.elements[0].normalized())) {
+ if (!separator.test_axis(p_transform_b.columns[0].normalized())) {
return;
}
+ real_t capsule_dir = capsule_B->get_height() * 0.5 - capsule_B->get_radius();
+
//capsule endpoints
- if (TEST_POINT(p_transform_a.get_origin(), (p_transform_b.get_origin() + p_transform_b.elements[1] * capsule_B->get_height() * 0.5))) {
+ if (TEST_POINT(p_transform_a.get_origin(), (p_transform_b.get_origin() + p_transform_b.columns[1] * capsule_dir))) {
return;
}
- if (TEST_POINT(p_transform_a.get_origin(), (p_transform_b.get_origin() + p_transform_b.elements[1] * capsule_B->get_height() * -0.5))) {
+ if (TEST_POINT(p_transform_a.get_origin(), (p_transform_b.get_origin() - p_transform_b.columns[1] * capsule_dir))) {
return;
}
@@ -727,11 +723,11 @@ static void _collision_circle_capsule(const Shape2DSW *p_a, const Transform2D &p
}
template <bool castA, bool castB, bool withMargin>
-static void _collision_circle_convex_polygon(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
- const CircleShape2DSW *circle_A = static_cast<const CircleShape2DSW *>(p_a);
- const ConvexPolygonShape2DSW *convex_B = static_cast<const ConvexPolygonShape2DSW *>(p_b);
+static void _collision_circle_convex_polygon(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
+ const GodotCircleShape2D *circle_A = static_cast<const GodotCircleShape2D *>(p_a);
+ const GodotConvexPolygonShape2D *convex_B = static_cast<const GodotConvexPolygonShape2D *>(p_b);
- SeparatorAxisTest2D<CircleShape2DSW, ConvexPolygonShape2DSW, castA, castB, withMargin> separator(circle_A, p_transform_a, convex_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
+ SeparatorAxisTest2D<GodotCircleShape2D, GodotConvexPolygonShape2D, castA, castB, withMargin> separator(circle_A, p_transform_a, convex_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
if (!separator.test_previous_axis()) {
return;
@@ -758,11 +754,11 @@ static void _collision_circle_convex_polygon(const Shape2DSW *p_a, const Transfo
/////////
template <bool castA, bool castB, bool withMargin>
-static void _collision_rectangle_rectangle(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
- const RectangleShape2DSW *rectangle_A = static_cast<const RectangleShape2DSW *>(p_a);
- const RectangleShape2DSW *rectangle_B = static_cast<const RectangleShape2DSW *>(p_b);
+static void _collision_rectangle_rectangle(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
+ const GodotRectangleShape2D *rectangle_A = static_cast<const GodotRectangleShape2D *>(p_a);
+ const GodotRectangleShape2D *rectangle_B = static_cast<const GodotRectangleShape2D *>(p_b);
- SeparatorAxisTest2D<RectangleShape2DSW, RectangleShape2DSW, castA, castB, withMargin> separator(rectangle_A, p_transform_a, rectangle_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
+ SeparatorAxisTest2D<GodotRectangleShape2D, GodotRectangleShape2D, castA, castB, withMargin> separator(rectangle_A, p_transform_a, rectangle_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
if (!separator.test_previous_axis()) {
return;
@@ -773,20 +769,20 @@ static void _collision_rectangle_rectangle(const Shape2DSW *p_a, const Transform
}
//box faces A
- if (!separator.test_axis(p_transform_a.elements[0].normalized())) {
+ if (!separator.test_axis(p_transform_a.columns[0].normalized())) {
return;
}
- if (!separator.test_axis(p_transform_a.elements[1].normalized())) {
+ if (!separator.test_axis(p_transform_a.columns[1].normalized())) {
return;
}
//box faces B
- if (!separator.test_axis(p_transform_b.elements[0].normalized())) {
+ if (!separator.test_axis(p_transform_b.columns[0].normalized())) {
return;
}
- if (!separator.test_axis(p_transform_b.elements[1].normalized())) {
+ if (!separator.test_axis(p_transform_b.columns[1].normalized())) {
return;
}
@@ -800,10 +796,10 @@ static void _collision_rectangle_rectangle(const Shape2DSW *p_a, const Transform
if (castA || castB) {
Transform2D aofs = p_transform_a;
- aofs.elements[2] += p_motion_a;
+ aofs.columns[2] += p_motion_a;
Transform2D bofs = p_transform_b;
- bofs.elements[2] += p_motion_b;
+ bofs.columns[2] += p_motion_b;
Transform2D aofsinv = aofs.affine_inverse();
Transform2D bofsinv = bofs.affine_inverse();
@@ -832,11 +828,11 @@ static void _collision_rectangle_rectangle(const Shape2DSW *p_a, const Transform
}
template <bool castA, bool castB, bool withMargin>
-static void _collision_rectangle_capsule(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
- const RectangleShape2DSW *rectangle_A = static_cast<const RectangleShape2DSW *>(p_a);
- const CapsuleShape2DSW *capsule_B = static_cast<const CapsuleShape2DSW *>(p_b);
+static void _collision_rectangle_capsule(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
+ const GodotRectangleShape2D *rectangle_A = static_cast<const GodotRectangleShape2D *>(p_a);
+ const GodotCapsuleShape2D *capsule_B = static_cast<const GodotCapsuleShape2D *>(p_b);
- SeparatorAxisTest2D<RectangleShape2DSW, CapsuleShape2DSW, castA, castB, withMargin> separator(rectangle_A, p_transform_a, capsule_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
+ SeparatorAxisTest2D<GodotRectangleShape2D, GodotCapsuleShape2D, castA, castB, withMargin> separator(rectangle_A, p_transform_a, capsule_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
if (!separator.test_previous_axis()) {
return;
@@ -847,16 +843,16 @@ static void _collision_rectangle_capsule(const Shape2DSW *p_a, const Transform2D
}
//box faces
- if (!separator.test_axis(p_transform_a.elements[0].normalized())) {
+ if (!separator.test_axis(p_transform_a.columns[0].normalized())) {
return;
}
- if (!separator.test_axis(p_transform_a.elements[1].normalized())) {
+ if (!separator.test_axis(p_transform_a.columns[1].normalized())) {
return;
}
//capsule axis
- if (!separator.test_axis(p_transform_b.elements[0].normalized())) {
+ if (!separator.test_axis(p_transform_b.columns[0].normalized())) {
return;
}
@@ -864,9 +860,11 @@ static void _collision_rectangle_capsule(const Shape2DSW *p_a, const Transform2D
Transform2D boxinv = p_transform_a.affine_inverse();
+ real_t capsule_dir = capsule_B->get_height() * 0.5 - capsule_B->get_radius();
+
for (int i = 0; i < 2; i++) {
{
- Vector2 capsule_endpoint = p_transform_b.get_origin() + p_transform_b.elements[1] * capsule_B->get_height() * (i == 0 ? 0.5 : -0.5);
+ Vector2 capsule_endpoint = p_transform_b.get_origin() + p_transform_b.columns[1] * capsule_dir;
if (!separator.test_axis(rectangle_A->get_circle_axis(p_transform_a, boxinv, capsule_endpoint))) {
return;
@@ -874,7 +872,7 @@ static void _collision_rectangle_capsule(const Shape2DSW *p_a, const Transform2D
}
if (castA) {
- Vector2 capsule_endpoint = p_transform_b.get_origin() + p_transform_b.elements[1] * capsule_B->get_height() * (i == 0 ? 0.5 : -0.5);
+ Vector2 capsule_endpoint = p_transform_b.get_origin() + p_transform_b.columns[1] * capsule_dir;
capsule_endpoint -= p_motion_a;
if (!separator.test_axis(rectangle_A->get_circle_axis(p_transform_a, boxinv, capsule_endpoint))) {
@@ -883,7 +881,7 @@ static void _collision_rectangle_capsule(const Shape2DSW *p_a, const Transform2D
}
if (castB) {
- Vector2 capsule_endpoint = p_transform_b.get_origin() + p_transform_b.elements[1] * capsule_B->get_height() * (i == 0 ? 0.5 : -0.5);
+ Vector2 capsule_endpoint = p_transform_b.get_origin() + p_transform_b.columns[1] * capsule_dir;
capsule_endpoint += p_motion_b;
if (!separator.test_axis(rectangle_A->get_circle_axis(p_transform_a, boxinv, capsule_endpoint))) {
@@ -892,7 +890,7 @@ static void _collision_rectangle_capsule(const Shape2DSW *p_a, const Transform2D
}
if (castA && castB) {
- Vector2 capsule_endpoint = p_transform_b.get_origin() + p_transform_b.elements[1] * capsule_B->get_height() * (i == 0 ? 0.5 : -0.5);
+ Vector2 capsule_endpoint = p_transform_b.get_origin() + p_transform_b.columns[1] * capsule_dir;
capsule_endpoint -= p_motion_a;
capsule_endpoint += p_motion_b;
@@ -900,17 +898,19 @@ static void _collision_rectangle_capsule(const Shape2DSW *p_a, const Transform2D
return;
}
}
+
+ capsule_dir *= -1.0;
}
separator.generate_contacts();
}
template <bool castA, bool castB, bool withMargin>
-static void _collision_rectangle_convex_polygon(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
- const RectangleShape2DSW *rectangle_A = static_cast<const RectangleShape2DSW *>(p_a);
- const ConvexPolygonShape2DSW *convex_B = static_cast<const ConvexPolygonShape2DSW *>(p_b);
+static void _collision_rectangle_convex_polygon(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
+ const GodotRectangleShape2D *rectangle_A = static_cast<const GodotRectangleShape2D *>(p_a);
+ const GodotConvexPolygonShape2D *convex_B = static_cast<const GodotConvexPolygonShape2D *>(p_b);
- SeparatorAxisTest2D<RectangleShape2DSW, ConvexPolygonShape2DSW, castA, castB, withMargin> separator(rectangle_A, p_transform_a, convex_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
+ SeparatorAxisTest2D<GodotRectangleShape2D, GodotConvexPolygonShape2D, castA, castB, withMargin> separator(rectangle_A, p_transform_a, convex_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
if (!separator.test_previous_axis()) {
return;
@@ -921,11 +921,11 @@ static void _collision_rectangle_convex_polygon(const Shape2DSW *p_a, const Tran
}
//box faces
- if (!separator.test_axis(p_transform_a.elements[0].normalized())) {
+ if (!separator.test_axis(p_transform_a.columns[0].normalized())) {
return;
}
- if (!separator.test_axis(p_transform_a.elements[1].normalized())) {
+ if (!separator.test_axis(p_transform_a.columns[1].normalized())) {
return;
}
@@ -968,11 +968,11 @@ static void _collision_rectangle_convex_polygon(const Shape2DSW *p_a, const Tran
/////////
template <bool castA, bool castB, bool withMargin>
-static void _collision_capsule_capsule(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
- const CapsuleShape2DSW *capsule_A = static_cast<const CapsuleShape2DSW *>(p_a);
- const CapsuleShape2DSW *capsule_B = static_cast<const CapsuleShape2DSW *>(p_b);
+static void _collision_capsule_capsule(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
+ const GodotCapsuleShape2D *capsule_A = static_cast<const GodotCapsuleShape2D *>(p_a);
+ const GodotCapsuleShape2D *capsule_B = static_cast<const GodotCapsuleShape2D *>(p_b);
- SeparatorAxisTest2D<CapsuleShape2DSW, CapsuleShape2DSW, castA, castB, withMargin> separator(capsule_A, p_transform_a, capsule_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
+ SeparatorAxisTest2D<GodotCapsuleShape2D, GodotCapsuleShape2D, castA, castB, withMargin> separator(capsule_A, p_transform_a, capsule_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
if (!separator.test_previous_axis()) {
return;
@@ -984,37 +984,43 @@ static void _collision_capsule_capsule(const Shape2DSW *p_a, const Transform2D &
//capsule axis
- if (!separator.test_axis(p_transform_b.elements[0].normalized())) {
+ if (!separator.test_axis(p_transform_b.columns[0].normalized())) {
return;
}
- if (!separator.test_axis(p_transform_a.elements[0].normalized())) {
+ if (!separator.test_axis(p_transform_a.columns[0].normalized())) {
return;
}
//capsule endpoints
+ real_t capsule_dir_A = capsule_A->get_height() * 0.5 - capsule_A->get_radius();
for (int i = 0; i < 2; i++) {
- Vector2 capsule_endpoint_A = p_transform_a.get_origin() + p_transform_a.elements[1] * capsule_A->get_height() * (i == 0 ? 0.5 : -0.5);
+ Vector2 capsule_endpoint_A = p_transform_a.get_origin() + p_transform_a.columns[1] * capsule_dir_A;
+ real_t capsule_dir_B = capsule_B->get_height() * 0.5 - capsule_B->get_radius();
for (int j = 0; j < 2; j++) {
- Vector2 capsule_endpoint_B = p_transform_b.get_origin() + p_transform_b.elements[1] * capsule_B->get_height() * (j == 0 ? 0.5 : -0.5);
+ Vector2 capsule_endpoint_B = p_transform_b.get_origin() + p_transform_b.columns[1] * capsule_dir_B;
if (TEST_POINT(capsule_endpoint_A, capsule_endpoint_B)) {
return;
}
+
+ capsule_dir_B *= -1.0;
}
+
+ capsule_dir_A *= -1.0;
}
separator.generate_contacts();
}
template <bool castA, bool castB, bool withMargin>
-static void _collision_capsule_convex_polygon(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
- const CapsuleShape2DSW *capsule_A = static_cast<const CapsuleShape2DSW *>(p_a);
- const ConvexPolygonShape2DSW *convex_B = static_cast<const ConvexPolygonShape2DSW *>(p_b);
+static void _collision_capsule_convex_polygon(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
+ const GodotCapsuleShape2D *capsule_A = static_cast<const GodotCapsuleShape2D *>(p_a);
+ const GodotConvexPolygonShape2D *convex_B = static_cast<const GodotConvexPolygonShape2D *>(p_b);
- SeparatorAxisTest2D<CapsuleShape2DSW, ConvexPolygonShape2DSW, castA, castB, withMargin> separator(capsule_A, p_transform_a, convex_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
+ SeparatorAxisTest2D<GodotCapsuleShape2D, GodotConvexPolygonShape2D, castA, castB, withMargin> separator(capsule_A, p_transform_a, convex_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
if (!separator.test_previous_axis()) {
return;
@@ -1026,7 +1032,7 @@ static void _collision_capsule_convex_polygon(const Shape2DSW *p_a, const Transf
//capsule axis
- if (!separator.test_axis(p_transform_a.elements[0].normalized())) {
+ if (!separator.test_axis(p_transform_a.columns[0].normalized())) {
return;
}
@@ -1034,12 +1040,15 @@ static void _collision_capsule_convex_polygon(const Shape2DSW *p_a, const Transf
for (int i = 0; i < convex_B->get_point_count(); i++) {
Vector2 cpoint = p_transform_b.xform(convex_B->get_point(i));
+ real_t capsule_dir = capsule_A->get_height() * 0.5 - capsule_A->get_radius();
for (int j = 0; j < 2; j++) {
- Vector2 capsule_endpoint_A = p_transform_a.get_origin() + p_transform_a.elements[1] * capsule_A->get_height() * (j == 0 ? 0.5 : -0.5);
+ Vector2 capsule_endpoint_A = p_transform_a.get_origin() + p_transform_a.columns[1] * capsule_dir;
if (TEST_POINT(capsule_endpoint_A, cpoint)) {
return;
}
+
+ capsule_dir *= -1.0;
}
if (!separator.test_axis(convex_B->get_xformed_segment_normal(p_transform_b, i))) {
@@ -1053,11 +1062,11 @@ static void _collision_capsule_convex_polygon(const Shape2DSW *p_a, const Transf
/////////
template <bool castA, bool castB, bool withMargin>
-static void _collision_convex_polygon_convex_polygon(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
- const ConvexPolygonShape2DSW *convex_A = static_cast<const ConvexPolygonShape2DSW *>(p_a);
- const ConvexPolygonShape2DSW *convex_B = static_cast<const ConvexPolygonShape2DSW *>(p_b);
+static void _collision_convex_polygon_convex_polygon(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) {
+ const GodotConvexPolygonShape2D *convex_A = static_cast<const GodotConvexPolygonShape2D *>(p_a);
+ const GodotConvexPolygonShape2D *convex_B = static_cast<const GodotConvexPolygonShape2D *>(p_b);
- SeparatorAxisTest2D<ConvexPolygonShape2DSW, ConvexPolygonShape2DSW, castA, castB, withMargin> separator(convex_A, p_transform_a, convex_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
+ SeparatorAxisTest2D<GodotConvexPolygonShape2D, GodotConvexPolygonShape2D, castA, castB, withMargin> separator(convex_A, p_transform_a, convex_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B);
if (!separator.test_previous_axis()) {
return;
@@ -1094,17 +1103,17 @@ static void _collision_convex_polygon_convex_polygon(const Shape2DSW *p_a, const
////////
-bool sat_2d_calculate_penetration(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CollisionSolver2DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap, Vector2 *sep_axis, real_t p_margin_A, real_t p_margin_B) {
+bool sat_2d_calculate_penetration(const GodotShape2D *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, GodotCollisionSolver2D::CallbackResult p_result_callback, void *p_userdata, bool p_swap, Vector2 *sep_axis, real_t p_margin_A, real_t p_margin_B) {
PhysicsServer2D::ShapeType type_A = p_shape_A->get_type();
- ERR_FAIL_COND_V(type_A == PhysicsServer2D::SHAPE_LINE, false);
- //ERR_FAIL_COND_V(type_A==PhysicsServer2D::SHAPE_RAY,false);
+ ERR_FAIL_COND_V(type_A == PhysicsServer2D::SHAPE_WORLD_BOUNDARY, false);
+ ERR_FAIL_COND_V(type_A == PhysicsServer2D::SHAPE_SEPARATION_RAY, false);
ERR_FAIL_COND_V(p_shape_A->is_concave(), false);
PhysicsServer2D::ShapeType type_B = p_shape_B->get_type();
- ERR_FAIL_COND_V(type_B == PhysicsServer2D::SHAPE_LINE, false);
- //ERR_FAIL_COND_V(type_B==PhysicsServer2D::SHAPE_RAY,false);
+ ERR_FAIL_COND_V(type_B == PhysicsServer2D::SHAPE_WORLD_BOUNDARY, false);
+ ERR_FAIL_COND_V(type_B == PhysicsServer2D::SHAPE_SEPARATION_RAY, false);
ERR_FAIL_COND_V(p_shape_B->is_concave(), false);
static const CollisionFunc collision_table[5][5] = {
@@ -1346,8 +1355,8 @@ bool sat_2d_calculate_penetration(const Shape2DSW *p_shape_A, const Transform2D
callback.collided = false;
callback.sep_axis = sep_axis;
- const Shape2DSW *A = p_shape_A;
- const Shape2DSW *B = p_shape_B;
+ const GodotShape2D *A = p_shape_A;
+ const GodotShape2D *B = p_shape_B;
const Transform2D *transform_A = &p_transform_A;
const Transform2D *transform_B = &p_transform_B;
const Vector2 *motion_A = &p_motion_A;
diff --git a/servers/physics_2d/collision_solver_2d_sat.h b/servers/physics_2d/godot_collision_solver_2d_sat.h
index 49cc5176f9..3d8e29c41a 100644
--- a/servers/physics_2d/collision_solver_2d_sat.h
+++ b/servers/physics_2d/godot_collision_solver_2d_sat.h
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* collision_solver_2d_sat.h */
+/* godot_collision_solver_2d_sat.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -28,11 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef COLLISION_SOLVER_2D_SAT_H
-#define COLLISION_SOLVER_2D_SAT_H
+#ifndef GODOT_COLLISION_SOLVER_2D_SAT_H
+#define GODOT_COLLISION_SOLVER_2D_SAT_H
-#include "collision_solver_2d_sw.h"
+#include "godot_collision_solver_2d.h"
-bool sat_2d_calculate_penetration(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CollisionSolver2DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap = false, Vector2 *sep_axis = nullptr, real_t p_margin_A = 0, real_t p_margin_B = 0);
+bool sat_2d_calculate_penetration(const GodotShape2D *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, GodotCollisionSolver2D::CallbackResult p_result_callback, void *p_userdata, bool p_swap = false, Vector2 *sep_axis = nullptr, real_t p_margin_A = 0, real_t p_margin_B = 0);
-#endif // COLLISION_SOLVER_2D_SAT_H
+#endif // GODOT_COLLISION_SOLVER_2D_SAT_H
diff --git a/servers/physics_2d/constraint_2d_sw.h b/servers/physics_2d/godot_constraint_2d.h
index 49ae4dd848..d9bf035c2b 100644
--- a/servers/physics_2d/constraint_2d_sw.h
+++ b/servers/physics_2d/godot_constraint_2d.h
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* constraint_2d_sw.h */
+/* godot_constraint_2d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -28,27 +28,23 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef CONSTRAINT_2D_SW_H
-#define CONSTRAINT_2D_SW_H
+#ifndef GODOT_CONSTRAINT_2D_H
+#define GODOT_CONSTRAINT_2D_H
-#include "body_2d_sw.h"
+#include "godot_body_2d.h"
-class Constraint2DSW {
- Body2DSW **_body_ptr;
+class GodotConstraint2D {
+ GodotBody2D **_body_ptr;
int _body_count;
- uint64_t island_step;
- Constraint2DSW *island_next;
- Constraint2DSW *island_list_next;
- bool disabled_collisions_between_bodies;
+ uint64_t island_step = 0;
+ bool disabled_collisions_between_bodies = true;
RID self;
protected:
- Constraint2DSW(Body2DSW **p_body_ptr = nullptr, int p_body_count = 0) {
+ GodotConstraint2D(GodotBody2D **p_body_ptr = nullptr, int p_body_count = 0) {
_body_ptr = p_body_ptr;
_body_count = p_body_count;
- island_step = 0;
- disabled_collisions_between_bodies = true;
}
public:
@@ -58,22 +54,17 @@ public:
_FORCE_INLINE_ uint64_t get_island_step() const { return island_step; }
_FORCE_INLINE_ void set_island_step(uint64_t p_step) { island_step = p_step; }
- _FORCE_INLINE_ Constraint2DSW *get_island_next() const { return island_next; }
- _FORCE_INLINE_ void set_island_next(Constraint2DSW *p_next) { island_next = p_next; }
-
- _FORCE_INLINE_ Constraint2DSW *get_island_list_next() const { return island_list_next; }
- _FORCE_INLINE_ void set_island_list_next(Constraint2DSW *p_next) { island_list_next = p_next; }
-
- _FORCE_INLINE_ Body2DSW **get_body_ptr() const { return _body_ptr; }
+ _FORCE_INLINE_ GodotBody2D **get_body_ptr() const { return _body_ptr; }
_FORCE_INLINE_ int get_body_count() const { return _body_count; }
_FORCE_INLINE_ void disable_collisions_between_bodies(const bool p_disabled) { disabled_collisions_between_bodies = p_disabled; }
_FORCE_INLINE_ bool is_disabled_collisions_between_bodies() const { return disabled_collisions_between_bodies; }
virtual bool setup(real_t p_step) = 0;
+ virtual bool pre_solve(real_t p_step) = 0;
virtual void solve(real_t p_step) = 0;
- virtual ~Constraint2DSW() {}
+ virtual ~GodotConstraint2D() {}
};
-#endif // CONSTRAINT_2D_SW_H
+#endif // GODOT_CONSTRAINT_2D_H
diff --git a/servers/physics_2d/joints_2d_sw.cpp b/servers/physics_2d/godot_joints_2d.cpp
index c7b556deba..0c21b08ea9 100644
--- a/servers/physics_2d/joints_2d_sw.cpp
+++ b/servers/physics_2d/godot_joints_2d.cpp
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* joints_2d_sw.cpp */
+/* godot_joints_2d.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -28,9 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "joints_2d_sw.h"
+#include "godot_joints_2d.h"
-#include "space_2d_sw.h"
+#include "godot_space_2d.h"
//based on chipmunk joint constraints
@@ -55,7 +55,7 @@
* SOFTWARE.
*/
-void Joint2DSW::copy_settings_from(Joint2DSW *p_joint) {
+void GodotJoint2D::copy_settings_from(GodotJoint2D *p_joint) {
set_self(p_joint->get_self());
set_max_force(p_joint->get_max_force());
set_bias(p_joint->get_bias());
@@ -63,18 +63,18 @@ void Joint2DSW::copy_settings_from(Joint2DSW *p_joint) {
disable_collisions_between_bodies(p_joint->is_disabled_collisions_between_bodies());
}
-static inline real_t k_scalar(Body2DSW *a, Body2DSW *b, const Vector2 &rA, const Vector2 &rB, const Vector2 &n) {
- real_t value = 0;
+static inline real_t k_scalar(GodotBody2D *a, GodotBody2D *b, const Vector2 &rA, const Vector2 &rB, const Vector2 &n) {
+ real_t value = 0.0;
{
value += a->get_inv_mass();
- real_t rcn = rA.cross(n);
+ real_t rcn = (rA - a->get_center_of_mass()).cross(n);
value += a->get_inv_inertia() * rcn * rcn;
}
if (b) {
value += b->get_inv_mass();
- real_t rcn = rB.cross(n);
+ real_t rcn = (rB - b->get_center_of_mass()).cross(n);
value += b->get_inv_inertia() * rcn * rcn;
}
@@ -82,23 +82,31 @@ static inline real_t k_scalar(Body2DSW *a, Body2DSW *b, const Vector2 &rA, const
}
static inline Vector2
-relative_velocity(Body2DSW *a, Body2DSW *b, Vector2 rA, Vector2 rB) {
- Vector2 sum = a->get_linear_velocity() - rA.orthogonal() * a->get_angular_velocity();
+relative_velocity(GodotBody2D *a, GodotBody2D *b, Vector2 rA, Vector2 rB) {
+ Vector2 sum = a->get_linear_velocity() - (rA - a->get_center_of_mass()).orthogonal() * a->get_angular_velocity();
if (b) {
- return (b->get_linear_velocity() - rB.orthogonal() * b->get_angular_velocity()) - sum;
+ return (b->get_linear_velocity() - (rB - b->get_center_of_mass()).orthogonal() * b->get_angular_velocity()) - sum;
} else {
return -sum;
}
}
static inline real_t
-normal_relative_velocity(Body2DSW *a, Body2DSW *b, Vector2 rA, Vector2 rB, Vector2 n) {
+normal_relative_velocity(GodotBody2D *a, GodotBody2D *b, Vector2 rA, Vector2 rB, Vector2 n) {
return relative_velocity(a, b, rA, rB).dot(n);
}
-bool PinJoint2DSW::setup(real_t p_step) {
- Space2DSW *space = A->get_space();
+bool GodotPinJoint2D::setup(real_t p_step) {
+ dynamic_A = (A->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC);
+ dynamic_B = (B->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC);
+
+ if (!dynamic_A && !dynamic_B) {
+ return false;
+ }
+
+ GodotSpace2D *space = A->get_space();
ERR_FAIL_COND_V(!space, false);
+
rA = A->get_transform().basis_xform(anchor_A);
rB = B ? B->get_transform().basis_xform(anchor_B) : anchor_B;
@@ -110,22 +118,26 @@ bool PinJoint2DSW::setup(real_t p_step) {
K1[0].y = 0.0f;
K1[1].y = A->get_inv_mass() + B_inv_mass;
+ Vector2 r1 = rA - A->get_center_of_mass();
+
Transform2D K2;
- K2[0].x = A->get_inv_inertia() * rA.y * rA.y;
- K2[1].x = -A->get_inv_inertia() * rA.x * rA.y;
- K2[0].y = -A->get_inv_inertia() * rA.x * rA.y;
- K2[1].y = A->get_inv_inertia() * rA.x * rA.x;
+ K2[0].x = A->get_inv_inertia() * r1.y * r1.y;
+ K2[1].x = -A->get_inv_inertia() * r1.x * r1.y;
+ K2[0].y = -A->get_inv_inertia() * r1.x * r1.y;
+ K2[1].y = A->get_inv_inertia() * r1.x * r1.x;
Transform2D K;
K[0] = K1[0] + K2[0];
K[1] = K1[1] + K2[1];
if (B) {
+ Vector2 r2 = rB - B->get_center_of_mass();
+
Transform2D K3;
- K3[0].x = B->get_inv_inertia() * rB.y * rB.y;
- K3[1].x = -B->get_inv_inertia() * rB.x * rB.y;
- K3[0].y = -B->get_inv_inertia() * rB.x * rB.y;
- K3[1].y = B->get_inv_inertia() * rB.x * rB.x;
+ K3[0].x = B->get_inv_inertia() * r2.y * r2.y;
+ K3[1].x = -B->get_inv_inertia() * r2.x * r2.y;
+ K3[0].y = -B->get_inv_inertia() * r2.x * r2.y;
+ K3[1].y = B->get_inv_inertia() * r2.x * r2.x;
K[0] += K3[0];
K[1] += K3[1];
@@ -143,12 +155,6 @@ bool PinJoint2DSW::setup(real_t p_step) {
bias = delta * -(get_bias() == 0 ? space->get_constraint_bias() : get_bias()) * (1.0 / p_step);
- // apply accumulated impulse
- A->apply_impulse(-P, rA);
- if (B) {
- B->apply_impulse(P, rB);
- }
-
return true;
}
@@ -156,49 +162,61 @@ inline Vector2 custom_cross(const Vector2 &p_vec, real_t p_other) {
return Vector2(p_other * p_vec.y, -p_other * p_vec.x);
}
-void PinJoint2DSW::solve(real_t p_step) {
+bool GodotPinJoint2D::pre_solve(real_t p_step) {
+ // Apply accumulated impulse.
+ if (dynamic_A) {
+ A->apply_impulse(-P, rA);
+ }
+ if (B && dynamic_B) {
+ B->apply_impulse(P, rB);
+ }
+
+ return true;
+}
+
+void GodotPinJoint2D::solve(real_t p_step) {
// compute relative velocity
- Vector2 vA = A->get_linear_velocity() - custom_cross(rA, A->get_angular_velocity());
+ Vector2 vA = A->get_linear_velocity() - custom_cross(rA - A->get_center_of_mass(), A->get_angular_velocity());
Vector2 rel_vel;
if (B) {
- rel_vel = B->get_linear_velocity() - custom_cross(rB, B->get_angular_velocity()) - vA;
+ rel_vel = B->get_linear_velocity() - custom_cross(rB - B->get_center_of_mass(), B->get_angular_velocity()) - vA;
} else {
rel_vel = -vA;
}
Vector2 impulse = M.basis_xform(bias - rel_vel - Vector2(softness, softness) * P);
- A->apply_impulse(-impulse, rA);
- if (B) {
+ if (dynamic_A) {
+ A->apply_impulse(-impulse, rA);
+ }
+ if (B && dynamic_B) {
B->apply_impulse(impulse, rB);
}
P += impulse;
}
-void PinJoint2DSW::set_param(PhysicsServer2D::PinJointParam p_param, real_t p_value) {
+void GodotPinJoint2D::set_param(PhysicsServer2D::PinJointParam p_param, real_t p_value) {
if (p_param == PhysicsServer2D::PIN_JOINT_SOFTNESS) {
softness = p_value;
}
}
-real_t PinJoint2DSW::get_param(PhysicsServer2D::PinJointParam p_param) const {
+real_t GodotPinJoint2D::get_param(PhysicsServer2D::PinJointParam p_param) const {
if (p_param == PhysicsServer2D::PIN_JOINT_SOFTNESS) {
return softness;
}
ERR_FAIL_V(0);
}
-PinJoint2DSW::PinJoint2DSW(const Vector2 &p_pos, Body2DSW *p_body_a, Body2DSW *p_body_b) :
- Joint2DSW(_arr, p_body_b ? 2 : 1) {
+GodotPinJoint2D::GodotPinJoint2D(const Vector2 &p_pos, GodotBody2D *p_body_a, GodotBody2D *p_body_b) :
+ GodotJoint2D(_arr, p_body_b ? 2 : 1) {
A = p_body_a;
B = p_body_b;
anchor_A = p_body_a->get_inv_transform().xform(p_pos);
anchor_B = p_body_b ? p_body_b->get_inv_transform().xform(p_pos) : p_pos;
- softness = 0;
-
p_body_a->add_constraint(this, 0);
if (p_body_b) {
p_body_b->add_constraint(this, 1);
@@ -210,7 +228,7 @@ PinJoint2DSW::PinJoint2DSW(const Vector2 &p_pos, Body2DSW *p_body_a, Body2DSW *p
//////////////////////////////////////////////
static inline void
-k_tensor(Body2DSW *a, Body2DSW *b, Vector2 r1, Vector2 r2, Vector2 *k1, Vector2 *k2) {
+k_tensor(GodotBody2D *a, GodotBody2D *b, Vector2 r1, Vector2 r2, Vector2 *k1, Vector2 *k2) {
// calculate mass matrix
// If I wasn't lazy and wrote a proper matrix class, this wouldn't be so gross...
real_t k11, k12, k21, k22;
@@ -222,6 +240,9 @@ k_tensor(Body2DSW *a, Body2DSW *b, Vector2 r1, Vector2 r2, Vector2 *k1, Vector2
k21 = 0.0f;
k22 = m_sum;
+ r1 -= a->get_center_of_mass();
+ r2 -= b->get_center_of_mass();
+
// add the influence from r1
real_t a_i_inv = a->get_inv_inertia();
real_t r1xsq = r1.x * r1.x * a_i_inv;
@@ -256,11 +277,20 @@ mult_k(const Vector2 &vr, const Vector2 &k1, const Vector2 &k2) {
return Vector2(vr.dot(k1), vr.dot(k2));
}
-bool GrooveJoint2DSW::setup(real_t p_step) {
+bool GodotGrooveJoint2D::setup(real_t p_step) {
+ dynamic_A = (A->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC);
+ dynamic_B = (B->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC);
+
+ if (!dynamic_A && !dynamic_B) {
+ return false;
+ }
+
+ GodotSpace2D *space = A->get_space();
+ ERR_FAIL_COND_V(!space, false);
+
// calculate endpoints in worldspace
Vector2 ta = A->get_transform().xform(A_groove_1);
Vector2 tb = A->get_transform().xform(A_groove_2);
- Space2DSW *space = A->get_space();
// calculate axis
Vector2 n = -(tb - ta).orthogonal().normalized();
@@ -297,17 +327,25 @@ bool GrooveJoint2DSW::setup(real_t p_step) {
Vector2 delta = (B->get_transform().get_origin() + rB) - (A->get_transform().get_origin() + rA);
real_t _b = get_bias();
- gbias = (delta * -(_b == 0 ? space->get_constraint_bias() : _b) * (1.0 / p_step)).clamped(get_max_bias());
-
- // apply accumulated impulse
- A->apply_impulse(-jn_acc, rA);
- B->apply_impulse(jn_acc, rB);
+ gbias = (delta * -(_b == 0 ? space->get_constraint_bias() : _b) * (1.0 / p_step)).limit_length(get_max_bias());
correct = true;
return true;
}
-void GrooveJoint2DSW::solve(real_t p_step) {
+bool GodotGrooveJoint2D::pre_solve(real_t p_step) {
+ // Apply accumulated impulse.
+ if (dynamic_A) {
+ A->apply_impulse(-jn_acc, rA);
+ }
+ if (dynamic_B) {
+ B->apply_impulse(jn_acc, rB);
+ }
+
+ return true;
+}
+
+void GodotGrooveJoint2D::solve(real_t p_step) {
// compute impulse
Vector2 vr = relative_velocity(A, B, rA, rB);
@@ -315,16 +353,20 @@ void GrooveJoint2DSW::solve(real_t p_step) {
Vector2 jOld = jn_acc;
j += jOld;
- jn_acc = (((clamp * j.cross(xf_normal)) > 0) ? j : j.project(xf_normal)).clamped(jn_max);
+ jn_acc = (((clamp * j.cross(xf_normal)) > 0) ? j : j.project(xf_normal)).limit_length(jn_max);
j = jn_acc - jOld;
- A->apply_impulse(-j, rA);
- B->apply_impulse(j, rB);
+ if (dynamic_A) {
+ A->apply_impulse(-j, rA);
+ }
+ if (dynamic_B) {
+ B->apply_impulse(j, rB);
+ }
}
-GrooveJoint2DSW::GrooveJoint2DSW(const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, Body2DSW *p_body_a, Body2DSW *p_body_b) :
- Joint2DSW(_arr, 2) {
+GodotGrooveJoint2D::GodotGrooveJoint2D(const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, GodotBody2D *p_body_a, GodotBody2D *p_body_b) :
+ GodotJoint2D(_arr, 2) {
A = p_body_a;
B = p_body_b;
@@ -341,7 +383,14 @@ GrooveJoint2DSW::GrooveJoint2DSW(const Vector2 &p_a_groove1, const Vector2 &p_a_
//////////////////////////////////////////////
//////////////////////////////////////////////
-bool DampedSpringJoint2DSW::setup(real_t p_step) {
+bool GodotDampedSpringJoint2D::setup(real_t p_step) {
+ dynamic_A = (A->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC);
+ dynamic_B = (B->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC);
+
+ if (!dynamic_A && !dynamic_B) {
+ return false;
+ }
+
rA = A->get_transform().basis_xform(anchor_A);
rB = B->get_transform().basis_xform(anchor_B);
@@ -360,17 +409,26 @@ bool DampedSpringJoint2DSW::setup(real_t p_step) {
target_vrn = 0.0f;
v_coef = 1.0f - Math::exp(-damping * (p_step)*k);
- // apply spring force
+ // Calculate spring force.
real_t f_spring = (rest_length - dist) * stiffness;
- Vector2 j = n * f_spring * (p_step);
+ j = n * f_spring * (p_step);
- A->apply_impulse(-j, rA);
- B->apply_impulse(j, rB);
+ return true;
+}
+
+bool GodotDampedSpringJoint2D::pre_solve(real_t p_step) {
+ // Apply spring force.
+ if (dynamic_A) {
+ A->apply_impulse(-j, rA);
+ }
+ if (dynamic_B) {
+ B->apply_impulse(j, rB);
+ }
return true;
}
-void DampedSpringJoint2DSW::solve(real_t p_step) {
+void GodotDampedSpringJoint2D::solve(real_t p_step) {
// compute relative velocity
real_t vrn = normal_relative_velocity(A, B, rA, rB, n) - target_vrn;
@@ -380,11 +438,15 @@ void DampedSpringJoint2DSW::solve(real_t p_step) {
target_vrn = vrn + v_damp;
Vector2 j = n * v_damp * n_mass;
- A->apply_impulse(-j, rA);
- B->apply_impulse(j, rB);
+ if (dynamic_A) {
+ A->apply_impulse(-j, rA);
+ }
+ if (dynamic_B) {
+ B->apply_impulse(j, rB);
+ }
}
-void DampedSpringJoint2DSW::set_param(PhysicsServer2D::DampedSpringParam p_param, real_t p_value) {
+void GodotDampedSpringJoint2D::set_param(PhysicsServer2D::DampedSpringParam p_param, real_t p_value) {
switch (p_param) {
case PhysicsServer2D::DAMPED_SPRING_REST_LENGTH: {
rest_length = p_value;
@@ -398,7 +460,7 @@ void DampedSpringJoint2DSW::set_param(PhysicsServer2D::DampedSpringParam p_param
}
}
-real_t DampedSpringJoint2DSW::get_param(PhysicsServer2D::DampedSpringParam p_param) const {
+real_t GodotDampedSpringJoint2D::get_param(PhysicsServer2D::DampedSpringParam p_param) const {
switch (p_param) {
case PhysicsServer2D::DAMPED_SPRING_REST_LENGTH: {
return rest_length;
@@ -414,16 +476,14 @@ real_t DampedSpringJoint2DSW::get_param(PhysicsServer2D::DampedSpringParam p_par
ERR_FAIL_V(0);
}
-DampedSpringJoint2DSW::DampedSpringJoint2DSW(const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, Body2DSW *p_body_a, Body2DSW *p_body_b) :
- Joint2DSW(_arr, 2) {
+GodotDampedSpringJoint2D::GodotDampedSpringJoint2D(const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, GodotBody2D *p_body_a, GodotBody2D *p_body_b) :
+ GodotJoint2D(_arr, 2) {
A = p_body_a;
B = p_body_b;
anchor_A = A->get_inv_transform().xform(p_anchor_a);
anchor_B = B->get_inv_transform().xform(p_anchor_b);
rest_length = p_anchor_a.distance_to(p_anchor_b);
- stiffness = 20;
- damping = 1.5;
A->add_constraint(this, 0);
B->add_constraint(this, 1);
diff --git a/servers/physics_2d/joints_2d_sw.h b/servers/physics_2d/godot_joints_2d.h
index 628de972ae..acaaf0f629 100644
--- a/servers/physics_2d/joints_2d_sw.h
+++ b/servers/physics_2d/godot_joints_2d.h
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* joints_2d_sw.h */
+/* godot_joints_2d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -28,16 +28,20 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef JOINTS_2D_SW_H
-#define JOINTS_2D_SW_H
+#ifndef GODOT_JOINTS_2D_H
+#define GODOT_JOINTS_2D_H
-#include "body_2d_sw.h"
-#include "constraint_2d_sw.h"
+#include "godot_body_2d.h"
+#include "godot_constraint_2d.h"
-class Joint2DSW : public Constraint2DSW {
- real_t max_force;
- real_t bias;
- real_t max_bias;
+class GodotJoint2D : public GodotConstraint2D {
+ real_t bias = 0;
+ real_t max_bias = 3.40282e+38;
+ real_t max_force = 3.40282e+38;
+
+protected:
+ bool dynamic_A = false;
+ bool dynamic_B = false;
public:
_FORCE_INLINE_ void set_max_force(real_t p_force) { max_force = p_force; }
@@ -49,21 +53,19 @@ public:
_FORCE_INLINE_ void set_max_bias(real_t p_bias) { max_bias = p_bias; }
_FORCE_INLINE_ real_t get_max_bias() const { return max_bias; }
- virtual bool setup(real_t p_step) { return false; }
- virtual void solve(real_t p_step) {}
+ virtual bool setup(real_t p_step) override { return false; }
+ virtual bool pre_solve(real_t p_step) override { return false; }
+ virtual void solve(real_t p_step) override {}
- void copy_settings_from(Joint2DSW *p_joint);
+ void copy_settings_from(GodotJoint2D *p_joint);
virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_TYPE_MAX; }
- Joint2DSW(Body2DSW **p_body_ptr = nullptr, int p_body_count = 0) :
- Constraint2DSW(p_body_ptr, p_body_count) {
- bias = 0;
- max_force = max_bias = 3.40282e+38;
- };
+ GodotJoint2D(GodotBody2D **p_body_ptr = nullptr, int p_body_count = 0) :
+ GodotConstraint2D(p_body_ptr, p_body_count) {}
- virtual ~Joint2DSW() {
+ virtual ~GodotJoint2D() {
for (int i = 0; i < get_body_count(); i++) {
- Body2DSW *body = get_body_ptr()[i];
+ GodotBody2D *body = get_body_ptr()[i];
if (body) {
body->remove_constraint(this, i);
}
@@ -71,14 +73,14 @@ public:
};
};
-class PinJoint2DSW : public Joint2DSW {
+class GodotPinJoint2D : public GodotJoint2D {
union {
struct {
- Body2DSW *A;
- Body2DSW *B;
+ GodotBody2D *A;
+ GodotBody2D *B;
};
- Body2DSW *_arr[2];
+ GodotBody2D *_arr[2] = { nullptr, nullptr };
};
Transform2D M;
@@ -87,28 +89,29 @@ class PinJoint2DSW : public Joint2DSW {
Vector2 anchor_B;
Vector2 bias;
Vector2 P;
- real_t softness;
+ real_t softness = 0.0;
public:
- virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_TYPE_PIN; }
+ virtual PhysicsServer2D::JointType get_type() const override { return PhysicsServer2D::JOINT_TYPE_PIN; }
- virtual bool setup(real_t p_step);
- virtual void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual bool pre_solve(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
void set_param(PhysicsServer2D::PinJointParam p_param, real_t p_value);
real_t get_param(PhysicsServer2D::PinJointParam p_param) const;
- PinJoint2DSW(const Vector2 &p_pos, Body2DSW *p_body_a, Body2DSW *p_body_b = nullptr);
+ GodotPinJoint2D(const Vector2 &p_pos, GodotBody2D *p_body_a, GodotBody2D *p_body_b = nullptr);
};
-class GrooveJoint2DSW : public Joint2DSW {
+class GodotGrooveJoint2D : public GodotJoint2D {
union {
struct {
- Body2DSW *A;
- Body2DSW *B;
+ GodotBody2D *A;
+ GodotBody2D *B;
};
- Body2DSW *_arr[2];
+ GodotBody2D *_arr[2] = { nullptr, nullptr };
};
Vector2 A_groove_1;
@@ -117,56 +120,59 @@ class GrooveJoint2DSW : public Joint2DSW {
Vector2 B_anchor;
Vector2 jn_acc;
Vector2 gbias;
- real_t jn_max;
- real_t clamp;
+ real_t jn_max = 0.0;
+ real_t clamp = 0.0;
Vector2 xf_normal;
Vector2 rA, rB;
Vector2 k1, k2;
- bool correct;
+ bool correct = false;
public:
- virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_TYPE_GROOVE; }
+ virtual PhysicsServer2D::JointType get_type() const override { return PhysicsServer2D::JOINT_TYPE_GROOVE; }
- virtual bool setup(real_t p_step);
- virtual void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual bool pre_solve(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
- GrooveJoint2DSW(const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, Body2DSW *p_body_a, Body2DSW *p_body_b);
+ GodotGrooveJoint2D(const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, GodotBody2D *p_body_a, GodotBody2D *p_body_b);
};
-class DampedSpringJoint2DSW : public Joint2DSW {
+class GodotDampedSpringJoint2D : public GodotJoint2D {
union {
struct {
- Body2DSW *A;
- Body2DSW *B;
+ GodotBody2D *A;
+ GodotBody2D *B;
};
- Body2DSW *_arr[2];
+ GodotBody2D *_arr[2] = { nullptr, nullptr };
};
Vector2 anchor_A;
Vector2 anchor_B;
- real_t rest_length;
- real_t damping;
- real_t stiffness;
+ real_t rest_length = 0.0;
+ real_t damping = 1.5;
+ real_t stiffness = 20.0;
Vector2 rA, rB;
Vector2 n;
- real_t n_mass;
- real_t target_vrn;
- real_t v_coef;
+ Vector2 j;
+ real_t n_mass = 0.0;
+ real_t target_vrn = 0.0;
+ real_t v_coef = 0.0;
public:
- virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_TYPE_DAMPED_SPRING; }
+ virtual PhysicsServer2D::JointType get_type() const override { return PhysicsServer2D::JOINT_TYPE_DAMPED_SPRING; }
- virtual bool setup(real_t p_step);
- virtual void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual bool pre_solve(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
void set_param(PhysicsServer2D::DampedSpringParam p_param, real_t p_value);
real_t get_param(PhysicsServer2D::DampedSpringParam p_param) const;
- DampedSpringJoint2DSW(const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, Body2DSW *p_body_a, Body2DSW *p_body_b);
+ GodotDampedSpringJoint2D(const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, GodotBody2D *p_body_a, GodotBody2D *p_body_b);
};
-#endif // JOINTS_2D_SW_H
+#endif // GODOT_JOINTS_2D_H
diff --git a/servers/physics_2d/godot_physics_server_2d.cpp b/servers/physics_2d/godot_physics_server_2d.cpp
new file mode 100644
index 0000000000..99e68de07c
--- /dev/null
+++ b/servers/physics_2d/godot_physics_server_2d.cpp
@@ -0,0 +1,1353 @@
+/*************************************************************************/
+/* godot_physics_server_2d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 "godot_physics_server_2d.h"
+
+#include "godot_body_direct_state_2d.h"
+#include "godot_broad_phase_2d_bvh.h"
+#include "godot_collision_solver_2d.h"
+
+#include "core/config/project_settings.h"
+#include "core/debugger/engine_debugger.h"
+#include "core/os/os.h"
+
+#define FLUSH_QUERY_CHECK(m_object) \
+ ERR_FAIL_COND_MSG(m_object->get_space() && flushing_queries, "Can't change this state while flushing queries. Use call_deferred() or set_deferred() to change monitoring state instead.");
+
+RID GodotPhysicsServer2D::_shape_create(ShapeType p_shape) {
+ GodotShape2D *shape = nullptr;
+ switch (p_shape) {
+ case SHAPE_WORLD_BOUNDARY: {
+ shape = memnew(GodotWorldBoundaryShape2D);
+ } break;
+ case SHAPE_SEPARATION_RAY: {
+ shape = memnew(GodotSeparationRayShape2D);
+ } break;
+ case SHAPE_SEGMENT: {
+ shape = memnew(GodotSegmentShape2D);
+ } break;
+ case SHAPE_CIRCLE: {
+ shape = memnew(GodotCircleShape2D);
+ } break;
+ case SHAPE_RECTANGLE: {
+ shape = memnew(GodotRectangleShape2D);
+ } break;
+ case SHAPE_CAPSULE: {
+ shape = memnew(GodotCapsuleShape2D);
+ } break;
+ case SHAPE_CONVEX_POLYGON: {
+ shape = memnew(GodotConvexPolygonShape2D);
+ } break;
+ case SHAPE_CONCAVE_POLYGON: {
+ shape = memnew(GodotConcavePolygonShape2D);
+ } break;
+ case SHAPE_CUSTOM: {
+ ERR_FAIL_V(RID());
+
+ } break;
+ }
+
+ RID id = shape_owner.make_rid(shape);
+ shape->set_self(id);
+
+ return id;
+}
+
+RID GodotPhysicsServer2D::world_boundary_shape_create() {
+ return _shape_create(SHAPE_WORLD_BOUNDARY);
+}
+
+RID GodotPhysicsServer2D::separation_ray_shape_create() {
+ return _shape_create(SHAPE_SEPARATION_RAY);
+}
+
+RID GodotPhysicsServer2D::segment_shape_create() {
+ return _shape_create(SHAPE_SEGMENT);
+}
+
+RID GodotPhysicsServer2D::circle_shape_create() {
+ return _shape_create(SHAPE_CIRCLE);
+}
+
+RID GodotPhysicsServer2D::rectangle_shape_create() {
+ return _shape_create(SHAPE_RECTANGLE);
+}
+
+RID GodotPhysicsServer2D::capsule_shape_create() {
+ return _shape_create(SHAPE_CAPSULE);
+}
+
+RID GodotPhysicsServer2D::convex_polygon_shape_create() {
+ return _shape_create(SHAPE_CONVEX_POLYGON);
+}
+
+RID GodotPhysicsServer2D::concave_polygon_shape_create() {
+ return _shape_create(SHAPE_CONCAVE_POLYGON);
+}
+
+void GodotPhysicsServer2D::shape_set_data(RID p_shape, const Variant &p_data) {
+ GodotShape2D *shape = shape_owner.get_or_null(p_shape);
+ ERR_FAIL_COND(!shape);
+ shape->set_data(p_data);
+};
+
+void GodotPhysicsServer2D::shape_set_custom_solver_bias(RID p_shape, real_t p_bias) {
+ GodotShape2D *shape = shape_owner.get_or_null(p_shape);
+ ERR_FAIL_COND(!shape);
+ shape->set_custom_bias(p_bias);
+}
+
+PhysicsServer2D::ShapeType GodotPhysicsServer2D::shape_get_type(RID p_shape) const {
+ const GodotShape2D *shape = shape_owner.get_or_null(p_shape);
+ ERR_FAIL_COND_V(!shape, SHAPE_CUSTOM);
+ return shape->get_type();
+};
+
+Variant GodotPhysicsServer2D::shape_get_data(RID p_shape) const {
+ const GodotShape2D *shape = shape_owner.get_or_null(p_shape);
+ ERR_FAIL_COND_V(!shape, Variant());
+ ERR_FAIL_COND_V(!shape->is_configured(), Variant());
+ return shape->get_data();
+};
+
+real_t GodotPhysicsServer2D::shape_get_custom_solver_bias(RID p_shape) const {
+ const GodotShape2D *shape = shape_owner.get_or_null(p_shape);
+ ERR_FAIL_COND_V(!shape, 0);
+ return shape->get_custom_bias();
+}
+
+void GodotPhysicsServer2D::_shape_col_cbk(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_userdata) {
+ CollCbkData *cbk = static_cast<CollCbkData *>(p_userdata);
+
+ if (cbk->max == 0) {
+ return;
+ }
+
+ Vector2 rel_dir = (p_point_A - p_point_B);
+ real_t rel_length2 = rel_dir.length_squared();
+ if (cbk->valid_dir != Vector2()) {
+ if (cbk->valid_depth < 10e20) {
+ if (rel_length2 > cbk->valid_depth * cbk->valid_depth ||
+ (rel_length2 > CMP_EPSILON && cbk->valid_dir.dot(rel_dir.normalized()) < CMP_EPSILON)) {
+ cbk->invalid_by_dir++;
+ return;
+ }
+ } else {
+ if (rel_length2 > 0 && cbk->valid_dir.dot(rel_dir.normalized()) < CMP_EPSILON) {
+ return;
+ }
+ }
+ }
+
+ if (cbk->amount == cbk->max) {
+ //find least deep
+ real_t min_depth = 1e20;
+ int min_depth_idx = 0;
+ for (int i = 0; i < cbk->amount; i++) {
+ real_t d = cbk->ptr[i * 2 + 0].distance_squared_to(cbk->ptr[i * 2 + 1]);
+ if (d < min_depth) {
+ min_depth = d;
+ min_depth_idx = i;
+ }
+ }
+
+ if (rel_length2 < min_depth) {
+ return;
+ }
+ cbk->ptr[min_depth_idx * 2 + 0] = p_point_A;
+ cbk->ptr[min_depth_idx * 2 + 1] = p_point_B;
+ cbk->passed++;
+
+ } else {
+ cbk->ptr[cbk->amount * 2 + 0] = p_point_A;
+ cbk->ptr[cbk->amount * 2 + 1] = p_point_B;
+ cbk->amount++;
+ cbk->passed++;
+ }
+}
+
+bool GodotPhysicsServer2D::shape_collide(RID p_shape_A, const Transform2D &p_xform_A, const Vector2 &p_motion_A, RID p_shape_B, const Transform2D &p_xform_B, const Vector2 &p_motion_B, Vector2 *r_results, int p_result_max, int &r_result_count) {
+ GodotShape2D *shape_A = shape_owner.get_or_null(p_shape_A);
+ ERR_FAIL_COND_V(!shape_A, false);
+ GodotShape2D *shape_B = shape_owner.get_or_null(p_shape_B);
+ ERR_FAIL_COND_V(!shape_B, false);
+
+ if (p_result_max == 0) {
+ return GodotCollisionSolver2D::solve(shape_A, p_xform_A, p_motion_A, shape_B, p_xform_B, p_motion_B, nullptr, nullptr);
+ }
+
+ CollCbkData cbk;
+ cbk.max = p_result_max;
+ cbk.amount = 0;
+ cbk.passed = 0;
+ cbk.ptr = r_results;
+
+ bool res = GodotCollisionSolver2D::solve(shape_A, p_xform_A, p_motion_A, shape_B, p_xform_B, p_motion_B, _shape_col_cbk, &cbk);
+ r_result_count = cbk.amount;
+ return res;
+}
+
+RID GodotPhysicsServer2D::space_create() {
+ GodotSpace2D *space = memnew(GodotSpace2D);
+ RID id = space_owner.make_rid(space);
+ space->set_self(id);
+ RID area_id = area_create();
+ GodotArea2D *area = area_owner.get_or_null(area_id);
+ ERR_FAIL_COND_V(!area, RID());
+ space->set_default_area(area);
+ area->set_space(space);
+ area->set_priority(-1);
+
+ return id;
+};
+
+void GodotPhysicsServer2D::space_set_active(RID p_space, bool p_active) {
+ GodotSpace2D *space = space_owner.get_or_null(p_space);
+ ERR_FAIL_COND(!space);
+ if (p_active) {
+ active_spaces.insert(space);
+ } else {
+ active_spaces.erase(space);
+ }
+}
+
+bool GodotPhysicsServer2D::space_is_active(RID p_space) const {
+ const GodotSpace2D *space = space_owner.get_or_null(p_space);
+ ERR_FAIL_COND_V(!space, false);
+
+ return active_spaces.has(space);
+}
+
+void GodotPhysicsServer2D::space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) {
+ GodotSpace2D *space = space_owner.get_or_null(p_space);
+ ERR_FAIL_COND(!space);
+
+ space->set_param(p_param, p_value);
+}
+
+real_t GodotPhysicsServer2D::space_get_param(RID p_space, SpaceParameter p_param) const {
+ const GodotSpace2D *space = space_owner.get_or_null(p_space);
+ ERR_FAIL_COND_V(!space, 0);
+ return space->get_param(p_param);
+}
+
+void GodotPhysicsServer2D::space_set_debug_contacts(RID p_space, int p_max_contacts) {
+ GodotSpace2D *space = space_owner.get_or_null(p_space);
+ ERR_FAIL_COND(!space);
+ space->set_debug_contacts(p_max_contacts);
+}
+
+Vector<Vector2> GodotPhysicsServer2D::space_get_contacts(RID p_space) const {
+ GodotSpace2D *space = space_owner.get_or_null(p_space);
+ ERR_FAIL_COND_V(!space, Vector<Vector2>());
+ return space->get_debug_contacts();
+}
+
+int GodotPhysicsServer2D::space_get_contact_count(RID p_space) const {
+ GodotSpace2D *space = space_owner.get_or_null(p_space);
+ ERR_FAIL_COND_V(!space, 0);
+ return space->get_debug_contact_count();
+}
+
+PhysicsDirectSpaceState2D *GodotPhysicsServer2D::space_get_direct_state(RID p_space) {
+ GodotSpace2D *space = space_owner.get_or_null(p_space);
+ ERR_FAIL_COND_V(!space, nullptr);
+ ERR_FAIL_COND_V_MSG((using_threads && !doing_sync) || space->is_locked(), nullptr, "Space state is inaccessible right now, wait for iteration or physics process notification.");
+
+ return space->get_direct_state();
+}
+
+RID GodotPhysicsServer2D::area_create() {
+ GodotArea2D *area = memnew(GodotArea2D);
+ RID rid = area_owner.make_rid(area);
+ area->set_self(rid);
+ return rid;
+}
+
+void GodotPhysicsServer2D::area_set_space(RID p_area, RID p_space) {
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND(!area);
+
+ GodotSpace2D *space = nullptr;
+ if (p_space.is_valid()) {
+ space = space_owner.get_or_null(p_space);
+ ERR_FAIL_COND(!space);
+ }
+
+ if (area->get_space() == space) {
+ return; //pointless
+ }
+
+ area->clear_constraints();
+ area->set_space(space);
+}
+
+RID GodotPhysicsServer2D::area_get_space(RID p_area) const {
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND_V(!area, RID());
+
+ GodotSpace2D *space = area->get_space();
+ if (!space) {
+ return RID();
+ }
+ return space->get_self();
+}
+
+void GodotPhysicsServer2D::area_add_shape(RID p_area, RID p_shape, const Transform2D &p_transform, bool p_disabled) {
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND(!area);
+
+ GodotShape2D *shape = shape_owner.get_or_null(p_shape);
+ ERR_FAIL_COND(!shape);
+
+ area->add_shape(shape, p_transform, p_disabled);
+}
+
+void GodotPhysicsServer2D::area_set_shape(RID p_area, int p_shape_idx, RID p_shape) {
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND(!area);
+
+ GodotShape2D *shape = shape_owner.get_or_null(p_shape);
+ ERR_FAIL_COND(!shape);
+ ERR_FAIL_COND(!shape->is_configured());
+
+ area->set_shape(p_shape_idx, shape);
+}
+
+void GodotPhysicsServer2D::area_set_shape_transform(RID p_area, int p_shape_idx, const Transform2D &p_transform) {
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_shape_transform(p_shape_idx, p_transform);
+}
+
+void GodotPhysicsServer2D::area_set_shape_disabled(RID p_area, int p_shape, bool p_disabled) {
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND(!area);
+ ERR_FAIL_INDEX(p_shape, area->get_shape_count());
+ FLUSH_QUERY_CHECK(area);
+
+ area->set_shape_disabled(p_shape, p_disabled);
+}
+
+int GodotPhysicsServer2D::area_get_shape_count(RID p_area) const {
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND_V(!area, -1);
+
+ return area->get_shape_count();
+}
+
+RID GodotPhysicsServer2D::area_get_shape(RID p_area, int p_shape_idx) const {
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND_V(!area, RID());
+
+ GodotShape2D *shape = area->get_shape(p_shape_idx);
+ ERR_FAIL_COND_V(!shape, RID());
+
+ return shape->get_self();
+}
+
+Transform2D GodotPhysicsServer2D::area_get_shape_transform(RID p_area, int p_shape_idx) const {
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND_V(!area, Transform2D());
+
+ return area->get_shape_transform(p_shape_idx);
+}
+
+void GodotPhysicsServer2D::area_remove_shape(RID p_area, int p_shape_idx) {
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->remove_shape(p_shape_idx);
+}
+
+void GodotPhysicsServer2D::area_clear_shapes(RID p_area) {
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND(!area);
+
+ while (area->get_shape_count()) {
+ area->remove_shape(0);
+ }
+}
+
+void GodotPhysicsServer2D::area_attach_object_instance_id(RID p_area, ObjectID p_id) {
+ if (space_owner.owns(p_area)) {
+ GodotSpace2D *space = space_owner.get_or_null(p_area);
+ p_area = space->get_default_area()->get_self();
+ }
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND(!area);
+ area->set_instance_id(p_id);
+}
+
+ObjectID GodotPhysicsServer2D::area_get_object_instance_id(RID p_area) const {
+ if (space_owner.owns(p_area)) {
+ GodotSpace2D *space = space_owner.get_or_null(p_area);
+ p_area = space->get_default_area()->get_self();
+ }
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND_V(!area, ObjectID());
+ return area->get_instance_id();
+}
+
+void GodotPhysicsServer2D::area_attach_canvas_instance_id(RID p_area, ObjectID p_id) {
+ if (space_owner.owns(p_area)) {
+ GodotSpace2D *space = space_owner.get_or_null(p_area);
+ p_area = space->get_default_area()->get_self();
+ }
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND(!area);
+ area->set_canvas_instance_id(p_id);
+}
+
+ObjectID GodotPhysicsServer2D::area_get_canvas_instance_id(RID p_area) const {
+ if (space_owner.owns(p_area)) {
+ GodotSpace2D *space = space_owner.get_or_null(p_area);
+ p_area = space->get_default_area()->get_self();
+ }
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND_V(!area, ObjectID());
+ return area->get_canvas_instance_id();
+}
+
+void GodotPhysicsServer2D::area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) {
+ if (space_owner.owns(p_area)) {
+ GodotSpace2D *space = space_owner.get_or_null(p_area);
+ p_area = space->get_default_area()->get_self();
+ }
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND(!area);
+ area->set_param(p_param, p_value);
+};
+
+void GodotPhysicsServer2D::area_set_transform(RID p_area, const Transform2D &p_transform) {
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND(!area);
+ area->set_transform(p_transform);
+};
+
+Variant GodotPhysicsServer2D::area_get_param(RID p_area, AreaParameter p_param) const {
+ if (space_owner.owns(p_area)) {
+ GodotSpace2D *space = space_owner.get_or_null(p_area);
+ p_area = space->get_default_area()->get_self();
+ }
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND_V(!area, Variant());
+
+ return area->get_param(p_param);
+};
+
+Transform2D GodotPhysicsServer2D::area_get_transform(RID p_area) const {
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND_V(!area, Transform2D());
+
+ return area->get_transform();
+};
+
+void GodotPhysicsServer2D::area_set_pickable(RID p_area, bool p_pickable) {
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND(!area);
+ area->set_pickable(p_pickable);
+}
+
+void GodotPhysicsServer2D::area_set_monitorable(RID p_area, bool p_monitorable) {
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND(!area);
+ FLUSH_QUERY_CHECK(area);
+
+ area->set_monitorable(p_monitorable);
+}
+
+void GodotPhysicsServer2D::area_set_collision_mask(RID p_area, uint32_t p_mask) {
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_collision_mask(p_mask);
+}
+
+void GodotPhysicsServer2D::area_set_collision_layer(RID p_area, uint32_t p_layer) {
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_collision_layer(p_layer);
+}
+
+void GodotPhysicsServer2D::area_set_monitor_callback(RID p_area, const Callable &p_callback) {
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_monitor_callback(p_callback.is_valid() ? p_callback : Callable());
+}
+
+void GodotPhysicsServer2D::area_set_area_monitor_callback(RID p_area, const Callable &p_callback) {
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_area_monitor_callback(p_callback.is_valid() ? p_callback : Callable());
+}
+
+/* BODY API */
+
+RID GodotPhysicsServer2D::body_create() {
+ GodotBody2D *body = memnew(GodotBody2D);
+ RID rid = body_owner.make_rid(body);
+ body->set_self(rid);
+ return rid;
+}
+
+void GodotPhysicsServer2D::body_set_space(RID p_body, RID p_space) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+ GodotSpace2D *space = nullptr;
+ if (p_space.is_valid()) {
+ space = space_owner.get_or_null(p_space);
+ ERR_FAIL_COND(!space);
+ }
+
+ if (body->get_space() == space) {
+ return; //pointless
+ }
+
+ body->clear_constraint_list();
+ body->set_space(space);
+};
+
+RID GodotPhysicsServer2D::body_get_space(RID p_body) const {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND_V(!body, RID());
+
+ GodotSpace2D *space = body->get_space();
+ if (!space) {
+ return RID();
+ }
+ return space->get_self();
+};
+
+void GodotPhysicsServer2D::body_set_mode(RID p_body, BodyMode p_mode) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+ FLUSH_QUERY_CHECK(body);
+
+ body->set_mode(p_mode);
+};
+
+PhysicsServer2D::BodyMode GodotPhysicsServer2D::body_get_mode(RID p_body) const {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND_V(!body, BODY_MODE_STATIC);
+
+ return body->get_mode();
+};
+
+void GodotPhysicsServer2D::body_add_shape(RID p_body, RID p_shape, const Transform2D &p_transform, bool p_disabled) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+
+ GodotShape2D *shape = shape_owner.get_or_null(p_shape);
+ ERR_FAIL_COND(!shape);
+
+ body->add_shape(shape, p_transform, p_disabled);
+}
+
+void GodotPhysicsServer2D::body_set_shape(RID p_body, int p_shape_idx, RID p_shape) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+
+ GodotShape2D *shape = shape_owner.get_or_null(p_shape);
+ ERR_FAIL_COND(!shape);
+ ERR_FAIL_COND(!shape->is_configured());
+
+ body->set_shape(p_shape_idx, shape);
+}
+
+void GodotPhysicsServer2D::body_set_shape_transform(RID p_body, int p_shape_idx, const Transform2D &p_transform) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_shape_transform(p_shape_idx, p_transform);
+}
+
+int GodotPhysicsServer2D::body_get_shape_count(RID p_body) const {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND_V(!body, -1);
+
+ return body->get_shape_count();
+}
+
+RID GodotPhysicsServer2D::body_get_shape(RID p_body, int p_shape_idx) const {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND_V(!body, RID());
+
+ GodotShape2D *shape = body->get_shape(p_shape_idx);
+ ERR_FAIL_COND_V(!shape, RID());
+
+ return shape->get_self();
+}
+
+Transform2D GodotPhysicsServer2D::body_get_shape_transform(RID p_body, int p_shape_idx) const {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND_V(!body, Transform2D());
+
+ return body->get_shape_transform(p_shape_idx);
+}
+
+void GodotPhysicsServer2D::body_remove_shape(RID p_body, int p_shape_idx) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->remove_shape(p_shape_idx);
+}
+
+void GodotPhysicsServer2D::body_clear_shapes(RID p_body) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+
+ while (body->get_shape_count()) {
+ body->remove_shape(0);
+ }
+}
+
+void GodotPhysicsServer2D::body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+ ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count());
+ FLUSH_QUERY_CHECK(body);
+
+ body->set_shape_disabled(p_shape_idx, p_disabled);
+}
+
+void GodotPhysicsServer2D::body_set_shape_as_one_way_collision(RID p_body, int p_shape_idx, bool p_enable, real_t p_margin) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+ ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count());
+ FLUSH_QUERY_CHECK(body);
+
+ body->set_shape_as_one_way_collision(p_shape_idx, p_enable, p_margin);
+}
+
+void GodotPhysicsServer2D::body_set_continuous_collision_detection_mode(RID p_body, CCDMode p_mode) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+ body->set_continuous_collision_detection_mode(p_mode);
+}
+
+GodotPhysicsServer2D::CCDMode GodotPhysicsServer2D::body_get_continuous_collision_detection_mode(RID p_body) const {
+ const GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND_V(!body, CCD_MODE_DISABLED);
+
+ return body->get_continuous_collision_detection_mode();
+}
+
+void GodotPhysicsServer2D::body_attach_object_instance_id(RID p_body, ObjectID p_id) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_instance_id(p_id);
+}
+
+ObjectID GodotPhysicsServer2D::body_get_object_instance_id(RID p_body) const {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND_V(!body, ObjectID());
+
+ return body->get_instance_id();
+}
+
+void GodotPhysicsServer2D::body_attach_canvas_instance_id(RID p_body, ObjectID p_id) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_canvas_instance_id(p_id);
+}
+
+ObjectID GodotPhysicsServer2D::body_get_canvas_instance_id(RID p_body) const {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND_V(!body, ObjectID());
+
+ return body->get_canvas_instance_id();
+}
+
+void GodotPhysicsServer2D::body_set_collision_layer(RID p_body, uint32_t p_layer) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+ body->set_collision_layer(p_layer);
+}
+
+uint32_t GodotPhysicsServer2D::body_get_collision_layer(RID p_body) const {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+
+ return body->get_collision_layer();
+}
+
+void GodotPhysicsServer2D::body_set_collision_mask(RID p_body, uint32_t p_mask) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+ body->set_collision_mask(p_mask);
+}
+
+uint32_t GodotPhysicsServer2D::body_get_collision_mask(RID p_body) const {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+
+ return body->get_collision_mask();
+}
+
+void GodotPhysicsServer2D::body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_param(p_param, p_value);
+}
+
+Variant GodotPhysicsServer2D::body_get_param(RID p_body, BodyParameter p_param) const {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+
+ return body->get_param(p_param);
+}
+
+void GodotPhysicsServer2D::body_reset_mass_properties(RID p_body) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+
+ return body->reset_mass_properties();
+}
+
+void GodotPhysicsServer2D::body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_state(p_state, p_variant);
+}
+
+Variant GodotPhysicsServer2D::body_get_state(RID p_body, BodyState p_state) const {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND_V(!body, Variant());
+
+ return body->get_state(p_state);
+}
+
+void GodotPhysicsServer2D::body_apply_central_impulse(RID p_body, const Vector2 &p_impulse) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->apply_central_impulse(p_impulse);
+ body->wakeup();
+}
+
+void GodotPhysicsServer2D::body_apply_torque_impulse(RID p_body, real_t p_torque) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+
+ _update_shapes();
+
+ body->apply_torque_impulse(p_torque);
+ body->wakeup();
+}
+
+void GodotPhysicsServer2D::body_apply_impulse(RID p_body, const Vector2 &p_impulse, const Vector2 &p_position) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+
+ _update_shapes();
+
+ body->apply_impulse(p_impulse, p_position);
+ body->wakeup();
+}
+
+void GodotPhysicsServer2D::body_apply_central_force(RID p_body, const Vector2 &p_force) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->apply_central_force(p_force);
+ body->wakeup();
+}
+
+void GodotPhysicsServer2D::body_apply_force(RID p_body, const Vector2 &p_force, const Vector2 &p_position) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->apply_force(p_force, p_position);
+ body->wakeup();
+}
+
+void GodotPhysicsServer2D::body_apply_torque(RID p_body, real_t p_torque) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->apply_torque(p_torque);
+ body->wakeup();
+}
+
+void GodotPhysicsServer2D::body_add_constant_central_force(RID p_body, const Vector2 &p_force) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->add_constant_central_force(p_force);
+ body->wakeup();
+}
+
+void GodotPhysicsServer2D::body_add_constant_force(RID p_body, const Vector2 &p_force, const Vector2 &p_position) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->add_constant_force(p_force, p_position);
+ body->wakeup();
+}
+
+void GodotPhysicsServer2D::body_add_constant_torque(RID p_body, real_t p_torque) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->add_constant_torque(p_torque);
+ body->wakeup();
+}
+
+void GodotPhysicsServer2D::body_set_constant_force(RID p_body, const Vector2 &p_force) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_constant_force(p_force);
+ if (!p_force.is_equal_approx(Vector2())) {
+ body->wakeup();
+ }
+}
+
+Vector2 GodotPhysicsServer2D::body_get_constant_force(RID p_body) const {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND_V(!body, Vector2());
+ return body->get_constant_force();
+}
+
+void GodotPhysicsServer2D::body_set_constant_torque(RID p_body, real_t p_torque) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_constant_torque(p_torque);
+ if (!Math::is_zero_approx(p_torque)) {
+ body->wakeup();
+ }
+}
+
+real_t GodotPhysicsServer2D::body_get_constant_torque(RID p_body) const {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+
+ return body->get_constant_torque();
+}
+
+void GodotPhysicsServer2D::body_set_axis_velocity(RID p_body, const Vector2 &p_axis_velocity) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+
+ _update_shapes();
+
+ Vector2 v = body->get_linear_velocity();
+ Vector2 axis = p_axis_velocity.normalized();
+ v -= axis * axis.dot(v);
+ v += p_axis_velocity;
+ body->set_linear_velocity(v);
+ body->wakeup();
+};
+
+void GodotPhysicsServer2D::body_add_collision_exception(RID p_body, RID p_body_b) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->add_exception(p_body_b);
+ body->wakeup();
+};
+
+void GodotPhysicsServer2D::body_remove_collision_exception(RID p_body, RID p_body_b) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->remove_exception(p_body_b);
+ body->wakeup();
+};
+
+void GodotPhysicsServer2D::body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+
+ for (int i = 0; i < body->get_exceptions().size(); i++) {
+ p_exceptions->push_back(body->get_exceptions()[i]);
+ }
+};
+
+void GodotPhysicsServer2D::body_set_contacts_reported_depth_threshold(RID p_body, real_t p_threshold) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+};
+
+real_t GodotPhysicsServer2D::body_get_contacts_reported_depth_threshold(RID p_body) const {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+ return 0;
+};
+
+void GodotPhysicsServer2D::body_set_omit_force_integration(RID p_body, bool p_omit) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_omit_force_integration(p_omit);
+};
+
+bool GodotPhysicsServer2D::body_is_omitting_force_integration(RID p_body) const {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND_V(!body, false);
+ return body->get_omit_force_integration();
+};
+
+void GodotPhysicsServer2D::body_set_max_contacts_reported(RID p_body, int p_contacts) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+ body->set_max_contacts_reported(p_contacts);
+}
+
+int GodotPhysicsServer2D::body_get_max_contacts_reported(RID p_body) const {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND_V(!body, -1);
+ return body->get_max_contacts_reported();
+}
+
+void GodotPhysicsServer2D::body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+ body->set_state_sync_callback(p_instance, p_callback);
+}
+
+void GodotPhysicsServer2D::body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+ body->set_force_integration_callback(p_callable, p_udata);
+}
+
+bool GodotPhysicsServer2D::body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND_V(!body, false);
+ ERR_FAIL_INDEX_V(p_body_shape, body->get_shape_count(), false);
+
+ return shape_collide(body->get_shape(p_body_shape)->get_self(), body->get_transform() * body->get_shape_transform(p_body_shape), Vector2(), p_shape, p_shape_xform, p_motion, r_results, p_result_max, r_result_count);
+}
+
+void GodotPhysicsServer2D::body_set_pickable(RID p_body, bool p_pickable) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+ body->set_pickable(p_pickable);
+}
+
+bool GodotPhysicsServer2D::body_test_motion(RID p_body, const MotionParameters &p_parameters, MotionResult *r_result) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND_V(!body, false);
+ ERR_FAIL_COND_V(!body->get_space(), false);
+ ERR_FAIL_COND_V(body->get_space()->is_locked(), false);
+
+ _update_shapes();
+
+ return body->get_space()->test_body_motion(body, p_parameters, r_result);
+}
+
+PhysicsDirectBodyState2D *GodotPhysicsServer2D::body_get_direct_state(RID p_body) {
+ ERR_FAIL_COND_V_MSG((using_threads && !doing_sync), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification.");
+
+ if (!body_owner.owns(p_body)) {
+ return nullptr;
+ }
+
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND_V(!body, nullptr);
+
+ if (!body->get_space()) {
+ return nullptr;
+ }
+
+ ERR_FAIL_COND_V_MSG(body->get_space()->is_locked(), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification.");
+
+ return body->get_direct_state();
+}
+
+/* JOINT API */
+
+RID GodotPhysicsServer2D::joint_create() {
+ GodotJoint2D *joint = memnew(GodotJoint2D);
+ RID joint_rid = joint_owner.make_rid(joint);
+ joint->set_self(joint_rid);
+ return joint_rid;
+}
+
+void GodotPhysicsServer2D::joint_clear(RID p_joint) {
+ GodotJoint2D *joint = joint_owner.get_or_null(p_joint);
+ if (joint->get_type() != JOINT_TYPE_MAX) {
+ GodotJoint2D *empty_joint = memnew(GodotJoint2D);
+ empty_joint->copy_settings_from(joint);
+
+ joint_owner.replace(p_joint, empty_joint);
+ memdelete(joint);
+ }
+}
+
+void GodotPhysicsServer2D::joint_set_param(RID p_joint, JointParam p_param, real_t p_value) {
+ GodotJoint2D *joint = joint_owner.get_or_null(p_joint);
+ ERR_FAIL_COND(!joint);
+
+ switch (p_param) {
+ case JOINT_PARAM_BIAS:
+ joint->set_bias(p_value);
+ break;
+ case JOINT_PARAM_MAX_BIAS:
+ joint->set_max_bias(p_value);
+ break;
+ case JOINT_PARAM_MAX_FORCE:
+ joint->set_max_force(p_value);
+ break;
+ }
+}
+
+real_t GodotPhysicsServer2D::joint_get_param(RID p_joint, JointParam p_param) const {
+ const GodotJoint2D *joint = joint_owner.get_or_null(p_joint);
+ ERR_FAIL_COND_V(!joint, -1);
+
+ switch (p_param) {
+ case JOINT_PARAM_BIAS:
+ return joint->get_bias();
+ break;
+ case JOINT_PARAM_MAX_BIAS:
+ return joint->get_max_bias();
+ break;
+ case JOINT_PARAM_MAX_FORCE:
+ return joint->get_max_force();
+ break;
+ }
+
+ return 0;
+}
+
+void GodotPhysicsServer2D::joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable) {
+ GodotJoint2D *joint = joint_owner.get_or_null(p_joint);
+ ERR_FAIL_COND(!joint);
+
+ joint->disable_collisions_between_bodies(p_disable);
+
+ if (2 == joint->get_body_count()) {
+ GodotBody2D *body_a = *joint->get_body_ptr();
+ GodotBody2D *body_b = *(joint->get_body_ptr() + 1);
+
+ if (p_disable) {
+ body_add_collision_exception(body_a->get_self(), body_b->get_self());
+ body_add_collision_exception(body_b->get_self(), body_a->get_self());
+ } else {
+ body_remove_collision_exception(body_a->get_self(), body_b->get_self());
+ body_remove_collision_exception(body_b->get_self(), body_a->get_self());
+ }
+ }
+}
+
+bool GodotPhysicsServer2D::joint_is_disabled_collisions_between_bodies(RID p_joint) const {
+ const GodotJoint2D *joint = joint_owner.get_or_null(p_joint);
+ ERR_FAIL_COND_V(!joint, true);
+
+ return joint->is_disabled_collisions_between_bodies();
+}
+
+void GodotPhysicsServer2D::joint_make_pin(RID p_joint, const Vector2 &p_pos, RID p_body_a, RID p_body_b) {
+ GodotBody2D *A = body_owner.get_or_null(p_body_a);
+ ERR_FAIL_COND(!A);
+ GodotBody2D *B = nullptr;
+ if (body_owner.owns(p_body_b)) {
+ B = body_owner.get_or_null(p_body_b);
+ ERR_FAIL_COND(!B);
+ }
+
+ GodotJoint2D *prev_joint = joint_owner.get_or_null(p_joint);
+ ERR_FAIL_COND(prev_joint == nullptr);
+
+ GodotJoint2D *joint = memnew(GodotPinJoint2D(p_pos, A, B));
+
+ joint_owner.replace(p_joint, joint);
+ joint->copy_settings_from(prev_joint);
+ memdelete(prev_joint);
+}
+
+void GodotPhysicsServer2D::joint_make_groove(RID p_joint, const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, RID p_body_a, RID p_body_b) {
+ GodotBody2D *A = body_owner.get_or_null(p_body_a);
+ ERR_FAIL_COND(!A);
+
+ GodotBody2D *B = body_owner.get_or_null(p_body_b);
+ ERR_FAIL_COND(!B);
+
+ GodotJoint2D *prev_joint = joint_owner.get_or_null(p_joint);
+ ERR_FAIL_COND(prev_joint == nullptr);
+
+ GodotJoint2D *joint = memnew(GodotGrooveJoint2D(p_a_groove1, p_a_groove2, p_b_anchor, A, B));
+
+ joint_owner.replace(p_joint, joint);
+ joint->copy_settings_from(prev_joint);
+ memdelete(prev_joint);
+}
+
+void GodotPhysicsServer2D::joint_make_damped_spring(RID p_joint, const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, RID p_body_a, RID p_body_b) {
+ GodotBody2D *A = body_owner.get_or_null(p_body_a);
+ ERR_FAIL_COND(!A);
+
+ GodotBody2D *B = body_owner.get_or_null(p_body_b);
+ ERR_FAIL_COND(!B);
+
+ GodotJoint2D *prev_joint = joint_owner.get_or_null(p_joint);
+ ERR_FAIL_COND(prev_joint == nullptr);
+
+ GodotJoint2D *joint = memnew(GodotDampedSpringJoint2D(p_anchor_a, p_anchor_b, A, B));
+
+ joint_owner.replace(p_joint, joint);
+ joint->copy_settings_from(prev_joint);
+ memdelete(prev_joint);
+}
+
+void GodotPhysicsServer2D::pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) {
+ GodotJoint2D *j = joint_owner.get_or_null(p_joint);
+ ERR_FAIL_COND(!j);
+ ERR_FAIL_COND(j->get_type() != JOINT_TYPE_PIN);
+
+ GodotPinJoint2D *pin_joint = static_cast<GodotPinJoint2D *>(j);
+ pin_joint->set_param(p_param, p_value);
+}
+
+real_t GodotPhysicsServer2D::pin_joint_get_param(RID p_joint, PinJointParam p_param) const {
+ GodotJoint2D *j = joint_owner.get_or_null(p_joint);
+ ERR_FAIL_COND_V(!j, 0);
+ ERR_FAIL_COND_V(j->get_type() != JOINT_TYPE_PIN, 0);
+
+ GodotPinJoint2D *pin_joint = static_cast<GodotPinJoint2D *>(j);
+ return pin_joint->get_param(p_param);
+}
+
+void GodotPhysicsServer2D::damped_spring_joint_set_param(RID p_joint, DampedSpringParam p_param, real_t p_value) {
+ GodotJoint2D *j = joint_owner.get_or_null(p_joint);
+ ERR_FAIL_COND(!j);
+ ERR_FAIL_COND(j->get_type() != JOINT_TYPE_DAMPED_SPRING);
+
+ GodotDampedSpringJoint2D *dsj = static_cast<GodotDampedSpringJoint2D *>(j);
+ dsj->set_param(p_param, p_value);
+}
+
+real_t GodotPhysicsServer2D::damped_spring_joint_get_param(RID p_joint, DampedSpringParam p_param) const {
+ GodotJoint2D *j = joint_owner.get_or_null(p_joint);
+ ERR_FAIL_COND_V(!j, 0);
+ ERR_FAIL_COND_V(j->get_type() != JOINT_TYPE_DAMPED_SPRING, 0);
+
+ GodotDampedSpringJoint2D *dsj = static_cast<GodotDampedSpringJoint2D *>(j);
+ return dsj->get_param(p_param);
+}
+
+PhysicsServer2D::JointType GodotPhysicsServer2D::joint_get_type(RID p_joint) const {
+ GodotJoint2D *joint = joint_owner.get_or_null(p_joint);
+ ERR_FAIL_COND_V(!joint, JOINT_TYPE_PIN);
+
+ return joint->get_type();
+}
+
+void GodotPhysicsServer2D::free(RID p_rid) {
+ _update_shapes(); // just in case
+
+ if (shape_owner.owns(p_rid)) {
+ GodotShape2D *shape = shape_owner.get_or_null(p_rid);
+
+ while (shape->get_owners().size()) {
+ GodotShapeOwner2D *so = shape->get_owners().begin()->key;
+ so->remove_shape(shape);
+ }
+
+ shape_owner.free(p_rid);
+ memdelete(shape);
+ } else if (body_owner.owns(p_rid)) {
+ GodotBody2D *body = body_owner.get_or_null(p_rid);
+
+ body_set_space(p_rid, RID());
+
+ while (body->get_shape_count()) {
+ body->remove_shape(0);
+ }
+
+ body_owner.free(p_rid);
+ memdelete(body);
+
+ } else if (area_owner.owns(p_rid)) {
+ GodotArea2D *area = area_owner.get_or_null(p_rid);
+
+ area->set_space(nullptr);
+
+ while (area->get_shape_count()) {
+ area->remove_shape(0);
+ }
+
+ area_owner.free(p_rid);
+ memdelete(area);
+ } else if (space_owner.owns(p_rid)) {
+ GodotSpace2D *space = space_owner.get_or_null(p_rid);
+
+ while (space->get_objects().size()) {
+ GodotCollisionObject2D *co = static_cast<GodotCollisionObject2D *>(*space->get_objects().begin());
+ co->set_space(nullptr);
+ }
+
+ active_spaces.erase(space);
+ free(space->get_default_area()->get_self());
+ space_owner.free(p_rid);
+ memdelete(space);
+ } else if (joint_owner.owns(p_rid)) {
+ GodotJoint2D *joint = joint_owner.get_or_null(p_rid);
+
+ joint_owner.free(p_rid);
+ memdelete(joint);
+
+ } else {
+ ERR_FAIL_MSG("Invalid ID.");
+ }
+}
+
+void GodotPhysicsServer2D::set_active(bool p_active) {
+ active = p_active;
+}
+
+void GodotPhysicsServer2D::init() {
+ doing_sync = false;
+ stepper = memnew(GodotStep2D);
+}
+
+void GodotPhysicsServer2D::step(real_t p_step) {
+ if (!active) {
+ return;
+ }
+
+ _update_shapes();
+
+ island_count = 0;
+ active_objects = 0;
+ collision_pairs = 0;
+ for (const GodotSpace2D *E : active_spaces) {
+ stepper->step(const_cast<GodotSpace2D *>(E), p_step);
+ island_count += E->get_island_count();
+ active_objects += E->get_active_objects();
+ collision_pairs += E->get_collision_pairs();
+ }
+}
+
+void GodotPhysicsServer2D::sync() {
+ doing_sync = true;
+}
+
+void GodotPhysicsServer2D::flush_queries() {
+ if (!active) {
+ return;
+ }
+
+ flushing_queries = true;
+
+ uint64_t time_beg = OS::get_singleton()->get_ticks_usec();
+
+ for (const GodotSpace2D *E : active_spaces) {
+ GodotSpace2D *space = const_cast<GodotSpace2D *>(E);
+ space->call_queries();
+ }
+
+ flushing_queries = false;
+
+ if (EngineDebugger::is_profiling("servers")) {
+ uint64_t total_time[GodotSpace2D::ELAPSED_TIME_MAX];
+ static const char *time_name[GodotSpace2D::ELAPSED_TIME_MAX] = {
+ "integrate_forces",
+ "generate_islands",
+ "setup_constraints",
+ "solve_constraints",
+ "integrate_velocities"
+ };
+
+ for (int i = 0; i < GodotSpace2D::ELAPSED_TIME_MAX; i++) {
+ total_time[i] = 0;
+ }
+
+ for (const GodotSpace2D *E : active_spaces) {
+ for (int i = 0; i < GodotSpace2D::ELAPSED_TIME_MAX; i++) {
+ total_time[i] += E->get_elapsed_time(GodotSpace2D::ElapsedTime(i));
+ }
+ }
+
+ Array values;
+ values.resize(GodotSpace2D::ELAPSED_TIME_MAX * 2);
+ for (int i = 0; i < GodotSpace2D::ELAPSED_TIME_MAX; i++) {
+ values[i * 2 + 0] = time_name[i];
+ values[i * 2 + 1] = USEC_TO_SEC(total_time[i]);
+ }
+ values.push_back("flush_queries");
+ values.push_back(USEC_TO_SEC(OS::get_singleton()->get_ticks_usec() - time_beg));
+
+ values.push_front("physics_2d");
+ EngineDebugger::profiler_add_frame_data("servers", values);
+ }
+}
+
+void GodotPhysicsServer2D::end_sync() {
+ doing_sync = false;
+}
+
+void GodotPhysicsServer2D::finish() {
+ memdelete(stepper);
+}
+
+void GodotPhysicsServer2D::_update_shapes() {
+ while (pending_shape_update_list.first()) {
+ pending_shape_update_list.first()->self()->_shape_changed();
+ pending_shape_update_list.remove(pending_shape_update_list.first());
+ }
+}
+
+int GodotPhysicsServer2D::get_process_info(ProcessInfo p_info) {
+ switch (p_info) {
+ case INFO_ACTIVE_OBJECTS: {
+ return active_objects;
+ } break;
+ case INFO_COLLISION_PAIRS: {
+ return collision_pairs;
+ } break;
+ case INFO_ISLAND_COUNT: {
+ return island_count;
+ } break;
+ }
+
+ return 0;
+}
+
+GodotPhysicsServer2D *GodotPhysicsServer2D::godot_singleton = nullptr;
+
+GodotPhysicsServer2D::GodotPhysicsServer2D(bool p_using_threads) {
+ godot_singleton = this;
+ GodotBroadPhase2D::create_func = GodotBroadPhase2DBVH::_create;
+
+ using_threads = p_using_threads;
+}
diff --git a/servers/physics_2d/physics_server_2d_sw.h b/servers/physics_2d/godot_physics_server_2d.h
index 65c5df0fce..2af6e5c97c 100644
--- a/servers/physics_2d/physics_server_2d_sw.h
+++ b/servers/physics_2d/godot_physics_server_2d.h
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* physics_server_2d_sw.h */
+/* godot_physics_server_2d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -28,50 +28,46 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef PHYSICS_2D_SERVER_SW
-#define PHYSICS_2D_SERVER_SW
+#ifndef GODOT_PHYSICS_SERVER_2D_H
+#define GODOT_PHYSICS_SERVER_2D_H
+
+#include "godot_joints_2d.h"
+#include "godot_shape_2d.h"
+#include "godot_space_2d.h"
+#include "godot_step_2d.h"
#include "core/templates/rid_owner.h"
-#include "joints_2d_sw.h"
#include "servers/physics_server_2d.h"
-#include "shape_2d_sw.h"
-#include "space_2d_sw.h"
-#include "step_2d_sw.h"
-
-class PhysicsServer2DSW : public PhysicsServer2D {
- GDCLASS(PhysicsServer2DSW, PhysicsServer2D);
- friend class PhysicsDirectSpaceState2DSW;
- friend class PhysicsDirectBodyState2DSW;
- bool active;
- int iterations;
- bool doing_sync;
- real_t last_step;
+class GodotPhysicsServer2D : public PhysicsServer2D {
+ GDCLASS(GodotPhysicsServer2D, PhysicsServer2D);
- int island_count;
- int active_objects;
- int collision_pairs;
+ friend class GodotPhysicsDirectSpaceState2D;
+ friend class GodotPhysicsDirectBodyState2D;
+ bool active = true;
+ bool doing_sync = false;
- bool using_threads;
+ int island_count = 0;
+ int active_objects = 0;
+ int collision_pairs = 0;
- bool flushing_queries;
+ bool using_threads = false;
- Step2DSW *stepper;
- Set<const Space2DSW *> active_spaces;
+ bool flushing_queries = false;
- PhysicsDirectBodyState2DSW *direct_state;
+ GodotStep2D *stepper = nullptr;
+ HashSet<const GodotSpace2D *> active_spaces;
- mutable RID_PtrOwner<Shape2DSW, true> shape_owner;
- mutable RID_PtrOwner<Space2DSW, true> space_owner;
- mutable RID_PtrOwner<Area2DSW, true> area_owner;
- mutable RID_PtrOwner<Body2DSW, true> body_owner;
- mutable RID_PtrOwner<Joint2DSW, true> joint_owner;
+ mutable RID_PtrOwner<GodotShape2D, true> shape_owner;
+ mutable RID_PtrOwner<GodotSpace2D, true> space_owner;
+ mutable RID_PtrOwner<GodotArea2D, true> area_owner;
+ mutable RID_PtrOwner<GodotBody2D, true> body_owner;
+ mutable RID_PtrOwner<GodotJoint2D, true> joint_owner;
- static PhysicsServer2DSW *singletonsw;
+ static GodotPhysicsServer2D *godot_singleton;
- //void _clear_query(Query2DSW *p_query);
- friend class CollisionObject2DSW;
- SelfList<CollisionObject2DSW>::List pending_shape_update_list;
+ friend class GodotCollisionObject2D;
+ SelfList<GodotCollisionObject2D>::List pending_shape_update_list;
void _update_shapes();
RID _shape_create(ShapeType p_shape);
@@ -79,16 +75,16 @@ class PhysicsServer2DSW : public PhysicsServer2D {
public:
struct CollCbkData {
Vector2 valid_dir;
- real_t valid_depth;
- int max;
- int amount;
- int passed;
- int invalid_by_dir;
- Vector2 *ptr;
+ real_t valid_depth = 0.0;
+ int max = 0;
+ int amount = 0;
+ int passed = 0;
+ int invalid_by_dir = 0;
+ Vector2 *ptr = nullptr;
};
- virtual RID line_shape_create() override;
- virtual RID ray_shape_create() override;
+ virtual RID world_boundary_shape_create() override;
+ virtual RID separation_ray_shape_create() override;
virtual RID segment_shape_create() override;
virtual RID circle_shape_create() override;
virtual RID rectangle_shape_create() override;
@@ -127,9 +123,6 @@ public:
virtual RID area_create() override;
- virtual void area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) override;
- virtual AreaSpaceOverrideMode area_get_space_override_mode(RID p_area) const override;
-
virtual void area_set_space(RID p_area, RID p_space) override;
virtual RID area_get_space(RID p_area) const override;
@@ -161,8 +154,8 @@ public:
virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) override;
virtual void area_set_collision_layer(RID p_area, uint32_t p_layer) override;
- virtual void area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) override;
- virtual void area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) override;
+ virtual void area_set_monitor_callback(RID p_area, const Callable &p_callback) override;
+ virtual void area_set_area_monitor_callback(RID p_area, const Callable &p_callback) override;
virtual void area_set_pickable(RID p_area, bool p_pickable) override;
@@ -180,12 +173,10 @@ public:
virtual void body_add_shape(RID p_body, RID p_shape, const Transform2D &p_transform = Transform2D(), bool p_disabled = false) override;
virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape) override;
virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform2D &p_transform) override;
- virtual void body_set_shape_metadata(RID p_body, int p_shape_idx, const Variant &p_metadata) override;
virtual int body_get_shape_count(RID p_body) const override;
virtual RID body_get_shape(RID p_body, int p_shape_idx) const override;
virtual Transform2D body_get_shape_transform(RID p_body, int p_shape_idx) const override;
- virtual Variant body_get_shape_metadata(RID p_body, int p_shape_idx) const override;
virtual void body_remove_shape(RID p_body, int p_shape_idx) override;
virtual void body_clear_shapes(RID p_body) override;
@@ -208,25 +199,32 @@ public:
virtual void body_set_collision_mask(RID p_body, uint32_t p_mask) override;
virtual uint32_t body_get_collision_mask(RID p_body) const override;
- virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value) override;
- virtual real_t body_get_param(RID p_body, BodyParameter p_param) const override;
+ virtual void body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) override;
+ virtual Variant body_get_param(RID p_body, BodyParameter p_param) const override;
+
+ virtual void body_reset_mass_properties(RID p_body) override;
virtual void body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) override;
virtual Variant body_get_state(RID p_body, BodyState p_state) const override;
- virtual void body_set_applied_force(RID p_body, const Vector2 &p_force) override;
- virtual Vector2 body_get_applied_force(RID p_body) const override;
-
- virtual void body_set_applied_torque(RID p_body, real_t p_torque) override;
- virtual real_t body_get_applied_torque(RID p_body) const override;
-
- virtual void body_add_central_force(RID p_body, const Vector2 &p_force) override;
- virtual void body_add_force(RID p_body, const Vector2 &p_force, const Vector2 &p_position = Vector2()) override;
- virtual void body_add_torque(RID p_body, real_t p_torque) override;
-
virtual void body_apply_central_impulse(RID p_body, const Vector2 &p_impulse) override;
virtual void body_apply_torque_impulse(RID p_body, real_t p_torque) override;
virtual void body_apply_impulse(RID p_body, const Vector2 &p_impulse, const Vector2 &p_position = Vector2()) override;
+
+ virtual void body_apply_central_force(RID p_body, const Vector2 &p_force) override;
+ virtual void body_apply_force(RID p_body, const Vector2 &p_force, const Vector2 &p_position = Vector2()) override;
+ virtual void body_apply_torque(RID p_body, real_t p_torque) override;
+
+ virtual void body_add_constant_central_force(RID p_body, const Vector2 &p_force) override;
+ virtual void body_add_constant_force(RID p_body, const Vector2 &p_force, const Vector2 &p_position = Vector2()) override;
+ virtual void body_add_constant_torque(RID p_body, real_t p_torque) override;
+
+ virtual void body_set_constant_force(RID p_body, const Vector2 &p_force) override;
+ virtual Vector2 body_get_constant_force(RID p_body) const override;
+
+ virtual void body_set_constant_torque(RID p_body, real_t p_torque) override;
+ virtual real_t body_get_constant_torque(RID p_body) const override;
+
virtual void body_set_axis_velocity(RID p_body, const Vector2 &p_axis_velocity) override;
virtual void body_add_collision_exception(RID p_body, RID p_body_b) override;
@@ -242,13 +240,14 @@ public:
virtual void body_set_max_contacts_reported(RID p_body, int p_contacts) override;
virtual int body_get_max_contacts_reported(RID p_body) const override;
- virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant()) override;
+ virtual void body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) override;
+ virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) override;
+
virtual bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) override;
virtual void body_set_pickable(RID p_body, bool p_pickable) override;
- virtual bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override;
- virtual int body_test_ray_separation(RID p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override;
+ virtual bool body_test_motion(RID p_body, const MotionParameters &p_parameters, MotionResult *r_result = nullptr) override;
// this function only works on physics process, errors and returns null otherwise
virtual PhysicsDirectBodyState2D *body_get_direct_state(RID p_body) override;
@@ -292,8 +291,8 @@ public:
int get_process_info(ProcessInfo p_info) override;
- PhysicsServer2DSW(bool p_using_threads = false);
- ~PhysicsServer2DSW() {}
+ GodotPhysicsServer2D(bool p_using_threads = false);
+ ~GodotPhysicsServer2D() {}
};
-#endif
+#endif // GODOT_PHYSICS_SERVER_2D_H
diff --git a/servers/physics_2d/shape_2d_sw.cpp b/servers/physics_2d/godot_shape_2d.cpp
index 6e7e802a8b..72ade3757b 100644
--- a/servers/physics_2d/shape_2d_sw.cpp
+++ b/servers/physics_2d/godot_shape_2d.cpp
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* shape_2d_sw.cpp */
+/* godot_shape_2d.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -28,59 +28,54 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "shape_2d_sw.h"
+#include "godot_shape_2d.h"
#include "core/math/geometry_2d.h"
#include "core/templates/sort_array.h"
-void Shape2DSW::configure(const Rect2 &p_aabb) {
+void GodotShape2D::configure(const Rect2 &p_aabb) {
aabb = p_aabb;
configured = true;
- for (Map<ShapeOwner2DSW *, int>::Element *E = owners.front(); E; E = E->next()) {
- ShapeOwner2DSW *co = (ShapeOwner2DSW *)E->key();
+ for (const KeyValue<GodotShapeOwner2D *, int> &E : owners) {
+ GodotShapeOwner2D *co = const_cast<GodotShapeOwner2D *>(E.key);
co->_shape_changed();
}
}
-Vector2 Shape2DSW::get_support(const Vector2 &p_normal) const {
+Vector2 GodotShape2D::get_support(const Vector2 &p_normal) const {
Vector2 res[2];
int amnt;
get_supports(p_normal, res, amnt);
return res[0];
}
-void Shape2DSW::add_owner(ShapeOwner2DSW *p_owner) {
- Map<ShapeOwner2DSW *, int>::Element *E = owners.find(p_owner);
+void GodotShape2D::add_owner(GodotShapeOwner2D *p_owner) {
+ HashMap<GodotShapeOwner2D *, int>::Iterator E = owners.find(p_owner);
if (E) {
- E->get()++;
+ E->value++;
} else {
owners[p_owner] = 1;
}
}
-void Shape2DSW::remove_owner(ShapeOwner2DSW *p_owner) {
- Map<ShapeOwner2DSW *, int>::Element *E = owners.find(p_owner);
+void GodotShape2D::remove_owner(GodotShapeOwner2D *p_owner) {
+ HashMap<GodotShapeOwner2D *, int>::Iterator E = owners.find(p_owner);
ERR_FAIL_COND(!E);
- E->get()--;
- if (E->get() == 0) {
- owners.erase(E);
+ E->value--;
+ if (E->value == 0) {
+ owners.remove(E);
}
}
-bool Shape2DSW::is_owner(ShapeOwner2DSW *p_owner) const {
+bool GodotShape2D::is_owner(GodotShapeOwner2D *p_owner) const {
return owners.has(p_owner);
}
-const Map<ShapeOwner2DSW *, int> &Shape2DSW::get_owners() const {
+const HashMap<GodotShapeOwner2D *, int> &GodotShape2D::get_owners() const {
return owners;
}
-Shape2DSW::Shape2DSW() {
- custom_bias = 0;
- configured = false;
-}
-
-Shape2DSW::~Shape2DSW() {
+GodotShape2D::~GodotShape2D() {
ERR_FAIL_COND(owners.size());
}
@@ -88,15 +83,15 @@ Shape2DSW::~Shape2DSW() {
/*********************************************************/
/*********************************************************/
-void LineShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {
+void GodotWorldBoundaryShape2D::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {
r_amount = 0;
}
-bool LineShape2DSW::contains_point(const Vector2 &p_point) const {
+bool GodotWorldBoundaryShape2D::contains_point(const Vector2 &p_point) const {
return normal.dot(p_point) < d;
}
-bool LineShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {
+bool GodotWorldBoundaryShape2D::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {
Vector2 segment = p_begin - p_end;
real_t den = normal.dot(segment);
@@ -118,11 +113,11 @@ bool LineShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_e
return true;
}
-real_t LineShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const {
+real_t GodotWorldBoundaryShape2D::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const {
return 0;
}
-void LineShape2DSW::set_data(const Variant &p_data) {
+void GodotWorldBoundaryShape2D::set_data(const Variant &p_data) {
ERR_FAIL_COND(p_data.get_type() != Variant::ARRAY);
Array arr = p_data;
ERR_FAIL_COND(arr.size() != 2);
@@ -131,7 +126,7 @@ void LineShape2DSW::set_data(const Variant &p_data) {
configure(Rect2(Vector2(-1e4, -1e4), Vector2(1e4 * 2, 1e4 * 2)));
}
-Variant LineShape2DSW::get_data() const {
+Variant GodotWorldBoundaryShape2D::get_data() const {
Array arr;
arr.resize(2);
arr[0] = normal;
@@ -143,7 +138,7 @@ Variant LineShape2DSW::get_data() const {
/*********************************************************/
/*********************************************************/
-void RayShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {
+void GodotSeparationRayShape2D::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {
r_amount = 1;
if (p_normal.y > 0) {
@@ -153,29 +148,29 @@ void RayShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports, in
}
}
-bool RayShape2DSW::contains_point(const Vector2 &p_point) const {
+bool GodotSeparationRayShape2D::contains_point(const Vector2 &p_point) const {
return false;
}
-bool RayShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {
+bool GodotSeparationRayShape2D::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {
return false; //rays can't be intersected
}
-real_t RayShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const {
+real_t GodotSeparationRayShape2D::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const {
return 0; //rays are mass-less
}
-void RayShape2DSW::set_data(const Variant &p_data) {
+void GodotSeparationRayShape2D::set_data(const Variant &p_data) {
Dictionary d = p_data;
length = d["length"];
- slips_on_slope = d["slips_on_slope"];
+ slide_on_slope = d["slide_on_slope"];
configure(Rect2(0, 0, 0.001, length));
}
-Variant RayShape2DSW::get_data() const {
+Variant GodotSeparationRayShape2D::get_data() const {
Dictionary d;
d["length"] = length;
- d["slips_on_slope"] = slips_on_slope;
+ d["slide_on_slope"] = slide_on_slope;
return d;
}
@@ -183,7 +178,7 @@ Variant RayShape2DSW::get_data() const {
/*********************************************************/
/*********************************************************/
-void SegmentShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {
+void GodotSegmentShape2D::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {
if (Math::abs(p_normal.dot(n)) > _SEGMENT_IS_VALID_SUPPORT_THRESHOLD) {
r_supports[0] = a;
r_supports[1] = b;
@@ -200,11 +195,11 @@ void SegmentShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports
r_amount = 1;
}
-bool SegmentShape2DSW::contains_point(const Vector2 &p_point) const {
+bool GodotSegmentShape2D::contains_point(const Vector2 &p_point) const {
return false;
}
-bool SegmentShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {
+bool GodotSegmentShape2D::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {
if (!Geometry2D::segment_intersects_segment(p_begin, p_end, a, b, &r_point)) {
return false;
}
@@ -218,11 +213,11 @@ bool SegmentShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &
return true;
}
-real_t SegmentShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const {
+real_t GodotSegmentShape2D::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const {
return p_mass * ((a * p_scale).distance_squared_to(b * p_scale)) / 12;
}
-void SegmentShape2DSW::set_data(const Variant &p_data) {
+void GodotSegmentShape2D::set_data(const Variant &p_data) {
ERR_FAIL_COND(p_data.get_type() != Variant::RECT2);
Rect2 r = p_data;
@@ -242,7 +237,7 @@ void SegmentShape2DSW::set_data(const Variant &p_data) {
configure(aabb);
}
-Variant SegmentShape2DSW::get_data() const {
+Variant GodotSegmentShape2D::get_data() const {
Rect2 r;
r.position = a;
r.size = b;
@@ -253,16 +248,16 @@ Variant SegmentShape2DSW::get_data() const {
/*********************************************************/
/*********************************************************/
-void CircleShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {
+void GodotCircleShape2D::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {
r_amount = 1;
*r_supports = p_normal * radius;
}
-bool CircleShape2DSW::contains_point(const Vector2 &p_point) const {
+bool GodotCircleShape2D::contains_point(const Vector2 &p_point) const {
return p_point.length_squared() < radius * radius;
}
-bool CircleShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {
+bool GodotCircleShape2D::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {
Vector2 line_vec = p_end - p_begin;
real_t a, b, c;
@@ -288,19 +283,19 @@ bool CircleShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p
return true;
}
-real_t CircleShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const {
+real_t GodotCircleShape2D::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const {
real_t a = radius * p_scale.x;
real_t b = radius * p_scale.y;
return p_mass * (a * a + b * b) / 4;
}
-void CircleShape2DSW::set_data(const Variant &p_data) {
+void GodotCircleShape2D::set_data(const Variant &p_data) {
ERR_FAIL_COND(!p_data.is_num());
radius = p_data;
configure(Rect2(-radius, -radius, radius * 2, radius * 2));
}
-Variant CircleShape2DSW::get_data() const {
+Variant GodotCircleShape2D::get_data() const {
return radius;
}
@@ -308,7 +303,7 @@ Variant CircleShape2DSW::get_data() const {
/*********************************************************/
/*********************************************************/
-void RectangleShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {
+void GodotRectangleShape2D::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {
for (int i = 0; i < 2; i++) {
Vector2 ag;
ag[i] = 1.0;
@@ -338,7 +333,7 @@ void RectangleShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_suppor
(p_normal.y < 0) ? -half_extents.y : half_extents.y);
}
-bool RectangleShape2DSW::contains_point(const Vector2 &p_point) const {
+bool GodotRectangleShape2D::contains_point(const Vector2 &p_point) const {
real_t x = p_point.x;
real_t y = p_point.y;
real_t edge_x = half_extents.x;
@@ -346,23 +341,23 @@ bool RectangleShape2DSW::contains_point(const Vector2 &p_point) const {
return (x >= -edge_x) && (x < edge_x) && (y >= -edge_y) && (y < edge_y);
}
-bool RectangleShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {
+bool GodotRectangleShape2D::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {
return get_aabb().intersects_segment(p_begin, p_end, &r_point, &r_normal);
}
-real_t RectangleShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const {
+real_t GodotRectangleShape2D::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const {
Vector2 he2 = half_extents * 2 * p_scale;
return p_mass * he2.dot(he2) / 12.0;
}
-void RectangleShape2DSW::set_data(const Variant &p_data) {
+void GodotRectangleShape2D::set_data(const Variant &p_data) {
ERR_FAIL_COND(p_data.get_type() != Variant::VECTOR2);
half_extents = p_data;
configure(Rect2(-half_extents, half_extents * 2.0));
}
-Variant RectangleShape2DSW::get_data() const {
+Variant GodotRectangleShape2D::get_data() const {
return half_extents;
}
@@ -370,7 +365,7 @@ Variant RectangleShape2DSW::get_data() const {
/*********************************************************/
/*********************************************************/
-void CapsuleShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {
+void GodotCapsuleShape2D::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {
Vector2 n = p_normal;
real_t d = n.y;
@@ -383,24 +378,24 @@ void CapsuleShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports
r_amount = 2;
r_supports[0] = n;
- r_supports[0].y += height * 0.5;
+ r_supports[0].y += height * 0.5 - radius;
r_supports[1] = n;
- r_supports[1].y -= height * 0.5;
+ r_supports[1].y -= height * 0.5 - radius;
} else {
- real_t h = (d > 0) ? height : -height;
+ real_t h = height * 0.5 - radius;
n *= radius;
- n.y += h * 0.5;
+ n.y += (d > 0) ? h : -h;
r_amount = 1;
*r_supports = n;
}
}
-bool CapsuleShape2DSW::contains_point(const Vector2 &p_point) const {
+bool GodotCapsuleShape2D::contains_point(const Vector2 &p_point) const {
Vector2 p = p_point;
p.y = Math::abs(p.y);
- p.y -= height * 0.5;
+ p.y -= height * 0.5 - radius;
if (p.y < 0) {
p.y = 0;
}
@@ -408,7 +403,7 @@ bool CapsuleShape2DSW::contains_point(const Vector2 &p_point) const {
return p.length_squared() < radius * radius;
}
-bool CapsuleShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {
+bool GodotCapsuleShape2D::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {
real_t d = 1e10;
Vector2 n = (p_end - p_begin).normalized();
bool collided = false;
@@ -417,7 +412,7 @@ bool CapsuleShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &
for (int i = 0; i < 2; i++) {
Vector2 begin = p_begin;
Vector2 end = p_end;
- real_t ofs = (i == 0) ? -height * 0.5 : height * 0.5;
+ real_t ofs = (i == 0) ? -height * 0.5 + radius : height * 0.5 - radius;
begin.y += ofs;
end.y += ofs;
@@ -454,7 +449,7 @@ bool CapsuleShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &
}
Vector2 rpos, rnorm;
- if (Rect2(Point2(-radius, -height * 0.5), Size2(radius * 2.0, height)).intersects_segment(p_begin, p_end, &rpos, &rnorm)) {
+ if (Rect2(Point2(-radius, -height * 0.5 + radius), Size2(radius * 2.0, height - radius * 2)).intersects_segment(p_begin, p_end, &rpos, &rnorm)) {
real_t pd = n.dot(rpos);
if (pd < d) {
r_point = rpos;
@@ -468,12 +463,12 @@ bool CapsuleShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &
return collided; //todo
}
-real_t CapsuleShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const {
- Vector2 he2 = Vector2(radius * 2, height + radius * 2) * p_scale;
+real_t GodotCapsuleShape2D::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const {
+ Vector2 he2 = Vector2(radius * 2, height) * p_scale;
return p_mass * he2.dot(he2) / 12.0;
}
-void CapsuleShape2DSW::set_data(const Variant &p_data) {
+void GodotCapsuleShape2D::set_data(const Variant &p_data) {
ERR_FAIL_COND(p_data.get_type() != Variant::ARRAY && p_data.get_type() != Variant::VECTOR2);
if (p_data.get_type() == Variant::ARRAY) {
@@ -487,11 +482,11 @@ void CapsuleShape2DSW::set_data(const Variant &p_data) {
height = p.y;
}
- Point2 he(radius, height * 0.5 + radius);
+ Point2 he(radius, height * 0.5);
configure(Rect2(-he, he * 2));
}
-Variant CapsuleShape2DSW::get_data() const {
+Variant GodotCapsuleShape2D::get_data() const {
return Point2(height, radius);
}
@@ -499,9 +494,10 @@ Variant CapsuleShape2DSW::get_data() const {
/*********************************************************/
/*********************************************************/
-void ConvexPolygonShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {
+void GodotConvexPolygonShape2D::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {
int support_idx = -1;
real_t d = -1e10;
+ r_amount = 0;
for (int i = 0; i < point_count; i++) {
//test point
@@ -520,13 +516,13 @@ void ConvexPolygonShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_su
}
}
- ERR_FAIL_COND(support_idx == -1);
+ ERR_FAIL_COND_MSG(support_idx == -1, "Convex polygon shape support not found.");
r_amount = 1;
r_supports[0] = points[support_idx].pos;
}
-bool ConvexPolygonShape2DSW::contains_point(const Vector2 &p_point) const {
+bool GodotConvexPolygonShape2D::contains_point(const Vector2 &p_point) const {
bool out = false;
bool in = false;
@@ -542,18 +538,12 @@ bool ConvexPolygonShape2DSW::contains_point(const Vector2 &p_point) const {
return in != out;
}
-bool ConvexPolygonShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {
+bool GodotConvexPolygonShape2D::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {
Vector2 n = (p_end - p_begin).normalized();
real_t d = 1e10;
bool inters = false;
for (int i = 0; i < point_count; i++) {
- //hmm.. no can do..
- /*
- if (d.dot(points[i].normal)>=0)
- continue;
- */
-
Vector2 res;
if (!Geometry2D::segment_intersects_segment(p_begin, p_end, points[i].pos, points[(i + 1) % point_count].pos, &res)) {
@@ -569,17 +559,11 @@ bool ConvexPolygonShape2DSW::intersect_segment(const Vector2 &p_begin, const Vec
}
}
- if (inters) {
- if (n.dot(r_normal) > 0) {
- r_normal = -r_normal;
- }
- }
-
- //return get_aabb().intersects_segment(p_begin,p_end,&r_point,&r_normal);
- return inters; //todo
+ return inters;
}
-real_t ConvexPolygonShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const {
+real_t GodotConvexPolygonShape2D::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const {
+ ERR_FAIL_COND_V_MSG(point_count == 0, 0, "Convex polygon shape has no points.");
Rect2 aabb;
aabb.position = points[0].pos * p_scale;
for (int i = 0; i < point_count; i++) {
@@ -589,7 +573,7 @@ real_t ConvexPolygonShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2
return p_mass * aabb.size.dot(aabb.size) / 12.0;
}
-void ConvexPolygonShape2DSW::set_data(const Variant &p_data) {
+void GodotConvexPolygonShape2D::set_data(const Variant &p_data) {
#ifdef REAL_T_IS_DOUBLE
ERR_FAIL_COND(p_data.get_type() != Variant::PACKED_VECTOR2_ARRAY && p_data.get_type() != Variant::PACKED_FLOAT64_ARRAY);
#else
@@ -645,7 +629,7 @@ void ConvexPolygonShape2DSW::set_data(const Variant &p_data) {
configure(aabb);
}
-Variant ConvexPolygonShape2DSW::get_data() const {
+Variant GodotConvexPolygonShape2D::get_data() const {
Vector<Vector2> dvr;
dvr.resize(point_count);
@@ -657,12 +641,7 @@ Variant ConvexPolygonShape2DSW::get_data() const {
return dvr;
}
-ConvexPolygonShape2DSW::ConvexPolygonShape2DSW() {
- points = nullptr;
- point_count = 0;
-}
-
-ConvexPolygonShape2DSW::~ConvexPolygonShape2DSW() {
+GodotConvexPolygonShape2D::~GodotConvexPolygonShape2D() {
if (points) {
memdelete_arr(points);
}
@@ -670,7 +649,7 @@ ConvexPolygonShape2DSW::~ConvexPolygonShape2DSW() {
//////////////////////////////////////////////////
-void ConcavePolygonShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {
+void GodotConcavePolygonShape2D::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {
real_t d = -1e10;
int idx = -1;
for (int i = 0; i < points.size(); i++) {
@@ -686,11 +665,15 @@ void ConcavePolygonShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_s
*r_supports = points[idx];
}
-bool ConcavePolygonShape2DSW::contains_point(const Vector2 &p_point) const {
+bool GodotConcavePolygonShape2D::contains_point(const Vector2 &p_point) const {
return false; //sorry
}
-bool ConcavePolygonShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {
+bool GodotConcavePolygonShape2D::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {
+ if (segments.size() == 0 || points.size() == 0) {
+ return false;
+ }
+
uint32_t *stack = (uint32_t *)alloca(sizeof(int) * bvh_depth);
enum {
@@ -794,7 +777,7 @@ bool ConcavePolygonShape2DSW::intersect_segment(const Vector2 &p_begin, const Ve
return inters;
}
-int ConcavePolygonShape2DSW::_generate_bvh(BVH *p_bvh, int p_len, int p_depth) {
+int GodotConcavePolygonShape2D::_generate_bvh(BVH *p_bvh, int p_len, int p_depth) {
if (p_len == 1) {
bvh_depth = MAX(p_depth, bvh_depth);
bvh.push_back(*p_bvh);
@@ -832,7 +815,7 @@ int ConcavePolygonShape2DSW::_generate_bvh(BVH *p_bvh, int p_len, int p_depth) {
return node_idx;
}
-void ConcavePolygonShape2DSW::set_data(const Variant &p_data) {
+void GodotConcavePolygonShape2D::set_data(const Variant &p_data) {
#ifdef REAL_T_IS_DOUBLE
ERR_FAIL_COND(p_data.get_type() != Variant::PACKED_VECTOR2_ARRAY && p_data.get_type() != Variant::PACKED_FLOAT64_ARRAY);
#else
@@ -858,7 +841,7 @@ void ConcavePolygonShape2DSW::set_data(const Variant &p_data) {
const Vector2 *arr = p2arr.ptr();
- Map<Point2, int> pointmap;
+ HashMap<Point2, int> pointmap;
for (int i = 0; i < len; i += 2) {
Point2 p1 = arr[i];
Point2 p2 = arr[i + 1];
@@ -885,10 +868,10 @@ void ConcavePolygonShape2DSW::set_data(const Variant &p_data) {
}
points.resize(pointmap.size());
- aabb.position = pointmap.front()->key();
- for (Map<Point2, int>::Element *E = pointmap.front(); E; E = E->next()) {
- aabb.expand_to(E->key());
- points.write[E->get()] = E->key();
+ aabb.position = pointmap.begin()->key;
+ for (const KeyValue<Point2, int> &E : pointmap) {
+ aabb.expand_to(E.key);
+ points.write[E.value] = E.key;
}
Vector<BVH> main_vbh;
@@ -909,7 +892,7 @@ void ConcavePolygonShape2DSW::set_data(const Variant &p_data) {
configure(aabb);
}
-Variant ConcavePolygonShape2DSW::get_data() const {
+Variant GodotConcavePolygonShape2D::get_data() const {
Vector<Vector2> rsegments;
int len = segments.size();
rsegments.resize(len * 2);
@@ -922,7 +905,7 @@ Variant ConcavePolygonShape2DSW::get_data() const {
return rsegments;
}
-void ConcavePolygonShape2DSW::cull(const Rect2 &p_local_aabb, Callback p_callback, void *p_userdata) const {
+void GodotConcavePolygonShape2D::cull(const Rect2 &p_local_aabb, QueryCallback p_callback, void *p_userdata) const {
uint32_t *stack = (uint32_t *)alloca(sizeof(int) * bvh_depth);
enum {
@@ -968,9 +951,11 @@ void ConcavePolygonShape2DSW::cull(const Rect2 &p_local_aabb, Callback p_callbac
Vector2 a = pointptr[s.points[0]];
Vector2 b = pointptr[s.points[1]];
- SegmentShape2DSW ss(a, b, (b - a).orthogonal().normalized());
+ GodotSegmentShape2D ss(a, b, (b - a).orthogonal().normalized());
- p_callback(p_userdata, &ss);
+ if (p_callback(p_userdata, &ss)) {
+ return;
+ }
stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
} else {
diff --git a/servers/physics_2d/shape_2d_sw.h b/servers/physics_2d/godot_shape_2d.h
index ee2730ebb5..cede01e18d 100644
--- a/servers/physics_2d/shape_2d_sw.h
+++ b/servers/physics_2d/godot_shape_2d.h
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* shape_2d_sw.h */
+/* godot_shape_2d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -28,41 +28,29 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SHAPE_2D_2DSW_H
-#define SHAPE_2D_2DSW_H
+#ifndef GODOT_SHAPE_2D_H
+#define GODOT_SHAPE_2D_H
#include "servers/physics_server_2d.h"
#define _SEGMENT_IS_VALID_SUPPORT_THRESHOLD 0.99998
-/*
+class GodotShape2D;
-SHAPE_LINE, ///< plane:"plane"
-SHAPE_SEGMENT, ///< real_t:"length"
-SHAPE_CIRCLE, ///< real_t:"radius"
-SHAPE_RECTANGLE, ///< vec3:"extents"
-SHAPE_CONVEX_POLYGON, ///< array of planes:"planes"
-SHAPE_CONCAVE_POLYGON, ///< Vector2 array:"triangles" , or Dictionary with "indices" (int array) and "triangles" (Vector2 array)
-SHAPE_CUSTOM, ///< Server-Implementation based custom shape, calling shape_create() with this value will result in an error
-
-*/
-
-class Shape2DSW;
-
-class ShapeOwner2DSW {
+class GodotShapeOwner2D {
public:
virtual void _shape_changed() = 0;
- virtual void remove_shape(Shape2DSW *p_shape) = 0;
+ virtual void remove_shape(GodotShape2D *p_shape) = 0;
- virtual ~ShapeOwner2DSW() {}
+ virtual ~GodotShapeOwner2D() {}
};
-class Shape2DSW {
+class GodotShape2D {
RID self;
Rect2 aabb;
- bool configured;
- real_t custom_bias;
+ bool configured = false;
+ real_t custom_bias = 0.0;
- Map<ShapeOwner2DSW *, int> owners;
+ HashMap<GodotShapeOwner2D *, int> owners;
protected:
void configure(const Rect2 &p_aabb);
@@ -76,6 +64,8 @@ public:
_FORCE_INLINE_ Rect2 get_aabb() const { return aabb; }
_FORCE_INLINE_ bool is_configured() const { return configured; }
+ virtual bool allows_one_way_collision() const { return true; }
+
virtual bool is_concave() const { return false; }
virtual bool contains_point(const Vector2 &p_point) const = 0;
@@ -93,10 +83,10 @@ public:
_FORCE_INLINE_ void set_custom_bias(real_t p_bias) { custom_bias = p_bias; }
_FORCE_INLINE_ real_t get_custom_bias() const { return custom_bias; }
- void add_owner(ShapeOwner2DSW *p_owner);
- void remove_owner(ShapeOwner2DSW *p_owner);
- bool is_owner(ShapeOwner2DSW *p_owner) const;
- const Map<ShapeOwner2DSW *, int> &get_owners() const;
+ void add_owner(GodotShapeOwner2D *p_owner);
+ void remove_owner(GodotShapeOwner2D *p_owner);
+ bool is_owner(GodotShapeOwner2D *p_owner) const;
+ const HashMap<GodotShapeOwner2D *, int> &get_owners() const;
_FORCE_INLINE_ void get_supports_transformed_cast(const Vector2 &p_cast, const Vector2 &p_normal, const Transform2D &p_xform, Vector2 *r_supports, int &r_amount) const {
get_supports(p_xform.basis_xform_inv(p_normal).normalized(), r_supports, r_amount);
@@ -131,46 +121,45 @@ public:
}
}
}
-
- Shape2DSW();
- virtual ~Shape2DSW();
+ GodotShape2D() {}
+ virtual ~GodotShape2D();
};
//let the optimizer do the magic
-#define DEFAULT_PROJECT_RANGE_CAST \
- virtual void project_range_castv(const Vector2 &p_cast, const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { \
- project_range_cast(p_cast, p_normal, p_transform, r_min, r_max); \
- } \
- _FORCE_INLINE_ void project_range_cast(const Vector2 &p_cast, const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { \
- real_t mina, maxa; \
- real_t minb, maxb; \
- Transform2D ofsb = p_transform; \
- ofsb.elements[2] += p_cast; \
- project_range(p_normal, p_transform, mina, maxa); \
- project_range(p_normal, ofsb, minb, maxb); \
- r_min = MIN(mina, minb); \
- r_max = MAX(maxa, maxb); \
+#define DEFAULT_PROJECT_RANGE_CAST \
+ virtual void project_range_castv(const Vector2 &p_cast, const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const override { \
+ project_range_cast(p_cast, p_normal, p_transform, r_min, r_max); \
+ } \
+ _FORCE_INLINE_ void project_range_cast(const Vector2 &p_cast, const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { \
+ real_t mina, maxa; \
+ real_t minb, maxb; \
+ Transform2D ofsb = p_transform; \
+ ofsb.columns[2] += p_cast; \
+ project_range(p_normal, p_transform, mina, maxa); \
+ project_range(p_normal, ofsb, minb, maxb); \
+ r_min = MIN(mina, minb); \
+ r_max = MAX(maxa, maxb); \
}
-class LineShape2DSW : public Shape2DSW {
+class GodotWorldBoundaryShape2D : public GodotShape2D {
Vector2 normal;
- real_t d;
+ real_t d = 0.0;
public:
_FORCE_INLINE_ Vector2 get_normal() const { return normal; }
_FORCE_INLINE_ real_t get_d() const { return d; }
- virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_LINE; }
+ virtual PhysicsServer2D::ShapeType get_type() const override { return PhysicsServer2D::SHAPE_WORLD_BOUNDARY; }
- virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal, p_transform, r_min, r_max); }
- virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const;
+ virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const override { project_range(p_normal, p_transform, r_min, r_max); }
+ virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const override;
- virtual bool contains_point(const Vector2 &p_point) const;
- virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const;
- virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const;
+ virtual bool contains_point(const Vector2 &p_point) const override;
+ virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const override;
+ virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const override;
- virtual void set_data(const Variant &p_data);
- virtual Variant get_data() const;
+ virtual void set_data(const Variant &p_data) override;
+ virtual Variant get_data() const override;
_FORCE_INLINE_ void project_range(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const {
//real large
@@ -178,7 +167,7 @@ public:
r_max = 1e10;
}
- virtual void project_range_castv(const Vector2 &p_cast, const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const {
+ virtual void project_range_castv(const Vector2 &p_cast, const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const override {
project_range_cast(p_cast, p_normal, p_transform, r_min, r_max);
}
@@ -189,25 +178,27 @@ public:
}
};
-class RayShape2DSW : public Shape2DSW {
- real_t length;
- bool slips_on_slope;
+class GodotSeparationRayShape2D : public GodotShape2D {
+ real_t length = 0.0;
+ bool slide_on_slope = false;
public:
_FORCE_INLINE_ real_t get_length() const { return length; }
- _FORCE_INLINE_ bool get_slips_on_slope() const { return slips_on_slope; }
+ _FORCE_INLINE_ bool get_slide_on_slope() const { return slide_on_slope; }
- virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_RAY; }
+ virtual PhysicsServer2D::ShapeType get_type() const override { return PhysicsServer2D::SHAPE_SEPARATION_RAY; }
- virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal, p_transform, r_min, r_max); }
- virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const;
+ virtual bool allows_one_way_collision() const override { return false; }
- virtual bool contains_point(const Vector2 &p_point) const;
- virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const;
- virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const;
+ virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const override { project_range(p_normal, p_transform, r_min, r_max); }
+ virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const override;
- virtual void set_data(const Variant &p_data);
- virtual Variant get_data() const;
+ virtual bool contains_point(const Vector2 &p_point) const override;
+ virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const override;
+ virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const override;
+
+ virtual void set_data(const Variant &p_data) override;
+ virtual Variant get_data() const override;
_FORCE_INLINE_ void project_range(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const {
//real large
@@ -220,11 +211,11 @@ public:
DEFAULT_PROJECT_RANGE_CAST
- _FORCE_INLINE_ RayShape2DSW() {}
- _FORCE_INLINE_ RayShape2DSW(real_t p_length) { length = p_length; }
+ _FORCE_INLINE_ GodotSeparationRayShape2D() {}
+ _FORCE_INLINE_ GodotSeparationRayShape2D(real_t p_length) { length = p_length; }
};
-class SegmentShape2DSW : public Shape2DSW {
+class GodotSegmentShape2D : public GodotShape2D {
Vector2 a;
Vector2 b;
Vector2 n;
@@ -234,20 +225,20 @@ public:
_FORCE_INLINE_ const Vector2 &get_b() const { return b; }
_FORCE_INLINE_ const Vector2 &get_normal() const { return n; }
- virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_SEGMENT; }
+ virtual PhysicsServer2D::ShapeType get_type() const override { return PhysicsServer2D::SHAPE_SEGMENT; }
_FORCE_INLINE_ Vector2 get_xformed_normal(const Transform2D &p_xform) const {
return (p_xform.xform(b) - p_xform.xform(a)).normalized().orthogonal();
}
- virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal, p_transform, r_min, r_max); }
- virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const;
+ virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const override { project_range(p_normal, p_transform, r_min, r_max); }
+ virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const override;
- virtual bool contains_point(const Vector2 &p_point) const;
- virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const;
- virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const;
+ virtual bool contains_point(const Vector2 &p_point) const override;
+ virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const override;
+ virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const override;
- virtual void set_data(const Variant &p_data);
- virtual Variant get_data() const;
+ virtual void set_data(const Variant &p_data) override;
+ virtual Variant get_data() const override;
_FORCE_INLINE_ void project_range(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const {
//real large
@@ -260,31 +251,31 @@ public:
DEFAULT_PROJECT_RANGE_CAST
- _FORCE_INLINE_ SegmentShape2DSW() {}
- _FORCE_INLINE_ SegmentShape2DSW(const Vector2 &p_a, const Vector2 &p_b, const Vector2 &p_n) {
+ _FORCE_INLINE_ GodotSegmentShape2D() {}
+ _FORCE_INLINE_ GodotSegmentShape2D(const Vector2 &p_a, const Vector2 &p_b, const Vector2 &p_n) {
a = p_a;
b = p_b;
n = p_n;
}
};
-class CircleShape2DSW : public Shape2DSW {
+class GodotCircleShape2D : public GodotShape2D {
real_t radius;
public:
_FORCE_INLINE_ const real_t &get_radius() const { return radius; }
- virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_CIRCLE; }
+ virtual PhysicsServer2D::ShapeType get_type() const override { return PhysicsServer2D::SHAPE_CIRCLE; }
- virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal, p_transform, r_min, r_max); }
- virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const;
+ virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const override { project_range(p_normal, p_transform, r_min, r_max); }
+ virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const override;
- virtual bool contains_point(const Vector2 &p_point) const;
- virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const;
- virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const;
+ virtual bool contains_point(const Vector2 &p_point) const override;
+ virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const override;
+ virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const override;
- virtual void set_data(const Variant &p_data);
- virtual Variant get_data() const;
+ virtual void set_data(const Variant &p_data) override;
+ virtual Variant get_data() const override;
_FORCE_INLINE_ void project_range(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const {
//real large
@@ -301,23 +292,23 @@ public:
DEFAULT_PROJECT_RANGE_CAST
};
-class RectangleShape2DSW : public Shape2DSW {
+class GodotRectangleShape2D : public GodotShape2D {
Vector2 half_extents;
public:
_FORCE_INLINE_ const Vector2 &get_half_extents() const { return half_extents; }
- virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_RECTANGLE; }
+ virtual PhysicsServer2D::ShapeType get_type() const override { return PhysicsServer2D::SHAPE_RECTANGLE; }
- virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal, p_transform, r_min, r_max); }
- virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const;
+ virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const override { project_range(p_normal, p_transform, r_min, r_max); }
+ virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const override;
- virtual bool contains_point(const Vector2 &p_point) const;
- virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const;
- virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const;
+ virtual bool contains_point(const Vector2 &p_point) const override;
+ virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const override;
+ virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const override;
- virtual void set_data(const Variant &p_data);
- virtual Variant get_data() const;
+ virtual void set_data(const Variant &p_data) override;
+ virtual Variant get_data() const override;
_FORCE_INLINE_ void project_range(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const {
// no matter the angle, the box is mirrored anyway
@@ -345,7 +336,7 @@ public:
return (p_xform.xform(he) - p_circle).normalized();
}
- _FORCE_INLINE_ Vector2 get_box_axis(const Transform2D &p_xform, const Transform2D &p_xform_inv, const RectangleShape2DSW *p_B, const Transform2D &p_B_xform, const Transform2D &p_B_xform_inv) const {
+ _FORCE_INLINE_ Vector2 get_box_axis(const Transform2D &p_xform, const Transform2D &p_xform_inv, const GodotRectangleShape2D *p_B, const Transform2D &p_B_xform, const Transform2D &p_B_xform_inv) const {
Vector2 a, b;
{
@@ -373,33 +364,33 @@ public:
DEFAULT_PROJECT_RANGE_CAST
};
-class CapsuleShape2DSW : public Shape2DSW {
- real_t radius;
- real_t height;
+class GodotCapsuleShape2D : public GodotShape2D {
+ real_t radius = 0.0;
+ real_t height = 0.0;
public:
_FORCE_INLINE_ const real_t &get_radius() const { return radius; }
_FORCE_INLINE_ const real_t &get_height() const { return height; }
- virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_CAPSULE; }
+ virtual PhysicsServer2D::ShapeType get_type() const override { return PhysicsServer2D::SHAPE_CAPSULE; }
- virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal, p_transform, r_min, r_max); }
- virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const;
+ virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const override { project_range(p_normal, p_transform, r_min, r_max); }
+ virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const override;
- virtual bool contains_point(const Vector2 &p_point) const;
- virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const;
- virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const;
+ virtual bool contains_point(const Vector2 &p_point) const override;
+ virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const override;
+ virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const override;
- virtual void set_data(const Variant &p_data);
- virtual Variant get_data() const;
+ virtual void set_data(const Variant &p_data) override;
+ virtual Variant get_data() const override;
_FORCE_INLINE_ void project_range(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const {
// no matter the angle, the box is mirrored anyway
Vector2 n = p_transform.basis_xform_inv(p_normal).normalized();
- real_t h = (n.y > 0) ? height : -height;
+ real_t h = height * 0.5 - radius;
n *= radius;
- n.y += h * 0.5;
+ n.y += (n.y > 0) ? h : -h;
r_max = p_normal.dot(p_transform.xform(n));
r_min = p_normal.dot(p_transform.xform(-n));
@@ -414,14 +405,14 @@ public:
DEFAULT_PROJECT_RANGE_CAST
};
-class ConvexPolygonShape2DSW : public Shape2DSW {
+class GodotConvexPolygonShape2D : public GodotShape2D {
struct Point {
Vector2 pos;
Vector2 normal; //normal to next segment
};
- Point *points;
- int point_count;
+ Point *points = nullptr;
+ int point_count = 0;
public:
_FORCE_INLINE_ int get_point_count() const { return point_count; }
@@ -434,17 +425,17 @@ public:
return (p_xform.xform(b) - p_xform.xform(a)).normalized().orthogonal();
}
- virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_CONVEX_POLYGON; }
+ virtual PhysicsServer2D::ShapeType get_type() const override { return PhysicsServer2D::SHAPE_CONVEX_POLYGON; }
- virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal, p_transform, r_min, r_max); }
- virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const;
+ virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const override { project_range(p_normal, p_transform, r_min, r_max); }
+ virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const override;
- virtual bool contains_point(const Vector2 &p_point) const;
- virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const;
- virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const;
+ virtual bool contains_point(const Vector2 &p_point) const override;
+ virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const override;
+ virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const override;
- virtual void set_data(const Variant &p_data);
- virtual Variant get_data() const;
+ virtual void set_data(const Variant &p_data) override;
+ virtual Variant get_data() const override;
_FORCE_INLINE_ void project_range(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const {
if (!points || point_count <= 0) {
@@ -466,21 +457,23 @@ public:
DEFAULT_PROJECT_RANGE_CAST
- ConvexPolygonShape2DSW();
- ~ConvexPolygonShape2DSW();
+ GodotConvexPolygonShape2D() {}
+ ~GodotConvexPolygonShape2D();
};
-class ConcaveShape2DSW : public Shape2DSW {
+class GodotConcaveShape2D : public GodotShape2D {
public:
- virtual bool is_concave() const { return true; }
- typedef void (*Callback)(void *p_userdata, Shape2DSW *p_convex);
+ virtual bool is_concave() const override { return true; }
+
+ // Returns true to stop the query.
+ typedef bool (*QueryCallback)(void *p_userdata, GodotShape2D *p_convex);
- virtual void cull(const Rect2 &p_local_aabb, Callback p_callback, void *p_userdata) const = 0;
+ virtual void cull(const Rect2 &p_local_aabb, QueryCallback p_callback, void *p_userdata) const = 0;
};
-class ConcavePolygonShape2DSW : public ConcaveShape2DSW {
+class GodotConcavePolygonShape2D : public GodotConcaveShape2D {
struct Segment {
- int points[2];
+ int points[2] = {};
};
Vector<Segment> segments;
@@ -488,11 +481,11 @@ class ConcavePolygonShape2DSW : public ConcaveShape2DSW {
struct BVH {
Rect2 aabb;
- int left, right;
+ int left = 0, right = 0;
};
Vector<BVH> bvh;
- int bvh_depth;
+ int bvh_depth = 0;
struct BVH_CompareX {
_FORCE_INLINE_ bool operator()(const BVH &a, const BVH &b) const {
@@ -509,27 +502,35 @@ class ConcavePolygonShape2DSW : public ConcaveShape2DSW {
int _generate_bvh(BVH *p_bvh, int p_len, int p_depth);
public:
- virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_CONCAVE_POLYGON; }
+ virtual PhysicsServer2D::ShapeType get_type() const override { return PhysicsServer2D::SHAPE_CONCAVE_POLYGON; }
- virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { /*project_range(p_normal,p_transform,r_min,r_max);*/
+ virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const override {
+ r_min = 0;
+ r_max = 0;
+ ERR_FAIL_MSG("Unsupported call to project_rangev in GodotConcavePolygonShape2D");
}
- virtual void project_range(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { /*project_range(p_normal,p_transform,r_min,r_max);*/
+
+ void project_range(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const {
+ r_min = 0;
+ r_max = 0;
+ ERR_FAIL_MSG("Unsupported call to project_range in GodotConcavePolygonShape2D");
}
- virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const;
- virtual bool contains_point(const Vector2 &p_point) const;
- virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const;
+ virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const override;
+
+ virtual bool contains_point(const Vector2 &p_point) const override;
+ virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const override;
- virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const { return 0; }
+ virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const override { return 0; }
- virtual void set_data(const Variant &p_data);
- virtual Variant get_data() const;
+ virtual void set_data(const Variant &p_data) override;
+ virtual Variant get_data() const override;
- virtual void cull(const Rect2 &p_local_aabb, Callback p_callback, void *p_userdata) const;
+ virtual void cull(const Rect2 &p_local_aabb, QueryCallback p_callback, void *p_userdata) const override;
DEFAULT_PROJECT_RANGE_CAST
};
#undef DEFAULT_PROJECT_RANGE_CAST
-#endif // SHAPE_2D_2DSW_H
+#endif // GODOT_SHAPE_2D_H
diff --git a/servers/physics_2d/godot_space_2d.cpp b/servers/physics_2d/godot_space_2d.cpp
new file mode 100644
index 0000000000..166ec3049e
--- /dev/null
+++ b/servers/physics_2d/godot_space_2d.cpp
@@ -0,0 +1,1242 @@
+/*************************************************************************/
+/* godot_space_2d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 "godot_space_2d.h"
+
+#include "godot_collision_solver_2d.h"
+#include "godot_physics_server_2d.h"
+
+#include "core/os/os.h"
+#include "core/templates/pair.h"
+
+#define TEST_MOTION_MARGIN_MIN_VALUE 0.0001
+#define TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR 0.05
+
+_FORCE_INLINE_ static bool _can_collide_with(GodotCollisionObject2D *p_object, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
+ if (!(p_object->get_collision_layer() & p_collision_mask)) {
+ return false;
+ }
+
+ if (p_object->get_type() == GodotCollisionObject2D::TYPE_AREA && !p_collide_with_areas) {
+ return false;
+ }
+
+ if (p_object->get_type() == GodotCollisionObject2D::TYPE_BODY && !p_collide_with_bodies) {
+ return false;
+ }
+
+ return true;
+}
+
+int GodotPhysicsDirectSpaceState2D::intersect_point(const PointParameters &p_parameters, ShapeResult *r_results, int p_result_max) {
+ if (p_result_max <= 0) {
+ return 0;
+ }
+
+ Rect2 aabb;
+ aabb.position = p_parameters.position - Vector2(0.00001, 0.00001);
+ aabb.size = Vector2(0.00002, 0.00002);
+
+ int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, GodotSpace2D::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
+
+ int cc = 0;
+
+ for (int i = 0; i < amount; i++) {
+ if (!_can_collide_with(space->intersection_query_results[i], p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas)) {
+ continue;
+ }
+
+ if (p_parameters.exclude.has(space->intersection_query_results[i]->get_self())) {
+ continue;
+ }
+
+ const GodotCollisionObject2D *col_obj = space->intersection_query_results[i];
+
+ if (p_parameters.pick_point && !col_obj->is_pickable()) {
+ continue;
+ }
+
+ if (p_parameters.canvas_instance_id.is_valid() && col_obj->get_canvas_instance_id() != p_parameters.canvas_instance_id) {
+ continue;
+ }
+
+ int shape_idx = space->intersection_query_subindex_results[i];
+
+ GodotShape2D *shape = col_obj->get_shape(shape_idx);
+
+ Vector2 local_point = (col_obj->get_transform() * col_obj->get_shape_transform(shape_idx)).affine_inverse().xform(p_parameters.position);
+
+ if (!shape->contains_point(local_point)) {
+ continue;
+ }
+
+ if (cc >= p_result_max) {
+ continue;
+ }
+
+ r_results[cc].collider_id = col_obj->get_instance_id();
+ if (r_results[cc].collider_id.is_valid()) {
+ r_results[cc].collider = ObjectDB::get_instance(r_results[cc].collider_id);
+ }
+ r_results[cc].rid = col_obj->get_self();
+ r_results[cc].shape = shape_idx;
+
+ cc++;
+ }
+
+ return cc;
+}
+
+bool GodotPhysicsDirectSpaceState2D::intersect_ray(const RayParameters &p_parameters, RayResult &r_result) {
+ ERR_FAIL_COND_V(space->locked, false);
+
+ Vector2 begin, end;
+ Vector2 normal;
+ begin = p_parameters.from;
+ end = p_parameters.to;
+ normal = (end - begin).normalized();
+
+ int amount = space->broadphase->cull_segment(begin, end, space->intersection_query_results, GodotSpace2D::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
+
+ //todo, create another array that references results, compute AABBs and check closest point to ray origin, sort, and stop evaluating results when beyond first collision
+
+ bool collided = false;
+ Vector2 res_point, res_normal;
+ int res_shape;
+ const GodotCollisionObject2D *res_obj;
+ real_t min_d = 1e10;
+
+ for (int i = 0; i < amount; i++) {
+ if (!_can_collide_with(space->intersection_query_results[i], p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas)) {
+ continue;
+ }
+
+ if (p_parameters.exclude.has(space->intersection_query_results[i]->get_self())) {
+ continue;
+ }
+
+ const GodotCollisionObject2D *col_obj = space->intersection_query_results[i];
+
+ int shape_idx = space->intersection_query_subindex_results[i];
+ Transform2D inv_xform = col_obj->get_shape_inv_transform(shape_idx) * col_obj->get_inv_transform();
+
+ Vector2 local_from = inv_xform.xform(begin);
+ Vector2 local_to = inv_xform.xform(end);
+
+ const GodotShape2D *shape = col_obj->get_shape(shape_idx);
+
+ Vector2 shape_point, shape_normal;
+
+ if (shape->contains_point(local_from)) {
+ if (p_parameters.hit_from_inside) {
+ // Hit shape at starting point.
+ min_d = 0;
+ res_point = begin;
+ res_normal = Vector2();
+ res_shape = shape_idx;
+ res_obj = col_obj;
+ collided = true;
+ break;
+ } else {
+ // Ignore shape when starting inside.
+ continue;
+ }
+ }
+
+ if (shape->intersect_segment(local_from, local_to, shape_point, shape_normal)) {
+ Transform2D xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
+ shape_point = xform.xform(shape_point);
+
+ real_t ld = normal.dot(shape_point);
+
+ if (ld < min_d) {
+ min_d = ld;
+ res_point = shape_point;
+ res_normal = inv_xform.basis_xform_inv(shape_normal).normalized();
+ res_shape = shape_idx;
+ res_obj = col_obj;
+ collided = true;
+ }
+ }
+ }
+
+ if (!collided) {
+ return false;
+ }
+
+ r_result.collider_id = res_obj->get_instance_id();
+ if (r_result.collider_id.is_valid()) {
+ r_result.collider = ObjectDB::get_instance(r_result.collider_id);
+ }
+ r_result.normal = res_normal;
+ r_result.position = res_point;
+ r_result.rid = res_obj->get_self();
+ r_result.shape = res_shape;
+
+ return true;
+}
+
+int GodotPhysicsDirectSpaceState2D::intersect_shape(const ShapeParameters &p_parameters, ShapeResult *r_results, int p_result_max) {
+ if (p_result_max <= 0) {
+ return 0;
+ }
+
+ GodotShape2D *shape = GodotPhysicsServer2D::godot_singleton->shape_owner.get_or_null(p_parameters.shape_rid);
+ ERR_FAIL_COND_V(!shape, 0);
+
+ Rect2 aabb = p_parameters.transform.xform(shape->get_aabb());
+ aabb = aabb.merge(Rect2(aabb.position + p_parameters.motion, aabb.size)); //motion
+ aabb = aabb.grow(p_parameters.margin);
+
+ int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, GodotSpace2D::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
+
+ int cc = 0;
+
+ for (int i = 0; i < amount; i++) {
+ if (cc >= p_result_max) {
+ break;
+ }
+
+ if (!_can_collide_with(space->intersection_query_results[i], p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas)) {
+ continue;
+ }
+
+ if (p_parameters.exclude.has(space->intersection_query_results[i]->get_self())) {
+ continue;
+ }
+
+ const GodotCollisionObject2D *col_obj = space->intersection_query_results[i];
+ int shape_idx = space->intersection_query_subindex_results[i];
+
+ if (!GodotCollisionSolver2D::solve(shape, p_parameters.transform, p_parameters.motion, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), nullptr, nullptr, nullptr, p_parameters.margin)) {
+ continue;
+ }
+
+ r_results[cc].collider_id = col_obj->get_instance_id();
+ if (r_results[cc].collider_id.is_valid()) {
+ r_results[cc].collider = ObjectDB::get_instance(r_results[cc].collider_id);
+ }
+ r_results[cc].rid = col_obj->get_self();
+ r_results[cc].shape = shape_idx;
+
+ cc++;
+ }
+
+ return cc;
+}
+
+bool GodotPhysicsDirectSpaceState2D::cast_motion(const ShapeParameters &p_parameters, real_t &p_closest_safe, real_t &p_closest_unsafe) {
+ GodotShape2D *shape = GodotPhysicsServer2D::godot_singleton->shape_owner.get_or_null(p_parameters.shape_rid);
+ ERR_FAIL_COND_V(!shape, false);
+
+ Rect2 aabb = p_parameters.transform.xform(shape->get_aabb());
+ aabb = aabb.merge(Rect2(aabb.position + p_parameters.motion, aabb.size)); //motion
+ aabb = aabb.grow(p_parameters.margin);
+
+ int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, GodotSpace2D::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
+
+ real_t best_safe = 1;
+ real_t best_unsafe = 1;
+
+ for (int i = 0; i < amount; i++) {
+ if (!_can_collide_with(space->intersection_query_results[i], p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas)) {
+ continue;
+ }
+
+ if (p_parameters.exclude.has(space->intersection_query_results[i]->get_self())) {
+ continue; //ignore excluded
+ }
+
+ const GodotCollisionObject2D *col_obj = space->intersection_query_results[i];
+ int shape_idx = space->intersection_query_subindex_results[i];
+
+ Transform2D col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
+ //test initial overlap, does it collide if going all the way?
+ if (!GodotCollisionSolver2D::solve(shape, p_parameters.transform, p_parameters.motion, col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), nullptr, nullptr, nullptr, p_parameters.margin)) {
+ continue;
+ }
+
+ //test initial overlap, ignore objects it's inside of.
+ if (GodotCollisionSolver2D::solve(shape, p_parameters.transform, Vector2(), col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), nullptr, nullptr, nullptr, p_parameters.margin)) {
+ continue;
+ }
+
+ Vector2 mnormal = p_parameters.motion.normalized();
+
+ //just do kinematic solving
+ real_t low = 0.0;
+ real_t hi = 1.0;
+ real_t fraction_coeff = 0.5;
+ for (int j = 0; j < 8; j++) { //steps should be customizable..
+ real_t fraction = low + (hi - low) * fraction_coeff;
+
+ Vector2 sep = mnormal; //important optimization for this to work fast enough
+ bool collided = GodotCollisionSolver2D::solve(shape, p_parameters.transform, p_parameters.motion * fraction, col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), nullptr, nullptr, &sep, p_parameters.margin);
+
+ if (collided) {
+ hi = fraction;
+ if ((j == 0) || (low > 0.0)) { // Did it not collide before?
+ // When alternating or first iteration, use dichotomy.
+ fraction_coeff = 0.5;
+ } else {
+ // When colliding again, converge faster towards low fraction
+ // for more accurate results with long motions that collide near the start.
+ fraction_coeff = 0.25;
+ }
+ } else {
+ low = fraction;
+ if ((j == 0) || (hi < 1.0)) { // Did it collide before?
+ // When alternating or first iteration, use dichotomy.
+ fraction_coeff = 0.5;
+ } else {
+ // When not colliding again, converge faster towards high fraction
+ // for more accurate results with long motions that collide near the end.
+ fraction_coeff = 0.75;
+ }
+ }
+ }
+
+ if (low < best_safe) {
+ best_safe = low;
+ best_unsafe = hi;
+ }
+ }
+
+ p_closest_safe = best_safe;
+ p_closest_unsafe = best_unsafe;
+
+ return true;
+}
+
+bool GodotPhysicsDirectSpaceState2D::collide_shape(const ShapeParameters &p_parameters, Vector2 *r_results, int p_result_max, int &r_result_count) {
+ if (p_result_max <= 0) {
+ return false;
+ }
+
+ GodotShape2D *shape = GodotPhysicsServer2D::godot_singleton->shape_owner.get_or_null(p_parameters.shape_rid);
+ ERR_FAIL_COND_V(!shape, 0);
+
+ Rect2 aabb = p_parameters.transform.xform(shape->get_aabb());
+ aabb = aabb.merge(Rect2(aabb.position + p_parameters.motion, aabb.size)); //motion
+ aabb = aabb.grow(p_parameters.margin);
+
+ int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, GodotSpace2D::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
+
+ bool collided = false;
+ r_result_count = 0;
+
+ GodotPhysicsServer2D::CollCbkData cbk;
+ cbk.max = p_result_max;
+ cbk.amount = 0;
+ cbk.passed = 0;
+ cbk.ptr = r_results;
+ GodotCollisionSolver2D::CallbackResult cbkres = GodotPhysicsServer2D::_shape_col_cbk;
+
+ GodotPhysicsServer2D::CollCbkData *cbkptr = &cbk;
+
+ for (int i = 0; i < amount; i++) {
+ if (!_can_collide_with(space->intersection_query_results[i], p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas)) {
+ continue;
+ }
+
+ const GodotCollisionObject2D *col_obj = space->intersection_query_results[i];
+
+ if (p_parameters.exclude.has(col_obj->get_self())) {
+ continue;
+ }
+
+ int shape_idx = space->intersection_query_subindex_results[i];
+
+ cbk.valid_dir = Vector2();
+ cbk.valid_depth = 0;
+
+ if (GodotCollisionSolver2D::solve(shape, p_parameters.transform, p_parameters.motion, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), cbkres, cbkptr, nullptr, p_parameters.margin)) {
+ collided = cbk.amount > 0;
+ }
+ }
+
+ r_result_count = cbk.amount;
+
+ return collided;
+}
+
+struct _RestCallbackData2D {
+ const GodotCollisionObject2D *object = nullptr;
+ const GodotCollisionObject2D *best_object = nullptr;
+ int local_shape = 0;
+ int best_local_shape = 0;
+ int shape = 0;
+ int best_shape = 0;
+ Vector2 best_contact;
+ Vector2 best_normal;
+ real_t best_len = 0.0;
+ Vector2 valid_dir;
+ real_t valid_depth = 0.0;
+ real_t min_allowed_depth = 0.0;
+};
+
+static void _rest_cbk_result(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_userdata) {
+ _RestCallbackData2D *rd = static_cast<_RestCallbackData2D *>(p_userdata);
+
+ Vector2 contact_rel = p_point_B - p_point_A;
+ real_t len = contact_rel.length();
+
+ if (len < rd->min_allowed_depth) {
+ return;
+ }
+
+ if (len <= rd->best_len) {
+ return;
+ }
+
+ Vector2 normal = contact_rel / len;
+
+ if (rd->valid_dir != Vector2()) {
+ if (len > rd->valid_depth) {
+ return;
+ }
+
+ if (rd->valid_dir.dot(normal) > -CMP_EPSILON) {
+ return;
+ }
+ }
+
+ rd->best_len = len;
+ rd->best_contact = p_point_B;
+ rd->best_normal = normal;
+ rd->best_object = rd->object;
+ rd->best_shape = rd->shape;
+ rd->best_local_shape = rd->local_shape;
+}
+
+bool GodotPhysicsDirectSpaceState2D::rest_info(const ShapeParameters &p_parameters, ShapeRestInfo *r_info) {
+ GodotShape2D *shape = GodotPhysicsServer2D::godot_singleton->shape_owner.get_or_null(p_parameters.shape_rid);
+ ERR_FAIL_COND_V(!shape, 0);
+
+ real_t margin = MAX(p_parameters.margin, TEST_MOTION_MARGIN_MIN_VALUE);
+
+ Rect2 aabb = p_parameters.transform.xform(shape->get_aabb());
+ aabb = aabb.merge(Rect2(aabb.position + p_parameters.motion, aabb.size)); //motion
+ aabb = aabb.grow(margin);
+
+ int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, GodotSpace2D::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
+
+ _RestCallbackData2D rcd;
+
+ // Allowed depth can't be lower than motion length, in order to handle contacts at low speed.
+ real_t motion_length = p_parameters.motion.length();
+ real_t min_contact_depth = margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR;
+ rcd.min_allowed_depth = MIN(motion_length, min_contact_depth);
+
+ for (int i = 0; i < amount; i++) {
+ if (!_can_collide_with(space->intersection_query_results[i], p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas)) {
+ continue;
+ }
+
+ const GodotCollisionObject2D *col_obj = space->intersection_query_results[i];
+
+ if (p_parameters.exclude.has(col_obj->get_self())) {
+ continue;
+ }
+
+ int shape_idx = space->intersection_query_subindex_results[i];
+
+ rcd.valid_dir = Vector2();
+ rcd.object = col_obj;
+ rcd.shape = shape_idx;
+ rcd.local_shape = 0;
+ bool sc = GodotCollisionSolver2D::solve(shape, p_parameters.transform, p_parameters.motion, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), _rest_cbk_result, &rcd, nullptr, margin);
+ if (!sc) {
+ continue;
+ }
+ }
+
+ if (rcd.best_len == 0 || !rcd.best_object) {
+ return false;
+ }
+
+ r_info->collider_id = rcd.best_object->get_instance_id();
+ r_info->shape = rcd.best_shape;
+ r_info->normal = rcd.best_normal;
+ r_info->point = rcd.best_contact;
+ r_info->rid = rcd.best_object->get_self();
+ if (rcd.best_object->get_type() == GodotCollisionObject2D::TYPE_BODY) {
+ const GodotBody2D *body = static_cast<const GodotBody2D *>(rcd.best_object);
+ Vector2 rel_vec = r_info->point - (body->get_transform().get_origin() + body->get_center_of_mass());
+ r_info->linear_velocity = Vector2(-body->get_angular_velocity() * rel_vec.y, body->get_angular_velocity() * rel_vec.x) + body->get_linear_velocity();
+
+ } else {
+ r_info->linear_velocity = Vector2();
+ }
+
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+int GodotSpace2D::_cull_aabb_for_body(GodotBody2D *p_body, const Rect2 &p_aabb) {
+ int amount = broadphase->cull_aabb(p_aabb, intersection_query_results, INTERSECTION_QUERY_MAX, intersection_query_subindex_results);
+
+ for (int i = 0; i < amount; i++) {
+ bool keep = true;
+
+ if (intersection_query_results[i] == p_body) {
+ keep = false;
+ } else if (intersection_query_results[i]->get_type() == GodotCollisionObject2D::TYPE_AREA) {
+ keep = false;
+ } else if (!p_body->collides_with(static_cast<GodotBody2D *>(intersection_query_results[i]))) {
+ keep = false;
+ } else if (static_cast<GodotBody2D *>(intersection_query_results[i])->has_exception(p_body->get_self()) || p_body->has_exception(intersection_query_results[i]->get_self())) {
+ keep = false;
+ }
+
+ if (!keep) {
+ if (i < amount - 1) {
+ SWAP(intersection_query_results[i], intersection_query_results[amount - 1]);
+ SWAP(intersection_query_subindex_results[i], intersection_query_subindex_results[amount - 1]);
+ }
+
+ amount--;
+ i--;
+ }
+ }
+
+ return amount;
+}
+
+bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D::MotionParameters &p_parameters, PhysicsServer2D::MotionResult *r_result) {
+ //give me back regular physics engine logic
+ //this is madness
+ //and most people using this function will think
+ //what it does is simpler than using physics
+ //this took about a week to get right..
+ //but is it right? who knows at this point..
+
+ if (r_result) {
+ r_result->collider_id = ObjectID();
+ r_result->collider_shape = 0;
+ }
+
+ Rect2 body_aabb;
+
+ bool shapes_found = false;
+
+ for (int i = 0; i < p_body->get_shape_count(); i++) {
+ if (p_body->is_shape_disabled(i)) {
+ continue;
+ }
+
+ if (!shapes_found) {
+ body_aabb = p_body->get_shape_aabb(i);
+ shapes_found = true;
+ } else {
+ body_aabb = body_aabb.merge(p_body->get_shape_aabb(i));
+ }
+ }
+
+ if (!shapes_found) {
+ if (r_result) {
+ *r_result = PhysicsServer2D::MotionResult();
+ r_result->travel = p_parameters.motion;
+ }
+ return false;
+ }
+
+ real_t margin = MAX(p_parameters.margin, TEST_MOTION_MARGIN_MIN_VALUE);
+
+ // Undo the currently transform the physics server is aware of and apply the provided one
+ body_aabb = p_parameters.from.xform(p_body->get_inv_transform().xform(body_aabb));
+ body_aabb = body_aabb.grow(margin);
+
+ static const int max_excluded_shape_pairs = 32;
+ ExcludedShapeSW excluded_shape_pairs[max_excluded_shape_pairs];
+ int excluded_shape_pair_count = 0;
+
+ real_t min_contact_depth = margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR;
+
+ real_t motion_length = p_parameters.motion.length();
+ Vector2 motion_normal = p_parameters.motion / motion_length;
+
+ Transform2D body_transform = p_parameters.from;
+
+ bool recovered = false;
+
+ {
+ //STEP 1, FREE BODY IF STUCK
+
+ const int max_results = 32;
+ int recover_attempts = 4;
+ Vector2 sr[max_results * 2];
+
+ do {
+ GodotPhysicsServer2D::CollCbkData cbk;
+ cbk.max = max_results;
+ cbk.amount = 0;
+ cbk.passed = 0;
+ cbk.ptr = sr;
+ cbk.invalid_by_dir = 0;
+ excluded_shape_pair_count = 0; //last step is the one valid
+
+ GodotPhysicsServer2D::CollCbkData *cbkptr = &cbk;
+ GodotCollisionSolver2D::CallbackResult cbkres = GodotPhysicsServer2D::_shape_col_cbk;
+
+ bool collided = false;
+
+ int amount = _cull_aabb_for_body(p_body, body_aabb);
+
+ for (int j = 0; j < p_body->get_shape_count(); j++) {
+ if (p_body->is_shape_disabled(j)) {
+ continue;
+ }
+
+ GodotShape2D *body_shape = p_body->get_shape(j);
+ Transform2D body_shape_xform = body_transform * p_body->get_shape_transform(j);
+
+ for (int i = 0; i < amount; i++) {
+ const GodotCollisionObject2D *col_obj = intersection_query_results[i];
+ if (p_parameters.exclude_bodies.has(col_obj->get_self())) {
+ continue;
+ }
+ if (p_parameters.exclude_objects.has(col_obj->get_instance_id())) {
+ continue;
+ }
+
+ int shape_idx = intersection_query_subindex_results[i];
+
+ Transform2D col_obj_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
+
+ if (body_shape->allows_one_way_collision() && col_obj->is_shape_set_as_one_way_collision(shape_idx)) {
+ cbk.valid_dir = col_obj_shape_xform.columns[1].normalized();
+
+ real_t owc_margin = col_obj->get_shape_one_way_collision_margin(shape_idx);
+ cbk.valid_depth = MAX(owc_margin, margin); //user specified, but never less than actual margin or it won't work
+ cbk.invalid_by_dir = 0;
+
+ if (col_obj->get_type() == GodotCollisionObject2D::TYPE_BODY) {
+ const GodotBody2D *b = static_cast<const GodotBody2D *>(col_obj);
+ if (b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_DYNAMIC) {
+ //fix for moving platforms (kinematic and dynamic), margin is increased by how much it moved in the given direction
+ Vector2 lv = b->get_linear_velocity();
+ //compute displacement from linear velocity
+ Vector2 motion = lv * last_step;
+ real_t motion_len = motion.length();
+ motion.normalize();
+ cbk.valid_depth += motion_len * MAX(motion.dot(-cbk.valid_dir), 0.0);
+ }
+ }
+ } else {
+ cbk.valid_dir = Vector2();
+ cbk.valid_depth = 0;
+ cbk.invalid_by_dir = 0;
+ }
+
+ int current_passed = cbk.passed; //save how many points passed collision
+ bool did_collide = false;
+
+ GodotShape2D *against_shape = col_obj->get_shape(shape_idx);
+ if (GodotCollisionSolver2D::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), cbkres, cbkptr, nullptr, margin)) {
+ did_collide = cbk.passed > current_passed; //more passed, so collision actually existed
+ }
+
+ if (!did_collide && cbk.invalid_by_dir > 0) {
+ //this shape must be excluded
+ if (excluded_shape_pair_count < max_excluded_shape_pairs) {
+ ExcludedShapeSW esp;
+ esp.local_shape = body_shape;
+ esp.against_object = col_obj;
+ esp.against_shape_index = shape_idx;
+ excluded_shape_pairs[excluded_shape_pair_count++] = esp;
+ }
+ }
+
+ if (did_collide) {
+ collided = true;
+ }
+ }
+ }
+
+ if (!collided) {
+ break;
+ }
+
+ recovered = true;
+
+ Vector2 recover_motion;
+ for (int i = 0; i < cbk.amount; i++) {
+ Vector2 a = sr[i * 2 + 0];
+ Vector2 b = sr[i * 2 + 1];
+
+ // Compute plane on b towards a.
+ Vector2 n = (a - b).normalized();
+ real_t d = n.dot(b);
+
+ // Compute depth on recovered motion.
+ real_t depth = n.dot(a + recover_motion) - d;
+ if (depth > min_contact_depth + CMP_EPSILON) {
+ // Only recover if there is penetration.
+ recover_motion -= n * (depth - min_contact_depth) * 0.4;
+ }
+ }
+
+ if (recover_motion == Vector2()) {
+ collided = false;
+ break;
+ }
+
+ body_transform.columns[2] += recover_motion;
+ body_aabb.position += recover_motion;
+
+ recover_attempts--;
+
+ } while (recover_attempts);
+ }
+
+ real_t safe = 1.0;
+ real_t unsafe = 1.0;
+ int best_shape = -1;
+
+ {
+ // STEP 2 ATTEMPT MOTION
+
+ Rect2 motion_aabb = body_aabb;
+ motion_aabb.position += p_parameters.motion;
+ motion_aabb = motion_aabb.merge(body_aabb);
+
+ int amount = _cull_aabb_for_body(p_body, motion_aabb);
+
+ for (int body_shape_idx = 0; body_shape_idx < p_body->get_shape_count(); body_shape_idx++) {
+ if (p_body->is_shape_disabled(body_shape_idx)) {
+ continue;
+ }
+
+ GodotShape2D *body_shape = p_body->get_shape(body_shape_idx);
+
+ // Colliding separation rays allows to properly snap to the ground,
+ // otherwise it's not needed in regular motion.
+ if (!p_parameters.collide_separation_ray && (body_shape->get_type() == PhysicsServer2D::SHAPE_SEPARATION_RAY)) {
+ // When slide on slope is on, separation ray shape acts like a regular shape.
+ if (!static_cast<GodotSeparationRayShape2D *>(body_shape)->get_slide_on_slope()) {
+ continue;
+ }
+ }
+
+ Transform2D body_shape_xform = body_transform * p_body->get_shape_transform(body_shape_idx);
+
+ bool stuck = false;
+
+ real_t best_safe = 1;
+ real_t best_unsafe = 1;
+
+ for (int i = 0; i < amount; i++) {
+ const GodotCollisionObject2D *col_obj = intersection_query_results[i];
+ if (p_parameters.exclude_bodies.has(col_obj->get_self())) {
+ continue;
+ }
+ if (p_parameters.exclude_objects.has(col_obj->get_instance_id())) {
+ continue;
+ }
+
+ int col_shape_idx = intersection_query_subindex_results[i];
+ GodotShape2D *against_shape = col_obj->get_shape(col_shape_idx);
+
+ bool excluded = false;
+
+ for (int k = 0; k < excluded_shape_pair_count; k++) {
+ if (excluded_shape_pairs[k].local_shape == body_shape && excluded_shape_pairs[k].against_object == col_obj && excluded_shape_pairs[k].against_shape_index == col_shape_idx) {
+ excluded = true;
+ break;
+ }
+ }
+
+ if (excluded) {
+ continue;
+ }
+
+ Transform2D col_obj_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(col_shape_idx);
+ //test initial overlap, does it collide if going all the way?
+ if (!GodotCollisionSolver2D::solve(body_shape, body_shape_xform, p_parameters.motion, against_shape, col_obj_shape_xform, Vector2(), nullptr, nullptr, nullptr, 0)) {
+ continue;
+ }
+
+ //test initial overlap
+ if (GodotCollisionSolver2D::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), nullptr, nullptr, nullptr, 0)) {
+ if (body_shape->allows_one_way_collision() && col_obj->is_shape_set_as_one_way_collision(col_shape_idx)) {
+ Vector2 direction = col_obj_shape_xform.columns[1].normalized();
+ if (motion_normal.dot(direction) < 0) {
+ continue;
+ }
+ }
+
+ stuck = true;
+ break;
+ }
+
+ //just do kinematic solving
+ real_t low = 0.0;
+ real_t hi = 1.0;
+ real_t fraction_coeff = 0.5;
+ for (int k = 0; k < 8; k++) { //steps should be customizable..
+ real_t fraction = low + (hi - low) * fraction_coeff;
+
+ Vector2 sep = motion_normal; //important optimization for this to work fast enough
+ bool collided = GodotCollisionSolver2D::solve(body_shape, body_shape_xform, p_parameters.motion * fraction, against_shape, col_obj_shape_xform, Vector2(), nullptr, nullptr, &sep, 0);
+
+ if (collided) {
+ hi = fraction;
+ if ((k == 0) || (low > 0.0)) { // Did it not collide before?
+ // When alternating or first iteration, use dichotomy.
+ fraction_coeff = 0.5;
+ } else {
+ // When colliding again, converge faster towards low fraction
+ // for more accurate results with long motions that collide near the start.
+ fraction_coeff = 0.25;
+ }
+ } else {
+ low = fraction;
+ if ((k == 0) || (hi < 1.0)) { // Did it collide before?
+ // When alternating or first iteration, use dichotomy.
+ fraction_coeff = 0.5;
+ } else {
+ // When not colliding again, converge faster towards high fraction
+ // for more accurate results with long motions that collide near the end.
+ fraction_coeff = 0.75;
+ }
+ }
+ }
+
+ if (body_shape->allows_one_way_collision() && col_obj->is_shape_set_as_one_way_collision(col_shape_idx)) {
+ Vector2 cd[2];
+ GodotPhysicsServer2D::CollCbkData cbk;
+ cbk.max = 1;
+ cbk.amount = 0;
+ cbk.passed = 0;
+ cbk.ptr = cd;
+ cbk.valid_dir = col_obj_shape_xform.columns[1].normalized();
+
+ cbk.valid_depth = 10e20;
+
+ Vector2 sep = motion_normal; //important optimization for this to work fast enough
+ bool collided = GodotCollisionSolver2D::solve(body_shape, body_shape_xform, p_parameters.motion * (hi + contact_max_allowed_penetration), col_obj->get_shape(col_shape_idx), col_obj_shape_xform, Vector2(), GodotPhysicsServer2D::_shape_col_cbk, &cbk, &sep, 0);
+ if (!collided || cbk.amount == 0) {
+ continue;
+ }
+ }
+
+ if (low < best_safe) {
+ best_safe = low;
+ best_unsafe = hi;
+ }
+ }
+
+ if (stuck) {
+ safe = 0;
+ unsafe = 0;
+ best_shape = body_shape_idx; //sadly it's the best
+ break;
+ }
+ if (best_safe == 1.0) {
+ continue;
+ }
+ if (best_safe < safe) {
+ safe = best_safe;
+ unsafe = best_unsafe;
+ best_shape = body_shape_idx;
+ }
+ }
+ }
+
+ bool collided = false;
+
+ if ((p_parameters.recovery_as_collision && recovered) || (safe < 1)) {
+ if (safe >= 1) {
+ best_shape = -1; //no best shape with cast, reset to -1
+ }
+
+ //it collided, let's get the rest info in unsafe advance
+ Transform2D ugt = body_transform;
+ ugt.columns[2] += p_parameters.motion * unsafe;
+
+ _RestCallbackData2D rcd;
+
+ // Allowed depth can't be lower than motion length, in order to handle contacts at low speed.
+ rcd.min_allowed_depth = MIN(motion_length, min_contact_depth);
+
+ body_aabb.position += p_parameters.motion * unsafe;
+ int amount = _cull_aabb_for_body(p_body, body_aabb);
+
+ int from_shape = best_shape != -1 ? best_shape : 0;
+ int to_shape = best_shape != -1 ? best_shape + 1 : p_body->get_shape_count();
+
+ for (int j = from_shape; j < to_shape; j++) {
+ if (p_body->is_shape_disabled(j)) {
+ continue;
+ }
+
+ Transform2D body_shape_xform = ugt * p_body->get_shape_transform(j);
+ GodotShape2D *body_shape = p_body->get_shape(j);
+
+ for (int i = 0; i < amount; i++) {
+ const GodotCollisionObject2D *col_obj = intersection_query_results[i];
+ if (p_parameters.exclude_bodies.has(col_obj->get_self())) {
+ continue;
+ }
+ if (p_parameters.exclude_objects.has(col_obj->get_instance_id())) {
+ continue;
+ }
+
+ int shape_idx = intersection_query_subindex_results[i];
+
+ GodotShape2D *against_shape = col_obj->get_shape(shape_idx);
+
+ bool excluded = false;
+ for (int k = 0; k < excluded_shape_pair_count; k++) {
+ if (excluded_shape_pairs[k].local_shape == body_shape && excluded_shape_pairs[k].against_object == col_obj && excluded_shape_pairs[k].against_shape_index == shape_idx) {
+ excluded = true;
+ break;
+ }
+ }
+ if (excluded) {
+ continue;
+ }
+
+ Transform2D col_obj_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
+
+ if (body_shape->allows_one_way_collision() && col_obj->is_shape_set_as_one_way_collision(shape_idx)) {
+ rcd.valid_dir = col_obj_shape_xform.columns[1].normalized();
+
+ real_t owc_margin = col_obj->get_shape_one_way_collision_margin(shape_idx);
+ rcd.valid_depth = MAX(owc_margin, margin); //user specified, but never less than actual margin or it won't work
+
+ if (col_obj->get_type() == GodotCollisionObject2D::TYPE_BODY) {
+ const GodotBody2D *b = static_cast<const GodotBody2D *>(col_obj);
+ if (b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_DYNAMIC) {
+ //fix for moving platforms (kinematic and dynamic), margin is increased by how much it moved in the given direction
+ Vector2 lv = b->get_linear_velocity();
+ //compute displacement from linear velocity
+ Vector2 motion = lv * last_step;
+ real_t motion_len = motion.length();
+ motion.normalize();
+ rcd.valid_depth += motion_len * MAX(motion.dot(-rcd.valid_dir), 0.0);
+ }
+ }
+ } else {
+ rcd.valid_dir = Vector2();
+ rcd.valid_depth = 0;
+ }
+
+ rcd.object = col_obj;
+ rcd.shape = shape_idx;
+ rcd.local_shape = j;
+ bool sc = GodotCollisionSolver2D::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), _rest_cbk_result, &rcd, nullptr, margin);
+ if (!sc) {
+ continue;
+ }
+ }
+ }
+
+ if (rcd.best_len != 0) {
+ if (r_result) {
+ r_result->collider = rcd.best_object->get_self();
+ r_result->collider_id = rcd.best_object->get_instance_id();
+ r_result->collider_shape = rcd.best_shape;
+ r_result->collision_local_shape = rcd.best_local_shape;
+ r_result->collision_normal = rcd.best_normal;
+ r_result->collision_point = rcd.best_contact;
+ r_result->collision_depth = rcd.best_len;
+ r_result->collision_safe_fraction = safe;
+ r_result->collision_unsafe_fraction = unsafe;
+
+ const GodotBody2D *body = static_cast<const GodotBody2D *>(rcd.best_object);
+ Vector2 rel_vec = r_result->collision_point - (body->get_transform().get_origin() + body->get_center_of_mass());
+ r_result->collider_velocity = Vector2(-body->get_angular_velocity() * rel_vec.y, body->get_angular_velocity() * rel_vec.x) + body->get_linear_velocity();
+
+ r_result->travel = safe * p_parameters.motion;
+ r_result->remainder = p_parameters.motion - safe * p_parameters.motion;
+ r_result->travel += (body_transform.get_origin() - p_parameters.from.get_origin());
+ }
+
+ collided = true;
+ }
+ }
+
+ if (!collided && r_result) {
+ r_result->travel = p_parameters.motion;
+ r_result->remainder = Vector2();
+ r_result->travel += (body_transform.get_origin() - p_parameters.from.get_origin());
+ }
+
+ return collided;
+}
+
+// Assumes a valid collision pair, this should have been checked beforehand in the BVH or octree.
+void *GodotSpace2D::_broadphase_pair(GodotCollisionObject2D *A, int p_subindex_A, GodotCollisionObject2D *B, int p_subindex_B, void *p_self) {
+ GodotCollisionObject2D::Type type_A = A->get_type();
+ GodotCollisionObject2D::Type type_B = B->get_type();
+ if (type_A > type_B) {
+ SWAP(A, B);
+ SWAP(p_subindex_A, p_subindex_B);
+ SWAP(type_A, type_B);
+ }
+
+ GodotSpace2D *self = static_cast<GodotSpace2D *>(p_self);
+ self->collision_pairs++;
+
+ if (type_A == GodotCollisionObject2D::TYPE_AREA) {
+ GodotArea2D *area = static_cast<GodotArea2D *>(A);
+ if (type_B == GodotCollisionObject2D::TYPE_AREA) {
+ GodotArea2D *area_b = static_cast<GodotArea2D *>(B);
+ GodotArea2Pair2D *area2_pair = memnew(GodotArea2Pair2D(area_b, p_subindex_B, area, p_subindex_A));
+ return area2_pair;
+ } else {
+ GodotBody2D *body = static_cast<GodotBody2D *>(B);
+ GodotAreaPair2D *area_pair = memnew(GodotAreaPair2D(body, p_subindex_B, area, p_subindex_A));
+ return area_pair;
+ }
+
+ } else {
+ GodotBodyPair2D *b = memnew(GodotBodyPair2D(static_cast<GodotBody2D *>(A), p_subindex_A, static_cast<GodotBody2D *>(B), p_subindex_B));
+ return b;
+ }
+
+ return nullptr;
+}
+
+void GodotSpace2D::_broadphase_unpair(GodotCollisionObject2D *A, int p_subindex_A, GodotCollisionObject2D *B, int p_subindex_B, void *p_data, void *p_self) {
+ if (!p_data) {
+ return;
+ }
+
+ GodotSpace2D *self = static_cast<GodotSpace2D *>(p_self);
+ self->collision_pairs--;
+ GodotConstraint2D *c = static_cast<GodotConstraint2D *>(p_data);
+ memdelete(c);
+}
+
+const SelfList<GodotBody2D>::List &GodotSpace2D::get_active_body_list() const {
+ return active_list;
+}
+
+void GodotSpace2D::body_add_to_active_list(SelfList<GodotBody2D> *p_body) {
+ active_list.add(p_body);
+}
+
+void GodotSpace2D::body_remove_from_active_list(SelfList<GodotBody2D> *p_body) {
+ active_list.remove(p_body);
+}
+
+void GodotSpace2D::body_add_to_mass_properties_update_list(SelfList<GodotBody2D> *p_body) {
+ mass_properties_update_list.add(p_body);
+}
+
+void GodotSpace2D::body_remove_from_mass_properties_update_list(SelfList<GodotBody2D> *p_body) {
+ mass_properties_update_list.remove(p_body);
+}
+
+GodotBroadPhase2D *GodotSpace2D::get_broadphase() {
+ return broadphase;
+}
+
+void GodotSpace2D::add_object(GodotCollisionObject2D *p_object) {
+ ERR_FAIL_COND(objects.has(p_object));
+ objects.insert(p_object);
+}
+
+void GodotSpace2D::remove_object(GodotCollisionObject2D *p_object) {
+ ERR_FAIL_COND(!objects.has(p_object));
+ objects.erase(p_object);
+}
+
+const HashSet<GodotCollisionObject2D *> &GodotSpace2D::get_objects() const {
+ return objects;
+}
+
+void GodotSpace2D::body_add_to_state_query_list(SelfList<GodotBody2D> *p_body) {
+ state_query_list.add(p_body);
+}
+
+void GodotSpace2D::body_remove_from_state_query_list(SelfList<GodotBody2D> *p_body) {
+ state_query_list.remove(p_body);
+}
+
+void GodotSpace2D::area_add_to_monitor_query_list(SelfList<GodotArea2D> *p_area) {
+ monitor_query_list.add(p_area);
+}
+
+void GodotSpace2D::area_remove_from_monitor_query_list(SelfList<GodotArea2D> *p_area) {
+ monitor_query_list.remove(p_area);
+}
+
+void GodotSpace2D::area_add_to_moved_list(SelfList<GodotArea2D> *p_area) {
+ area_moved_list.add(p_area);
+}
+
+void GodotSpace2D::area_remove_from_moved_list(SelfList<GodotArea2D> *p_area) {
+ area_moved_list.remove(p_area);
+}
+
+const SelfList<GodotArea2D>::List &GodotSpace2D::get_moved_area_list() const {
+ return area_moved_list;
+}
+
+void GodotSpace2D::call_queries() {
+ while (state_query_list.first()) {
+ GodotBody2D *b = state_query_list.first()->self();
+ state_query_list.remove(state_query_list.first());
+ b->call_queries();
+ }
+
+ while (monitor_query_list.first()) {
+ GodotArea2D *a = monitor_query_list.first()->self();
+ monitor_query_list.remove(monitor_query_list.first());
+ a->call_queries();
+ }
+}
+
+void GodotSpace2D::setup() {
+ contact_debug_count = 0;
+
+ while (mass_properties_update_list.first()) {
+ mass_properties_update_list.first()->self()->update_mass_properties();
+ mass_properties_update_list.remove(mass_properties_update_list.first());
+ }
+}
+
+void GodotSpace2D::update() {
+ broadphase->update();
+}
+
+void GodotSpace2D::set_param(PhysicsServer2D::SpaceParameter p_param, real_t p_value) {
+ switch (p_param) {
+ case PhysicsServer2D::SPACE_PARAM_CONTACT_RECYCLE_RADIUS:
+ contact_recycle_radius = p_value;
+ break;
+ case PhysicsServer2D::SPACE_PARAM_CONTACT_MAX_SEPARATION:
+ contact_max_separation = p_value;
+ break;
+ case PhysicsServer2D::SPACE_PARAM_CONTACT_MAX_ALLOWED_PENETRATION:
+ contact_max_allowed_penetration = p_value;
+ break;
+ case PhysicsServer2D::SPACE_PARAM_CONTACT_DEFAULT_BIAS:
+ contact_bias = p_value;
+ break;
+ case PhysicsServer2D::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD:
+ body_linear_velocity_sleep_threshold = p_value;
+ break;
+ case PhysicsServer2D::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD:
+ body_angular_velocity_sleep_threshold = p_value;
+ break;
+ case PhysicsServer2D::SPACE_PARAM_BODY_TIME_TO_SLEEP:
+ body_time_to_sleep = p_value;
+ break;
+ case PhysicsServer2D::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS:
+ constraint_bias = p_value;
+ break;
+ case PhysicsServer2D::SPACE_PARAM_SOLVER_ITERATIONS:
+ solver_iterations = p_value;
+ break;
+ }
+}
+
+real_t GodotSpace2D::get_param(PhysicsServer2D::SpaceParameter p_param) const {
+ switch (p_param) {
+ case PhysicsServer2D::SPACE_PARAM_CONTACT_RECYCLE_RADIUS:
+ return contact_recycle_radius;
+ case PhysicsServer2D::SPACE_PARAM_CONTACT_MAX_SEPARATION:
+ return contact_max_separation;
+ case PhysicsServer2D::SPACE_PARAM_CONTACT_MAX_ALLOWED_PENETRATION:
+ return contact_max_allowed_penetration;
+ case PhysicsServer2D::SPACE_PARAM_CONTACT_DEFAULT_BIAS:
+ return contact_bias;
+ case PhysicsServer2D::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD:
+ return body_linear_velocity_sleep_threshold;
+ case PhysicsServer2D::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD:
+ return body_angular_velocity_sleep_threshold;
+ case PhysicsServer2D::SPACE_PARAM_BODY_TIME_TO_SLEEP:
+ return body_time_to_sleep;
+ case PhysicsServer2D::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS:
+ return constraint_bias;
+ case PhysicsServer2D::SPACE_PARAM_SOLVER_ITERATIONS:
+ return solver_iterations;
+ }
+ return 0;
+}
+
+void GodotSpace2D::lock() {
+ locked = true;
+}
+
+void GodotSpace2D::unlock() {
+ locked = false;
+}
+
+bool GodotSpace2D::is_locked() const {
+ return locked;
+}
+
+GodotPhysicsDirectSpaceState2D *GodotSpace2D::get_direct_state() {
+ return direct_access;
+}
+
+GodotSpace2D::GodotSpace2D() {
+ body_linear_velocity_sleep_threshold = GLOBAL_DEF("physics/2d/sleep_threshold_linear", 2.0);
+ body_angular_velocity_sleep_threshold = GLOBAL_DEF("physics/2d/sleep_threshold_angular", Math::deg2rad(8.0));
+ body_time_to_sleep = GLOBAL_DEF("physics/2d/time_before_sleep", 0.5);
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/time_before_sleep", PropertyInfo(Variant::FLOAT, "physics/2d/time_before_sleep", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater"));
+
+ solver_iterations = GLOBAL_DEF("physics/2d/solver/solver_iterations", 16);
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/solver/solver_iterations", PropertyInfo(Variant::INT, "physics/2d/solver/solver_iterations", PROPERTY_HINT_RANGE, "1,32,1,or_greater"));
+
+ contact_recycle_radius = GLOBAL_DEF("physics/2d/solver/contact_recycle_radius", 1.0);
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/solver/contact_recycle_radius", PropertyInfo(Variant::FLOAT, "physics/2d/solver/contact_max_separation", PROPERTY_HINT_RANGE, "0,10,0.01,or_greater"));
+
+ contact_max_separation = GLOBAL_DEF("physics/2d/solver/contact_max_separation", 1.5);
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/solver/contact_max_separation", PropertyInfo(Variant::FLOAT, "physics/2d/solver/contact_max_separation", PROPERTY_HINT_RANGE, "0,10,0.01,or_greater"));
+
+ contact_max_allowed_penetration = GLOBAL_DEF("physics/2d/solver/contact_max_allowed_penetration", 0.3);
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/solver/contact_max_allowed_penetration", PropertyInfo(Variant::FLOAT, "physics/2d/solver/contact_max_allowed_penetration", PROPERTY_HINT_RANGE, "0,10,0.01,or_greater"));
+
+ contact_bias = GLOBAL_DEF("physics/2d/solver/default_contact_bias", 0.8);
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/solver/default_contact_bias", PropertyInfo(Variant::FLOAT, "physics/2d/solver/default_contact_bias", PROPERTY_HINT_RANGE, "0,1,0.01"));
+
+ constraint_bias = GLOBAL_DEF("physics/2d/solver/default_constraint_bias", 0.2);
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/solver/default_constraint_bias", PropertyInfo(Variant::FLOAT, "physics/2d/solver/default_constraint_bias", PROPERTY_HINT_RANGE, "0,1,0.01"));
+
+ broadphase = GodotBroadPhase2D::create_func();
+ broadphase->set_pair_callback(_broadphase_pair, this);
+ broadphase->set_unpair_callback(_broadphase_unpair, this);
+
+ direct_access = memnew(GodotPhysicsDirectSpaceState2D);
+ direct_access->space = this;
+}
+
+GodotSpace2D::~GodotSpace2D() {
+ memdelete(broadphase);
+ memdelete(direct_access);
+}
diff --git a/servers/physics_2d/godot_space_2d.h b/servers/physics_2d/godot_space_2d.h
new file mode 100644
index 0000000000..b6fc48bd70
--- /dev/null
+++ b/servers/physics_2d/godot_space_2d.h
@@ -0,0 +1,214 @@
+/*************************************************************************/
+/* godot_space_2d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 GODOT_SPACE_2D_H
+#define GODOT_SPACE_2D_H
+
+#include "godot_area_2d.h"
+#include "godot_area_pair_2d.h"
+#include "godot_body_2d.h"
+#include "godot_body_pair_2d.h"
+#include "godot_broad_phase_2d.h"
+#include "godot_collision_object_2d.h"
+
+#include "core/config/project_settings.h"
+#include "core/templates/hash_map.h"
+#include "core/typedefs.h"
+
+class GodotPhysicsDirectSpaceState2D : public PhysicsDirectSpaceState2D {
+ GDCLASS(GodotPhysicsDirectSpaceState2D, PhysicsDirectSpaceState2D);
+
+public:
+ GodotSpace2D *space = nullptr;
+
+ virtual int intersect_point(const PointParameters &p_parameters, ShapeResult *r_results, int p_result_max) override;
+ virtual bool intersect_ray(const RayParameters &p_parameters, RayResult &r_result) override;
+ virtual int intersect_shape(const ShapeParameters &p_parameters, ShapeResult *r_results, int p_result_max) override;
+ virtual bool cast_motion(const ShapeParameters &p_parameters, real_t &p_closest_safe, real_t &p_closest_unsafe) override;
+ virtual bool collide_shape(const ShapeParameters &p_parameters, Vector2 *r_results, int p_result_max, int &r_result_count) override;
+ virtual bool rest_info(const ShapeParameters &p_parameters, ShapeRestInfo *r_info) override;
+
+ GodotPhysicsDirectSpaceState2D() {}
+};
+
+class GodotSpace2D {
+public:
+ enum ElapsedTime {
+ ELAPSED_TIME_INTEGRATE_FORCES,
+ ELAPSED_TIME_GENERATE_ISLANDS,
+ ELAPSED_TIME_SETUP_CONSTRAINTS,
+ ELAPSED_TIME_SOLVE_CONSTRAINTS,
+ ELAPSED_TIME_INTEGRATE_VELOCITIES,
+ ELAPSED_TIME_MAX
+
+ };
+
+private:
+ struct ExcludedShapeSW {
+ GodotShape2D *local_shape = nullptr;
+ const GodotCollisionObject2D *against_object = nullptr;
+ int against_shape_index = 0;
+ };
+
+ uint64_t elapsed_time[ELAPSED_TIME_MAX] = {};
+
+ GodotPhysicsDirectSpaceState2D *direct_access = nullptr;
+ RID self;
+
+ GodotBroadPhase2D *broadphase = nullptr;
+ SelfList<GodotBody2D>::List active_list;
+ SelfList<GodotBody2D>::List mass_properties_update_list;
+ SelfList<GodotBody2D>::List state_query_list;
+ SelfList<GodotArea2D>::List monitor_query_list;
+ SelfList<GodotArea2D>::List area_moved_list;
+
+ static void *_broadphase_pair(GodotCollisionObject2D *A, int p_subindex_A, GodotCollisionObject2D *B, int p_subindex_B, void *p_self);
+ static void _broadphase_unpair(GodotCollisionObject2D *A, int p_subindex_A, GodotCollisionObject2D *B, int p_subindex_B, void *p_data, void *p_self);
+
+ HashSet<GodotCollisionObject2D *> objects;
+
+ GodotArea2D *area = nullptr;
+
+ int solver_iterations = 0;
+
+ real_t contact_recycle_radius = 0.0;
+ real_t contact_max_separation = 0.0;
+ real_t contact_max_allowed_penetration = 0.0;
+ real_t contact_bias = 0.0;
+ real_t constraint_bias = 0.0;
+
+ enum {
+ INTERSECTION_QUERY_MAX = 2048
+ };
+
+ GodotCollisionObject2D *intersection_query_results[INTERSECTION_QUERY_MAX];
+ int intersection_query_subindex_results[INTERSECTION_QUERY_MAX];
+
+ real_t body_linear_velocity_sleep_threshold = 0.0;
+ real_t body_angular_velocity_sleep_threshold = 0.0;
+ real_t body_time_to_sleep = 0.0;
+
+ bool locked = false;
+
+ real_t last_step = 0.001;
+
+ int island_count = 0;
+ int active_objects = 0;
+ int collision_pairs = 0;
+
+ int _cull_aabb_for_body(GodotBody2D *p_body, const Rect2 &p_aabb);
+
+ Vector<Vector2> contact_debug;
+ int contact_debug_count = 0;
+
+ friend class GodotPhysicsDirectSpaceState2D;
+
+public:
+ _FORCE_INLINE_ void set_self(const RID &p_self) { self = p_self; }
+ _FORCE_INLINE_ RID get_self() const { return self; }
+
+ void set_default_area(GodotArea2D *p_area) { area = p_area; }
+ GodotArea2D *get_default_area() const { return area; }
+
+ const SelfList<GodotBody2D>::List &get_active_body_list() const;
+ void body_add_to_active_list(SelfList<GodotBody2D> *p_body);
+ void body_remove_from_active_list(SelfList<GodotBody2D> *p_body);
+ void body_add_to_mass_properties_update_list(SelfList<GodotBody2D> *p_body);
+ void body_remove_from_mass_properties_update_list(SelfList<GodotBody2D> *p_body);
+ void area_add_to_moved_list(SelfList<GodotArea2D> *p_area);
+ void area_remove_from_moved_list(SelfList<GodotArea2D> *p_area);
+ const SelfList<GodotArea2D>::List &get_moved_area_list() const;
+
+ void body_add_to_state_query_list(SelfList<GodotBody2D> *p_body);
+ void body_remove_from_state_query_list(SelfList<GodotBody2D> *p_body);
+
+ void area_add_to_monitor_query_list(SelfList<GodotArea2D> *p_area);
+ void area_remove_from_monitor_query_list(SelfList<GodotArea2D> *p_area);
+
+ GodotBroadPhase2D *get_broadphase();
+
+ void add_object(GodotCollisionObject2D *p_object);
+ void remove_object(GodotCollisionObject2D *p_object);
+ const HashSet<GodotCollisionObject2D *> &get_objects() const;
+
+ _FORCE_INLINE_ int get_solver_iterations() const { return solver_iterations; }
+ _FORCE_INLINE_ real_t get_contact_recycle_radius() const { return contact_recycle_radius; }
+ _FORCE_INLINE_ real_t get_contact_max_separation() const { return contact_max_separation; }
+ _FORCE_INLINE_ real_t get_contact_max_allowed_penetration() const { return contact_max_allowed_penetration; }
+ _FORCE_INLINE_ real_t get_contact_bias() const { return contact_bias; }
+ _FORCE_INLINE_ real_t get_constraint_bias() const { return constraint_bias; }
+ _FORCE_INLINE_ real_t get_body_linear_velocity_sleep_threshold() const { return body_linear_velocity_sleep_threshold; }
+ _FORCE_INLINE_ real_t get_body_angular_velocity_sleep_threshold() const { return body_angular_velocity_sleep_threshold; }
+ _FORCE_INLINE_ real_t get_body_time_to_sleep() const { return body_time_to_sleep; }
+
+ void update();
+ void setup();
+ void call_queries();
+
+ bool is_locked() const;
+ void lock();
+ void unlock();
+
+ real_t get_last_step() const { return last_step; }
+ void set_last_step(real_t p_step) { last_step = p_step; }
+
+ void set_param(PhysicsServer2D::SpaceParameter p_param, real_t p_value);
+ real_t get_param(PhysicsServer2D::SpaceParameter p_param) const;
+
+ void set_island_count(int p_island_count) { island_count = p_island_count; }
+ int get_island_count() const { return island_count; }
+
+ void set_active_objects(int p_active_objects) { active_objects = p_active_objects; }
+ int get_active_objects() const { return active_objects; }
+
+ int get_collision_pairs() const { return collision_pairs; }
+
+ bool test_body_motion(GodotBody2D *p_body, const PhysicsServer2D::MotionParameters &p_parameters, PhysicsServer2D::MotionResult *r_result);
+
+ void set_debug_contacts(int p_amount) { contact_debug.resize(p_amount); }
+ _FORCE_INLINE_ bool is_debugging_contacts() const { return !contact_debug.is_empty(); }
+ _FORCE_INLINE_ void add_debug_contact(const Vector2 &p_contact) {
+ if (contact_debug_count < contact_debug.size()) {
+ contact_debug.write[contact_debug_count++] = p_contact;
+ }
+ }
+ _FORCE_INLINE_ Vector<Vector2> get_debug_contacts() { return contact_debug; }
+ _FORCE_INLINE_ int get_debug_contact_count() { return contact_debug_count; }
+
+ GodotPhysicsDirectSpaceState2D *get_direct_state();
+
+ void set_elapsed_time(ElapsedTime p_time, uint64_t p_msec) { elapsed_time[p_time] = p_msec; }
+ uint64_t get_elapsed_time(ElapsedTime p_time) const { return elapsed_time[p_time]; }
+
+ GodotSpace2D();
+ ~GodotSpace2D();
+};
+
+#endif // GODOT_SPACE_2D_H
diff --git a/servers/physics_2d/godot_step_2d.cpp b/servers/physics_2d/godot_step_2d.cpp
new file mode 100644
index 0000000000..0603458acd
--- /dev/null
+++ b/servers/physics_2d/godot_step_2d.cpp
@@ -0,0 +1,305 @@
+/*************************************************************************/
+/* godot_step_2d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 "godot_step_2d.h"
+
+#include "core/os/os.h"
+
+#define BODY_ISLAND_COUNT_RESERVE 128
+#define BODY_ISLAND_SIZE_RESERVE 512
+#define ISLAND_COUNT_RESERVE 128
+#define ISLAND_SIZE_RESERVE 512
+#define CONSTRAINT_COUNT_RESERVE 1024
+
+void GodotStep2D::_populate_island(GodotBody2D *p_body, LocalVector<GodotBody2D *> &p_body_island, LocalVector<GodotConstraint2D *> &p_constraint_island) {
+ p_body->set_island_step(_step);
+
+ if (p_body->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC) {
+ // Only dynamic bodies are tested for activation.
+ p_body_island.push_back(p_body);
+ }
+
+ for (const Pair<GodotConstraint2D *, int> &E : p_body->get_constraint_list()) {
+ GodotConstraint2D *constraint = const_cast<GodotConstraint2D *>(E.first);
+ if (constraint->get_island_step() == _step) {
+ continue; // Already processed.
+ }
+ constraint->set_island_step(_step);
+ p_constraint_island.push_back(constraint);
+ all_constraints.push_back(constraint);
+
+ for (int i = 0; i < constraint->get_body_count(); i++) {
+ if (i == E.second) {
+ continue;
+ }
+ GodotBody2D *other_body = constraint->get_body_ptr()[i];
+ if (other_body->get_island_step() == _step) {
+ continue; // Already processed.
+ }
+ if (other_body->get_mode() == PhysicsServer2D::BODY_MODE_STATIC) {
+ continue; // Static bodies don't connect islands.
+ }
+ _populate_island(other_body, p_body_island, p_constraint_island);
+ }
+ }
+}
+
+void GodotStep2D::_setup_contraint(uint32_t p_constraint_index, void *p_userdata) {
+ GodotConstraint2D *constraint = all_constraints[p_constraint_index];
+ constraint->setup(delta);
+}
+
+void GodotStep2D::_pre_solve_island(LocalVector<GodotConstraint2D *> &p_constraint_island) const {
+ uint32_t constraint_count = p_constraint_island.size();
+ uint32_t valid_constraint_count = 0;
+ for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) {
+ GodotConstraint2D *constraint = p_constraint_island[constraint_index];
+ if (p_constraint_island[constraint_index]->pre_solve(delta)) {
+ // Keep this constraint for solving.
+ p_constraint_island[valid_constraint_count++] = constraint;
+ }
+ }
+ p_constraint_island.resize(valid_constraint_count);
+}
+
+void GodotStep2D::_solve_island(uint32_t p_island_index, void *p_userdata) const {
+ const LocalVector<GodotConstraint2D *> &constraint_island = constraint_islands[p_island_index];
+
+ for (int i = 0; i < iterations; i++) {
+ uint32_t constraint_count = constraint_island.size();
+ for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) {
+ constraint_island[constraint_index]->solve(delta);
+ }
+ }
+}
+
+void GodotStep2D::_check_suspend(LocalVector<GodotBody2D *> &p_body_island) const {
+ bool can_sleep = true;
+
+ uint32_t body_count = p_body_island.size();
+ for (uint32_t body_index = 0; body_index < body_count; ++body_index) {
+ GodotBody2D *body = p_body_island[body_index];
+
+ if (!body->sleep_test(delta)) {
+ can_sleep = false;
+ }
+ }
+
+ // Put all to sleep or wake up everyone.
+ for (uint32_t body_index = 0; body_index < body_count; ++body_index) {
+ GodotBody2D *body = p_body_island[body_index];
+
+ bool active = body->is_active();
+
+ if (active == can_sleep) {
+ body->set_active(!can_sleep);
+ }
+ }
+}
+
+void GodotStep2D::step(GodotSpace2D *p_space, real_t p_delta) {
+ p_space->lock(); // can't access space during this
+
+ p_space->setup(); //update inertias, etc
+
+ p_space->set_last_step(p_delta);
+
+ iterations = p_space->get_solver_iterations();
+ delta = p_delta;
+
+ const SelfList<GodotBody2D>::List *body_list = &p_space->get_active_body_list();
+
+ /* INTEGRATE FORCES */
+
+ uint64_t profile_begtime = OS::get_singleton()->get_ticks_usec();
+ uint64_t profile_endtime = 0;
+
+ int active_count = 0;
+
+ const SelfList<GodotBody2D> *b = body_list->first();
+ while (b) {
+ b->self()->integrate_forces(p_delta);
+ b = b->next();
+ active_count++;
+ }
+
+ p_space->set_active_objects(active_count);
+
+ // Update the broadphase to register collision pairs.
+ p_space->update();
+
+ { //profile
+ profile_endtime = OS::get_singleton()->get_ticks_usec();
+ p_space->set_elapsed_time(GodotSpace2D::ELAPSED_TIME_INTEGRATE_FORCES, profile_endtime - profile_begtime);
+ profile_begtime = profile_endtime;
+ }
+
+ /* GENERATE CONSTRAINT ISLANDS FOR MOVING AREAS */
+
+ uint32_t island_count = 0;
+
+ const SelfList<GodotArea2D>::List &aml = p_space->get_moved_area_list();
+
+ while (aml.first()) {
+ for (GodotConstraint2D *E : aml.first()->self()->get_constraints()) {
+ GodotConstraint2D *constraint = E;
+ if (constraint->get_island_step() == _step) {
+ continue;
+ }
+ constraint->set_island_step(_step);
+
+ // Each constraint can be on a separate island for areas as there's no solving phase.
+ ++island_count;
+ if (constraint_islands.size() < island_count) {
+ constraint_islands.resize(island_count);
+ }
+ LocalVector<GodotConstraint2D *> &constraint_island = constraint_islands[island_count - 1];
+ constraint_island.clear();
+
+ all_constraints.push_back(constraint);
+ constraint_island.push_back(constraint);
+ }
+ p_space->area_remove_from_moved_list((SelfList<GodotArea2D> *)aml.first()); //faster to remove here
+ }
+
+ /* GENERATE CONSTRAINT ISLANDS FOR ACTIVE RIGID BODIES */
+
+ b = body_list->first();
+
+ uint32_t body_island_count = 0;
+
+ while (b) {
+ GodotBody2D *body = b->self();
+
+ if (body->get_island_step() != _step) {
+ ++body_island_count;
+ if (body_islands.size() < body_island_count) {
+ body_islands.resize(body_island_count);
+ }
+ LocalVector<GodotBody2D *> &body_island = body_islands[body_island_count - 1];
+ body_island.clear();
+ body_island.reserve(BODY_ISLAND_SIZE_RESERVE);
+
+ ++island_count;
+ if (constraint_islands.size() < island_count) {
+ constraint_islands.resize(island_count);
+ }
+ LocalVector<GodotConstraint2D *> &constraint_island = constraint_islands[island_count - 1];
+ constraint_island.clear();
+ constraint_island.reserve(ISLAND_SIZE_RESERVE);
+
+ _populate_island(body, body_island, constraint_island);
+
+ if (body_island.is_empty()) {
+ --body_island_count;
+ }
+
+ if (constraint_island.is_empty()) {
+ --island_count;
+ }
+ }
+ b = b->next();
+ }
+
+ p_space->set_island_count((int)island_count);
+
+ { //profile
+ profile_endtime = OS::get_singleton()->get_ticks_usec();
+ p_space->set_elapsed_time(GodotSpace2D::ELAPSED_TIME_GENERATE_ISLANDS, profile_endtime - profile_begtime);
+ profile_begtime = profile_endtime;
+ }
+
+ /* SETUP CONSTRAINTS / PROCESS COLLISIONS */
+
+ uint32_t total_contraint_count = all_constraints.size();
+ WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &GodotStep2D::_setup_contraint, nullptr, total_contraint_count, -1, true, SNAME("Physics2DConstraintSetup"));
+ WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);
+
+ { //profile
+ profile_endtime = OS::get_singleton()->get_ticks_usec();
+ p_space->set_elapsed_time(GodotSpace2D::ELAPSED_TIME_SETUP_CONSTRAINTS, profile_endtime - profile_begtime);
+ profile_begtime = profile_endtime;
+ }
+
+ /* PRE-SOLVE CONSTRAINT ISLANDS */
+
+ // Warning: This doesn't run on threads, because it involves thread-unsafe processing.
+ for (uint32_t island_index = 0; island_index < island_count; ++island_index) {
+ _pre_solve_island(constraint_islands[island_index]);
+ }
+
+ /* SOLVE CONSTRAINT ISLANDS */
+
+ // Warning: _solve_island modifies the constraint islands for optimization purpose,
+ // their content is not reliable after these calls and shouldn't be used anymore.
+ group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &GodotStep2D::_solve_island, nullptr, island_count, -1, true, SNAME("Physics2DConstraintSolveIslands"));
+ WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);
+
+ { //profile
+ profile_endtime = OS::get_singleton()->get_ticks_usec();
+ p_space->set_elapsed_time(GodotSpace2D::ELAPSED_TIME_SOLVE_CONSTRAINTS, profile_endtime - profile_begtime);
+ profile_begtime = profile_endtime;
+ }
+
+ /* INTEGRATE VELOCITIES */
+
+ b = body_list->first();
+ while (b) {
+ const SelfList<GodotBody2D> *n = b->next();
+ b->self()->integrate_velocities(p_delta);
+ b = n; // in case it shuts itself down
+ }
+
+ /* SLEEP / WAKE UP ISLANDS */
+
+ for (uint32_t island_index = 0; island_index < body_island_count; ++island_index) {
+ _check_suspend(body_islands[island_index]);
+ }
+
+ { //profile
+ profile_endtime = OS::get_singleton()->get_ticks_usec();
+ p_space->set_elapsed_time(GodotSpace2D::ELAPSED_TIME_INTEGRATE_VELOCITIES, profile_endtime - profile_begtime);
+ //profile_begtime=profile_endtime;
+ }
+
+ all_constraints.clear();
+
+ p_space->unlock();
+ _step++;
+}
+
+GodotStep2D::GodotStep2D() {
+ body_islands.reserve(BODY_ISLAND_COUNT_RESERVE);
+ constraint_islands.reserve(ISLAND_COUNT_RESERVE);
+ all_constraints.reserve(CONSTRAINT_COUNT_RESERVE);
+}
+
+GodotStep2D::~GodotStep2D() {
+}
diff --git a/servers/physics_2d/area_pair_2d_sw.h b/servers/physics_2d/godot_step_2d.h
index 4015aad5d1..9f8fdd6ce3 100644
--- a/servers/physics_2d/area_pair_2d_sw.h
+++ b/servers/physics_2d/godot_step_2d.h
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* area_pair_2d_sw.h */
+/* godot_step_2d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -28,41 +28,34 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef AREA_PAIR_2D_SW_H
-#define AREA_PAIR_2D_SW_H
+#ifndef GODOT_STEP_2D_H
+#define GODOT_STEP_2D_H
-#include "area_2d_sw.h"
-#include "body_2d_sw.h"
-#include "constraint_2d_sw.h"
+#include "godot_space_2d.h"
-class AreaPair2DSW : public Constraint2DSW {
- Body2DSW *body;
- Area2DSW *area;
- int body_shape;
- int area_shape;
- bool colliding;
+#include "core/object/worker_thread_pool.h"
+#include "core/templates/local_vector.h"
-public:
- bool setup(real_t p_step);
- void solve(real_t p_step);
+class GodotStep2D {
+ uint64_t _step = 1;
- AreaPair2DSW(Body2DSW *p_body, int p_body_shape, Area2DSW *p_area, int p_area_shape);
- ~AreaPair2DSW();
-};
+ int iterations = 0;
+ real_t delta = 0.0;
-class Area2Pair2DSW : public Constraint2DSW {
- Area2DSW *area_a;
- Area2DSW *area_b;
- int shape_a;
- int shape_b;
- bool colliding;
+ LocalVector<LocalVector<GodotBody2D *>> body_islands;
+ LocalVector<LocalVector<GodotConstraint2D *>> constraint_islands;
+ LocalVector<GodotConstraint2D *> all_constraints;
-public:
- bool setup(real_t p_step);
- void solve(real_t p_step);
+ void _populate_island(GodotBody2D *p_body, LocalVector<GodotBody2D *> &p_body_island, LocalVector<GodotConstraint2D *> &p_constraint_island);
+ void _setup_contraint(uint32_t p_constraint_index, void *p_userdata = nullptr);
+ void _pre_solve_island(LocalVector<GodotConstraint2D *> &p_constraint_island) const;
+ void _solve_island(uint32_t p_island_index, void *p_userdata = nullptr) const;
+ void _check_suspend(LocalVector<GodotBody2D *> &p_body_island) const;
- Area2Pair2DSW(Area2DSW *p_area_a, int p_shape_a, Area2DSW *p_area_b, int p_shape_b);
- ~Area2Pair2DSW();
+public:
+ void step(GodotSpace2D *p_space, real_t p_delta);
+ GodotStep2D();
+ ~GodotStep2D();
};
-#endif // AREA_PAIR_2D_SW_H
+#endif // GODOT_STEP_2D_H
diff --git a/servers/physics_2d/physics_server_2d_sw.cpp b/servers/physics_2d/physics_server_2d_sw.cpp
deleted file mode 100644
index 1040437ca7..0000000000
--- a/servers/physics_2d/physics_server_2d_sw.cpp
+++ /dev/null
@@ -1,1368 +0,0 @@
-/*************************************************************************/
-/* physics_server_2d_sw.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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 "physics_server_2d_sw.h"
-
-#include "broad_phase_2d_basic.h"
-#include "broad_phase_2d_hash_grid.h"
-#include "collision_solver_2d_sw.h"
-#include "core/config/project_settings.h"
-#include "core/debugger/engine_debugger.h"
-#include "core/os/os.h"
-
-#define FLUSH_QUERY_CHECK(m_object) \
- ERR_FAIL_COND_MSG(m_object->get_space() && flushing_queries, "Can't change this state while flushing queries. Use call_deferred() or set_deferred() to change monitoring state instead.");
-
-RID PhysicsServer2DSW::_shape_create(ShapeType p_shape) {
- Shape2DSW *shape = nullptr;
- switch (p_shape) {
- case SHAPE_LINE: {
- shape = memnew(LineShape2DSW);
- } break;
- case SHAPE_RAY: {
- shape = memnew(RayShape2DSW);
- } break;
- case SHAPE_SEGMENT: {
- shape = memnew(SegmentShape2DSW);
- } break;
- case SHAPE_CIRCLE: {
- shape = memnew(CircleShape2DSW);
- } break;
- case SHAPE_RECTANGLE: {
- shape = memnew(RectangleShape2DSW);
- } break;
- case SHAPE_CAPSULE: {
- shape = memnew(CapsuleShape2DSW);
- } break;
- case SHAPE_CONVEX_POLYGON: {
- shape = memnew(ConvexPolygonShape2DSW);
- } break;
- case SHAPE_CONCAVE_POLYGON: {
- shape = memnew(ConcavePolygonShape2DSW);
- } break;
- case SHAPE_CUSTOM: {
- ERR_FAIL_V(RID());
-
- } break;
- }
-
- RID id = shape_owner.make_rid(shape);
- shape->set_self(id);
-
- return id;
-}
-
-RID PhysicsServer2DSW::line_shape_create() {
- return _shape_create(SHAPE_LINE);
-}
-
-RID PhysicsServer2DSW::ray_shape_create() {
- return _shape_create(SHAPE_RAY);
-}
-
-RID PhysicsServer2DSW::segment_shape_create() {
- return _shape_create(SHAPE_SEGMENT);
-}
-
-RID PhysicsServer2DSW::circle_shape_create() {
- return _shape_create(SHAPE_CIRCLE);
-}
-
-RID PhysicsServer2DSW::rectangle_shape_create() {
- return _shape_create(SHAPE_RECTANGLE);
-}
-
-RID PhysicsServer2DSW::capsule_shape_create() {
- return _shape_create(SHAPE_CAPSULE);
-}
-
-RID PhysicsServer2DSW::convex_polygon_shape_create() {
- return _shape_create(SHAPE_CONVEX_POLYGON);
-}
-
-RID PhysicsServer2DSW::concave_polygon_shape_create() {
- return _shape_create(SHAPE_CONCAVE_POLYGON);
-}
-
-void PhysicsServer2DSW::shape_set_data(RID p_shape, const Variant &p_data) {
- Shape2DSW *shape = shape_owner.getornull(p_shape);
- ERR_FAIL_COND(!shape);
- shape->set_data(p_data);
-};
-
-void PhysicsServer2DSW::shape_set_custom_solver_bias(RID p_shape, real_t p_bias) {
- Shape2DSW *shape = shape_owner.getornull(p_shape);
- ERR_FAIL_COND(!shape);
- shape->set_custom_bias(p_bias);
-}
-
-PhysicsServer2D::ShapeType PhysicsServer2DSW::shape_get_type(RID p_shape) const {
- const Shape2DSW *shape = shape_owner.getornull(p_shape);
- ERR_FAIL_COND_V(!shape, SHAPE_CUSTOM);
- return shape->get_type();
-};
-
-Variant PhysicsServer2DSW::shape_get_data(RID p_shape) const {
- const Shape2DSW *shape = shape_owner.getornull(p_shape);
- ERR_FAIL_COND_V(!shape, Variant());
- ERR_FAIL_COND_V(!shape->is_configured(), Variant());
- return shape->get_data();
-};
-
-real_t PhysicsServer2DSW::shape_get_custom_solver_bias(RID p_shape) const {
- const Shape2DSW *shape = shape_owner.getornull(p_shape);
- ERR_FAIL_COND_V(!shape, 0);
- return shape->get_custom_bias();
-}
-
-void PhysicsServer2DSW::_shape_col_cbk(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_userdata) {
- CollCbkData *cbk = (CollCbkData *)p_userdata;
-
- if (cbk->max == 0) {
- return;
- }
-
- Vector2 rel_dir = (p_point_A - p_point_B);
- real_t rel_length2 = rel_dir.length_squared();
- if (cbk->valid_dir != Vector2()) {
- if (cbk->valid_depth < 10e20) {
- if (rel_length2 > cbk->valid_depth * cbk->valid_depth ||
- (rel_length2 > CMP_EPSILON && cbk->valid_dir.dot(rel_dir.normalized()) < CMP_EPSILON)) {
- cbk->invalid_by_dir++;
- return;
- }
- } else {
- if (rel_length2 > 0 && cbk->valid_dir.dot(rel_dir.normalized()) < CMP_EPSILON) {
- return;
- }
- }
- }
-
- if (cbk->amount == cbk->max) {
- //find least deep
- real_t min_depth = 1e20;
- int min_depth_idx = 0;
- for (int i = 0; i < cbk->amount; i++) {
- real_t d = cbk->ptr[i * 2 + 0].distance_squared_to(cbk->ptr[i * 2 + 1]);
- if (d < min_depth) {
- min_depth = d;
- min_depth_idx = i;
- }
- }
-
- if (rel_length2 < min_depth) {
- return;
- }
- cbk->ptr[min_depth_idx * 2 + 0] = p_point_A;
- cbk->ptr[min_depth_idx * 2 + 1] = p_point_B;
- cbk->passed++;
-
- } else {
- cbk->ptr[cbk->amount * 2 + 0] = p_point_A;
- cbk->ptr[cbk->amount * 2 + 1] = p_point_B;
- cbk->amount++;
- cbk->passed++;
- }
-}
-
-bool PhysicsServer2DSW::shape_collide(RID p_shape_A, const Transform2D &p_xform_A, const Vector2 &p_motion_A, RID p_shape_B, const Transform2D &p_xform_B, const Vector2 &p_motion_B, Vector2 *r_results, int p_result_max, int &r_result_count) {
- Shape2DSW *shape_A = shape_owner.getornull(p_shape_A);
- ERR_FAIL_COND_V(!shape_A, false);
- Shape2DSW *shape_B = shape_owner.getornull(p_shape_B);
- ERR_FAIL_COND_V(!shape_B, false);
-
- if (p_result_max == 0) {
- return CollisionSolver2DSW::solve(shape_A, p_xform_A, p_motion_A, shape_B, p_xform_B, p_motion_B, nullptr, nullptr);
- }
-
- CollCbkData cbk;
- cbk.max = p_result_max;
- cbk.amount = 0;
- cbk.passed = 0;
- cbk.ptr = r_results;
-
- bool res = CollisionSolver2DSW::solve(shape_A, p_xform_A, p_motion_A, shape_B, p_xform_B, p_motion_B, _shape_col_cbk, &cbk);
- r_result_count = cbk.amount;
- return res;
-}
-
-RID PhysicsServer2DSW::space_create() {
- Space2DSW *space = memnew(Space2DSW);
- RID id = space_owner.make_rid(space);
- space->set_self(id);
- RID area_id = area_create();
- Area2DSW *area = area_owner.getornull(area_id);
- ERR_FAIL_COND_V(!area, RID());
- space->set_default_area(area);
- area->set_space(space);
- area->set_priority(-1);
-
- return id;
-};
-
-void PhysicsServer2DSW::space_set_active(RID p_space, bool p_active) {
- Space2DSW *space = space_owner.getornull(p_space);
- ERR_FAIL_COND(!space);
- if (p_active) {
- active_spaces.insert(space);
- } else {
- active_spaces.erase(space);
- }
-}
-
-bool PhysicsServer2DSW::space_is_active(RID p_space) const {
- const Space2DSW *space = space_owner.getornull(p_space);
- ERR_FAIL_COND_V(!space, false);
-
- return active_spaces.has(space);
-}
-
-void PhysicsServer2DSW::space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) {
- Space2DSW *space = space_owner.getornull(p_space);
- ERR_FAIL_COND(!space);
-
- space->set_param(p_param, p_value);
-}
-
-real_t PhysicsServer2DSW::space_get_param(RID p_space, SpaceParameter p_param) const {
- const Space2DSW *space = space_owner.getornull(p_space);
- ERR_FAIL_COND_V(!space, 0);
- return space->get_param(p_param);
-}
-
-void PhysicsServer2DSW::space_set_debug_contacts(RID p_space, int p_max_contacts) {
- Space2DSW *space = space_owner.getornull(p_space);
- ERR_FAIL_COND(!space);
- space->set_debug_contacts(p_max_contacts);
-}
-
-Vector<Vector2> PhysicsServer2DSW::space_get_contacts(RID p_space) const {
- Space2DSW *space = space_owner.getornull(p_space);
- ERR_FAIL_COND_V(!space, Vector<Vector2>());
- return space->get_debug_contacts();
-}
-
-int PhysicsServer2DSW::space_get_contact_count(RID p_space) const {
- Space2DSW *space = space_owner.getornull(p_space);
- ERR_FAIL_COND_V(!space, 0);
- return space->get_debug_contact_count();
-}
-
-PhysicsDirectSpaceState2D *PhysicsServer2DSW::space_get_direct_state(RID p_space) {
- Space2DSW *space = space_owner.getornull(p_space);
- ERR_FAIL_COND_V(!space, nullptr);
- ERR_FAIL_COND_V_MSG((using_threads && !doing_sync) || space->is_locked(), nullptr, "Space state is inaccessible right now, wait for iteration or physics process notification.");
-
- return space->get_direct_state();
-}
-
-RID PhysicsServer2DSW::area_create() {
- Area2DSW *area = memnew(Area2DSW);
- RID rid = area_owner.make_rid(area);
- area->set_self(rid);
- return rid;
-};
-
-void PhysicsServer2DSW::area_set_space(RID p_area, RID p_space) {
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- Space2DSW *space = nullptr;
- if (p_space.is_valid()) {
- space = space_owner.getornull(p_space);
- ERR_FAIL_COND(!space);
- }
-
- if (area->get_space() == space) {
- return; //pointless
- }
-
- area->clear_constraints();
- area->set_space(space);
-};
-
-RID PhysicsServer2DSW::area_get_space(RID p_area) const {
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, RID());
-
- Space2DSW *space = area->get_space();
- if (!space) {
- return RID();
- }
- return space->get_self();
-};
-
-void PhysicsServer2DSW::area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) {
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- area->set_space_override_mode(p_mode);
-}
-
-PhysicsServer2D::AreaSpaceOverrideMode PhysicsServer2DSW::area_get_space_override_mode(RID p_area) const {
- const Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, AREA_SPACE_OVERRIDE_DISABLED);
-
- return area->get_space_override_mode();
-}
-
-void PhysicsServer2DSW::area_add_shape(RID p_area, RID p_shape, const Transform2D &p_transform, bool p_disabled) {
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- Shape2DSW *shape = shape_owner.getornull(p_shape);
- ERR_FAIL_COND(!shape);
-
- area->add_shape(shape, p_transform, p_disabled);
-}
-
-void PhysicsServer2DSW::area_set_shape(RID p_area, int p_shape_idx, RID p_shape) {
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- Shape2DSW *shape = shape_owner.getornull(p_shape);
- ERR_FAIL_COND(!shape);
- ERR_FAIL_COND(!shape->is_configured());
-
- area->set_shape(p_shape_idx, shape);
-}
-
-void PhysicsServer2DSW::area_set_shape_transform(RID p_area, int p_shape_idx, const Transform2D &p_transform) {
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- area->set_shape_transform(p_shape_idx, p_transform);
-}
-
-void PhysicsServer2DSW::area_set_shape_disabled(RID p_area, int p_shape, bool p_disabled) {
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
- ERR_FAIL_INDEX(p_shape, area->get_shape_count());
- FLUSH_QUERY_CHECK(area);
-
- area->set_shape_as_disabled(p_shape, p_disabled);
-}
-
-int PhysicsServer2DSW::area_get_shape_count(RID p_area) const {
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, -1);
-
- return area->get_shape_count();
-}
-
-RID PhysicsServer2DSW::area_get_shape(RID p_area, int p_shape_idx) const {
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, RID());
-
- Shape2DSW *shape = area->get_shape(p_shape_idx);
- ERR_FAIL_COND_V(!shape, RID());
-
- return shape->get_self();
-}
-
-Transform2D PhysicsServer2DSW::area_get_shape_transform(RID p_area, int p_shape_idx) const {
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, Transform2D());
-
- return area->get_shape_transform(p_shape_idx);
-}
-
-void PhysicsServer2DSW::area_remove_shape(RID p_area, int p_shape_idx) {
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- area->remove_shape(p_shape_idx);
-}
-
-void PhysicsServer2DSW::area_clear_shapes(RID p_area) {
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- while (area->get_shape_count()) {
- area->remove_shape(0);
- }
-}
-
-void PhysicsServer2DSW::area_attach_object_instance_id(RID p_area, ObjectID p_id) {
- if (space_owner.owns(p_area)) {
- Space2DSW *space = space_owner.getornull(p_area);
- p_area = space->get_default_area()->get_self();
- }
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
- area->set_instance_id(p_id);
-}
-
-ObjectID PhysicsServer2DSW::area_get_object_instance_id(RID p_area) const {
- if (space_owner.owns(p_area)) {
- Space2DSW *space = space_owner.getornull(p_area);
- p_area = space->get_default_area()->get_self();
- }
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, ObjectID());
- return area->get_instance_id();
-}
-
-void PhysicsServer2DSW::area_attach_canvas_instance_id(RID p_area, ObjectID p_id) {
- if (space_owner.owns(p_area)) {
- Space2DSW *space = space_owner.getornull(p_area);
- p_area = space->get_default_area()->get_self();
- }
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
- area->set_canvas_instance_id(p_id);
-}
-
-ObjectID PhysicsServer2DSW::area_get_canvas_instance_id(RID p_area) const {
- if (space_owner.owns(p_area)) {
- Space2DSW *space = space_owner.getornull(p_area);
- p_area = space->get_default_area()->get_self();
- }
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, ObjectID());
- return area->get_canvas_instance_id();
-}
-
-void PhysicsServer2DSW::area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) {
- if (space_owner.owns(p_area)) {
- Space2DSW *space = space_owner.getornull(p_area);
- p_area = space->get_default_area()->get_self();
- }
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
- area->set_param(p_param, p_value);
-};
-
-void PhysicsServer2DSW::area_set_transform(RID p_area, const Transform2D &p_transform) {
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
- area->set_transform(p_transform);
-};
-
-Variant PhysicsServer2DSW::area_get_param(RID p_area, AreaParameter p_param) const {
- if (space_owner.owns(p_area)) {
- Space2DSW *space = space_owner.getornull(p_area);
- p_area = space->get_default_area()->get_self();
- }
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, Variant());
-
- return area->get_param(p_param);
-};
-
-Transform2D PhysicsServer2DSW::area_get_transform(RID p_area) const {
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, Transform2D());
-
- return area->get_transform();
-};
-
-void PhysicsServer2DSW::area_set_pickable(RID p_area, bool p_pickable) {
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
- area->set_pickable(p_pickable);
-}
-
-void PhysicsServer2DSW::area_set_monitorable(RID p_area, bool p_monitorable) {
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
- FLUSH_QUERY_CHECK(area);
-
- area->set_monitorable(p_monitorable);
-}
-
-void PhysicsServer2DSW::area_set_collision_mask(RID p_area, uint32_t p_mask) {
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- area->set_collision_mask(p_mask);
-}
-
-void PhysicsServer2DSW::area_set_collision_layer(RID p_area, uint32_t p_layer) {
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- area->set_collision_layer(p_layer);
-}
-
-void PhysicsServer2DSW::area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) {
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- area->set_monitor_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method);
-}
-
-void PhysicsServer2DSW::area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) {
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- area->set_area_monitor_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method);
-}
-
-/* BODY API */
-
-RID PhysicsServer2DSW::body_create() {
- Body2DSW *body = memnew(Body2DSW);
- RID rid = body_owner.make_rid(body);
- body->set_self(rid);
- return rid;
-}
-
-void PhysicsServer2DSW::body_set_space(RID p_body, RID p_space) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- Space2DSW *space = nullptr;
- if (p_space.is_valid()) {
- space = space_owner.getornull(p_space);
- ERR_FAIL_COND(!space);
- }
-
- if (body->get_space() == space) {
- return; //pointless
- }
-
- body->clear_constraint_list();
- body->set_space(space);
-};
-
-RID PhysicsServer2DSW::body_get_space(RID p_body) const {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, RID());
-
- Space2DSW *space = body->get_space();
- if (!space) {
- return RID();
- }
- return space->get_self();
-};
-
-void PhysicsServer2DSW::body_set_mode(RID p_body, BodyMode p_mode) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- FLUSH_QUERY_CHECK(body);
-
- body->set_mode(p_mode);
-};
-
-PhysicsServer2D::BodyMode PhysicsServer2DSW::body_get_mode(RID p_body) const {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, BODY_MODE_STATIC);
-
- return body->get_mode();
-};
-
-void PhysicsServer2DSW::body_add_shape(RID p_body, RID p_shape, const Transform2D &p_transform, bool p_disabled) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- Shape2DSW *shape = shape_owner.getornull(p_shape);
- ERR_FAIL_COND(!shape);
-
- body->add_shape(shape, p_transform, p_disabled);
-}
-
-void PhysicsServer2DSW::body_set_shape(RID p_body, int p_shape_idx, RID p_shape) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- Shape2DSW *shape = shape_owner.getornull(p_shape);
- ERR_FAIL_COND(!shape);
- ERR_FAIL_COND(!shape->is_configured());
-
- body->set_shape(p_shape_idx, shape);
-}
-
-void PhysicsServer2DSW::body_set_shape_transform(RID p_body, int p_shape_idx, const Transform2D &p_transform) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_shape_transform(p_shape_idx, p_transform);
-}
-
-void PhysicsServer2DSW::body_set_shape_metadata(RID p_body, int p_shape_idx, const Variant &p_metadata) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- body->set_shape_metadata(p_shape_idx, p_metadata);
-}
-
-Variant PhysicsServer2DSW::body_get_shape_metadata(RID p_body, int p_shape_idx) const {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, Variant());
- return body->get_shape_metadata(p_shape_idx);
-}
-
-int PhysicsServer2DSW::body_get_shape_count(RID p_body) const {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, -1);
-
- return body->get_shape_count();
-}
-
-RID PhysicsServer2DSW::body_get_shape(RID p_body, int p_shape_idx) const {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, RID());
-
- Shape2DSW *shape = body->get_shape(p_shape_idx);
- ERR_FAIL_COND_V(!shape, RID());
-
- return shape->get_self();
-}
-
-Transform2D PhysicsServer2DSW::body_get_shape_transform(RID p_body, int p_shape_idx) const {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, Transform2D());
-
- return body->get_shape_transform(p_shape_idx);
-}
-
-void PhysicsServer2DSW::body_remove_shape(RID p_body, int p_shape_idx) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->remove_shape(p_shape_idx);
-}
-
-void PhysicsServer2DSW::body_clear_shapes(RID p_body) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- while (body->get_shape_count()) {
- body->remove_shape(0);
- }
-}
-
-void PhysicsServer2DSW::body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count());
- FLUSH_QUERY_CHECK(body);
-
- body->set_shape_as_disabled(p_shape_idx, p_disabled);
-}
-
-void PhysicsServer2DSW::body_set_shape_as_one_way_collision(RID p_body, int p_shape_idx, bool p_enable, real_t p_margin) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count());
- FLUSH_QUERY_CHECK(body);
-
- body->set_shape_as_one_way_collision(p_shape_idx, p_enable, p_margin);
-}
-
-void PhysicsServer2DSW::body_set_continuous_collision_detection_mode(RID p_body, CCDMode p_mode) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- body->set_continuous_collision_detection_mode(p_mode);
-}
-
-PhysicsServer2DSW::CCDMode PhysicsServer2DSW::body_get_continuous_collision_detection_mode(RID p_body) const {
- const Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, CCD_MODE_DISABLED);
-
- return body->get_continuous_collision_detection_mode();
-}
-
-void PhysicsServer2DSW::body_attach_object_instance_id(RID p_body, ObjectID p_id) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_instance_id(p_id);
-};
-
-ObjectID PhysicsServer2DSW::body_get_object_instance_id(RID p_body) const {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, ObjectID());
-
- return body->get_instance_id();
-};
-
-void PhysicsServer2DSW::body_attach_canvas_instance_id(RID p_body, ObjectID p_id) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_canvas_instance_id(p_id);
-};
-
-ObjectID PhysicsServer2DSW::body_get_canvas_instance_id(RID p_body) const {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, ObjectID());
-
- return body->get_canvas_instance_id();
-};
-
-void PhysicsServer2DSW::body_set_collision_layer(RID p_body, uint32_t p_layer) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- body->set_collision_layer(p_layer);
-};
-
-uint32_t PhysicsServer2DSW::body_get_collision_layer(RID p_body) const {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, 0);
-
- return body->get_collision_layer();
-};
-
-void PhysicsServer2DSW::body_set_collision_mask(RID p_body, uint32_t p_mask) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- body->set_collision_mask(p_mask);
-};
-
-uint32_t PhysicsServer2DSW::body_get_collision_mask(RID p_body) const {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, 0);
-
- return body->get_collision_mask();
-};
-
-void PhysicsServer2DSW::body_set_param(RID p_body, BodyParameter p_param, real_t p_value) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_param(p_param, p_value);
-};
-
-real_t PhysicsServer2DSW::body_get_param(RID p_body, BodyParameter p_param) const {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, 0);
-
- return body->get_param(p_param);
-};
-
-void PhysicsServer2DSW::body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_state(p_state, p_variant);
-};
-
-Variant PhysicsServer2DSW::body_get_state(RID p_body, BodyState p_state) const {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, Variant());
-
- return body->get_state(p_state);
-};
-
-void PhysicsServer2DSW::body_set_applied_force(RID p_body, const Vector2 &p_force) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_applied_force(p_force);
- body->wakeup();
-};
-
-Vector2 PhysicsServer2DSW::body_get_applied_force(RID p_body) const {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, Vector2());
- return body->get_applied_force();
-};
-
-void PhysicsServer2DSW::body_set_applied_torque(RID p_body, real_t p_torque) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_applied_torque(p_torque);
- body->wakeup();
-};
-
-real_t PhysicsServer2DSW::body_get_applied_torque(RID p_body) const {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, 0);
-
- return body->get_applied_torque();
-};
-
-void PhysicsServer2DSW::body_apply_central_impulse(RID p_body, const Vector2 &p_impulse) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->apply_central_impulse(p_impulse);
- body->wakeup();
-}
-
-void PhysicsServer2DSW::body_apply_torque_impulse(RID p_body, real_t p_torque) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- _update_shapes();
-
- body->apply_torque_impulse(p_torque);
- body->wakeup();
-}
-
-void PhysicsServer2DSW::body_apply_impulse(RID p_body, const Vector2 &p_impulse, const Vector2 &p_position) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- _update_shapes();
-
- body->apply_impulse(p_impulse, p_position);
- body->wakeup();
-};
-
-void PhysicsServer2DSW::body_add_central_force(RID p_body, const Vector2 &p_force) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->add_central_force(p_force);
- body->wakeup();
-};
-
-void PhysicsServer2DSW::body_add_force(RID p_body, const Vector2 &p_force, const Vector2 &p_position) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->add_force(p_force, p_position);
- body->wakeup();
-};
-
-void PhysicsServer2DSW::body_add_torque(RID p_body, real_t p_torque) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->add_torque(p_torque);
- body->wakeup();
-};
-
-void PhysicsServer2DSW::body_set_axis_velocity(RID p_body, const Vector2 &p_axis_velocity) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- _update_shapes();
-
- Vector2 v = body->get_linear_velocity();
- Vector2 axis = p_axis_velocity.normalized();
- v -= axis * axis.dot(v);
- v += p_axis_velocity;
- body->set_linear_velocity(v);
- body->wakeup();
-};
-
-void PhysicsServer2DSW::body_add_collision_exception(RID p_body, RID p_body_b) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->add_exception(p_body_b);
- body->wakeup();
-};
-
-void PhysicsServer2DSW::body_remove_collision_exception(RID p_body, RID p_body_b) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->remove_exception(p_body_b);
- body->wakeup();
-};
-
-void PhysicsServer2DSW::body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- for (int i = 0; i < body->get_exceptions().size(); i++) {
- p_exceptions->push_back(body->get_exceptions()[i]);
- }
-};
-
-void PhysicsServer2DSW::body_set_contacts_reported_depth_threshold(RID p_body, real_t p_threshold) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-};
-
-real_t PhysicsServer2DSW::body_get_contacts_reported_depth_threshold(RID p_body) const {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, 0);
- return 0;
-};
-
-void PhysicsServer2DSW::body_set_omit_force_integration(RID p_body, bool p_omit) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_omit_force_integration(p_omit);
-};
-
-bool PhysicsServer2DSW::body_is_omitting_force_integration(RID p_body) const {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, false);
- return body->get_omit_force_integration();
-};
-
-void PhysicsServer2DSW::body_set_max_contacts_reported(RID p_body, int p_contacts) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- body->set_max_contacts_reported(p_contacts);
-}
-
-int PhysicsServer2DSW::body_get_max_contacts_reported(RID p_body) const {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, -1);
- return body->get_max_contacts_reported();
-}
-
-void PhysicsServer2DSW::body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- body->set_force_integration_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method, p_udata);
-}
-
-bool PhysicsServer2DSW::body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, false);
- ERR_FAIL_INDEX_V(p_body_shape, body->get_shape_count(), false);
-
- return shape_collide(body->get_shape(p_body_shape)->get_self(), body->get_transform() * body->get_shape_transform(p_body_shape), Vector2(), p_shape, p_shape_xform, p_motion, r_results, p_result_max, r_result_count);
-}
-
-void PhysicsServer2DSW::body_set_pickable(RID p_body, bool p_pickable) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- body->set_pickable(p_pickable);
-}
-
-bool PhysicsServer2DSW::body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin, MotionResult *r_result, bool p_exclude_raycast_shapes) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, false);
- ERR_FAIL_COND_V(!body->get_space(), false);
- ERR_FAIL_COND_V(body->get_space()->is_locked(), false);
-
- _update_shapes();
-
- return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, p_margin, r_result, p_exclude_raycast_shapes);
-}
-
-int PhysicsServer2DSW::body_test_ray_separation(RID p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, false);
- ERR_FAIL_COND_V(!body->get_space(), false);
- ERR_FAIL_COND_V(body->get_space()->is_locked(), false);
-
- return body->get_space()->test_body_ray_separation(body, p_transform, p_infinite_inertia, r_recover_motion, r_results, p_result_max, p_margin);
-}
-
-PhysicsDirectBodyState2D *PhysicsServer2DSW::body_get_direct_state(RID p_body) {
- ERR_FAIL_COND_V_MSG((using_threads && !doing_sync), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification.");
-
- if (!body_owner.owns(p_body)) {
- return nullptr;
- }
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, nullptr);
- ERR_FAIL_COND_V(!body->get_space(), nullptr);
- ERR_FAIL_COND_V_MSG(body->get_space()->is_locked(), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification.");
-
- direct_state->body = body;
- return direct_state;
-}
-
-/* JOINT API */
-
-RID PhysicsServer2DSW::joint_create() {
- Joint2DSW *joint = memnew(Joint2DSW);
- RID joint_rid = joint_owner.make_rid(joint);
- joint->set_self(joint_rid);
- return joint_rid;
-}
-
-void PhysicsServer2DSW::joint_clear(RID p_joint) {
- Joint2DSW *joint = joint_owner.getornull(p_joint);
- if (joint->get_type() != JOINT_TYPE_MAX) {
- Joint2DSW *empty_joint = memnew(Joint2DSW);
- empty_joint->copy_settings_from(joint);
-
- joint_owner.replace(p_joint, empty_joint);
- memdelete(joint);
- }
-}
-
-void PhysicsServer2DSW::joint_set_param(RID p_joint, JointParam p_param, real_t p_value) {
- Joint2DSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND(!joint);
-
- switch (p_param) {
- case JOINT_PARAM_BIAS:
- joint->set_bias(p_value);
- break;
- case JOINT_PARAM_MAX_BIAS:
- joint->set_max_bias(p_value);
- break;
- case JOINT_PARAM_MAX_FORCE:
- joint->set_max_force(p_value);
- break;
- }
-}
-
-real_t PhysicsServer2DSW::joint_get_param(RID p_joint, JointParam p_param) const {
- const Joint2DSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND_V(!joint, -1);
-
- switch (p_param) {
- case JOINT_PARAM_BIAS:
- return joint->get_bias();
- break;
- case JOINT_PARAM_MAX_BIAS:
- return joint->get_max_bias();
- break;
- case JOINT_PARAM_MAX_FORCE:
- return joint->get_max_force();
- break;
- }
-
- return 0;
-}
-
-void PhysicsServer2DSW::joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable) {
- Joint2DSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND(!joint);
-
- joint->disable_collisions_between_bodies(p_disable);
-
- if (2 == joint->get_body_count()) {
- Body2DSW *body_a = *joint->get_body_ptr();
- Body2DSW *body_b = *(joint->get_body_ptr() + 1);
-
- if (p_disable) {
- body_add_collision_exception(body_a->get_self(), body_b->get_self());
- body_add_collision_exception(body_b->get_self(), body_a->get_self());
- } else {
- body_remove_collision_exception(body_a->get_self(), body_b->get_self());
- body_remove_collision_exception(body_b->get_self(), body_a->get_self());
- }
- }
-}
-
-bool PhysicsServer2DSW::joint_is_disabled_collisions_between_bodies(RID p_joint) const {
- const Joint2DSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND_V(!joint, true);
-
- return joint->is_disabled_collisions_between_bodies();
-}
-
-void PhysicsServer2DSW::joint_make_pin(RID p_joint, const Vector2 &p_pos, RID p_body_a, RID p_body_b) {
- Body2DSW *A = body_owner.getornull(p_body_a);
- ERR_FAIL_COND(!A);
- Body2DSW *B = nullptr;
- if (body_owner.owns(p_body_b)) {
- B = body_owner.getornull(p_body_b);
- ERR_FAIL_COND(!B);
- }
-
- Joint2DSW *prev_joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND(prev_joint == nullptr);
-
- Joint2DSW *joint = memnew(PinJoint2DSW(p_pos, A, B));
-
- joint_owner.replace(p_joint, joint);
- joint->copy_settings_from(prev_joint);
- memdelete(prev_joint);
-}
-
-void PhysicsServer2DSW::joint_make_groove(RID p_joint, const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, RID p_body_a, RID p_body_b) {
- Body2DSW *A = body_owner.getornull(p_body_a);
- ERR_FAIL_COND(!A);
-
- Body2DSW *B = body_owner.getornull(p_body_b);
- ERR_FAIL_COND(!B);
-
- Joint2DSW *prev_joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND(prev_joint == nullptr);
-
- Joint2DSW *joint = memnew(GrooveJoint2DSW(p_a_groove1, p_a_groove2, p_b_anchor, A, B));
-
- joint_owner.replace(p_joint, joint);
- joint->copy_settings_from(prev_joint);
- memdelete(prev_joint);
-}
-
-void PhysicsServer2DSW::joint_make_damped_spring(RID p_joint, const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, RID p_body_a, RID p_body_b) {
- Body2DSW *A = body_owner.getornull(p_body_a);
- ERR_FAIL_COND(!A);
-
- Body2DSW *B = body_owner.getornull(p_body_b);
- ERR_FAIL_COND(!B);
-
- Joint2DSW *prev_joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND(prev_joint == nullptr);
-
- Joint2DSW *joint = memnew(DampedSpringJoint2DSW(p_anchor_a, p_anchor_b, A, B));
-
- joint_owner.replace(p_joint, joint);
- joint->copy_settings_from(prev_joint);
- memdelete(prev_joint);
-}
-
-void PhysicsServer2DSW::pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) {
- Joint2DSW *j = joint_owner.getornull(p_joint);
- ERR_FAIL_COND(!j);
- ERR_FAIL_COND(j->get_type() != JOINT_TYPE_PIN);
-
- PinJoint2DSW *pin_joint = static_cast<PinJoint2DSW *>(j);
- pin_joint->set_param(p_param, p_value);
-}
-
-real_t PhysicsServer2DSW::pin_joint_get_param(RID p_joint, PinJointParam p_param) const {
- Joint2DSW *j = joint_owner.getornull(p_joint);
- ERR_FAIL_COND_V(!j, 0);
- ERR_FAIL_COND_V(j->get_type() != JOINT_TYPE_PIN, 0);
-
- PinJoint2DSW *pin_joint = static_cast<PinJoint2DSW *>(j);
- return pin_joint->get_param(p_param);
-}
-
-void PhysicsServer2DSW::damped_spring_joint_set_param(RID p_joint, DampedSpringParam p_param, real_t p_value) {
- Joint2DSW *j = joint_owner.getornull(p_joint);
- ERR_FAIL_COND(!j);
- ERR_FAIL_COND(j->get_type() != JOINT_TYPE_DAMPED_SPRING);
-
- DampedSpringJoint2DSW *dsj = static_cast<DampedSpringJoint2DSW *>(j);
- dsj->set_param(p_param, p_value);
-}
-
-real_t PhysicsServer2DSW::damped_spring_joint_get_param(RID p_joint, DampedSpringParam p_param) const {
- Joint2DSW *j = joint_owner.getornull(p_joint);
- ERR_FAIL_COND_V(!j, 0);
- ERR_FAIL_COND_V(j->get_type() != JOINT_TYPE_DAMPED_SPRING, 0);
-
- DampedSpringJoint2DSW *dsj = static_cast<DampedSpringJoint2DSW *>(j);
- return dsj->get_param(p_param);
-}
-
-PhysicsServer2D::JointType PhysicsServer2DSW::joint_get_type(RID p_joint) const {
- Joint2DSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND_V(!joint, JOINT_TYPE_PIN);
-
- return joint->get_type();
-}
-
-void PhysicsServer2DSW::free(RID p_rid) {
- _update_shapes(); // just in case
-
- if (shape_owner.owns(p_rid)) {
- Shape2DSW *shape = shape_owner.getornull(p_rid);
-
- while (shape->get_owners().size()) {
- ShapeOwner2DSW *so = shape->get_owners().front()->key();
- so->remove_shape(shape);
- }
-
- shape_owner.free(p_rid);
- memdelete(shape);
- } else if (body_owner.owns(p_rid)) {
- Body2DSW *body = body_owner.getornull(p_rid);
-
- /*
- if (body->get_state_query())
- _clear_query(body->get_state_query());
-
- if (body->get_direct_state_query())
- _clear_query(body->get_direct_state_query());
- */
-
- body_set_space(p_rid, RID());
-
- while (body->get_shape_count()) {
- body->remove_shape(0);
- }
-
- body_owner.free(p_rid);
- memdelete(body);
-
- } else if (area_owner.owns(p_rid)) {
- Area2DSW *area = area_owner.getornull(p_rid);
-
- /*
- if (area->get_monitor_query())
- _clear_query(area->get_monitor_query());
- */
-
- area->set_space(nullptr);
-
- while (area->get_shape_count()) {
- area->remove_shape(0);
- }
-
- area_owner.free(p_rid);
- memdelete(area);
- } else if (space_owner.owns(p_rid)) {
- Space2DSW *space = space_owner.getornull(p_rid);
-
- while (space->get_objects().size()) {
- CollisionObject2DSW *co = (CollisionObject2DSW *)space->get_objects().front()->get();
- co->set_space(nullptr);
- }
-
- active_spaces.erase(space);
- free(space->get_default_area()->get_self());
- space_owner.free(p_rid);
- memdelete(space);
- } else if (joint_owner.owns(p_rid)) {
- Joint2DSW *joint = joint_owner.getornull(p_rid);
-
- joint_owner.free(p_rid);
- memdelete(joint);
-
- } else {
- ERR_FAIL_MSG("Invalid ID.");
- }
-};
-
-void PhysicsServer2DSW::set_active(bool p_active) {
- active = p_active;
-};
-
-void PhysicsServer2DSW::init() {
- doing_sync = false;
- last_step = 0.001;
- iterations = 8; // 8?
- stepper = memnew(Step2DSW);
- direct_state = memnew(PhysicsDirectBodyState2DSW);
-};
-
-void PhysicsServer2DSW::step(real_t p_step) {
- if (!active) {
- return;
- }
-
- _update_shapes();
-
- last_step = p_step;
- PhysicsDirectBodyState2DSW::singleton->step = p_step;
- island_count = 0;
- active_objects = 0;
- collision_pairs = 0;
- for (Set<const Space2DSW *>::Element *E = active_spaces.front(); E; E = E->next()) {
- stepper->step((Space2DSW *)E->get(), p_step, iterations);
- island_count += E->get()->get_island_count();
- active_objects += E->get()->get_active_objects();
- collision_pairs += E->get()->get_collision_pairs();
- }
-};
-
-void PhysicsServer2DSW::sync() {
- doing_sync = true;
-};
-
-void PhysicsServer2DSW::flush_queries() {
- if (!active) {
- return;
- }
-
- flushing_queries = true;
-
- uint64_t time_beg = OS::get_singleton()->get_ticks_usec();
-
- for (Set<const Space2DSW *>::Element *E = active_spaces.front(); E; E = E->next()) {
- Space2DSW *space = (Space2DSW *)E->get();
- space->call_queries();
- }
-
- flushing_queries = false;
-
- if (EngineDebugger::is_profiling("servers")) {
- uint64_t total_time[Space2DSW::ELAPSED_TIME_MAX];
- static const char *time_name[Space2DSW::ELAPSED_TIME_MAX] = {
- "integrate_forces",
- "generate_islands",
- "setup_constraints",
- "solve_constraints",
- "integrate_velocities"
- };
-
- for (int i = 0; i < Space2DSW::ELAPSED_TIME_MAX; i++) {
- total_time[i] = 0;
- }
-
- for (Set<const Space2DSW *>::Element *E = active_spaces.front(); E; E = E->next()) {
- for (int i = 0; i < Space2DSW::ELAPSED_TIME_MAX; i++) {
- total_time[i] += E->get()->get_elapsed_time(Space2DSW::ElapsedTime(i));
- }
- }
-
- Array values;
- values.resize(Space2DSW::ELAPSED_TIME_MAX * 2);
- for (int i = 0; i < Space2DSW::ELAPSED_TIME_MAX; i++) {
- values[i * 2 + 0] = time_name[i];
- values[i * 2 + 1] = USEC_TO_SEC(total_time[i]);
- }
- values.push_back("flush_queries");
- values.push_back(USEC_TO_SEC(OS::get_singleton()->get_ticks_usec() - time_beg));
-
- values.push_front("physics_2d");
- EngineDebugger::profiler_add_frame_data("servers", values);
- }
-}
-
-void PhysicsServer2DSW::end_sync() {
- doing_sync = false;
-}
-
-void PhysicsServer2DSW::finish() {
- memdelete(stepper);
- memdelete(direct_state);
-};
-
-void PhysicsServer2DSW::_update_shapes() {
- while (pending_shape_update_list.first()) {
- pending_shape_update_list.first()->self()->_shape_changed();
- pending_shape_update_list.remove(pending_shape_update_list.first());
- }
-}
-
-int PhysicsServer2DSW::get_process_info(ProcessInfo p_info) {
- switch (p_info) {
- case INFO_ACTIVE_OBJECTS: {
- return active_objects;
- } break;
- case INFO_COLLISION_PAIRS: {
- return collision_pairs;
- } break;
- case INFO_ISLAND_COUNT: {
- return island_count;
- } break;
- }
-
- return 0;
-}
-
-PhysicsServer2DSW *PhysicsServer2DSW::singletonsw = nullptr;
-
-PhysicsServer2DSW::PhysicsServer2DSW(bool p_using_threads) {
- singletonsw = this;
- BroadPhase2DSW::create_func = BroadPhase2DHashGrid::_create;
- //BroadPhase2DSW::create_func=BroadPhase2DBasic::_create;
-
- active = true;
- island_count = 0;
- active_objects = 0;
- collision_pairs = 0;
- using_threads = p_using_threads;
- flushing_queries = false;
-};
diff --git a/servers/physics_2d/physics_server_2d_wrap_mt.cpp b/servers/physics_2d/physics_server_2d_wrap_mt.cpp
deleted file mode 100644
index 790c87cc44..0000000000
--- a/servers/physics_2d/physics_server_2d_wrap_mt.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-/*************************************************************************/
-/* physics_server_2d_wrap_mt.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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 "physics_server_2d_wrap_mt.h"
-
-#include "core/os/os.h"
-
-void PhysicsServer2DWrapMT::thread_exit() {
- exit.set();
-}
-
-void PhysicsServer2DWrapMT::thread_step(real_t p_delta) {
- physics_2d_server->step(p_delta);
- step_sem.post();
-}
-
-void PhysicsServer2DWrapMT::_thread_callback(void *_instance) {
- PhysicsServer2DWrapMT *vsmt = reinterpret_cast<PhysicsServer2DWrapMT *>(_instance);
-
- vsmt->thread_loop();
-}
-
-void PhysicsServer2DWrapMT::thread_loop() {
- server_thread = Thread::get_caller_id();
-
- physics_2d_server->init();
-
- exit.clear();
- step_thread_up.set();
- while (!exit.is_set()) {
- // flush commands one by one, until exit is requested
- command_queue.wait_and_flush_one();
- }
-
- command_queue.flush_all(); // flush all
-
- physics_2d_server->finish();
-}
-
-/* EVENT QUEUING */
-
-void PhysicsServer2DWrapMT::step(real_t p_step) {
- if (create_thread) {
- command_queue.push(this, &PhysicsServer2DWrapMT::thread_step, p_step);
- } else {
- command_queue.flush_all(); //flush all pending from other threads
- physics_2d_server->step(p_step);
- }
-}
-
-void PhysicsServer2DWrapMT::sync() {
- if (create_thread) {
- if (first_frame) {
- first_frame = false;
- } else {
- step_sem.wait(); //must not wait if a step was not issued
- }
- }
- physics_2d_server->sync();
-}
-
-void PhysicsServer2DWrapMT::flush_queries() {
- physics_2d_server->flush_queries();
-}
-
-void PhysicsServer2DWrapMT::end_sync() {
- physics_2d_server->end_sync();
-}
-
-void PhysicsServer2DWrapMT::init() {
- if (create_thread) {
- //OS::get_singleton()->release_rendering_thread();
- thread.start(_thread_callback, this);
- while (!step_thread_up.is_set()) {
- OS::get_singleton()->delay_usec(1000);
- }
- } else {
- physics_2d_server->init();
- }
-}
-
-void PhysicsServer2DWrapMT::finish() {
- if (thread.is_started()) {
- command_queue.push(this, &PhysicsServer2DWrapMT::thread_exit);
- thread.wait_to_finish();
- } else {
- physics_2d_server->finish();
- }
-}
-
-PhysicsServer2DWrapMT::PhysicsServer2DWrapMT(PhysicsServer2D *p_contained, bool p_create_thread) :
- command_queue(p_create_thread) {
- physics_2d_server = p_contained;
- create_thread = p_create_thread;
- step_pending = 0;
-
- pool_max_size = GLOBAL_GET("memory/limits/multithreaded_server/rid_pool_prealloc");
-
- if (!p_create_thread) {
- server_thread = Thread::get_caller_id();
- } else {
- server_thread = 0;
- }
-
- main_thread = Thread::get_caller_id();
- first_frame = true;
-}
-
-PhysicsServer2DWrapMT::~PhysicsServer2DWrapMT() {
- memdelete(physics_2d_server);
- //finish();
-}
diff --git a/servers/physics_2d/physics_server_2d_wrap_mt.h b/servers/physics_2d/physics_server_2d_wrap_mt.h
deleted file mode 100644
index 3577f706de..0000000000
--- a/servers/physics_2d/physics_server_2d_wrap_mt.h
+++ /dev/null
@@ -1,336 +0,0 @@
-/*************************************************************************/
-/* physics_server_2d_wrap_mt.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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 PHYSICS2DSERVERWRAPMT_H
-#define PHYSICS2DSERVERWRAPMT_H
-
-#include "core/config/project_settings.h"
-#include "core/os/thread.h"
-#include "core/templates/command_queue_mt.h"
-#include "core/templates/safe_refcount.h"
-#include "servers/physics_server_2d.h"
-
-#ifdef DEBUG_SYNC
-#define SYNC_DEBUG print_line("sync on: " + String(__FUNCTION__));
-#else
-#define SYNC_DEBUG
-#endif
-
-class PhysicsServer2DWrapMT : public PhysicsServer2D {
- mutable PhysicsServer2D *physics_2d_server;
-
- mutable CommandQueueMT command_queue;
-
- static void _thread_callback(void *_instance);
- void thread_loop();
-
- Thread::ID server_thread;
- Thread::ID main_thread;
- SafeFlag exit;
- Thread thread;
- SafeFlag step_thread_up;
- bool create_thread;
-
- Semaphore step_sem;
- int step_pending;
- void thread_step(real_t p_delta);
- void thread_flush();
-
- void thread_exit();
-
- bool first_frame;
-
- Mutex alloc_mutex;
- int pool_max_size;
-
-public:
-#define ServerName PhysicsServer2D
-#define ServerNameWrapMT PhysicsServer2DWrapMT
-#define server_name physics_2d_server
-#define WRITE_ACTION
-
-#include "servers/server_wrap_mt_common.h"
-
- //FUNC1RID(shape,ShapeType); todo fix
- FUNCRID(line_shape)
- FUNCRID(ray_shape)
- FUNCRID(segment_shape)
- FUNCRID(circle_shape)
- FUNCRID(rectangle_shape)
- FUNCRID(capsule_shape)
- FUNCRID(convex_polygon_shape)
- FUNCRID(concave_polygon_shape)
-
- FUNC2(shape_set_data, RID, const Variant &);
- FUNC2(shape_set_custom_solver_bias, RID, real_t);
-
- FUNC1RC(ShapeType, shape_get_type, RID);
- FUNC1RC(Variant, shape_get_data, RID);
- FUNC1RC(real_t, shape_get_custom_solver_bias, RID);
-
- //these work well, but should be used from the main thread only
- bool shape_collide(RID p_shape_A, const Transform2D &p_xform_A, const Vector2 &p_motion_A, RID p_shape_B, const Transform2D &p_xform_B, const Vector2 &p_motion_B, Vector2 *r_results, int p_result_max, int &r_result_count) override {
- ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false);
- return physics_2d_server->shape_collide(p_shape_A, p_xform_A, p_motion_A, p_shape_B, p_xform_B, p_motion_B, r_results, p_result_max, r_result_count);
- }
-
- /* SPACE API */
-
- FUNCRID(space);
- FUNC2(space_set_active, RID, bool);
- FUNC1RC(bool, space_is_active, RID);
-
- FUNC3(space_set_param, RID, SpaceParameter, real_t);
- FUNC2RC(real_t, space_get_param, RID, SpaceParameter);
-
- // this function only works on physics process, errors and returns null otherwise
- PhysicsDirectSpaceState2D *space_get_direct_state(RID p_space) override {
- ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), nullptr);
- return physics_2d_server->space_get_direct_state(p_space);
- }
-
- FUNC2(space_set_debug_contacts, RID, int);
- virtual Vector<Vector2> space_get_contacts(RID p_space) const override {
- ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), Vector<Vector2>());
- return physics_2d_server->space_get_contacts(p_space);
- }
-
- virtual int space_get_contact_count(RID p_space) const override {
- ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), 0);
- return physics_2d_server->space_get_contact_count(p_space);
- }
-
- /* AREA API */
-
- //FUNC0RID(area);
- FUNCRID(area);
-
- FUNC2(area_set_space, RID, RID);
- FUNC1RC(RID, area_get_space, RID);
-
- FUNC2(area_set_space_override_mode, RID, AreaSpaceOverrideMode);
- FUNC1RC(AreaSpaceOverrideMode, area_get_space_override_mode, RID);
-
- FUNC4(area_add_shape, RID, RID, const Transform2D &, bool);
- FUNC3(area_set_shape, RID, int, RID);
- FUNC3(area_set_shape_transform, RID, int, const Transform2D &);
- FUNC3(area_set_shape_disabled, RID, int, bool);
-
- FUNC1RC(int, area_get_shape_count, RID);
- FUNC2RC(RID, area_get_shape, RID, int);
- FUNC2RC(Transform2D, area_get_shape_transform, RID, int);
- FUNC2(area_remove_shape, RID, int);
- FUNC1(area_clear_shapes, RID);
-
- FUNC2(area_attach_object_instance_id, RID, ObjectID);
- FUNC1RC(ObjectID, area_get_object_instance_id, RID);
-
- FUNC2(area_attach_canvas_instance_id, RID, ObjectID);
- FUNC1RC(ObjectID, area_get_canvas_instance_id, RID);
-
- FUNC3(area_set_param, RID, AreaParameter, const Variant &);
- FUNC2(area_set_transform, RID, const Transform2D &);
-
- FUNC2RC(Variant, area_get_param, RID, AreaParameter);
- FUNC1RC(Transform2D, area_get_transform, RID);
-
- FUNC2(area_set_collision_mask, RID, uint32_t);
- FUNC2(area_set_collision_layer, RID, uint32_t);
-
- FUNC2(area_set_monitorable, RID, bool);
- FUNC2(area_set_pickable, RID, bool);
-
- FUNC3(area_set_monitor_callback, RID, Object *, const StringName &);
- FUNC3(area_set_area_monitor_callback, RID, Object *, const StringName &);
-
- /* BODY API */
-
- //FUNC2RID(body,BodyMode,bool);
- FUNCRID(body)
-
- FUNC2(body_set_space, RID, RID);
- FUNC1RC(RID, body_get_space, RID);
-
- FUNC2(body_set_mode, RID, BodyMode);
- FUNC1RC(BodyMode, body_get_mode, RID);
-
- FUNC4(body_add_shape, RID, RID, const Transform2D &, bool);
- FUNC3(body_set_shape, RID, int, RID);
- FUNC3(body_set_shape_transform, RID, int, const Transform2D &);
- FUNC3(body_set_shape_metadata, RID, int, const Variant &);
-
- FUNC1RC(int, body_get_shape_count, RID);
- FUNC2RC(Transform2D, body_get_shape_transform, RID, int);
- FUNC2RC(Variant, body_get_shape_metadata, RID, int);
- FUNC2RC(RID, body_get_shape, RID, int);
-
- FUNC3(body_set_shape_disabled, RID, int, bool);
- FUNC4(body_set_shape_as_one_way_collision, RID, int, bool, real_t);
-
- FUNC2(body_remove_shape, RID, int);
- FUNC1(body_clear_shapes, RID);
-
- FUNC2(body_attach_object_instance_id, RID, ObjectID);
- FUNC1RC(ObjectID, body_get_object_instance_id, RID);
-
- FUNC2(body_attach_canvas_instance_id, RID, ObjectID);
- FUNC1RC(ObjectID, body_get_canvas_instance_id, RID);
-
- FUNC2(body_set_continuous_collision_detection_mode, RID, CCDMode);
- FUNC1RC(CCDMode, body_get_continuous_collision_detection_mode, RID);
-
- FUNC2(body_set_collision_layer, RID, uint32_t);
- FUNC1RC(uint32_t, body_get_collision_layer, RID);
-
- FUNC2(body_set_collision_mask, RID, uint32_t);
- FUNC1RC(uint32_t, body_get_collision_mask, RID);
-
- FUNC3(body_set_param, RID, BodyParameter, real_t);
- FUNC2RC(real_t, body_get_param, RID, BodyParameter);
-
- FUNC3(body_set_state, RID, BodyState, const Variant &);
- FUNC2RC(Variant, body_get_state, RID, BodyState);
-
- FUNC2(body_set_applied_force, RID, const Vector2 &);
- FUNC1RC(Vector2, body_get_applied_force, RID);
-
- FUNC2(body_set_applied_torque, RID, real_t);
- FUNC1RC(real_t, body_get_applied_torque, RID);
-
- FUNC2(body_add_central_force, RID, const Vector2 &);
- FUNC3(body_add_force, RID, const Vector2 &, const Vector2 &);
- FUNC2(body_add_torque, RID, real_t);
- FUNC2(body_apply_central_impulse, RID, const Vector2 &);
- FUNC2(body_apply_torque_impulse, RID, real_t);
- FUNC3(body_apply_impulse, RID, const Vector2 &, const Vector2 &);
- FUNC2(body_set_axis_velocity, RID, const Vector2 &);
-
- FUNC2(body_add_collision_exception, RID, RID);
- FUNC2(body_remove_collision_exception, RID, RID);
- FUNC2S(body_get_collision_exceptions, RID, List<RID> *);
-
- FUNC2(body_set_max_contacts_reported, RID, int);
- FUNC1RC(int, body_get_max_contacts_reported, RID);
-
- FUNC2(body_set_contacts_reported_depth_threshold, RID, real_t);
- FUNC1RC(real_t, body_get_contacts_reported_depth_threshold, RID);
-
- FUNC2(body_set_omit_force_integration, RID, bool);
- FUNC1RC(bool, body_is_omitting_force_integration, RID);
-
- FUNC4(body_set_force_integration_callback, RID, Object *, const StringName &, const Variant &);
-
- bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) override {
- return physics_2d_server->body_collide_shape(p_body, p_body_shape, p_shape, p_shape_xform, p_motion, r_results, p_result_max, r_result_count);
- }
-
- FUNC2(body_set_pickable, RID, bool);
-
- bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override {
- ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false);
- return physics_2d_server->body_test_motion(p_body, p_from, p_motion, p_infinite_inertia, p_margin, r_result, p_exclude_raycast_shapes);
- }
-
- int body_test_ray_separation(RID p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override {
- ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false);
- return physics_2d_server->body_test_ray_separation(p_body, p_transform, p_infinite_inertia, r_recover_motion, r_results, p_result_max, p_margin);
- }
-
- // this function only works on physics process, errors and returns null otherwise
- PhysicsDirectBodyState2D *body_get_direct_state(RID p_body) override {
- ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), nullptr);
- return physics_2d_server->body_get_direct_state(p_body);
- }
-
- /* JOINT API */
-
- FUNCRID(joint)
-
- FUNC1(joint_clear, RID)
-
- FUNC3(joint_set_param, RID, JointParam, real_t);
- FUNC2RC(real_t, joint_get_param, RID, JointParam);
-
- FUNC2(joint_disable_collisions_between_bodies, RID, const bool);
- FUNC1RC(bool, joint_is_disabled_collisions_between_bodies, RID);
-
- ///FUNC3RID(pin_joint,const Vector2&,RID,RID);
- ///FUNC5RID(groove_joint,const Vector2&,const Vector2&,const Vector2&,RID,RID);
- ///FUNC4RID(damped_spring_joint,const Vector2&,const Vector2&,RID,RID);
-
- //TODO need to convert this to FUNCRID, but it's a hassle..
-
- FUNC4(joint_make_pin, RID, const Vector2 &, RID, RID);
- FUNC6(joint_make_groove, RID, const Vector2 &, const Vector2 &, const Vector2 &, RID, RID);
- FUNC5(joint_make_damped_spring, RID, const Vector2 &, const Vector2 &, RID, RID);
-
- FUNC3(pin_joint_set_param, RID, PinJointParam, real_t);
- FUNC2RC(real_t, pin_joint_get_param, RID, PinJointParam);
-
- FUNC3(damped_spring_joint_set_param, RID, DampedSpringParam, real_t);
- FUNC2RC(real_t, damped_spring_joint_get_param, RID, DampedSpringParam);
-
- FUNC1RC(JointType, joint_get_type, RID);
-
- /* MISC */
-
- FUNC1(free, RID);
- FUNC1(set_active, bool);
-
- virtual void init() override;
- virtual void step(real_t p_step) override;
- virtual void sync() override;
- virtual void end_sync() override;
- virtual void flush_queries() override;
- virtual void finish() override;
-
- virtual bool is_flushing_queries() const override {
- return physics_2d_server->is_flushing_queries();
- }
-
- int get_process_info(ProcessInfo p_info) override {
- return physics_2d_server->get_process_info(p_info);
- }
-
- PhysicsServer2DWrapMT(PhysicsServer2D *p_contained, bool p_create_thread);
- ~PhysicsServer2DWrapMT();
-
-#undef ServerNameWrapMT
-#undef ServerName
-#undef server_name
-#undef WRITE_ACTION
-};
-
-#ifdef DEBUG_SYNC
-#undef DEBUG_SYNC
-#endif
-#undef SYNC_DEBUG
-
-#endif // PHYSICS2DSERVERWRAPMT_H
diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp
deleted file mode 100644
index 4f12248c3e..0000000000
--- a/servers/physics_2d/space_2d_sw.cpp
+++ /dev/null
@@ -1,1411 +0,0 @@
-/*************************************************************************/
-/* space_2d_sw.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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 "space_2d_sw.h"
-
-#include "collision_solver_2d_sw.h"
-#include "core/os/os.h"
-#include "core/templates/pair.h"
-#include "physics_server_2d_sw.h"
-_FORCE_INLINE_ static bool _can_collide_with(CollisionObject2DSW *p_object, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
- if (!(p_object->get_collision_layer() & p_collision_mask)) {
- return false;
- }
-
- if (p_object->get_type() == CollisionObject2DSW::TYPE_AREA && !p_collide_with_areas) {
- return false;
- }
-
- if (p_object->get_type() == CollisionObject2DSW::TYPE_BODY && !p_collide_with_bodies) {
- return false;
- }
-
- return true;
-}
-
-int PhysicsDirectSpaceState2DSW::_intersect_point_impl(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_point, bool p_filter_by_canvas, ObjectID p_canvas_instance_id) {
- if (p_result_max <= 0) {
- return 0;
- }
-
- Rect2 aabb;
- aabb.position = p_point - Vector2(0.00001, 0.00001);
- aabb.size = Vector2(0.00002, 0.00002);
-
- int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, Space2DSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
-
- int cc = 0;
-
- for (int i = 0; i < amount; i++) {
- if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas)) {
- continue;
- }
-
- if (p_exclude.has(space->intersection_query_results[i]->get_self())) {
- continue;
- }
-
- const CollisionObject2DSW *col_obj = space->intersection_query_results[i];
-
- if (p_pick_point && !col_obj->is_pickable()) {
- continue;
- }
-
- if (p_filter_by_canvas && col_obj->get_canvas_instance_id() != p_canvas_instance_id) {
- continue;
- }
-
- int shape_idx = space->intersection_query_subindex_results[i];
-
- if (col_obj->is_shape_set_as_disabled(shape_idx)) {
- continue;
- }
-
- Shape2DSW *shape = col_obj->get_shape(shape_idx);
-
- Vector2 local_point = (col_obj->get_transform() * col_obj->get_shape_transform(shape_idx)).affine_inverse().xform(p_point);
-
- if (!shape->contains_point(local_point)) {
- continue;
- }
-
- if (cc >= p_result_max) {
- continue;
- }
-
- r_results[cc].collider_id = col_obj->get_instance_id();
- if (r_results[cc].collider_id.is_valid()) {
- r_results[cc].collider = ObjectDB::get_instance(r_results[cc].collider_id);
- }
- r_results[cc].rid = col_obj->get_self();
- r_results[cc].shape = shape_idx;
- r_results[cc].metadata = col_obj->get_shape_metadata(shape_idx);
-
- cc++;
- }
-
- return cc;
-}
-
-int PhysicsDirectSpaceState2DSW::intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_point) {
- return _intersect_point_impl(p_point, r_results, p_result_max, p_exclude, p_collision_mask, p_collide_with_bodies, p_collide_with_areas, p_pick_point);
-}
-
-int PhysicsDirectSpaceState2DSW::intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_instance_id, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_point) {
- return _intersect_point_impl(p_point, r_results, p_result_max, p_exclude, p_collision_mask, p_collide_with_bodies, p_collide_with_areas, p_pick_point, true, p_canvas_instance_id);
-}
-
-bool PhysicsDirectSpaceState2DSW::intersect_ray(const Vector2 &p_from, const Vector2 &p_to, RayResult &r_result, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
- ERR_FAIL_COND_V(space->locked, false);
-
- Vector2 begin, end;
- Vector2 normal;
- begin = p_from;
- end = p_to;
- normal = (end - begin).normalized();
-
- int amount = space->broadphase->cull_segment(begin, end, space->intersection_query_results, Space2DSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
-
- //todo, create another array that references results, compute AABBs and check closest point to ray origin, sort, and stop evaluating results when beyond first collision
-
- bool collided = false;
- Vector2 res_point, res_normal;
- int res_shape;
- const CollisionObject2DSW *res_obj;
- real_t min_d = 1e10;
-
- for (int i = 0; i < amount; i++) {
- if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas)) {
- continue;
- }
-
- if (p_exclude.has(space->intersection_query_results[i]->get_self())) {
- continue;
- }
-
- const CollisionObject2DSW *col_obj = space->intersection_query_results[i];
-
- int shape_idx = space->intersection_query_subindex_results[i];
- Transform2D inv_xform = col_obj->get_shape_inv_transform(shape_idx) * col_obj->get_inv_transform();
-
- Vector2 local_from = inv_xform.xform(begin);
- Vector2 local_to = inv_xform.xform(end);
-
- /*local_from = col_obj->get_inv_transform().xform(begin);
- local_from = col_obj->get_shape_inv_transform(shape_idx).xform(local_from);
-
- local_to = col_obj->get_inv_transform().xform(end);
- local_to = col_obj->get_shape_inv_transform(shape_idx).xform(local_to);*/
-
- const Shape2DSW *shape = col_obj->get_shape(shape_idx);
-
- Vector2 shape_point, shape_normal;
-
- if (shape->intersect_segment(local_from, local_to, shape_point, shape_normal)) {
- Transform2D xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
- shape_point = xform.xform(shape_point);
-
- real_t ld = normal.dot(shape_point);
-
- if (ld < min_d) {
- min_d = ld;
- res_point = shape_point;
- res_normal = inv_xform.basis_xform_inv(shape_normal).normalized();
- res_shape = shape_idx;
- res_obj = col_obj;
- collided = true;
- }
- }
- }
-
- if (!collided) {
- return false;
- }
-
- r_result.collider_id = res_obj->get_instance_id();
- if (r_result.collider_id.is_valid()) {
- r_result.collider = ObjectDB::get_instance(r_result.collider_id);
- }
- r_result.normal = res_normal;
- r_result.metadata = res_obj->get_shape_metadata(res_shape);
- r_result.position = res_point;
- r_result.rid = res_obj->get_self();
- r_result.shape = res_shape;
-
- return true;
-}
-
-int PhysicsDirectSpaceState2DSW::intersect_shape(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
- if (p_result_max <= 0) {
- return 0;
- }
-
- Shape2DSW *shape = PhysicsServer2DSW::singletonsw->shape_owner.getornull(p_shape);
- ERR_FAIL_COND_V(!shape, 0);
-
- Rect2 aabb = p_xform.xform(shape->get_aabb());
- aabb = aabb.grow(p_margin);
-
- int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, Space2DSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
-
- int cc = 0;
-
- for (int i = 0; i < amount; i++) {
- if (cc >= p_result_max) {
- break;
- }
-
- if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas)) {
- continue;
- }
-
- if (p_exclude.has(space->intersection_query_results[i]->get_self())) {
- continue;
- }
-
- const CollisionObject2DSW *col_obj = space->intersection_query_results[i];
- int shape_idx = space->intersection_query_subindex_results[i];
-
- if (col_obj->is_shape_set_as_disabled(shape_idx)) {
- continue;
- }
-
- if (!CollisionSolver2DSW::solve(shape, p_xform, p_motion, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), nullptr, nullptr, nullptr, p_margin)) {
- continue;
- }
-
- r_results[cc].collider_id = col_obj->get_instance_id();
- if (r_results[cc].collider_id.is_valid()) {
- r_results[cc].collider = ObjectDB::get_instance(r_results[cc].collider_id);
- }
- r_results[cc].rid = col_obj->get_self();
- r_results[cc].shape = shape_idx;
- r_results[cc].metadata = col_obj->get_shape_metadata(shape_idx);
-
- cc++;
- }
-
- return cc;
-}
-
-bool PhysicsDirectSpaceState2DSW::cast_motion(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
- Shape2DSW *shape = PhysicsServer2DSW::singletonsw->shape_owner.getornull(p_shape);
- ERR_FAIL_COND_V(!shape, false);
-
- Rect2 aabb = p_xform.xform(shape->get_aabb());
- aabb = aabb.merge(Rect2(aabb.position + p_motion, aabb.size)); //motion
- aabb = aabb.grow(p_margin);
-
- int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, Space2DSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
-
- real_t best_safe = 1;
- real_t best_unsafe = 1;
-
- for (int i = 0; i < amount; i++) {
- if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas)) {
- continue;
- }
-
- if (p_exclude.has(space->intersection_query_results[i]->get_self())) {
- continue; //ignore excluded
- }
-
- const CollisionObject2DSW *col_obj = space->intersection_query_results[i];
- int shape_idx = space->intersection_query_subindex_results[i];
-
- if (col_obj->is_shape_set_as_disabled(shape_idx)) {
- continue;
- }
-
- Transform2D col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
- //test initial overlap, does it collide if going all the way?
- if (!CollisionSolver2DSW::solve(shape, p_xform, p_motion, col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), nullptr, nullptr, nullptr, p_margin)) {
- continue;
- }
-
- //test initial overlap, ignore objects it's inside of.
- if (CollisionSolver2DSW::solve(shape, p_xform, Vector2(), col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), nullptr, nullptr, nullptr, p_margin)) {
- continue;
- }
-
- //just do kinematic solving
- real_t low = 0;
- real_t hi = 1;
- Vector2 mnormal = p_motion.normalized();
-
- for (int j = 0; j < 8; j++) { //steps should be customizable..
-
- real_t ofs = (low + hi) * 0.5;
-
- Vector2 sep = mnormal; //important optimization for this to work fast enough
- bool collided = CollisionSolver2DSW::solve(shape, p_xform, p_motion * ofs, col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), nullptr, nullptr, &sep, p_margin);
-
- if (collided) {
- hi = ofs;
- } else {
- low = ofs;
- }
- }
-
- if (low < best_safe) {
- best_safe = low;
- best_unsafe = hi;
- }
- }
-
- p_closest_safe = best_safe;
- p_closest_unsafe = best_unsafe;
-
- return true;
-}
-
-bool PhysicsDirectSpaceState2DSW::collide_shape(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, Vector2 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
- if (p_result_max <= 0) {
- return false;
- }
-
- Shape2DSW *shape = PhysicsServer2DSW::singletonsw->shape_owner.getornull(p_shape);
- ERR_FAIL_COND_V(!shape, 0);
-
- Rect2 aabb = p_shape_xform.xform(shape->get_aabb());
- aabb = aabb.merge(Rect2(aabb.position + p_motion, aabb.size)); //motion
- aabb = aabb.grow(p_margin);
-
- int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, Space2DSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
-
- bool collided = false;
- r_result_count = 0;
-
- PhysicsServer2DSW::CollCbkData cbk;
- cbk.max = p_result_max;
- cbk.amount = 0;
- cbk.passed = 0;
- cbk.ptr = r_results;
- CollisionSolver2DSW::CallbackResult cbkres = PhysicsServer2DSW::_shape_col_cbk;
-
- PhysicsServer2DSW::CollCbkData *cbkptr = &cbk;
-
- for (int i = 0; i < amount; i++) {
- if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas)) {
- continue;
- }
-
- const CollisionObject2DSW *col_obj = space->intersection_query_results[i];
-
- if (p_exclude.has(col_obj->get_self())) {
- continue;
- }
-
- int shape_idx = space->intersection_query_subindex_results[i];
-
- if (col_obj->is_shape_set_as_disabled(shape_idx)) {
- continue;
- }
-
- cbk.valid_dir = Vector2();
- cbk.valid_depth = 0;
-
- if (CollisionSolver2DSW::solve(shape, p_shape_xform, p_motion, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), cbkres, cbkptr, nullptr, p_margin)) {
- collided = cbk.amount > 0;
- }
- }
-
- r_result_count = cbk.amount;
-
- return collided;
-}
-
-struct _RestCallbackData2D {
- const CollisionObject2DSW *object;
- const CollisionObject2DSW *best_object;
- int local_shape;
- int best_local_shape;
- int shape;
- int best_shape;
- Vector2 best_contact;
- Vector2 best_normal;
- real_t best_len;
- Vector2 valid_dir;
- real_t valid_depth;
- real_t min_allowed_depth;
-};
-
-static void _rest_cbk_result(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_userdata) {
- _RestCallbackData2D *rd = (_RestCallbackData2D *)p_userdata;
-
- Vector2 contact_rel = p_point_B - p_point_A;
- real_t len = contact_rel.length();
-
- if (len < rd->min_allowed_depth) {
- return;
- }
-
- if (len <= rd->best_len) {
- return;
- }
-
- Vector2 normal = contact_rel / len;
-
- if (rd->valid_dir != Vector2()) {
- if (len > rd->valid_depth) {
- return;
- }
-
- if (rd->valid_dir.dot(normal) > -CMP_EPSILON) {
- return;
- }
- }
-
- rd->best_len = len;
- rd->best_contact = p_point_B;
- rd->best_normal = normal;
- rd->best_object = rd->object;
- rd->best_shape = rd->shape;
- rd->best_local_shape = rd->local_shape;
-}
-
-bool PhysicsDirectSpaceState2DSW::rest_info(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
- Shape2DSW *shape = PhysicsServer2DSW::singletonsw->shape_owner.getornull(p_shape);
- ERR_FAIL_COND_V(!shape, 0);
-
- Rect2 aabb = p_shape_xform.xform(shape->get_aabb());
- aabb = aabb.merge(Rect2(aabb.position + p_motion, aabb.size)); //motion
- aabb = aabb.grow(p_margin);
-
- int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, Space2DSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
-
- _RestCallbackData2D rcd;
- rcd.best_len = 0;
- rcd.best_object = nullptr;
- rcd.best_shape = 0;
- rcd.min_allowed_depth = space->test_motion_min_contact_depth;
-
- for (int i = 0; i < amount; i++) {
- if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas)) {
- continue;
- }
-
- const CollisionObject2DSW *col_obj = space->intersection_query_results[i];
-
- if (p_exclude.has(col_obj->get_self())) {
- continue;
- }
-
- int shape_idx = space->intersection_query_subindex_results[i];
-
- if (col_obj->is_shape_set_as_disabled(shape_idx)) {
- continue;
- }
-
- rcd.valid_dir = Vector2();
- rcd.object = col_obj;
- rcd.shape = shape_idx;
- rcd.local_shape = 0;
- bool sc = CollisionSolver2DSW::solve(shape, p_shape_xform, p_motion, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), _rest_cbk_result, &rcd, nullptr, p_margin);
- if (!sc) {
- continue;
- }
- }
-
- if (rcd.best_len == 0 || !rcd.best_object) {
- return false;
- }
-
- r_info->collider_id = rcd.best_object->get_instance_id();
- r_info->shape = rcd.best_shape;
- r_info->normal = rcd.best_normal;
- r_info->point = rcd.best_contact;
- r_info->rid = rcd.best_object->get_self();
- r_info->metadata = rcd.best_object->get_shape_metadata(rcd.best_shape);
- if (rcd.best_object->get_type() == CollisionObject2DSW::TYPE_BODY) {
- const Body2DSW *body = static_cast<const Body2DSW *>(rcd.best_object);
- Vector2 rel_vec = r_info->point - body->get_transform().get_origin();
- r_info->linear_velocity = Vector2(-body->get_angular_velocity() * rel_vec.y, body->get_angular_velocity() * rel_vec.x) + body->get_linear_velocity();
-
- } else {
- r_info->linear_velocity = Vector2();
- }
-
- return true;
-}
-
-PhysicsDirectSpaceState2DSW::PhysicsDirectSpaceState2DSW() {
- space = nullptr;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-int Space2DSW::_cull_aabb_for_body(Body2DSW *p_body, const Rect2 &p_aabb) {
- int amount = broadphase->cull_aabb(p_aabb, intersection_query_results, INTERSECTION_QUERY_MAX, intersection_query_subindex_results);
-
- for (int i = 0; i < amount; i++) {
- bool keep = true;
-
- if (intersection_query_results[i] == p_body) {
- keep = false;
- } else if (intersection_query_results[i]->get_type() == CollisionObject2DSW::TYPE_AREA) {
- keep = false;
- } else if ((static_cast<Body2DSW *>(intersection_query_results[i])->test_collision_mask(p_body)) == 0) {
- keep = false;
- } else if (static_cast<Body2DSW *>(intersection_query_results[i])->has_exception(p_body->get_self()) || p_body->has_exception(intersection_query_results[i]->get_self())) {
- keep = false;
- } else if (static_cast<Body2DSW *>(intersection_query_results[i])->is_shape_set_as_disabled(intersection_query_subindex_results[i])) {
- keep = false;
- }
-
- if (!keep) {
- if (i < amount - 1) {
- SWAP(intersection_query_results[i], intersection_query_results[amount - 1]);
- SWAP(intersection_query_subindex_results[i], intersection_query_subindex_results[amount - 1]);
- }
-
- amount--;
- i--;
- }
- }
-
- return amount;
-}
-
-int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, PhysicsServer2D::SeparationResult *r_results, int p_result_max, real_t p_margin) {
- Rect2 body_aabb;
-
- bool shapes_found = false;
-
- for (int i = 0; i < p_body->get_shape_count(); i++) {
- if (p_body->is_shape_set_as_disabled(i)) {
- continue;
- }
-
- if (p_body->get_shape(i)->get_type() != PhysicsServer2D::SHAPE_RAY) {
- continue;
- }
-
- if (!shapes_found) {
- body_aabb = p_body->get_shape_aabb(i);
- shapes_found = true;
- } else {
- body_aabb = body_aabb.merge(p_body->get_shape_aabb(i));
- }
- }
-
- if (!shapes_found) {
- return 0;
- }
-
- // Undo the currently transform the physics server is aware of and apply the provided one
- body_aabb = p_transform.xform(p_body->get_inv_transform().xform(body_aabb));
- body_aabb = body_aabb.grow(p_margin);
-
- Transform2D body_transform = p_transform;
-
- for (int i = 0; i < p_result_max; i++) {
- //reset results
- r_results[i].collision_depth = 0;
- }
-
- int rays_found = 0;
-
- {
- // raycast AND separate
-
- const int max_results = 32;
- int recover_attempts = 4;
- Vector2 sr[max_results * 2];
- PhysicsServer2DSW::CollCbkData cbk;
- cbk.max = max_results;
- PhysicsServer2DSW::CollCbkData *cbkptr = &cbk;
- CollisionSolver2DSW::CallbackResult cbkres = PhysicsServer2DSW::_shape_col_cbk;
-
- do {
- Vector2 recover_motion;
-
- bool collided = false;
-
- int amount = _cull_aabb_for_body(p_body, body_aabb);
-
- for (int j = 0; j < p_body->get_shape_count(); j++) {
- if (p_body->is_shape_set_as_disabled(j)) {
- continue;
- }
-
- Shape2DSW *body_shape = p_body->get_shape(j);
-
- if (body_shape->get_type() != PhysicsServer2D::SHAPE_RAY) {
- continue;
- }
-
- Transform2D body_shape_xform = body_transform * p_body->get_shape_transform(j);
-
- for (int i = 0; i < amount; i++) {
- const CollisionObject2DSW *col_obj = intersection_query_results[i];
- int shape_idx = intersection_query_subindex_results[i];
-
- cbk.amount = 0;
- cbk.passed = 0;
- cbk.ptr = sr;
- cbk.invalid_by_dir = 0;
-
- if (CollisionObject2DSW::TYPE_BODY == col_obj->get_type()) {
- const Body2DSW *b = static_cast<const Body2DSW *>(col_obj);
- if (p_infinite_inertia && PhysicsServer2D::BODY_MODE_STATIC != b->get_mode() && PhysicsServer2D::BODY_MODE_KINEMATIC != b->get_mode()) {
- continue;
- }
- }
-
- Transform2D col_obj_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
-
- /*
- * There is no point in supporting one way collisions with ray shapes, as they will always collide in the desired
- * direction. Use a short ray shape if you want to achieve a similar effect.
- *
- if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) {
- cbk.valid_dir = col_obj_shape_xform.get_axis(1).normalized();
- cbk.valid_depth = p_margin; //only valid depth is the collision margin
- cbk.invalid_by_dir = 0;
-
- } else {
-*/
-
- cbk.valid_dir = Vector2();
- cbk.valid_depth = 0;
- cbk.invalid_by_dir = 0;
-
- /*
- }
- */
-
- Shape2DSW *against_shape = col_obj->get_shape(shape_idx);
- if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), cbkres, cbkptr, nullptr, p_margin)) {
- if (cbk.amount > 0) {
- collided = true;
- }
-
- int ray_index = -1; //reuse shape
- for (int k = 0; k < rays_found; k++) {
- if (r_results[ray_index].collision_local_shape == j) {
- ray_index = k;
- }
- }
-
- if (ray_index == -1 && rays_found < p_result_max) {
- ray_index = rays_found;
- rays_found++;
- }
-
- if (ray_index != -1) {
- PhysicsServer2D::SeparationResult &result = r_results[ray_index];
-
- for (int k = 0; k < cbk.amount; k++) {
- Vector2 a = sr[k * 2 + 0];
- Vector2 b = sr[k * 2 + 1];
-
- recover_motion += (b - a) / cbk.amount;
-
- real_t depth = a.distance_to(b);
- if (depth > result.collision_depth) {
- result.collision_depth = depth;
- result.collision_point = b;
- result.collision_normal = (b - a).normalized();
- result.collision_local_shape = j;
- result.collider_shape = shape_idx;
- result.collider = col_obj->get_self();
- result.collider_id = col_obj->get_instance_id();
- result.collider_metadata = col_obj->get_shape_metadata(shape_idx);
- if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) {
- Body2DSW *body = (Body2DSW *)col_obj;
-
- Vector2 rel_vec = b - body->get_transform().get_origin();
- result.collider_velocity = Vector2(-body->get_angular_velocity() * rel_vec.y, body->get_angular_velocity() * rel_vec.x) + body->get_linear_velocity();
- }
- }
- }
- }
- }
- }
- }
-
- if (!collided || recover_motion == Vector2()) {
- break;
- }
-
- body_transform.elements[2] += recover_motion;
- body_aabb.position += recover_motion;
-
- recover_attempts--;
- } while (recover_attempts);
- }
-
- //optimize results (remove non colliding)
- for (int i = 0; i < rays_found; i++) {
- if (r_results[i].collision_depth == 0) {
- rays_found--;
- SWAP(r_results[i], r_results[rays_found]);
- }
- }
-
- r_recover_motion = body_transform.elements[2] - p_transform.elements[2];
- return rays_found;
-}
-
-bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer2D::MotionResult *r_result, bool p_exclude_raycast_shapes) {
- //give me back regular physics engine logic
- //this is madness
- //and most people using this function will think
- //what it does is simpler than using physics
- //this took about a week to get right..
- //but is it right? who knows at this point..
-
- if (r_result) {
- r_result->collider_id = ObjectID();
- r_result->collider_shape = 0;
- }
- Rect2 body_aabb;
-
- bool shapes_found = false;
-
- for (int i = 0; i < p_body->get_shape_count(); i++) {
- if (p_body->is_shape_set_as_disabled(i)) {
- continue;
- }
-
- if (p_exclude_raycast_shapes && p_body->get_shape(i)->get_type() == PhysicsServer2D::SHAPE_RAY) {
- continue;
- }
-
- if (!shapes_found) {
- body_aabb = p_body->get_shape_aabb(i);
- shapes_found = true;
- } else {
- body_aabb = body_aabb.merge(p_body->get_shape_aabb(i));
- }
- }
-
- if (!shapes_found) {
- if (r_result) {
- *r_result = PhysicsServer2D::MotionResult();
- r_result->motion = p_motion;
- }
- return false;
- }
-
- // Undo the currently transform the physics server is aware of and apply the provided one
- body_aabb = p_from.xform(p_body->get_inv_transform().xform(body_aabb));
- body_aabb = body_aabb.grow(p_margin);
-
- static const int max_excluded_shape_pairs = 32;
- ExcludedShapeSW excluded_shape_pairs[max_excluded_shape_pairs];
- int excluded_shape_pair_count = 0;
-
- real_t motion_length = p_motion.length();
- Vector2 motion_normal = p_motion / motion_length;
-
- Transform2D body_transform = p_from;
-
- bool recovered = false;
-
- {
- //STEP 1, FREE BODY IF STUCK
-
- const int max_results = 32;
- int recover_attempts = 4;
- Vector2 sr[max_results * 2];
-
- do {
- PhysicsServer2DSW::CollCbkData cbk;
- cbk.max = max_results;
- cbk.amount = 0;
- cbk.passed = 0;
- cbk.ptr = sr;
- cbk.invalid_by_dir = 0;
- excluded_shape_pair_count = 0; //last step is the one valid
-
- PhysicsServer2DSW::CollCbkData *cbkptr = &cbk;
- CollisionSolver2DSW::CallbackResult cbkres = PhysicsServer2DSW::_shape_col_cbk;
-
- bool collided = false;
-
- int amount = _cull_aabb_for_body(p_body, body_aabb);
-
- for (int j = 0; j < p_body->get_shape_count(); j++) {
- if (p_body->is_shape_set_as_disabled(j)) {
- continue;
- }
-
- Shape2DSW *body_shape = p_body->get_shape(j);
- if (p_exclude_raycast_shapes && body_shape->get_type() == PhysicsServer2D::SHAPE_RAY) {
- continue;
- }
-
- Transform2D body_shape_xform = body_transform * p_body->get_shape_transform(j);
- for (int i = 0; i < amount; i++) {
- const CollisionObject2DSW *col_obj = intersection_query_results[i];
- int shape_idx = intersection_query_subindex_results[i];
-
- if (CollisionObject2DSW::TYPE_BODY == col_obj->get_type()) {
- const Body2DSW *b = static_cast<const Body2DSW *>(col_obj);
- if (p_infinite_inertia && PhysicsServer2D::BODY_MODE_STATIC != b->get_mode() && PhysicsServer2D::BODY_MODE_KINEMATIC != b->get_mode()) {
- continue;
- }
- }
-
- Transform2D col_obj_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
-
- if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) {
- cbk.valid_dir = col_obj_shape_xform.get_axis(1).normalized();
-
- real_t owc_margin = col_obj->get_shape_one_way_collision_margin(shape_idx);
- cbk.valid_depth = MAX(owc_margin, p_margin); //user specified, but never less than actual margin or it won't work
- cbk.invalid_by_dir = 0;
-
- if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) {
- const Body2DSW *b = static_cast<const Body2DSW *>(col_obj);
- if (b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_RIGID) {
- //fix for moving platforms (kinematic and dynamic), margin is increased by how much it moved in the given direction
- Vector2 lv = b->get_linear_velocity();
- //compute displacement from linear velocity
- Vector2 motion = lv * PhysicsDirectBodyState2DSW::singleton->step;
- real_t motion_len = motion.length();
- motion.normalize();
- cbk.valid_depth += motion_len * MAX(motion.dot(-cbk.valid_dir), 0.0);
- }
- }
- } else {
- cbk.valid_dir = Vector2();
- cbk.valid_depth = 0;
- cbk.invalid_by_dir = 0;
- }
-
- int current_passed = cbk.passed; //save how many points passed collision
- bool did_collide = false;
-
- Shape2DSW *against_shape = col_obj->get_shape(shape_idx);
- if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), cbkres, cbkptr, nullptr, p_margin)) {
- did_collide = cbk.passed > current_passed; //more passed, so collision actually existed
- }
-
- if (!did_collide && cbk.invalid_by_dir > 0) {
- //this shape must be excluded
- if (excluded_shape_pair_count < max_excluded_shape_pairs) {
- ExcludedShapeSW esp;
- esp.local_shape = body_shape;
- esp.against_object = col_obj;
- esp.against_shape_index = shape_idx;
- excluded_shape_pairs[excluded_shape_pair_count++] = esp;
- }
- }
-
- if (did_collide) {
- collided = true;
- }
- }
- }
-
- if (!collided) {
- break;
- }
-
- Vector2 recover_motion;
- for (int i = 0; i < cbk.amount; i++) {
- Vector2 a = sr[i * 2 + 0];
- Vector2 b = sr[i * 2 + 1];
-
- // Compute plane on b towards a.
- Vector2 n = (a - b).normalized();
- real_t d = n.dot(b);
-
- // Compute depth on recovered motion.
- real_t depth = n.dot(a + recover_motion) - d;
- if (depth > 0.0) {
- // Only recover if there is penetration.
- recover_motion -= n * depth * 0.4;
- }
- }
-
- if (recover_motion == Vector2()) {
- collided = false;
- break;
- }
-
- recovered = true;
-
- body_transform.elements[2] += recover_motion;
- body_aabb.position += recover_motion;
-
- recover_attempts--;
-
- } while (recover_attempts);
- }
-
- real_t safe = 1.0;
- real_t unsafe = 1.0;
- int best_shape = -1;
-
- {
- // STEP 2 ATTEMPT MOTION
-
- Rect2 motion_aabb = body_aabb;
- motion_aabb.position += p_motion;
- motion_aabb = motion_aabb.merge(body_aabb);
-
- int amount = _cull_aabb_for_body(p_body, motion_aabb);
-
- for (int body_shape_idx = 0; body_shape_idx < p_body->get_shape_count(); body_shape_idx++) {
- if (p_body->is_shape_set_as_disabled(body_shape_idx)) {
- continue;
- }
-
- Shape2DSW *body_shape = p_body->get_shape(body_shape_idx);
- if (p_exclude_raycast_shapes && body_shape->get_type() == PhysicsServer2D::SHAPE_RAY) {
- continue;
- }
-
- Transform2D body_shape_xform = body_transform * p_body->get_shape_transform(body_shape_idx);
-
- bool stuck = false;
-
- real_t best_safe = 1;
- real_t best_unsafe = 1;
-
- for (int i = 0; i < amount; i++) {
- const CollisionObject2DSW *col_obj = intersection_query_results[i];
- int col_shape_idx = intersection_query_subindex_results[i];
- Shape2DSW *against_shape = col_obj->get_shape(col_shape_idx);
-
- if (CollisionObject2DSW::TYPE_BODY == col_obj->get_type()) {
- const Body2DSW *b = static_cast<const Body2DSW *>(col_obj);
- if (p_infinite_inertia && PhysicsServer2D::BODY_MODE_STATIC != b->get_mode() && PhysicsServer2D::BODY_MODE_KINEMATIC != b->get_mode()) {
- continue;
- }
- }
-
- bool excluded = false;
-
- for (int k = 0; k < excluded_shape_pair_count; k++) {
- if (excluded_shape_pairs[k].local_shape == body_shape && excluded_shape_pairs[k].against_object == col_obj && excluded_shape_pairs[k].against_shape_index == col_shape_idx) {
- excluded = true;
- break;
- }
- }
-
- if (excluded) {
- continue;
- }
-
- Transform2D col_obj_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(col_shape_idx);
- //test initial overlap, does it collide if going all the way?
- if (!CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion, against_shape, col_obj_shape_xform, Vector2(), nullptr, nullptr, nullptr, 0)) {
- continue;
- }
-
- //test initial overlap
- if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), nullptr, nullptr, nullptr, 0)) {
- if (col_obj->is_shape_set_as_one_way_collision(col_shape_idx)) {
- Vector2 direction = col_obj_shape_xform.get_axis(1).normalized();
- if (motion_normal.dot(direction) < 0) {
- continue;
- }
- }
-
- stuck = true;
- break;
- }
-
- //just do kinematic solving
- real_t low = 0;
- real_t hi = 1;
-
- for (int k = 0; k < 8; k++) { //steps should be customizable..
-
- real_t ofs = (low + hi) * 0.5;
-
- Vector2 sep = motion_normal; //important optimization for this to work fast enough
- bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion * ofs, against_shape, col_obj_shape_xform, Vector2(), nullptr, nullptr, &sep, 0);
-
- if (collided) {
- hi = ofs;
- } else {
- low = ofs;
- }
- }
-
- if (col_obj->is_shape_set_as_one_way_collision(col_shape_idx)) {
- Vector2 cd[2];
- PhysicsServer2DSW::CollCbkData cbk;
- cbk.max = 1;
- cbk.amount = 0;
- cbk.passed = 0;
- cbk.ptr = cd;
- cbk.valid_dir = col_obj_shape_xform.get_axis(1).normalized();
-
- cbk.valid_depth = 10e20;
-
- Vector2 sep = motion_normal; //important optimization for this to work fast enough
- bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion * (hi + contact_max_allowed_penetration), col_obj->get_shape(col_shape_idx), col_obj_shape_xform, Vector2(), PhysicsServer2DSW::_shape_col_cbk, &cbk, &sep, 0);
- if (!collided || cbk.amount == 0) {
- continue;
- }
- }
-
- if (low < best_safe) {
- best_safe = low;
- best_unsafe = hi;
- }
- }
-
- if (stuck) {
- safe = 0;
- unsafe = 0;
- best_shape = body_shape_idx; //sadly it's the best
- break;
- }
- if (best_safe == 1.0) {
- continue;
- }
- if (best_safe < safe) {
- safe = best_safe;
- unsafe = best_unsafe;
- best_shape = body_shape_idx;
- }
- }
- }
-
- bool collided = false;
-
- if (recovered || (safe < 1)) {
- if (safe >= 1) {
- best_shape = -1; //no best shape with cast, reset to -1
- }
-
- //it collided, let's get the rest info in unsafe advance
- Transform2D ugt = body_transform;
- ugt.elements[2] += p_motion * unsafe;
-
- _RestCallbackData2D rcd;
- rcd.best_len = 0;
- rcd.best_object = nullptr;
- rcd.best_shape = 0;
-
- // Allowed depth can't be lower than motion length, in order to handle contacts at low speed.
- rcd.min_allowed_depth = MIN(motion_length, test_motion_min_contact_depth);
-
- int from_shape = best_shape != -1 ? best_shape : 0;
- int to_shape = best_shape != -1 ? best_shape + 1 : p_body->get_shape_count();
-
- for (int j = from_shape; j < to_shape; j++) {
- if (p_body->is_shape_set_as_disabled(j)) {
- continue;
- }
-
- Transform2D body_shape_xform = ugt * p_body->get_shape_transform(j);
- Shape2DSW *body_shape = p_body->get_shape(j);
-
- if (p_exclude_raycast_shapes && body_shape->get_type() == PhysicsServer2D::SHAPE_RAY) {
- continue;
- }
-
- body_aabb.position += p_motion * unsafe;
-
- int amount = _cull_aabb_for_body(p_body, body_aabb);
-
- for (int i = 0; i < amount; i++) {
- const CollisionObject2DSW *col_obj = intersection_query_results[i];
- int shape_idx = intersection_query_subindex_results[i];
-
- if (CollisionObject2DSW::TYPE_BODY == col_obj->get_type()) {
- const Body2DSW *b = static_cast<const Body2DSW *>(col_obj);
- if (p_infinite_inertia && PhysicsServer2D::BODY_MODE_STATIC != b->get_mode() && PhysicsServer2D::BODY_MODE_KINEMATIC != b->get_mode()) {
- continue;
- }
- }
-
- Shape2DSW *against_shape = col_obj->get_shape(shape_idx);
-
- bool excluded = false;
- for (int k = 0; k < excluded_shape_pair_count; k++) {
- if (excluded_shape_pairs[k].local_shape == body_shape && excluded_shape_pairs[k].against_object == col_obj && excluded_shape_pairs[k].against_shape_index == shape_idx) {
- excluded = true;
- break;
- }
- }
- if (excluded) {
- continue;
- }
-
- Transform2D col_obj_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
-
- if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) {
- rcd.valid_dir = col_obj_shape_xform.get_axis(1).normalized();
-
- real_t owc_margin = col_obj->get_shape_one_way_collision_margin(shape_idx);
- rcd.valid_depth = MAX(owc_margin, p_margin); //user specified, but never less than actual margin or it won't work
-
- if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) {
- const Body2DSW *b = static_cast<const Body2DSW *>(col_obj);
- if (b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_RIGID) {
- //fix for moving platforms (kinematic and dynamic), margin is increased by how much it moved in the given direction
- Vector2 lv = b->get_linear_velocity();
- //compute displacement from linear velocity
- Vector2 motion = lv * PhysicsDirectBodyState2DSW::singleton->step;
- real_t motion_len = motion.length();
- motion.normalize();
- rcd.valid_depth += motion_len * MAX(motion.dot(-rcd.valid_dir), 0.0);
- }
- }
- } else {
- rcd.valid_dir = Vector2();
- rcd.valid_depth = 0;
- }
-
- rcd.object = col_obj;
- rcd.shape = shape_idx;
- rcd.local_shape = j;
- bool sc = CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), _rest_cbk_result, &rcd, nullptr, p_margin);
- if (!sc) {
- continue;
- }
- }
- }
-
- if (rcd.best_len != 0) {
- if (r_result) {
- r_result->collider = rcd.best_object->get_self();
- r_result->collider_id = rcd.best_object->get_instance_id();
- r_result->collider_shape = rcd.best_shape;
- r_result->collision_local_shape = rcd.best_local_shape;
- r_result->collision_normal = rcd.best_normal;
- r_result->collision_point = rcd.best_contact;
- r_result->collider_metadata = rcd.best_object->get_shape_metadata(rcd.best_shape);
-
- const Body2DSW *body = static_cast<const Body2DSW *>(rcd.best_object);
- Vector2 rel_vec = r_result->collision_point - body->get_transform().get_origin();
- r_result->collider_velocity = Vector2(-body->get_angular_velocity() * rel_vec.y, body->get_angular_velocity() * rel_vec.x) + body->get_linear_velocity();
-
- r_result->motion = safe * p_motion;
- r_result->remainder = p_motion - safe * p_motion;
- r_result->motion += (body_transform.get_origin() - p_from.get_origin());
- }
-
- collided = true;
- }
- }
-
- if (!collided && r_result) {
- r_result->motion = p_motion;
- r_result->remainder = Vector2();
- r_result->motion += (body_transform.get_origin() - p_from.get_origin());
- }
-
- return collided;
-}
-
-void *Space2DSW::_broadphase_pair(CollisionObject2DSW *A, int p_subindex_A, CollisionObject2DSW *B, int p_subindex_B, void *p_self) {
- if (!A->test_collision_mask(B)) {
- return nullptr;
- }
-
- CollisionObject2DSW::Type type_A = A->get_type();
- CollisionObject2DSW::Type type_B = B->get_type();
- if (type_A > type_B) {
- SWAP(A, B);
- SWAP(p_subindex_A, p_subindex_B);
- SWAP(type_A, type_B);
- }
-
- Space2DSW *self = (Space2DSW *)p_self;
- self->collision_pairs++;
-
- if (type_A == CollisionObject2DSW::TYPE_AREA) {
- Area2DSW *area = static_cast<Area2DSW *>(A);
- if (type_B == CollisionObject2DSW::TYPE_AREA) {
- Area2DSW *area_b = static_cast<Area2DSW *>(B);
- Area2Pair2DSW *area2_pair = memnew(Area2Pair2DSW(area_b, p_subindex_B, area, p_subindex_A));
- return area2_pair;
- } else {
- Body2DSW *body = static_cast<Body2DSW *>(B);
- AreaPair2DSW *area_pair = memnew(AreaPair2DSW(body, p_subindex_B, area, p_subindex_A));
- return area_pair;
- }
-
- } else {
- BodyPair2DSW *b = memnew(BodyPair2DSW((Body2DSW *)A, p_subindex_A, (Body2DSW *)B, p_subindex_B));
- return b;
- }
-
- return nullptr;
-}
-
-void Space2DSW::_broadphase_unpair(CollisionObject2DSW *A, int p_subindex_A, CollisionObject2DSW *B, int p_subindex_B, void *p_data, void *p_self) {
- if (!p_data) {
- return;
- }
-
- Space2DSW *self = (Space2DSW *)p_self;
- self->collision_pairs--;
- Constraint2DSW *c = (Constraint2DSW *)p_data;
- memdelete(c);
-}
-
-const SelfList<Body2DSW>::List &Space2DSW::get_active_body_list() const {
- return active_list;
-}
-
-void Space2DSW::body_add_to_active_list(SelfList<Body2DSW> *p_body) {
- active_list.add(p_body);
-}
-
-void Space2DSW::body_remove_from_active_list(SelfList<Body2DSW> *p_body) {
- active_list.remove(p_body);
-}
-
-void Space2DSW::body_add_to_inertia_update_list(SelfList<Body2DSW> *p_body) {
- inertia_update_list.add(p_body);
-}
-
-void Space2DSW::body_remove_from_inertia_update_list(SelfList<Body2DSW> *p_body) {
- inertia_update_list.remove(p_body);
-}
-
-BroadPhase2DSW *Space2DSW::get_broadphase() {
- return broadphase;
-}
-
-void Space2DSW::add_object(CollisionObject2DSW *p_object) {
- ERR_FAIL_COND(objects.has(p_object));
- objects.insert(p_object);
-}
-
-void Space2DSW::remove_object(CollisionObject2DSW *p_object) {
- ERR_FAIL_COND(!objects.has(p_object));
- objects.erase(p_object);
-}
-
-const Set<CollisionObject2DSW *> &Space2DSW::get_objects() const {
- return objects;
-}
-
-void Space2DSW::body_add_to_state_query_list(SelfList<Body2DSW> *p_body) {
- state_query_list.add(p_body);
-}
-
-void Space2DSW::body_remove_from_state_query_list(SelfList<Body2DSW> *p_body) {
- state_query_list.remove(p_body);
-}
-
-void Space2DSW::area_add_to_monitor_query_list(SelfList<Area2DSW> *p_area) {
- monitor_query_list.add(p_area);
-}
-
-void Space2DSW::area_remove_from_monitor_query_list(SelfList<Area2DSW> *p_area) {
- monitor_query_list.remove(p_area);
-}
-
-void Space2DSW::area_add_to_moved_list(SelfList<Area2DSW> *p_area) {
- area_moved_list.add(p_area);
-}
-
-void Space2DSW::area_remove_from_moved_list(SelfList<Area2DSW> *p_area) {
- area_moved_list.remove(p_area);
-}
-
-const SelfList<Area2DSW>::List &Space2DSW::get_moved_area_list() const {
- return area_moved_list;
-}
-
-void Space2DSW::call_queries() {
- while (state_query_list.first()) {
- Body2DSW *b = state_query_list.first()->self();
- state_query_list.remove(state_query_list.first());
- b->call_queries();
- }
-
- while (monitor_query_list.first()) {
- Area2DSW *a = monitor_query_list.first()->self();
- monitor_query_list.remove(monitor_query_list.first());
- a->call_queries();
- }
-}
-
-void Space2DSW::setup() {
- contact_debug_count = 0;
-
- while (inertia_update_list.first()) {
- inertia_update_list.first()->self()->update_inertias();
- inertia_update_list.remove(inertia_update_list.first());
- }
-}
-
-void Space2DSW::update() {
- broadphase->update();
-}
-
-void Space2DSW::set_param(PhysicsServer2D::SpaceParameter p_param, real_t p_value) {
- switch (p_param) {
- case PhysicsServer2D::SPACE_PARAM_CONTACT_RECYCLE_RADIUS:
- contact_recycle_radius = p_value;
- break;
- case PhysicsServer2D::SPACE_PARAM_CONTACT_MAX_SEPARATION:
- contact_max_separation = p_value;
- break;
- case PhysicsServer2D::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION:
- contact_max_allowed_penetration = p_value;
- break;
- case PhysicsServer2D::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD:
- body_linear_velocity_sleep_threshold = p_value;
- break;
- case PhysicsServer2D::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD:
- body_angular_velocity_sleep_threshold = p_value;
- break;
- case PhysicsServer2D::SPACE_PARAM_BODY_TIME_TO_SLEEP:
- body_time_to_sleep = p_value;
- break;
- case PhysicsServer2D::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS:
- constraint_bias = p_value;
- break;
- case PhysicsServer2D::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH:
- test_motion_min_contact_depth = p_value;
- break;
- }
-}
-
-real_t Space2DSW::get_param(PhysicsServer2D::SpaceParameter p_param) const {
- switch (p_param) {
- case PhysicsServer2D::SPACE_PARAM_CONTACT_RECYCLE_RADIUS:
- return contact_recycle_radius;
- case PhysicsServer2D::SPACE_PARAM_CONTACT_MAX_SEPARATION:
- return contact_max_separation;
- case PhysicsServer2D::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION:
- return contact_max_allowed_penetration;
- case PhysicsServer2D::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD:
- return body_linear_velocity_sleep_threshold;
- case PhysicsServer2D::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD:
- return body_angular_velocity_sleep_threshold;
- case PhysicsServer2D::SPACE_PARAM_BODY_TIME_TO_SLEEP:
- return body_time_to_sleep;
- case PhysicsServer2D::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS:
- return constraint_bias;
- case PhysicsServer2D::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH:
- return test_motion_min_contact_depth;
- }
- return 0;
-}
-
-void Space2DSW::lock() {
- locked = true;
-}
-
-void Space2DSW::unlock() {
- locked = false;
-}
-
-bool Space2DSW::is_locked() const {
- return locked;
-}
-
-PhysicsDirectSpaceState2DSW *Space2DSW::get_direct_state() {
- return direct_access;
-}
-
-Space2DSW::Space2DSW() {
- collision_pairs = 0;
- active_objects = 0;
- island_count = 0;
-
- contact_debug_count = 0;
-
- locked = false;
- contact_recycle_radius = 1.0;
- contact_max_separation = 1.5;
- contact_max_allowed_penetration = 0.3;
- test_motion_min_contact_depth = 0.005;
-
- constraint_bias = 0.2;
- body_linear_velocity_sleep_threshold = GLOBAL_DEF("physics/2d/sleep_threshold_linear", 2.0);
- body_angular_velocity_sleep_threshold = GLOBAL_DEF("physics/2d/sleep_threshold_angular", Math::deg2rad(8.0));
- body_time_to_sleep = GLOBAL_DEF("physics/2d/time_before_sleep", 0.5);
- ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/time_before_sleep", PropertyInfo(Variant::FLOAT, "physics/2d/time_before_sleep", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater"));
-
- broadphase = BroadPhase2DSW::create_func();
- broadphase->set_pair_callback(_broadphase_pair, this);
- broadphase->set_unpair_callback(_broadphase_unpair, this);
- area = nullptr;
-
- direct_access = memnew(PhysicsDirectSpaceState2DSW);
- direct_access->space = this;
-
- for (int i = 0; i < ELAPSED_TIME_MAX; i++) {
- elapsed_time[i] = 0;
- }
-}
-
-Space2DSW::~Space2DSW() {
- memdelete(broadphase);
- memdelete(direct_access);
-}
diff --git a/servers/physics_2d/space_2d_sw.h b/servers/physics_2d/space_2d_sw.h
deleted file mode 100644
index 4d737d622f..0000000000
--- a/servers/physics_2d/space_2d_sw.h
+++ /dev/null
@@ -1,208 +0,0 @@
-/*************************************************************************/
-/* space_2d_sw.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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 SPACE_2D_SW_H
-#define SPACE_2D_SW_H
-
-#include "area_2d_sw.h"
-#include "area_pair_2d_sw.h"
-#include "body_2d_sw.h"
-#include "body_pair_2d_sw.h"
-#include "broad_phase_2d_sw.h"
-#include "collision_object_2d_sw.h"
-#include "core/config/project_settings.h"
-#include "core/templates/hash_map.h"
-#include "core/typedefs.h"
-
-class PhysicsDirectSpaceState2DSW : public PhysicsDirectSpaceState2D {
- GDCLASS(PhysicsDirectSpaceState2DSW, PhysicsDirectSpaceState2D);
-
- int _intersect_point_impl(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_point, bool p_filter_by_canvas = false, ObjectID p_canvas_instance_id = ObjectID());
-
-public:
- Space2DSW *space;
-
- virtual int intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) override;
- virtual int intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_instance_id, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) override;
- virtual bool intersect_ray(const Vector2 &p_from, const Vector2 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
- virtual int intersect_shape(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
- virtual bool cast_motion(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
- virtual bool collide_shape(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, Vector2 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
- virtual bool rest_info(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
-
- PhysicsDirectSpaceState2DSW();
-};
-
-class Space2DSW {
-public:
- enum ElapsedTime {
- ELAPSED_TIME_INTEGRATE_FORCES,
- ELAPSED_TIME_GENERATE_ISLANDS,
- ELAPSED_TIME_SETUP_CONSTRAINTS,
- ELAPSED_TIME_SOLVE_CONSTRAINTS,
- ELAPSED_TIME_INTEGRATE_VELOCITIES,
- ELAPSED_TIME_MAX
-
- };
-
-private:
- struct ExcludedShapeSW {
- Shape2DSW *local_shape;
- const CollisionObject2DSW *against_object;
- int against_shape_index;
- };
-
- uint64_t elapsed_time[ELAPSED_TIME_MAX];
-
- PhysicsDirectSpaceState2DSW *direct_access;
- RID self;
-
- BroadPhase2DSW *broadphase;
- SelfList<Body2DSW>::List active_list;
- SelfList<Body2DSW>::List inertia_update_list;
- SelfList<Body2DSW>::List state_query_list;
- SelfList<Area2DSW>::List monitor_query_list;
- SelfList<Area2DSW>::List area_moved_list;
-
- static void *_broadphase_pair(CollisionObject2DSW *A, int p_subindex_A, CollisionObject2DSW *B, int p_subindex_B, void *p_self);
- static void _broadphase_unpair(CollisionObject2DSW *A, int p_subindex_A, CollisionObject2DSW *B, int p_subindex_B, void *p_data, void *p_self);
-
- Set<CollisionObject2DSW *> objects;
-
- Area2DSW *area;
-
- real_t contact_recycle_radius;
- real_t contact_max_separation;
- real_t contact_max_allowed_penetration;
- real_t constraint_bias;
- real_t test_motion_min_contact_depth;
-
- enum {
- INTERSECTION_QUERY_MAX = 2048
- };
-
- CollisionObject2DSW *intersection_query_results[INTERSECTION_QUERY_MAX];
- int intersection_query_subindex_results[INTERSECTION_QUERY_MAX];
-
- real_t body_linear_velocity_sleep_threshold;
- real_t body_angular_velocity_sleep_threshold;
- real_t body_time_to_sleep;
-
- bool locked;
-
- int island_count;
- int active_objects;
- int collision_pairs;
-
- int _cull_aabb_for_body(Body2DSW *p_body, const Rect2 &p_aabb);
-
- Vector<Vector2> contact_debug;
- int contact_debug_count;
-
- friend class PhysicsDirectSpaceState2DSW;
-
-public:
- _FORCE_INLINE_ void set_self(const RID &p_self) { self = p_self; }
- _FORCE_INLINE_ RID get_self() const { return self; }
-
- void set_default_area(Area2DSW *p_area) { area = p_area; }
- Area2DSW *get_default_area() const { return area; }
-
- const SelfList<Body2DSW>::List &get_active_body_list() const;
- void body_add_to_active_list(SelfList<Body2DSW> *p_body);
- void body_remove_from_active_list(SelfList<Body2DSW> *p_body);
- void body_add_to_inertia_update_list(SelfList<Body2DSW> *p_body);
- void body_remove_from_inertia_update_list(SelfList<Body2DSW> *p_body);
- void area_add_to_moved_list(SelfList<Area2DSW> *p_area);
- void area_remove_from_moved_list(SelfList<Area2DSW> *p_area);
- const SelfList<Area2DSW>::List &get_moved_area_list() const;
-
- void body_add_to_state_query_list(SelfList<Body2DSW> *p_body);
- void body_remove_from_state_query_list(SelfList<Body2DSW> *p_body);
-
- void area_add_to_monitor_query_list(SelfList<Area2DSW> *p_area);
- void area_remove_from_monitor_query_list(SelfList<Area2DSW> *p_area);
-
- BroadPhase2DSW *get_broadphase();
-
- void add_object(CollisionObject2DSW *p_object);
- void remove_object(CollisionObject2DSW *p_object);
- const Set<CollisionObject2DSW *> &get_objects() const;
-
- _FORCE_INLINE_ real_t get_contact_recycle_radius() const { return contact_recycle_radius; }
- _FORCE_INLINE_ real_t get_contact_max_separation() const { return contact_max_separation; }
- _FORCE_INLINE_ real_t get_contact_max_allowed_penetration() const { return contact_max_allowed_penetration; }
- _FORCE_INLINE_ real_t get_constraint_bias() const { return constraint_bias; }
- _FORCE_INLINE_ real_t get_body_linear_velocity_sleep_threshold() const { return body_linear_velocity_sleep_threshold; }
- _FORCE_INLINE_ real_t get_body_angular_velocity_sleep_threshold() const { return body_angular_velocity_sleep_threshold; }
- _FORCE_INLINE_ real_t get_body_time_to_sleep() const { return body_time_to_sleep; }
-
- void update();
- void setup();
- void call_queries();
-
- bool is_locked() const;
- void lock();
- void unlock();
-
- void set_param(PhysicsServer2D::SpaceParameter p_param, real_t p_value);
- real_t get_param(PhysicsServer2D::SpaceParameter p_param) const;
-
- void set_island_count(int p_island_count) { island_count = p_island_count; }
- int get_island_count() const { return island_count; }
-
- void set_active_objects(int p_active_objects) { active_objects = p_active_objects; }
- int get_active_objects() const { return active_objects; }
-
- int get_collision_pairs() const { return collision_pairs; }
-
- bool test_body_motion(Body2DSW *p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer2D::MotionResult *r_result, bool p_exclude_raycast_shapes = true);
- int test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, PhysicsServer2D::SeparationResult *r_results, int p_result_max, real_t p_margin);
-
- void set_debug_contacts(int p_amount) { contact_debug.resize(p_amount); }
- _FORCE_INLINE_ bool is_debugging_contacts() const { return !contact_debug.is_empty(); }
- _FORCE_INLINE_ void add_debug_contact(const Vector2 &p_contact) {
- if (contact_debug_count < contact_debug.size()) {
- contact_debug.write[contact_debug_count++] = p_contact;
- }
- }
- _FORCE_INLINE_ Vector<Vector2> get_debug_contacts() { return contact_debug; }
- _FORCE_INLINE_ int get_debug_contact_count() { return contact_debug_count; }
-
- PhysicsDirectSpaceState2DSW *get_direct_state();
-
- void set_elapsed_time(ElapsedTime p_time, uint64_t p_msec) { elapsed_time[p_time] = p_msec; }
- uint64_t get_elapsed_time(ElapsedTime p_time) const { return elapsed_time[p_time]; }
-
- Space2DSW();
- ~Space2DSW();
-};
-
-#endif // SPACE_2D_SW_H
diff --git a/servers/physics_2d/step_2d_sw.cpp b/servers/physics_2d/step_2d_sw.cpp
deleted file mode 100644
index 6613d19729..0000000000
--- a/servers/physics_2d/step_2d_sw.cpp
+++ /dev/null
@@ -1,304 +0,0 @@
-/*************************************************************************/
-/* step_2d_sw.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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 "step_2d_sw.h"
-#include "core/os/os.h"
-
-void Step2DSW::_populate_island(Body2DSW *p_body, Body2DSW **p_island, Constraint2DSW **p_constraint_island) {
- p_body->set_island_step(_step);
- p_body->set_island_next(*p_island);
- *p_island = p_body;
-
- for (const List<Pair<Constraint2DSW *, int>>::Element *E = p_body->get_constraint_list().front(); E; E = E->next()) {
- Constraint2DSW *c = (Constraint2DSW *)E->get().first;
- if (c->get_island_step() == _step) {
- continue; //already processed
- }
- c->set_island_step(_step);
- c->set_island_next(*p_constraint_island);
- *p_constraint_island = c;
-
- for (int i = 0; i < c->get_body_count(); i++) {
- if (i == E->get().second) {
- continue;
- }
- Body2DSW *b = c->get_body_ptr()[i];
- if (b->get_island_step() == _step || b->get_mode() == PhysicsServer2D::BODY_MODE_STATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) {
- continue; //no go
- }
- _populate_island(c->get_body_ptr()[i], p_island, p_constraint_island);
- }
- }
-}
-
-bool Step2DSW::_setup_island(Constraint2DSW *p_island, real_t p_delta) {
- Constraint2DSW *ci = p_island;
- Constraint2DSW *prev_ci = nullptr;
- bool removed_root = false;
- while (ci) {
- bool process = ci->setup(p_delta);
-
- if (!process) {
- //remove from island if process fails
- if (prev_ci) {
- prev_ci->set_island_next(ci->get_island_next());
- } else {
- removed_root = true;
- prev_ci = ci;
- }
- } else {
- prev_ci = ci;
- }
- ci = ci->get_island_next();
- }
-
- return removed_root;
-}
-
-void Step2DSW::_solve_island(Constraint2DSW *p_island, int p_iterations, real_t p_delta) {
- for (int i = 0; i < p_iterations; i++) {
- Constraint2DSW *ci = p_island;
- while (ci) {
- ci->solve(p_delta);
- ci = ci->get_island_next();
- }
- }
-}
-
-void Step2DSW::_check_suspend(Body2DSW *p_island, real_t p_delta) {
- bool can_sleep = true;
-
- Body2DSW *b = p_island;
- while (b) {
- if (b->get_mode() == PhysicsServer2D::BODY_MODE_STATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) {
- b = b->get_island_next();
- continue; //ignore for static
- }
-
- if (!b->sleep_test(p_delta)) {
- can_sleep = false;
- }
-
- b = b->get_island_next();
- }
-
- //put all to sleep or wake up everyoen
-
- b = p_island;
- while (b) {
- if (b->get_mode() == PhysicsServer2D::BODY_MODE_STATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) {
- b = b->get_island_next();
- continue; //ignore for static
- }
-
- bool active = b->is_active();
-
- if (active == can_sleep) {
- b->set_active(!can_sleep);
- }
-
- b = b->get_island_next();
- }
-}
-
-void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
- p_space->lock(); // can't access space during this
-
- p_space->setup(); //update inertias, etc
-
- const SelfList<Body2DSW>::List *body_list = &p_space->get_active_body_list();
-
- /* INTEGRATE FORCES */
-
- uint64_t profile_begtime = OS::get_singleton()->get_ticks_usec();
- uint64_t profile_endtime = 0;
-
- int active_count = 0;
-
- const SelfList<Body2DSW> *b = body_list->first();
- while (b) {
- b->self()->integrate_forces(p_delta);
- b = b->next();
- active_count++;
- }
-
- p_space->set_active_objects(active_count);
-
- { //profile
- profile_endtime = OS::get_singleton()->get_ticks_usec();
- p_space->set_elapsed_time(Space2DSW::ELAPSED_TIME_INTEGRATE_FORCES, profile_endtime - profile_begtime);
- profile_begtime = profile_endtime;
- }
-
- /* GENERATE CONSTRAINT ISLANDS */
-
- Body2DSW *island_list = nullptr;
- Constraint2DSW *constraint_island_list = nullptr;
- b = body_list->first();
-
- int island_count = 0;
-
- while (b) {
- Body2DSW *body = b->self();
-
- if (body->get_island_step() != _step) {
- Body2DSW *island = nullptr;
- Constraint2DSW *constraint_island = nullptr;
- _populate_island(body, &island, &constraint_island);
-
- island->set_island_list_next(island_list);
- island_list = island;
-
- if (constraint_island) {
- constraint_island->set_island_list_next(constraint_island_list);
- constraint_island_list = constraint_island;
- island_count++;
- }
- }
- b = b->next();
- }
-
- p_space->set_island_count(island_count);
-
- const SelfList<Area2DSW>::List &aml = p_space->get_moved_area_list();
-
- while (aml.first()) {
- for (const Set<Constraint2DSW *>::Element *E = aml.first()->self()->get_constraints().front(); E; E = E->next()) {
- Constraint2DSW *c = E->get();
- if (c->get_island_step() == _step) {
- continue;
- }
- c->set_island_step(_step);
- c->set_island_next(nullptr);
- c->set_island_list_next(constraint_island_list);
- constraint_island_list = c;
- }
- p_space->area_remove_from_moved_list((SelfList<Area2DSW> *)aml.first()); //faster to remove here
- }
-
- { //profile
- profile_endtime = OS::get_singleton()->get_ticks_usec();
- p_space->set_elapsed_time(Space2DSW::ELAPSED_TIME_GENERATE_ISLANDS, profile_endtime - profile_begtime);
- profile_begtime = profile_endtime;
- }
-
- /* SETUP CONSTRAINT ISLANDS */
-
- {
- Constraint2DSW *ci = constraint_island_list;
- Constraint2DSW *prev_ci = nullptr;
- while (ci) {
- if (_setup_island(ci, p_delta)) {
- //removed the root from the island graph because it is not to be processed
-
- Constraint2DSW *next = ci->get_island_next();
-
- if (next) {
- //root from list being deleted no longer exists, replace by next
- next->set_island_list_next(ci->get_island_list_next());
- if (prev_ci) {
- prev_ci->set_island_list_next(next);
- } else {
- constraint_island_list = next;
- }
- prev_ci = next;
- } else {
- //list is empty, just skip
- if (prev_ci) {
- prev_ci->set_island_list_next(ci->get_island_list_next());
-
- } else {
- constraint_island_list = ci->get_island_list_next();
- }
- }
- } else {
- prev_ci = ci;
- }
-
- ci = ci->get_island_list_next();
- }
- }
-
- { //profile
- profile_endtime = OS::get_singleton()->get_ticks_usec();
- p_space->set_elapsed_time(Space2DSW::ELAPSED_TIME_SETUP_CONSTRAINTS, profile_endtime - profile_begtime);
- profile_begtime = profile_endtime;
- }
-
- /* SOLVE CONSTRAINT ISLANDS */
-
- {
- Constraint2DSW *ci = constraint_island_list;
- while (ci) {
- //iterating each island separatedly improves cache efficiency
- _solve_island(ci, p_iterations, p_delta);
- ci = ci->get_island_list_next();
- }
- }
-
- { //profile
- profile_endtime = OS::get_singleton()->get_ticks_usec();
- p_space->set_elapsed_time(Space2DSW::ELAPSED_TIME_SOLVE_CONSTRAINTS, profile_endtime - profile_begtime);
- profile_begtime = profile_endtime;
- }
-
- /* INTEGRATE VELOCITIES */
-
- b = body_list->first();
- while (b) {
- const SelfList<Body2DSW> *n = b->next();
- b->self()->integrate_velocities(p_delta);
- b = n; // in case it shuts itself down
- }
-
- /* SLEEP / WAKE UP ISLANDS */
-
- {
- Body2DSW *bi = island_list;
- while (bi) {
- _check_suspend(bi, p_delta);
- bi = bi->get_island_list_next();
- }
- }
-
- { //profile
- profile_endtime = OS::get_singleton()->get_ticks_usec();
- p_space->set_elapsed_time(Space2DSW::ELAPSED_TIME_INTEGRATE_VELOCITIES, profile_endtime - profile_begtime);
- //profile_begtime=profile_endtime;
- }
-
- p_space->update();
- p_space->unlock();
- _step++;
-}
-
-Step2DSW::Step2DSW() {
- _step = 1;
-}