Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

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