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.

426 lines
13 KiB

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