Import box2d-contacts branch from love-experiments

Fix issues with Contact lifetime, based on the work of
Matteo "teomat" Goggi
This commit is contained in:
Boolsheet
2012-07-24 23:59:42 +02:00
parent 82d6edb32c
commit cde5aa3307
4 changed files with 56 additions and 16 deletions
+15 -1
View File
@@ -39,7 +39,21 @@ Contact::Contact(b2Contact *contact)
Contact::~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) int Contact::getPositions(lua_State *L)
+12
View File
@@ -59,6 +59,18 @@ public:
virtual ~Contact(); 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. * Gets the position of each point of contact.
* @return The position along the x-axis. * @return The position along the x-axis.
+25 -14
View File
@@ -77,9 +77,13 @@ void World::ContactCallback::process(b2Contact *contact, const b2ContactImpulse
throw love::Exception("A fixture has escaped Memoizer!"); 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; int args = 3;
if (impulse) if (impulse)
@@ -117,12 +121,12 @@ bool World::ContactFilter::process(Fixture *a, Fixture *b)
a->getFilterData(filterA); a->getFilterData(filterA);
b->getFilterData(filterB); b->getFilterData(filterB);
if (filterA[2] != 0 && // 0 is the default group, so this does not count 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 filterA[2] == filterB[2]) // if they are in the same group
return filterA[2] > 0; // Negative indexes mean you don't collide return filterA[2] > 0; // Negative indexes mean you don't collide
if ((filterA[1] & filterB[0]) == 0 || 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 return false; // A and B aren't set to collide
if (ref != 0) if (ref != 0)
@@ -290,6 +294,11 @@ void World::BeginContact(b2Contact *contact)
void World::EndContact(b2Contact *contact) void World::EndContact(b2Contact *contact)
{ {
end.process(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) void World::PreSolve(b2Contact *contact, const b2Manifold *oldManifold)
@@ -332,19 +341,19 @@ int World::setCallbacks(lua_State *L)
case 4: case 4:
if (postsolve.ref) if (postsolve.ref)
delete postsolve.ref; delete postsolve.ref;
postsolve.ref = luax_refif (L, LUA_TFUNCTION); postsolve.ref = luax_refif(L, LUA_TFUNCTION);
case 3: case 3:
if (presolve.ref) if (presolve.ref)
delete presolve.ref; delete presolve.ref;
presolve.ref = luax_refif (L, LUA_TFUNCTION); presolve.ref = luax_refif(L, LUA_TFUNCTION);
case 2: case 2:
if (end.ref) if (end.ref)
delete end.ref; delete end.ref;
end.ref = luax_refif (L, LUA_TFUNCTION); end.ref = luax_refif(L, LUA_TFUNCTION);
case 1: case 1:
if (begin.ref) if (begin.ref)
delete begin.ref; delete begin.ref;
begin.ref = luax_refif (L, LUA_TFUNCTION); begin.ref = luax_refif(L, LUA_TFUNCTION);
} }
return 0; return 0;
@@ -364,7 +373,7 @@ int World::setContactFilter(lua_State *L)
luax_assert_argc(L, 1); luax_assert_argc(L, 1);
if (filter.ref) if (filter.ref)
delete filter.ref; delete filter.ref;
filter.ref = luax_refif (L, LUA_TFUNCTION); filter.ref = luax_refif(L, LUA_TFUNCTION);
return 0; return 0;
} }
@@ -468,8 +477,10 @@ int World::getContactList(lua_State *L) const
{ {
if (!c) break; if (!c) break;
Contact *contact = (Contact *)Memoizer::find(c); Contact *contact = (Contact *)Memoizer::find(c);
if (!contact) throw love::Exception("A contact has escaped Memoizer!"); if (!contact)
contact->retain(); contact = new Contact(c);
else
contact->retain();
luax_newtype(L, "Contact", PHYSICS_CONTACT_T, (void *)contact); luax_newtype(L, "Contact", PHYSICS_CONTACT_T, (void *)contact);
lua_rawseti(L, -2, i); lua_rawseti(L, -2, i);
i++; i++;
@@ -494,7 +505,7 @@ int World::queryBoundingBox(lua_State *L)
box.lowerBound = Physics::scaleDown(b2Vec2(lx, ly)); box.lowerBound = Physics::scaleDown(b2Vec2(lx, ly));
box.upperBound = Physics::scaleDown(b2Vec2(ux, uy)); box.upperBound = Physics::scaleDown(b2Vec2(ux, uy));
if (query.ref) delete query.ref; if (query.ref) delete query.ref;
query.ref = luax_refif (L, LUA_TFUNCTION); query.ref = luax_refif(L, LUA_TFUNCTION);
world->QueryAABB(&query, box); world->QueryAABB(&query, box);
return 0; return 0;
} }
@@ -510,7 +521,7 @@ int World::rayCast(lua_State *L)
b2Vec2 v2 = Physics::scaleDown(b2Vec2(x2, y2)); b2Vec2 v2 = Physics::scaleDown(b2Vec2(x2, y2));
if (raycast.ref) if (raycast.ref)
delete raycast.ref; delete raycast.ref;
raycast.ref = luax_refif (L, LUA_TFUNCTION); raycast.ref = luax_refif(L, LUA_TFUNCTION);
world->RayCast(&raycast, v1, v2); world->RayCast(&raycast, v1, v2);
return 0; return 0;
} }
+4 -1
View File
@@ -29,7 +29,10 @@ namespace box2d
Contact *luax_checkcontact(lua_State *L, int idx) Contact *luax_checkcontact(lua_State *L, int idx)
{ {
return luax_checktype<Contact>(L, idx, "Contact", PHYSICS_CONTACT_T); Contact *c = luax_checktype<Contact>(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) int w_Contact_getPositions(lua_State *L)