1
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <math.h>
5
6 #include <btBulletCollisionCommon.h>
7 #include <btBulletDynamicsCommon.h>
8 #include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
9 #include <BulletCollision/CollisionShapes/btCollisionShape.h>
10 #include <BulletDynamics/ConstraintSolver/btTypedConstraint.h>
11 #include <BulletCollision/CollisionDispatch/btGhostObject.h>
12 #include <BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h>
13 #include <BulletCollision/NarrowPhaseCollision/btRaycastCallback.h>
14
15 #include "../core/gl_util.h"
16 #include "../core/gl_font.h"
17 #include "../core/gl_text.h"
18 #include "../core/console.h"
19 #include "../core/vmath.h"
20 #include "../core/obb.h"
21 #include "../render/render.h"
22 #include "../script/script.h"
23 #include "../engine.h"
24 #include "../mesh.h"
25 #include "../skeletal_model.h"
26 #include "../character_controller.h"
27 #include "../entity.h"
28 #include "../resource.h"
29 #include "../room.h"
30 #include "../world.h"
31 #include "physics.h"
32 #include "ragdoll.h"
33 #include "hair.h"
34
35
36 /*
37 * INTERNAL BHYSICS CLASSES
38 */
39 class bt_engine_ClosestRayResultCallback : public btCollisionWorld::ClosestRayResultCallback
40 {
41 public:
bt_engine_ClosestRayResultCallback(engine_container_p cont,float from[3],float to[3],int16_t filter)42 bt_engine_ClosestRayResultCallback(engine_container_p cont, float from[3], float to[3], int16_t filter) :
43 btCollisionWorld::ClosestRayResultCallback(btVector3(from[0], from[1], from[2]), btVector3(to[0], to[1], to[2])),
44 m_cont(cont),
45 m_filter(filter)
46 {
47 m_collisionFilterGroup = btBroadphaseProxy::SensorTrigger;
48 m_collisionFilterMask = (filter & (COLLISION_GROUP_STATIC_OBLECT | COLLISION_GROUP_STATIC_ROOM)) ? (btBroadphaseProxy::StaticFilter) : 0x0000;
49 m_collisionFilterMask |= (filter & COLLISION_GROUP_KINEMATIC) ? (btBroadphaseProxy::KinematicFilter) : 0x0000;
50 m_collisionFilterMask |= (filter & (COLLISION_GROUP_CHARACTERS | COLLISION_GROUP_VEHICLE)) ? (btBroadphaseProxy::CharacterFilter) : 0x0000;
51 m_collisionFilterMask |= (filter & COLLISION_GROUP_DYNAMICS) ? (btBroadphaseProxy::DefaultFilter) : 0x0000;
52 }
53
addSingleResult(btCollisionWorld::LocalRayResult & rayResult,bool normalInWorldSpace)54 virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace) override
55 {
56 room_p r0 = NULL, r1 = NULL;
57 engine_container_p c1;
58
59 r0 = (m_cont) ? (m_cont->room) : (NULL);
60 c1 = (engine_container_p)rayResult.m_collisionObject->getUserPointer();
61 r1 = (c1) ? (c1->room) : (NULL);
62
63 if(c1 && (((c1->collision_group & m_filter) == 0x0000) || (c1 == m_cont)))
64 {
65 return 1.0f;
66 }
67
68 if(!r0 || !r1)
69 {
70 return ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace);
71 }
72
73 if(r0 && r1)
74 {
75 if(Room_IsInOverlappedRoomsList(r0, r1))
76 {
77 return 1.0f;
78 }
79 if(Room_IsInNearRoomsList(r0, r1))
80 {
81 if(m_cont->collision_heavy && (r0 != r1) && (!m_cont->sector || ((m_cont->sector->room_above != r1) && (m_cont->sector->room_below != r1))))
82 {
83 btVector3 pt = this->m_rayFromWorld.lerp(this->m_rayToWorld, rayResult.m_hitFraction);
84 room_sector_p ps0 = Room_GetSectorRaw(r1, m_cont->sector->pos);
85 room_sector_p ps1 = Room_GetSectorRaw(r0, pt.m_floats);
86 if((!ps0 || !ps1 || (ps0->portal_to_room != r0) || (ps1->portal_to_room != r1)) &&
87 (!ps0 || ((ps0->room_above != r0) && (ps0->room_below != r0))) &&
88 (!ps1 || ((ps1->room_above != r0) && (ps1->room_below != r0))))
89 {
90 return 1.0f;
91 }
92 }
93 return ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace);
94 }
95 }
96
97 return 1.0f;
98 }
99
100 engine_container_p m_cont;
101 int16_t m_filter;
102 };
103
104
105 class bt_engine_ClosestConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback
106 {
107 public:
bt_engine_ClosestConvexResultCallback(engine_container_p cont,float from[3],float to[3],int16_t filter)108 bt_engine_ClosestConvexResultCallback(engine_container_p cont, float from[3], float to[3], int16_t filter) :
109 btCollisionWorld::ClosestConvexResultCallback(btVector3(from[0], from[1], from[2]), btVector3(to[0], to[1], to[2])),
110 m_cont(cont),
111 m_filter(filter)
112 {
113 m_collisionFilterGroup = btBroadphaseProxy::SensorTrigger;
114 m_collisionFilterMask = (filter & (COLLISION_GROUP_STATIC_OBLECT | COLLISION_GROUP_STATIC_ROOM)) ? (btBroadphaseProxy::StaticFilter) : 0x0000;
115 m_collisionFilterMask |= (filter & COLLISION_GROUP_KINEMATIC) ? (btBroadphaseProxy::KinematicFilter) : 0x0000;
116 m_collisionFilterMask |= (filter & (COLLISION_GROUP_CHARACTERS | COLLISION_GROUP_VEHICLE)) ? (btBroadphaseProxy::CharacterFilter) : 0x0000;
117 m_collisionFilterMask |= (filter & COLLISION_GROUP_DYNAMICS) ? (btBroadphaseProxy::DefaultFilter) : 0x0000;
118 }
119
addSingleResult(btCollisionWorld::LocalConvexResult & convexResult,bool normalInWorldSpace)120 virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult &convexResult, bool normalInWorldSpace)
121 {
122 room_p r0 = NULL, r1 = NULL;
123 engine_container_p c1;
124
125 r0 = (m_cont)?(m_cont->room):(NULL);
126 c1 = (engine_container_p)convexResult.m_hitCollisionObject->getUserPointer();
127 r1 = (c1) ? (c1->room) : (NULL);
128
129 if(c1 && (((c1->collision_group & m_filter) == 0x0000) || (c1 == m_cont)))
130 {
131 return 1.0f;
132 }
133
134 if(!r0 || !r1)
135 {
136 return ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace);
137 }
138
139 if(r0 && r1)
140 {
141 if(Room_IsInOverlappedRoomsList(r0, r1))
142 {
143 return 1.0f;
144 }
145 if(Room_IsInNearRoomsList(r0, r1))
146 {
147 if(m_cont->collision_heavy && (r0 != r1) && (!m_cont->sector || ((m_cont->sector->room_above != r1) && (m_cont->sector->room_below != r1))))
148 {
149 room_sector_p ps0 = Room_GetSectorRaw(r1, m_cont->sector->pos);
150 room_sector_p ps1 = Room_GetSectorRaw(r0, convexResult.m_hitPointLocal.m_floats);
151 if((!ps0 || !ps1 || (ps0->portal_to_room != r0) || (ps1->portal_to_room != r1)) &&
152 (!ps0 || ((ps0->room_above != r0) && (ps0->room_below != r0))) &&
153 (!ps1 || ((ps1->room_above != r0) && (ps1->room_below != r0))))
154 {
155 return 1.0f;
156 }
157 }
158 return ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace);
159 }
160 }
161
162 return 1.0f;
163 }
164
165 private:
166 engine_container_p m_cont;
167 int16_t m_filter;
168 };
169
170
171 struct bt_engine_OverlapFilterCallback : public btOverlapFilterCallback
172 {
173 // return true when pairs need collision
needBroadphaseCollisionbt_engine_OverlapFilterCallback174 virtual bool needBroadphaseCollision(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) const
175 {
176 bool collides = (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) &&
177 (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask);
178
179 if(collides)
180 {
181 btCollisionObject *obj0 = (btCollisionObject*)proxy0->m_clientObject;
182 btCollisionObject *obj1 = (btCollisionObject*)proxy1->m_clientObject;
183 engine_container_p c0 = (engine_container_p)obj0->getUserPointer();
184 engine_container_p c1 = (engine_container_p)obj1->getUserPointer();;
185 room_p r0 = (c0) ? (c0->room) : (NULL);
186 room_p r1 = (c1) ? (c1->room) : (NULL);
187
188 int num_ghosts = (proxy0->m_collisionFilterGroup == btBroadphaseProxy::SensorTrigger) +
189 (proxy1->m_collisionFilterGroup == btBroadphaseProxy::SensorTrigger);
190
191 if(num_ghosts == 2)
192 {
193 return false;
194 }
195
196 if(c1 && c1 == c0) // No self interaction
197 {
198 return false;
199 }
200
201 if((c0 && c0->collision_group == COLLISION_GROUP_TRIGGERS && !obj1->isStaticOrKinematicObject()) ||
202 (c1 && c1->collision_group == COLLISION_GROUP_TRIGGERS && !obj0->isStaticOrKinematicObject()))
203 {
204 return false;
205 }
206
207 collides = ((!r0 && !r1) || (Room_IsInNearRoomsList(r0, r1) && !Room_IsInOverlappedRoomsList(r0, r1) &&
208 (num_ghosts || ((c0->collision_group & c1->collision_mask) && (c1->collision_group & c0->collision_mask)))));
209
210 if(collides && (r0 != r1) && c0 && c1 && (r0->content->overlapped_room_list || r1->content->overlapped_room_list || c0->collision_heavy || c1->collision_heavy))
211 {
212 if(c0->sector && c1->sector)
213 {
214 room_sector_p ps0 = Room_GetSectorRaw(r1, c0->sector->pos);
215 room_sector_p ps1 = Room_GetSectorRaw(r0, c1->sector->pos);
216 collides = (ps0 && ps1 && (ps0->portal_to_room == r0) && (ps1->portal_to_room == r1)) ||
217 (ps0 && ((ps0->room_above == r0) || (ps0->room_below == r0))) ||
218 (ps1 && ((ps1->room_above == r0) || (ps1->room_below == r0)));
219 }
220 else if(c0->sector && !c1->sector)
221 {
222 room_sector_p pc0 = Room_GetSectorRaw(r1, c0->sector->pos);
223 collides = pc0 && (pc0->portal_to_room == r0);
224 }
225 else if(!c0->sector && c1->sector)
226 {
227 room_sector_p pc1 = Room_GetSectorRaw(r0, c1->sector->pos);
228 collides = pc1 && (pc1->portal_to_room == r1);
229 }
230 }
231 }
232
233 return collides;
234 }
235 } bt_engine_overlap_filter_callback;
236
237
238 struct physics_object_s
239 {
240 btRigidBody *bt_body;
241 };
242
243 struct kinematic_info_s
244 {
245 bool has_collisions;
246 };
247
248 typedef struct physics_data_s
249 {
250 // kinematic
251 btRigidBody **bt_body;
252 struct kinematic_info_s *bt_info;
253
254 // dynamic
255 struct ghost_shape_s *ghosts_info;
256 btPairCachingGhostObject **ghost_objects; // like Bullet character controller for penetration resolving.
257 btManifoldArray *manifoldArray; // keep track of the contact manifolds
258 struct collision_node_s *collision_track;
259 uint16_t objects_count; // Ragdoll joints
260 uint16_t bt_joint_count; // Ragdoll joints
261 btTypedConstraint **bt_joints; // Ragdoll joints
262
263 int16_t collision_group;
264 int16_t collision_mask;
265 struct engine_container_s *cont;
266 }physics_data_t, *physics_data_p;
267
268
269 class CBulletDebugDrawer : public btIDebugDraw
270 {
271 public:
CBulletDebugDrawer()272 CBulletDebugDrawer() :
273 m_debugMode(0)
274 {
275 }
276
~CBulletDebugDrawer()277 ~CBulletDebugDrawer(){}
278
drawLine(const btVector3 & from,const btVector3 & to,const btVector3 & color)279 virtual void drawLine(const btVector3& from,const btVector3& to,const btVector3& color) override
280 {
281 renderer.debugDrawer->DrawLine(from.m_floats, to.m_floats, color.m_floats, color.m_floats);
282 }
283
drawLine(const btVector3 & from,const btVector3 & to,const btVector3 & fromColor,const btVector3 & toColor)284 virtual void drawLine(const btVector3& from,const btVector3& to, const btVector3& fromColor, const btVector3& toColor) override
285 {
286 renderer.debugDrawer->DrawLine(from.m_floats, to.m_floats, fromColor.m_floats, toColor.m_floats);
287 }
288
drawContactPoint(const btVector3 & PointOnB,const btVector3 & normalOnB,btScalar distance,int lifeTime,const btVector3 & color)289 virtual void drawContactPoint(const btVector3& PointOnB,const btVector3& normalOnB,btScalar distance,int lifeTime,const btVector3& color) override
290 {
291
292 }
293
reportErrorWarning(const char * warningString)294 virtual void reportErrorWarning(const char* warningString) override
295 {
296 Con_AddLine(warningString, FONTSTYLE_CONSOLE_WARNING);
297 }
298
draw3dText(const btVector3 & location,const char * textString)299 virtual void draw3dText(const btVector3& location, const char* textString) override
300 {
301 renderer.OutTextXYZ(location.m_floats[0], location.m_floats[1], location.m_floats[2], textString);
302 }
303
setDebugMode(int debugMode)304 virtual void setDebugMode(int debugMode) override
305 {
306 m_debugMode = debugMode;
307 }
308
getDebugMode() const309 virtual int getDebugMode() const override
310 {
311 return m_debugMode;
312 }
313
314 private:
315 int32_t m_debugMode;
316 };
317
318 btDefaultCollisionConfiguration *bt_engine_collisionConfiguration = NULL;
319 btCollisionDispatcher *bt_engine_dispatcher = NULL;
320 btGhostPairCallback *bt_engine_ghostPairCallback = NULL;
321 btBroadphaseInterface *bt_engine_overlappingPairCache = NULL;
322 btSequentialImpulseConstraintSolver *bt_engine_solver = NULL;
323 btDiscreteDynamicsWorld *bt_engine_dynamicsWorld = NULL;
324
325 CBulletDebugDrawer bt_debug_drawer;
326
327 /* bullet collision model calculation */
328 btCollisionShape* BT_CSfromBBox(btScalar *bb_min, btScalar *bb_max);
329 btCollisionShape* BT_CSfromMesh(struct base_mesh_s *mesh, bool useCompression, bool buildBvh, bool is_static = true);
330 btCollisionShape* BT_CSfromHeightmap(struct room_sector_s *heightmap, uint32_t sectors_count, struct sector_tween_s *tweens, uint32_t tweens_count, bool useCompression, bool buildBvh);
331
332 uint32_t BT_AddFloorAndCeilingToTrimesh(btTriangleMesh *trimesh, struct room_sector_s *sector);
333 uint32_t BT_AddSectorTweenToTrimesh(btTriangleMesh *trimesh, struct sector_tween_s *tween);
334
335 void Physics_DeleteRigidBody(struct physics_data_s *physics); // only for internal usage
336
getInnerBBRadius(btScalar bb_min[3],btScalar bb_max[3])337 btScalar getInnerBBRadius(btScalar bb_min[3], btScalar bb_max[3])
338 {
339 btScalar r = bb_max[0] - bb_min[0];
340 btScalar t = bb_max[1] - bb_min[1];
341 r = ((t > r) && (r != 0.0f)) ? (r) : (t);
342 t = bb_max[2] - bb_min[2];
343 return ((t > r) && (r != 0.0f)) ? (0.5f * r) : (0.5f * t);
344 }
345
346 // Bullet Physics initialization.
Physics_Init()347 void Physics_Init()
348 {
349 ///collision configuration contains default setup for memory, collision setup. Advanced users can create their own configuration.
350 bt_engine_collisionConfiguration = new btDefaultCollisionConfiguration();
351
352 ///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
353 bt_engine_dispatcher = new btCollisionDispatcher(bt_engine_collisionConfiguration);
354
355 ///btDbvtBroadphase is a good general purpose broadphase. You can also try out btAxis3Sweep.
356 bt_engine_overlappingPairCache = new btDbvtBroadphase();
357 bt_engine_ghostPairCallback = new btGhostPairCallback();
358 bt_engine_overlappingPairCache->getOverlappingPairCache()->setInternalGhostPairCallback(bt_engine_ghostPairCallback);
359
360 ///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded)
361 bt_engine_solver = new btSequentialImpulseConstraintSolver;
362
363 bt_engine_dynamicsWorld = new btDiscreteDynamicsWorld(bt_engine_dispatcher, bt_engine_overlappingPairCache, bt_engine_solver, bt_engine_collisionConfiguration);
364 bt_engine_dynamicsWorld->getPairCache()->setOverlapFilterCallback(&bt_engine_overlap_filter_callback);
365 bt_engine_dynamicsWorld->setGravity(btVector3(0, 0, -4500.0));
366
367 bt_debug_drawer.setDebugMode(btIDebugDraw::DBG_DrawWireframe | btIDebugDraw::DBG_DrawConstraints);
368 bt_engine_dynamicsWorld->setDebugDrawer(&bt_debug_drawer);
369 }
370
371
Physics_Destroy()372 void Physics_Destroy()
373 {
374 //delete dynamics world
375 delete bt_engine_dynamicsWorld;
376
377 //delete solver
378 delete bt_engine_solver;
379
380 //delete broadphase
381 delete bt_engine_overlappingPairCache;
382
383 //delete dispatcher
384 delete bt_engine_dispatcher;
385
386 delete bt_engine_collisionConfiguration;
387
388 delete bt_engine_ghostPairCallback;
389 }
390
391
Physics_StepSimulation(float time)392 void Physics_StepSimulation(float time)
393 {
394 time = (time < 0.1f) ? (time) : (0.0f);
395 bt_engine_dynamicsWorld->stepSimulation(time, 0);
396 }
397
Physics_DebugDrawWorld()398 void Physics_DebugDrawWorld()
399 {
400 bt_engine_dynamicsWorld->debugDrawWorld();
401 }
402
Physics_CleanUpObjects()403 void Physics_CleanUpObjects()
404 {
405 if(bt_engine_dynamicsWorld != NULL)
406 {
407 int num_obj = bt_engine_dynamicsWorld->getNumCollisionObjects();
408 for(int i = 0; i < num_obj; i++)
409 {
410 btCollisionObject* obj = bt_engine_dynamicsWorld->getCollisionObjectArray()[i];
411 btRigidBody* body = btRigidBody::upcast(obj);
412 if(body != NULL)
413 {
414 engine_container_p cont = (engine_container_p)body->getUserPointer();
415 body->setUserPointer(NULL);
416
417 if(cont && (cont->object_type == OBJECT_BULLET_MISC))
418 {
419 if(body->getMotionState())
420 {
421 delete body->getMotionState();
422 body->setMotionState(NULL);
423 }
424
425 if(body->getCollisionShape())
426 {
427 delete body->getCollisionShape();
428 body->setCollisionShape(NULL);
429 }
430
431 bt_engine_dynamicsWorld->removeRigidBody(body);
432 cont->room = NULL;
433 free(cont);
434 delete body;
435 }
436 }
437 }
438 }
439 }
440
Physics_CreatePhysicsData(struct engine_container_s * cont)441 struct physics_data_s *Physics_CreatePhysicsData(struct engine_container_s *cont)
442 {
443 struct physics_data_s *ret = (struct physics_data_s*)malloc(sizeof(struct physics_data_s));
444
445 ret->bt_body = NULL;
446 ret->bt_info = NULL;
447 ret->bt_joints = NULL;
448 ret->objects_count = 0;
449 ret->bt_joint_count = 0;
450 ret->manifoldArray = NULL;
451 ret->ghosts_info = NULL;
452 ret->ghost_objects = NULL;
453 ret->collision_track = NULL;
454 ret->collision_group = btBroadphaseProxy::KinematicFilter;
455 ret->collision_mask = btBroadphaseProxy::AllFilter;
456 ret->cont = cont;
457
458 return ret;
459 }
460
461
Physics_DeletePhysicsData(struct physics_data_s * physics)462 void Physics_DeletePhysicsData(struct physics_data_s *physics)
463 {
464 if(physics)
465 {
466 for(collision_node_p cn = physics->collision_track; cn;)
467 {
468 collision_node_p next = cn->next;
469 free(cn);
470 cn = next;
471 }
472 physics->collision_track = NULL;
473
474 if(physics->bt_info)
475 {
476 free(physics->bt_info);
477 physics->bt_info = NULL;
478 }
479
480 if(physics->bt_joints)
481 {
482 for(uint32_t i = 0; i < physics->bt_joint_count; i++)
483 {
484 if(physics->bt_joints[i])
485 {
486 bt_engine_dynamicsWorld->removeConstraint(physics->bt_joints[i]);
487 delete physics->bt_joints[i];
488 physics->bt_joints[i] = NULL;
489 }
490 }
491
492 free(physics->bt_joints);
493 physics->bt_joints = NULL;
494 physics->bt_joint_count = 0;
495 }
496
497 if(physics->ghost_objects)
498 {
499 for(int i = 0; i < physics->objects_count; i++)
500 {
501 physics->ghost_objects[i]->setUserPointer(NULL);
502 if(physics->ghost_objects[i]->getCollisionShape())
503 {
504 delete physics->ghost_objects[i]->getCollisionShape();
505 physics->ghost_objects[i]->setCollisionShape(NULL);
506 }
507 bt_engine_dynamicsWorld->removeCollisionObject(physics->ghost_objects[i]);
508 delete physics->ghost_objects[i];
509 physics->ghost_objects[i] = NULL;
510 }
511 free(physics->ghost_objects);
512 physics->ghost_objects = NULL;
513 }
514
515 if(physics->ghosts_info)
516 {
517 free(physics->ghosts_info);
518 physics->ghosts_info = NULL;
519 }
520
521 if(physics->manifoldArray)
522 {
523 physics->manifoldArray->clear();
524 delete physics->manifoldArray;
525 physics->manifoldArray = NULL;
526 }
527
528 Physics_DeleteRigidBody(physics);
529
530 physics->objects_count = 0;
531 free(physics);
532 }
533 }
534
535
536 /* Common physics functions */
Physics_GetGravity(float g[3])537 void Physics_GetGravity(float g[3])
538 {
539 btVector3 bt_g = bt_engine_dynamicsWorld->getGravity();
540 vec3_copy(g, bt_g.m_floats);
541 }
542
543
Physics_SetGravity(float g[3])544 void Physics_SetGravity(float g[3])
545 {
546 btVector3 bt_g(g[0], g[1], g[2]);
547 bt_engine_dynamicsWorld->setGravity(bt_g);
548 }
549
550
Physics_RayTest(struct collision_result_s * result,float from[3],float to[3],struct engine_container_s * cont,int16_t filter)551 int Physics_RayTest(struct collision_result_s *result, float from[3], float to[3], struct engine_container_s *cont, int16_t filter)
552 {
553 bt_engine_ClosestRayResultCallback cb(cont, from, to, filter);
554 btVector3 vFrom(from[0], from[1], from[2]), vTo(to[0], to[1], to[2]);
555
556 if(result)
557 {
558 result->hit = 0x00;
559 result->obj = NULL;
560 result->fraction = 1.0f;
561 bt_engine_dynamicsWorld->rayTest(vFrom, vTo, cb);
562 if(cb.hasHit())
563 {
564 result->obj = (struct engine_container_s *)cb.m_collisionObject->getUserPointer();
565 result->hit = 0x01;
566 result->bone_num = cb.m_collisionObject->getUserIndex();
567 vec3_copy(result->normale, cb.m_hitNormalWorld.m_floats);
568 vFrom.setInterpolate3(vFrom, vTo, cb.m_closestHitFraction);
569 vec3_copy(result->point, vFrom.m_floats);
570 result->fraction = cb.m_closestHitFraction;
571 return 1;
572 }
573 }
574 else
575 {
576 bt_engine_dynamicsWorld->rayTest(vFrom, vTo, cb);
577 return cb.hasHit();
578 }
579
580 return 0;
581 }
582
583
Physics_RayTestFiltered(struct collision_result_s * result,float from[3],float to[3],struct engine_container_s * cont,int16_t filter)584 int Physics_RayTestFiltered(struct collision_result_s *result, float from[3], float to[3], struct engine_container_s *cont, int16_t filter)
585 {
586 bt_engine_ClosestRayResultCallback cb(cont, from, to, filter);
587 btVector3 vFrom(from[0], from[1], from[2]), vTo(to[0], to[1], to[2]);
588
589 cb.m_flags |= btTriangleRaycastCallback::kF_FilterBackfaces;
590 cb.m_flags |= btTriangleRaycastCallback::kF_KeepUnflippedNormal;
591
592 if(result)
593 {
594 result->hit = 0x00;
595 result->obj = NULL;
596 result->fraction = 1.0f;
597 bt_engine_dynamicsWorld->rayTest(vFrom, vTo, cb);
598 if(cb.hasHit())
599 {
600 result->obj = (struct engine_container_s *)cb.m_collisionObject->getUserPointer();
601 result->hit = 0x01;
602 result->bone_num = cb.m_collisionObject->getUserIndex();
603 vec3_copy(result->normale, cb.m_hitNormalWorld.m_floats);
604 vFrom.setInterpolate3(vFrom, vTo, cb.m_closestHitFraction);
605 vec3_copy(result->point, vFrom.m_floats);
606 result->fraction = cb.m_closestHitFraction;
607 return 1;
608 }
609 }
610 else
611 {
612 bt_engine_dynamicsWorld->rayTest(vFrom, vTo, cb);
613 return cb.hasHit();
614 }
615
616 return 0;
617 }
618
619
Physics_SphereTest(struct collision_result_s * result,float from[3],float to[3],float R,struct engine_container_s * cont,int16_t filter)620 int Physics_SphereTest(struct collision_result_s *result, float from[3], float to[3], float R, struct engine_container_s *cont, int16_t filter)
621 {
622 bt_engine_ClosestConvexResultCallback cb(cont, from, to, filter);
623 btVector3 vFrom(from[0], from[1], from[2]), vTo(to[0], to[1], to[2]);
624 btTransform tFrom, tTo;
625 btSphereShape sphere(R);
626
627 tFrom.setIdentity();
628 tFrom.setOrigin(vFrom);
629 tTo.setIdentity();
630 tTo.setOrigin(vTo);
631
632 if(result)
633 {
634 result->obj = NULL;
635 result->hit = 0x00;
636 result->fraction = 1.0f;
637 bt_engine_dynamicsWorld->convexSweepTest(&sphere, tFrom, tTo, cb);
638 if(cb.hasHit())
639 {
640 result->obj = (struct engine_container_s *)cb.m_hitCollisionObject->getUserPointer();
641 result->hit = 0x01;
642 result->bone_num = cb.m_hitCollisionObject->getUserIndex();
643 vec3_copy(result->normale, cb.m_hitNormalWorld.m_floats);
644 vec3_copy(result->point, cb.m_hitPointWorld.m_floats);
645 result->fraction = cb.m_closestHitFraction;
646 return 1;
647 }
648 }
649 else
650 {
651 bt_engine_dynamicsWorld->convexSweepTest(&sphere, tFrom, tTo, cb);
652 return cb.hasHit();
653 }
654
655 return 0;
656 }
657
658
Physics_IsBodyesInited(struct physics_data_s * physics)659 int Physics_IsBodyesInited(struct physics_data_s *physics)
660 {
661 return physics && physics->bt_body;
662 }
663
664
Physics_IsGhostsInited(struct physics_data_s * physics)665 int Physics_IsGhostsInited(struct physics_data_s *physics)
666 {
667 return physics && physics->ghost_objects;
668 }
669
Physics_GetBodiesCount(struct physics_data_s * physics)670 int Physics_GetBodiesCount(struct physics_data_s *physics)
671 {
672 return (physics) ? (physics->objects_count) : (0);
673 }
674
Physics_GetBodyWorldTransform(struct physics_data_s * physics,float tr[16],uint16_t index)675 void Physics_GetBodyWorldTransform(struct physics_data_s *physics, float tr[16], uint16_t index)
676 {
677 if(physics->bt_body[index])
678 {
679 physics->bt_body[index]->getWorldTransform().getOpenGLMatrix(tr);
680 }
681 }
682
683
Physics_SetBodyWorldTransform(struct physics_data_s * physics,float tr[16],uint16_t index)684 void Physics_SetBodyWorldTransform(struct physics_data_s *physics, float tr[16], uint16_t index)
685 {
686 if(physics->bt_body[index])
687 {
688 physics->bt_body[index]->getWorldTransform().setFromOpenGLMatrix(tr);
689 }
690 }
691
692
Physics_GetGhostWorldTransform(struct physics_data_s * physics,float tr[16],uint16_t index)693 void Physics_GetGhostWorldTransform(struct physics_data_s *physics, float tr[16], uint16_t index)
694 {
695 if(physics->ghost_objects && physics->ghost_objects[index])
696 {
697 float offset[3], pos[3];
698 offset[0] = -physics->ghosts_info[index].offset[0];
699 offset[1] = -physics->ghosts_info[index].offset[1];
700 offset[2] = -physics->ghosts_info[index].offset[2];
701 physics->ghost_objects[index]->getWorldTransform().getOpenGLMatrix(tr);
702 Mat4_vec3_mul_macro(pos, tr, offset);
703 vec3_copy(tr + 12, pos);
704 }
705 }
706
707
Physics_SetGhostWorldTransform(struct physics_data_s * physics,float tr[16],uint16_t index)708 void Physics_SetGhostWorldTransform(struct physics_data_s *physics, float tr[16], uint16_t index)
709 {
710 if(physics->ghost_objects && physics->ghost_objects[index])
711 {
712 btVector3 origin;
713 Mat4_vec3_mul_macro(origin.m_floats, tr, physics->ghosts_info[index].offset);
714 physics->ghost_objects[index]->getWorldTransform().setFromOpenGLMatrix(tr);
715 physics->ghost_objects[index]->getWorldTransform().setOrigin(origin);
716 }
717 }
718
719
Physics_GetGhostShapeInfo(struct physics_data_s * physics,uint16_t index)720 ghost_shape_p Physics_GetGhostShapeInfo(struct physics_data_s *physics, uint16_t index)
721 {
722 return physics->ghosts_info + index;
723 }
724
725
726 /**
727 * It is from bullet_character_controller
728 */
Physics_GetGhostCurrentCollision(struct physics_data_s * physics,uint16_t index,int16_t filter)729 collision_node_p Physics_GetGhostCurrentCollision(struct physics_data_s *physics, uint16_t index, int16_t filter)
730 {
731 // Here we must refresh the overlapping paircache as the penetrating movement itself or the
732 // previous recovery iteration might have used setWorldTransform and pushed us into an object
733 // that is not in the previous cache contents from the last timestep, as will happen if we
734 // are pushed into a new AABB overlap. Unhandled this means the next convex sweep gets stuck.
735 //
736 // Do this by calling the broadphase's setAabb with the moved AABB, this will update the broadphase
737 // paircache and the ghostobject's internal paircache at the same time. /BW
738
739 collision_node_p *cn = &(physics->collision_track);
740 btPairCachingGhostObject *ghost = physics->ghost_objects[index];
741 if(ghost && ghost->getBroadphaseHandle())
742 {
743 int num_pairs, manifolds_size;
744 btBroadphasePairArray &pairArray = ghost->getOverlappingPairCache()->getOverlappingPairArray();
745 btVector3 aabb_min, aabb_max;
746
747 ghost->getCollisionShape()->getAabb(ghost->getWorldTransform(), aabb_min, aabb_max);
748 bt_engine_dynamicsWorld->getBroadphase()->setAabb(ghost->getBroadphaseHandle(), aabb_min, aabb_max, bt_engine_dynamicsWorld->getDispatcher());
749 bt_engine_dynamicsWorld->getDispatcher()->dispatchAllCollisionPairs(ghost->getOverlappingPairCache(), bt_engine_dynamicsWorld->getDispatchInfo(), bt_engine_dynamicsWorld->getDispatcher());
750
751 num_pairs = pairArray.size();
752 for(int i = 0; i < num_pairs; i++)
753 {
754 // do not use commented code: it prevents to collision skips.
755 //btBroadphasePair &pair = pairArray[i];
756 //btBroadphasePair* collisionPair = bt_engine_dynamicsWorld->getPairCache()->findPair(pair.m_pProxy0,pair.m_pProxy1);
757 btBroadphasePair *collisionPair = &pairArray[i];
758 if(collisionPair && collisionPair->m_algorithm)
759 {
760 physics->manifoldArray->clear();
761 collisionPair->m_algorithm->getAllContactManifolds(*(physics->manifoldArray));
762 manifolds_size = physics->manifoldArray->size();
763 for(int j = 0; j < manifolds_size; j++)
764 {
765 btPersistentManifold* manifold = (*(physics->manifoldArray))[j];
766 btCollisionObject *obj = (btCollisionObject*)manifold->getBody0();
767 btScalar directionSign = btScalar(1.0);
768 if(obj == ghost)
769 {
770 obj = (btCollisionObject*)manifold->getBody1();
771 directionSign = btScalar(-1.0);
772 }
773
774 engine_container_p cont = (engine_container_p)obj->getUserPointer();
775 if(cont && (cont->collision_group & filter))
776 {
777 for(int k = 0; k < manifold->getNumContacts(); k++)
778 {
779 const btManifoldPoint&pt = manifold->getContactPoint(k);
780 btScalar dist = pt.getDistance();
781
782 if(dist < 0.0)
783 {
784 if(*cn == NULL)
785 {
786 *cn = (collision_node_p)malloc(sizeof(collision_node_t));
787 (*cn)->next = NULL;
788 }
789
790 (*cn)->obj = cont;
791 (*cn)->part_from = obj->getUserIndex();
792 (*cn)->part_self = i;
793 (*cn)->penetration[0] = pt.m_normalWorldOnB[0];
794 (*cn)->penetration[1] = pt.m_normalWorldOnB[1];
795 (*cn)->penetration[2] = pt.m_normalWorldOnB[2];
796 (*cn)->penetration[3] = dist * directionSign;
797 (*cn)->point[0] = pt.m_positionWorldOnA[0];
798 (*cn)->point[1] = pt.m_positionWorldOnA[1];
799 (*cn)->point[2] = pt.m_positionWorldOnA[2];
800
801 cn = &((*cn)->next);
802 }
803 }
804 }
805 }
806 }
807 }
808 physics->manifoldArray->clear();
809 }
810
811 if(*cn)
812 {
813 (*cn)->obj = NULL;
814 }
815
816 return physics->collision_track;
817 }
818
819
BT_CSfromBBox(btScalar * bb_min,btScalar * bb_max)820 btCollisionShape *BT_CSfromBBox(btScalar *bb_min, btScalar *bb_max)
821 {
822 obb_p obb = OBB_Create();
823 polygon_p p = obb->base_polygons;
824 btTriangleMesh *trimesh = new btTriangleMesh;
825 btVector3 v0, v1, v2;
826 btCollisionShape* ret;
827 int cnt = 0;
828
829 OBB_Rebuild(obb, bb_min, bb_max);
830 for(uint32_t i = 0; i < 6; i++, p++)
831 {
832 if(!Polygon_IsBroken(p))
833 {
834 for(uint32_t j = 1; j + 1 < p->vertex_count; j++)
835 {
836 vec3_copy(v0.m_floats, p->vertices[j + 1].position);
837 vec3_copy(v1.m_floats, p->vertices[j].position);
838 vec3_copy(v2.m_floats, p->vertices[0].position);
839 trimesh->addTriangle(v0, v1, v2, true);
840 }
841 cnt ++;
842 }
843 }
844
845 OBB_Delete(obb);
846
847 if(cnt == 0)
848 {
849 delete trimesh;
850 return NULL;
851 }
852
853 ret = new btConvexTriangleMeshShape(trimesh, true);
854
855 return ret;
856 }
857
858
BT_CSfromMesh(struct base_mesh_s * mesh,bool useCompression,bool buildBvh,bool is_static)859 btCollisionShape *BT_CSfromMesh(struct base_mesh_s *mesh, bool useCompression, bool buildBvh, bool is_static)
860 {
861 uint32_t cnt = 0;
862 polygon_p p;
863 btTriangleMesh *trimesh = new btTriangleMesh;
864 btCollisionShape* ret = NULL;
865 btVector3 v0, v1, v2;
866
867 p = mesh->polygons;
868 for(uint32_t i = 0; i < mesh->polygons_count; i++, p++)
869 {
870 if(!Polygon_IsBroken(p))
871 {
872 for(uint32_t j = 1; j + 1 < p->vertex_count; j++)
873 {
874 vec3_copy(v0.m_floats, p->vertices[j + 1].position);
875 vec3_copy(v1.m_floats, p->vertices[j].position);
876 vec3_copy(v2.m_floats, p->vertices[0].position);
877 trimesh->addTriangle(v0, v1, v2, true);
878 }
879 cnt ++;
880 }
881 }
882
883 if(cnt == 0)
884 {
885 delete trimesh;
886 return NULL;
887 }
888
889 if(is_static)
890 {
891 ret = new btBvhTriangleMeshShape(trimesh, useCompression, buildBvh);
892 }
893 else
894 {
895 ret = new btConvexTriangleMeshShape(trimesh, true);
896 }
897
898 return ret;
899 }
900
901
BT_AddFloorAndCeilingToTrimesh(btTriangleMesh * trimesh,struct room_sector_s * sector)902 uint32_t BT_AddFloorAndCeilingToTrimesh(btTriangleMesh *trimesh, struct room_sector_s *sector)
903 {
904 uint32_t cnt = 0;
905 float *v0, *v1, *v2, *v3;
906
907 v0 = sector->floor_corners[0];
908 v1 = sector->floor_corners[1];
909 v2 = sector->floor_corners[2];
910 v3 = sector->floor_corners[3];
911 if( (sector->floor_penetration_config != TR_PENETRATION_CONFIG_GHOST) &&
912 (sector->floor_penetration_config != TR_PENETRATION_CONFIG_WALL ) )
913 {
914 if( (sector->floor_diagonal_type == TR_SECTOR_DIAGONAL_TYPE_NONE) ||
915 (sector->floor_diagonal_type == TR_SECTOR_DIAGONAL_TYPE_NW ) )
916 {
917 if(sector->floor_penetration_config != TR_PENETRATION_CONFIG_DOOR_VERTICAL_A)
918 {
919 trimesh->addTriangle(btVector3(v3[0], v3[1], v3[2]),
920 btVector3(v2[0], v2[1], v2[2]),
921 btVector3(v0[0], v0[1], v0[2]),
922 true);
923 cnt++;
924 }
925
926 if(sector->floor_penetration_config != TR_PENETRATION_CONFIG_DOOR_VERTICAL_B)
927 {
928 trimesh->addTriangle(btVector3(v2[0], v2[1], v2[2]),
929 btVector3(v1[0], v1[1], v1[2]),
930 btVector3(v0[0], v0[1], v0[2]),
931 true);
932 cnt++;
933 }
934 }
935 else
936 {
937 if(sector->floor_penetration_config != TR_PENETRATION_CONFIG_DOOR_VERTICAL_A)
938 {
939 trimesh->addTriangle(btVector3(v3[0], v3[1], v3[2]),
940 btVector3(v2[0], v2[1], v2[2]),
941 btVector3(v1[0], v1[1], v1[2]),
942 true);
943 cnt++;
944 }
945
946 if(sector->floor_penetration_config != TR_PENETRATION_CONFIG_DOOR_VERTICAL_B)
947 {
948 trimesh->addTriangle(btVector3(v3[0], v3[1], v3[2]),
949 btVector3(v1[0], v1[1], v1[2]),
950 btVector3(v0[0], v0[1], v0[2]),
951 true);
952 cnt++;
953 }
954 }
955 }
956
957 v0 = sector->ceiling_corners[0];
958 v1 = sector->ceiling_corners[1];
959 v2 = sector->ceiling_corners[2];
960 v3 = sector->ceiling_corners[3];
961 if( (sector->ceiling_penetration_config != TR_PENETRATION_CONFIG_GHOST) &&
962 (sector->ceiling_penetration_config != TR_PENETRATION_CONFIG_WALL ) )
963 {
964 if( (sector->ceiling_diagonal_type == TR_SECTOR_DIAGONAL_TYPE_NONE) ||
965 (sector->ceiling_diagonal_type == TR_SECTOR_DIAGONAL_TYPE_NW ) )
966 {
967 if(sector->ceiling_penetration_config != TR_PENETRATION_CONFIG_DOOR_VERTICAL_A)
968 {
969 trimesh->addTriangle(btVector3(v0[0], v0[1], v0[2]),
970 btVector3(v2[0], v2[1], v2[2]),
971 btVector3(v3[0], v3[1], v3[2]),
972 true);
973 cnt++;
974 }
975
976 if(sector->ceiling_penetration_config != TR_PENETRATION_CONFIG_DOOR_VERTICAL_B)
977 {
978 trimesh->addTriangle(btVector3(v0[0], v0[1], v0[2]),
979 btVector3(v1[0], v1[1], v1[2]),
980 btVector3(v2[0], v2[1], v2[2]),
981 true);
982 cnt++;
983 }
984 }
985 else
986 {
987 if(sector->ceiling_penetration_config != TR_PENETRATION_CONFIG_DOOR_VERTICAL_A)
988 {
989 trimesh->addTriangle(btVector3(v0[0], v0[1], v0[2]),
990 btVector3(v1[0], v1[1], v1[2]),
991 btVector3(v3[0], v3[1], v3[2]),
992 true);
993 cnt++;
994 }
995
996 if(sector->ceiling_penetration_config != TR_PENETRATION_CONFIG_DOOR_VERTICAL_B)
997 {
998 trimesh->addTriangle(btVector3(v1[0], v1[1], v1[2]),
999 btVector3(v2[0], v2[1], v2[2]),
1000 btVector3(v3[0], v3[1], v3[2]),
1001 true);
1002 cnt++;
1003 }
1004 }
1005 }
1006
1007 return cnt;
1008 }
1009
1010
BT_AddSectorTweenToTrimesh(btTriangleMesh * trimesh,struct sector_tween_s * tween)1011 uint32_t BT_AddSectorTweenToTrimesh(btTriangleMesh *trimesh, struct sector_tween_s *tween)
1012 {
1013 uint32_t cnt = 0;
1014 float *v0, *v1, *v2, *v3;
1015
1016 if(tween->ceiling_tween_inverted == 0x00)
1017 {
1018 v0 = tween->ceiling_corners[0];
1019 v1 = tween->ceiling_corners[1];
1020 v2 = tween->ceiling_corners[2];
1021 v3 = tween->ceiling_corners[3];
1022 }
1023 else
1024 {
1025 v0 = tween->ceiling_corners[0];
1026 v1 = tween->ceiling_corners[3];
1027 v2 = tween->ceiling_corners[2];
1028 v3 = tween->ceiling_corners[1];
1029 }
1030
1031 switch(tween->ceiling_tween_type)
1032 {
1033 case TR_SECTOR_TWEEN_TYPE_2TRIANGLES:
1034 {
1035 btScalar t = fabs((tween->ceiling_corners[2][2] - tween->ceiling_corners[3][2]) /
1036 (tween->ceiling_corners[0][2] - tween->ceiling_corners[1][2]));
1037 t = 1.0 / (1.0 + t);
1038 btScalar o[3], t1 = 1.0 - t;
1039 vec3_interpolate_macro(o, v0, v2, t, t1);
1040
1041 trimesh->addTriangle(btVector3(v0[0], v0[1], v0[2]),
1042 btVector3(v1[0], v1[1], v1[2]),
1043 btVector3(o[0], o[1], o[2]),
1044 true);
1045 trimesh->addTriangle(btVector3(v3[0], v3[1], v3[2]),
1046 btVector3(v2[0], v2[1], v2[2]),
1047 btVector3(o[0], o[1], o[2]),
1048 true);
1049 cnt += 2;
1050 }
1051 break;
1052
1053 case TR_SECTOR_TWEEN_TYPE_TRIANGLE_LEFT:
1054 {
1055 trimesh->addTriangle(btVector3(v0[0], v0[1], v0[2]),
1056 btVector3(v1[0], v1[1], v1[2]),
1057 btVector3(v3[0], v3[1], v3[2]),
1058 true);
1059 cnt++;
1060 }
1061 break;
1062
1063 case TR_SECTOR_TWEEN_TYPE_TRIANGLE_RIGHT:
1064 {
1065 trimesh->addTriangle(btVector3(v1[0], v1[1], v1[2]),
1066 btVector3(v2[0], v2[1], v2[2]),
1067 btVector3(v3[0], v3[1], v3[2]),
1068 true);
1069 cnt++;
1070 }
1071 break;
1072
1073 case TR_SECTOR_TWEEN_TYPE_QUAD:
1074 {
1075 trimesh->addTriangle(btVector3(v0[0], v0[1], v0[2]),
1076 btVector3(v1[0], v1[1], v1[2]),
1077 btVector3(v3[0], v3[1], v3[2]),
1078 true);
1079 trimesh->addTriangle(btVector3(v1[0], v1[1], v1[2]),
1080 btVector3(v2[0], v2[1], v2[2]),
1081 btVector3(v3[0], v3[1], v3[2]),
1082 true);
1083 cnt += 2;
1084 }
1085 break;
1086 };
1087
1088 if(tween->floor_tween_inverted == 0x00)
1089 {
1090 v0 = tween->floor_corners[0];
1091 v1 = tween->floor_corners[1];
1092 v2 = tween->floor_corners[2];
1093 v3 = tween->floor_corners[3];
1094 }
1095 else
1096 {
1097 v0 = tween->floor_corners[0];
1098 v1 = tween->floor_corners[3];
1099 v2 = tween->floor_corners[2];
1100 v3 = tween->floor_corners[1];
1101 }
1102
1103 switch(tween->floor_tween_type)
1104 {
1105 case TR_SECTOR_TWEEN_TYPE_2TRIANGLES:
1106 {
1107 btScalar t = fabs((tween->floor_corners[2][2] - tween->floor_corners[3][2]) /
1108 (tween->floor_corners[0][2] - tween->floor_corners[1][2]));
1109 t = 1.0 / (1.0 + t);
1110 btScalar o[3], t1 = 1.0 - t;
1111 vec3_interpolate_macro(o, v0, v2, t, t1);
1112
1113 trimesh->addTriangle(btVector3(v0[0], v0[1], v0[2]),
1114 btVector3(v1[0], v1[1], v1[2]),
1115 btVector3(o[0], o[1], o[2]),
1116 true);
1117 trimesh->addTriangle(btVector3(v3[0], v3[1], v3[2]),
1118 btVector3(v2[0], v2[1], v2[2]),
1119 btVector3(o[0], o[1], o[2]),
1120 true);
1121 cnt += 2;
1122 }
1123 break;
1124
1125 case TR_SECTOR_TWEEN_TYPE_TRIANGLE_LEFT:
1126 {
1127 trimesh->addTriangle(btVector3(v0[0], v0[1], v0[2]),
1128 btVector3(v1[0], v1[1], v1[2]),
1129 btVector3(v3[0], v3[1], v3[2]),
1130 true);
1131 cnt++;
1132 }
1133 break;
1134
1135 case TR_SECTOR_TWEEN_TYPE_TRIANGLE_RIGHT:
1136 {
1137 trimesh->addTriangle(btVector3(v1[0], v1[1], v1[2]),
1138 btVector3(v2[0], v2[1], v2[2]),
1139 btVector3(v3[0], v3[1], v3[2]),
1140 true);
1141 cnt++;
1142 }
1143 break;
1144
1145 case TR_SECTOR_TWEEN_TYPE_QUAD:
1146 {
1147 trimesh->addTriangle(btVector3(v0[0], v0[1], v0[2]),
1148 btVector3(v1[0], v1[1], v1[2]),
1149 btVector3(v3[0], v3[1], v3[2]),
1150 true);
1151 trimesh->addTriangle(btVector3(v1[0], v1[1], v1[2]),
1152 btVector3(v2[0], v2[1], v2[2]),
1153 btVector3(v3[0], v3[1], v3[2]),
1154 true);
1155 cnt += 2;
1156 }
1157 break;
1158 };
1159
1160 return cnt;
1161 }
1162
1163
BT_CSfromHeightmap(struct room_sector_s * heightmap,uint32_t sectors_count,struct sector_tween_s * tweens,uint32_t tweens_count,bool useCompression,bool buildBvh)1164 btCollisionShape *BT_CSfromHeightmap(struct room_sector_s *heightmap, uint32_t sectors_count, struct sector_tween_s *tweens, uint32_t tweens_count, bool useCompression, bool buildBvh)
1165 {
1166 uint32_t cnt = 0;
1167 btTriangleMesh *trimesh = new btTriangleMesh;
1168 btCollisionShape* ret = NULL;
1169
1170 for(uint32_t i = 0; i < sectors_count; i++)
1171 {
1172 cnt += BT_AddFloorAndCeilingToTrimesh(trimesh, heightmap + i);
1173 }
1174
1175 for(uint32_t i = 0; i < tweens_count; i++)
1176 {
1177 cnt += BT_AddSectorTweenToTrimesh(trimesh, tweens + i);
1178 }
1179
1180 if(cnt == 0)
1181 {
1182 delete trimesh;
1183 return NULL;
1184 }
1185
1186 ret = new btBvhTriangleMeshShape(trimesh, useCompression, buildBvh);
1187 return ret;
1188 }
1189
1190 /*
1191 * =============================================================================
1192 */
1193
Physics_GenRigidBody(struct physics_data_s * physics,struct ss_bone_frame_s * bf)1194 void Physics_GenRigidBody(struct physics_data_s *physics, struct ss_bone_frame_s *bf)
1195 {
1196 btVector3 localInertia(0, 0, 0);
1197 btTransform startTransform;
1198 btCollisionShape *cshape = NULL;
1199
1200 Physics_DeleteRigidBody(physics);
1201 if(physics->bt_info)
1202 {
1203 free(physics->bt_info);
1204 physics->bt_info = NULL;
1205 }
1206
1207 switch(physics->cont->collision_shape)
1208 {
1209 case COLLISION_SHAPE_SINGLE_BOX:
1210 {
1211 physics->objects_count = 1;
1212 physics->bt_body = (btRigidBody**)malloc(physics->objects_count * sizeof(btRigidBody*));
1213 physics->bt_info = (struct kinematic_info_s*)malloc(physics->objects_count * sizeof(struct kinematic_info_s));
1214 physics->bt_info->has_collisions = true;
1215
1216 float hx = (bf->bb_max[0] - bf->bb_min[0]) * 0.5f;
1217 float hy = (bf->bb_max[1] - bf->bb_min[1]) * 0.5f;
1218 float hz = (bf->bb_max[2] - bf->bb_min[2]) * 0.5f;
1219 cshape = new btBoxShape(btVector3(hx, hy, hz));
1220 cshape->calculateLocalInertia(0.0, localInertia);
1221 cshape->setMargin(COLLISION_MARGIN_DEFAULT);
1222 startTransform.setIdentity();
1223 btDefaultMotionState* motionState = new btDefaultMotionState(startTransform);
1224 physics->bt_body[0] = new btRigidBody(0.0, motionState, cshape, localInertia);
1225 physics->bt_body[0]->setUserPointer(physics->cont);
1226 physics->bt_body[0]->setUserIndex(0);
1227 physics->bt_body[0]->setRestitution(1.0);
1228 physics->bt_body[0]->setFriction(1.0);
1229 bt_engine_dynamicsWorld->addRigidBody(physics->bt_body[0], btBroadphaseProxy::KinematicFilter, btBroadphaseProxy::AllFilter);
1230 }
1231 break;
1232
1233 case COLLISION_SHAPE_SINGLE_SPHERE:
1234 {
1235 physics->objects_count = 1;
1236 physics->bt_body = (btRigidBody**)malloc(physics->objects_count * sizeof(btRigidBody*));
1237 physics->bt_info = (struct kinematic_info_s*)malloc(physics->objects_count * sizeof(struct kinematic_info_s));
1238 physics->bt_info->has_collisions = true;
1239
1240 cshape = new btSphereShape(getInnerBBRadius(bf->bb_min, bf->bb_max));
1241 cshape->calculateLocalInertia(0.0, localInertia);
1242 cshape->setMargin(COLLISION_MARGIN_DEFAULT);
1243 startTransform.setIdentity();
1244 btDefaultMotionState* motionState = new btDefaultMotionState(startTransform);
1245 physics->bt_body[0] = new btRigidBody(0.0, motionState, cshape, localInertia);
1246 physics->bt_body[0]->setUserPointer(physics->cont);
1247 physics->bt_body[0]->setUserIndex(0);
1248 physics->bt_body[0]->setRestitution(1.0);
1249 physics->bt_body[0]->setFriction(1.0);
1250 bt_engine_dynamicsWorld->addRigidBody(physics->bt_body[0], btBroadphaseProxy::KinematicFilter, btBroadphaseProxy::AllFilter);
1251 }
1252 break;
1253
1254 default:
1255 {
1256 physics->objects_count = bf->bone_tag_count;
1257 physics->bt_body = (btRigidBody**)malloc(physics->objects_count * sizeof(btRigidBody*));
1258 physics->bt_info = (struct kinematic_info_s*)malloc(physics->objects_count * sizeof(struct kinematic_info_s));
1259
1260 for(uint32_t i = 0; i < physics->objects_count; i++)
1261 {
1262 base_mesh_p mesh = bf->bone_tags[i].mesh_base;
1263 cshape = NULL;
1264 physics->bt_info[i].has_collisions = false;
1265 switch(physics->cont->collision_shape)
1266 {
1267 case COLLISION_SHAPE_TRIMESH_CONVEX:
1268 cshape = BT_CSfromMesh(mesh, true, true, false);
1269 break;
1270
1271 case COLLISION_SHAPE_TRIMESH:
1272 cshape = BT_CSfromMesh(mesh, true, true, true);
1273 break;
1274
1275 case COLLISION_SHAPE_BOX:
1276 cshape = BT_CSfromBBox(mesh->bb_min, mesh->bb_max);
1277 break;
1278
1279 ///@TODO: add other shapes implementation; may be change default;
1280 default:
1281 cshape = BT_CSfromMesh(mesh, true, true, true);
1282 break;
1283 };
1284
1285 physics->bt_body[i] = NULL;
1286
1287 if(cshape)
1288 {
1289 physics->bt_info[i].has_collisions = true;
1290 cshape->calculateLocalInertia(0.0, localInertia);
1291 cshape->setMargin(COLLISION_MARGIN_DEFAULT);
1292
1293 startTransform.setIdentity();
1294 btDefaultMotionState* motionState = new btDefaultMotionState(startTransform);
1295 physics->bt_body[i] = new btRigidBody(0.0, motionState, cshape, localInertia);
1296 physics->bt_body[i]->setUserPointer(physics->cont);
1297 physics->bt_body[i]->setUserIndex(i);
1298 physics->bt_body[i]->setRestitution(1.0);
1299 physics->bt_body[i]->setFriction(1.0);
1300 bt_engine_dynamicsWorld->addRigidBody(physics->bt_body[i], btBroadphaseProxy::KinematicFilter, btBroadphaseProxy::AllFilter);
1301 }
1302 }
1303 }
1304 break;
1305 };
1306 }
1307
1308
Physics_DeleteRigidBody(struct physics_data_s * physics)1309 void Physics_DeleteRigidBody(struct physics_data_s *physics)
1310 {
1311 if(physics->bt_body)
1312 {
1313 for(int i = 0; i < physics->objects_count; i++)
1314 {
1315 btRigidBody *body = physics->bt_body[i];
1316 if(body)
1317 {
1318 body->setUserPointer(NULL);
1319 if(body->getMotionState())
1320 {
1321 delete body->getMotionState();
1322 body->setMotionState(NULL);
1323 }
1324 if(body->getCollisionShape())
1325 {
1326 delete body->getCollisionShape();
1327 body->setCollisionShape(NULL);
1328 }
1329
1330 bt_engine_dynamicsWorld->removeRigidBody(body);
1331 delete body;
1332 physics->bt_body[i] = NULL;
1333 }
1334 }
1335 free(physics->bt_body);
1336 physics->bt_body = NULL;
1337 }
1338 }
1339
1340
1341 /*
1342 * 80% boxes hack now is default, but may be rewritten;
1343 */
Physics_CreateGhosts(struct physics_data_s * physics,struct ss_bone_frame_s * bf,struct ghost_shape_s * shape_info)1344 void Physics_CreateGhosts(struct physics_data_s *physics, struct ss_bone_frame_s *bf, struct ghost_shape_s *shape_info)
1345 {
1346 if(physics->objects_count > 0)
1347 {
1348 btTransform tr;
1349 if(!physics->manifoldArray)
1350 {
1351 physics->manifoldArray = new btManifoldArray();
1352 }
1353
1354 switch(physics->cont->collision_shape)
1355 {
1356 case COLLISION_SHAPE_SINGLE_BOX:
1357 {
1358 physics->ghosts_info = (ghost_shape_p)malloc(sizeof(ghost_shape_t));
1359 physics->ghosts_info[0].shape_id = COLLISION_SHAPE_SINGLE_BOX;
1360 vec3_copy(physics->ghosts_info[0].bb_max, bf->bb_max);
1361 vec3_copy(physics->ghosts_info[0].bb_min, bf->bb_min);
1362 physics->ghosts_info[0].radius = getInnerBBRadius(bf->bb_min, bf->bb_max);
1363 vec3_set_zero(physics->ghosts_info[0].offset);
1364
1365 physics->ghost_objects = (btPairCachingGhostObject**)malloc(bf->bone_tag_count * sizeof(btPairCachingGhostObject*));
1366 physics->ghost_objects[0] = new btPairCachingGhostObject();
1367 physics->ghost_objects[0]->setIgnoreCollisionCheck(physics->bt_body[0], true);
1368 tr.setIdentity();
1369 physics->ghost_objects[0]->setWorldTransform(tr);
1370 physics->ghost_objects[0]->setUserPointer(physics->cont);
1371 physics->ghost_objects[0]->setUserIndex(-1);
1372
1373 float hx = (bf->bb_max[0] - bf->bb_min[0]) * 0.5f;
1374 float hy = (bf->bb_max[1] - bf->bb_min[1]) * 0.5f;
1375 float hz = (bf->bb_max[2] - bf->bb_min[2]) * 0.5f;
1376 physics->ghost_objects[0]->setCollisionShape(new btBoxShape(btVector3(hx, hy, hz)));
1377 physics->ghost_objects[0]->getCollisionShape()->setMargin(COLLISION_MARGIN_DEFAULT);
1378 bt_engine_dynamicsWorld->addCollisionObject(physics->ghost_objects[0], btBroadphaseProxy::SensorTrigger, btBroadphaseProxy::AllFilter & ~btBroadphaseProxy::SensorTrigger);
1379 }
1380 break;
1381
1382 case COLLISION_SHAPE_SINGLE_SPHERE:
1383 {
1384 physics->ghosts_info = (ghost_shape_p)malloc(sizeof(ghost_shape_t));
1385 physics->ghosts_info[0].shape_id = COLLISION_SHAPE_SINGLE_SPHERE;
1386 vec3_copy(physics->ghosts_info[0].bb_max, bf->bb_max);
1387 vec3_copy(physics->ghosts_info[0].bb_min, bf->bb_min);
1388 physics->ghosts_info[0].radius = getInnerBBRadius(bf->bb_min, bf->bb_max);
1389 vec3_set_zero(physics->ghosts_info[0].offset);
1390
1391 physics->ghost_objects = (btPairCachingGhostObject**)malloc(bf->bone_tag_count * sizeof(btPairCachingGhostObject*));
1392 physics->ghost_objects[0] = new btPairCachingGhostObject();
1393 physics->ghost_objects[0]->setIgnoreCollisionCheck(physics->bt_body[0], true);
1394 tr.setIdentity();
1395 physics->ghost_objects[0]->setWorldTransform(tr);
1396 physics->ghost_objects[0]->setUserPointer(physics->cont);
1397 physics->ghost_objects[0]->setUserIndex(-1);
1398 physics->ghost_objects[0]->setCollisionShape(new btSphereShape(physics->ghosts_info[0].radius));
1399 physics->ghost_objects[0]->getCollisionShape()->setMargin(COLLISION_MARGIN_DEFAULT);
1400 bt_engine_dynamicsWorld->addCollisionObject(physics->ghost_objects[0], btBroadphaseProxy::SensorTrigger, btBroadphaseProxy::AllFilter & ~btBroadphaseProxy::SensorTrigger);
1401 }
1402 break;
1403
1404 default:
1405 {
1406 physics->ghosts_info = (ghost_shape_p)malloc(bf->bone_tag_count * sizeof(ghost_shape_t));
1407 physics->ghost_objects = (btPairCachingGhostObject**)malloc(bf->bone_tag_count * sizeof(btPairCachingGhostObject*));
1408 for(uint32_t i = 0; i < physics->objects_count; i++)
1409 {
1410 ss_bone_tag_p b_tag = bf->bone_tags + i;
1411
1412 physics->ghost_objects[i] = new btPairCachingGhostObject();
1413 physics->ghost_objects[i]->setIgnoreCollisionCheck(physics->bt_body[i], true);
1414 tr.setIdentity();
1415 physics->ghost_objects[i]->setWorldTransform(tr);
1416 physics->ghost_objects[i]->setUserPointer(physics->cont);
1417 physics->ghost_objects[i]->setUserIndex(i);
1418 if(shape_info)
1419 {
1420 float hx = (shape_info[i].bb_max[0] - shape_info[i].bb_min[0]) * 0.5f;
1421 float hy = (shape_info[i].bb_max[1] - shape_info[i].bb_min[1]) * 0.5f;
1422 float hz = (shape_info[i].bb_max[2] - shape_info[i].bb_min[2]) * 0.5f;
1423 physics->ghosts_info[i] = shape_info[i];
1424 switch(shape_info[i].shape_id)
1425 {
1426 case COLLISION_SHAPE_BOX:
1427 physics->ghost_objects[i]->setCollisionShape(new btBoxShape(btVector3(hx, hy, hz)));
1428 break;
1429
1430 case COLLISION_SHAPE_SPHERE:
1431 physics->ghost_objects[i]->setCollisionShape(new btSphereShape(hx));
1432 break;
1433
1434 default:
1435 vec3_set_zero(physics->ghosts_info[i].offset);
1436 physics->ghost_objects[i]->setCollisionShape(BT_CSfromMesh(b_tag->mesh_base, true, true, false));
1437 break;
1438 };
1439 }
1440 else
1441 {
1442 physics->ghosts_info[i].shape_id = COLLISION_SHAPE_TRIMESH_CONVEX;
1443 vec3_copy(physics->ghosts_info[i].bb_max, b_tag->mesh_base->bb_max);
1444 vec3_copy(physics->ghosts_info[i].bb_min, b_tag->mesh_base->bb_min);
1445 vec3_set_zero(physics->ghosts_info[i].offset);
1446 physics->ghost_objects[i]->setCollisionShape(BT_CSfromMesh(b_tag->mesh_base, true, true, false));
1447 }
1448 physics->ghosts_info[i].radius = getInnerBBRadius(physics->ghosts_info[i].bb_min, physics->ghosts_info[i].bb_max);
1449 physics->ghost_objects[i]->getCollisionShape()->setMargin(COLLISION_MARGIN_DEFAULT);
1450 bt_engine_dynamicsWorld->addCollisionObject(physics->ghost_objects[i], btBroadphaseProxy::SensorTrigger, btBroadphaseProxy::AllFilter & ~btBroadphaseProxy::SensorTrigger);
1451 }
1452 }
1453 };
1454 }
1455 }
1456
1457
Physics_SetGhostCollisionShape(struct physics_data_s * physics,struct ss_bone_frame_s * bf,uint16_t index,struct ghost_shape_s * shape_info)1458 void Physics_SetGhostCollisionShape(struct physics_data_s *physics, struct ss_bone_frame_s *bf, uint16_t index, struct ghost_shape_s *shape_info)
1459 {
1460 if(physics->ghost_objects && (index < physics->objects_count) && physics->ghost_objects[index])
1461 {
1462 btCollisionShape *new_shape = NULL;
1463 float hx = (shape_info->bb_max[0] - shape_info->bb_min[0]) * 0.5f;
1464 float hy = (shape_info->bb_max[1] - shape_info->bb_min[1]) * 0.5f;
1465 float hz = (shape_info->bb_max[2] - shape_info->bb_min[2]) * 0.5f;
1466 shape_info->radius = getInnerBBRadius(shape_info->bb_min, shape_info->bb_max);
1467 if((hx <= 0.0f) || (hy <= 0.0f) || (hz <= 0.0f))
1468 {
1469 shape_info->shape_id = COLLISION_NONE;
1470 physics->ghosts_info[index].shape_id = COLLISION_NONE;
1471 }
1472
1473 switch(shape_info->shape_id)
1474 {
1475 case COLLISION_SHAPE_BOX:
1476 new_shape = new btBoxShape(btVector3(hx, hy, hz));
1477 break;
1478
1479 case COLLISION_SHAPE_SPHERE:
1480 new_shape = new btSphereShape(hx);
1481 break;
1482
1483 case COLLISION_SHAPE_TRIMESH:
1484 new_shape = BT_CSfromMesh(bf->bone_tags[index].mesh_base, true, true, false);
1485 break;
1486
1487 case COLLISION_NONE:
1488 bt_engine_dynamicsWorld->removeCollisionObject(physics->ghost_objects[index]);
1489 break;
1490 };
1491
1492 if(new_shape)
1493 {
1494 btCollisionShape *old_shape = physics->ghost_objects[index]->getCollisionShape();
1495 physics->ghosts_info[index] = *shape_info;
1496 physics->ghost_objects[index]->setCollisionShape(new_shape);
1497 physics->ghost_objects[index]->getCollisionShape()->setMargin(COLLISION_MARGIN_DEFAULT);
1498 if(!physics->ghost_objects[index]->getBroadphaseHandle())
1499 {
1500 bt_engine_dynamicsWorld->addCollisionObject(physics->ghost_objects[index], btBroadphaseProxy::SensorTrigger, btBroadphaseProxy::AllFilter & ~btBroadphaseProxy::SensorTrigger);
1501 }
1502 if(old_shape)
1503 {
1504 delete old_shape;
1505 }
1506 }
1507 }
1508 }
1509
1510
Physics_GenStaticMeshRigidBody(struct static_mesh_s * smesh)1511 void Physics_GenStaticMeshRigidBody(struct static_mesh_s *smesh)
1512 {
1513 btCollisionShape *cshape = NULL;
1514
1515 if(smesh->self->collision_group == COLLISION_NONE)
1516 {
1517 return;
1518 }
1519
1520 smesh->physics_body = NULL;
1521 switch(smesh->self->collision_shape)
1522 {
1523 case COLLISION_SHAPE_BOX:
1524 cshape = BT_CSfromBBox(smesh->cbb_min, smesh->cbb_max);
1525 break;
1526
1527 case COLLISION_SHAPE_BOX_BASE:
1528 cshape = BT_CSfromBBox(smesh->mesh->bb_min, smesh->mesh->bb_max);
1529 break;
1530
1531 case COLLISION_SHAPE_TRIMESH:
1532 cshape = BT_CSfromMesh(smesh->mesh, true, true, true);
1533 break;
1534
1535 case COLLISION_SHAPE_TRIMESH_CONVEX:
1536 cshape = BT_CSfromMesh(smesh->mesh, true, true, false);
1537 break;
1538
1539 default:
1540 cshape = NULL;
1541 break;
1542 };
1543
1544 if(cshape)
1545 {
1546 btVector3 localInertia(0, 0, 0);
1547 btTransform startTransform;
1548 startTransform.setFromOpenGLMatrix(smesh->transform);
1549 smesh->physics_body = (struct physics_object_s*)malloc(sizeof(struct physics_object_s));
1550 btDefaultMotionState* motionState = new btDefaultMotionState(startTransform);
1551 smesh->physics_body->bt_body = new btRigidBody(0.0, motionState, cshape, localInertia);
1552 cshape->setMargin(COLLISION_MARGIN_DEFAULT);
1553 smesh->physics_body->bt_body->setRestitution(1.0);
1554 smesh->physics_body->bt_body->setFriction(1.0);
1555 bt_engine_dynamicsWorld->addRigidBody(smesh->physics_body->bt_body, btBroadphaseProxy::StaticFilter, btBroadphaseProxy::AllFilter);
1556 smesh->physics_body->bt_body->setUserPointer(smesh->self);
1557 }
1558 }
1559
1560
Physics_GenRoomRigidBody(struct room_s * room,struct room_sector_s * heightmap,uint32_t sectors_count,struct sector_tween_s * tweens,int num_tweens)1561 struct physics_object_s* Physics_GenRoomRigidBody(struct room_s *room, struct room_sector_s *heightmap, uint32_t sectors_count, struct sector_tween_s *tweens, int num_tweens)
1562 {
1563 btCollisionShape *cshape = BT_CSfromHeightmap(heightmap, sectors_count, tweens, num_tweens, true, true);
1564 struct physics_object_s *ret = NULL;
1565
1566 if(cshape)
1567 {
1568 btVector3 localInertia(0, 0, 0);
1569 btTransform tr;
1570 tr.setFromOpenGLMatrix(room->transform);
1571 ret = (struct physics_object_s*)malloc(sizeof(struct physics_object_s));
1572 btDefaultMotionState* motionState = new btDefaultMotionState(tr);
1573 cshape->setMargin(COLLISION_MARGIN_DEFAULT);
1574 ret->bt_body = new btRigidBody(0.0, motionState, cshape, localInertia);
1575 bt_engine_dynamicsWorld->addRigidBody(ret->bt_body, btBroadphaseProxy::StaticFilter, btBroadphaseProxy::AllFilter);
1576 ret->bt_body->setUserPointer(room->self);
1577 ret->bt_body->setUserIndex(0);
1578 ret->bt_body->setRestitution(1.0);
1579 ret->bt_body->setFriction(1.0);
1580 }
1581
1582 return ret;
1583 }
1584
1585
Physics_SetOwnerObject(struct physics_object_s * obj,struct engine_container_s * self)1586 void Physics_SetOwnerObject(struct physics_object_s *obj, struct engine_container_s *self)
1587 {
1588 if(obj && obj->bt_body)
1589 {
1590 obj->bt_body->setUserPointer(self);
1591 }
1592 }
1593
1594
Physics_DeleteObject(struct physics_object_s * obj)1595 void Physics_DeleteObject(struct physics_object_s *obj)
1596 {
1597 if(obj)
1598 {
1599 obj->bt_body->setUserPointer(NULL);
1600 if(obj->bt_body->getMotionState())
1601 {
1602 delete obj->bt_body->getMotionState();
1603 obj->bt_body->setMotionState(NULL);
1604 }
1605 if(obj->bt_body->getCollisionShape())
1606 {
1607 delete obj->bt_body->getCollisionShape();
1608 obj->bt_body->setCollisionShape(NULL);
1609 }
1610
1611 bt_engine_dynamicsWorld->removeRigidBody(obj->bt_body);
1612 delete obj->bt_body;
1613 free(obj);
1614 }
1615 }
1616
1617
Physics_EnableObject(struct physics_object_s * obj)1618 void Physics_EnableObject(struct physics_object_s *obj)
1619 {
1620 if(obj->bt_body && !obj->bt_body->isInWorld())
1621 {
1622 bt_engine_dynamicsWorld->addRigidBody(obj->bt_body, btBroadphaseProxy::StaticFilter, btBroadphaseProxy::AllFilter);
1623 }
1624 }
1625
1626
Physics_DisableObject(struct physics_object_s * obj)1627 void Physics_DisableObject(struct physics_object_s *obj)
1628 {
1629 if(obj->bt_body && obj->bt_body->isInWorld())
1630 {
1631 bt_engine_dynamicsWorld->removeRigidBody(obj->bt_body);
1632 }
1633 }
1634
1635
1636 /**
1637 * This function enables collision for entity_p in all cases exept NULL models.
1638 * If collision models does not exists, function will create them;
1639 * @param ent - pointer to the entity.
1640 */
Physics_EnableCollision(struct physics_data_s * physics)1641 void Physics_EnableCollision(struct physics_data_s *physics)
1642 {
1643 if(physics->bt_body)
1644 {
1645 for(uint32_t i = 0; i < physics->objects_count; i++)
1646 {
1647 btRigidBody *b = physics->bt_body[i];
1648 if(b && physics->bt_info[i].has_collisions && !b->isInWorld())
1649 {
1650 bt_engine_dynamicsWorld->addRigidBody(b, physics->collision_group, physics->collision_mask);
1651 }
1652 if(physics->ghost_objects && physics->ghost_objects[i] &&
1653 (physics->ghosts_info[i].shape_id != COLLISION_NONE) &&
1654 !physics->ghost_objects[i]->getBroadphaseHandle())
1655 {
1656 bt_engine_dynamicsWorld->addCollisionObject(physics->ghost_objects[i], btBroadphaseProxy::SensorTrigger, btBroadphaseProxy::AllFilter & ~btBroadphaseProxy::SensorTrigger);
1657 }
1658 }
1659 }
1660 }
1661
1662
Physics_DisableCollision(struct physics_data_s * physics)1663 void Physics_DisableCollision(struct physics_data_s *physics)
1664 {
1665 if(physics->bt_body != NULL)
1666 {
1667 for(uint32_t i = 0; i < physics->objects_count; i++)
1668 {
1669 btRigidBody *b = physics->bt_body[i];
1670 if(b && b->isInWorld())
1671 {
1672 bt_engine_dynamicsWorld->removeRigidBody(b);
1673 }
1674
1675 if(physics->ghost_objects && physics->ghost_objects[i] &&
1676 physics->ghost_objects[i]->getBroadphaseHandle())
1677 {
1678 bt_engine_dynamicsWorld->removeCollisionObject(physics->ghost_objects[i]);
1679 }
1680 }
1681 }
1682 }
1683
1684
Physics_SetBoneCollision(struct physics_data_s * physics,int bone_index,int collision)1685 void Physics_SetBoneCollision(struct physics_data_s *physics, int bone_index, int collision)
1686 {
1687 if(physics->bt_body && (bone_index >= 0) && (bone_index < physics->objects_count))
1688 {
1689 btRigidBody *b = physics->bt_body[bone_index];
1690 physics->bt_info[bone_index].has_collisions = collision;
1691
1692 if(b && !collision && b->isInWorld())
1693 {
1694 bt_engine_dynamicsWorld->removeRigidBody(b);
1695 }
1696 }
1697 }
1698
1699
Physics_SetCollisionGroupAndMask(struct physics_data_s * physics,int16_t group,int16_t mask)1700 void Physics_SetCollisionGroupAndMask(struct physics_data_s *physics, int16_t group, int16_t mask)
1701 {
1702 if(physics->bt_body != NULL)
1703 {
1704 physics->collision_group = (group & (COLLISION_GROUP_STATIC_OBLECT | COLLISION_GROUP_STATIC_ROOM)) ? (btBroadphaseProxy::StaticFilter) : 0x0000;
1705 physics->collision_group |= (group & COLLISION_GROUP_KINEMATIC) ? (btBroadphaseProxy::KinematicFilter) : 0x0000;
1706 physics->collision_group |= (group & (COLLISION_GROUP_CHARACTERS | COLLISION_GROUP_VEHICLE)) ? (btBroadphaseProxy::CharacterFilter) : 0x0000;
1707 physics->collision_group |= (group & COLLISION_GROUP_DYNAMICS) ? (btBroadphaseProxy::DefaultFilter) : 0x0000;
1708
1709 physics->collision_mask = btBroadphaseProxy::SensorTrigger;
1710 physics->collision_mask |= (mask & (COLLISION_GROUP_STATIC_OBLECT | COLLISION_GROUP_STATIC_ROOM)) ? (btBroadphaseProxy::StaticFilter) : 0x0000;
1711 physics->collision_mask |= (mask & COLLISION_GROUP_KINEMATIC) ? (btBroadphaseProxy::KinematicFilter) : 0x0000;
1712 physics->collision_mask |= (mask & (COLLISION_GROUP_CHARACTERS | COLLISION_GROUP_VEHICLE)) ? (btBroadphaseProxy::CharacterFilter) : 0x0000;
1713 physics->collision_mask |= (mask & COLLISION_GROUP_DYNAMICS) ? (btBroadphaseProxy::DefaultFilter) : 0x0000;
1714 physics->collision_mask = (mask == COLLISION_MASK_ALL) ? (btBroadphaseProxy::AllFilter) : physics->collision_mask;
1715
1716 for(uint32_t i = 0; i < physics->objects_count; i++)
1717 {
1718 btRigidBody *b = physics->bt_body[i];
1719 if(b && b->getBroadphaseHandle())
1720 {
1721 b->getBroadphaseHandle()->m_collisionFilterGroup = physics->collision_group;
1722 b->getBroadphaseHandle()->m_collisionFilterMask = physics->collision_mask;
1723 }
1724 }
1725 }
1726 }
1727
1728
Physics_SetCollisionScale(struct physics_data_s * physics,float scaling[3])1729 void Physics_SetCollisionScale(struct physics_data_s *physics, float scaling[3])
1730 {
1731 for(int i = 0; i < physics->objects_count; i++)
1732 {
1733 bt_engine_dynamicsWorld->removeRigidBody(physics->bt_body[i]);
1734 physics->bt_body[i]->getCollisionShape()->setLocalScaling(btVector3(scaling[0], scaling[1], scaling[2]));
1735 bt_engine_dynamicsWorld->addRigidBody(physics->bt_body[i]);
1736
1737 physics->bt_body[i]->activate();
1738 }
1739 }
1740
1741
Physics_SetBodyMass(struct physics_data_s * physics,float mass,uint16_t index)1742 void Physics_SetBodyMass(struct physics_data_s *physics, float mass, uint16_t index)
1743 {
1744 btVector3 inertia (0.0, 0.0, 0.0);
1745 bt_engine_dynamicsWorld->removeRigidBody(physics->bt_body[index]);
1746
1747 physics->bt_body[index]->getCollisionShape()->calculateLocalInertia(mass, inertia);
1748
1749 physics->bt_body[index]->setMassProps(mass, inertia);
1750
1751 physics->bt_body[index]->updateInertiaTensor();
1752 physics->bt_body[index]->clearForces();
1753
1754 btVector3 factor = (mass > 0.0) ? (btVector3(1.0, 1.0, 1.0)) : (btVector3(0.0, 0.0, 0.0));
1755 physics->bt_body[index]->setLinearFactor (factor);
1756 physics->bt_body[index]->setAngularFactor(factor);
1757
1758 bt_engine_dynamicsWorld->addRigidBody(physics->bt_body[index]);
1759
1760 physics->bt_body[index]->activate();
1761 }
1762
1763
Physics_PushBody(struct physics_data_s * physics,float speed[3],uint16_t index)1764 void Physics_PushBody(struct physics_data_s *physics, float speed[3], uint16_t index)
1765 {
1766 physics->bt_body[index]->setLinearVelocity(btVector3(speed[0], speed[1], speed[2]));
1767 }
1768
1769
Physics_SetLinearFactor(struct physics_data_s * physics,float factor[3],uint16_t index)1770 void Physics_SetLinearFactor(struct physics_data_s *physics, float factor[3], uint16_t index)
1771 {
1772 physics->bt_body[index]->setLinearFactor(btVector3(factor[0], factor[1], factor[2]));
1773 }
1774
1775
1776 /* *****************************************************************************
1777 * ************************ HAIR DATA ****************************************
1778 * ****************************************************************************/
1779
1780 typedef struct hair_element_s
1781 {
1782 struct base_mesh_s *mesh; // Pointer to rendered mesh.
1783 btCollisionShape *shape; // Pointer to collision shape.
1784 btRigidBody *body; // Pointer to dynamic body.
1785 btGeneric6DofConstraint *joint; // Array of joints.
1786 }hair_element_t, *hair_element_p;
1787
1788
1789 typedef struct hair_s
1790 {
1791 engine_container_p container;
1792 uint32_t owner_body; // Owner entity's body ID.
1793
1794 uint8_t root_index; // Index of "root" element.
1795 uint8_t tail_index; // Index of "tail" element.
1796
1797 uint8_t element_count; // Overall amount of elements.
1798 hair_element_s *elements; // Array of elements.
1799
1800 uint8_t vertex_map_count;
1801 uint32_t *hair_vertex_map; // Hair vertex indices to link
1802 uint32_t *head_vertex_map; // Head vertex indices to link
1803
1804 }hair_t, *hair_p;
1805
1806
Hair_Create(struct hair_setup_s * setup,struct physics_data_s * physics)1807 struct hair_s *Hair_Create(struct hair_setup_s *setup, struct physics_data_s *physics)
1808 {
1809 // No setup or parent to link to - bypass function.
1810
1811 if(!physics || !setup || (setup->link_body >= physics->objects_count) ||
1812 !physics->bt_body[setup->link_body])
1813 {
1814 return NULL;
1815 }
1816
1817 skeletal_model_p model = World_GetModelByID(setup->model_id);
1818 if((!model) || (model->mesh_count == 0))
1819 {
1820 return NULL;
1821 }
1822
1823 // Setup engine container. FIXME: DOESN'T WORK PROPERLY ATM.
1824 struct hair_s *hair = (struct hair_s*)calloc(1, sizeof(struct hair_s));
1825 hair->container = Container_Create();
1826 hair->container->collision_group = COLLISION_GROUP_DYNAMICS_NI;
1827 hair->container->collision_mask = COLLISION_GROUP_STATIC_ROOM | COLLISION_GROUP_STATIC_OBLECT | COLLISION_GROUP_KINEMATIC | COLLISION_GROUP_CHARACTERS;
1828 hair->container->collision_shape = COLLISION_SHAPE_TRIMESH;
1829 hair->container->object_type = OBJECT_HAIR;
1830 hair->container->object = hair;
1831 hair->container->room = physics->cont->room;
1832
1833 // Setup initial hair parameters.
1834 hair->owner_body = setup->link_body; // Entity body to refer to.
1835
1836 // Setup initial position / angles.
1837 btTransform startTransform = physics->bt_body[hair->owner_body]->getWorldTransform();
1838 // Number of elements (bodies) is equal to number of hair meshes.
1839
1840 hair->element_count = model->mesh_count;
1841 hair->elements = (hair_element_p)calloc(hair->element_count, sizeof(hair_element_t));
1842
1843 // Root index should be always zero, as it is how engine determines that it is
1844 // connected to head and renders it properly. Tail index should be always the
1845 // last element of the hair, as it indicates absence of "child" constraint.
1846
1847 hair->root_index = 0;
1848 hair->tail_index = hair->element_count - 1;
1849
1850 // Weight step is needed to determine the weight of each hair body.
1851 // It is derived from root body weight and tail body weight.
1852
1853 btScalar weight_step = ((setup->root_weight - setup->tail_weight) / hair->element_count);
1854 btScalar current_weight = setup->root_weight;
1855
1856 for(uint32_t i = 0; i < hair->element_count; i++)
1857 {
1858 // Point to corresponding mesh.
1859
1860 hair->elements[i].mesh = model->mesh_tree[i].mesh_base;
1861
1862 // Begin creating ACTUAL physical hair mesh.
1863 btVector3 localInertia(0, 0, 0);
1864
1865 // Make collision shape out of mesh.
1866 hair->elements[i].shape = BT_CSfromMesh(hair->elements[i].mesh, true, true, false);
1867 hair->elements[i].shape->calculateLocalInertia((current_weight * setup->hair_inertia), localInertia);
1868 hair->elements[i].joint = NULL;
1869
1870 // Decrease next body weight to weight_step parameter.
1871 current_weight -= weight_step;
1872
1873 // Initialize motion state for body.
1874 btDefaultMotionState* motionState = new btDefaultMotionState(startTransform);
1875
1876 // Make rigid body.
1877 hair->elements[i].body = new btRigidBody(current_weight, motionState, hair->elements[i].shape, localInertia);
1878
1879 // Damping makes body stop in space by itself, to prevent it from continous movement.
1880 hair->elements[i].body->setDamping(setup->hair_damping[0], setup->hair_damping[1]);
1881
1882 // Restitution and friction parameters define "bounciness" and "dullness" of hair.
1883 hair->elements[i].body->setRestitution(setup->hair_restitution);
1884 hair->elements[i].body->setFriction(setup->hair_friction);
1885
1886 // Since hair is always moving with Lara, even if she's in still state (like, hanging
1887 // on a ledge), hair bodies shouldn't deactivate over time.
1888 hair->elements[i].body->forceActivationState(DISABLE_DEACTIVATION);
1889
1890 // Hair bodies must not collide with each other, and also collide ONLY with kinematic
1891 // bodies (e. g. animated meshes), or else Lara's ghost object or anything else will be able to
1892 // collide with hair!
1893 hair->elements[i].body->setUserPointer(hair->container);
1894 bt_engine_dynamicsWorld->addRigidBody(hair->elements[i].body, btBroadphaseProxy::DebrisFilter, btBroadphaseProxy::DefaultFilter | btBroadphaseProxy::StaticFilter | btBroadphaseProxy::KinematicFilter | btBroadphaseProxy::CharacterFilter);
1895
1896 hair->elements[i].body->activate();
1897 }
1898
1899 // GENERATE CONSTRAINTS.
1900 // All constraints are generic 6-DOF type, as they seem perfect fit for hair.
1901
1902 // If multiple joints per body is specified, joints are placed in circular manner,
1903 // with obvious step of (SIMD_2_PI) / joint count. It means that all joints will form
1904 // circle-like figure.
1905
1906 for(uint32_t i = 0; i < hair->element_count; i++)
1907 {
1908 btRigidBody* prev_body;
1909 btScalar body_length;
1910
1911 // Each body width and height are used to calculate position of each joint.
1912
1913 //btScalar body_width = fabs(hair->elements[i].mesh->bb_max[0] - hair->elements[i].mesh->bb_min[0]);
1914 //btScalar body_depth = fabs(hair->elements[i].mesh->bb_max[3] - hair->elements[i].mesh->bb_min[3]);
1915
1916 btTransform localA; localA.setIdentity();
1917 btTransform localB; localB.setIdentity();
1918
1919 btScalar joint_x = 0.0;
1920 btScalar joint_y = 0.0;
1921
1922 if(i == 0) // First joint group
1923 {
1924 // Adjust pivot point A to parent body.
1925 localA.setOrigin(btVector3(setup->head_offset[0] + joint_x, setup->head_offset[1], setup->head_offset[2] + joint_y));
1926 localA.getBasis().setEulerZYX(setup->root_angle[0], setup->root_angle[1], setup->root_angle[2]);
1927
1928 localB.setOrigin(btVector3(joint_x, 0.0, joint_y));
1929 localB.getBasis().setEulerZYX(0,-SIMD_HALF_PI,0);
1930
1931 prev_body = physics->bt_body[hair->owner_body]; // Previous body is parent body.
1932 }
1933 else
1934 {
1935 // Adjust pivot point A to previous mesh's length, considering mesh overlap multiplier.
1936
1937 body_length = fabs(hair->elements[i-1].mesh->bb_max[1] - hair->elements[i-1].mesh->bb_min[1]) * setup->joint_overlap;
1938
1939 localA.setOrigin(btVector3(joint_x, body_length, joint_y));
1940 localA.getBasis().setEulerZYX(0,SIMD_HALF_PI,0);
1941
1942 // Pivot point B is automatically adjusted by Bullet.
1943
1944 localB.setOrigin(btVector3(joint_x, 0.0, joint_y));
1945 localB.getBasis().setEulerZYX(0,SIMD_HALF_PI,0);
1946
1947 prev_body = hair->elements[i-1].body; // Previous body is preceiding hair mesh.
1948 }
1949
1950 // Create 6DOF constraint.
1951 hair->elements[i].joint = new btGeneric6DofConstraint(*prev_body, *(hair->elements[i].body), localA, localB, true);
1952
1953 // CFM and ERP parameters are critical for making joint "hard" and link
1954 // to Lara's head. With wrong values, constraints may become "elastic".
1955 for(int axis = 0; axis <= 5; axis++)
1956 {
1957 hair->elements[i].joint->setParam(BT_CONSTRAINT_STOP_CFM, setup->joint_cfm, axis);
1958 hair->elements[i].joint->setParam(BT_CONSTRAINT_STOP_ERP, setup->joint_erp, axis);
1959 }
1960
1961 if(i == 0)
1962 {
1963 // First joint group should be more limited in motion, as it is connected
1964 // right to the head. NB: Should we make it scriptable as well?
1965 hair->elements[i].joint->setLinearLowerLimit(btVector3(0., 0., 0.));
1966 hair->elements[i].joint->setLinearUpperLimit(btVector3(0., 0., 0.));
1967 hair->elements[i].joint->setAngularLowerLimit(btVector3(-SIMD_HALF_PI, 0., -SIMD_HALF_PI*0.4));
1968 hair->elements[i].joint->setAngularUpperLimit(btVector3(-SIMD_HALF_PI*0.3, 0., SIMD_HALF_PI*0.4));
1969
1970 // Increased solver iterations make constraint even more stable.
1971 hair->elements[i].joint->setOverrideNumSolverIterations(100);
1972 }
1973 else
1974 {
1975 // Normal joint with more movement freedom.
1976 hair->elements[i].joint->setLinearLowerLimit(btVector3(0., 0., 0.));
1977 hair->elements[i].joint->setLinearUpperLimit(btVector3(0., 0., 0.));
1978 hair->elements[i].joint->setAngularLowerLimit(btVector3(-SIMD_HALF_PI*0.5, 0., -SIMD_HALF_PI*0.5));
1979 hair->elements[i].joint->setAngularUpperLimit(btVector3( SIMD_HALF_PI*0.5, 0., SIMD_HALF_PI*0.5));
1980 }
1981 hair->elements[i].joint->setDbgDrawSize(btScalar(5.f)); // Draw constraint axes.
1982
1983 // Add constraint to the world.
1984 bt_engine_dynamicsWorld->addConstraint(hair->elements[i].joint, true);
1985 }
1986
1987 return hair;
1988 }
1989
1990
Hair_Delete(struct hair_s * hair)1991 void Hair_Delete(struct hair_s *hair)
1992 {
1993 if(hair)
1994 {
1995 for(int i = 0; i < hair->element_count; i++)
1996 {
1997 if(hair->elements[i].joint)
1998 {
1999 bt_engine_dynamicsWorld->removeConstraint(hair->elements[i].joint);
2000 delete hair->elements[i].joint;
2001 hair->elements[i].joint = NULL;
2002 }
2003 }
2004
2005 for(int i = 0; i < hair->element_count; i++)
2006 {
2007 if(hair->elements[i].body)
2008 {
2009 hair->elements[i].body->setUserPointer(NULL);
2010 bt_engine_dynamicsWorld->removeRigidBody(hair->elements[i].body);
2011 delete hair->elements[i].body;
2012 hair->elements[i].body = NULL;
2013 }
2014 if(hair->elements[i].shape)
2015 {
2016 delete hair->elements[i].shape;
2017 hair->elements[i].shape = NULL;
2018 }
2019 }
2020 free(hair->elements);
2021 hair->elements = NULL;
2022 hair->element_count = 0;
2023
2024 hair->container = NULL;
2025 hair->owner_body = 0;
2026
2027 hair->root_index = 0;
2028 hair->tail_index = 0;
2029
2030 free(hair->container);
2031 hair->container = NULL;
2032
2033 free(hair);
2034 }
2035 }
2036
2037
Hair_Update(struct hair_s * hair,struct physics_data_s * physics)2038 void Hair_Update(struct hair_s *hair, struct physics_data_s *physics)
2039 {
2040 if(hair && (hair->element_count > 0))
2041 {
2042 hair->container->room = physics->cont->room;
2043 }
2044 }
2045
Hair_GetElementsCount(struct hair_s * hair)2046 int Hair_GetElementsCount(struct hair_s *hair)
2047 {
2048 return (hair)?(hair->element_count):(0);
2049 }
2050
Hair_GetElementInfo(struct hair_s * hair,int element,struct base_mesh_s ** mesh,float tr[16])2051 void Hair_GetElementInfo(struct hair_s *hair, int element, struct base_mesh_s **mesh, float tr[16])
2052 {
2053 hair->elements[element].body->getWorldTransform().getOpenGLMatrix(tr);
2054 *mesh = hair->elements[element].mesh;
2055 }
2056
2057
2058 /* *****************************************************************************
2059 * ************************ RAGDOLL DATA *************************************
2060 * ****************************************************************************/
2061
Ragdoll_Create(struct physics_data_s * physics,struct ss_bone_frame_s * bf,struct rd_setup_s * setup)2062 bool Ragdoll_Create(struct physics_data_s *physics, struct ss_bone_frame_s *bf, struct rd_setup_s *setup)
2063 {
2064 // No entity, setup or body count overflow - bypass function.
2065
2066 if(!physics || !setup || (setup->body_count > physics->objects_count))
2067 {
2068 return false;
2069 }
2070
2071 bool result = true;
2072
2073 // If ragdoll already exists, overwrite it with new one.
2074
2075 if(physics->bt_joint_count > 0)
2076 {
2077 result = Ragdoll_Delete(physics);
2078 }
2079
2080 // Setup bodies.
2081 physics->bt_joint_count = 0;
2082 // update current character animation and full fix body to avoid starting ragdoll partially inside the wall or floor...
2083 for(uint32_t i = 0; i < setup->body_count; i++)
2084 {
2085 if(physics->bt_body[i] == NULL)
2086 {
2087 result = false;
2088 continue; // If body is absent, return false and bypass this body setup.
2089 }
2090
2091 btVector3 inertia (0.0, 0.0, 0.0);
2092 btScalar mass = setup->body_setup[i].mass;
2093
2094 if(physics->bt_body[i]->isInWorld())
2095 {
2096 bt_engine_dynamicsWorld->removeRigidBody(physics->bt_body[i]);
2097 }
2098 physics->bt_body[i]->getCollisionShape()->calculateLocalInertia(mass, inertia);
2099 physics->bt_body[i]->setMassProps(mass, inertia);
2100
2101 physics->bt_body[i]->updateInertiaTensor();
2102 physics->bt_body[i]->clearForces();
2103
2104 physics->bt_body[i]->setLinearFactor (btVector3(1.0, 1.0, 1.0));
2105 physics->bt_body[i]->setAngularFactor(btVector3(1.0, 1.0, 1.0));
2106
2107 physics->bt_body[i]->setDamping(setup->body_setup[i].damping[0], setup->body_setup[i].damping[1]);
2108 physics->bt_body[i]->setRestitution(setup->body_setup[i].restitution);
2109 physics->bt_body[i]->setFriction(setup->body_setup[i].friction);
2110 physics->bt_body[i]->setSleepingThresholds(RD_DEFAULT_SLEEPING_THRESHOLD, RD_DEFAULT_SLEEPING_THRESHOLD);
2111
2112 if(bf->bone_tags[i].parent == NULL)
2113 {
2114 btScalar r = getInnerBBRadius(bf->bone_tags[i].mesh_base->bb_min, bf->bone_tags[i].mesh_base->bb_max);
2115 physics->bt_body[i]->setCcdMotionThreshold(0.8 * r);
2116 physics->bt_body[i]->setCcdSweptSphereRadius(r);
2117 }
2118 }
2119
2120 for(uint32_t i = 0; i < setup->body_count; i++)
2121 {
2122 bt_engine_dynamicsWorld->addRigidBody(physics->bt_body[i], btBroadphaseProxy::CharacterFilter, btBroadphaseProxy::CharacterFilter | btBroadphaseProxy::StaticFilter | btBroadphaseProxy::KinematicFilter);
2123 physics->bt_body[i]->activate();
2124 physics->bt_body[i]->setLinearVelocity(btVector3(0.0, 0.0, 0.0));
2125 }
2126
2127 // Setup constraints.
2128 physics->bt_joint_count = setup->joint_count;
2129 physics->bt_joints = (btTypedConstraint**)calloc(physics->bt_joint_count, sizeof(btTypedConstraint*));
2130
2131 for(int i = 0; i < physics->bt_joint_count; i++)
2132 {
2133 if( (setup->joint_setup[i].body_index >= setup->body_count) ||
2134 (physics->bt_body[setup->joint_setup[i].body_index] == NULL) )
2135 {
2136 result = false;
2137 break; // If body 1 or body 2 are absent, return false and bypass this joint.
2138 }
2139
2140 btTransform localA, localB;
2141 ss_bone_tag_p btB = bf->bone_tags + setup->joint_setup[i].body_index;
2142 ss_bone_tag_p btA = btB->parent;
2143 if(btA == NULL)
2144 {
2145 result = false;
2146 break;
2147 }
2148 #if 0
2149 localA.setFromOpenGLMatrix(btB->transform);
2150 localB.setIdentity();
2151 #else
2152 localA.getBasis().setEulerZYX(setup->joint_setup[i].body1_angle[0], setup->joint_setup[i].body1_angle[1], setup->joint_setup[i].body1_angle[2]);
2153 //localA.setOrigin(setup->joint_setup[i].body1_offset);
2154 localA.setOrigin(btVector3(btB->transform[12+0], btB->transform[12+1], btB->transform[12+2]));
2155
2156 localB.getBasis().setEulerZYX(setup->joint_setup[i].body2_angle[0], setup->joint_setup[i].body2_angle[1], setup->joint_setup[i].body2_angle[2]);
2157 //localB.setOrigin(setup->joint_setup[i].body2_offset);
2158 localB.setOrigin(btVector3(0.0, 0.0, 0.0));
2159 #endif
2160
2161 switch(setup->joint_setup[i].joint_type)
2162 {
2163 case RD_CONSTRAINT_POINT:
2164 {
2165 btPoint2PointConstraint* pointC = new btPoint2PointConstraint(*physics->bt_body[btA->index], *physics->bt_body[btB->index], localA.getOrigin(), localB.getOrigin());
2166 physics->bt_joints[i] = pointC;
2167 }
2168 break;
2169
2170 case RD_CONSTRAINT_HINGE:
2171 {
2172 btHingeConstraint* hingeC = new btHingeConstraint(*physics->bt_body[btA->index], *physics->bt_body[btB->index], localA, localB);
2173 hingeC->setLimit(setup->joint_setup[i].joint_limit[0], setup->joint_setup[i].joint_limit[1], 0.9, 0.3, 0.3);
2174 physics->bt_joints[i] = hingeC;
2175 }
2176 break;
2177
2178 case RD_CONSTRAINT_CONE:
2179 {
2180 btConeTwistConstraint* coneC = new btConeTwistConstraint(*physics->bt_body[btA->index], *physics->bt_body[btB->index], localA, localB);
2181 coneC->setLimit(setup->joint_setup[i].joint_limit[0], setup->joint_setup[i].joint_limit[1], setup->joint_setup[i].joint_limit[2], 0.9, 0.3, 0.7);
2182 physics->bt_joints[i] = coneC;
2183 }
2184 break;
2185 }
2186
2187 physics->bt_joints[i]->setParam(BT_CONSTRAINT_STOP_CFM, setup->joint_cfm, -1);
2188 physics->bt_joints[i]->setParam(BT_CONSTRAINT_STOP_ERP, setup->joint_erp, -1);
2189
2190 physics->bt_joints[i]->setDbgDrawSize(64.0);
2191 bt_engine_dynamicsWorld->addConstraint(physics->bt_joints[i], true);
2192 }
2193
2194 if(result == false)
2195 {
2196 Ragdoll_Delete(physics); // PARANOID: Clean up the mess, if something went wrong.
2197 }
2198
2199 physics->cont->collision_group = COLLISION_GROUP_DYNAMICS_NI;
2200
2201 return result;
2202 }
2203
2204
Ragdoll_Delete(struct physics_data_s * physics)2205 bool Ragdoll_Delete(struct physics_data_s *physics)
2206 {
2207 if(physics->bt_joint_count == 0)
2208 {
2209 return false;
2210 }
2211
2212 for(uint32_t i = 0; i < physics->bt_joint_count; i++)
2213 {
2214 if(physics->bt_joints[i])
2215 {
2216 bt_engine_dynamicsWorld->removeConstraint(physics->bt_joints[i]);
2217 delete physics->bt_joints[i];
2218 physics->bt_joints[i] = NULL;
2219 }
2220 }
2221
2222 for(uint32_t i = 0; i < physics->objects_count; i++)
2223 {
2224 if(physics->bt_body[i]->isInWorld())
2225 {
2226 bt_engine_dynamicsWorld->removeRigidBody(physics->bt_body[i]);
2227 }
2228 physics->bt_body[i]->setMassProps(0, btVector3(0.0, 0.0, 0.0));
2229 bt_engine_dynamicsWorld->addRigidBody(physics->bt_body[i], btBroadphaseProxy::KinematicFilter, btBroadphaseProxy::AllFilter);
2230 }
2231
2232 free(physics->bt_joints);
2233 physics->bt_joints = NULL;
2234 physics->bt_joint_count = 0;
2235 physics->cont->collision_group = COLLISION_GROUP_CHARACTERS;
2236
2237 return true;
2238
2239 // NB! Bodies remain in the same state!
2240 // To make them static again, additionally call setEntityBodyMass script function.
2241 }
2242