File indexing completed on 2025-08-03 03:50:00

0001 /*
0002 * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
0003 *
0004 * This software is provided 'as-is', without any express or implied
0005 * warranty.  In no event will the authors be held liable for any damages
0006 * arising from the use of this software.
0007 * Permission is granted to anyone to use this software for any purpose,
0008 * including commercial applications, and to alter it and redistribute it
0009 * freely, subject to the following restrictions:
0010 * 1. The origin of this software must not be misrepresented; you must not
0011 * claim that you wrote the original software. If you use this software
0012 * in a product, an acknowledgment in the product documentation would be
0013 * appreciated but is not required.
0014 * 2. Altered source versions must be plainly marked as such, and must not be
0015 * misrepresented as being the original software.
0016 * 3. This notice may not be removed or altered from any source distribution.
0017 */
0018 
0019 #include <Box2D/Dynamics/b2Body.h>
0020 #include <Box2D/Dynamics/b2Fixture.h>
0021 #include <Box2D/Dynamics/b2World.h>
0022 #include <Box2D/Dynamics/Contacts/b2Contact.h>
0023 #include <Box2D/Dynamics/Joints/b2Joint.h>
0024 
0025 b2Body::b2Body(const b2BodyDef* bd, b2World* world)
0026 {
0027     b2Assert(bd->position.IsValid());
0028     b2Assert(bd->linearVelocity.IsValid());
0029     b2Assert(b2IsValid(bd->angle));
0030     b2Assert(b2IsValid(bd->angularVelocity));
0031     b2Assert(b2IsValid(bd->inertiaScale) && bd->inertiaScale >= 0.0f);
0032     b2Assert(b2IsValid(bd->angularDamping) && bd->angularDamping >= 0.0f);
0033     b2Assert(b2IsValid(bd->linearDamping) && bd->linearDamping >= 0.0f);
0034 
0035     m_flags = 0;
0036 
0037     if (bd->bullet)
0038     {
0039         m_flags |= e_bulletFlag;
0040     }
0041     if (bd->fixedRotation)
0042     {
0043         m_flags |= e_fixedRotationFlag;
0044     }
0045     if (bd->allowSleep)
0046     {
0047         m_flags |= e_autoSleepFlag;
0048     }
0049     if (bd->awake)
0050     {
0051         m_flags |= e_awakeFlag;
0052     }
0053     if (bd->active)
0054     {
0055         m_flags |= e_activeFlag;
0056     }
0057 
0058     m_world = world;
0059 
0060     m_xf.position = bd->position;
0061     m_xf.R.Set(bd->angle);
0062 
0063     m_sweep.localCenter.SetZero();
0064     m_sweep.a0 = m_sweep.a = bd->angle;
0065     m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);
0066 
0067     m_jointList = NULL;
0068     m_contactList = NULL;
0069     m_prev = NULL;
0070     m_next = NULL;
0071 
0072     m_linearVelocity = bd->linearVelocity;
0073     m_angularVelocity = bd->angularVelocity;
0074 
0075     m_linearDamping = bd->linearDamping;
0076     m_angularDamping = bd->angularDamping;
0077 
0078     m_force.SetZero();
0079     m_torque = 0.0f;
0080 
0081     m_sleepTime = 0.0f;
0082 
0083     m_type = bd->type;
0084 
0085     if (m_type == b2_dynamicBody)
0086     {
0087         m_mass = 1.0f;
0088         m_invMass = 1.0f;
0089     }
0090     else
0091     {
0092         m_mass = 0.0f;
0093         m_invMass = 0.0f;
0094     }
0095 
0096     m_I = 0.0f;
0097     m_invI = 0.0f;
0098 
0099     m_userData = bd->userData;
0100 
0101     m_fixtureList = NULL;
0102     m_fixtureCount = 0;
0103 }
0104 
0105 b2Body::~b2Body()
0106 {
0107     // shapes and joints are destroyed in b2World::Destroy
0108 }
0109 
0110 void b2Body::SetType(b2BodyType type)
0111 {
0112     if (m_type == type)
0113     {
0114         return;
0115     }
0116 
0117     m_type = type;
0118 
0119     ResetMassData();
0120 
0121     if (m_type == b2_staticBody)
0122     {
0123         m_linearVelocity.SetZero();
0124         m_angularVelocity = 0.0f;
0125     }
0126 
0127     SetAwake(true);
0128 
0129     m_force.SetZero();
0130     m_torque = 0.0f;
0131 
0132     // Since the body type changed, we need to flag contacts for filtering.
0133     for (b2ContactEdge* ce = m_contactList; ce; ce = ce->next)
0134     {
0135         ce->contact->FlagForFiltering();
0136     }
0137 }
0138 
0139 b2Fixture* b2Body::CreateFixture(const b2FixtureDef* def)
0140 {
0141     b2Assert(m_world->IsLocked() == false);
0142     if (m_world->IsLocked() == true)
0143     {
0144         return NULL;
0145     }
0146 
0147     b2BlockAllocator* allocator = &m_world->m_blockAllocator;
0148 
0149     void* memory = allocator->Allocate(sizeof(b2Fixture));
0150     b2Fixture* fixture = new (memory) b2Fixture;
0151     fixture->Create(allocator, this, def);
0152 
0153     if (m_flags & e_activeFlag)
0154     {
0155         b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
0156         fixture->CreateProxies(broadPhase, m_xf);
0157     }
0158 
0159     fixture->m_next = m_fixtureList;
0160     m_fixtureList = fixture;
0161     ++m_fixtureCount;
0162 
0163     fixture->m_body = this;
0164 
0165     // Adjust mass properties if needed.
0166     if (fixture->m_density > 0.0f)
0167     {
0168         ResetMassData();
0169     }
0170 
0171     // Let the world know we have a new fixture. This will cause new contacts
0172     // to be created at the beginning of the next time step.
0173     m_world->m_flags |= b2World::e_newFixture;
0174 
0175     return fixture;
0176 }
0177 
0178 b2Fixture* b2Body::CreateFixture(const b2Shape* shape, qreal density)
0179 {
0180     b2FixtureDef def;
0181     def.shape = shape;
0182     def.density = density;
0183 
0184     return CreateFixture(&def);
0185 }
0186 
0187 void b2Body::DestroyFixture(b2Fixture* fixture)
0188 {
0189     b2Assert(m_world->IsLocked() == false);
0190     if (m_world->IsLocked() == true)
0191     {
0192         return;
0193     }
0194 
0195     b2Assert(fixture->m_body == this);
0196 
0197     // Remove the fixture from this body's singly linked list.
0198     b2Assert(m_fixtureCount > 0);
0199     b2Fixture** node = &m_fixtureList;
0200     bool found = false;
0201     while (*node != NULL)
0202     {
0203         if (*node == fixture)
0204         {
0205             *node = fixture->m_next;
0206             found = true;
0207             break;
0208         }
0209 
0210         node = &(*node)->m_next;
0211     }
0212 
0213     // You tried to remove a shape that is not attached to this body.
0214     b2Assert(found);
0215 
0216     // Destroy any contacts associated with the fixture.
0217     b2ContactEdge* edge = m_contactList;
0218     while (edge)
0219     {
0220         b2Contact* c = edge->contact;
0221         edge = edge->next;
0222 
0223         b2Fixture* fixtureA = c->GetFixtureA();
0224         b2Fixture* fixtureB = c->GetFixtureB();
0225 
0226         if (fixture == fixtureA || fixture == fixtureB)
0227         {
0228             // This destroys the contact and removes it from
0229             // this body's contact list.
0230             m_world->m_contactManager.Destroy(c);
0231         }
0232     }
0233 
0234     b2BlockAllocator* allocator = &m_world->m_blockAllocator;
0235 
0236     if (m_flags & e_activeFlag)
0237     {
0238         b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
0239         fixture->DestroyProxies(broadPhase);
0240     }
0241 
0242     fixture->Destroy(allocator);
0243     fixture->m_body = NULL;
0244     fixture->m_next = NULL;
0245     fixture->~b2Fixture();
0246     allocator->Free(fixture, sizeof(b2Fixture));
0247 
0248     --m_fixtureCount;
0249 
0250     // Reset the mass data.
0251     ResetMassData();
0252 }
0253 
0254 void b2Body::ResetMassData()
0255 {
0256     // Compute mass data from shapes. Each shape has its own density.
0257     m_mass = 0.0f;
0258     m_invMass = 0.0f;
0259     m_I = 0.0f;
0260     m_invI = 0.0f;
0261     m_sweep.localCenter.SetZero();
0262 
0263     // Static and kinematic bodies have zero mass.
0264     if (m_type == b2_staticBody || m_type == b2_kinematicBody)
0265     {
0266         m_sweep.c0 = m_sweep.c = m_xf.position;
0267         return;
0268     }
0269 
0270     b2Assert(m_type == b2_dynamicBody);
0271 
0272     // Accumulate mass over all fixtures.
0273     b2Vec2 center = b2Vec2_zero;
0274     for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
0275     {
0276         if (f->m_density == 0.0f)
0277         {
0278             continue;
0279         }
0280 
0281         b2MassData massData;
0282         f->GetMassData(&massData);
0283         m_mass += massData.mass;
0284         center += massData.mass * massData.center;
0285         m_I += massData.I;
0286     }
0287 
0288     // Compute center of mass.
0289     if (m_mass > 0.0f)
0290     {
0291         m_invMass = 1.0f / m_mass;
0292         center *= m_invMass;
0293     }
0294     else
0295     {
0296         // Force all dynamic bodies to have a positive mass.
0297         m_mass = 1.0f;
0298         m_invMass = 1.0f;
0299     }
0300 
0301     if (m_I > 0.0f && (m_flags & e_fixedRotationFlag) == 0)
0302     {
0303         // Center the inertia about the center of mass.
0304         m_I -= m_mass * b2Dot(center, center);
0305         b2Assert(m_I > 0.0f);
0306         m_invI = 1.0f / m_I;
0307 
0308     }
0309     else
0310     {
0311         m_I = 0.0f;
0312         m_invI = 0.0f;
0313     }
0314 
0315     // Move center of mass.
0316     b2Vec2 oldCenter = m_sweep.c;
0317     m_sweep.localCenter = center;
0318     m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);
0319 
0320     // Update center of mass velocity.
0321     m_linearVelocity += b2Cross(m_angularVelocity, m_sweep.c - oldCenter);
0322 }
0323 
0324 void b2Body::SetMassData(const b2MassData* massData)
0325 {
0326     b2Assert(m_world->IsLocked() == false);
0327     if (m_world->IsLocked() == true)
0328     {
0329         return;
0330     }
0331 
0332     if (m_type != b2_dynamicBody)
0333     {
0334         return;
0335     }
0336 
0337     m_invMass = 0.0f;
0338     m_I = 0.0f;
0339     m_invI = 0.0f;
0340 
0341     m_mass = massData->mass;
0342     if (m_mass <= 0.0f)
0343     {
0344         m_mass = 1.0f;
0345     }
0346 
0347     m_invMass = 1.0f / m_mass;
0348 
0349     if (massData->I > 0.0f && (m_flags & b2Body::e_fixedRotationFlag) == 0)
0350     {
0351         m_I = massData->I - m_mass * b2Dot(massData->center, massData->center);
0352         b2Assert(m_I > 0.0f);
0353         m_invI = 1.0f / m_I;
0354     }
0355 
0356     // Move center of mass.
0357     b2Vec2 oldCenter = m_sweep.c;
0358     m_sweep.localCenter = massData->center;
0359     m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);
0360 
0361     // Update center of mass velocity.
0362     m_linearVelocity += b2Cross(m_angularVelocity, m_sweep.c - oldCenter);
0363 }
0364 
0365 bool b2Body::ShouldCollide(const b2Body* other) const
0366 {
0367     // At least one body should be dynamic.
0368     if (m_type != b2_dynamicBody && other->m_type != b2_dynamicBody)
0369     {
0370         return false;
0371     }
0372 
0373     // Does a joint prevent collision?
0374     for (b2JointEdge* jn = m_jointList; jn; jn = jn->next)
0375     {
0376         if (jn->other == other)
0377         {
0378             if (jn->joint->m_collideConnected == false)
0379             {
0380                 return false;
0381             }
0382         }
0383     }
0384 
0385     return true;
0386 }
0387 
0388 void b2Body::SetTransform(const b2Vec2& position, qreal angle)
0389 {
0390     b2Assert(m_world->IsLocked() == false);
0391     if (m_world->IsLocked() == true)
0392     {
0393         return;
0394     }
0395 
0396     m_xf.R.Set(angle);
0397     m_xf.position = position;
0398 
0399     m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);
0400     m_sweep.a0 = m_sweep.a = angle;
0401 
0402     b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
0403     for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
0404     {
0405         f->Synchronize(broadPhase, m_xf, m_xf);
0406     }
0407 
0408     m_world->m_contactManager.FindNewContacts();
0409 }
0410 
0411 void b2Body::SynchronizeFixtures()
0412 {
0413     b2Transform xf1;
0414     xf1.R.Set(m_sweep.a0);
0415     xf1.position = m_sweep.c0 - b2Mul(xf1.R, m_sweep.localCenter);
0416 
0417     b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
0418     for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
0419     {
0420         f->Synchronize(broadPhase, xf1, m_xf);
0421     }
0422 }
0423 
0424 void b2Body::SetActive(bool flag)
0425 {
0426     b2Assert(m_world->IsLocked() == false);
0427 
0428     if (flag == IsActive())
0429     {
0430         return;
0431     }
0432 
0433     if (flag)
0434     {
0435         m_flags |= e_activeFlag;
0436 
0437         // Create all proxies.
0438         b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
0439         for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
0440         {
0441             f->CreateProxies(broadPhase, m_xf);
0442         }
0443 
0444         // Contacts are created the next time step.
0445     }
0446     else
0447     {
0448         m_flags &= ~e_activeFlag;
0449 
0450         // Destroy all proxies.
0451         b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
0452         for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
0453         {
0454             f->DestroyProxies(broadPhase);
0455         }
0456 
0457         // Destroy the attached contacts.
0458         b2ContactEdge* ce = m_contactList;
0459         while (ce)
0460         {
0461             b2ContactEdge* ce0 = ce;
0462             ce = ce->next;
0463             m_world->m_contactManager.Destroy(ce0->contact);
0464         }
0465         m_contactList = NULL;
0466     }
0467 }
0468