diff --git a/src/modules/physics/box2d/World.cpp b/src/modules/physics/box2d/World.cpp index 7d6671767..9f1cf7f76 100644 --- a/src/modules/physics/box2d/World.cpp +++ b/src/modules/physics/box2d/World.cpp @@ -168,6 +168,39 @@ namespace box2d } return true; } + + World::RayCastCallback::RayCastCallback() + : ref(0) + { + } + + World::RayCastCallback::~RayCastCallback() + { + if(ref != 0) + delete ref; + } + + float32 World::RayCastCallback::ReportFixture(b2Fixture * fixture, const b2Vec2& point, const b2Vec2& normal, float32 fraction) + { + if (ref != 0) + { + lua_State * L = ref->getL(); + ref->push(); + Fixture * f = (Fixture *)Memoizer::find(fixture); + if (!f) throw love::Exception("A fixture has escaped Memoizer!"); + luax_newtype(L, "Fixture", PHYSICS_FIXTURE_T, (void*)f); + b2Vec2 scaledPoint = Physics::scaleUp(point); + lua_pushnumber(L, scaledPoint.x); + lua_pushnumber(L, scaledPoint.y); + b2Vec2 scaledNormal = Physics::scaleUp(normal); + lua_pushnumber(L, scaledNormal.x); + lua_pushnumber(L, scaledNormal.y); + lua_pushnumber(L, fraction); + lua_call(L, 6, 1); + return (float32)luaL_checknumber(L, -1); + } + return 0; + } World::World() : world(NULL) @@ -339,6 +372,21 @@ namespace box2d world->QueryAABB(&query, box); return 0; } + + int World::rayCast(lua_State * L) + { + luax_assert_argc(L, 5); + float x1 = (float)luaL_checknumber(L, 1); + float y1 = (float)luaL_checknumber(L, 2); + float x2 = (float)luaL_checknumber(L, 3); + float y2 = (float)luaL_checknumber(L, 4); + b2Vec2 v1 = Physics::scaleDown(b2Vec2(x1, y1)); + b2Vec2 v2 = Physics::scaleDown(b2Vec2(x2, y2)); + if (raycast.ref) delete raycast.ref; + raycast.ref = luax_refif(L, LUA_TFUNCTION); + world->RayCast(&raycast, v1, v2); + return 0; + } } // box2d } // physics diff --git a/src/modules/physics/box2d/World.h b/src/modules/physics/box2d/World.h index f2508a6c5..76d84fd98 100644 --- a/src/modules/physics/box2d/World.h +++ b/src/modules/physics/box2d/World.h @@ -95,6 +95,15 @@ namespace box2d ~QueryCallback(); virtual bool ReportFixture(b2Fixture * fixture); }; + + class RayCastCallback : public b2RayCastCallback + { + public: + Reference * ref; + RayCastCallback(); + ~RayCastCallback(); + virtual float32 ReportFixture(b2Fixture * fixture, const b2Vec2& point, const b2Vec2& normal, float32 fraction); + }; private: @@ -108,6 +117,7 @@ namespace box2d ContactCallback begin, end, presolve, postsolve; ContactFilter filter; QueryCallback query; + RayCastCallback raycast; public: @@ -215,6 +225,11 @@ namespace box2d * Gets all fixtures that overlap a given bounding box. **/ int queryBoundingBox(lua_State * L); + + /** + * Raycasts the World for all Fixtures in the path of the ray. + **/ + int rayCast(lua_State * L); }; diff --git a/src/modules/physics/box2d/wrap_World.cpp b/src/modules/physics/box2d/wrap_World.cpp index 39b846e15..9fe819f3f 100644 --- a/src/modules/physics/box2d/wrap_World.cpp +++ b/src/modules/physics/box2d/wrap_World.cpp @@ -119,6 +119,13 @@ namespace box2d lua_remove(L, 1); return t->queryBoundingBox(L); } + + int w_World_rayCast(lua_State * L) + { + World * t = luax_checkworld(L, 1); + lua_remove(L, 1); + return t->rayCast(L); + } static const luaL_Reg functions[] = { { "update", w_World_update }, @@ -133,6 +140,7 @@ namespace box2d { "getBodyCount", w_World_getBodyCount }, { "getJointCount", w_World_getJointCount }, { "queryBoundingBox", w_World_queryBoundingBox }, + { "rayCast", w_World_rayCast }, { 0, 0 } }; diff --git a/src/modules/physics/box2d/wrap_World.h b/src/modules/physics/box2d/wrap_World.h index 4c2192842..3fddb8ec6 100644 --- a/src/modules/physics/box2d/wrap_World.h +++ b/src/modules/physics/box2d/wrap_World.h @@ -44,6 +44,7 @@ namespace box2d int w_World_getBodyCount(lua_State * L); int w_World_getJointCount(lua_State * L); int w_World_queryBoundingBox(lua_State * L); + int w_World_rayCast(lua_State * L); int luaopen_world(lua_State * L); } // box2d