123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500 |
- /*
- * Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
- * Copyright (c) 2013 Google, Inc.
- *
- * This software is provided 'as-is', without any express or implied
- * warranty. In no event will the authors be held liable for any damages
- * arising from the use of this software.
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- * 1. The origin of this software must not be misrepresented; you must not
- * claim that you wrote the original software. If you use this software
- * in a product, an acknowledgment in the product documentation would be
- * appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- * misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- */
- #include <Box2D/Dynamics/b2World.h>
- #include <Box2D/Dynamics/b2Body.h>
- #include <Box2D/Dynamics/b2Fixture.h>
- #include <Box2D/Dynamics/b2Island.h>
- #include <Box2D/Dynamics/Joints/b2PulleyJoint.h>
- #include <Box2D/Dynamics/Contacts/b2Contact.h>
- #include <Box2D/Dynamics/Contacts/b2ContactSolver.h>
- #include <Box2D/Collision/b2Collision.h>
- #include <Box2D/Collision/b2BroadPhase.h>
- #include <Box2D/Collision/Shapes/b2CircleShape.h>
- #include <Box2D/Collision/Shapes/b2EdgeShape.h>
- #include <Box2D/Collision/Shapes/b2ChainShape.h>
- #include <Box2D/Collision/Shapes/b2PolygonShape.h>
- #include <Box2D/Collision/b2TimeOfImpact.h>
- #include <Box2D/Common/b2Draw.h>
- #include <Box2D/Common/b2Timer.h>
- #include <new>
- b2World::b2World(const b2Vec2& gravity)
- {
- Init(gravity);
- }
- b2World::~b2World()
- {
- // Some shapes allocate using b2Alloc.
- b2Body* b = m_bodyList;
- while (b)
- {
- b2Body* bNext = b->m_next;
- b2Fixture* f = b->m_fixtureList;
- while (f)
- {
- b2Fixture* fNext = f->m_next;
- f->m_proxyCount = 0;
- f->Destroy(&m_blockAllocator);
- f = fNext;
- }
- b = bNext;
- }
- while (m_particleSystemList)
- {
- DestroyParticleSystem(m_particleSystemList);
- }
- // Even though the block allocator frees them for us, for safety,
- // we should ensure that all buffers have been freed.
- b2Assert(m_blockAllocator.GetNumGiantAllocations() == 0);
- }
- void b2World::SetDestructionListener(b2DestructionListener* listener)
- {
- m_destructionListener = listener;
- }
- void b2World::SetContactFilter(b2ContactFilter* filter)
- {
- m_contactManager.m_contactFilter = filter;
- }
- void b2World::SetContactListener(b2ContactListener* listener)
- {
- m_contactManager.m_contactListener = listener;
- }
- void b2World::SetDebugDraw(b2Draw* debugDraw)
- {
- m_debugDraw = debugDraw;
- }
- b2Body* b2World::CreateBody(const b2BodyDef* def)
- {
- b2Assert(IsLocked() == false);
- if (IsLocked())
- {
- return NULL;
- }
- void* mem = m_blockAllocator.Allocate(sizeof(b2Body));
- b2Body* b = new (mem) b2Body(def, this);
- // Add to world doubly linked list.
- b->m_prev = NULL;
- b->m_next = m_bodyList;
- if (m_bodyList)
- {
- m_bodyList->m_prev = b;
- }
- m_bodyList = b;
- ++m_bodyCount;
- return b;
- }
- void b2World::DestroyBody(b2Body* b)
- {
- b2Assert(m_bodyCount > 0);
- b2Assert(IsLocked() == false);
- if (IsLocked())
- {
- return;
- }
- // Delete the attached joints.
- b2JointEdge* je = b->m_jointList;
- while (je)
- {
- b2JointEdge* je0 = je;
- je = je->next;
- if (m_destructionListener)
- {
- m_destructionListener->SayGoodbye(je0->joint);
- }
- DestroyJoint(je0->joint);
- b->m_jointList = je;
- }
- b->m_jointList = NULL;
- // Delete the attached contacts.
- b2ContactEdge* ce = b->m_contactList;
- while (ce)
- {
- b2ContactEdge* ce0 = ce;
- ce = ce->next;
- m_contactManager.Destroy(ce0->contact);
- }
- b->m_contactList = NULL;
- // Delete the attached fixtures. This destroys broad-phase proxies.
- b2Fixture* f = b->m_fixtureList;
- while (f)
- {
- b2Fixture* f0 = f;
- f = f->m_next;
- if (m_destructionListener)
- {
- m_destructionListener->SayGoodbye(f0);
- }
- f0->DestroyProxies(&m_contactManager.m_broadPhase);
- f0->Destroy(&m_blockAllocator);
- f0->~b2Fixture();
- m_blockAllocator.Free(f0, sizeof(b2Fixture));
- b->m_fixtureList = f;
- b->m_fixtureCount -= 1;
- }
- b->m_fixtureList = NULL;
- b->m_fixtureCount = 0;
- // Remove world body list.
- if (b->m_prev)
- {
- b->m_prev->m_next = b->m_next;
- }
- if (b->m_next)
- {
- b->m_next->m_prev = b->m_prev;
- }
- if (b == m_bodyList)
- {
- m_bodyList = b->m_next;
- }
- --m_bodyCount;
- b->~b2Body();
- m_blockAllocator.Free(b, sizeof(b2Body));
- }
- b2Joint* b2World::CreateJoint(const b2JointDef* def)
- {
- b2Assert(IsLocked() == false);
- if (IsLocked())
- {
- return NULL;
- }
- b2Joint* j = b2Joint::Create(def, &m_blockAllocator);
- // Connect to the world list.
- j->m_prev = NULL;
- j->m_next = m_jointList;
- if (m_jointList)
- {
- m_jointList->m_prev = j;
- }
- m_jointList = j;
- ++m_jointCount;
- // Connect to the bodies' doubly linked lists.
- j->m_edgeA.joint = j;
- j->m_edgeA.other = j->m_bodyB;
- j->m_edgeA.prev = NULL;
- j->m_edgeA.next = j->m_bodyA->m_jointList;
- if (j->m_bodyA->m_jointList) j->m_bodyA->m_jointList->prev = &j->m_edgeA;
- j->m_bodyA->m_jointList = &j->m_edgeA;
- j->m_edgeB.joint = j;
- j->m_edgeB.other = j->m_bodyA;
- j->m_edgeB.prev = NULL;
- j->m_edgeB.next = j->m_bodyB->m_jointList;
- if (j->m_bodyB->m_jointList) j->m_bodyB->m_jointList->prev = &j->m_edgeB;
- j->m_bodyB->m_jointList = &j->m_edgeB;
- b2Body* bodyA = def->bodyA;
- b2Body* bodyB = def->bodyB;
- // If the joint prevents collisions, then flag any contacts for filtering.
- if (def->collideConnected == false)
- {
- b2ContactEdge* edge = bodyB->GetContactList();
- while (edge)
- {
- if (edge->other == bodyA)
- {
- // Flag the contact for filtering at the next time step (where either
- // body is awake).
- edge->contact->FlagForFiltering();
- }
- edge = edge->next;
- }
- }
- // Note: creating a joint doesn't wake the bodies.
- return j;
- }
- void b2World::DestroyJoint(b2Joint* j)
- {
- b2Assert(IsLocked() == false);
- if (IsLocked())
- {
- return;
- }
- bool collideConnected = j->m_collideConnected;
- // Remove from the doubly linked list.
- if (j->m_prev)
- {
- j->m_prev->m_next = j->m_next;
- }
- if (j->m_next)
- {
- j->m_next->m_prev = j->m_prev;
- }
- if (j == m_jointList)
- {
- m_jointList = j->m_next;
- }
- // Disconnect from island graph.
- b2Body* bodyA = j->m_bodyA;
- b2Body* bodyB = j->m_bodyB;
- // Wake up connected bodies.
- bodyA->SetAwake(true);
- bodyB->SetAwake(true);
- // Remove from body 1.
- if (j->m_edgeA.prev)
- {
- j->m_edgeA.prev->next = j->m_edgeA.next;
- }
- if (j->m_edgeA.next)
- {
- j->m_edgeA.next->prev = j->m_edgeA.prev;
- }
- if (&j->m_edgeA == bodyA->m_jointList)
- {
- bodyA->m_jointList = j->m_edgeA.next;
- }
- j->m_edgeA.prev = NULL;
- j->m_edgeA.next = NULL;
- // Remove from body 2
- if (j->m_edgeB.prev)
- {
- j->m_edgeB.prev->next = j->m_edgeB.next;
- }
- if (j->m_edgeB.next)
- {
- j->m_edgeB.next->prev = j->m_edgeB.prev;
- }
- if (&j->m_edgeB == bodyB->m_jointList)
- {
- bodyB->m_jointList = j->m_edgeB.next;
- }
- j->m_edgeB.prev = NULL;
- j->m_edgeB.next = NULL;
- b2Joint::Destroy(j, &m_blockAllocator);
- b2Assert(m_jointCount > 0);
- --m_jointCount;
- // If the joint prevents collisions, then flag any contacts for filtering.
- if (collideConnected == false)
- {
- b2ContactEdge* edge = bodyB->GetContactList();
- while (edge)
- {
- if (edge->other == bodyA)
- {
- // Flag the contact for filtering at the next time step (where either
- // body is awake).
- edge->contact->FlagForFiltering();
- }
- edge = edge->next;
- }
- }
- }
- b2ParticleSystem* b2World::CreateParticleSystem(const b2ParticleSystemDef* def)
- {
- b2Assert(IsLocked() == false);
- if (IsLocked())
- {
- return NULL;
- }
- void* mem = m_blockAllocator.Allocate(sizeof(b2ParticleSystem));
- b2ParticleSystem* p = new (mem) b2ParticleSystem(def, this);
- // Add to world doubly linked list.
- p->m_prev = NULL;
- p->m_next = m_particleSystemList;
- if (m_particleSystemList)
- {
- m_particleSystemList->m_prev = p;
- }
- m_particleSystemList = p;
- return p;
- }
- void b2World::DestroyParticleSystem(b2ParticleSystem* p)
- {
- b2Assert(m_particleSystemList != NULL);
- b2Assert(IsLocked() == false);
- if (IsLocked())
- {
- return;
- }
- // Remove world particleSystem list.
- if (p->m_prev)
- {
- p->m_prev->m_next = p->m_next;
- }
- if (p->m_next)
- {
- p->m_next->m_prev = p->m_prev;
- }
- if (p == m_particleSystemList)
- {
- m_particleSystemList = p->m_next;
- }
- p->~b2ParticleSystem();
- m_blockAllocator.Free(p, sizeof(b2ParticleSystem));
- }
- //
- void b2World::SetAllowSleeping(bool flag)
- {
- if (flag == m_allowSleep)
- {
- return;
- }
- m_allowSleep = flag;
- if (m_allowSleep == false)
- {
- for (b2Body* b = m_bodyList; b; b = b->m_next)
- {
- b->SetAwake(true);
- }
- }
- }
- // Initialize the world with a specified gravity.
- void b2World::Init(const b2Vec2& gravity)
- {
- m_destructionListener = NULL;
- m_debugDraw = NULL;
- m_bodyList = NULL;
- m_jointList = NULL;
- m_particleSystemList = NULL;
- m_bodyCount = 0;
- m_jointCount = 0;
- m_warmStarting = true;
- m_continuousPhysics = true;
- m_subStepping = false;
- m_stepComplete = true;
- m_allowSleep = true;
- m_gravity = gravity;
- m_flags = e_clearForces;
- m_inv_dt0 = 0.0f;
- m_contactManager.m_allocator = &m_blockAllocator;
- m_liquidFunVersion = &b2_liquidFunVersion;
- m_liquidFunVersionString = b2_liquidFunVersionString;
- memset(&m_profile, 0, sizeof(b2Profile));
- }
- // Find islands, integrate and solve constraints, solve position constraints
- void b2World::Solve(const b2TimeStep& step)
- {
- // update previous transforms
- for (b2Body* b = m_bodyList; b; b = b->m_next)
- {
- b->m_xf0 = b->m_xf;
- }
- m_profile.solveInit = 0.0f;
- m_profile.solveVelocity = 0.0f;
- m_profile.solvePosition = 0.0f;
- // Size the island for the worst case.
- b2Island island(m_bodyCount,
- m_contactManager.m_contactCount,
- m_jointCount,
- &m_stackAllocator,
- m_contactManager.m_contactListener);
- // Clear all the island flags.
- for (b2Body* b = m_bodyList; b; b = b->m_next)
- {
- b->m_flags &= ~b2Body::e_islandFlag;
- }
- for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next)
- {
- c->m_flags &= ~b2Contact::e_islandFlag;
- }
- for (b2Joint* j = m_jointList; j; j = j->m_next)
- {
- j->m_islandFlag = false;
- }
- // Build and simulate all awake islands.
- int32 stackSize = m_bodyCount;
- b2Body** stack = (b2Body**)m_stackAllocator.Allocate(stackSize * sizeof(b2Body*));
- for (b2Body* seed = m_bodyList; seed; seed = seed->m_next)
- {
- if (seed->m_flags & b2Body::e_islandFlag)
- {
- continue;
- }
- if (seed->IsAwake() == false || seed->IsActive() == false)
- {
- continue;
- }
- // The seed can be dynamic or kinematic.
- if (seed->GetType() == b2_staticBody)
- {
- continue;
- }
- // Reset island and stack.
- island.Clear();
- int32 stackCount = 0;
- stack[stackCount++] = seed;
- seed->m_flags |= b2Body::e_islandFlag;
- // Perform a depth first search (DFS) on the constraint graph.
- while (stackCount > 0)
- {
- // Grab the next body off the stack and add it to the island.
- b2Body* b = stack[--stackCount];
- b2Assert(b->IsActive() == true);
- island.Add(b);
- // Make sure the body is awake.
- b->SetAwake(true);
- // To keep islands as small as possible, we don't
- // propagate islands across static bodies.
- if (b->GetType() == b2_staticBody)
- {
- continue;
- }
- // Search all contacts connected to this body.
- for (b2ContactEdge* ce = b->m_contactList; ce; ce = ce->next)
- {
- b2Contact* contact = ce->contact;
- // Has this contact already been added to an island?
- if (contact->m_flags & b2Contact::e_islandFlag)
- {
- continue;
- }
- // Is this contact solid and touching?
- if (contact->IsEnabled() == false ||
- contact->IsTouching() == false)
- {
- continue;
- }
- // Skip sensors.
- bool sensorA = contact->m_fixtureA->m_isSensor;
- bool sensorB = contact->m_fixtureB->m_isSensor;
- if (sensorA || sensorB)
- {
- continue;
- }
- island.Add(contact);
- contact->m_flags |= b2Contact::e_islandFlag;
- b2Body* other = ce->other;
- // Was the other body already added to this island?
- if (other->m_flags & b2Body::e_islandFlag)
- {
- continue;
- }
- b2Assert(stackCount < stackSize);
- stack[stackCount++] = other;
- other->m_flags |= b2Body::e_islandFlag;
- }
- // Search all joints connect to this body.
- for (b2JointEdge* je = b->m_jointList; je; je = je->next)
- {
- if (je->joint->m_islandFlag == true)
- {
- continue;
- }
- b2Body* other = je->other;
- // Don't simulate joints connected to inactive bodies.
- if (other->IsActive() == false)
- {
- continue;
- }
- island.Add(je->joint);
- je->joint->m_islandFlag = true;
- if (other->m_flags & b2Body::e_islandFlag)
- {
- continue;
- }
- b2Assert(stackCount < stackSize);
- stack[stackCount++] = other;
- other->m_flags |= b2Body::e_islandFlag;
- }
- }
- b2Profile profile;
- island.Solve(&profile, step, m_gravity, m_allowSleep);
- m_profile.solveInit += profile.solveInit;
- m_profile.solveVelocity += profile.solveVelocity;
- m_profile.solvePosition += profile.solvePosition;
- // Post solve cleanup.
- for (int32 i = 0; i < island.m_bodyCount; ++i)
- {
- // Allow static bodies to participate in other islands.
- b2Body* b = island.m_bodies[i];
- if (b->GetType() == b2_staticBody)
- {
- b->m_flags &= ~b2Body::e_islandFlag;
- }
- }
- }
- m_stackAllocator.Free(stack);
- {
- b2Timer timer;
- // Synchronize fixtures, check for out of range bodies.
- for (b2Body* b = m_bodyList; b; b = b->GetNext())
- {
- // If a body was not in an island then it did not move.
- if ((b->m_flags & b2Body::e_islandFlag) == 0)
- {
- continue;
- }
- if (b->GetType() == b2_staticBody)
- {
- continue;
- }
- // Update fixtures (for broad-phase).
- b->SynchronizeFixtures();
- }
- // Look for new contacts.
- m_contactManager.FindNewContacts();
- m_profile.broadphase = timer.GetMilliseconds();
- }
- }
- // Find TOI contacts and solve them.
- void b2World::SolveTOI(const b2TimeStep& step)
- {
- b2Island island(2 * b2_maxTOIContacts, b2_maxTOIContacts, 0, &m_stackAllocator, m_contactManager.m_contactListener);
- if (m_stepComplete)
- {
- for (b2Body* b = m_bodyList; b; b = b->m_next)
- {
- b->m_flags &= ~b2Body::e_islandFlag;
- b->m_sweep.alpha0 = 0.0f;
- }
- for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next)
- {
- // Invalidate TOI
- c->m_flags &= ~(b2Contact::e_toiFlag | b2Contact::e_islandFlag);
- c->m_toiCount = 0;
- c->m_toi = 1.0f;
- }
- }
- // Find TOI events and solve them.
- for (;;)
- {
- // Find the first TOI.
- b2Contact* minContact = NULL;
- float32 minAlpha = 1.0f;
- for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next)
- {
- // Is this contact disabled?
- if (c->IsEnabled() == false)
- {
- continue;
- }
- // Prevent excessive sub-stepping.
- if (c->m_toiCount > b2_maxSubSteps)
- {
- continue;
- }
- float32 alpha = 1.0f;
- if (c->m_flags & b2Contact::e_toiFlag)
- {
- // This contact has a valid cached TOI.
- alpha = c->m_toi;
- }
- else
- {
- b2Fixture* fA = c->GetFixtureA();
- b2Fixture* fB = c->GetFixtureB();
- // Is there a sensor?
- if (fA->IsSensor() || fB->IsSensor())
- {
- continue;
- }
- b2Body* bA = fA->GetBody();
- b2Body* bB = fB->GetBody();
- b2BodyType typeA = bA->m_type;
- b2BodyType typeB = bB->m_type;
- b2Assert(typeA == b2_dynamicBody || typeB == b2_dynamicBody);
- bool activeA = bA->IsAwake() && typeA != b2_staticBody;
- bool activeB = bB->IsAwake() && typeB != b2_staticBody;
- // Is at least one body active (awake and dynamic or kinematic)?
- if (activeA == false && activeB == false)
- {
- continue;
- }
- bool collideA = bA->IsBullet() || typeA != b2_dynamicBody;
- bool collideB = bB->IsBullet() || typeB != b2_dynamicBody;
- // Are these two non-bullet dynamic bodies?
- if (collideA == false && collideB == false)
- {
- continue;
- }
- // Compute the TOI for this contact.
- // Put the sweeps onto the same time interval.
- float32 alpha0 = bA->m_sweep.alpha0;
- if (bA->m_sweep.alpha0 < bB->m_sweep.alpha0)
- {
- alpha0 = bB->m_sweep.alpha0;
- bA->m_sweep.Advance(alpha0);
- }
- else if (bB->m_sweep.alpha0 < bA->m_sweep.alpha0)
- {
- alpha0 = bA->m_sweep.alpha0;
- bB->m_sweep.Advance(alpha0);
- }
- b2Assert(alpha0 < 1.0f);
- int32 indexA = c->GetChildIndexA();
- int32 indexB = c->GetChildIndexB();
- // Compute the time of impact in interval [0, minTOI]
- b2TOIInput input;
- input.proxyA.Set(fA->GetShape(), indexA);
- input.proxyB.Set(fB->GetShape(), indexB);
- input.sweepA = bA->m_sweep;
- input.sweepB = bB->m_sweep;
- input.tMax = 1.0f;
- b2TOIOutput output;
- b2TimeOfImpact(&output, &input);
- // Beta is the fraction of the remaining portion of the .
- float32 beta = output.t;
- if (output.state == b2TOIOutput::e_touching)
- {
- alpha = b2Min(alpha0 + (1.0f - alpha0) * beta, 1.0f);
- }
- else
- {
- alpha = 1.0f;
- }
- c->m_toi = alpha;
- c->m_flags |= b2Contact::e_toiFlag;
- }
- if (alpha < minAlpha)
- {
- // This is the minimum TOI found so far.
- minContact = c;
- minAlpha = alpha;
- }
- }
- if (minContact == NULL || 1.0f - 10.0f * b2_epsilon < minAlpha)
- {
- // No more TOI events. Done!
- m_stepComplete = true;
- break;
- }
- // Advance the bodies to the TOI.
- b2Fixture* fA = minContact->GetFixtureA();
- b2Fixture* fB = minContact->GetFixtureB();
- b2Body* bA = fA->GetBody();
- b2Body* bB = fB->GetBody();
- b2Sweep backup1 = bA->m_sweep;
- b2Sweep backup2 = bB->m_sweep;
- bA->Advance(minAlpha);
- bB->Advance(minAlpha);
- // The TOI contact likely has some new contact points.
- minContact->Update(m_contactManager.m_contactListener);
- minContact->m_flags &= ~b2Contact::e_toiFlag;
- ++minContact->m_toiCount;
- // Is the contact solid?
- if (minContact->IsEnabled() == false || minContact->IsTouching() == false)
- {
- // Restore the sweeps.
- minContact->SetEnabled(false);
- bA->m_sweep = backup1;
- bB->m_sweep = backup2;
- bA->SynchronizeTransform();
- bB->SynchronizeTransform();
- continue;
- }
- bA->SetAwake(true);
- bB->SetAwake(true);
- // Build the island
- island.Clear();
- island.Add(bA);
- island.Add(bB);
- island.Add(minContact);
- bA->m_flags |= b2Body::e_islandFlag;
- bB->m_flags |= b2Body::e_islandFlag;
- minContact->m_flags |= b2Contact::e_islandFlag;
- // Get contacts on bodyA and bodyB.
- b2Body* bodies[2] = {bA, bB};
- for (int32 i = 0; i < 2; ++i)
- {
- b2Body* body = bodies[i];
- if (body->m_type == b2_dynamicBody)
- {
- for (b2ContactEdge* ce = body->m_contactList; ce; ce = ce->next)
- {
- if (island.m_bodyCount == island.m_bodyCapacity)
- {
- break;
- }
- if (island.m_contactCount == island.m_contactCapacity)
- {
- break;
- }
- b2Contact* contact = ce->contact;
- // Has this contact already been added to the island?
- if (contact->m_flags & b2Contact::e_islandFlag)
- {
- continue;
- }
- // Only add static, kinematic, or bullet bodies.
- b2Body* other = ce->other;
- if (other->m_type == b2_dynamicBody &&
- body->IsBullet() == false && other->IsBullet() == false)
- {
- continue;
- }
- // Skip sensors.
- bool sensorA = contact->m_fixtureA->m_isSensor;
- bool sensorB = contact->m_fixtureB->m_isSensor;
- if (sensorA || sensorB)
- {
- continue;
- }
- // Tentatively advance the body to the TOI.
- b2Sweep backup = other->m_sweep;
- if ((other->m_flags & b2Body::e_islandFlag) == 0)
- {
- other->Advance(minAlpha);
- }
- // Update the contact points
- contact->Update(m_contactManager.m_contactListener);
- // Was the contact disabled by the user?
- if (contact->IsEnabled() == false)
- {
- other->m_sweep = backup;
- other->SynchronizeTransform();
- continue;
- }
- // Are there contact points?
- if (contact->IsTouching() == false)
- {
- other->m_sweep = backup;
- other->SynchronizeTransform();
- continue;
- }
- // Add the contact to the island
- contact->m_flags |= b2Contact::e_islandFlag;
- island.Add(contact);
- // Has the other body already been added to the island?
- if (other->m_flags & b2Body::e_islandFlag)
- {
- continue;
- }
- // Add the other body to the island.
- other->m_flags |= b2Body::e_islandFlag;
- if (other->m_type != b2_staticBody)
- {
- other->SetAwake(true);
- }
- island.Add(other);
- }
- }
- }
- b2TimeStep subStep;
- subStep.dt = (1.0f - minAlpha) * step.dt;
- subStep.inv_dt = 1.0f / subStep.dt;
- subStep.dtRatio = 1.0f;
- subStep.positionIterations = 20;
- subStep.velocityIterations = step.velocityIterations;
- subStep.particleIterations = step.particleIterations;
- subStep.warmStarting = false;
- island.SolveTOI(subStep, bA->m_islandIndex, bB->m_islandIndex);
- // Reset island flags and synchronize broad-phase proxies.
- for (int32 i = 0; i < island.m_bodyCount; ++i)
- {
- b2Body* body = island.m_bodies[i];
- body->m_flags &= ~b2Body::e_islandFlag;
- if (body->m_type != b2_dynamicBody)
- {
- continue;
- }
- body->SynchronizeFixtures();
- // Invalidate all contact TOIs on this displaced body.
- for (b2ContactEdge* ce = body->m_contactList; ce; ce = ce->next)
- {
- ce->contact->m_flags &= ~(b2Contact::e_toiFlag | b2Contact::e_islandFlag);
- }
- }
- // Commit fixture proxy movements to the broad-phase so that new contacts are created.
- // Also, some contacts can be destroyed.
- m_contactManager.FindNewContacts();
- if (m_subStepping)
- {
- m_stepComplete = false;
- break;
- }
- }
- }
- void b2World::Step(
- float32 dt,
- int32 velocityIterations,
- int32 positionIterations,
- int32 particleIterations)
- {
- b2Timer stepTimer;
- // If new fixtures were added, we need to find the new contacts.
- if (m_flags & e_newFixture)
- {
- m_contactManager.FindNewContacts();
- m_flags &= ~e_newFixture;
- }
- m_flags |= e_locked;
- b2TimeStep step;
- step.dt = dt;
- step.velocityIterations = velocityIterations;
- step.positionIterations = positionIterations;
- step.particleIterations = particleIterations;
- if (dt > 0.0f)
- {
- step.inv_dt = 1.0f / dt;
- }
- else
- {
- step.inv_dt = 0.0f;
- }
- step.dtRatio = m_inv_dt0 * dt;
- step.warmStarting = m_warmStarting;
- // Update contacts. This is where some contacts are destroyed.
- {
- b2Timer timer;
- m_contactManager.Collide();
- m_profile.collide = timer.GetMilliseconds();
- }
- // Integrate velocities, solve velocity constraints, and integrate positions.
- if (m_stepComplete && step.dt > 0.0f)
- {
- b2Timer timer;
- for (b2ParticleSystem* p = m_particleSystemList; p; p = p->GetNext())
- {
- p->Solve(step); // Particle Simulation
- }
- Solve(step);
- m_profile.solve = timer.GetMilliseconds();
- }
- // Handle TOI events.
- if (m_continuousPhysics && step.dt > 0.0f)
- {
- b2Timer timer;
- SolveTOI(step);
- m_profile.solveTOI = timer.GetMilliseconds();
- }
- if (step.dt > 0.0f)
- {
- m_inv_dt0 = step.inv_dt;
- }
- if (m_flags & e_clearForces)
- {
- ClearForces();
- }
- m_flags &= ~e_locked;
- m_profile.step = stepTimer.GetMilliseconds();
- }
- void b2World::ClearForces()
- {
- for (b2Body* body = m_bodyList; body; body = body->GetNext())
- {
- body->m_force.SetZero();
- body->m_torque = 0.0f;
- }
- }
- struct b2WorldQueryWrapper
- {
- bool QueryCallback(int32 proxyId)
- {
- b2FixtureProxy* proxy = (b2FixtureProxy*)broadPhase->GetUserData(proxyId);
- return callback->ReportFixture(proxy->fixture);
- }
- const b2BroadPhase* broadPhase;
- b2QueryCallback* callback;
- };
- void b2World::QueryAABB(b2QueryCallback* callback, const b2AABB& aabb) const
- {
- b2WorldQueryWrapper wrapper;
- wrapper.broadPhase = &m_contactManager.m_broadPhase;
- wrapper.callback = callback;
- m_contactManager.m_broadPhase.Query(&wrapper, aabb);
- for (b2ParticleSystem* p = m_particleSystemList; p; p = p->GetNext())
- {
- if (callback->ShouldQueryParticleSystem(p))
- {
- p->QueryAABB(callback, aabb);
- }
- }
- }
- void b2World::QueryShapeAABB(b2QueryCallback* callback, const b2Shape& shape,
- const b2Transform& xf) const
- {
- b2AABB aabb;
- shape.ComputeAABB(&aabb, xf, 0);
- QueryAABB(callback, aabb);
- }
- struct b2WorldRayCastWrapper
- {
- float32 RayCastCallback(const b2RayCastInput& input, int32 proxyId)
- {
- void* userData = broadPhase->GetUserData(proxyId);
- b2FixtureProxy* proxy = (b2FixtureProxy*)userData;
- b2Fixture* fixture = proxy->fixture;
- int32 index = proxy->childIndex;
- b2RayCastOutput output;
- bool hit = fixture->RayCast(&output, input, index);
- if (hit)
- {
- float32 fraction = output.fraction;
- b2Vec2 point = (1.0f - fraction) * input.p1 + fraction * input.p2;
- return callback->ReportFixture(fixture, point, output.normal, fraction);
- }
- return input.maxFraction;
- }
- const b2BroadPhase* broadPhase;
- b2RayCastCallback* callback;
- };
- void b2World::RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2) const
- {
- b2WorldRayCastWrapper wrapper;
- wrapper.broadPhase = &m_contactManager.m_broadPhase;
- wrapper.callback = callback;
- b2RayCastInput input;
- input.maxFraction = 1.0f;
- input.p1 = point1;
- input.p2 = point2;
- m_contactManager.m_broadPhase.RayCast(&wrapper, input);
- for (b2ParticleSystem* p = m_particleSystemList; p; p = p->GetNext())
- {
- if (callback->ShouldQueryParticleSystem(p))
- {
- p->RayCast(callback, point1, point2);
- }
- }
- }
- void b2World::DrawShape(b2Fixture* fixture, const b2Transform& xf, const b2Color& color)
- {
- switch (fixture->GetType())
- {
- case b2Shape::e_circle:
- {
- b2CircleShape* circle = (b2CircleShape*)fixture->GetShape();
- b2Vec2 center = b2Mul(xf, circle->m_p);
- float32 radius = circle->m_radius;
- b2Vec2 axis = b2Mul(xf.q, b2Vec2(1.0f, 0.0f));
- m_debugDraw->DrawSolidCircle(center, radius, axis, color);
- }
- break;
- case b2Shape::e_edge:
- {
- b2EdgeShape* edge = (b2EdgeShape*)fixture->GetShape();
- b2Vec2 v1 = b2Mul(xf, edge->m_vertex1);
- b2Vec2 v2 = b2Mul(xf, edge->m_vertex2);
- m_debugDraw->DrawSegment(v1, v2, color);
- }
- break;
- case b2Shape::e_chain:
- {
- b2ChainShape* chain = (b2ChainShape*)fixture->GetShape();
- int32 count = chain->m_count;
- const b2Vec2* vertices = chain->m_vertices;
- b2Vec2 v1 = b2Mul(xf, vertices[0]);
- for (int32 i = 1; i < count; ++i)
- {
- b2Vec2 v2 = b2Mul(xf, vertices[i]);
- m_debugDraw->DrawSegment(v1, v2, color);
- m_debugDraw->DrawCircle(v1, 0.05f, color);
- v1 = v2;
- }
- }
- break;
- case b2Shape::e_polygon:
- {
- b2PolygonShape* poly = (b2PolygonShape*)fixture->GetShape();
- int32 vertexCount = poly->m_count;
- b2Assert(vertexCount <= b2_maxPolygonVertices);
- b2Vec2 vertices[b2_maxPolygonVertices];
- for (int32 i = 0; i < vertexCount; ++i)
- {
- vertices[i] = b2Mul(xf, poly->m_vertices[i]);
- }
- m_debugDraw->DrawSolidPolygon(vertices, vertexCount, color);
- }
- break;
- default:
- break;
- }
- }
- void b2World::DrawJoint(b2Joint* joint)
- {
- b2Body* bodyA = joint->GetBodyA();
- b2Body* bodyB = joint->GetBodyB();
- const b2Transform& xf1 = bodyA->GetTransform();
- const b2Transform& xf2 = bodyB->GetTransform();
- b2Vec2 x1 = xf1.p;
- b2Vec2 x2 = xf2.p;
- b2Vec2 p1 = joint->GetAnchorA();
- b2Vec2 p2 = joint->GetAnchorB();
- b2Color color(0.5f, 0.8f, 0.8f);
- switch (joint->GetType())
- {
- case e_distanceJoint:
- m_debugDraw->DrawSegment(p1, p2, color);
- break;
- case e_pulleyJoint:
- {
- b2PulleyJoint* pulley = (b2PulleyJoint*)joint;
- b2Vec2 s1 = pulley->GetGroundAnchorA();
- b2Vec2 s2 = pulley->GetGroundAnchorB();
- m_debugDraw->DrawSegment(s1, p1, color);
- m_debugDraw->DrawSegment(s2, p2, color);
- m_debugDraw->DrawSegment(s1, s2, color);
- }
- break;
- case e_mouseJoint:
- // don't draw this
- break;
- default:
- m_debugDraw->DrawSegment(x1, p1, color);
- m_debugDraw->DrawSegment(p1, p2, color);
- m_debugDraw->DrawSegment(x2, p2, color);
- }
- }
- void b2World::DrawParticleSystem(const b2ParticleSystem& system)
- {
- int32 particleCount = system.GetParticleCount();
- if (particleCount)
- {
- float32 radius = system.GetRadius();
- const b2Vec2* positionBuffer = system.GetPositionBuffer();
- if (system.m_colorBuffer.data)
- {
- const b2ParticleColor* colorBuffer = system.GetColorBuffer();
- m_debugDraw->DrawParticles(positionBuffer, radius, colorBuffer, particleCount);
- }
- else
- {
- m_debugDraw->DrawParticles(positionBuffer, radius, NULL, particleCount);
- }
- }
- }
- void b2World::DrawDebugData()
- {
- if (m_debugDraw == NULL)
- {
- return;
- }
- uint32 flags = m_debugDraw->GetFlags();
- if (flags & b2Draw::e_shapeBit)
- {
- for (b2Body* b = m_bodyList; b; b = b->GetNext())
- {
- const b2Transform& xf = b->GetTransform();
- for (b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext())
- {
- if (b->IsActive() == false)
- {
- DrawShape(f, xf, b2Color(0.5f, 0.5f, 0.3f));
- }
- else if (b->GetType() == b2_staticBody)
- {
- DrawShape(f, xf, b2Color(0.5f, 0.9f, 0.5f));
- }
- else if (b->GetType() == b2_kinematicBody)
- {
- DrawShape(f, xf, b2Color(0.5f, 0.5f, 0.9f));
- }
- else if (b->IsAwake() == false)
- {
- DrawShape(f, xf, b2Color(0.6f, 0.6f, 0.6f));
- }
- else
- {
- DrawShape(f, xf, b2Color(0.9f, 0.7f, 0.7f));
- }
- }
- }
- }
- if (flags & b2Draw::e_particleBit)
- {
- for (b2ParticleSystem* p = m_particleSystemList; p; p = p->GetNext())
- {
- DrawParticleSystem(*p);
- }
- }
- if (flags & b2Draw::e_jointBit)
- {
- for (b2Joint* j = m_jointList; j; j = j->GetNext())
- {
- DrawJoint(j);
- }
- }
- if (flags & b2Draw::e_pairBit)
- {
- b2Color color(0.3f, 0.9f, 0.9f);
- for (b2Contact* c = m_contactManager.m_contactList; c; c = c->GetNext())
- {
- //b2Fixture* fixtureA = c->GetFixtureA();
- //b2Fixture* fixtureB = c->GetFixtureB();
- //b2Vec2 cA = fixtureA->GetAABB().GetCenter();
- //b2Vec2 cB = fixtureB->GetAABB().GetCenter();
- //m_debugDraw->DrawSegment(cA, cB, color);
- }
- }
- if (flags & b2Draw::e_aabbBit)
- {
- b2Color color(0.9f, 0.3f, 0.9f);
- b2BroadPhase* bp = &m_contactManager.m_broadPhase;
- for (b2Body* b = m_bodyList; b; b = b->GetNext())
- {
- if (b->IsActive() == false)
- {
- continue;
- }
- for (b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext())
- {
- for (int32 i = 0; i < f->m_proxyCount; ++i)
- {
- b2FixtureProxy* proxy = f->m_proxies + i;
- b2AABB aabb = bp->GetFatAABB(proxy->proxyId);
- b2Vec2 vs[4];
- vs[0].Set(aabb.lowerBound.x, aabb.lowerBound.y);
- vs[1].Set(aabb.upperBound.x, aabb.lowerBound.y);
- vs[2].Set(aabb.upperBound.x, aabb.upperBound.y);
- vs[3].Set(aabb.lowerBound.x, aabb.upperBound.y);
- m_debugDraw->DrawPolygon(vs, 4, color);
- }
- }
- }
- }
- if (flags & b2Draw::e_centerOfMassBit)
- {
- for (b2Body* b = m_bodyList; b; b = b->GetNext())
- {
- b2Transform xf = b->GetTransform();
- xf.p = b->GetWorldCenter();
- m_debugDraw->DrawTransform(xf);
- }
- }
- }
- static float32 GetSmallestRadius(const b2World* world)
- {
- float32 smallestRadius = b2_maxFloat;
- for (const b2ParticleSystem* system = world->GetParticleSystemList();
- system != NULL;
- system = system->GetNext())
- {
- smallestRadius = b2Min(smallestRadius, system->GetRadius());
- }
- return smallestRadius;
- }
- int b2World::CalculateReasonableParticleIterations(float32 timeStep) const
- {
- if (m_particleSystemList == NULL)
- return 1;
- // Use the smallest radius, since that represents the worst-case.
- return b2CalculateParticleIterations(m_gravity.Length(),
- GetSmallestRadius(this),
- timeStep);
- }
- int32 b2World::GetProxyCount() const
- {
- return m_contactManager.m_broadPhase.GetProxyCount();
- }
- int32 b2World::GetTreeHeight() const
- {
- return m_contactManager.m_broadPhase.GetTreeHeight();
- }
- int32 b2World::GetTreeBalance() const
- {
- return m_contactManager.m_broadPhase.GetTreeBalance();
- }
- float32 b2World::GetTreeQuality() const
- {
- return m_contactManager.m_broadPhase.GetTreeQuality();
- }
- void b2World::ShiftOrigin(const b2Vec2& newOrigin)
- {
- b2Assert((m_flags & e_locked) == 0);
- if ((m_flags & e_locked) == e_locked)
- {
- return;
- }
- for (b2Body* b = m_bodyList; b; b = b->m_next)
- {
- b->m_xf.p -= newOrigin;
- b->m_sweep.c0 -= newOrigin;
- b->m_sweep.c -= newOrigin;
- }
- for (b2Joint* j = m_jointList; j; j = j->m_next)
- {
- j->ShiftOrigin(newOrigin);
- }
- m_contactManager.m_broadPhase.ShiftOrigin(newOrigin);
- }
- void b2World::Dump()
- {
- if ((m_flags & e_locked) == e_locked)
- {
- return;
- }
- b2Log("b2Vec2 g(%.15lef, %.15lef);\n", m_gravity.x, m_gravity.y);
- b2Log("m_world->SetGravity(g);\n");
- b2Log("b2Body** bodies = (b2Body**)b2Alloc(%d * sizeof(b2Body*));\n", m_bodyCount);
- b2Log("b2Joint** joints = (b2Joint**)b2Alloc(%d * sizeof(b2Joint*));\n", m_jointCount);
- int32 i = 0;
- for (b2Body* b = m_bodyList; b; b = b->m_next)
- {
- b->m_islandIndex = i;
- b->Dump();
- ++i;
- }
- i = 0;
- for (b2Joint* j = m_jointList; j; j = j->m_next)
- {
- j->m_index = i;
- ++i;
- }
- // First pass on joints, skip gear joints.
- for (b2Joint* j = m_jointList; j; j = j->m_next)
- {
- if (j->m_type == e_gearJoint)
- {
- continue;
- }
- b2Log("{\n");
- j->Dump();
- b2Log("}\n");
- }
- // Second pass on joints, only gear joints.
- for (b2Joint* j = m_jointList; j; j = j->m_next)
- {
- if (j->m_type != e_gearJoint)
- {
- continue;
- }
- b2Log("{\n");
- j->Dump();
- b2Log("}\n");
- }
- b2Log("b2Free(joints);\n");
- b2Log("b2Free(bodies);\n");
- b2Log("joints = NULL;\n");
- b2Log("bodies = NULL;\n");
- }
|