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.

пре 11 година
пре 11 година
пре 11 година
пре 11 година
пре 11 година
пре 11 година
пре 11 година
пре 11 година
пре 12 година
пре 11 година
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  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 */