You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

419 lines
13 KiB

  1. //
  2. // LolPhysics
  3. //
  4. // Copyright: (c) 2009-2013 Benjamin "Touky" Huet <huet.benjamin@gmail.com>
  5. // (c) 2012 Sam Hocevar <sam@hocevar.net>
  6. //
  7. #pragma once
  8. #include <cstring>
  9. #include <bullet/btBulletDynamicsCommon.h>
  10. #include <bullet/btBulletCollisionCommon.h>
  11. #include <BulletDynamics/Character/btKinematicCharacterController.h>
  12. #include "lolbtphysicsintegration.h"
  13. #include "easyphysics.h"
  14. #include "easyconstraint.h"
  15. namespace lol
  16. {
  17. namespace phys
  18. {
  19. enum eRaycastType
  20. {
  21. ERT_Closest,
  22. ERT_AllHit,
  23. ERT_AnyHit, //Will stop at the first hit. Hit data are supposed to be irrelevant
  24. ERT_MAX
  25. };
  26. struct RayCastResult
  27. {
  28. RayCastResult(int CollisionFilterGroup=1, int CollisionFilterMask=(0xFF))
  29. {
  30. memset(this, 0, sizeof(RayCastResult));
  31. m_collision_filter_group = CollisionFilterGroup;
  32. m_collision_filter_mask = CollisionFilterMask;
  33. }
  34. void Reset()
  35. {
  36. m_collider_list.empty();
  37. m_hit_normal_list.empty();
  38. m_hit_point_list.empty();
  39. m_hit_fraction_list.empty();
  40. }
  41. array<EasyPhysic*> m_collider_list;
  42. array<vec3> m_hit_normal_list;
  43. array<vec3> m_hit_point_list;
  44. array<float> m_hit_fraction_list;
  45. short int m_collision_filter_group;
  46. short int m_collision_filter_mask;
  47. unsigned int m_flags; //???
  48. };
  49. class Simulation : public Entity
  50. {
  51. public:
  52. Simulation() :
  53. m_broadphase(0),
  54. m_collision_configuration(0),
  55. m_dispatcher(0),
  56. m_solver(0),
  57. m_dynamics_world(0),
  58. m_timestep(1.f/60.f)
  59. {
  60. m_gamegroup = GAMEGROUP_SIMULATION;
  61. }
  62. ~Simulation()
  63. {
  64. Exit();
  65. }
  66. char const *GetName() { return "<Simulation>"; }
  67. public:
  68. void Init()
  69. {
  70. // Build the broadphase
  71. if (1)
  72. {
  73. m_Sweep_broadphase = new btAxisSweep3(LOL2BT_VEC3(m_world_min), LOL2BT_VEC3(m_world_max));
  74. m_Sweep_broadphase->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback());
  75. m_broadphase = m_Sweep_broadphase;
  76. }
  77. else
  78. m_broadphase = new btDbvtBroadphase();
  79. // Set up the collision configuration and dispatcher
  80. m_collision_configuration = new btDefaultCollisionConfiguration();
  81. m_dispatcher = new btCollisionDispatcher(m_collision_configuration);
  82. // The actual physics solver
  83. m_solver = new btSequentialImpulseConstraintSolver;
  84. // The world.
  85. m_dynamics_world = new btDiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, m_collision_configuration);
  86. }
  87. virtual void TickGame(float seconds)
  88. {
  89. Entity::TickGame(seconds);
  90. //step the simulation
  91. if (m_dynamics_world)
  92. {
  93. //the "+1" is to have at least one Timestep and to ensure float to int .5f conversion.
  94. int steps = (int)(seconds / m_timestep) + 1;
  95. m_dynamics_world->stepSimulation(seconds, steps, m_timestep);
  96. }
  97. }
  98. //Rip-Off of the btKinematicClosestNotMeRayResultCallback
  99. class ClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback
  100. {
  101. public:
  102. ClosestNotMeRayResultCallback(btCollisionObject* Me, const btVector3& rayFromWorld, const btVector3& rayToWorld) :
  103. btCollisionWorld::ClosestRayResultCallback(rayFromWorld, rayToWorld)
  104. {
  105. m_me = Me;
  106. }
  107. virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace)
  108. {
  109. if (rayResult.m_collisionObject == m_me)
  110. return 1.0;
  111. return ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace);
  112. }
  113. protected:
  114. btCollisionObject* m_me;
  115. };
  116. //Will stop at the first hit. Hit data are supposed to be irrelevant
  117. class AnyHitRayResultCallback : public btCollisionWorld::ClosestRayResultCallback
  118. {
  119. public:
  120. AnyHitRayResultCallback(const btVector3& rayFromWorld, const btVector3& rayToWorld) :
  121. btCollisionWorld::ClosestRayResultCallback(rayFromWorld, rayToWorld)
  122. {
  123. }
  124. virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace)
  125. {
  126. UNUSED(rayResult);
  127. UNUSED(normalInWorldSpace);
  128. return .0f;
  129. }
  130. };
  131. //Returns true when hitting something. If SourceCaster is set, it will be ignored by Raycast.
  132. bool RayHits(RayCastResult& HitResult, eRaycastType RaycastType, const vec3& RayFrom, const vec3& RayTo, EasyPhysic* SourceCaster=NULL)
  133. {
  134. bool bResult = false;
  135. btCollisionWorld::RayResultCallback* BtRayResult = NULL;
  136. btCollisionWorld::ClosestRayResultCallback* BtRayResult_Closest;
  137. btCollisionWorld::AllHitsRayResultCallback* BtRayResult_AllHits;
  138. switch (RaycastType)
  139. {
  140. case ERT_Closest:
  141. {
  142. if (SourceCaster)
  143. BtRayResult_Closest = new ClosestNotMeRayResultCallback(SourceCaster->m_collision_object, LOL2BTU_VEC3(RayFrom), LOL2BTU_VEC3(RayTo));
  144. else
  145. BtRayResult_Closest = new btCollisionWorld::ClosestRayResultCallback(LOL2BTU_VEC3(RayFrom), LOL2BTU_VEC3(RayTo));
  146. BtRayResult = BtRayResult_Closest;
  147. break;
  148. }
  149. case ERT_AllHit:
  150. {
  151. BtRayResult_AllHits = new btCollisionWorld::AllHitsRayResultCallback(LOL2BTU_VEC3(RayFrom), LOL2BTU_VEC3(RayTo));
  152. BtRayResult = BtRayResult_AllHits;
  153. break;
  154. }
  155. case ERT_AnyHit:
  156. {
  157. BtRayResult_Closest = new AnyHitRayResultCallback(LOL2BTU_VEC3(RayFrom), LOL2BTU_VEC3(RayTo));
  158. BtRayResult = BtRayResult_Closest;
  159. break;
  160. }
  161. default:
  162. {
  163. ASSERT(0, "Raycast not handled");
  164. }
  165. }
  166. m_dynamics_world->rayTest(LOL2BTU_VEC3(RayFrom), LOL2BTU_VEC3(RayTo), *BtRayResult);
  167. if (BtRayResult->hasHit())
  168. {
  169. bResult = true;
  170. switch (RaycastType)
  171. {
  172. case ERT_Closest:
  173. {
  174. HitResult.m_collider_list << (EasyPhysic*)BtRayResult_Closest->m_collisionObject->getUserPointer();
  175. HitResult.m_hit_normal_list << BT2LOLU_VEC3(BtRayResult_Closest->m_hitNormalWorld);
  176. HitResult.m_hit_point_list << BT2LOLU_VEC3(BtRayResult_Closest->m_hitPointWorld);
  177. HitResult.m_hit_fraction_list << BtRayResult_Closest->m_closestHitFraction;
  178. break;
  179. }
  180. case ERT_AllHit:
  181. {
  182. for (int i = 0; i < BtRayResult_AllHits->m_collisionObjects.size(); i++)
  183. {
  184. HitResult.m_collider_list << (EasyPhysic*)BtRayResult_AllHits->m_collisionObjects[i]->getUserPointer();
  185. HitResult.m_hit_normal_list << BT2LOLU_VEC3(BtRayResult_AllHits->m_hitNormalWorld[i]);
  186. HitResult.m_hit_point_list << BT2LOLU_VEC3(BtRayResult_AllHits->m_hitPointWorld[i]);
  187. HitResult.m_hit_fraction_list << BtRayResult_AllHits->m_hitFractions[i];
  188. }
  189. break;
  190. }
  191. default:
  192. {
  193. ASSERT(0, "Raycast not handled");
  194. }
  195. }
  196. }
  197. delete BtRayResult;
  198. return bResult;
  199. }
  200. void Exit()
  201. {
  202. delete m_dynamics_world;
  203. delete m_solver;
  204. delete m_dispatcher;
  205. delete m_collision_configuration;
  206. delete m_broadphase;
  207. }
  208. btDiscreteDynamicsWorld* GetWorld()
  209. {
  210. return m_dynamics_world;
  211. }
  212. private:
  213. void CustomSetContinuousDetection(bool ShouldUseCCD)
  214. {
  215. if (m_dynamics_world)
  216. m_dynamics_world->getDispatchInfo().m_useContinuous = ShouldUseCCD;
  217. }
  218. void CustomSetGravity(vec3 &NewGravity)
  219. {
  220. if (m_dynamics_world)
  221. m_dynamics_world->setGravity(LOL2BT_VEC3(NewGravity * LOL2BT_UNIT));
  222. }
  223. void CustomSetWorldLimit(vec3 const &NewWorldMin, vec3 const &NewWorldMax)
  224. {
  225. UNUSED(NewWorldMin);
  226. UNUSED(NewWorldMax);
  227. }
  228. void CustomSetTimestep(float NewTimestep) { }
  229. //broadphase
  230. btBroadphaseInterface* m_broadphase;
  231. btAxisSweep3* m_Sweep_broadphase;
  232. // Set up the collision configuration and dispatc
  233. btDefaultCollisionConfiguration* m_collision_configuration;
  234. btCollisionDispatcher* m_dispatcher;
  235. // The actual physics solver
  236. btSequentialImpulseConstraintSolver* m_solver;
  237. // The world.
  238. btDiscreteDynamicsWorld* m_dynamics_world;
  239. public:
  240. //Main logic :
  241. //The Set*() functions do the all-lib-independent data storage.
  242. //And then it calls the CustomSet*() which are the specialized versions.
  243. //Sets the continuous collision detection flag.
  244. void SetContinuousDetection(bool ShouldUseCCD)
  245. {
  246. m_using_CCD = ShouldUseCCD;
  247. CustomSetContinuousDetection(ShouldUseCCD);
  248. }
  249. //Sets the simulation gravity.
  250. void SetGravity(vec3 &NewGravity)
  251. {
  252. m_gravity = NewGravity;
  253. CustomSetGravity(NewGravity);
  254. }
  255. //Sets the simulation gravity.
  256. void SetWorldLimit(vec3 const &NewWorldMin, vec3 const &NewWorldMax)
  257. {
  258. m_world_min = NewWorldMin;
  259. m_world_max = NewWorldMax;
  260. CustomSetWorldLimit(NewWorldMin, NewWorldMax);
  261. }
  262. //Sets the simulation fixed timestep.
  263. void SetTimestep(float NewTimestep)
  264. {
  265. if (NewTimestep > .0f)
  266. {
  267. m_timestep = NewTimestep;
  268. CustomSetTimestep(NewTimestep);
  269. }
  270. }
  271. private:
  272. friend class EasyPhysic;
  273. friend class EasyCharacterController;
  274. friend class EasyConstraint;
  275. enum eEasyPhysicType
  276. {
  277. EEPT_Dynamic,
  278. EEPT_Static,
  279. EEPT_Ghost,
  280. EEPT_CollisionObject,
  281. EEPT_CharacterController,
  282. EEPT_MAX
  283. };
  284. //m_owner_simulation
  285. //Adds the given EasyPhysic to the correct list.
  286. void ObjectRegistration(bool AddObject, EasyPhysic* NewEP, eEasyPhysicType CurType)
  287. {
  288. array<EasyPhysic*>* SearchList = NULL;
  289. switch(CurType)
  290. {
  291. case EEPT_Dynamic:
  292. {
  293. SearchList = &m_dynamic_list;
  294. break;
  295. }
  296. case EEPT_Static:
  297. {
  298. SearchList = &m_static_list;
  299. break;
  300. }
  301. case EEPT_Ghost:
  302. {
  303. SearchList = &m_ghost_list;
  304. break;
  305. }
  306. case EEPT_CollisionObject:
  307. {
  308. SearchList = &m_collision_object_list;
  309. break;
  310. }
  311. case EEPT_CharacterController:
  312. {
  313. SearchList = &m_character_controller_list;
  314. break;
  315. }
  316. default:
  317. {
  318. ASSERT(0, "Physic type does not exist.");
  319. }
  320. }
  321. if (AddObject)
  322. {
  323. NewEP->m_owner_simulation = this;
  324. (*SearchList) << NewEP;
  325. }
  326. else
  327. {
  328. NewEP->m_owner_simulation = NULL;
  329. SearchList->remove_item(NewEP);
  330. }
  331. }
  332. void ObjectRegistration(bool AddObject, EasyConstraint* NewEC)
  333. {
  334. array<EasyConstraint*>* SearchList = NULL;
  335. SearchList = &m_constraint_list;
  336. if (AddObject)
  337. {
  338. NewEC->m_owner_simulation = this;
  339. (*SearchList) << NewEC;
  340. }
  341. else
  342. {
  343. NewEC->m_owner_simulation = NULL;
  344. SearchList->remove_item(NewEC);
  345. }
  346. }
  347. //Easy Physics body List
  348. array<EasyPhysic*> m_dynamic_list;
  349. array<EasyPhysic*> m_static_list;
  350. array<EasyPhysic*> m_ghost_list;
  351. array<EasyPhysic*> m_collision_object_list;
  352. array<EasyPhysic*> m_character_controller_list;
  353. array<EasyConstraint*> m_constraint_list;
  354. //Easy Physics data storage
  355. float m_timestep;
  356. bool m_using_CCD;
  357. vec3 m_gravity;
  358. vec3 m_world_min;
  359. vec3 m_world_max;
  360. };
  361. } /* namespace phys */
  362. } /* namespace lol */