From cde5aa3307fb7161e225831741965584b7bd62e5 Mon Sep 17 00:00:00 2001 From: Boolsheet Date: Tue, 24 Jul 2012 23:59:42 +0200 Subject: [PATCH] Import box2d-contacts branch from love-experiments Fix issues with Contact lifetime, based on the work of Matteo "teomat" Goggi --- src/modules/physics/box2d/Contact.cpp | 16 ++++++++- src/modules/physics/box2d/Contact.h | 12 +++++++ src/modules/physics/box2d/World.cpp | 39 ++++++++++++++-------- src/modules/physics/box2d/wrap_Contact.cpp | 5 ++- 4 files changed, 56 insertions(+), 16 deletions(-) diff --git a/src/modules/physics/box2d/Contact.cpp b/src/modules/physics/box2d/Contact.cpp index 6d1162bfa..7aa260bc4 100644 --- a/src/modules/physics/box2d/Contact.cpp +++ b/src/modules/physics/box2d/Contact.cpp @@ -39,7 +39,21 @@ Contact::Contact(b2Contact *contact) Contact::~Contact() { - Memoizer::remove(contact); + invalidate(); +} + +void Contact::invalidate() +{ + if (contact != NULL) + { + Memoizer::remove(contact); + contact = NULL; + } +} + +bool Contact::isValid() +{ + return contact != NULL ? true : false; } int Contact::getPositions(lua_State *L) diff --git a/src/modules/physics/box2d/Contact.h b/src/modules/physics/box2d/Contact.h index 6bf5184a4..852a7e635 100644 --- a/src/modules/physics/box2d/Contact.h +++ b/src/modules/physics/box2d/Contact.h @@ -59,6 +59,18 @@ public: virtual ~Contact(); + /** + * Removes the b2Contact pointer from Memoizer and sets it + * to null on the Contact. + **/ + void invalidate(); + + /** + * Returns if the Contact still points to a valid b2Contact. + * @return True if the contact is still valid or false if it has been destroyed. + **/ + bool isValid(); + /** * Gets the position of each point of contact. * @return The position along the x-axis. diff --git a/src/modules/physics/box2d/World.cpp b/src/modules/physics/box2d/World.cpp index 897e65a78..3f158024c 100644 --- a/src/modules/physics/box2d/World.cpp +++ b/src/modules/physics/box2d/World.cpp @@ -77,9 +77,13 @@ void World::ContactCallback::process(b2Contact *contact, const b2ContactImpulse throw love::Exception("A fixture has escaped Memoizer!"); } - Contact *c = new Contact(contact); + Contact *cobj = (Contact *)Memoizer::find(contact); + if (!cobj) + cobj = new Contact(contact); + else + cobj->retain(); - luax_newtype(L, "Contact", (PHYSICS_CONTACT_T), (void *)c); + luax_newtype(L, "Contact", (PHYSICS_CONTACT_T), (void *)cobj); int args = 3; if (impulse) @@ -117,12 +121,12 @@ bool World::ContactFilter::process(Fixture *a, Fixture *b) a->getFilterData(filterA); b->getFilterData(filterB); - if (filterA[2] != 0 && // 0 is the default group, so this does not count - filterA[2] == filterB[2]) // if they are in the same group + if (filterA[2] != 0 && // 0 is the default group, so this does not count + filterA[2] == filterB[2]) // if they are in the same group return filterA[2] > 0; // Negative indexes mean you don't collide if ((filterA[1] & filterB[0]) == 0 || - (filterB[1] & filterA[0]) == 0) + (filterB[1] & filterA[0]) == 0) return false; // A and B aren't set to collide if (ref != 0) @@ -290,6 +294,11 @@ void World::BeginContact(b2Contact *contact) void World::EndContact(b2Contact *contact) { end.process(contact); + + // Letting the Contact know that the b2Contact will be destroyed any second. + Contact *c = (Contact *)Memoizer::find(contact); + if (c != NULL) + c->invalidate(); } void World::PreSolve(b2Contact *contact, const b2Manifold *oldManifold) @@ -332,19 +341,19 @@ int World::setCallbacks(lua_State *L) case 4: if (postsolve.ref) delete postsolve.ref; - postsolve.ref = luax_refif (L, LUA_TFUNCTION); + postsolve.ref = luax_refif(L, LUA_TFUNCTION); case 3: if (presolve.ref) delete presolve.ref; - presolve.ref = luax_refif (L, LUA_TFUNCTION); + presolve.ref = luax_refif(L, LUA_TFUNCTION); case 2: if (end.ref) delete end.ref; - end.ref = luax_refif (L, LUA_TFUNCTION); + end.ref = luax_refif(L, LUA_TFUNCTION); case 1: if (begin.ref) delete begin.ref; - begin.ref = luax_refif (L, LUA_TFUNCTION); + begin.ref = luax_refif(L, LUA_TFUNCTION); } return 0; @@ -364,7 +373,7 @@ int World::setContactFilter(lua_State *L) luax_assert_argc(L, 1); if (filter.ref) delete filter.ref; - filter.ref = luax_refif (L, LUA_TFUNCTION); + filter.ref = luax_refif(L, LUA_TFUNCTION); return 0; } @@ -468,8 +477,10 @@ int World::getContactList(lua_State *L) const { if (!c) break; Contact *contact = (Contact *)Memoizer::find(c); - if (!contact) throw love::Exception("A contact has escaped Memoizer!"); - contact->retain(); + if (!contact) + contact = new Contact(c); + else + contact->retain(); luax_newtype(L, "Contact", PHYSICS_CONTACT_T, (void *)contact); lua_rawseti(L, -2, i); i++; @@ -494,7 +505,7 @@ int World::queryBoundingBox(lua_State *L) box.lowerBound = Physics::scaleDown(b2Vec2(lx, ly)); box.upperBound = Physics::scaleDown(b2Vec2(ux, uy)); if (query.ref) delete query.ref; - query.ref = luax_refif (L, LUA_TFUNCTION); + query.ref = luax_refif(L, LUA_TFUNCTION); world->QueryAABB(&query, box); return 0; } @@ -510,7 +521,7 @@ int World::rayCast(lua_State *L) b2Vec2 v2 = Physics::scaleDown(b2Vec2(x2, y2)); if (raycast.ref) delete raycast.ref; - raycast.ref = luax_refif (L, LUA_TFUNCTION); + raycast.ref = luax_refif(L, LUA_TFUNCTION); world->RayCast(&raycast, v1, v2); return 0; } diff --git a/src/modules/physics/box2d/wrap_Contact.cpp b/src/modules/physics/box2d/wrap_Contact.cpp index d2d2db348..625be10ef 100644 --- a/src/modules/physics/box2d/wrap_Contact.cpp +++ b/src/modules/physics/box2d/wrap_Contact.cpp @@ -29,7 +29,10 @@ namespace box2d Contact *luax_checkcontact(lua_State *L, int idx) { - return luax_checktype(L, idx, "Contact", PHYSICS_CONTACT_T); + Contact *c = luax_checktype(L, idx, "Contact", PHYSICS_CONTACT_T); + if (!c->isValid()) + luaL_error(L, "Attempt to use destroyed contact."); + return c; } int w_Contact_getPositions(lua_State *L)