Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

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