The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

516 lines
11KB

  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. #include "b2Body.h"
  19. #include "b2Fixture.h"
  20. #include "b2World.h"
  21. #include "Contacts/b2Contact.h"
  22. #include "Joints/b2Joint.h"
  23. b2Body::b2Body(const b2BodyDef* bd, b2World* world)
  24. {
  25. b2Assert(bd->position.IsValid());
  26. b2Assert(bd->linearVelocity.IsValid());
  27. b2Assert(b2IsValid(bd->angle));
  28. b2Assert(b2IsValid(bd->angularVelocity));
  29. b2Assert(b2IsValid(bd->angularDamping) && bd->angularDamping >= 0.0f);
  30. b2Assert(b2IsValid(bd->linearDamping) && bd->linearDamping >= 0.0f);
  31. m_flags = 0;
  32. if (bd->bullet)
  33. {
  34. m_flags |= e_bulletFlag;
  35. }
  36. if (bd->fixedRotation)
  37. {
  38. m_flags |= e_fixedRotationFlag;
  39. }
  40. if (bd->allowSleep)
  41. {
  42. m_flags |= e_autoSleepFlag;
  43. }
  44. if (bd->awake)
  45. {
  46. m_flags |= e_awakeFlag;
  47. }
  48. if (bd->active)
  49. {
  50. m_flags |= e_activeFlag;
  51. }
  52. m_world = world;
  53. m_xf.p = bd->position;
  54. m_xf.q.Set(bd->angle);
  55. m_sweep.localCenter.SetZero();
  56. m_sweep.c0 = m_xf.p;
  57. m_sweep.c = m_xf.p;
  58. m_sweep.a0 = bd->angle;
  59. m_sweep.a = bd->angle;
  60. m_sweep.alpha0 = 0.0f;
  61. m_jointList = NULL;
  62. m_contactList = NULL;
  63. m_prev = NULL;
  64. m_next = NULL;
  65. m_linearVelocity = bd->linearVelocity;
  66. m_angularVelocity = bd->angularVelocity;
  67. m_linearDamping = bd->linearDamping;
  68. m_angularDamping = bd->angularDamping;
  69. m_gravityScale = bd->gravityScale;
  70. m_force.SetZero();
  71. m_torque = 0.0f;
  72. m_sleepTime = 0.0f;
  73. m_type = bd->type;
  74. if (m_type == b2_dynamicBody)
  75. {
  76. m_mass = 1.0f;
  77. m_invMass = 1.0f;
  78. }
  79. else
  80. {
  81. m_mass = 0.0f;
  82. m_invMass = 0.0f;
  83. }
  84. m_I = 0.0f;
  85. m_invI = 0.0f;
  86. m_userData = bd->userData;
  87. m_fixtureList = NULL;
  88. m_fixtureCount = 0;
  89. }
  90. b2Body::~b2Body()
  91. {
  92. // shapes and joints are destroyed in b2World::Destroy
  93. }
  94. void b2Body::SetType(b2BodyType type)
  95. {
  96. b2Assert(m_world->IsLocked() == false);
  97. if (m_world->IsLocked() == true)
  98. {
  99. return;
  100. }
  101. if (m_type == type)
  102. {
  103. return;
  104. }
  105. m_type = type;
  106. ResetMassData();
  107. if (m_type == b2_staticBody)
  108. {
  109. m_linearVelocity.SetZero();
  110. m_angularVelocity = 0.0f;
  111. m_sweep.a0 = m_sweep.a;
  112. m_sweep.c0 = m_sweep.c;
  113. SynchronizeFixtures();
  114. }
  115. SetAwake(true);
  116. m_force.SetZero();
  117. m_torque = 0.0f;
  118. // Since the body type changed, we need to flag contacts for filtering.
  119. for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
  120. {
  121. f->Refilter();
  122. }
  123. }
  124. b2Fixture* b2Body::CreateFixture(const b2FixtureDef* def)
  125. {
  126. b2Assert(m_world->IsLocked() == false);
  127. if (m_world->IsLocked() == true)
  128. {
  129. return NULL;
  130. }
  131. b2BlockAllocator* allocator = &m_world->m_blockAllocator;
  132. void* memory = allocator->Allocate(sizeof(b2Fixture));
  133. b2Fixture* fixture = new (memory) b2Fixture;
  134. fixture->Create(allocator, this, def);
  135. if (m_flags & e_activeFlag)
  136. {
  137. b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
  138. fixture->CreateProxies(broadPhase, m_xf);
  139. }
  140. fixture->m_next = m_fixtureList;
  141. m_fixtureList = fixture;
  142. ++m_fixtureCount;
  143. fixture->m_body = this;
  144. // Adjust mass properties if needed.
  145. if (fixture->m_density > 0.0f)
  146. {
  147. ResetMassData();
  148. }
  149. // Let the world know we have a new fixture. This will cause new contacts
  150. // to be created at the beginning of the next time step.
  151. m_world->m_flags |= b2World::e_newFixture;
  152. return fixture;
  153. }
  154. b2Fixture* b2Body::CreateFixture(const b2Shape* shape, float32 density)
  155. {
  156. b2FixtureDef def;
  157. def.shape = shape;
  158. def.density = density;
  159. return CreateFixture(&def);
  160. }
  161. void b2Body::DestroyFixture(b2Fixture* fixture)
  162. {
  163. b2Assert(m_world->IsLocked() == false);
  164. if (m_world->IsLocked() == true)
  165. {
  166. return;
  167. }
  168. b2Assert(fixture->m_body == this);
  169. // Remove the fixture from this body's singly linked list.
  170. b2Assert(m_fixtureCount > 0);
  171. b2Fixture** node = &m_fixtureList;
  172. bool found = false;
  173. while (*node != NULL)
  174. {
  175. if (*node == fixture)
  176. {
  177. *node = fixture->m_next;
  178. found = true;
  179. break;
  180. }
  181. node = &(*node)->m_next;
  182. }
  183. // You tried to remove a shape that is not attached to this body.
  184. b2Assert(found);
  185. juce::ignoreUnused (found);
  186. // Destroy any contacts associated with the fixture.
  187. b2ContactEdge* edge = m_contactList;
  188. while (edge)
  189. {
  190. b2Contact* c = edge->contact;
  191. edge = edge->next;
  192. b2Fixture* fixtureA = c->GetFixtureA();
  193. b2Fixture* fixtureB = c->GetFixtureB();
  194. if (fixture == fixtureA || fixture == fixtureB)
  195. {
  196. // This destroys the contact and removes it from
  197. // this body's contact list.
  198. m_world->m_contactManager.Destroy(c);
  199. }
  200. }
  201. b2BlockAllocator* allocator = &m_world->m_blockAllocator;
  202. if (m_flags & e_activeFlag)
  203. {
  204. b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
  205. fixture->DestroyProxies(broadPhase);
  206. }
  207. fixture->Destroy(allocator);
  208. fixture->m_body = NULL;
  209. fixture->m_next = NULL;
  210. fixture->~b2Fixture();
  211. allocator->Free(fixture, sizeof(b2Fixture));
  212. --m_fixtureCount;
  213. // Reset the mass data.
  214. ResetMassData();
  215. }
  216. void b2Body::ResetMassData()
  217. {
  218. // Compute mass data from shapes. Each shape has its own density.
  219. m_mass = 0.0f;
  220. m_invMass = 0.0f;
  221. m_I = 0.0f;
  222. m_invI = 0.0f;
  223. m_sweep.localCenter.SetZero();
  224. // Static and kinematic bodies have zero mass.
  225. if (m_type == b2_staticBody || m_type == b2_kinematicBody)
  226. {
  227. m_sweep.c0 = m_xf.p;
  228. m_sweep.c = m_xf.p;
  229. m_sweep.a0 = m_sweep.a;
  230. return;
  231. }
  232. b2Assert(m_type == b2_dynamicBody);
  233. // Accumulate mass over all fixtures.
  234. b2Vec2 localCenter = b2Vec2_zero;
  235. for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
  236. {
  237. if (f->m_density == 0.0f)
  238. {
  239. continue;
  240. }
  241. b2MassData massData;
  242. f->GetMassData(&massData);
  243. m_mass += massData.mass;
  244. localCenter += massData.mass * massData.center;
  245. m_I += massData.I;
  246. }
  247. // Compute center of mass.
  248. if (m_mass > 0.0f)
  249. {
  250. m_invMass = 1.0f / m_mass;
  251. localCenter *= m_invMass;
  252. }
  253. else
  254. {
  255. // Force all dynamic bodies to have a positive mass.
  256. m_mass = 1.0f;
  257. m_invMass = 1.0f;
  258. }
  259. if (m_I > 0.0f && (m_flags & e_fixedRotationFlag) == 0)
  260. {
  261. // Center the inertia about the center of mass.
  262. m_I -= m_mass * b2Dot(localCenter, localCenter);
  263. b2Assert(m_I > 0.0f);
  264. m_invI = 1.0f / m_I;
  265. }
  266. else
  267. {
  268. m_I = 0.0f;
  269. m_invI = 0.0f;
  270. }
  271. // Move center of mass.
  272. b2Vec2 oldCenter = m_sweep.c;
  273. m_sweep.localCenter = localCenter;
  274. m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);
  275. // Update center of mass velocity.
  276. m_linearVelocity += b2Cross(m_angularVelocity, m_sweep.c - oldCenter);
  277. }
  278. void b2Body::SetMassData(const b2MassData* massData)
  279. {
  280. b2Assert(m_world->IsLocked() == false);
  281. if (m_world->IsLocked() == true)
  282. {
  283. return;
  284. }
  285. if (m_type != b2_dynamicBody)
  286. {
  287. return;
  288. }
  289. m_invMass = 0.0f;
  290. m_I = 0.0f;
  291. m_invI = 0.0f;
  292. m_mass = massData->mass;
  293. if (m_mass <= 0.0f)
  294. {
  295. m_mass = 1.0f;
  296. }
  297. m_invMass = 1.0f / m_mass;
  298. if (massData->I > 0.0f && (m_flags & b2Body::e_fixedRotationFlag) == 0)
  299. {
  300. m_I = massData->I - m_mass * b2Dot(massData->center, massData->center);
  301. b2Assert(m_I > 0.0f);
  302. m_invI = 1.0f / m_I;
  303. }
  304. // Move center of mass.
  305. b2Vec2 oldCenter = m_sweep.c;
  306. m_sweep.localCenter = massData->center;
  307. m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);
  308. // Update center of mass velocity.
  309. m_linearVelocity += b2Cross(m_angularVelocity, m_sweep.c - oldCenter);
  310. }
  311. bool b2Body::ShouldCollide(const b2Body* other) const
  312. {
  313. // At least one body should be dynamic.
  314. if (m_type != b2_dynamicBody && other->m_type != b2_dynamicBody)
  315. {
  316. return false;
  317. }
  318. // Does a joint prevent collision?
  319. for (b2JointEdge* jn = m_jointList; jn; jn = jn->next)
  320. {
  321. if (jn->other == other)
  322. {
  323. if (jn->joint->m_collideConnected == false)
  324. {
  325. return false;
  326. }
  327. }
  328. }
  329. return true;
  330. }
  331. void b2Body::SetTransform(const b2Vec2& position, float32 angle)
  332. {
  333. b2Assert(m_world->IsLocked() == false);
  334. if (m_world->IsLocked() == true)
  335. {
  336. return;
  337. }
  338. m_xf.q.Set(angle);
  339. m_xf.p = position;
  340. m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);
  341. m_sweep.a = angle;
  342. m_sweep.c0 = m_sweep.c;
  343. m_sweep.a0 = angle;
  344. b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
  345. for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
  346. {
  347. f->Synchronize(broadPhase, m_xf, m_xf);
  348. }
  349. m_world->m_contactManager.FindNewContacts();
  350. }
  351. void b2Body::SynchronizeFixtures()
  352. {
  353. b2Transform xf1;
  354. xf1.q.Set(m_sweep.a0);
  355. xf1.p = m_sweep.c0 - b2Mul(xf1.q, m_sweep.localCenter);
  356. b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
  357. for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
  358. {
  359. f->Synchronize(broadPhase, xf1, m_xf);
  360. }
  361. }
  362. void b2Body::SetActive(bool flag)
  363. {
  364. b2Assert(m_world->IsLocked() == false);
  365. if (flag == IsActive())
  366. {
  367. return;
  368. }
  369. if (flag)
  370. {
  371. m_flags |= e_activeFlag;
  372. // Create all proxies.
  373. b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
  374. for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
  375. {
  376. f->CreateProxies(broadPhase, m_xf);
  377. }
  378. // Contacts are created the next time step.
  379. }
  380. else
  381. {
  382. m_flags &= ~e_activeFlag;
  383. // Destroy all proxies.
  384. b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
  385. for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
  386. {
  387. f->DestroyProxies(broadPhase);
  388. }
  389. // Destroy the attached contacts.
  390. b2ContactEdge* ce = m_contactList;
  391. while (ce)
  392. {
  393. b2ContactEdge* ce0 = ce;
  394. ce = ce->next;
  395. m_world->m_contactManager.Destroy(ce0->contact);
  396. }
  397. m_contactList = NULL;
  398. }
  399. }
  400. void b2Body::Dump()
  401. {
  402. int32 bodyIndex = m_islandIndex;
  403. b2Log("{\n");
  404. b2Log(" b2BodyDef bd;\n");
  405. b2Log(" bd.type = b2BodyType(%d);\n", m_type);
  406. b2Log(" bd.position.Set(%.15lef, %.15lef);\n", m_xf.p.x, m_xf.p.y);
  407. b2Log(" bd.angle = %.15lef;\n", m_sweep.a);
  408. b2Log(" bd.linearVelocity.Set(%.15lef, %.15lef);\n", m_linearVelocity.x, m_linearVelocity.y);
  409. b2Log(" bd.angularVelocity = %.15lef;\n", m_angularVelocity);
  410. b2Log(" bd.linearDamping = %.15lef;\n", m_linearDamping);
  411. b2Log(" bd.angularDamping = %.15lef;\n", m_angularDamping);
  412. b2Log(" bd.allowSleep = bool(%d);\n", m_flags & e_autoSleepFlag);
  413. b2Log(" bd.awake = bool(%d);\n", m_flags & e_awakeFlag);
  414. b2Log(" bd.fixedRotation = bool(%d);\n", m_flags & e_fixedRotationFlag);
  415. b2Log(" bd.bullet = bool(%d);\n", m_flags & e_bulletFlag);
  416. b2Log(" bd.active = bool(%d);\n", m_flags & e_activeFlag);
  417. b2Log(" bd.gravityScale = %.15lef;\n", m_gravityScale);
  418. b2Log(" bodies[%d] = m_world->CreateBody(&bd);\n", m_islandIndex);
  419. b2Log("\n");
  420. for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
  421. {
  422. b2Log(" {\n");
  423. f->Dump(bodyIndex);
  424. b2Log(" }\n");
  425. }
  426. b2Log("}\n");
  427. }