World.cpp 14 KB

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