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.
 
 
 

423 line
12 KiB

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