PhysicsWorld.cpp 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103
  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> >, ManifoldPair>::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. // First only store the collision pair as weak pointers and the manifold pointer, so user code can safely destroy
  739. // objects during collision event handling
  740. Pair<WeakPtr<RigidBody>, WeakPtr<RigidBody> > bodyPair;
  741. if (bodyA < bodyB)
  742. {
  743. bodyPair = MakePair(bodyWeakA, bodyWeakB);
  744. currentCollisions_[bodyPair].manifold_ = contactManifold;
  745. }
  746. else
  747. {
  748. bodyPair = MakePair(bodyWeakB, bodyWeakA);
  749. currentCollisions_[bodyPair].flippedManifold_ = contactManifold;
  750. }
  751. }
  752. for (HashMap<Pair<WeakPtr<RigidBody>, WeakPtr<RigidBody> >, ManifoldPair>::Iterator i = currentCollisions_.Begin();
  753. i != currentCollisions_.End(); ++i)
  754. {
  755. RigidBody* bodyA = i->first_.first_;
  756. RigidBody* bodyB = i->first_.second_;
  757. if (!bodyA || !bodyB)
  758. continue;
  759. Node* nodeA = bodyA->GetNode();
  760. Node* nodeB = bodyB->GetNode();
  761. WeakPtr<Node> nodeWeakA(nodeA);
  762. WeakPtr<Node> nodeWeakB(nodeB);
  763. bool trigger = bodyA->IsTrigger() || bodyB->IsTrigger();
  764. bool newCollision = !previousCollisions_.Contains(i->first_);
  765. physicsCollisionData_[PhysicsCollision::P_NODEA] = nodeA;
  766. physicsCollisionData_[PhysicsCollision::P_NODEB] = nodeB;
  767. physicsCollisionData_[PhysicsCollision::P_BODYA] = bodyA;
  768. physicsCollisionData_[PhysicsCollision::P_BODYB] = bodyB;
  769. physicsCollisionData_[PhysicsCollision::P_TRIGGER] = trigger;
  770. contacts_.Clear();
  771. // "Pointers not flipped"-manifold, send unmodified normals
  772. btPersistentManifold* contactManifold = i->second_.manifold_;
  773. if (contactManifold)
  774. {
  775. for (int j = 0; j < contactManifold->getNumContacts(); ++j)
  776. {
  777. btManifoldPoint& point = contactManifold->getContactPoint(j);
  778. contacts_.WriteVector3(ToVector3(point.m_positionWorldOnB));
  779. contacts_.WriteVector3(ToVector3(point.m_normalWorldOnB));
  780. contacts_.WriteFloat(point.m_distance1);
  781. contacts_.WriteFloat(point.m_appliedImpulse);
  782. }
  783. }
  784. // "Pointers flipped"-manifold, flip normals also
  785. contactManifold = i->second_.flippedManifold_;
  786. if (contactManifold)
  787. {
  788. for (int j = 0; j < contactManifold->getNumContacts(); ++j)
  789. {
  790. btManifoldPoint& point = contactManifold->getContactPoint(j);
  791. contacts_.WriteVector3(ToVector3(point.m_positionWorldOnB));
  792. contacts_.WriteVector3(-ToVector3(point.m_normalWorldOnB));
  793. contacts_.WriteFloat(point.m_distance1);
  794. contacts_.WriteFloat(point.m_appliedImpulse);
  795. }
  796. }
  797. physicsCollisionData_[PhysicsCollision::P_CONTACTS] = contacts_.GetBuffer();
  798. // Send separate collision start event if collision is new
  799. if (newCollision)
  800. {
  801. SendEvent(E_PHYSICSCOLLISIONSTART, physicsCollisionData_);
  802. // Skip rest of processing if either of the nodes or bodies is removed as a response to the event
  803. if (!nodeWeakA || !nodeWeakB || !i->first_.first_ || !i->first_.second_)
  804. continue;
  805. }
  806. // Then send the ongoing collision event
  807. SendEvent(E_PHYSICSCOLLISION, physicsCollisionData_);
  808. if (!nodeWeakA || !nodeWeakB || !i->first_.first_ || !i->first_.second_)
  809. continue;
  810. nodeCollisionData_[NodeCollision::P_BODY] = bodyA;
  811. nodeCollisionData_[NodeCollision::P_OTHERNODE] = nodeB;
  812. nodeCollisionData_[NodeCollision::P_OTHERBODY] = bodyB;
  813. nodeCollisionData_[NodeCollision::P_TRIGGER] = trigger;
  814. nodeCollisionData_[NodeCollision::P_CONTACTS] = contacts_.GetBuffer();
  815. if (newCollision)
  816. {
  817. nodeA->SendEvent(E_NODECOLLISIONSTART, nodeCollisionData_);
  818. if (!nodeWeakA || !nodeWeakB || !i->first_.first_ || !i->first_.second_)
  819. continue;
  820. }
  821. nodeA->SendEvent(E_NODECOLLISION, nodeCollisionData_);
  822. if (!nodeWeakA || !nodeWeakB || !i->first_.first_ || !i->first_.second_)
  823. continue;
  824. // Flip perspective to body B
  825. contacts_.Clear();
  826. contactManifold = i->second_.manifold_;
  827. if (contactManifold)
  828. {
  829. for (int j = 0; j < contactManifold->getNumContacts(); ++j)
  830. {
  831. btManifoldPoint& point = contactManifold->getContactPoint(j);
  832. contacts_.WriteVector3(ToVector3(point.m_positionWorldOnB));
  833. contacts_.WriteVector3(-ToVector3(point.m_normalWorldOnB));
  834. contacts_.WriteFloat(point.m_distance1);
  835. contacts_.WriteFloat(point.m_appliedImpulse);
  836. }
  837. }
  838. contactManifold = i->second_.flippedManifold_;
  839. if (contactManifold)
  840. {
  841. for (int j = 0; j < contactManifold->getNumContacts(); ++j)
  842. {
  843. btManifoldPoint& point = contactManifold->getContactPoint(j);
  844. contacts_.WriteVector3(ToVector3(point.m_positionWorldOnB));
  845. contacts_.WriteVector3(ToVector3(point.m_normalWorldOnB));
  846. contacts_.WriteFloat(point.m_distance1);
  847. contacts_.WriteFloat(point.m_appliedImpulse);
  848. }
  849. }
  850. nodeCollisionData_[NodeCollision::P_BODY] = bodyB;
  851. nodeCollisionData_[NodeCollision::P_OTHERNODE] = nodeA;
  852. nodeCollisionData_[NodeCollision::P_OTHERBODY] = bodyA;
  853. nodeCollisionData_[NodeCollision::P_CONTACTS] = contacts_.GetBuffer();
  854. if (newCollision)
  855. {
  856. nodeB->SendEvent(E_NODECOLLISIONSTART, nodeCollisionData_);
  857. if (!nodeWeakA || !nodeWeakB || !i->first_.first_ || !i->first_.second_)
  858. continue;
  859. }
  860. nodeB->SendEvent(E_NODECOLLISION, nodeCollisionData_);
  861. }
  862. }
  863. // Send collision end events as applicable
  864. {
  865. physicsCollisionData_[PhysicsCollisionEnd::P_WORLD] = this;
  866. for (HashMap<Pair<WeakPtr<RigidBody>, WeakPtr<RigidBody> >, ManifoldPair>::Iterator
  867. i = previousCollisions_.Begin(); i != previousCollisions_.End(); ++i)
  868. {
  869. if (!currentCollisions_.Contains(i->first_))
  870. {
  871. RigidBody* bodyA = i->first_.first_;
  872. RigidBody* bodyB = i->first_.second_;
  873. if (!bodyA || !bodyB)
  874. continue;
  875. bool trigger = bodyA->IsTrigger() || bodyB->IsTrigger();
  876. // Skip collision event signaling if both objects are static, or if collision event mode does not match
  877. if (bodyA->GetMass() == 0.0f && bodyB->GetMass() == 0.0f)
  878. continue;
  879. if (bodyA->GetCollisionEventMode() == COLLISION_NEVER || bodyB->GetCollisionEventMode() == COLLISION_NEVER)
  880. continue;
  881. if (bodyA->GetCollisionEventMode() == COLLISION_ACTIVE && bodyB->GetCollisionEventMode() == COLLISION_ACTIVE &&
  882. !bodyA->IsActive() && !bodyB->IsActive())
  883. continue;
  884. Node* nodeA = bodyA->GetNode();
  885. Node* nodeB = bodyB->GetNode();
  886. WeakPtr<Node> nodeWeakA(nodeA);
  887. WeakPtr<Node> nodeWeakB(nodeB);
  888. physicsCollisionData_[PhysicsCollisionEnd::P_BODYA] = bodyA;
  889. physicsCollisionData_[PhysicsCollisionEnd::P_BODYB] = bodyB;
  890. physicsCollisionData_[PhysicsCollisionEnd::P_NODEA] = nodeA;
  891. physicsCollisionData_[PhysicsCollisionEnd::P_NODEB] = nodeB;
  892. physicsCollisionData_[PhysicsCollisionEnd::P_TRIGGER] = trigger;
  893. SendEvent(E_PHYSICSCOLLISIONEND, physicsCollisionData_);
  894. // Skip rest of processing if either of the nodes or bodies is removed as a response to the event
  895. if (!nodeWeakA || !nodeWeakB || !i->first_.first_ || !i->first_.second_)
  896. continue;
  897. nodeCollisionData_[NodeCollisionEnd::P_BODY] = bodyA;
  898. nodeCollisionData_[NodeCollisionEnd::P_OTHERNODE] = nodeB;
  899. nodeCollisionData_[NodeCollisionEnd::P_OTHERBODY] = bodyB;
  900. nodeCollisionData_[NodeCollisionEnd::P_TRIGGER] = trigger;
  901. nodeA->SendEvent(E_NODECOLLISIONEND, nodeCollisionData_);
  902. if (!nodeWeakA || !nodeWeakB || !i->first_.first_ || !i->first_.second_)
  903. continue;
  904. nodeCollisionData_[NodeCollisionEnd::P_BODY] = bodyB;
  905. nodeCollisionData_[NodeCollisionEnd::P_OTHERNODE] = nodeA;
  906. nodeCollisionData_[NodeCollisionEnd::P_OTHERBODY] = bodyA;
  907. nodeB->SendEvent(E_NODECOLLISIONEND, nodeCollisionData_);
  908. }
  909. }
  910. }
  911. previousCollisions_ = currentCollisions_;
  912. }
  913. void RegisterPhysicsLibrary(Context* context)
  914. {
  915. CollisionShape::RegisterObject(context);
  916. RigidBody::RegisterObject(context);
  917. Constraint::RegisterObject(context);
  918. PhysicsWorld::RegisterObject(context);
  919. }
  920. }