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.

431 lines
13 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright © 2010—2015 Sam Hocevar <sam@hocevar.net>
  5. // © 2009—2013 Cédric Lecacheur <jordx@free.fr>
  6. // © 2009—2013 Benjamin “Touky” Huet <huet.benjamin@gmail.com>
  7. //
  8. // This library is free software. It comes without any warranty, to
  9. // the extent permitted by applicable law. You can redistribute it
  10. // and/or modify it under the terms of the Do What the Fuck You Want
  11. // to Public License, Version 2, as published by the WTFPL Task Force.
  12. // See http://www.wtfpl.net/ for more details.
  13. //
  14. #if HAVE_CONFIG_H
  15. # include "config.h"
  16. #endif
  17. #include "lolbtphysicsintegration.h"
  18. #include "lolphysics.h"
  19. namespace lol
  20. {
  21. namespace phys
  22. {
  23. //-------------------------------------------------------------------------
  24. //EASY_PHYSIC
  25. //--
  26. EasyPhysic::EasyPhysic(WorldEntity* NewOwnerEntity) :
  27. m_collision_object(nullptr),
  28. m_ghost_object(nullptr),
  29. m_rigid_body(nullptr),
  30. m_local_inertia(btVector3(.0f, .0f, .0f)),
  31. m_collision_shape(nullptr),
  32. m_convex_shape(nullptr),
  33. m_motion_state(nullptr),
  34. m_mass(.0f),
  35. m_hit_restitution(.0f),
  36. m_collision_group(1),
  37. m_collision_mask(1),
  38. m_owner_entity(NewOwnerEntity),
  39. m_owner_simulation(nullptr),
  40. m_base_physic(nullptr)
  41. {
  42. }
  43. EasyPhysic::~EasyPhysic()
  44. {
  45. m_rigid_body = nullptr;
  46. delete m_collision_object;
  47. delete m_collision_shape;
  48. delete m_motion_state;
  49. }
  50. //-------------------------------------------------------------------------
  51. //Set Shape functions
  52. //--
  53. void EasyPhysic::SetShapeTo(btCollisionShape* collision_shape)
  54. {
  55. bool bReinitToRigidBody = false;
  56. if (m_rigid_body)
  57. {
  58. bReinitToRigidBody = true;
  59. delete m_rigid_body;
  60. }
  61. if (m_collision_shape)
  62. delete m_collision_shape;
  63. m_collision_shape = collision_shape;
  64. if (bReinitToRigidBody)
  65. InitBodyToRigid();
  66. }
  67. //Box Shape support
  68. void EasyPhysic::SetShapeToBox(lol::vec3& box_size)
  69. {
  70. vec3 new_box_size = box_size * LOL2BT_UNIT * LOL2BT_SIZE;
  71. m_convex_shape = new btBoxShape(LOL2BT_VEC3(new_box_size));
  72. SetShapeTo(m_convex_shape);
  73. }
  74. void EasyPhysic::SetShapeToSphere(float radius)
  75. {
  76. m_convex_shape = new btSphereShape(radius * LOL2BT_UNIT * LOL2BT_SIZE);
  77. SetShapeTo(m_convex_shape);
  78. }
  79. void EasyPhysic::SetShapeToCone(float radius, float height)
  80. {
  81. m_convex_shape = new btConeShape( radius * LOL2BT_UNIT,
  82. height * LOL2BT_UNIT);
  83. SetShapeTo(m_convex_shape);
  84. }
  85. void EasyPhysic::SetShapeToCylinder(lol::vec3& cyl_size)
  86. {
  87. vec3 new_cyl_size = cyl_size * LOL2BT_UNIT;
  88. new_cyl_size.y *= LOL2BT_SIZE;
  89. m_convex_shape = new btCylinderShape(LOL2BT_VEC3(new_cyl_size));
  90. SetShapeTo(m_convex_shape);
  91. }
  92. void EasyPhysic::SetShapeToCapsule(float radius, float height)
  93. {
  94. m_convex_shape = new btCapsuleShape(radius * LOL2BT_UNIT * LOL2BT_SIZE,
  95. height * LOL2BT_UNIT * LOL2BT_SIZE);
  96. SetShapeTo(m_convex_shape);
  97. }
  98. //-------------------------------------------------------------------------
  99. //Base Location/Rotation setup
  100. //--
  101. //Getter
  102. mat4 EasyPhysic::GetTransform()
  103. {
  104. m_local_to_world = lol::mat4(1.0f);
  105. if (m_rigid_body && m_motion_state)
  106. {
  107. btTransform CurTransform;
  108. m_motion_state->getWorldTransform(CurTransform);
  109. CurTransform.getOpenGLMatrix(&m_local_to_world[0][0]);
  110. }
  111. else if (m_collision_object)
  112. m_collision_object->getWorldTransform().getOpenGLMatrix(&m_local_to_world[0][0]);
  113. return m_local_to_world;
  114. }
  115. //Setter
  116. void EasyPhysic::SetTransform(const lol::vec3& base_location, const lol::quat& base_rotation)
  117. {
  118. lol::mat4 PreviousMatrix = m_local_to_world;
  119. m_local_to_world = lol::mat4::translate(base_location) * lol::mat4(base_rotation);
  120. if (m_ghost_object)
  121. m_ghost_object->setWorldTransform(btTransform(LOL2BT_QUAT(base_rotation), LOL2BT_VEC3(LOL2BT_UNIT * base_location)));
  122. else
  123. {
  124. if (m_motion_state)
  125. m_motion_state->setWorldTransform(btTransform(LOL2BT_QUAT(base_rotation), LOL2BT_VEC3(LOL2BT_UNIT * base_location)));
  126. else
  127. m_motion_state = new btDefaultMotionState(btTransform(LOL2BT_QUAT(base_rotation), LOL2BT_VEC3(LOL2BT_UNIT * base_location)));
  128. }
  129. for (int i = 0; i < m_based_physic_list.count(); i++)
  130. {
  131. if (m_based_physic_list[i])
  132. m_based_physic_list[i]->BaseTransformChanged(PreviousMatrix, m_local_to_world);
  133. else
  134. m_based_physic_list.remove(i--);
  135. }
  136. }
  137. //Internal callback when Base transform has changed.
  138. void EasyPhysic::BaseTransformChanged(const lol::mat4& PreviousMatrix, const lol::mat4& NewMatrix)
  139. {
  140. mat4 PreviousMatrixLoc = ((m_base_lock_location)?(PreviousMatrix):(lol::mat4::translate(PreviousMatrix[3].xyz)));
  141. mat4 PreviousMatrixRot = ((m_base_lock_rotation)?(lol::mat4(lol::quat(lol::mat3(PreviousMatrix)))):(lol::mat4(1.f)));
  142. mat4 NewMatrixLoc = ((m_base_lock_location)?(NewMatrix):(lol::mat4::translate(NewMatrix[3].xyz)));
  143. mat4 NewMatrixRot = ((m_base_lock_rotation)?(lol::mat4(lol::quat(lol::mat3(NewMatrix)))):(lol::mat4(1.f)));
  144. if (m_ghost_object || (m_rigid_body->getCollisionFlags() & btCollisionObject::CF_KINEMATIC_OBJECT))
  145. {
  146. mat4 ThisMatrixLoc = NewMatrixLoc * inverse(PreviousMatrixLoc) * lol::mat4::translate(m_local_to_world[3].xyz);
  147. mat4 ThisMatrixRot = NewMatrixRot * inverse(PreviousMatrixRot) * lol::mat4(lol::quat(lol::mat3(m_local_to_world)));
  148. SetTransform(ThisMatrixLoc[3].xyz, lol::quat(lol::mat3(ThisMatrixRot)));
  149. }
  150. }
  151. //-------------------------------------------------------------------------
  152. //Mass related functions
  153. //--
  154. //Set Mass functions
  155. void EasyPhysic::SetMass(float mass)
  156. {
  157. m_mass = mass;
  158. if (m_rigid_body)
  159. {
  160. SetLocalInertia(m_mass);
  161. m_rigid_body->setMassProps(m_mass, m_local_inertia);
  162. }
  163. }
  164. //-------------------------------------------------------------------------
  165. //Hit restitution functions
  166. //--
  167. //Set Hit Restitution functions
  168. void EasyPhysic::SetHitRestitution(float hit_restitution)
  169. {
  170. m_hit_restitution = hit_restitution;
  171. if (m_rigid_body)
  172. {
  173. m_rigid_body->setRestitution(m_hit_restitution);
  174. }
  175. }
  176. //-------------------------------------------------------------------------
  177. //Final conversion pass functions : Body related
  178. //--
  179. //Init to rigid body
  180. void EasyPhysic::InitBodyToRigid(bool SetToKinematic)
  181. {
  182. if (m_collision_object)
  183. delete m_collision_object;
  184. if (!m_motion_state)
  185. SetTransform(vec3(.0f));
  186. btRigidBody::btRigidBodyConstructionInfo NewInfos(m_mass, m_motion_state, m_collision_shape, m_local_inertia);
  187. NewInfos.m_restitution = m_hit_restitution;
  188. m_rigid_body = new btRigidBody(NewInfos);
  189. m_collision_object = m_rigid_body;
  190. m_collision_object->setUserPointer(this);
  191. if (m_mass == .0f)
  192. {
  193. if (SetToKinematic)
  194. {
  195. m_rigid_body->setActivationState(DISABLE_DEACTIVATION);
  196. m_rigid_body->setCollisionFlags(m_rigid_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
  197. }
  198. }
  199. else
  200. SetMass(m_mass);
  201. }
  202. //Return correct Ghost Object
  203. btGhostObject* EasyPhysic::GetGhostObjectInstance()
  204. {
  205. return new btGhostObject();
  206. }
  207. //Init to Ghost object, for Overlap/Sweep Test/Touching logic
  208. void EasyPhysic::InitBodyToGhost()
  209. {
  210. if (m_collision_object)
  211. delete m_collision_object;
  212. m_ghost_object = GetGhostObjectInstance();
  213. m_ghost_object->setCollisionShape(m_collision_shape);
  214. m_collision_object = m_ghost_object;
  215. m_collision_object->setUserPointer(this);
  216. SetTransform(m_local_to_world[3].xyz, lol::quat(lol::mat3(m_local_to_world)));
  217. m_ghost_object->setCollisionFlags(m_ghost_object->getCollisionFlags());
  218. }
  219. //-------------
  220. //Touch logic
  221. //-------------
  222. // btManifoldArray manifoldArray;
  223. // btBroadphasePairArray& pairArray = ghostObject->getOverlappingPairCache()->getOverlappingPairArray();
  224. // int numPairs = pairArray.size();
  225. // for (int i=0;i<numPairs;i++)
  226. // {
  227. // manifoldArray.clear();
  228. // const btBroadphasePair& pair = pairArray[i];
  229. //
  230. // //unless we manually perform collision detection on this pair, the contacts are in the dynamics world paircache:
  231. // btBroadphasePair* collisionPair = dynamicsWorld->getPairCache()->findPair(pair.m_pProxy0,pair.m_pProxy1);
  232. // if (!collisionPair)
  233. // continue;
  234. // if (collisionPair->m_algorithm)
  235. // collisionPair->m_algorithm->getAllContactManifolds(manifoldArray);
  236. // for (int j=0;j<manifoldArray.size();j++)
  237. // {
  238. // btPersistentManifold* manifold = manifoldArray[j];
  239. // btScalar directionSign = manifold->getBody0() == m_ghostObject ? btScalar(-1.0) : btScalar(1.0);
  240. // for (int p=0;p<manifold->getNumContacts();p++)
  241. // {
  242. // const btManifoldPoint&pt = manifold->getContactPoint(p);
  243. // if (pt.getDistance()<0.f)
  244. //{
  245. // const btVector3& ptA = pt.getPositionWorldOnA();
  246. // const btVector3& ptB = pt.getPositionWorldOnB();
  247. // const btVector3& normalOnB = pt.m_normalWorldOnB;
  248. // /// work here
  249. //}
  250. // }
  251. // }
  252. // }
  253. //Add Physic object to the simulation
  254. void EasyPhysic::AddToSimulation(class Simulation* current_simulation)
  255. {
  256. btDiscreteDynamicsWorld* dynamics_world = current_simulation->GetWorld();
  257. if (dynamics_world)
  258. {
  259. if (m_ghost_object)
  260. {
  261. dynamics_world->addCollisionObject(m_ghost_object, m_collision_group, m_collision_mask);
  262. current_simulation->ObjectRegistration(true, this, Simulation::EEPT_Ghost);
  263. }
  264. else if (m_rigid_body)
  265. {
  266. dynamics_world->addRigidBody(m_rigid_body, m_collision_group, m_collision_mask);
  267. if (m_mass != .0f)
  268. current_simulation->ObjectRegistration(true, this, Simulation::EEPT_Dynamic);
  269. else
  270. current_simulation->ObjectRegistration(true, this, Simulation::EEPT_Static);
  271. }
  272. else
  273. {
  274. dynamics_world->addCollisionObject(m_collision_object, m_collision_group, m_collision_mask);
  275. current_simulation->ObjectRegistration(true, this, Simulation::EEPT_CollisionObject);
  276. }
  277. }
  278. }
  279. //Remove Physic object to the simulation
  280. void EasyPhysic::RemoveFromSimulation(class Simulation* current_simulation)
  281. {
  282. btDiscreteDynamicsWorld* dynamics_world = current_simulation->GetWorld();
  283. if (dynamics_world)
  284. {
  285. if (m_rigid_body)
  286. {
  287. dynamics_world->removeRigidBody(m_rigid_body);
  288. if (m_mass != .0f)
  289. current_simulation->ObjectRegistration(false, this, Simulation::EEPT_Dynamic);
  290. else
  291. current_simulation->ObjectRegistration(false, this, Simulation::EEPT_Static);
  292. }
  293. else
  294. {
  295. dynamics_world->removeCollisionObject(m_collision_object);
  296. if (m_ghost_object)
  297. current_simulation->ObjectRegistration(false, this, Simulation::EEPT_Ghost);
  298. current_simulation->ObjectRegistration(false, this, Simulation::EEPT_CollisionObject);
  299. }
  300. }
  301. }
  302. //-------------------------------------------------------------------------
  303. //Force/Impulse functions
  304. //--
  305. void EasyPhysic::AddImpulse(const lol::vec3& impulse)
  306. {
  307. if (m_rigid_body)
  308. m_rigid_body->applyCentralImpulse(LOL2BT_VEC3(impulse));
  309. }
  310. void EasyPhysic::AddImpulse(const lol::vec3& impulse, const lol::vec3& rel_pos)
  311. {
  312. if (m_rigid_body)
  313. m_rigid_body->applyImpulse(LOL2BT_VEC3(impulse), LOL2BTU_VEC3(rel_pos));
  314. }
  315. void EasyPhysic::AddImpulseTorque(const lol::vec3& torque)
  316. {
  317. if (m_rigid_body)
  318. m_rigid_body->applyTorqueImpulse(LOL2BT_VEC3(torque));
  319. }
  320. //--
  321. void EasyPhysic::AddForce(const lol::vec3& force)
  322. {
  323. if (m_rigid_body)
  324. m_rigid_body->applyCentralForce(LOL2BT_VEC3(force));
  325. }
  326. void EasyPhysic::AddForce(const lol::vec3& force, const lol::vec3& rel_pos)
  327. {
  328. if (m_rigid_body)
  329. m_rigid_body->applyForce(LOL2BT_VEC3(force), LOL2BTU_VEC3(rel_pos));
  330. }
  331. void EasyPhysic::AddForceTorque(const lol::vec3& torque)
  332. {
  333. if (m_rigid_body)
  334. m_rigid_body->applyTorque(LOL2BT_VEC3(torque));
  335. }
  336. //-------------------------------------------------------------------------
  337. //Movements getter
  338. //--
  339. lol::vec3 EasyPhysic::GetLinearVelocity() const
  340. {
  341. if (m_rigid_body)
  342. return BT2LOL_VEC3(m_rigid_body->getLinearVelocity());
  343. return lol::vec3(.0f);
  344. }
  345. lol::vec3 EasyPhysic::GetLinearForce() const
  346. {
  347. if (m_rigid_body)
  348. return BT2LOL_VEC3(m_rigid_body->getTotalForce());
  349. return lol::vec3(.0f);
  350. }
  351. lol::vec3 EasyPhysic::GetAngularVelocity() const
  352. {
  353. if (m_rigid_body)
  354. return BT2LOL_VEC3(m_rigid_body->getAngularVelocity());
  355. return lol::vec3(.0f);
  356. }
  357. lol::vec3 EasyPhysic::GetAngularForce() const
  358. {
  359. if (m_rigid_body)
  360. return BT2LOL_VEC3(m_rigid_body->getTotalTorque());
  361. return lol::vec3(.0f);
  362. }
  363. //Set Local Inertia
  364. void EasyPhysic::SetLocalInertia(float mass)
  365. {
  366. if (mass != .0f)
  367. m_collision_shape->calculateLocalInertia(mass, m_local_inertia);
  368. else
  369. m_local_inertia = btVector3(.0f, .0f, .0f);
  370. }
  371. } /* namespace phys */
  372. } /* namespace lol */