1 /*************************************************************************/
2 /* godot_result_callbacks.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
10 /* */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the */
13 /* "Software"), to deal in the Software without restriction, including */
14 /* without limitation the rights to use, copy, modify, merge, publish, */
15 /* distribute, sublicense, and/or sell copies of the Software, and to */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions: */
18 /* */
19 /* The above copyright notice and this permission notice shall be */
20 /* included in all copies or substantial portions of the Software. */
21 /* */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29 /*************************************************************************/
30
31 #include "godot_result_callbacks.h"
32
33 #include "area_bullet.h"
34 #include "bullet_types_converter.h"
35 #include "collision_object_bullet.h"
36 #include "rigid_body_bullet.h"
37 #include <BulletCollision/CollisionDispatch/btInternalEdgeUtility.h>
38
39 /**
40 @author AndreaCatania
41 */
42
godotContactAddedCallback(btManifoldPoint & cp,const btCollisionObjectWrapper * colObj0Wrap,int partId0,int index0,const btCollisionObjectWrapper * colObj1Wrap,int partId1,int index1)43 bool godotContactAddedCallback(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1) {
44 if (!colObj1Wrap->getCollisionObject()->getCollisionShape()->isCompound()) {
45 btAdjustInternalEdgeContacts(cp, colObj1Wrap, colObj0Wrap, partId1, index1);
46 }
47 return true;
48 }
49
test_collision_filters(uint32_t body0_collision_layer,uint32_t body0_collision_mask,uint32_t body1_collision_layer,uint32_t body1_collision_mask)50 bool GodotFilterCallback::test_collision_filters(uint32_t body0_collision_layer, uint32_t body0_collision_mask, uint32_t body1_collision_layer, uint32_t body1_collision_mask) {
51 return body0_collision_layer & body1_collision_mask || body1_collision_layer & body0_collision_mask;
52 }
53
needBroadphaseCollision(btBroadphaseProxy * proxy0,btBroadphaseProxy * proxy1) const54 bool GodotFilterCallback::needBroadphaseCollision(btBroadphaseProxy *proxy0, btBroadphaseProxy *proxy1) const {
55 return GodotFilterCallback::test_collision_filters(proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask, proxy1->m_collisionFilterGroup, proxy1->m_collisionFilterMask);
56 }
57
needsCollision(btBroadphaseProxy * proxy0) const58 bool GodotClosestRayResultCallback::needsCollision(btBroadphaseProxy *proxy0) const {
59 const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask);
60 if (needs) {
61 btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject);
62 CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());
63
64 if (CollisionObjectBullet::TYPE_AREA == gObj->getType()) {
65 if (!collide_with_areas)
66 return false;
67 } else {
68 if (!collide_with_bodies)
69 return false;
70 }
71
72 if (m_pickRay && !gObj->is_ray_pickable()) {
73 return false;
74 }
75
76 if (m_exclude->has(gObj->get_self())) {
77 return false;
78 }
79
80 return true;
81 } else {
82 return false;
83 }
84 }
85
needsCollision(btBroadphaseProxy * proxy0) const86 bool GodotAllConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0) const {
87 if (count >= m_resultMax)
88 return false;
89
90 const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask);
91 if (needs) {
92 btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject);
93 CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());
94 if (m_exclude->has(gObj->get_self())) {
95 return false;
96 }
97
98 return true;
99 } else {
100 return false;
101 }
102 }
103
addSingleResult(btCollisionWorld::LocalConvexResult & convexResult,bool normalInWorldSpace)104 btScalar GodotAllConvexResultCallback::addSingleResult(btCollisionWorld::LocalConvexResult &convexResult, bool normalInWorldSpace) {
105 if (count >= m_resultMax)
106 return 1; // not used by bullet
107
108 CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(convexResult.m_hitCollisionObject->getUserPointer());
109
110 PhysicsDirectSpaceState::ShapeResult &result = m_results[count];
111
112 result.shape = convexResult.m_localShapeInfo->m_triangleIndex; // "m_triangleIndex" Is a odd name but contains the compound shape ID
113 result.rid = gObj->get_self();
114 result.collider_id = gObj->get_instance_id();
115 result.collider = 0 == result.collider_id ? NULL : ObjectDB::get_instance(result.collider_id);
116
117 ++count;
118 return 1; // not used by bullet
119 }
120
needsCollision(btBroadphaseProxy * proxy0) const121 bool GodotKinClosestConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0) const {
122 const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask);
123 if (needs) {
124 btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject);
125 CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());
126 if (gObj == m_self_object) {
127 return false;
128 } else {
129
130 // A kinematic body can't be stopped by a rigid body since the mass of kinematic body is infinite
131 if (m_infinite_inertia && !btObj->isStaticOrKinematicObject())
132 return false;
133
134 if (gObj->getType() == CollisionObjectBullet::TYPE_AREA)
135 return false;
136
137 if (m_self_object->has_collision_exception(gObj) || gObj->has_collision_exception(m_self_object))
138 return false;
139 }
140 return true;
141 } else {
142 return false;
143 }
144 }
145
needsCollision(btBroadphaseProxy * proxy0) const146 bool GodotClosestConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0) const {
147 const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask);
148 if (needs) {
149 btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject);
150 CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());
151
152 if (CollisionObjectBullet::TYPE_AREA == gObj->getType()) {
153 if (!collide_with_areas)
154 return false;
155 } else {
156 if (!collide_with_bodies)
157 return false;
158 }
159
160 if (m_exclude->has(gObj->get_self())) {
161 return false;
162 }
163 return true;
164 } else {
165 return false;
166 }
167 }
168
addSingleResult(btCollisionWorld::LocalConvexResult & convexResult,bool normalInWorldSpace)169 btScalar GodotClosestConvexResultCallback::addSingleResult(btCollisionWorld::LocalConvexResult &convexResult, bool normalInWorldSpace) {
170 if (convexResult.m_localShapeInfo)
171 m_shapeId = convexResult.m_localShapeInfo->m_triangleIndex; // "m_triangleIndex" Is a odd name but contains the compound shape ID
172 else
173 m_shapeId = 0;
174 return btCollisionWorld::ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace);
175 }
176
needsCollision(btBroadphaseProxy * proxy0) const177 bool GodotAllContactResultCallback::needsCollision(btBroadphaseProxy *proxy0) const {
178 if (m_count >= m_resultMax)
179 return false;
180
181 const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask);
182 if (needs) {
183 btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject);
184 CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());
185
186 if (CollisionObjectBullet::TYPE_AREA == gObj->getType()) {
187 if (!collide_with_areas)
188 return false;
189 } else {
190 if (!collide_with_bodies)
191 return false;
192 }
193
194 if (m_exclude->has(gObj->get_self())) {
195 return false;
196 }
197 return true;
198 } else {
199 return false;
200 }
201 }
202
addSingleResult(btManifoldPoint & cp,const btCollisionObjectWrapper * colObj0Wrap,int partId0,int index0,const btCollisionObjectWrapper * colObj1Wrap,int partId1,int index1)203 btScalar GodotAllContactResultCallback::addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1) {
204
205 if (m_count >= m_resultMax)
206 return cp.getDistance();
207
208 if (cp.getDistance() <= 0) {
209
210 PhysicsDirectSpaceState::ShapeResult &result = m_results[m_count];
211 // Penetrated
212
213 CollisionObjectBullet *colObj;
214 if (m_self_object == colObj0Wrap->getCollisionObject()) {
215 colObj = static_cast<CollisionObjectBullet *>(colObj1Wrap->getCollisionObject()->getUserPointer());
216 result.shape = cp.m_index1;
217 } else {
218 colObj = static_cast<CollisionObjectBullet *>(colObj0Wrap->getCollisionObject()->getUserPointer());
219 result.shape = cp.m_index0;
220 }
221
222 result.collider_id = colObj->get_instance_id();
223 result.collider = 0 == result.collider_id ? NULL : ObjectDB::get_instance(result.collider_id);
224 result.rid = colObj->get_self();
225 ++m_count;
226 }
227
228 return cp.getDistance();
229 }
230
needsCollision(btBroadphaseProxy * proxy0) const231 bool GodotContactPairContactResultCallback::needsCollision(btBroadphaseProxy *proxy0) const {
232 if (m_count >= m_resultMax)
233 return false;
234
235 const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask);
236 if (needs) {
237 btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject);
238 CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());
239
240 if (CollisionObjectBullet::TYPE_AREA == gObj->getType()) {
241 if (!collide_with_areas)
242 return false;
243 } else {
244 if (!collide_with_bodies)
245 return false;
246 }
247
248 if (m_exclude->has(gObj->get_self())) {
249 return false;
250 }
251 return true;
252 } else {
253 return false;
254 }
255 }
256
addSingleResult(btManifoldPoint & cp,const btCollisionObjectWrapper * colObj0Wrap,int partId0,int index0,const btCollisionObjectWrapper * colObj1Wrap,int partId1,int index1)257 btScalar GodotContactPairContactResultCallback::addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1) {
258 if (m_count >= m_resultMax)
259 return 1; // not used by bullet
260
261 if (m_self_object == colObj0Wrap->getCollisionObject()) {
262 B_TO_G(cp.m_localPointA, m_results[m_count * 2 + 0]); // Local contact
263 B_TO_G(cp.m_localPointB, m_results[m_count * 2 + 1]);
264 } else {
265 B_TO_G(cp.m_localPointB, m_results[m_count * 2 + 0]); // Local contact
266 B_TO_G(cp.m_localPointA, m_results[m_count * 2 + 1]);
267 }
268
269 ++m_count;
270
271 return 1; // Not used by bullet
272 }
273
needsCollision(btBroadphaseProxy * proxy0) const274 bool GodotRestInfoContactResultCallback::needsCollision(btBroadphaseProxy *proxy0) const {
275 const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask);
276 if (needs) {
277 btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject);
278 CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());
279
280 if (CollisionObjectBullet::TYPE_AREA == gObj->getType()) {
281 if (!collide_with_areas)
282 return false;
283 } else {
284 if (!collide_with_bodies)
285 return false;
286 }
287
288 if (m_exclude->has(gObj->get_self())) {
289 return false;
290 }
291 return true;
292 } else {
293 return false;
294 }
295 }
296
addSingleResult(btManifoldPoint & cp,const btCollisionObjectWrapper * colObj0Wrap,int partId0,int index0,const btCollisionObjectWrapper * colObj1Wrap,int partId1,int index1)297 btScalar GodotRestInfoContactResultCallback::addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1) {
298
299 if (cp.getDistance() <= m_min_distance) {
300 m_min_distance = cp.getDistance();
301
302 CollisionObjectBullet *colObj;
303 if (m_self_object == colObj0Wrap->getCollisionObject()) {
304 colObj = static_cast<CollisionObjectBullet *>(colObj1Wrap->getCollisionObject()->getUserPointer());
305 m_result->shape = cp.m_index1;
306 B_TO_G(cp.getPositionWorldOnB(), m_result->point);
307 B_TO_G(cp.m_normalWorldOnB, m_result->normal);
308 m_rest_info_bt_point = cp.getPositionWorldOnB();
309 m_rest_info_collision_object = colObj1Wrap->getCollisionObject();
310 } else {
311 colObj = static_cast<CollisionObjectBullet *>(colObj0Wrap->getCollisionObject()->getUserPointer());
312 m_result->shape = cp.m_index0;
313 B_TO_G(cp.m_normalWorldOnB * -1, m_result->normal);
314 m_rest_info_bt_point = cp.getPositionWorldOnA();
315 m_rest_info_collision_object = colObj0Wrap->getCollisionObject();
316 }
317
318 m_result->collider_id = colObj->get_instance_id();
319 m_result->rid = colObj->get_self();
320
321 m_collided = true;
322 }
323
324 return 1; // Not used by bullet
325 }
326
addContactPoint(const btVector3 & normalOnBInWorld,const btVector3 & pointInWorldOnB,btScalar depth)327 void GodotDeepPenetrationContactResultCallback::addContactPoint(const btVector3 &normalOnBInWorld, const btVector3 &pointInWorldOnB, btScalar depth) {
328
329 if (m_penetration_distance > depth) { // Has penetration?
330
331 const bool isSwapped = m_manifoldPtr->getBody0() != m_body0Wrap->getCollisionObject();
332 m_penetration_distance = depth;
333 m_other_compound_shape_index = isSwapped ? m_index0 : m_index1;
334 m_pointWorld = isSwapped ? (pointInWorldOnB + (normalOnBInWorld * depth)) : pointInWorldOnB;
335
336 m_pointNormalWorld = isSwapped ? normalOnBInWorld * -1 : normalOnBInWorld;
337 }
338 }
339