| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413 |
- //
- // Copyright (c) 2008-2014 the Urho3D project.
- //
- // 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.
- //
- #include "Precompiled.h"
- #include "Context.h"
- #include "DebugRenderer.h"
- #include "PhysicsEvents2D.h"
- #include "PhysicsUtils2D.h"
- #include "PhysicsWorld2D.h"
- #include "Profiler.h"
- #include "RigidBody2D.h"
- #include "Scene.h"
- #include "SceneEvents.h"
- #include "DebugNew.h"
- namespace Urho3D
- {
- extern const char* SUBSYSTEM_CATEGORY;
- static const Vector2 DEFAULT_GRAVITY(0.0f, -9.81f);
- PhysicsWorld2D::PhysicsWorld2D(Context* context) : Component(context),
- world_(0),
- gravity_(DEFAULT_GRAVITY),
- velocityIterations_(8),
- positionIterations_(3),
- debugRenderer_(0),
- applyingTransforms_(false)
- {
- // Set default debug draw flags
- m_drawFlags = e_shapeBit;
- // Create Box2D world
- world_ = new b2World(ToB2Vec2(gravity_));
- // Set contact listener
- world_->SetContactListener(this);
- // Set debug draw
- world_->SetDebugDraw(this);
- world_->SetContinuousPhysics(true);
- world_->SetSubStepping(true);
- }
- PhysicsWorld2D::~PhysicsWorld2D()
- {
- for (unsigned i = 0; i < rigidBodies_.Size(); ++i)
- if (rigidBodies_[i])
- rigidBodies_[i]->ReleaseBody();
- delete world_;
- world_ = 0;
- }
- void PhysicsWorld2D::RegisterObject(Context* context)
- {
- context->RegisterFactory<PhysicsWorld2D>(SUBSYSTEM_CATEGORY);
- ACCESSOR_ATTRIBUTE(PhysicsWorld2D, VAR_BOOL, "Draw Shape", GetDrawShape, SetDrawShape, bool, false, AM_DEFAULT);
- ACCESSOR_ATTRIBUTE(PhysicsWorld2D, VAR_BOOL, "Draw Joint", GetDrawJoint, SetDrawJoint, bool, false, AM_DEFAULT);
- ACCESSOR_ATTRIBUTE(PhysicsWorld2D, VAR_BOOL, "Draw Aabb", GetDrawAabb, SetDrawAabb, bool, false, AM_DEFAULT);
- ACCESSOR_ATTRIBUTE(PhysicsWorld2D, VAR_BOOL, "Draw Pair", GetDrawPair, SetDrawPair, bool, false, AM_DEFAULT);
- ACCESSOR_ATTRIBUTE(PhysicsWorld2D, VAR_BOOL, "Draw CenterOfMass", GetDrawCenterOfMass, SetDrawCenterOfMass, bool, false, AM_DEFAULT);
- ACCESSOR_ATTRIBUTE(PhysicsWorld2D, VAR_BOOL, "Allow Sleeping", GetAllowSleeping, SetAllowSleeping, bool, false, AM_DEFAULT);
- ACCESSOR_ATTRIBUTE(PhysicsWorld2D, VAR_BOOL, "Warm Starting", GetWarmStarting, SetWarmStarting, bool, false, AM_DEFAULT);
- ACCESSOR_ATTRIBUTE(PhysicsWorld2D, VAR_BOOL, "Continuous Physics", GetContinuousPhysics, SetContinuousPhysics, bool, false, AM_DEFAULT);
- ACCESSOR_ATTRIBUTE(PhysicsWorld2D, VAR_BOOL, "Sub Stepping", GetSubStepping, SetSubStepping, bool, false, AM_DEFAULT);
- REF_ACCESSOR_ATTRIBUTE(PhysicsWorld2D, VAR_VECTOR2, "Gravity", GetGravity, SetGravity, Vector2, DEFAULT_GRAVITY, AM_DEFAULT);
- ACCESSOR_ATTRIBUTE(PhysicsWorld2D, VAR_BOOL, "Auto Clear Forces", GetAutoClearForces, SetAutoClearForces, bool, false, AM_DEFAULT);
- ACCESSOR_ATTRIBUTE(PhysicsWorld2D, VAR_INT, "Velocity Iterations", GetVelocityIterations, SetVelocityIterations, int, false, AM_DEFAULT);
- ACCESSOR_ATTRIBUTE(PhysicsWorld2D, VAR_INT, "Position Iterations", GetPositionIterations, SetPositionIterations, int, false, AM_DEFAULT);
- COPY_BASE_ATTRIBUTES(PhysicsWorld2D, Component);
- }
- void PhysicsWorld2D::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
- {
- if (debug)
- {
- PROFILE(Physics2DDrawDebug);
- debugRenderer_ = debug;
- debugDepthTest_ = depthTest;
- world_->DrawDebugData();
- debugRenderer_ = 0;
- }
- }
- void PhysicsWorld2D::BeginContact(b2Contact* contact)
- {
- b2Fixture* fixtureA = contact->GetFixtureA();
- b2Fixture* fixtureB = contact->GetFixtureB();
- if (!fixtureA || !fixtureB)
- return;
- using namespace PhysicsBeginContact2D;
- VariantMap& eventData = GetEventDataMap();
- eventData[P_WORLD] = this;
- RigidBody2D* rigidBodyA = (RigidBody2D*)(fixtureA->GetBody()->GetUserData());
- RigidBody2D* rigidBodyB = (RigidBody2D*)(fixtureB->GetBody()->GetUserData());
- eventData[P_BODYA] = rigidBodyA;
- eventData[P_BODYB] = rigidBodyB;
- eventData[P_NODEA] = rigidBodyA->GetNode();
- eventData[P_NODEB] = rigidBodyB->GetNode();
- SendEvent(E_PHYSICSBEGINCONTACT2D, eventData);
- }
- void PhysicsWorld2D::EndContact(b2Contact* contact)
- {
- b2Fixture* fixtureA = contact->GetFixtureA();
- b2Fixture* fixtureB = contact->GetFixtureB();
- if (!fixtureA || !fixtureB)
- return;
- using namespace PhysicsEndContact2D;
- VariantMap& eventData = GetEventDataMap();
- eventData[P_WORLD] = this;
- RigidBody2D* rigidBodyA = (RigidBody2D*)(fixtureA->GetBody()->GetUserData());
- RigidBody2D* rigidBodyB = (RigidBody2D*)(fixtureB->GetBody()->GetUserData());
- eventData[P_BODYA] = rigidBodyA;
- eventData[P_BODYB] = rigidBodyB;
- eventData[P_NODEA] = rigidBodyA->GetNode();
- eventData[P_NODEB] = rigidBodyB->GetNode();
- SendEvent(E_PHYSICSENDCOLLISION2D, eventData);
- }
- void PhysicsWorld2D::DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color)
- {
- if (!debugRenderer_)
- return;
- Color c = ToColor(color);
- for (int i = 0; i < vertexCount - 1; ++i)
- debugRenderer_->AddLine(ToVector3(vertices[i]), ToVector3(vertices[i + 1]), c, debugDepthTest_);
- debugRenderer_->AddLine(ToVector3(vertices[vertexCount - 1]), ToVector3(vertices[0]), c, debugDepthTest_);
- }
- void PhysicsWorld2D::DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color)
- {
- if (!debugRenderer_)
- return;
- Vector3 v = ToVector3(vertices[0]);
- Color c(color.r, color.g, color.b, 0.5f);
- for (int i = 1; i < vertexCount - 1; ++i)
- debugRenderer_->AddTriangle(v, ToVector3(vertices[i]), ToVector3(vertices[i + 1]), c, debugDepthTest_);
- }
- void PhysicsWorld2D::DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color)
- {
- if (!debugRenderer_)
- return;
- Vector3 p = ToVector3(center);
- Color c = ToColor(color);
- for (unsigned i = 0; i < 360; i += 30)
- {
- unsigned j = i + 30;
- float x1 = radius * Cos((float)i);
- float y1 = radius * Sin((float)i);
- float x2 = radius * Cos((float)j);
- float y2 = radius * Sin((float)j);
- debugRenderer_->AddLine(p + Vector3(x1, y1, 0.0f), p + Vector3(x2, y2, 0.0f), c, debugDepthTest_);
- }
- }
- void PhysicsWorld2D::DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color)
- {
- if (!debugRenderer_)
- return;
- Vector3 p = ToVector3(center);
- Color c(color.r, color.g, color.b, 0.5f);
- for (unsigned i = 0; i < 360; i += 30)
- {
- unsigned j = i + 30;
- float x1 = radius * Cos((float)i);
- float y1 = radius * Sin((float)i);
- float x2 = radius * Cos((float)j);
- float y2 = radius * Sin((float)j);
- debugRenderer_->AddTriangle(p, p + Vector3(x1, y1, 0.0f), p + Vector3(x2, y2, 0.0f), c, debugDepthTest_);
- }
- }
- void PhysicsWorld2D::DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color)
- {
- if (debugRenderer_)
- debugRenderer_->AddLine(ToVector3(p1), ToVector3(p2), ToColor(color), debugDepthTest_);
- }
- void PhysicsWorld2D::DrawTransform(const b2Transform& xf)
- {
- if (!debugRenderer_)
- return;
- const float32 axisScale = 0.4f;
- b2Vec2 p1 = xf.p, p2;
- p2 = p1 + axisScale * xf.q.GetXAxis();
- debugRenderer_->AddLine(Vector3(p1.x, p1.y, 0.0f), Vector3(p2.x, p2.y, 0.0f), Color::RED, debugDepthTest_);
- p2 = p1 + axisScale * xf.q.GetYAxis();
- debugRenderer_->AddLine(Vector3(p1.x, p1.y, 0.0f), Vector3(p2.x, p2.y, 0.0f), Color::GREEN, debugDepthTest_);
- }
- void PhysicsWorld2D::SetDrawShape(bool drawShape)
- {
- if (drawShape)
- m_drawFlags |= e_shapeBit;
- else
- m_drawFlags &= ~e_shapeBit;
- }
- void PhysicsWorld2D::SetDrawJoint(bool drawJoint)
- {
- if (drawJoint)
- m_drawFlags |= e_jointBit;
- else
- m_drawFlags &= ~e_jointBit;
- }
- void PhysicsWorld2D::SetDrawAabb(bool drawAabb)
- {
- if (drawAabb)
- m_drawFlags |= e_aabbBit;
- else
- m_drawFlags &= ~e_aabbBit;
- }
- void PhysicsWorld2D::SetDrawPair(bool drawPair)
- {
- if (drawPair)
- m_drawFlags |= e_pairBit;
- else
- m_drawFlags &= ~e_pairBit;
- }
- void PhysicsWorld2D::SetDrawCenterOfMass(bool drawCenterOfMass)
- {
- if (drawCenterOfMass)
- m_drawFlags |= e_centerOfMassBit;
- else
- m_drawFlags &= ~e_centerOfMassBit;
- }
- void PhysicsWorld2D::SetAllowSleeping(bool enable)
- {
- world_->SetAllowSleeping(enable);
- }
- void PhysicsWorld2D::SetWarmStarting(bool enable)
- {
- world_->SetWarmStarting(enable);
- }
- void PhysicsWorld2D::SetContinuousPhysics(bool enable)
- {
- world_->SetContinuousPhysics(enable);
- }
- void PhysicsWorld2D::SetSubStepping(bool enable)
- {
- world_->SetSubStepping(enable);
- }
- void PhysicsWorld2D::SetGravity(const Vector2& gravity)
- {
- gravity_ = gravity;
- world_->SetGravity(ToB2Vec2(gravity_));
- }
- void PhysicsWorld2D::SetAutoClearForces(bool enable)
- {
- world_->SetAutoClearForces(enable);
- }
- void PhysicsWorld2D::SetVelocityIterations(int velocityIterations)
- {
- velocityIterations_ = velocityIterations;
- }
- void PhysicsWorld2D::SetPositionIterations(int positionIterations)
- {
- positionIterations_ = positionIterations;
- }
- void PhysicsWorld2D::AddRigidBody(RigidBody2D* rigidBody)
- {
- if (!rigidBody)
- return;
- WeakPtr<RigidBody2D> rigidBodyPtr(rigidBody);
- if (rigidBodies_.Contains(rigidBodyPtr))
- return;
- rigidBodies_.Push(rigidBodyPtr);
- }
- void PhysicsWorld2D::RemoveRigidBody(RigidBody2D* rigidBody)
- {
- if (!rigidBody)
- return;
- WeakPtr<RigidBody2D> rigidBodyPtr(rigidBody);
- rigidBodies_.Remove(rigidBodyPtr);
- }
- void PhysicsWorld2D::Update(float timeStep)
- {
- using namespace Physics2DPreStep2D;
- VariantMap& eventData = GetEventDataMap();
- eventData[P_WORLD] = this;
- eventData[P_TIMESTEP] = timeStep;
- SendEvent(E_PHYSICSPRESTEP2D, eventData);
- world_->Step(timeStep, velocityIterations_, positionIterations_);
- for (unsigned i = 0; i < rigidBodies_.Size(); ++i)
- rigidBodies_[i]->ApplyWorldTransform();
- using namespace PhysicsPostStep2D;
- SendEvent(E_PHYSICSPOSTSTEP2D, eventData);
- }
- void PhysicsWorld2D::DrawDebugGeometry()
- {
- DebugRenderer* debug = GetComponent<DebugRenderer>();
- if (debug)
- DrawDebugGeometry(debug, false);
- }
- void PhysicsWorld2D::SetDebugRenderer(DebugRenderer* debug)
- {
- debugRenderer_ = debug;
- }
- void PhysicsWorld2D::SetDebugDepthTest(bool enable)
- {
- debugDepthTest_ = enable;
- }
- bool PhysicsWorld2D::GetAllowSleeping() const
- {
- return world_->GetAllowSleeping();
- }
- bool PhysicsWorld2D::GetWarmStarting() const
- {
- return world_->GetWarmStarting();
- }
- bool PhysicsWorld2D::GetContinuousPhysics() const
- {
- return world_->GetContinuousPhysics();
- }
- bool PhysicsWorld2D::GetSubStepping() const
- {
- return world_->GetSubStepping();
- }
- bool PhysicsWorld2D::GetAutoClearForces() const
- {
- return world_->GetAutoClearForces();
- }
- void PhysicsWorld2D::OnNodeSet(Node* node)
- {
- // Subscribe to the scene subsystem update, which will trigger the physics simulation step
- if (node)
- {
- scene_ = GetScene();
- SubscribeToEvent(node, E_SCENESUBSYSTEMUPDATE, HANDLER(PhysicsWorld2D, HandleSceneSubsystemUpdate));
- }
- }
- void PhysicsWorld2D::HandleSceneSubsystemUpdate(StringHash eventType, VariantMap& eventData)
- {
- using namespace SceneSubsystemUpdate;
- Update(eventData[P_TIMESTEP].GetFloat());
- }
- }
|