World.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  1. /**
  2. * Copyright (c) 2006-2016 LOVE Development Team
  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. *
  8. * Permission is granted to anyone to use this software for any purpose,
  9. * including commercial applications, and to alter it and redistribute it
  10. * freely, subject to the following restrictions:
  11. *
  12. * 1. The origin of this software must not be misrepresented; you must not
  13. * claim that you wrote the original software. If you use this software
  14. * in a product, an acknowledgment in the product documentation would be
  15. * appreciated but is not required.
  16. * 2. Altered source versions must be plainly marked as such, and must not be
  17. * misrepresented as being the original software.
  18. * 3. This notice may not be removed or altered from any source distribution.
  19. **/
  20. #include "World.h"
  21. #include "Fixture.h"
  22. #include "Shape.h"
  23. #include "Contact.h"
  24. #include "Physics.h"
  25. #include "common/Memoizer.h"
  26. #include "common/Reference.h"
  27. namespace love
  28. {
  29. namespace physics
  30. {
  31. namespace box2d
  32. {
  33. World::ContactCallback::ContactCallback()
  34. : ref(nullptr)
  35. , L(nullptr)
  36. {
  37. }
  38. World::ContactCallback::~ContactCallback()
  39. {
  40. if (ref != nullptr)
  41. delete ref;
  42. }
  43. void World::ContactCallback::process(b2Contact *contact, const b2ContactImpulse *impulse)
  44. {
  45. // Process contacts.
  46. if (ref != nullptr && L != nullptr)
  47. {
  48. ref->push(L);
  49. // Push first fixture.
  50. {
  51. Fixture *a = (Fixture *)Memoizer::find(contact->GetFixtureA());
  52. if (a != nullptr)
  53. luax_pushtype(L, PHYSICS_FIXTURE_ID, a);
  54. else
  55. throw love::Exception("A fixture has escaped Memoizer!");
  56. }
  57. // Push second fixture.
  58. {
  59. Fixture *b = (Fixture *)Memoizer::find(contact->GetFixtureB());
  60. if (b != nullptr)
  61. luax_pushtype(L, PHYSICS_FIXTURE_ID, b);
  62. else
  63. throw love::Exception("A fixture has escaped Memoizer!");
  64. }
  65. Contact *cobj = (Contact *)Memoizer::find(contact);
  66. if (!cobj)
  67. cobj = new Contact(contact);
  68. else
  69. cobj->retain();
  70. luax_pushtype(L, PHYSICS_CONTACT_ID, cobj);
  71. cobj->release();
  72. int args = 3;
  73. if (impulse)
  74. {
  75. for (int c = 0; c < impulse->count; c++)
  76. {
  77. lua_pushnumber(L, Physics::scaleUp(impulse->normalImpulses[c]));
  78. lua_pushnumber(L, Physics::scaleUp(impulse->tangentImpulses[c]));
  79. args += 2;
  80. }
  81. }
  82. lua_call(L, args, 0);
  83. }
  84. }
  85. World::ContactFilter::ContactFilter()
  86. : ref(nullptr)
  87. , L(nullptr)
  88. {
  89. }
  90. World::ContactFilter::~ContactFilter()
  91. {
  92. if (ref != nullptr)
  93. delete ref;
  94. }
  95. bool World::ContactFilter::process(Fixture *a, Fixture *b)
  96. {
  97. // Handle masks, reimplemented from the manual
  98. int filterA[3], filterB[3];
  99. // [0] categoryBits
  100. // [1] maskBits
  101. // [2] groupIndex
  102. a->getFilterData(filterA);
  103. b->getFilterData(filterB);
  104. if (filterA[2] != 0 && // 0 is the default group, so this does not count
  105. filterA[2] == filterB[2]) // if they are in the same group
  106. return filterA[2] > 0; // Negative indexes mean you don't collide
  107. if ((filterA[1] & filterB[0]) == 0 ||
  108. (filterB[1] & filterA[0]) == 0)
  109. return false; // A and B aren't set to collide
  110. if (ref != nullptr && L != nullptr)
  111. {
  112. ref->push(L);
  113. luax_pushtype(L, PHYSICS_FIXTURE_ID, a);
  114. luax_pushtype(L, PHYSICS_FIXTURE_ID, b);
  115. lua_call(L, 2, 1);
  116. return luax_toboolean(L, -1);
  117. }
  118. return true;
  119. }
  120. World::QueryCallback::QueryCallback(lua_State *L, int idx)
  121. : L(L)
  122. , funcidx(idx)
  123. {
  124. luaL_checktype(L, funcidx, LUA_TFUNCTION);
  125. }
  126. World::QueryCallback::~QueryCallback()
  127. {
  128. }
  129. bool World::QueryCallback::ReportFixture(b2Fixture *fixture)
  130. {
  131. if (L != nullptr)
  132. {
  133. lua_pushvalue(L, funcidx);
  134. Fixture *f = (Fixture *)Memoizer::find(fixture);
  135. if (!f)
  136. throw love::Exception("A fixture has escaped Memoizer!");
  137. luax_pushtype(L, PHYSICS_FIXTURE_ID, f);
  138. lua_call(L, 1, 1);
  139. bool cont = luax_toboolean(L, -1);
  140. lua_pop(L, 1);
  141. return cont;
  142. }
  143. return true;
  144. }
  145. World::RayCastCallback::RayCastCallback(lua_State *L, int idx)
  146. : L(L)
  147. , funcidx(idx)
  148. {
  149. luaL_checktype(L, funcidx, LUA_TFUNCTION);
  150. }
  151. World::RayCastCallback::~RayCastCallback()
  152. {
  153. }
  154. float32 World::RayCastCallback::ReportFixture(b2Fixture *fixture, const b2Vec2 &point, const b2Vec2 &normal, float32 fraction)
  155. {
  156. if (L != nullptr)
  157. {
  158. lua_pushvalue(L, funcidx);
  159. Fixture *f = (Fixture *)Memoizer::find(fixture);
  160. if (!f)
  161. throw love::Exception("A fixture has escaped Memoizer!");
  162. luax_pushtype(L, PHYSICS_FIXTURE_ID, f);
  163. b2Vec2 scaledPoint = Physics::scaleUp(point);
  164. lua_pushnumber(L, scaledPoint.x);
  165. lua_pushnumber(L, scaledPoint.y);
  166. lua_pushnumber(L, normal.x);
  167. lua_pushnumber(L, normal.y);
  168. lua_pushnumber(L, fraction);
  169. lua_call(L, 6, 1);
  170. if (!lua_isnumber(L, -1))
  171. luaL_error(L, "Raycast callback didn't return a number!");
  172. float32 fraction = (float32) lua_tonumber(L, -1);
  173. lua_pop(L, 1);
  174. return fraction;
  175. }
  176. return 0;
  177. }
  178. void World::SayGoodbye(b2Fixture *fixture)
  179. {
  180. Fixture *f = (Fixture *)Memoizer::find(fixture);
  181. // Hint implicit destruction with true.
  182. if (f) f->destroy(true);
  183. }
  184. void World::SayGoodbye(b2Joint *joint)
  185. {
  186. Joint *j = (Joint *)Memoizer::find(joint);
  187. // Hint implicit destruction with true.
  188. if (j) j->destroyJoint(true);
  189. }
  190. World::World()
  191. : world(nullptr)
  192. , destructWorld(false)
  193. {
  194. world = new b2World(b2Vec2(0,0));
  195. world->SetAllowSleeping(true);
  196. world->SetContactListener(this);
  197. world->SetContactFilter(this);
  198. world->SetDestructionListener(this);
  199. b2BodyDef def;
  200. groundBody = world->CreateBody(&def);
  201. Memoizer::add(world, this);
  202. }
  203. World::World(b2Vec2 gravity, bool sleep)
  204. : world(nullptr)
  205. , destructWorld(false)
  206. {
  207. world = new b2World(Physics::scaleDown(gravity));
  208. world->SetAllowSleeping(sleep);
  209. world->SetContactListener(this);
  210. world->SetContactFilter(this);
  211. world->SetDestructionListener(this);
  212. b2BodyDef def;
  213. groundBody = world->CreateBody(&def);
  214. Memoizer::add(world, this);
  215. }
  216. World::~World()
  217. {
  218. destroy();
  219. }
  220. void World::update(float dt)
  221. {
  222. update(dt, 8, 3); // Box2D 2.3's recommended defaults.
  223. }
  224. void World::update(float dt, int velocityIterations, int positionIterations)
  225. {
  226. world->Step(dt, velocityIterations, positionIterations);
  227. // Destroy all objects marked during the time step.
  228. for (Body *b : destructBodies)
  229. {
  230. if (b->body != nullptr) b->destroy();
  231. // Release for reference in vector.
  232. b->release();
  233. }
  234. for (Fixture *f : destructFixtures)
  235. {
  236. if (f->isValid()) f->destroy();
  237. // Release for reference in vector.
  238. f->release();
  239. }
  240. for (Joint *j : destructJoints)
  241. {
  242. if (j->isValid()) j->destroyJoint();
  243. // Release for reference in vector.
  244. j->release();
  245. }
  246. destructBodies.clear();
  247. destructFixtures.clear();
  248. destructJoints.clear();
  249. if (destructWorld)
  250. destroy();
  251. }
  252. void World::BeginContact(b2Contact *contact)
  253. {
  254. begin.process(contact);
  255. }
  256. void World::EndContact(b2Contact *contact)
  257. {
  258. end.process(contact);
  259. // Letting the Contact know that the b2Contact will be destroyed any second.
  260. Contact *c = (Contact *)Memoizer::find(contact);
  261. if (c != NULL)
  262. c->invalidate();
  263. }
  264. void World::PreSolve(b2Contact *contact, const b2Manifold *oldManifold)
  265. {
  266. B2_NOT_USED(oldManifold); // not sure what to do with this
  267. presolve.process(contact);
  268. }
  269. void World::PostSolve(b2Contact *contact, const b2ContactImpulse *impulse)
  270. {
  271. postsolve.process(contact, impulse);
  272. }
  273. bool World::ShouldCollide(b2Fixture *fixtureA, b2Fixture *fixtureB)
  274. {
  275. // Fixtures should be memoized, if we created them
  276. Fixture *a = (Fixture *)Memoizer::find(fixtureA);
  277. Fixture *b = (Fixture *)Memoizer::find(fixtureB);
  278. if (!a || !b)
  279. throw love::Exception("A fixture has escaped Memoizer!");
  280. return filter.process(a, b);
  281. }
  282. bool World::isValid() const
  283. {
  284. return world != nullptr;
  285. }
  286. int World::setCallbacks(lua_State *L)
  287. {
  288. int nargs = lua_gettop(L);
  289. for (int i = 1; i <= 4; i++)
  290. {
  291. if (!lua_isnoneornil(L, i))
  292. luaL_checktype(L, i, LUA_TFUNCTION);
  293. }
  294. delete begin.ref;
  295. begin.ref = nullptr;
  296. delete end.ref;
  297. end.ref = nullptr;
  298. delete presolve.ref;
  299. presolve.ref = nullptr;
  300. delete postsolve.ref;
  301. postsolve.ref = nullptr;
  302. if (nargs >= 1)
  303. {
  304. lua_pushvalue(L, 1);
  305. begin.ref = luax_refif(L, LUA_TFUNCTION);
  306. begin.L = L;
  307. }
  308. if (nargs >= 2)
  309. {
  310. lua_pushvalue(L, 2);
  311. end.ref = luax_refif(L, LUA_TFUNCTION);
  312. end.L = L;
  313. }
  314. if (nargs >= 3)
  315. {
  316. lua_pushvalue(L, 3);
  317. presolve.ref = luax_refif(L, LUA_TFUNCTION);
  318. presolve.L = L;
  319. }
  320. if (nargs >= 4)
  321. {
  322. lua_pushvalue(L, 4);
  323. postsolve.ref = luax_refif(L, LUA_TFUNCTION);
  324. postsolve.L = L;
  325. }
  326. return 0;
  327. }
  328. int World::getCallbacks(lua_State *L)
  329. {
  330. begin.ref ? begin.ref->push(L) : lua_pushnil(L);
  331. end.ref ? end.ref->push(L) : lua_pushnil(L);
  332. presolve.ref ? presolve.ref->push(L) : lua_pushnil(L);
  333. postsolve.ref ? postsolve.ref->push(L) : lua_pushnil(L);
  334. return 4;
  335. }
  336. void World::setCallbacksL(lua_State *L)
  337. {
  338. begin.L = end.L = presolve.L = postsolve.L = filter.L = L;
  339. }
  340. int World::setContactFilter(lua_State *L)
  341. {
  342. if (!lua_isnoneornil(L, 1))
  343. luaL_checktype(L, 1, LUA_TFUNCTION);
  344. if (filter.ref)
  345. delete filter.ref;
  346. filter.ref = luax_refif(L, LUA_TFUNCTION);
  347. filter.L = L;
  348. return 0;
  349. }
  350. int World::getContactFilter(lua_State *L)
  351. {
  352. filter.ref ? filter.ref->push(L) : lua_pushnil(L);
  353. return 1;
  354. }
  355. void World::setGravity(float x, float y)
  356. {
  357. world->SetGravity(Physics::scaleDown(b2Vec2(x, y)));
  358. }
  359. int World::getGravity(lua_State *L)
  360. {
  361. b2Vec2 v = Physics::scaleUp(world->GetGravity());
  362. lua_pushnumber(L, v.x);
  363. lua_pushnumber(L, v.y);
  364. return 2;
  365. }
  366. void World::translateOrigin(float x, float y)
  367. {
  368. world->ShiftOrigin(Physics::scaleDown(b2Vec2(x, y)));
  369. }
  370. void World::setSleepingAllowed(bool allow)
  371. {
  372. world->SetAllowSleeping(allow);
  373. }
  374. bool World::isSleepingAllowed() const
  375. {
  376. return world->GetAllowSleeping();
  377. }
  378. bool World::isLocked() const
  379. {
  380. return world->IsLocked();
  381. }
  382. int World::getBodyCount() const
  383. {
  384. return world->GetBodyCount()-1; // ignore the ground body
  385. }
  386. int World::getJointCount() const
  387. {
  388. return world->GetJointCount();
  389. }
  390. int World::getContactCount() const
  391. {
  392. return world->GetContactCount();
  393. }
  394. int World::getBodyList(lua_State *L) const
  395. {
  396. lua_newtable(L);
  397. b2Body *b = world->GetBodyList();
  398. int i = 1;
  399. do
  400. {
  401. if (!b)
  402. break;
  403. if (b == groundBody)
  404. continue;
  405. Body *body = (Body *)Memoizer::find(b);
  406. if (!body)
  407. throw love::Exception("A body has escaped Memoizer!");
  408. luax_pushtype(L, PHYSICS_BODY_ID, body);
  409. lua_rawseti(L, -2, i);
  410. i++;
  411. }
  412. while ((b = b->GetNext()));
  413. return 1;
  414. }
  415. int World::getJointList(lua_State *L) const
  416. {
  417. lua_newtable(L);
  418. b2Joint *j = world->GetJointList();
  419. int i = 1;
  420. do
  421. {
  422. if (!j) break;
  423. Joint *joint = (Joint *)Memoizer::find(j);
  424. if (!joint) throw love::Exception("A joint has escaped Memoizer!");
  425. luax_pushtype(L, PHYSICS_JOINT_ID, joint);
  426. lua_rawseti(L, -2, i);
  427. i++;
  428. }
  429. while ((j = j->GetNext()));
  430. return 1;
  431. }
  432. int World::getContactList(lua_State *L) const
  433. {
  434. lua_newtable(L);
  435. b2Contact *c = world->GetContactList();
  436. int i = 1;
  437. do
  438. {
  439. if (!c) break;
  440. Contact *contact = (Contact *)Memoizer::find(c);
  441. if (!contact)
  442. contact = new Contact(c);
  443. else
  444. contact->retain();
  445. luax_pushtype(L, PHYSICS_CONTACT_ID, contact);
  446. contact->release();
  447. lua_rawseti(L, -2, i);
  448. i++;
  449. }
  450. while ((c = c->GetNext()));
  451. return 1;
  452. }
  453. b2Body *World::getGroundBody() const
  454. {
  455. return groundBody;
  456. }
  457. int World::queryBoundingBox(lua_State *L)
  458. {
  459. b2AABB box;
  460. float lx = (float)luaL_checknumber(L, 1);
  461. float ly = (float)luaL_checknumber(L, 2);
  462. float ux = (float)luaL_checknumber(L, 3);
  463. float uy = (float)luaL_checknumber(L, 4);
  464. box.lowerBound = Physics::scaleDown(b2Vec2(lx, ly));
  465. box.upperBound = Physics::scaleDown(b2Vec2(ux, uy));
  466. luaL_checktype(L, 5, LUA_TFUNCTION);
  467. QueryCallback query(L, 5);
  468. world->QueryAABB(&query, box);
  469. return 0;
  470. }
  471. int World::rayCast(lua_State *L)
  472. {
  473. float x1 = (float)luaL_checknumber(L, 1);
  474. float y1 = (float)luaL_checknumber(L, 2);
  475. float x2 = (float)luaL_checknumber(L, 3);
  476. float y2 = (float)luaL_checknumber(L, 4);
  477. b2Vec2 v1 = Physics::scaleDown(b2Vec2(x1, y1));
  478. b2Vec2 v2 = Physics::scaleDown(b2Vec2(x2, y2));
  479. luaL_checktype(L, 5, LUA_TFUNCTION);
  480. RayCastCallback raycast(L, 5);
  481. world->RayCast(&raycast, v1, v2);
  482. return 0;
  483. }
  484. void World::destroy()
  485. {
  486. if (world == nullptr)
  487. return;
  488. if (world->IsLocked())
  489. {
  490. destructWorld = true;
  491. return;
  492. }
  493. // Cleaning up the world.
  494. b2Body *b = world->GetBodyList();
  495. while (b)
  496. {
  497. b2Body *t = b;
  498. b = b->GetNext();
  499. if (t == groundBody)
  500. continue;
  501. Body *body = (Body *)Memoizer::find(t);
  502. if (!body)
  503. throw love::Exception("A body has escaped Memoizer!");
  504. body->destroy();
  505. }
  506. world->DestroyBody(groundBody);
  507. Memoizer::remove(world);
  508. delete world;
  509. world = nullptr;
  510. }
  511. } // box2d
  512. } // physics
  513. } // love