Home | History | Annotate | Download | only in Dynamics
      1 /*
      2 * Copyright (c) 2006-2007 Erin Catto http://www.box2d.org
      3 *
      4 * This software is provided 'as-is', without any express or implied
      5 * warranty.  In no event will the authors be held liable for any damages
      6 * arising from the use of this software.
      7 * Permission is granted to anyone to use this software for any purpose,
      8 * including commercial applications, and to alter it and redistribute it
      9 * freely, subject to the following restrictions:
     10 * 1. The origin of this software must not be misrepresented; you must not
     11 * claim that you wrote the original software. If you use this software
     12 * in a product, an acknowledgment in the product documentation would be
     13 * appreciated but is not required.
     14 * 2. Altered source versions must be plainly marked as such, and must not be
     15 * misrepresented as being the original software.
     16 * 3. This notice may not be removed or altered from any source distribution.
     17 */
     18 
     19 #include <Box2D/Dynamics/b2Body.h>
     20 #include <Box2D/Dynamics/b2Fixture.h>
     21 #include <Box2D/Dynamics/b2World.h>
     22 #include <Box2D/Dynamics/Contacts/b2Contact.h>
     23 #include <Box2D/Dynamics/Joints/b2Joint.h>
     24 
     25 b2Body::b2Body(const b2BodyDef* bd, b2World* world)
     26 {
     27 	b2Assert(bd->position.IsValid());
     28 	b2Assert(bd->linearVelocity.IsValid());
     29 	b2Assert(b2IsValid(bd->angle));
     30 	b2Assert(b2IsValid(bd->angularVelocity));
     31 	b2Assert(b2IsValid(bd->angularDamping) && bd->angularDamping >= 0.0f);
     32 	b2Assert(b2IsValid(bd->linearDamping) && bd->linearDamping >= 0.0f);
     33 
     34 	m_flags = 0;
     35 
     36 	if (bd->bullet)
     37 	{
     38 		m_flags |= e_bulletFlag;
     39 	}
     40 	if (bd->fixedRotation)
     41 	{
     42 		m_flags |= e_fixedRotationFlag;
     43 	}
     44 	if (bd->allowSleep)
     45 	{
     46 		m_flags |= e_autoSleepFlag;
     47 	}
     48 	if (bd->awake)
     49 	{
     50 		m_flags |= e_awakeFlag;
     51 	}
     52 	if (bd->active)
     53 	{
     54 		m_flags |= e_activeFlag;
     55 	}
     56 
     57 	m_world = world;
     58 
     59 	m_xf.p = bd->position;
     60 	m_xf.q.Set(bd->angle);
     61 
     62 	m_sweep.localCenter.SetZero();
     63 	m_sweep.c0 = m_xf.p;
     64 	m_sweep.c = m_xf.p;
     65 	m_sweep.a0 = bd->angle;
     66 	m_sweep.a = bd->angle;
     67 	m_sweep.alpha0 = 0.0f;
     68 
     69 	m_jointList = NULL;
     70 	m_contactList = NULL;
     71 	m_prev = NULL;
     72 	m_next = NULL;
     73 
     74 	m_linearVelocity = bd->linearVelocity;
     75 	m_angularVelocity = bd->angularVelocity;
     76 
     77 	m_linearDamping = bd->linearDamping;
     78 	m_angularDamping = bd->angularDamping;
     79 	m_gravityScale = bd->gravityScale;
     80 
     81 	m_force.SetZero();
     82 	m_torque = 0.0f;
     83 
     84 	m_sleepTime = 0.0f;
     85 
     86 	m_type = bd->type;
     87 
     88 	if (m_type == b2_dynamicBody)
     89 	{
     90 		m_mass = 1.0f;
     91 		m_invMass = 1.0f;
     92 	}
     93 	else
     94 	{
     95 		m_mass = 0.0f;
     96 		m_invMass = 0.0f;
     97 	}
     98 
     99 	m_I = 0.0f;
    100 	m_invI = 0.0f;
    101 
    102 	m_userData = bd->userData;
    103 
    104 	m_fixtureList = NULL;
    105 	m_fixtureCount = 0;
    106 }
    107 
    108 b2Body::~b2Body()
    109 {
    110 	// shapes and joints are destroyed in b2World::Destroy
    111 }
    112 
    113 void b2Body::SetType(b2BodyType type)
    114 {
    115 	b2Assert(m_world->IsLocked() == false);
    116 	if (m_world->IsLocked() == true)
    117 	{
    118 		return;
    119 	}
    120 
    121 	if (m_type == type)
    122 	{
    123 		return;
    124 	}
    125 
    126 	m_type = type;
    127 
    128 	ResetMassData();
    129 
    130 	if (m_type == b2_staticBody)
    131 	{
    132 		m_linearVelocity.SetZero();
    133 		m_angularVelocity = 0.0f;
    134 		m_sweep.a0 = m_sweep.a;
    135 		m_sweep.c0 = m_sweep.c;
    136 		SynchronizeFixtures();
    137 	}
    138 
    139 	SetAwake(true);
    140 
    141 	m_force.SetZero();
    142 	m_torque = 0.0f;
    143 
    144 	// Delete the attached contacts.
    145 	b2ContactEdge* ce = m_contactList;
    146 	while (ce)
    147 	{
    148 		b2ContactEdge* ce0 = ce;
    149 		ce = ce->next;
    150 		m_world->m_contactManager.Destroy(ce0->contact);
    151 	}
    152 	m_contactList = NULL;
    153 
    154 	// Touch the proxies so that new contacts will be created (when appropriate)
    155 	b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
    156 	for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
    157 	{
    158 		int32 proxyCount = f->m_proxyCount;
    159 		for (int32 i = 0; i < proxyCount; ++i)
    160 		{
    161 			broadPhase->TouchProxy(f->m_proxies[i].proxyId);
    162 		}
    163 	}
    164 }
    165 
    166 b2Fixture* b2Body::CreateFixture(const b2FixtureDef* def)
    167 {
    168 	b2Assert(m_world->IsLocked() == false);
    169 	if (m_world->IsLocked() == true)
    170 	{
    171 		return NULL;
    172 	}
    173 
    174 	b2BlockAllocator* allocator = &m_world->m_blockAllocator;
    175 
    176 	void* memory = allocator->Allocate(sizeof(b2Fixture));
    177 	b2Fixture* fixture = new (memory) b2Fixture;
    178 	fixture->Create(allocator, this, def);
    179 
    180 	if (m_flags & e_activeFlag)
    181 	{
    182 		b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
    183 		fixture->CreateProxies(broadPhase, m_xf);
    184 	}
    185 
    186 	fixture->m_next = m_fixtureList;
    187 	m_fixtureList = fixture;
    188 	++m_fixtureCount;
    189 
    190 	fixture->m_body = this;
    191 
    192 	// Adjust mass properties if needed.
    193 	if (fixture->m_density > 0.0f)
    194 	{
    195 		ResetMassData();
    196 	}
    197 
    198 	// Let the world know we have a new fixture. This will cause new contacts
    199 	// to be created at the beginning of the next time step.
    200 	m_world->m_flags |= b2World::e_newFixture;
    201 
    202 	return fixture;
    203 }
    204 
    205 b2Fixture* b2Body::CreateFixture(const b2Shape* shape, float32 density)
    206 {
    207 	b2FixtureDef def;
    208 	def.shape = shape;
    209 	def.density = density;
    210 
    211 	return CreateFixture(&def);
    212 }
    213 
    214 void b2Body::DestroyFixture(b2Fixture* fixture)
    215 {
    216 	b2Assert(m_world->IsLocked() == false);
    217 	if (m_world->IsLocked() == true)
    218 	{
    219 		return;
    220 	}
    221 
    222 	b2Assert(fixture->m_body == this);
    223 
    224 	// Remove the fixture from this body's singly linked list.
    225 	b2Assert(m_fixtureCount > 0);
    226 	b2Fixture** node = &m_fixtureList;
    227 	bool found = false;
    228 	while (*node != NULL)
    229 	{
    230 		if (*node == fixture)
    231 		{
    232 			*node = fixture->m_next;
    233 			found = true;
    234 			break;
    235 		}
    236 
    237 		node = &(*node)->m_next;
    238 	}
    239 
    240 	// You tried to remove a shape that is not attached to this body.
    241 	b2Assert(found);
    242 
    243 	// Destroy any contacts associated with the fixture.
    244 	b2ContactEdge* edge = m_contactList;
    245 	while (edge)
    246 	{
    247 		b2Contact* c = edge->contact;
    248 		edge = edge->next;
    249 
    250 		b2Fixture* fixtureA = c->GetFixtureA();
    251 		b2Fixture* fixtureB = c->GetFixtureB();
    252 
    253 		if (fixture == fixtureA || fixture == fixtureB)
    254 		{
    255 			// This destroys the contact and removes it from
    256 			// this body's contact list.
    257 			m_world->m_contactManager.Destroy(c);
    258 		}
    259 	}
    260 
    261 	b2BlockAllocator* allocator = &m_world->m_blockAllocator;
    262 
    263 	if (m_flags & e_activeFlag)
    264 	{
    265 		b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
    266 		fixture->DestroyProxies(broadPhase);
    267 	}
    268 
    269 	fixture->Destroy(allocator);
    270 	fixture->m_body = NULL;
    271 	fixture->m_next = NULL;
    272 	fixture->~b2Fixture();
    273 	allocator->Free(fixture, sizeof(b2Fixture));
    274 
    275 	--m_fixtureCount;
    276 
    277 	// Reset the mass data.
    278 	ResetMassData();
    279 }
    280 
    281 void b2Body::ResetMassData()
    282 {
    283 	// Compute mass data from shapes. Each shape has its own density.
    284 	m_mass = 0.0f;
    285 	m_invMass = 0.0f;
    286 	m_I = 0.0f;
    287 	m_invI = 0.0f;
    288 	m_sweep.localCenter.SetZero();
    289 
    290 	// Static and kinematic bodies have zero mass.
    291 	if (m_type == b2_staticBody || m_type == b2_kinematicBody)
    292 	{
    293 		m_sweep.c0 = m_xf.p;
    294 		m_sweep.c = m_xf.p;
    295 		m_sweep.a0 = m_sweep.a;
    296 		return;
    297 	}
    298 
    299 	b2Assert(m_type == b2_dynamicBody);
    300 
    301 	// Accumulate mass over all fixtures.
    302 	b2Vec2 localCenter = b2Vec2_zero;
    303 	for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
    304 	{
    305 		if (f->m_density == 0.0f)
    306 		{
    307 			continue;
    308 		}
    309 
    310 		b2MassData massData;
    311 		f->GetMassData(&massData);
    312 		m_mass += massData.mass;
    313 		localCenter += massData.mass * massData.center;
    314 		m_I += massData.I;
    315 	}
    316 
    317 	// Compute center of mass.
    318 	if (m_mass > 0.0f)
    319 	{
    320 		m_invMass = 1.0f / m_mass;
    321 		localCenter *= m_invMass;
    322 	}
    323 	else
    324 	{
    325 		// Force all dynamic bodies to have a positive mass.
    326 		m_mass = 1.0f;
    327 		m_invMass = 1.0f;
    328 	}
    329 
    330 	if (m_I > 0.0f && (m_flags & e_fixedRotationFlag) == 0)
    331 	{
    332 		// Center the inertia about the center of mass.
    333 		m_I -= m_mass * b2Dot(localCenter, localCenter);
    334 		b2Assert(m_I > 0.0f);
    335 		m_invI = 1.0f / m_I;
    336 
    337 	}
    338 	else
    339 	{
    340 		m_I = 0.0f;
    341 		m_invI = 0.0f;
    342 	}
    343 
    344 	// Move center of mass.
    345 	b2Vec2 oldCenter = m_sweep.c;
    346 	m_sweep.localCenter = localCenter;
    347 	m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);
    348 
    349 	// Update center of mass velocity.
    350 	m_linearVelocity += b2Cross(m_angularVelocity, m_sweep.c - oldCenter);
    351 }
    352 
    353 void b2Body::SetMassData(const b2MassData* massData)
    354 {
    355 	b2Assert(m_world->IsLocked() == false);
    356 	if (m_world->IsLocked() == true)
    357 	{
    358 		return;
    359 	}
    360 
    361 	if (m_type != b2_dynamicBody)
    362 	{
    363 		return;
    364 	}
    365 
    366 	m_invMass = 0.0f;
    367 	m_I = 0.0f;
    368 	m_invI = 0.0f;
    369 
    370 	m_mass = massData->mass;
    371 	if (m_mass <= 0.0f)
    372 	{
    373 		m_mass = 1.0f;
    374 	}
    375 
    376 	m_invMass = 1.0f / m_mass;
    377 
    378 	if (massData->I > 0.0f && (m_flags & b2Body::e_fixedRotationFlag) == 0)
    379 	{
    380 		m_I = massData->I - m_mass * b2Dot(massData->center, massData->center);
    381 		b2Assert(m_I > 0.0f);
    382 		m_invI = 1.0f / m_I;
    383 	}
    384 
    385 	// Move center of mass.
    386 	b2Vec2 oldCenter = m_sweep.c;
    387 	m_sweep.localCenter =  massData->center;
    388 	m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);
    389 
    390 	// Update center of mass velocity.
    391 	m_linearVelocity += b2Cross(m_angularVelocity, m_sweep.c - oldCenter);
    392 }
    393 
    394 bool b2Body::ShouldCollide(const b2Body* other) const
    395 {
    396 	// At least one body should be dynamic.
    397 	if (m_type != b2_dynamicBody && other->m_type != b2_dynamicBody)
    398 	{
    399 		return false;
    400 	}
    401 
    402 	// Does a joint prevent collision?
    403 	for (b2JointEdge* jn = m_jointList; jn; jn = jn->next)
    404 	{
    405 		if (jn->other == other)
    406 		{
    407 			if (jn->joint->m_collideConnected == false)
    408 			{
    409 				return false;
    410 			}
    411 		}
    412 	}
    413 
    414 	return true;
    415 }
    416 
    417 void b2Body::SetTransform(const b2Vec2& position, float32 angle)
    418 {
    419 	b2Assert(m_world->IsLocked() == false);
    420 	if (m_world->IsLocked() == true)
    421 	{
    422 		return;
    423 	}
    424 
    425 	m_xf.q.Set(angle);
    426 	m_xf.p = position;
    427 
    428 	m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);
    429 	m_sweep.a = angle;
    430 
    431 	m_sweep.c0 = m_sweep.c;
    432 	m_sweep.a0 = angle;
    433 
    434 	b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
    435 	for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
    436 	{
    437 		f->Synchronize(broadPhase, m_xf, m_xf);
    438 	}
    439 }
    440 
    441 void b2Body::SynchronizeFixtures()
    442 {
    443 	b2Transform xf1;
    444 	xf1.q.Set(m_sweep.a0);
    445 	xf1.p = m_sweep.c0 - b2Mul(xf1.q, m_sweep.localCenter);
    446 
    447 	b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
    448 	for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
    449 	{
    450 		f->Synchronize(broadPhase, xf1, m_xf);
    451 	}
    452 }
    453 
    454 void b2Body::SetActive(bool flag)
    455 {
    456 	b2Assert(m_world->IsLocked() == false);
    457 
    458 	if (flag == IsActive())
    459 	{
    460 		return;
    461 	}
    462 
    463 	if (flag)
    464 	{
    465 		m_flags |= e_activeFlag;
    466 
    467 		// Create all proxies.
    468 		b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
    469 		for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
    470 		{
    471 			f->CreateProxies(broadPhase, m_xf);
    472 		}
    473 
    474 		// Contacts are created the next time step.
    475 	}
    476 	else
    477 	{
    478 		m_flags &= ~e_activeFlag;
    479 
    480 		// Destroy all proxies.
    481 		b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
    482 		for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
    483 		{
    484 			f->DestroyProxies(broadPhase);
    485 		}
    486 
    487 		// Destroy the attached contacts.
    488 		b2ContactEdge* ce = m_contactList;
    489 		while (ce)
    490 		{
    491 			b2ContactEdge* ce0 = ce;
    492 			ce = ce->next;
    493 			m_world->m_contactManager.Destroy(ce0->contact);
    494 		}
    495 		m_contactList = NULL;
    496 	}
    497 }
    498 
    499 void b2Body::SetFixedRotation(bool flag)
    500 {
    501 	bool status = (m_flags & e_fixedRotationFlag) == e_fixedRotationFlag;
    502 	if (status == flag)
    503 	{
    504 		return;
    505 	}
    506 
    507 	if (flag)
    508 	{
    509 		m_flags |= e_fixedRotationFlag;
    510 	}
    511 	else
    512 	{
    513 		m_flags &= ~e_fixedRotationFlag;
    514 	}
    515 
    516 	m_angularVelocity = 0.0f;
    517 
    518 	ResetMassData();
    519 }
    520 
    521 void b2Body::Dump()
    522 {
    523 	int32 bodyIndex = m_islandIndex;
    524 
    525 	b2Log("{\n");
    526 	b2Log("  b2BodyDef bd;\n");
    527 	b2Log("  bd.type = b2BodyType(%d);\n", m_type);
    528 	b2Log("  bd.position.Set(%.15lef, %.15lef);\n", m_xf.p.x, m_xf.p.y);
    529 	b2Log("  bd.angle = %.15lef;\n", m_sweep.a);
    530 	b2Log("  bd.linearVelocity.Set(%.15lef, %.15lef);\n", m_linearVelocity.x, m_linearVelocity.y);
    531 	b2Log("  bd.angularVelocity = %.15lef;\n", m_angularVelocity);
    532 	b2Log("  bd.linearDamping = %.15lef;\n", m_linearDamping);
    533 	b2Log("  bd.angularDamping = %.15lef;\n", m_angularDamping);
    534 	b2Log("  bd.allowSleep = bool(%d);\n", m_flags & e_autoSleepFlag);
    535 	b2Log("  bd.awake = bool(%d);\n", m_flags & e_awakeFlag);
    536 	b2Log("  bd.fixedRotation = bool(%d);\n", m_flags & e_fixedRotationFlag);
    537 	b2Log("  bd.bullet = bool(%d);\n", m_flags & e_bulletFlag);
    538 	b2Log("  bd.active = bool(%d);\n", m_flags & e_activeFlag);
    539 	b2Log("  bd.gravityScale = %.15lef;\n", m_gravityScale);
    540 	b2Log("  bodies[%d] = m_world->CreateBody(&bd);\n", m_islandIndex);
    541 	b2Log("\n");
    542 	for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
    543 	{
    544 		b2Log("  {\n");
    545 		f->Dump(bodyIndex);
    546 		b2Log("  }\n");
    547 	}
    548 	b2Log("}\n");
    549 }
    550