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 
b2Body(const b2BodyDef * bd,b2World * world)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 
~b2Body()108 b2Body::~b2Body()
109 {
110 	// shapes and joints are destroyed in b2World::Destroy
111 }
112 
SetType(b2BodyType type)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 
CreateFixture(const b2FixtureDef * def)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 
CreateFixture(const b2Shape * shape,float32 density)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 
DestroyFixture(b2Fixture * fixture)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 
ResetMassData()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 
SetMassData(const b2MassData * massData)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 
ShouldCollide(const b2Body * other) const394 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 
SetTransform(const b2Vec2 & position,float32 angle)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 
SynchronizeFixtures()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 
SetActive(bool flag)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 
SetFixedRotation(bool flag)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 
Dump()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