From d4a97d49f3666c0607509545dcce1964e73425b7 Mon Sep 17 00:00:00 2001 From: rude Date: Sat, 15 Aug 2009 14:29:47 +0200 Subject: [PATCH] Added all callbacks to World. --- src/common/runtime.cpp | 14 ++ src/common/runtime.h | 9 ++ src/modules/physics/box2d/World.cpp | 198 ++++++++++++++--------- src/modules/physics/box2d/World.h | 34 ++-- src/modules/physics/box2d/wrap_World.cpp | 12 +- src/modules/physics/box2d/wrap_World.h | 4 +- 6 files changed, 174 insertions(+), 97 deletions(-) diff --git a/src/common/runtime.cpp b/src/common/runtime.cpp index e9547500c..b3ef3d7c4 100644 --- a/src/common/runtime.cpp +++ b/src/common/runtime.cpp @@ -23,6 +23,7 @@ // LOVE #include "Module.h" #include "Object.h" +#include "Reference.h" // STD #include @@ -53,6 +54,19 @@ namespace love return 0; } + Reference * luax_refif(lua_State * L, int type) + { + Reference * r = 0; + + // Create a reference only if the test succeeds. + if(lua_type(L, -1) == type) + r = new Reference(L); + else // Pop the value even if it fails (but also if it succeeds). + lua_pop(L, 1); + + return r; + } + void luax_printstack(lua_State * L) { for(int i = 1;i<=lua_gettop(L);i++) diff --git a/src/common/runtime.h b/src/common/runtime.h index 32aee9e74..93ba0dfb0 100644 --- a/src/common/runtime.h +++ b/src/common/runtime.h @@ -35,6 +35,7 @@ namespace love { // Forward declarations. class Module; + class Reference; /** * Registries represent special tables which can be accessed with @@ -68,6 +69,14 @@ namespace love int value; }; + /** + * Returns a reference to the top stack element (-1) if the value + * is of the specified type. If the value is incorrect, zero is returned. + * + * In any case, the top stack element is popped, regardless of its type. + **/ + Reference * luax_refif(lua_State * L, int type); + /** * Prints the current contents of the stack. Only useful for debugging. * @param L The Lua state. diff --git a/src/modules/physics/box2d/World.cpp b/src/modules/physics/box2d/World.cpp index 67a3b5fd1..92f51e7d0 100644 --- a/src/modules/physics/box2d/World.cpp +++ b/src/modules/physics/box2d/World.cpp @@ -22,6 +22,7 @@ #include "Shape.h" #include "Contact.h" +#include namespace love { @@ -30,74 +31,18 @@ namespace physics namespace box2d { - World::World(b2AABB aabb) - : add_ref(0), meter(DEFAULT_METER) + World::ContactCallback::ContactCallback() + : ref(0) { - world = new b2World(scaleDown(aabb), b2Vec2(0,0), true); - world->SetContactListener(this); - add_contacts.reserve(10); } - World::World(b2AABB aabb, b2Vec2 gravity, bool sleep) - : add_ref(0), meter(DEFAULT_METER) + World::ContactCallback::~ContactCallback() { - world = new b2World(scaleDown(aabb), scaleDown(gravity), sleep); - world->SetContactListener(this); - add_contacts.reserve(10); + if(ref != 0) + delete ref; } - World::~World() - { - if(add_ref != 0) - delete add_ref; - - delete world; - } - - void World::update(float dt) - { - world->Step(dt, 10); - - // Process contacts. - if(add_ref != 0) - { - lua_State * L = add_ref->getL(); - for(int i = 0;i<(int)add_contacts.size();i++) - { - // Push the function. - add_ref->push(); - - // Push first userdata. - { - shapeudata * d = (shapeudata *)(add_contacts[i]->point.shape1->GetUserData()); - if(d->ref != 0) - d->ref->push(); - else - lua_pushnil(L); - } - - // Push first userdata. - { - shapeudata * d = (shapeudata *)(add_contacts[i]->point.shape2->GetUserData()); - if(d->ref != 0) - d->ref->push(); - else - lua_pushnil(L); - } - - luax_newtype(L, "Contact", (PHYSICS_CONTACT_T), (void*)add_contacts[i], false); - lua_call(L, 3, 0); - } - - // Clear contacts. - for(int i = 0;i<(int)add_contacts.size();i++) - delete add_contacts[i]; - add_contacts.clear(); - } - - } - - void World::Add(const b2ContactPoint* point) + void World::ContactCallback::add(World * world, const b2ContactPoint* point) { /** * We must copy contacts, since we're not allowed to process @@ -105,33 +50,128 @@ namespace box2d * pretty much guarantees segfault. ^^ **/ - if(add_ref != 0) - add_contacts.push_back(new Contact(this, point)); + if(ref != 0) + contacts.push_back(new Contact(world, point)); } - int World::setCallback(lua_State * L) + void World::ContactCallback::process() { - luax_assert_argc(L, 1, 1); - luax_assert_function(L, -1); - - if(add_ref != 0) + // Process contacts. + if(ref != 0) { - delete add_ref; - add_ref = 0; + lua_State * L = ref->getL(); + for(int i = 0;i<(int)contacts.size();i++) + { + // Push the function. + ref->push(); + + // Push first userdata. + { + shapeudata * d = (shapeudata *)(contacts[i]->point.shape1->GetUserData()); + if(d->ref != 0) + d->ref->push(); + else + lua_pushnil(L); + } + + // Push first userdata. + { + shapeudata * d = (shapeudata *)(contacts[i]->point.shape2->GetUserData()); + if(d->ref != 0) + d->ref->push(); + else + lua_pushnil(L); + } + + luax_newtype(L, "Contact", (PHYSICS_CONTACT_T), (void*)contacts[i], false); + lua_call(L, 3, 0); + } + + // Clear contacts. + for(int i = 0;i<(int)contacts.size();i++) + delete contacts[i]; + contacts.clear(); + } + + } + + World::World(b2AABB aabb) + : meter(DEFAULT_METER) + { + world = new b2World(scaleDown(aabb), b2Vec2(0,0), true); + world->SetContactListener(this); + } + + World::World(b2AABB aabb, b2Vec2 gravity, bool sleep) + : meter(DEFAULT_METER) + { + world = new b2World(scaleDown(aabb), scaleDown(gravity), sleep); + world->SetContactListener(this); + } + + World::~World() + { + delete world; + } + + void World::update(float dt) + { + world->Step(dt, 10); + + + add.process(); + persist.process(); + remove.process(); + result.process(); + } + + void World::Add(const b2ContactPoint* point) + { + add.add(this, point); + } + + void World::Persist(const b2ContactPoint* point) + { + persist.add(this, point); + } + + void World::Remove(const b2ContactPoint* point) + { + remove.add(this, point); + } + + void World::Result(const b2ContactPoint* point) + { + result.add(this, point); + } + + int World::setCallbacks(lua_State * L) + { + int n = lua_gettop(L); + luax_assert_argc(L, 1, 4); + + switch(n) + { + case 4: + result.ref = luax_refif(L, LUA_TFUNCTION); + case 3: + remove.ref = luax_refif(L, LUA_TFUNCTION); + case 2: + persist.ref = luax_refif(L, LUA_TFUNCTION); + case 1: + add.ref = luax_refif(L, LUA_TFUNCTION); } - add_ref = new Reference(L); return 0; } - int World::getCallback(lua_State * L) + int World::getCallbacks(lua_State * L) { - if(add_ref != 0) - add_ref->push(); - else - lua_pushnil(L); - - return 1; + add.ref ? add.ref->push() : lua_pushnil(L); + persist.ref ? persist.ref->push() : lua_pushnil(L); + remove.ref ? remove.ref->push() : lua_pushnil(L); + result.ref ? result.ref->push() : lua_pushnil(L); + return lua_gettop(L); } void World::setGravity(float x, float y) diff --git a/src/modules/physics/box2d/World.h b/src/modules/physics/box2d/World.h index fa6e26c88..625079689 100644 --- a/src/modules/physics/box2d/World.h +++ b/src/modules/physics/box2d/World.h @@ -60,16 +60,26 @@ namespace box2d friend class MouseJoint; friend class Body; + public: + + class ContactCallback + { + public: + Reference * ref; + std::vector contacts; + ContactCallback(); + ~ContactCallback(); + void add(World * world, const b2ContactPoint* point); + void process(); + }; + private: // Pointer to the Box2D world. b2World * world; // Contact callbacks. - Reference * add_ref; - - // Contacts buffers. - std::vector add_contacts; + ContactCallback add, persist, remove, result; // The length of one meter in pixels. int meter; @@ -109,18 +119,22 @@ namespace box2d // From b2ContactListener void Add(const b2ContactPoint* point); + void Persist(const b2ContactPoint* point); + void Remove(const b2ContactPoint* point); + void Result(const b2ContactPoint* point); /** - * Recieves a Lua function as argument, and - * stores it for use when a collision occurs. + * Receives up to four Lua functions as arguments. Each function is + * collision callback for the four events (in order): add, persist, + * remove and result. The value "nil" is accepted if one or more events + * are uninteresting. **/ - int setCallback(lua_State * L); + int setCallbacks(lua_State * L); /** - * Returns the stored Lua function for collision - * handling, or nil if there is none. + * Returns the functions previously set by setCallbacks. **/ - int getCallback(lua_State * L); + int getCallbacks(lua_State * L); /** * Sets the current gravity of the World. diff --git a/src/modules/physics/box2d/wrap_World.cpp b/src/modules/physics/box2d/wrap_World.cpp index dac341718..0fed24668 100644 --- a/src/modules/physics/box2d/wrap_World.cpp +++ b/src/modules/physics/box2d/wrap_World.cpp @@ -40,18 +40,18 @@ namespace box2d return 0; } - int w_World_setCallback(lua_State * L) + int w_World_setCallbacks(lua_State * L) { World * t = luax_checkworld(L, 1); lua_remove(L, 1); - return t->setCallback(L); + return t->setCallbacks(L); } - int w_World_getCallback(lua_State * L) + int w_World_getCallbacks(lua_State * L) { World * t = luax_checkworld(L, 1); lua_remove(L, 1); - return t->getCallback(L); + return t->getCallbacks(L); } int w_World_setGravity(lua_State * L) @@ -116,8 +116,8 @@ namespace box2d static const luaL_Reg functions[] = { { "update", w_World_update }, - { "setCallback", w_World_setCallback }, - { "getCallback", w_World_getCallback }, + { "setCallbacks", w_World_setCallbacks }, + { "getCallbacks", w_World_getCallbacks }, { "setGravity", w_World_setGravity }, { "getGravity", w_World_getGravity }, { "setAllowSleep", w_World_setAllowSleep }, diff --git a/src/modules/physics/box2d/wrap_World.h b/src/modules/physics/box2d/wrap_World.h index 78946513f..39fa5efc1 100644 --- a/src/modules/physics/box2d/wrap_World.h +++ b/src/modules/physics/box2d/wrap_World.h @@ -33,8 +33,8 @@ namespace box2d { World * luax_checkworld(lua_State * L, int idx); int w_World_update(lua_State * L); - int w_World_setCallback(lua_State * L); - int w_World_getCallback(lua_State * L); + int w_World_setCallbacks(lua_State * L); + int w_World_getCallbacks(lua_State * L); int w_World_setGravity(lua_State * L); int w_World_getGravity(lua_State * L); int w_World_setAllowSleep(lua_State * L);