PhysicsWorld.cpp 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066
  1. //
  2. // Copyright (c) 2008-2016 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "../Precompiled.h"
  23. #include "../Core/Context.h"
  24. #include "../Core/Mutex.h"
  25. #include "../Core/Profiler.h"
  26. #include "../Graphics/DebugRenderer.h"
  27. #include "../Graphics/Model.h"
  28. #include "../IO/Log.h"
  29. #include "../Math/Ray.h"
  30. #include "../Physics/CollisionShape.h"
  31. #include "../Physics/Constraint.h"
  32. #include "../Physics/PhysicsEvents.h"
  33. #include "../Physics/PhysicsUtils.h"
  34. #include "../Physics/PhysicsWorld.h"
  35. #include "../Physics/RigidBody.h"
  36. #include "../Scene/Scene.h"
  37. #include "../Scene/SceneEvents.h"
  38. // ATOMIC BEGIN
  39. #include <Bullet/src/BulletCollision/BroadphaseCollision/btDbvtBroadphase.h>
  40. #include <Bullet/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h>
  41. #include <Bullet/src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.h>
  42. #include <Bullet/src/BulletCollision/CollisionShapes/btBoxShape.h>
  43. #include <Bullet/src/BulletCollision/CollisionShapes/btSphereShape.h>
  44. #include <Bullet/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h>
  45. #include <Bullet/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h>
  46. // ATOMIC END
  47. extern ContactAddedCallback gContactAddedCallback;
  48. namespace Atomic
  49. {
  50. const char* PHYSICS_CATEGORY = "Physics";
  51. extern const char* SUBSYSTEM_CATEGORY;
  52. static const int MAX_SOLVER_ITERATIONS = 256;
  53. static const int DEFAULT_FPS = 60;
  54. static const Vector3 DEFAULT_GRAVITY = Vector3(0.0f, -9.81f, 0.0f);
  55. PhysicsWorldConfig PhysicsWorld::config;
  56. static bool CompareRaycastResults(const PhysicsRaycastResult& lhs, const PhysicsRaycastResult& rhs)
  57. {
  58. return lhs.distance_ < rhs.distance_;
  59. }
  60. void InternalPreTickCallback(btDynamicsWorld* world, btScalar timeStep)
  61. {
  62. static_cast<PhysicsWorld*>(world->getWorldUserInfo())->PreStep(timeStep);
  63. }
  64. void InternalTickCallback(btDynamicsWorld* world, btScalar timeStep)
  65. {
  66. static_cast<PhysicsWorld*>(world->getWorldUserInfo())->PostStep(timeStep);
  67. }
  68. static bool CustomMaterialCombinerCallback(btManifoldPoint& cp, const btCollisionObjectWrapper* colObj0Wrap, int partId0,
  69. int index0, const btCollisionObjectWrapper* colObj1Wrap, int partId1, int index1)
  70. {
  71. btAdjustInternalEdgeContacts(cp, colObj1Wrap, colObj0Wrap, partId1, index1);
  72. cp.m_combinedFriction = colObj0Wrap->getCollisionObject()->getFriction() * colObj1Wrap->getCollisionObject()->getFriction();
  73. cp.m_combinedRestitution =
  74. colObj0Wrap->getCollisionObject()->getRestitution() * colObj1Wrap->getCollisionObject()->getRestitution();
  75. return true;
  76. }
  77. /// Callback for physics world queries.
  78. struct PhysicsQueryCallback : public btCollisionWorld::ContactResultCallback
  79. {
  80. /// Construct.
  81. PhysicsQueryCallback(PODVector<RigidBody*>& result, unsigned collisionMask) :
  82. result_(result),
  83. collisionMask_(collisionMask)
  84. {
  85. }
  86. /// Add a contact result.
  87. virtual btScalar addSingleResult(btManifoldPoint&, const btCollisionObjectWrapper* colObj0Wrap, int, int,
  88. const btCollisionObjectWrapper* colObj1Wrap, int, int)
  89. {
  90. RigidBody* body = reinterpret_cast<RigidBody*>(colObj0Wrap->getCollisionObject()->getUserPointer());
  91. if (body && !result_.Contains(body) && (body->GetCollisionLayer() & collisionMask_))
  92. result_.Push(body);
  93. body = reinterpret_cast<RigidBody*>(colObj1Wrap->getCollisionObject()->getUserPointer());
  94. if (body && !result_.Contains(body) && (body->GetCollisionLayer() & collisionMask_))
  95. result_.Push(body);
  96. return 0.0f;
  97. }
  98. /// Found rigid bodies.
  99. PODVector<RigidBody*>& result_;
  100. /// Collision mask for the query.
  101. unsigned collisionMask_;
  102. };
  103. PhysicsWorld::PhysicsWorld(Context* context) :
  104. Component(context),
  105. collisionConfiguration_(0),
  106. collisionDispatcher_(0),
  107. broadphase_(0),
  108. solver_(0),
  109. world_(0),
  110. fps_(DEFAULT_FPS),
  111. maxSubSteps_(0),
  112. timeAcc_(0.0f),
  113. maxNetworkAngularVelocity_(DEFAULT_MAX_NETWORK_ANGULAR_VELOCITY),
  114. updateEnabled_(true),
  115. interpolation_(true),
  116. internalEdge_(true),
  117. applyingTransforms_(false),
  118. simulating_(false),
  119. debugRenderer_(0),
  120. debugMode_(btIDebugDraw::DBG_DrawWireframe | btIDebugDraw::DBG_DrawConstraints | btIDebugDraw::DBG_DrawConstraintLimits)
  121. {
  122. gContactAddedCallback = CustomMaterialCombinerCallback;
  123. if (PhysicsWorld::config.collisionConfig_)
  124. collisionConfiguration_ = PhysicsWorld::config.collisionConfig_;
  125. else
  126. collisionConfiguration_ = new btDefaultCollisionConfiguration();
  127. collisionDispatcher_ = new btCollisionDispatcher(collisionConfiguration_);
  128. broadphase_ = new btDbvtBroadphase();
  129. solver_ = new btSequentialImpulseConstraintSolver();
  130. world_ = new btDiscreteDynamicsWorld(collisionDispatcher_, broadphase_, solver_, collisionConfiguration_);
  131. world_->setGravity(ToBtVector3(DEFAULT_GRAVITY));
  132. world_->getDispatchInfo().m_useContinuous = true;
  133. world_->getSolverInfo().m_splitImpulse = false; // Disable by default for performance
  134. world_->setDebugDrawer(this);
  135. world_->setInternalTickCallback(InternalPreTickCallback, static_cast<void*>(this), true);
  136. world_->setInternalTickCallback(InternalTickCallback, static_cast<void*>(this), false);
  137. }
  138. PhysicsWorld::~PhysicsWorld()
  139. {
  140. if (scene_)
  141. {
  142. // Force all remaining constraints, rigid bodies and collision shapes to release themselves
  143. for (PODVector<Constraint*>::Iterator i = constraints_.Begin(); i != constraints_.End(); ++i)
  144. (*i)->ReleaseConstraint();
  145. for (PODVector<RigidBody*>::Iterator i = rigidBodies_.Begin(); i != rigidBodies_.End(); ++i)
  146. (*i)->ReleaseBody();
  147. for (PODVector<CollisionShape*>::Iterator i = collisionShapes_.Begin(); i != collisionShapes_.End(); ++i)
  148. (*i)->ReleaseShape();
  149. }
  150. delete world_;
  151. world_ = 0;
  152. delete solver_;
  153. solver_ = 0;
  154. delete broadphase_;
  155. broadphase_ = 0;
  156. delete collisionDispatcher_;
  157. collisionDispatcher_ = 0;
  158. // Delete configuration only if it was the default created by PhysicsWorld
  159. if (!PhysicsWorld::config.collisionConfig_)
  160. delete collisionConfiguration_;
  161. collisionConfiguration_ = 0;
  162. }
  163. void PhysicsWorld::RegisterObject(Context* context)
  164. {
  165. context->RegisterFactory<PhysicsWorld>(SUBSYSTEM_CATEGORY);
  166. ATOMIC_MIXED_ACCESSOR_ATTRIBUTE("Gravity", GetGravity, SetGravity, Vector3, DEFAULT_GRAVITY, AM_DEFAULT);
  167. ATOMIC_ATTRIBUTE("Physics FPS", int, fps_, DEFAULT_FPS, AM_DEFAULT);
  168. ATOMIC_ATTRIBUTE("Max Substeps", int, maxSubSteps_, 0, AM_DEFAULT);
  169. ATOMIC_ACCESSOR_ATTRIBUTE("Solver Iterations", GetNumIterations, SetNumIterations, int, 10, AM_DEFAULT);
  170. ATOMIC_ATTRIBUTE("Net Max Angular Vel.", float, maxNetworkAngularVelocity_, DEFAULT_MAX_NETWORK_ANGULAR_VELOCITY, AM_DEFAULT);
  171. ATOMIC_ATTRIBUTE("Interpolation", bool, interpolation_, true, AM_FILE);
  172. ATOMIC_ATTRIBUTE("Internal Edge Utility", bool, internalEdge_, true, AM_DEFAULT);
  173. ATOMIC_ACCESSOR_ATTRIBUTE("Split Impulse", GetSplitImpulse, SetSplitImpulse, bool, false, AM_DEFAULT);
  174. }
  175. bool PhysicsWorld::isVisible(const btVector3& aabbMin, const btVector3& aabbMax)
  176. {
  177. if (debugRenderer_)
  178. return debugRenderer_->IsInside(BoundingBox(ToVector3(aabbMin), ToVector3(aabbMax)));
  179. else
  180. return false;
  181. }
  182. void PhysicsWorld::drawLine(const btVector3& from, const btVector3& to, const btVector3& color)
  183. {
  184. if (debugRenderer_)
  185. debugRenderer_->AddLine(ToVector3(from), ToVector3(to), Color(color.x(), color.y(), color.z()), debugDepthTest_);
  186. }
  187. void PhysicsWorld::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
  188. {
  189. if (debug)
  190. {
  191. ATOMIC_PROFILE(PhysicsDrawDebug);
  192. debugRenderer_ = debug;
  193. debugDepthTest_ = depthTest;
  194. world_->debugDrawWorld();
  195. debugRenderer_ = 0;
  196. }
  197. }
  198. void PhysicsWorld::reportErrorWarning(const char* warningString)
  199. {
  200. ATOMIC_LOGWARNING("Physics: " + String(warningString));
  201. }
  202. void PhysicsWorld::drawContactPoint(const btVector3& pointOnB, const btVector3& normalOnB, btScalar distance, int lifeTime,
  203. const btVector3& color)
  204. {
  205. }
  206. void PhysicsWorld::draw3dText(const btVector3& location, const char* textString)
  207. {
  208. }
  209. void PhysicsWorld::Update(float timeStep)
  210. {
  211. ATOMIC_PROFILE(UpdatePhysics);
  212. float internalTimeStep = 1.0f / fps_;
  213. int maxSubSteps = (int)(timeStep * fps_) + 1;
  214. if (maxSubSteps_ < 0)
  215. {
  216. internalTimeStep = timeStep;
  217. maxSubSteps = 1;
  218. }
  219. else if (maxSubSteps_ > 0)
  220. maxSubSteps = Min(maxSubSteps, maxSubSteps_);
  221. delayedWorldTransforms_.Clear();
  222. simulating_ = true;
  223. if (interpolation_)
  224. world_->stepSimulation(timeStep, maxSubSteps, internalTimeStep);
  225. else
  226. {
  227. timeAcc_ += timeStep;
  228. while (timeAcc_ >= internalTimeStep && maxSubSteps > 0)
  229. {
  230. world_->stepSimulation(internalTimeStep, 0, internalTimeStep);
  231. timeAcc_ -= internalTimeStep;
  232. --maxSubSteps;
  233. }
  234. }
  235. simulating_ = false;
  236. // Apply delayed (parented) world transforms now
  237. while (!delayedWorldTransforms_.Empty())
  238. {
  239. for (HashMap<RigidBody*, DelayedWorldTransform>::Iterator i = delayedWorldTransforms_.Begin();
  240. i != delayedWorldTransforms_.End();)
  241. {
  242. const DelayedWorldTransform& transform = i->second_;
  243. // If parent's transform has already been assigned, can proceed
  244. if (!delayedWorldTransforms_.Contains(transform.parentRigidBody_))
  245. {
  246. transform.rigidBody_->ApplyWorldTransform(transform.worldPosition_, transform.worldRotation_);
  247. i = delayedWorldTransforms_.Erase(i);
  248. }
  249. else
  250. ++i;
  251. }
  252. }
  253. }
  254. void PhysicsWorld::UpdateCollisions()
  255. {
  256. world_->performDiscreteCollisionDetection();
  257. }
  258. void PhysicsWorld::SetFps(int fps)
  259. {
  260. fps_ = (unsigned)Clamp(fps, 1, 1000);
  261. MarkNetworkUpdate();
  262. }
  263. void PhysicsWorld::SetGravity(const Vector3& gravity)
  264. {
  265. world_->setGravity(ToBtVector3(gravity));
  266. MarkNetworkUpdate();
  267. }
  268. void PhysicsWorld::SetMaxSubSteps(int num)
  269. {
  270. maxSubSteps_ = num;
  271. MarkNetworkUpdate();
  272. }
  273. void PhysicsWorld::SetNumIterations(int num)
  274. {
  275. num = Clamp(num, 1, MAX_SOLVER_ITERATIONS);
  276. world_->getSolverInfo().m_numIterations = num;
  277. MarkNetworkUpdate();
  278. }
  279. void PhysicsWorld::SetUpdateEnabled(bool enable)
  280. {
  281. updateEnabled_ = enable;
  282. }
  283. void PhysicsWorld::SetInterpolation(bool enable)
  284. {
  285. interpolation_ = enable;
  286. }
  287. void PhysicsWorld::SetInternalEdge(bool enable)
  288. {
  289. internalEdge_ = enable;
  290. MarkNetworkUpdate();
  291. }
  292. void PhysicsWorld::SetSplitImpulse(bool enable)
  293. {
  294. world_->getSolverInfo().m_splitImpulse = enable;
  295. MarkNetworkUpdate();
  296. }
  297. void PhysicsWorld::SetMaxNetworkAngularVelocity(float velocity)
  298. {
  299. maxNetworkAngularVelocity_ = Clamp(velocity, 1.0f, 32767.0f);
  300. MarkNetworkUpdate();
  301. }
  302. void PhysicsWorld::Raycast(PODVector<PhysicsRaycastResult>& result, const Ray& ray, float maxDistance, unsigned collisionMask)
  303. {
  304. ATOMIC_PROFILE(PhysicsRaycast);
  305. if (maxDistance >= M_INFINITY)
  306. ATOMIC_LOGWARNING("Infinite maxDistance in physics raycast is not supported");
  307. btCollisionWorld::AllHitsRayResultCallback
  308. rayCallback(ToBtVector3(ray.origin_), ToBtVector3(ray.origin_ + maxDistance * ray.direction_));
  309. rayCallback.m_collisionFilterGroup = (short)0xffff;
  310. rayCallback.m_collisionFilterMask = (short)collisionMask;
  311. world_->rayTest(rayCallback.m_rayFromWorld, rayCallback.m_rayToWorld, rayCallback);
  312. for (int i = 0; i < rayCallback.m_collisionObjects.size(); ++i)
  313. {
  314. PhysicsRaycastResult newResult;
  315. newResult.body_ = static_cast<RigidBody*>(rayCallback.m_collisionObjects[i]->getUserPointer());
  316. newResult.position_ = ToVector3(rayCallback.m_hitPointWorld[i]);
  317. newResult.normal_ = ToVector3(rayCallback.m_hitNormalWorld[i]);
  318. newResult.distance_ = (newResult.position_ - ray.origin_).Length();
  319. newResult.hitFraction_ = rayCallback.m_closestHitFraction;
  320. result.Push(newResult);
  321. }
  322. Sort(result.Begin(), result.End(), CompareRaycastResults);
  323. }
  324. void PhysicsWorld::RaycastSingle(PhysicsRaycastResult& result, const Ray& ray, float maxDistance, unsigned collisionMask)
  325. {
  326. ATOMIC_PROFILE(PhysicsRaycastSingle);
  327. if (maxDistance >= M_INFINITY)
  328. ATOMIC_LOGWARNING("Infinite maxDistance in physics raycast is not supported");
  329. btCollisionWorld::ClosestRayResultCallback
  330. rayCallback(ToBtVector3(ray.origin_), ToBtVector3(ray.origin_ + maxDistance * ray.direction_));
  331. rayCallback.m_collisionFilterGroup = (short)0xffff;
  332. rayCallback.m_collisionFilterMask = (short)collisionMask;
  333. world_->rayTest(rayCallback.m_rayFromWorld, rayCallback.m_rayToWorld, rayCallback);
  334. if (rayCallback.hasHit())
  335. {
  336. result.position_ = ToVector3(rayCallback.m_hitPointWorld);
  337. result.normal_ = ToVector3(rayCallback.m_hitNormalWorld);
  338. result.distance_ = (result.position_ - ray.origin_).Length();
  339. result.hitFraction_ = rayCallback.m_closestHitFraction;
  340. result.body_ = static_cast<RigidBody*>(rayCallback.m_collisionObject->getUserPointer());
  341. }
  342. else
  343. {
  344. result.position_ = Vector3::ZERO;
  345. result.normal_ = Vector3::ZERO;
  346. result.distance_ = M_INFINITY;
  347. result.hitFraction_ = 0.0f;
  348. result.body_ = 0;
  349. }
  350. }
  351. void PhysicsWorld::RaycastSingleSegmented(PhysicsRaycastResult& result, const Ray& ray, float maxDistance, float segmentDistance, unsigned collisionMask)
  352. {
  353. ATOMIC_PROFILE(PhysicsRaycastSingleSegmented);
  354. if (maxDistance >= M_INFINITY)
  355. ATOMIC_LOGWARNING("Infinite maxDistance in physics raycast is not supported");
  356. btVector3 start = ToBtVector3(ray.origin_);
  357. btVector3 end;
  358. btVector3 direction = ToBtVector3(ray.direction_);
  359. float distance;
  360. for (float remainingDistance = maxDistance; remainingDistance > 0; remainingDistance -= segmentDistance)
  361. {
  362. distance = Min(remainingDistance, segmentDistance);
  363. end = start + distance * direction;
  364. btCollisionWorld::ClosestRayResultCallback rayCallback(start, end);
  365. rayCallback.m_collisionFilterGroup = (short)0xffff;
  366. rayCallback.m_collisionFilterMask = (short)collisionMask;
  367. world_->rayTest(rayCallback.m_rayFromWorld, rayCallback.m_rayToWorld, rayCallback);
  368. if (rayCallback.hasHit())
  369. {
  370. result.position_ = ToVector3(rayCallback.m_hitPointWorld);
  371. result.normal_ = ToVector3(rayCallback.m_hitNormalWorld);
  372. result.distance_ = (result.position_ - ray.origin_).Length();
  373. result.hitFraction_ = rayCallback.m_closestHitFraction;
  374. result.body_ = static_cast<RigidBody*>(rayCallback.m_collisionObject->getUserPointer());
  375. // No need to cast the rest of the segments
  376. return;
  377. }
  378. // Use the end position as the new start position
  379. start = end;
  380. }
  381. // Didn't hit anything
  382. result.position_ = Vector3::ZERO;
  383. result.normal_ = Vector3::ZERO;
  384. result.distance_ = M_INFINITY;
  385. result.hitFraction_ = 0.0f;
  386. result.body_ = 0;
  387. }
  388. void PhysicsWorld::SphereCast(PhysicsRaycastResult& result, const Ray& ray, float radius, float maxDistance, unsigned collisionMask)
  389. {
  390. ATOMIC_PROFILE(PhysicsSphereCast);
  391. if (maxDistance >= M_INFINITY)
  392. ATOMIC_LOGWARNING("Infinite maxDistance in physics sphere cast is not supported");
  393. btSphereShape shape(radius);
  394. Vector3 endPos = ray.origin_ + maxDistance * ray.direction_;
  395. btCollisionWorld::ClosestConvexResultCallback
  396. convexCallback(ToBtVector3(ray.origin_), ToBtVector3(endPos));
  397. convexCallback.m_collisionFilterGroup = (short)0xffff;
  398. convexCallback.m_collisionFilterMask = (short)collisionMask;
  399. world_->convexSweepTest(&shape, btTransform(btQuaternion::getIdentity(), convexCallback.m_convexFromWorld),
  400. btTransform(btQuaternion::getIdentity(), convexCallback.m_convexToWorld), convexCallback);
  401. if (convexCallback.hasHit())
  402. {
  403. result.body_ = static_cast<RigidBody*>(convexCallback.m_hitCollisionObject->getUserPointer());
  404. result.position_ = ToVector3(convexCallback.m_hitPointWorld);
  405. result.normal_ = ToVector3(convexCallback.m_hitNormalWorld);
  406. result.distance_ = convexCallback.m_closestHitFraction * (endPos - ray.origin_).Length();
  407. result.hitFraction_ = convexCallback.m_closestHitFraction;
  408. }
  409. else
  410. {
  411. result.body_ = 0;
  412. result.position_ = Vector3::ZERO;
  413. result.normal_ = Vector3::ZERO;
  414. result.distance_ = M_INFINITY;
  415. result.hitFraction_ = 0.0f;
  416. }
  417. }
  418. void PhysicsWorld::ConvexCast(PhysicsRaycastResult& result, CollisionShape* shape, const Vector3& startPos,
  419. const Quaternion& startRot, const Vector3& endPos, const Quaternion& endRot, unsigned collisionMask)
  420. {
  421. if (!shape || !shape->GetCollisionShape())
  422. {
  423. ATOMIC_LOGERROR("Null collision shape for convex cast");
  424. result.body_ = 0;
  425. result.position_ = Vector3::ZERO;
  426. result.normal_ = Vector3::ZERO;
  427. result.distance_ = M_INFINITY;
  428. result.hitFraction_ = 0.0f;
  429. return;
  430. }
  431. // If shape is attached in a rigidbody, set its collision group temporarily to 0 to make sure it is not returned in the sweep result
  432. RigidBody* bodyComp = shape->GetComponent<RigidBody>();
  433. btRigidBody* body = bodyComp ? bodyComp->GetBody() : (btRigidBody*)0;
  434. btBroadphaseProxy* proxy = body ? body->getBroadphaseProxy() : (btBroadphaseProxy*)0;
  435. short group = 0;
  436. if (proxy)
  437. {
  438. group = proxy->m_collisionFilterGroup;
  439. proxy->m_collisionFilterGroup = 0;
  440. }
  441. // Take the shape's offset position & rotation into account
  442. Node* shapeNode = shape->GetNode();
  443. Matrix3x4 startTransform(startPos, startRot, shapeNode ? shapeNode->GetWorldScale() : Vector3::ONE);
  444. Matrix3x4 endTransform(endPos, endRot, shapeNode ? shapeNode->GetWorldScale() : Vector3::ONE);
  445. Vector3 effectiveStartPos = startTransform * shape->GetPosition();
  446. Vector3 effectiveEndPos = endTransform * shape->GetPosition();
  447. Quaternion effectiveStartRot = startRot * shape->GetRotation();
  448. Quaternion effectiveEndRot = endRot * shape->GetRotation();
  449. ConvexCast(result, shape->GetCollisionShape(), effectiveStartPos, effectiveStartRot, effectiveEndPos, effectiveEndRot, collisionMask);
  450. // Restore the collision group
  451. if (proxy)
  452. proxy->m_collisionFilterGroup = group;
  453. }
  454. void PhysicsWorld::ConvexCast(PhysicsRaycastResult& result, btCollisionShape* shape, const Vector3& startPos,
  455. const Quaternion& startRot, const Vector3& endPos, const Quaternion& endRot, unsigned collisionMask)
  456. {
  457. if (!shape)
  458. {
  459. ATOMIC_LOGERROR("Null collision shape for convex cast");
  460. result.body_ = 0;
  461. result.position_ = Vector3::ZERO;
  462. result.normal_ = Vector3::ZERO;
  463. result.distance_ = M_INFINITY;
  464. result.hitFraction_ = 0.0f;
  465. return;
  466. }
  467. if (!shape->isConvex())
  468. {
  469. ATOMIC_LOGERROR("Can not use non-convex collision shape for convex cast");
  470. result.body_ = 0;
  471. result.position_ = Vector3::ZERO;
  472. result.normal_ = Vector3::ZERO;
  473. result.distance_ = M_INFINITY;
  474. result.hitFraction_ = 0.0f;
  475. return;
  476. }
  477. ATOMIC_PROFILE(PhysicsConvexCast);
  478. btCollisionWorld::ClosestConvexResultCallback convexCallback(ToBtVector3(startPos), ToBtVector3(endPos));
  479. convexCallback.m_collisionFilterGroup = (short)0xffff;
  480. convexCallback.m_collisionFilterMask = (short)collisionMask;
  481. world_->convexSweepTest(static_cast<btConvexShape*>(shape), btTransform(ToBtQuaternion(startRot),
  482. convexCallback.m_convexFromWorld), btTransform(ToBtQuaternion(endRot), convexCallback.m_convexToWorld),
  483. convexCallback);
  484. if (convexCallback.hasHit())
  485. {
  486. result.body_ = static_cast<RigidBody*>(convexCallback.m_hitCollisionObject->getUserPointer());
  487. result.position_ = ToVector3(convexCallback.m_hitPointWorld);
  488. result.normal_ = ToVector3(convexCallback.m_hitNormalWorld);
  489. result.distance_ = convexCallback.m_closestHitFraction * (endPos - startPos).Length();
  490. result.hitFraction_ = convexCallback.m_closestHitFraction;
  491. }
  492. else
  493. {
  494. result.body_ = 0;
  495. result.position_ = Vector3::ZERO;
  496. result.normal_ = Vector3::ZERO;
  497. result.distance_ = M_INFINITY;
  498. result.hitFraction_ = 0.0f;
  499. }
  500. }
  501. void PhysicsWorld::RemoveCachedGeometry(Model* model)
  502. {
  503. for (HashMap<Pair<Model*, unsigned>, SharedPtr<CollisionGeometryData> >::Iterator i = triMeshCache_.Begin();
  504. i != triMeshCache_.End();)
  505. {
  506. HashMap<Pair<Model*, unsigned>, SharedPtr<CollisionGeometryData> >::Iterator current = i++;
  507. if (current->first_.first_ == model)
  508. triMeshCache_.Erase(current);
  509. }
  510. for (HashMap<Pair<Model*, unsigned>, SharedPtr<CollisionGeometryData> >::Iterator i = convexCache_.Begin();
  511. i != convexCache_.End();)
  512. {
  513. HashMap<Pair<Model*, unsigned>, SharedPtr<CollisionGeometryData> >::Iterator current = i++;
  514. if (current->first_.first_ == model)
  515. convexCache_.Erase(current);
  516. }
  517. }
  518. void PhysicsWorld::GetRigidBodies(PODVector<RigidBody*>& result, const Sphere& sphere, unsigned collisionMask)
  519. {
  520. ATOMIC_PROFILE(PhysicsSphereQuery);
  521. result.Clear();
  522. btSphereShape sphereShape(sphere.radius_);
  523. btRigidBody* tempRigidBody = new btRigidBody(1.0f, 0, &sphereShape);
  524. tempRigidBody->setWorldTransform(btTransform(btQuaternion::getIdentity(), ToBtVector3(sphere.center_)));
  525. // Need to activate the temporary rigid body to get reliable results from static, sleeping objects
  526. tempRigidBody->activate();
  527. world_->addRigidBody(tempRigidBody);
  528. PhysicsQueryCallback callback(result, collisionMask);
  529. world_->contactTest(tempRigidBody, callback);
  530. world_->removeRigidBody(tempRigidBody);
  531. delete tempRigidBody;
  532. }
  533. void PhysicsWorld::GetRigidBodies(PODVector<RigidBody*>& result, const BoundingBox& box, unsigned collisionMask)
  534. {
  535. ATOMIC_PROFILE(PhysicsBoxQuery);
  536. result.Clear();
  537. btBoxShape boxShape(ToBtVector3(box.HalfSize()));
  538. btRigidBody* tempRigidBody = new btRigidBody(1.0f, 0, &boxShape);
  539. tempRigidBody->setWorldTransform(btTransform(btQuaternion::getIdentity(), ToBtVector3(box.Center())));
  540. tempRigidBody->activate();
  541. world_->addRigidBody(tempRigidBody);
  542. PhysicsQueryCallback callback(result, collisionMask);
  543. world_->contactTest(tempRigidBody, callback);
  544. world_->removeRigidBody(tempRigidBody);
  545. delete tempRigidBody;
  546. }
  547. void PhysicsWorld::GetRigidBodies(PODVector<RigidBody*>& result, const RigidBody* body)
  548. {
  549. ATOMIC_PROFILE(PhysicsBodyQuery);
  550. result.Clear();
  551. if (!body || !body->GetBody())
  552. return;
  553. PhysicsQueryCallback callback(result, body->GetCollisionMask());
  554. world_->contactTest(body->GetBody(), callback);
  555. // Remove the body itself from the returned list
  556. for (unsigned i = 0; i < result.Size(); i++)
  557. {
  558. if (result[i] == body)
  559. {
  560. result.Erase(i);
  561. break;
  562. }
  563. }
  564. }
  565. void PhysicsWorld::GetCollidingBodies(PODVector<RigidBody*>& result, const RigidBody* body)
  566. {
  567. ATOMIC_PROFILE(GetCollidingBodies);
  568. result.Clear();
  569. for (HashMap<Pair<WeakPtr<RigidBody>, WeakPtr<RigidBody> >, btPersistentManifold*>::Iterator i = currentCollisions_.Begin();
  570. i != currentCollisions_.End(); ++i)
  571. {
  572. if (i->first_.first_ == body)
  573. {
  574. if (i->first_.second_)
  575. result.Push(i->first_.second_);
  576. }
  577. else if (i->first_.second_ == body)
  578. {
  579. if (i->first_.first_)
  580. result.Push(i->first_.first_);
  581. }
  582. }
  583. }
  584. Vector3 PhysicsWorld::GetGravity() const
  585. {
  586. return ToVector3(world_->getGravity());
  587. }
  588. int PhysicsWorld::GetNumIterations() const
  589. {
  590. return world_->getSolverInfo().m_numIterations;
  591. }
  592. bool PhysicsWorld::GetSplitImpulse() const
  593. {
  594. return world_->getSolverInfo().m_splitImpulse != 0;
  595. }
  596. void PhysicsWorld::AddRigidBody(RigidBody* body)
  597. {
  598. rigidBodies_.Push(body);
  599. }
  600. void PhysicsWorld::RemoveRigidBody(RigidBody* body)
  601. {
  602. rigidBodies_.Remove(body);
  603. // Remove possible dangling pointer from the delayedWorldTransforms structure
  604. delayedWorldTransforms_.Erase(body);
  605. }
  606. void PhysicsWorld::AddCollisionShape(CollisionShape* shape)
  607. {
  608. collisionShapes_.Push(shape);
  609. }
  610. void PhysicsWorld::RemoveCollisionShape(CollisionShape* shape)
  611. {
  612. collisionShapes_.Remove(shape);
  613. }
  614. void PhysicsWorld::AddConstraint(Constraint* constraint)
  615. {
  616. constraints_.Push(constraint);
  617. }
  618. void PhysicsWorld::RemoveConstraint(Constraint* constraint)
  619. {
  620. constraints_.Remove(constraint);
  621. }
  622. void PhysicsWorld::AddDelayedWorldTransform(const DelayedWorldTransform& transform)
  623. {
  624. delayedWorldTransforms_[transform.rigidBody_] = transform;
  625. }
  626. void PhysicsWorld::DrawDebugGeometry(bool depthTest)
  627. {
  628. DebugRenderer* debug = GetComponent<DebugRenderer>();
  629. DrawDebugGeometry(debug, depthTest);
  630. }
  631. void PhysicsWorld::SetDebugRenderer(DebugRenderer* debug)
  632. {
  633. debugRenderer_ = debug;
  634. }
  635. void PhysicsWorld::SetDebugDepthTest(bool enable)
  636. {
  637. debugDepthTest_ = enable;
  638. }
  639. void PhysicsWorld::CleanupGeometryCache()
  640. {
  641. // Remove cached shapes whose only reference is the cache itself
  642. for (HashMap<Pair<Model*, unsigned>, SharedPtr<CollisionGeometryData> >::Iterator i = triMeshCache_.Begin();
  643. i != triMeshCache_.End();)
  644. {
  645. HashMap<Pair<Model*, unsigned>, SharedPtr<CollisionGeometryData> >::Iterator current = i++;
  646. if (current->second_.Refs() == 1)
  647. triMeshCache_.Erase(current);
  648. }
  649. for (HashMap<Pair<Model*, unsigned>, SharedPtr<CollisionGeometryData> >::Iterator i = convexCache_.Begin();
  650. i != convexCache_.End();)
  651. {
  652. HashMap<Pair<Model*, unsigned>, SharedPtr<CollisionGeometryData> >::Iterator current = i++;
  653. if (current->second_.Refs() == 1)
  654. convexCache_.Erase(current);
  655. }
  656. }
  657. void PhysicsWorld::OnSceneSet(Scene* scene)
  658. {
  659. // Subscribe to the scene subsystem update, which will trigger the physics simulation step
  660. if (scene)
  661. {
  662. scene_ = GetScene();
  663. SubscribeToEvent(scene_, E_SCENESUBSYSTEMUPDATE, ATOMIC_HANDLER(PhysicsWorld, HandleSceneSubsystemUpdate));
  664. }
  665. else
  666. UnsubscribeFromEvent(E_SCENESUBSYSTEMUPDATE);
  667. }
  668. void PhysicsWorld::HandleSceneSubsystemUpdate(StringHash eventType, VariantMap& eventData)
  669. {
  670. if (!updateEnabled_)
  671. return;
  672. using namespace SceneSubsystemUpdate;
  673. Update(eventData[P_TIMESTEP].GetFloat());
  674. }
  675. void PhysicsWorld::PreStep(float timeStep)
  676. {
  677. // Send pre-step event
  678. using namespace PhysicsPreStep;
  679. VariantMap& eventData = GetEventDataMap();
  680. eventData[P_WORLD] = this;
  681. eventData[P_TIMESTEP] = timeStep;
  682. SendEvent(E_PHYSICSPRESTEP, eventData);
  683. // Start profiling block for the actual simulation step
  684. #ifdef ATOMIC_PROFILING
  685. Profiler* profiler = GetSubsystem<Profiler>();
  686. if (profiler)
  687. profiler->BeginBlock("StepSimulation");
  688. #endif
  689. }
  690. void PhysicsWorld::PostStep(float timeStep)
  691. {
  692. #ifdef ATOMIC_PROFILING
  693. Profiler* profiler = GetSubsystem<Profiler>();
  694. if (profiler)
  695. profiler->EndBlock();
  696. #endif
  697. SendCollisionEvents();
  698. // Send post-step event
  699. using namespace PhysicsPostStep;
  700. VariantMap& eventData = GetEventDataMap();
  701. eventData[P_WORLD] = this;
  702. eventData[P_TIMESTEP] = timeStep;
  703. SendEvent(E_PHYSICSPOSTSTEP, eventData);
  704. }
  705. void PhysicsWorld::SendCollisionEvents()
  706. {
  707. ATOMIC_PROFILE(SendCollisionEvents);
  708. currentCollisions_.Clear();
  709. physicsCollisionData_.Clear();
  710. nodeCollisionData_.Clear();
  711. int numManifolds = collisionDispatcher_->getNumManifolds();
  712. if (numManifolds)
  713. {
  714. physicsCollisionData_[PhysicsCollision::P_WORLD] = this;
  715. for (int i = 0; i < numManifolds; ++i)
  716. {
  717. btPersistentManifold* contactManifold = collisionDispatcher_->getManifoldByIndexInternal(i);
  718. // First check that there are actual contacts, as the manifold exists also when objects are close but not touching
  719. if (!contactManifold->getNumContacts())
  720. continue;
  721. const btCollisionObject* objectA = contactManifold->getBody0();
  722. const btCollisionObject* objectB = contactManifold->getBody1();
  723. RigidBody* bodyA = static_cast<RigidBody*>(objectA->getUserPointer());
  724. RigidBody* bodyB = static_cast<RigidBody*>(objectB->getUserPointer());
  725. // If it's not a rigidbody, maybe a ghost object
  726. if (!bodyA || !bodyB)
  727. continue;
  728. // Skip collision event signaling if both objects are static, or if collision event mode does not match
  729. if (bodyA->GetMass() == 0.0f && bodyB->GetMass() == 0.0f)
  730. continue;
  731. if (bodyA->GetCollisionEventMode() == COLLISION_NEVER || bodyB->GetCollisionEventMode() == COLLISION_NEVER)
  732. continue;
  733. if (bodyA->GetCollisionEventMode() == COLLISION_ACTIVE && bodyB->GetCollisionEventMode() == COLLISION_ACTIVE &&
  734. !bodyA->IsActive() && !bodyB->IsActive())
  735. continue;
  736. WeakPtr<RigidBody> bodyWeakA(bodyA);
  737. WeakPtr<RigidBody> bodyWeakB(bodyB);
  738. Pair<WeakPtr<RigidBody>, WeakPtr<RigidBody> > bodyPair;
  739. if (bodyA < bodyB)
  740. bodyPair = MakePair(bodyWeakA, bodyWeakB);
  741. else
  742. bodyPair = MakePair(bodyWeakB, bodyWeakA);
  743. // First only store the collision pair as weak pointers and the manifold pointer, so user code can safely destroy
  744. // objects during collision event handling
  745. currentCollisions_[bodyPair] = contactManifold;
  746. }
  747. for (HashMap<Pair<WeakPtr<RigidBody>, WeakPtr<RigidBody> >, btPersistentManifold*>::Iterator i = currentCollisions_.Begin();
  748. i != currentCollisions_.End(); ++i)
  749. {
  750. RigidBody* bodyA = i->first_.first_;
  751. RigidBody* bodyB = i->first_.second_;
  752. if (!bodyA || !bodyB)
  753. continue;
  754. btPersistentManifold* contactManifold = i->second_;
  755. Node* nodeA = bodyA->GetNode();
  756. Node* nodeB = bodyB->GetNode();
  757. WeakPtr<Node> nodeWeakA(nodeA);
  758. WeakPtr<Node> nodeWeakB(nodeB);
  759. bool trigger = bodyA->IsTrigger() || bodyB->IsTrigger();
  760. bool newCollision = !previousCollisions_.Contains(i->first_);
  761. physicsCollisionData_[PhysicsCollision::P_NODEA] = nodeA;
  762. physicsCollisionData_[PhysicsCollision::P_NODEB] = nodeB;
  763. physicsCollisionData_[PhysicsCollision::P_BODYA] = bodyA;
  764. physicsCollisionData_[PhysicsCollision::P_BODYB] = bodyB;
  765. physicsCollisionData_[PhysicsCollision::P_TRIGGER] = trigger;
  766. contacts_.Clear();
  767. for (int j = 0; j < contactManifold->getNumContacts(); ++j)
  768. {
  769. btManifoldPoint& point = contactManifold->getContactPoint(j);
  770. contacts_.WriteVector3(ToVector3(point.m_positionWorldOnB));
  771. contacts_.WriteVector3(ToVector3(point.m_normalWorldOnB));
  772. contacts_.WriteFloat(point.m_distance1);
  773. contacts_.WriteFloat(point.m_appliedImpulse);
  774. }
  775. physicsCollisionData_[PhysicsCollision::P_CONTACTS] = contacts_.GetBuffer();
  776. // Send separate collision start event if collision is new
  777. if (newCollision)
  778. {
  779. SendEvent(E_PHYSICSCOLLISIONSTART, physicsCollisionData_);
  780. // Skip rest of processing if either of the nodes or bodies is removed as a response to the event
  781. if (!nodeWeakA || !nodeWeakB || !i->first_.first_ || !i->first_.second_)
  782. continue;
  783. }
  784. // Then send the ongoing collision event
  785. SendEvent(E_PHYSICSCOLLISION, physicsCollisionData_);
  786. if (!nodeWeakA || !nodeWeakB || !i->first_.first_ || !i->first_.second_)
  787. continue;
  788. nodeCollisionData_[NodeCollision::P_BODY] = bodyA;
  789. nodeCollisionData_[NodeCollision::P_OTHERNODE] = nodeB;
  790. nodeCollisionData_[NodeCollision::P_OTHERBODY] = bodyB;
  791. nodeCollisionData_[NodeCollision::P_TRIGGER] = trigger;
  792. nodeCollisionData_[NodeCollision::P_CONTACTS] = contacts_.GetBuffer();
  793. if (newCollision)
  794. {
  795. nodeA->SendEvent(E_NODECOLLISIONSTART, nodeCollisionData_);
  796. if (!nodeWeakA || !nodeWeakB || !i->first_.first_ || !i->first_.second_)
  797. continue;
  798. }
  799. nodeA->SendEvent(E_NODECOLLISION, nodeCollisionData_);
  800. if (!nodeWeakA || !nodeWeakB || !i->first_.first_ || !i->first_.second_)
  801. continue;
  802. contacts_.Clear();
  803. for (int j = 0; j < contactManifold->getNumContacts(); ++j)
  804. {
  805. btManifoldPoint& point = contactManifold->getContactPoint(j);
  806. contacts_.WriteVector3(ToVector3(point.m_positionWorldOnB));
  807. contacts_.WriteVector3(-ToVector3(point.m_normalWorldOnB));
  808. contacts_.WriteFloat(point.m_distance1);
  809. contacts_.WriteFloat(point.m_appliedImpulse);
  810. }
  811. nodeCollisionData_[NodeCollision::P_BODY] = bodyB;
  812. nodeCollisionData_[NodeCollision::P_OTHERNODE] = nodeA;
  813. nodeCollisionData_[NodeCollision::P_OTHERBODY] = bodyA;
  814. nodeCollisionData_[NodeCollision::P_CONTACTS] = contacts_.GetBuffer();
  815. if (newCollision)
  816. {
  817. nodeB->SendEvent(E_NODECOLLISIONSTART, nodeCollisionData_);
  818. if (!nodeWeakA || !nodeWeakB || !i->first_.first_ || !i->first_.second_)
  819. continue;
  820. }
  821. nodeB->SendEvent(E_NODECOLLISION, nodeCollisionData_);
  822. }
  823. }
  824. // Send collision end events as applicable
  825. {
  826. physicsCollisionData_[PhysicsCollisionEnd::P_WORLD] = this;
  827. for (HashMap<Pair<WeakPtr<RigidBody>, WeakPtr<RigidBody> >, btPersistentManifold*>::Iterator
  828. i = previousCollisions_.Begin(); i != previousCollisions_.End(); ++i)
  829. {
  830. if (!currentCollisions_.Contains(i->first_))
  831. {
  832. RigidBody* bodyA = i->first_.first_;
  833. RigidBody* bodyB = i->first_.second_;
  834. if (!bodyA || !bodyB)
  835. continue;
  836. bool trigger = bodyA->IsTrigger() || bodyB->IsTrigger();
  837. // Skip collision event signaling if both objects are static, or if collision event mode does not match
  838. if (bodyA->GetMass() == 0.0f && bodyB->GetMass() == 0.0f)
  839. continue;
  840. if (bodyA->GetCollisionEventMode() == COLLISION_NEVER || bodyB->GetCollisionEventMode() == COLLISION_NEVER)
  841. continue;
  842. if (bodyA->GetCollisionEventMode() == COLLISION_ACTIVE && bodyB->GetCollisionEventMode() == COLLISION_ACTIVE &&
  843. !bodyA->IsActive() && !bodyB->IsActive())
  844. continue;
  845. Node* nodeA = bodyA->GetNode();
  846. Node* nodeB = bodyB->GetNode();
  847. WeakPtr<Node> nodeWeakA(nodeA);
  848. WeakPtr<Node> nodeWeakB(nodeB);
  849. physicsCollisionData_[PhysicsCollisionEnd::P_BODYA] = bodyA;
  850. physicsCollisionData_[PhysicsCollisionEnd::P_BODYB] = bodyB;
  851. physicsCollisionData_[PhysicsCollisionEnd::P_NODEA] = nodeA;
  852. physicsCollisionData_[PhysicsCollisionEnd::P_NODEB] = nodeB;
  853. physicsCollisionData_[PhysicsCollisionEnd::P_TRIGGER] = trigger;
  854. SendEvent(E_PHYSICSCOLLISIONEND, physicsCollisionData_);
  855. // Skip rest of processing if either of the nodes or bodies is removed as a response to the event
  856. if (!nodeWeakA || !nodeWeakB || !i->first_.first_ || !i->first_.second_)
  857. continue;
  858. nodeCollisionData_[NodeCollisionEnd::P_BODY] = bodyA;
  859. nodeCollisionData_[NodeCollisionEnd::P_OTHERNODE] = nodeB;
  860. nodeCollisionData_[NodeCollisionEnd::P_OTHERBODY] = bodyB;
  861. nodeCollisionData_[NodeCollisionEnd::P_TRIGGER] = trigger;
  862. nodeA->SendEvent(E_NODECOLLISIONEND, nodeCollisionData_);
  863. if (!nodeWeakA || !nodeWeakB || !i->first_.first_ || !i->first_.second_)
  864. continue;
  865. nodeCollisionData_[NodeCollisionEnd::P_BODY] = bodyB;
  866. nodeCollisionData_[NodeCollisionEnd::P_OTHERNODE] = nodeA;
  867. nodeCollisionData_[NodeCollisionEnd::P_OTHERBODY] = bodyA;
  868. nodeB->SendEvent(E_NODECOLLISIONEND, nodeCollisionData_);
  869. }
  870. }
  871. }
  872. previousCollisions_ = currentCollisions_;
  873. }
  874. void RegisterPhysicsLibrary(Context* context)
  875. {
  876. CollisionShape::RegisterObject(context);
  877. RigidBody::RegisterObject(context);
  878. Constraint::RegisterObject(context);
  879. PhysicsWorld::RegisterObject(context);
  880. }
  881. }