// MIT License // Copyright (c) 2019 Erin Catto // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. #ifndef B2_WORLD_H #define B2_WORLD_H #include "b2_api.h" #include "b2_block_allocator.h" #include "b2_contact_manager.h" #include "b2_math.h" #include "b2_stack_allocator.h" #include "b2_time_step.h" #include "b2_world_callbacks.h" #include "b2_particle_system.h" struct b2AABB; struct b2BodyDef; struct b2Color; struct b2JointDef; class b2Body; class b2Draw; class b2Fixture; class b2Joint; class b2ParticleGroup; /// The world class manages all physics entities, dynamic simulation, /// and asynchronous queries. The world also contains efficient memory /// management facilities. class B2_API b2World { public: /// Construct a world object. /// @param gravity the world gravity vector. b2World(const b2Vec2& gravity); /// Destruct the world. All physics entities are destroyed and all heap memory is released. ~b2World(); /// Register a destruction listener. The listener is owned by you and must /// remain in scope. void SetDestructionListener(b2DestructionListener* listener); /// Register a contact filter to provide specific control over collision. /// Otherwise the default filter is used (b2_defaultFilter). The listener is /// owned by you and must remain in scope. void SetContactFilter(b2ContactFilter* filter); /// Register a contact event listener. The listener is owned by you and must /// remain in scope. void SetContactListener(b2ContactListener* listener); /// Register a routine for debug drawing. The debug draw functions are called /// inside with b2World::DrawDebugData method. The debug draw object is owned /// by you and must remain in scope. void SetDebugDraw(b2Draw* debugDraw); /// Create a rigid body given a definition. No reference to the definition /// is retained. /// @warning This function is locked during callbacks. b2Body* CreateBody(const b2BodyDef* def); /// Destroy a rigid body given a definition. No reference to the definition /// is retained. This function is locked during callbacks. /// @warning This automatically deletes all associated shapes and joints. /// @warning This function is locked during callbacks. void DestroyBody(b2Body* body); /// Create a joint to constrain bodies together. No reference to the definition /// is retained. This may cause the connected bodies to cease colliding. /// @warning This function is locked during callbacks. b2Joint* CreateJoint(const b2JointDef* def); /// Destroy a joint. This may cause the connected bodies to begin colliding. /// @warning This function is locked during callbacks. void DestroyJoint(b2Joint* joint); #ifdef ENABLE_LIQUID /// Create a particle system given a definition. No reference to the /// definition is retained. /// @warning This function is locked during callbacks. b2ParticleSystem* CreateParticleSystem(const b2ParticleSystemDef* def); /// Destroy a particle system. /// @warning This function is locked during callbacks. void DestroyParticleSystem(b2ParticleSystem* p); /// Get the world particle-system list. With the returned body, use /// b2ParticleSystem::GetNext to get the next particle-system in the world /// list. A NULL particle-system indicates the end of the list. /// @return the head of the world particle-system list. b2ParticleSystem* GetParticleSystemList(); const b2ParticleSystem* GetParticleSystemList() const; #endif // ENABLE_LIQUID /// Take a time step. This performs collision detection, integration, /// and constraint solution. /// For the numerical stability of particles, minimize the following /// dimensionless gravity acceleration: /// gravity / particleRadius * (timeStep / particleIterations)^2 /// b2CalculateParticleIterations() or /// CalculateReasonableParticleIterations() help to determine the optimal /// particleIterations. /// @param timeStep the amount of time to simulate, this should not vary. /// @param velocityIterations for the velocity constraint solver. /// @param positionIterations for the position constraint solver. /// @param particleIterations for the particle simulation. void Step( float32 timeStep, int32 velocityIterations, int32 positionIterations, int32 particleIterations); /// Take a time step. This performs collision detection, integration, /// and constraint solution. /// @param timeStep the amount of time to simulate, this should not vary. /// @param velocityIterations for the velocity constraint solver. /// @param positionIterations for the position constraint solver. void Step( float timeStep, int32 velocityIterations, int32 positionIterations) { Step(timeStep, velocityIterations, positionIterations, 1); } /// Manually clear the force buffer on all bodies. By default, forces are cleared automatically /// after each call to Step. The default behavior is modified by calling SetAutoClearForces. /// The purpose of this function is to support sub-stepping. Sub-stepping is often used to maintain /// a fixed sized time step under a variable frame-rate. /// When you perform sub-stepping you will disable auto clearing of forces and instead call /// ClearForces after all sub-steps are complete in one pass of your game loop. /// @see SetAutoClearForces void ClearForces(); /// Call this to draw shapes and other debug draw data. This is intentionally non-const. void DebugDraw(); /// Query the world for all fixtures that potentially overlap the /// provided AABB. /// @param callback a user implemented callback class. /// @param aabb the query box. void QueryAABB(b2QueryCallback* callback, const b2AABB& aabb); /// Ray-cast the world for all fixtures in the path of the ray. Your callback /// controls whether you get the closest point, any point, or n-points. /// The ray-cast ignores shapes that contain the starting point. /// @param callback a user implemented callback class. /// @param point1 the ray starting point /// @param point2 the ray ending point void RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2); /// Get the world body list. With the returned body, use b2Body::GetNext to get /// the next body in the world list. A nullptr body indicates the end of the list. /// @return the head of the world body list. b2Body* GetBodyList(); const b2Body* GetBodyList() const; /// Get the world joint list. With the returned joint, use b2Joint::GetNext to get /// the next joint in the world list. A nullptr joint indicates the end of the list. /// @return the head of the world joint list. b2Joint* GetJointList(); const b2Joint* GetJointList() const; /// Get the world contact list. With the returned contact, use b2Contact::GetNext to get /// the next contact in the world list. A special marker contact, returned by GetContactListEnd, indicates the end of the list. /// @return the head of the world contact list. /// @warning contacts are created and destroyed in the middle of a time step. /// Use b2ContactListener to avoid missing contacts. b2Contact* GetContactListStart(); const b2Contact* GetContactListStart() const; /// @return a special marker contact that marks the end of iteration for the contact list. b2Contact* GetContactListEnd(); const b2Contact* GetContactListEnd() const; /// Enable/disable sleep. void SetAllowSleeping(bool flag); bool GetAllowSleeping() const { return m_allowSleep; } /// Enable/disable warm starting. For testing. void SetWarmStarting(bool flag) { m_warmStarting = flag; } bool GetWarmStarting() const { return m_warmStarting; } /// Enable/disable continuous physics. For testing. void SetContinuousPhysics(bool flag) { m_continuousPhysics = flag; } bool GetContinuousPhysics() const { return m_continuousPhysics; } /// Enable/disable single stepped continuous physics. For testing. void SetSubStepping(bool flag) { m_subStepping = flag; } bool GetSubStepping() const { return m_subStepping; } /// Get the number of broad-phase proxies. int32 GetProxyCount() const; /// Get the number of bodies. int32 GetBodyCount() const; /// Get the number of joints. int32 GetJointCount() const; /// Get the number of contacts (each may have 0 or more contact points). int32 GetContactCount() const; /// Get the height of the dynamic tree. int32 GetTreeHeight() const; /// Change the global gravity vector. void SetGravity(const b2Vec2& gravity); /// Get the global gravity vector. b2Vec2 GetGravity() const; /// Is the world locked (in the middle of a time step). bool IsLocked() const; /// Set flag to control automatic clearing of forces after each time step. void SetAutoClearForces(bool flag); /// Get the flag that controls automatic clearing of forces after each time step. bool GetAutoClearForces() const; /// Shift the world origin. Useful for large worlds. /// The body shift formula is: position -= newOrigin /// @param newOrigin the new origin with respect to the old origin void ShiftOrigin(const b2Vec2& newOrigin); /// Get the contact manager for testing. const b2ContactManager& GetContactManager() const; /// Get the current profile. const b2Profile& GetProfile() const; /// Dump the world into the log file. /// @warning this should be called outside of a time step. void Dump(); private: friend class b2Body; friend class b2Fixture; friend class b2ContactManager; friend class b2Controller; friend class b2ParticleSystem; void RemoveDeadContacts(); void Solve(const b2TimeStep& step); void SolveTOI(const b2TimeStep& step); float CalculateTOI(b2Contact* c); void DrawShape(b2Fixture* shape, const b2Transform& xf, const b2Color& color); void DrawParticleSystem(const b2ParticleSystem& system); b2BlockAllocator m_blockAllocator; b2StackAllocator m_stackAllocator; b2ContactManager m_contactManager; b2Body* m_bodyListHead; b2Body* m_bodyListTail; b2Joint* m_jointList; b2ParticleSystem* m_particleSystemList; int32 m_bodyCount; int32 m_jointCount; b2Vec2 m_gravity; bool m_allowSleep; b2DestructionListener* m_destructionListener; b2Draw* m_debugDraw; // This is used to compute the time step ratio to // support a variable time step. float m_inv_dt0; bool m_newContacts; bool m_removedBodies; bool m_locked; bool m_clearForces; // These are for debugging the solver. bool m_warmStarting; bool m_continuousPhysics; bool m_subStepping; bool m_stepComplete; b2Profile m_profile; }; inline b2Body* b2World::GetBodyList() { return m_bodyListHead; } inline const b2Body* b2World::GetBodyList() const { return m_bodyListHead; } inline b2Joint* b2World::GetJointList() { return m_jointList; } inline const b2Joint* b2World::GetJointList() const { return m_jointList; } inline b2Contact* b2World::GetContactListStart() { return m_contactManager.Start(); } inline const b2Contact* b2World::GetContactListStart() const { return m_contactManager.Start(); } inline b2Contact* b2World::GetContactListEnd() { return m_contactManager.End(); } inline const b2Contact* b2World::GetContactListEnd() const { return m_contactManager.End(); } #ifdef ENABLE_LIQUID inline b2ParticleSystem* b2World::GetParticleSystemList() { return m_particleSystemList; } inline const b2ParticleSystem* b2World::GetParticleSystemList() const { return m_particleSystemList; } #endif // ENABLE_LIQUID inline int32 b2World::GetBodyCount() const { return m_bodyCount; } inline int32 b2World::GetJointCount() const { return m_jointCount; } inline int32 b2World::GetContactCount() const { return m_contactManager.m_contactCount; } inline void b2World::SetGravity(const b2Vec2& gravity) { m_gravity = gravity; } inline b2Vec2 b2World::GetGravity() const { return m_gravity; } inline bool b2World::IsLocked() const { return m_locked; } inline void b2World::SetAutoClearForces(bool flag) { m_clearForces = flag; } /// Get the flag that controls automatic clearing of forces after each time step. inline bool b2World::GetAutoClearForces() const { return m_clearForces; } inline const b2ContactManager& b2World::GetContactManager() const { return m_contactManager; } inline const b2Profile& b2World::GetProfile() const { return m_profile; } #endif