diff --git a/CMakeLists.txt b/CMakeLists.txt index 644f71410..550d20fef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -837,8 +837,6 @@ set(LOVE_SRC_MODULE_PHYSICS_BOX2D src/modules/physics/box2d/DistanceJoint.h src/modules/physics/box2d/EdgeShape.cpp src/modules/physics/box2d/EdgeShape.h - src/modules/physics/box2d/Fixture.cpp - src/modules/physics/box2d/Fixture.h src/modules/physics/box2d/FrictionJoint.cpp src/modules/physics/box2d/FrictionJoint.h src/modules/physics/box2d/GearJoint.cpp @@ -881,8 +879,6 @@ set(LOVE_SRC_MODULE_PHYSICS_BOX2D src/modules/physics/box2d/wrap_DistanceJoint.h src/modules/physics/box2d/wrap_EdgeShape.cpp src/modules/physics/box2d/wrap_EdgeShape.h - src/modules/physics/box2d/wrap_Fixture.cpp - src/modules/physics/box2d/wrap_Fixture.h src/modules/physics/box2d/wrap_FrictionJoint.cpp src/modules/physics/box2d/wrap_FrictionJoint.h src/modules/physics/box2d/wrap_GearJoint.cpp diff --git a/src/common/deprecation.cpp b/src/common/deprecation.cpp index f0b0cae72..84f1b264f 100644 --- a/src/common/deprecation.cpp +++ b/src/common/deprecation.cpp @@ -107,8 +107,12 @@ std::string getDeprecationNotice(const DeprecationInfo &info, bool usewhere) if (info.apiType == API_FUNCTION) notice << "function "; + else if (info.apiType == API_FUNCTION_VARIANT) + notice << "function variant in "; else if (info.apiType == API_METHOD) notice << "method "; + else if (info.apiType == API_METHOD_VARIANT) + notice << "method variant in "; else if (info.apiType == API_CALLBACK) notice << "callback "; else if (info.apiType == API_FIELD) @@ -188,7 +192,9 @@ MarkDeprecated::~MarkDeprecated() STRINGMAP_BEGIN(APIType, API_MAX_ENUM, apiType) { { "function", API_FUNCTION }, + { "functionvariant", API_FUNCTION_VARIANT }, { "method", API_METHOD }, + { "methodvariant", API_METHOD_VARIANT }, { "callback", API_CALLBACK }, { "field", API_FIELD }, { "constant", API_CONSTANT }, diff --git a/src/common/deprecation.h b/src/common/deprecation.h index 7ac407cb3..55b0e89e2 100644 --- a/src/common/deprecation.h +++ b/src/common/deprecation.h @@ -32,7 +32,9 @@ namespace love enum APIType { API_FUNCTION, + API_FUNCTION_VARIANT, API_METHOD, + API_METHOD_VARIANT, API_CALLBACK, API_FIELD, API_CONSTANT, diff --git a/src/modules/physics/box2d/Body.cpp b/src/modules/physics/box2d/Body.cpp index 2c8acfd64..a3e7ee110 100644 --- a/src/modules/physics/box2d/Body.cpp +++ b/src/modules/physics/box2d/Body.cpp @@ -23,12 +23,12 @@ #include "common/math.h" #include "Shape.h" -#include "Fixture.h" #include "World.h" #include "Physics.h" // Needed for luax_pushjoint. #include "wrap_Joint.h" +#include "wrap_Shape.h" namespace love { @@ -461,20 +461,20 @@ World *Body::getWorld() const return world; } -Fixture *Body::getFixture() const +Shape *Body::getShape() const { b2Fixture *f = body->GetFixtureList(); if (f == nullptr) return nullptr; - Fixture *fixture = (Fixture *)(f->GetUserData().pointer); - if (!fixture) - throw love::Exception("A fixture has escaped Memoizer!"); + Shape *shape = (Shape *)(f->GetUserData().pointer); + if (!shape) + throw love::Exception("A Shape has escaped Memoizer!"); - return fixture; + return shape; } -int Body::getFixtures(lua_State *L) const +int Body::getShapes(lua_State *L) const { lua_newtable(L); b2Fixture *f = body->GetFixtureList(); @@ -483,10 +483,10 @@ int Body::getFixtures(lua_State *L) const { if (!f) break; - Fixture *fixture = (Fixture *)(f->GetUserData().pointer); - if (!fixture) - throw love::Exception("A fixture has escaped Memoizer!"); - luax_pushtype(L, fixture); + Shape *shape = (Shape *)(f->GetUserData().pointer); + if (!shape) + throw love::Exception("A Shape has escaped Memoizer!"); + luax_pushshape(L, shape); lua_rawseti(L, -2, i); i++; } diff --git a/src/modules/physics/box2d/Body.h b/src/modules/physics/box2d/Body.h index 0be88c6c7..1d0b2d770 100644 --- a/src/modules/physics/box2d/Body.h +++ b/src/modules/physics/box2d/Body.h @@ -39,7 +39,6 @@ namespace box2d // Forward declarations. class World; class Shape; -class Fixture; /** * A Body is an entity which has position and orientation @@ -57,7 +56,6 @@ public: friend class CircleShape; friend class PolygonShape; friend class Shape; - friend class Fixture; // Public because joints et al ask for b2body b2Body *body; @@ -391,15 +389,14 @@ public: World *getWorld() const; /** - * Gets the first Fixture attached to this Body. + * Gets the first Shape attached to this Body. **/ - Fixture *getFixture() const; + Shape *getShape() const; /** - * Get an array of all the Fixtures attached to this Body. - * @return An array of Fixtures. + * Get an array of all the Shapes attached to this Body. **/ - int getFixtures(lua_State *L) const; + int getShapes(lua_State *L) const; /** * Get an array of all Joints attached to this Body. diff --git a/src/modules/physics/box2d/ChainShape.cpp b/src/modules/physics/box2d/ChainShape.cpp index 9bfef155c..7a2390ab0 100644 --- a/src/modules/physics/box2d/ChainShape.cpp +++ b/src/modules/physics/box2d/ChainShape.cpp @@ -34,8 +34,8 @@ namespace box2d love::Type ChainShape::type("ChainShape", &Shape::type); -ChainShape::ChainShape(b2ChainShape *c, bool own) - : Shape(c, own) +ChainShape::ChainShape(Body *body, const b2ChainShape &c) + : Shape(body, c) { } @@ -45,6 +45,7 @@ ChainShape::~ChainShape() void ChainShape::setNextVertex(float x, float y) { + throwIfShapeNotValid(); b2Vec2 v(x, y); b2ChainShape *c = (b2ChainShape *)shape; c->m_nextVertex = Physics::scaleDown(v); @@ -52,6 +53,7 @@ void ChainShape::setNextVertex(float x, float y) void ChainShape::setPreviousVertex(float x, float y) { + throwIfShapeNotValid(); b2Vec2 v(x, y); b2ChainShape *c = (b2ChainShape *)shape; c->m_prevVertex = Physics::scaleDown(v); @@ -59,44 +61,40 @@ void ChainShape::setPreviousVertex(float x, float y) b2Vec2 ChainShape::getNextVertex() const { + throwIfShapeNotValid(); b2ChainShape *c = (b2ChainShape *)shape; - return Physics::scaleUp(c->m_nextVertex); } b2Vec2 ChainShape::getPreviousVertex() const { + throwIfShapeNotValid(); b2ChainShape *c = (b2ChainShape *)shape; - return Physics::scaleUp(c->m_prevVertex); } EdgeShape *ChainShape::getChildEdge(int index) const { + throwIfShapeNotValid(); + b2ChainShape *c = (b2ChainShape *)shape; - b2EdgeShape *e = new b2EdgeShape; - try - { - c->GetChildEdge(e, index); - } - catch (love::Exception &) - { - delete e; - throw; - } + b2EdgeShape e; + c->GetChildEdge(&e, index); - return new EdgeShape(e, true); + return new EdgeShape(nullptr, e); } int ChainShape::getVertexCount() const { + throwIfShapeNotValid(); b2ChainShape *c = (b2ChainShape *)shape; return c->m_count; } b2Vec2 ChainShape::getPoint(int index) const { + throwIfShapeNotValid(); b2ChainShape *c = (b2ChainShape *)shape; if (index < 0 || index >= c->m_count) throw love::Exception("Physics error: index out of bounds"); @@ -106,6 +104,7 @@ b2Vec2 ChainShape::getPoint(int index) const const b2Vec2 *ChainShape::getPoints() const { + throwIfShapeNotValid(); b2ChainShape *c = (b2ChainShape *)shape; return c->m_vertices; } diff --git a/src/modules/physics/box2d/ChainShape.h b/src/modules/physics/box2d/ChainShape.h index 07f89f440..2b2ee14e1 100644 --- a/src/modules/physics/box2d/ChainShape.h +++ b/src/modules/physics/box2d/ChainShape.h @@ -45,7 +45,7 @@ public: * Create a new ChainShape from a Box2D chain shape. * @param c The chain shape. **/ - ChainShape(b2ChainShape *c, bool own = true); + ChainShape(Body *body, const b2ChainShape &c); virtual ~ChainShape(); diff --git a/src/modules/physics/box2d/CircleShape.cpp b/src/modules/physics/box2d/CircleShape.cpp index 545620f81..628b96bb0 100644 --- a/src/modules/physics/box2d/CircleShape.cpp +++ b/src/modules/physics/box2d/CircleShape.cpp @@ -34,8 +34,8 @@ namespace box2d love::Type CircleShape::type("CircleShape", &Shape::type); -CircleShape::CircleShape(b2CircleShape *c, bool own) - : Shape(c, own) +CircleShape::CircleShape(Body *body, const b2CircleShape &c) + : Shape(body, c) { } @@ -45,16 +45,19 @@ CircleShape::~CircleShape() float CircleShape::getRadius() const { + throwIfShapeNotValid(); return Physics::scaleUp(shape->m_radius); } void CircleShape::setRadius(float r) { + throwIfShapeNotValid(); shape->m_radius = Physics::scaleDown(r); } void CircleShape::getPoint(float &x_o, float &y_o) const { + throwIfShapeNotValid(); b2CircleShape *c = (b2CircleShape *) shape; x_o = Physics::scaleUp(c->m_p.x); y_o = Physics::scaleUp(c->m_p.y); @@ -62,6 +65,7 @@ void CircleShape::getPoint(float &x_o, float &y_o) const void CircleShape::setPoint(float x, float y) { + throwIfShapeNotValid(); b2CircleShape *c = (b2CircleShape *) shape; c->m_p = Physics::scaleDown(b2Vec2(x, y)); } diff --git a/src/modules/physics/box2d/CircleShape.h b/src/modules/physics/box2d/CircleShape.h index 438034bb8..20e5e3bac 100644 --- a/src/modules/physics/box2d/CircleShape.h +++ b/src/modules/physics/box2d/CircleShape.h @@ -50,7 +50,7 @@ public: * Create a new CircleShape from the a Box2D CircleShape definition. * @param c The CircleShape definition. **/ - CircleShape(b2CircleShape *c, bool own = true); + CircleShape(Body *body, const b2CircleShape &c); virtual ~CircleShape(); diff --git a/src/modules/physics/box2d/Contact.cpp b/src/modules/physics/box2d/Contact.cpp index 46e2b2a89..63b51ef04 100644 --- a/src/modules/physics/box2d/Contact.cpp +++ b/src/modules/physics/box2d/Contact.cpp @@ -35,7 +35,6 @@ Contact::Contact(World *world, b2Contact *contact) : contact(contact) , world(world) { - //contact->user world->registerObject(contact, this); } @@ -46,16 +45,16 @@ Contact::~Contact() void Contact::invalidate() { - if (contact != NULL) + if (contact != nullptr) { world->unregisterObject(contact); - contact = NULL; + contact = nullptr; } } bool Contact::isValid() { - return contact != NULL; + return contact != nullptr; } int Contact::getPositions(lua_State *L) @@ -144,13 +143,13 @@ void Contact::getChildren(int &childA, int &childB) childB = contact->GetChildIndexB(); } -void Contact::getFixtures(Fixture *&fixtureA, Fixture *&fixtureB) +void Contact::getShapes(Shape *&shapeA, Shape *&shapeB) { - fixtureA = (Fixture *) (contact->GetFixtureA()->GetUserData().pointer); - fixtureB = (Fixture *) (contact->GetFixtureB()->GetUserData().pointer); + shapeA = (Shape *) (contact->GetFixtureA()->GetUserData().pointer); + shapeB = (Shape *) (contact->GetFixtureB()->GetUserData().pointer); - if (!fixtureA || !fixtureB) - throw love::Exception("A fixture has escaped Memoizer!"); + if (!shapeA || !shapeB) + throw love::Exception("A Shape has escaped Memoizer!"); } } // box2d diff --git a/src/modules/physics/box2d/Contact.h b/src/modules/physics/box2d/Contact.h index afbe587d6..1287ca285 100644 --- a/src/modules/physics/box2d/Contact.h +++ b/src/modules/physics/box2d/Contact.h @@ -151,9 +151,9 @@ public: void getChildren(int &childA, int &childB); /** - * Gets the Fixtures associated with this Contact. + * Gets the Shapes associated with this Contact. **/ - void getFixtures(Fixture *&fixtureA, Fixture *&fixtureB); + void getShapes(Shape *&shapeA, Shape *&shapeB); private: diff --git a/src/modules/physics/box2d/EdgeShape.cpp b/src/modules/physics/box2d/EdgeShape.cpp index e4f3c146f..f49925783 100644 --- a/src/modules/physics/box2d/EdgeShape.cpp +++ b/src/modules/physics/box2d/EdgeShape.cpp @@ -34,8 +34,8 @@ namespace box2d love::Type EdgeShape::type("EdgeShape", &Shape::type); -EdgeShape::EdgeShape(b2EdgeShape *e, bool own) - : Shape(e, own) +EdgeShape::EdgeShape(Body *body, const b2EdgeShape &e) + : Shape(body, e) { } @@ -45,6 +45,7 @@ EdgeShape::~EdgeShape() void EdgeShape::setNextVertex(float x, float y) { + throwIfShapeNotValid(); b2EdgeShape *e = (b2EdgeShape *)shape; b2Vec2 v(x, y); e->m_vertex3 = Physics::scaleDown(v); @@ -52,13 +53,14 @@ void EdgeShape::setNextVertex(float x, float y) b2Vec2 EdgeShape::getNextVertex() const { + throwIfShapeNotValid(); b2EdgeShape *e = (b2EdgeShape *)shape; - return Physics::scaleUp(e->m_vertex3); } void EdgeShape::setPreviousVertex(float x, float y) { + throwIfShapeNotValid(); b2EdgeShape *e = (b2EdgeShape *)shape; b2Vec2 v(x, y); e->m_vertex0 = Physics::scaleDown(v); @@ -66,13 +68,14 @@ void EdgeShape::setPreviousVertex(float x, float y) b2Vec2 EdgeShape::getPreviousVertex() const { + throwIfShapeNotValid(); b2EdgeShape *e = (b2EdgeShape *)shape; - return Physics::scaleUp(e->m_vertex0); } int EdgeShape::getPoints(lua_State *L) { + throwIfShapeNotValid(); b2EdgeShape *e = (b2EdgeShape *)shape; b2Vec2 v1 = Physics::scaleUp(e->m_vertex1); b2Vec2 v2 = Physics::scaleUp(e->m_vertex2); diff --git a/src/modules/physics/box2d/EdgeShape.h b/src/modules/physics/box2d/EdgeShape.h index 4db2383ce..9445e5b62 100644 --- a/src/modules/physics/box2d/EdgeShape.h +++ b/src/modules/physics/box2d/EdgeShape.h @@ -45,7 +45,7 @@ public: * Create a new EdgeShape from a Box2D edge shape. * @param e The edge shape. **/ - EdgeShape(b2EdgeShape *e, bool own = true); + EdgeShape(Body *body, const b2EdgeShape &e); virtual ~EdgeShape(); diff --git a/src/modules/physics/box2d/Fixture.cpp b/src/modules/physics/box2d/Fixture.cpp deleted file mode 100644 index 12fc9b2d7..000000000 --- a/src/modules/physics/box2d/Fixture.cpp +++ /dev/null @@ -1,349 +0,0 @@ -/** - * Copyright (c) 2006-2023 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -#include "Fixture.h" - -// Module -#include "Body.h" -#include "World.h" -#include "Physics.h" - -// STD -#include - -namespace love -{ -namespace physics -{ -namespace box2d -{ - -love::Type Fixture::type("Fixture", &Object::type); - -Fixture::Fixture(Body *body, Shape *shape, float density) - : body(body) - , fixture(nullptr) -{ - b2FixtureDef def; - def.shape = shape->shape; - def.userData.pointer = (uintptr_t)this; - def.density = density; - fixture = body->body->CreateFixture(&def); - this->retain(); -} - -Fixture::~Fixture() -{ - if (ref) - delete ref; -} - -void Fixture::checkCreateShape() -{ - if (shape.get() != nullptr || fixture == nullptr || fixture->GetShape() == nullptr) - return; - - b2Shape *bshape = fixture->GetShape(); - - switch (bshape->GetType()) - { - case b2Shape::e_circle: - shape.set(new CircleShape((b2CircleShape *) bshape, false), Acquire::NORETAIN); - break; - case b2Shape::e_edge: - shape.set(new EdgeShape((b2EdgeShape *) bshape, false), Acquire::NORETAIN); - break; - case b2Shape::e_polygon: - shape.set(new PolygonShape((b2PolygonShape *) bshape, false), Acquire::NORETAIN); - break; - case b2Shape::e_chain: - shape.set(new ChainShape((b2ChainShape *) bshape, false), Acquire::NORETAIN); - break; - default: - break; - } -} - -Shape::Type Fixture::getType() -{ - checkCreateShape(); - if (shape.get() == nullptr) - return Shape::SHAPE_INVALID; - else - return shape->getType(); -} - -void Fixture::setFriction(float friction) -{ - fixture->SetFriction(friction); -} - -void Fixture::setRestitution(float restitution) -{ - fixture->SetRestitution(restitution); -} - -void Fixture::setDensity(float density) -{ - fixture->SetDensity(density); -} - -void Fixture::setSensor(bool sensor) -{ - fixture->SetSensor(sensor); -} - -float Fixture::getFriction() const -{ - return fixture->GetFriction(); -} - -float Fixture::getRestitution() const -{ - return fixture->GetRestitution(); -} - -float Fixture::getDensity() const -{ - return fixture->GetDensity(); -} - -bool Fixture::isSensor() const -{ - return fixture->IsSensor(); -} - -Body *Fixture::getBody() const -{ - return body; -} - -Shape *Fixture::getShape() -{ - checkCreateShape(); - return shape; -} - -bool Fixture::isValid() const -{ - return fixture != nullptr; -} - -void Fixture::setFilterData(int *v) -{ - b2Filter f; - f.categoryBits = (uint16) v[0]; - f.maskBits = (uint16) v[1]; - f.groupIndex = (int16) v[2]; - fixture->SetFilterData(f); -} - -void Fixture::getFilterData(int *v) -{ - b2Filter f = fixture->GetFilterData(); - v[0] = (int) f.categoryBits; - v[1] = (int) f.maskBits; - v[2] = (int) f.groupIndex; -} - -int Fixture::setCategory(lua_State *L) -{ - b2Filter f = fixture->GetFilterData(); - f.categoryBits = (uint16)getBits(L); - fixture->SetFilterData(f); - return 0; -} - -int Fixture::setMask(lua_State *L) -{ - b2Filter f = fixture->GetFilterData(); - f.maskBits = ~(uint16)getBits(L); - fixture->SetFilterData(f); - return 0; -} - -void Fixture::setGroupIndex(int index) -{ - b2Filter f = fixture->GetFilterData(); - f.groupIndex = (uint16)index; - fixture->SetFilterData(f); -} - -int Fixture::getGroupIndex() const -{ - b2Filter f = fixture->GetFilterData(); - return f.groupIndex; -} - -int Fixture::getCategory(lua_State *L) -{ - return pushBits(L, fixture->GetFilterData().categoryBits); -} - -int Fixture::getMask(lua_State *L) -{ - return pushBits(L, ~(fixture->GetFilterData().maskBits)); -} - -uint16 Fixture::getBits(lua_State *L) -{ - // Get number of args. - bool istable = lua_istable(L, 1); - int argc = istable ? (int) luax_objlen(L, 1) : lua_gettop(L); - - // The new bitset. - std::bitset<16> b; - - for (int i = 1; i <= argc; i++) - { - size_t bpos = 0; - - if (istable) - { - lua_rawgeti(L, 1, i); - bpos = (size_t) (lua_tointeger(L, -1) - 1); - lua_pop(L, 1); - } - else - bpos = (size_t) (lua_tointeger(L, i) - 1); - - if (bpos >= 16) - luaL_error(L, "Values must be in range 1-16."); - - b.set(bpos, true); - } - - return (uint16)b.to_ulong(); -} - -int Fixture::pushBits(lua_State *L, uint16 bits) -{ - // Create a bitset. - std::bitset<16> b((int)bits); - - // Push all set bits. - for (int i = 0; i<16; i++) - if (b.test(i)) - lua_pushinteger(L, i+1); - - // Count number of set bits. - return (int)b.count(); -} - -int Fixture::setUserData(lua_State *L) -{ - love::luax_assert_argc(L, 1, 1); - - if(!ref) - ref = new Reference(); - - ref->ref(L); - - return 0; -} - -int Fixture::getUserData(lua_State *L) -{ - if (ref != nullptr) - ref->push(L); - else - lua_pushnil(L); - - return 1; -} - -bool Fixture::testPoint(float x, float y) const -{ - return fixture->TestPoint(Physics::scaleDown(b2Vec2(x, y))); -} - -int Fixture::rayCast(lua_State *L) const -{ - float p1x = Physics::scaleDown((float)luaL_checknumber(L, 1)); - float p1y = Physics::scaleDown((float)luaL_checknumber(L, 2)); - float p2x = Physics::scaleDown((float)luaL_checknumber(L, 3)); - float p2y = Physics::scaleDown((float)luaL_checknumber(L, 4)); - float maxFraction = (float)luaL_checknumber(L, 5); - int childIndex = (int) luaL_optinteger(L, 6, 1) - 1; // Convert from 1-based index - b2RayCastInput input; - input.p1.Set(p1x, p1y); - input.p2.Set(p2x, p2y); - input.maxFraction = maxFraction; - b2RayCastOutput output; - if (!fixture->RayCast(&output, input, childIndex)) - return 0; // Nothing hit. - lua_pushnumber(L, output.normal.x); - lua_pushnumber(L, output.normal.y); - lua_pushnumber(L, output.fraction); - return 3; -} - -int Fixture::getBoundingBox(lua_State *L) const -{ - int childIndex = (int) luaL_optinteger(L, 1, 1) - 1; // Convert from 1-based index - b2AABB box; - luax_catchexcept(L, [&]() { box = fixture->GetAABB(childIndex); }); - box = Physics::scaleUp(box); - lua_pushnumber(L, box.lowerBound.x); - lua_pushnumber(L, box.lowerBound.y); - lua_pushnumber(L, box.upperBound.x); - lua_pushnumber(L, box.upperBound.y); - return 4; -} - -int Fixture::getMassData(lua_State *L) const -{ - b2MassData data; - fixture->GetMassData(&data); - b2Vec2 center = Physics::scaleUp(data.center); - lua_pushnumber(L, center.x); - lua_pushnumber(L, center.y); - lua_pushnumber(L, data.mass); - lua_pushnumber(L, data.I); - return 4; -} - -void Fixture::destroy(bool implicit) -{ - if (body->world->world->IsLocked()) - { - // Called during time step. Save reference for destruction afterwards. - this->retain(); - body->world->destructFixtures.push_back(this); - return; - } - - shape.set(nullptr); - - if (!implicit && fixture != nullptr) - body->body->DestroyFixture(fixture); - fixture = nullptr; - - // Remove userdata reference to avoid it sticking around after GC - if (ref) - ref->unref(); - - // Box2D fixture destroyed. Release its reference to the love Fixture. - this->release(); -} - -} // box2d -} // physics -} // love diff --git a/src/modules/physics/box2d/Fixture.h b/src/modules/physics/box2d/Fixture.h deleted file mode 100644 index 4f0d54e99..000000000 --- a/src/modules/physics/box2d/Fixture.h +++ /dev/null @@ -1,216 +0,0 @@ -/** - * Copyright (c) 2006-2023 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -#ifndef LOVE_PHYSICS_BOX2D_FIXTURE_H -#define LOVE_PHYSICS_BOX2D_FIXTURE_H - -// LOVE -#include "physics/Shape.h" -#include "physics/box2d/Body.h" -#include "physics/box2d/Shape.h" -#include "common/Object.h" -#include "common/Reference.h" - -// Box2D -#include - -namespace love -{ -namespace physics -{ -namespace box2d -{ - -class World; - -/** - * A Fixture is used to attach a shape to a body for collision detection. - * A Fixture inherits its transform from its parent. Fixtures hold - * additional non-geometric data such as friction, collision filters, - * etc. - **/ -class Fixture : public Object -{ -public: - friend class Physics; - - static love::Type type; - - /** - * Creates a Fixture. - **/ - Fixture(Body *body, Shape *shape, float density); - - virtual ~Fixture(); - - /** - * Gets the type of the Fixture's Shape. Useful for - * debug drawing. - **/ - Shape::Type getType(); - - /** - * Gets the Shape attached to this Fixture. - **/ - Shape *getShape(); - - /** - * Returns true if the fixture is active in a Box2D world. - **/ - bool isValid() const; - - /** - * Checks whether this Fixture acts as a sensor. - * @return True if sensor, false otherwise. - **/ - bool isSensor() const; - - /** - * Set whether this Fixture should be a sensor or not. - * @param sensor True if sensor, false if not. - **/ - void setSensor(bool sensor); - - /** - * Gets the Body this Fixture is attached to. - **/ - Body *getBody() const; - - /** - * Sets the filter data. An integer array is used even though the - * first two elements are unsigned shorts. The elements are: - * category (16-bits), mask (16-bits) and group (32-bits/int). - **/ - void setFilterData(int *v); - - /** - * Gets the filter data. An integer array is used even though the - * first two elements are unsigned shorts. The elements are: - * category (16-bits), mask (16-bits) and group (32-bits/int). - **/ - void getFilterData(int *v); - - /** - * This function stores an in-C reference to - * arbitrary Lua data in the Box2D Fixture object. - **/ - int setUserData(lua_State *L); - - /** - * Gets the data set with setData. If no - * data is set, nil is returned. - **/ - int getUserData(lua_State *L); - - /** - * Sets the friction of the Fixture. - * @param friction The new friction. - **/ - void setFriction(float friction); - - /** - * Sets the restitution for the Fixture. - * @param restitution The restitution. - **/ - void setRestitution(float restitution); - - /** - * Sets the density of the Fixture. - * @param density The density of the Fixture. - **/ - void setDensity(float density); - - /** - * Gets the friction of the Fixture. - * @returns The friction. - **/ - float getFriction() const; - - /** - * Gets the restitution of the Fixture. - * @return The restitution of the Fixture. - **/ - float getRestitution() const; - - /** - * Gets the density of the Fixture. - * @return The density. - **/ - float getDensity() const; - - /** - * Checks if a point is inside the Fixture. - * @param x The x-component of the point. - * @param y The y-component of the point. - **/ - bool testPoint(float x, float y) const; - - /** - * Cast a ray against this Fixture. - **/ - int rayCast(lua_State *L) const; - - void setGroupIndex(int index); - int getGroupIndex() const; - - int setCategory(lua_State *L); - int setMask(lua_State *L); - int getCategory(lua_State *L); - int getMask(lua_State *L); - uint16 getBits(lua_State *L); - int pushBits(lua_State *L, uint16 bits); - - /** - * Gets the bounding box for this Fixture. - * The function returns eight values which can be - * passed directly to love.graphics.polygon. - **/ - int getBoundingBox(lua_State *L) const; - - /** - * Gets the mass data for this Fixture. - * This operation may be expensive. - **/ - int getMassData(lua_State *L) const; - - /** - * Destroys this fixture. - **/ - void destroy(bool implicit = false); - -protected: - - void checkCreateShape(); - - Body *body; - b2Fixture *fixture; - - // Reference to arbitrary data. - Reference* ref = nullptr; - - StrongRef shape; - -}; - -} // box2d -} // physics -} // love - -#endif // LOVE_PHYSICS_BOX2D_FIXTURE_H diff --git a/src/modules/physics/box2d/Physics.cpp b/src/modules/physics/box2d/Physics.cpp index 5c3a134f9..6fb860b18 100644 --- a/src/modules/physics/box2d/Physics.cpp +++ b/src/modules/physics/box2d/Physics.cpp @@ -35,6 +35,7 @@ namespace box2d float Physics::meter = Physics::DEFAULT_METER; Physics::Physics() + : blockAllocator() { meter = DEFAULT_METER; } @@ -66,8 +67,7 @@ Body *Physics::newBody(World *world, Body::Type type) Body *Physics::newCircleBody(World *world, Body::Type type, float x, float y, float radius) { StrongRef body(newBody(world, x, y, type), Acquire::NORETAIN); - StrongRef shape(newCircleShape(0, 0, radius), Acquire::NORETAIN); - StrongRef fixture(newFixture(body, shape, 1.0f), Acquire::NORETAIN); + StrongRef shape(newCircleShape(body, 0, 0, radius), Acquire::NORETAIN); body->retain(); return body.get(); } @@ -75,8 +75,7 @@ Body *Physics::newCircleBody(World *world, Body::Type type, float x, float y, fl Body *Physics::newRectangleBody(World *world, Body::Type type, float x, float y, float w, float h, float angle) { StrongRef body(newBody(world, x, y, type), Acquire::NORETAIN); - StrongRef shape(newRectangleShape(0, 0, w, h, angle), Acquire::NORETAIN); - StrongRef fixture(newFixture(body, shape, 1.0f), Acquire::NORETAIN); + StrongRef shape(newRectangleShape(body, 0, 0, w, h, angle), Acquire::NORETAIN); body->retain(); return body.get(); } @@ -93,8 +92,7 @@ Body *Physics::newPolygonBody(World *world, Body::Type type, const Vector2 *coor localcoords.push_back(coords[i] - origin); StrongRef body(newBody(world, origin.x, origin.y, type), Acquire::NORETAIN); - StrongRef shape(newPolygonShape(localcoords.data(), count), Acquire::NORETAIN); - StrongRef fixture(newFixture(body, shape, 1.0f), Acquire::NORETAIN); + StrongRef shape(newPolygonShape(body, localcoords.data(), count), Acquire::NORETAIN); body->retain(); return body.get(); } @@ -104,8 +102,7 @@ Body *Physics::newEdgeBody(World *world, Body::Type type, float x1, float y1, fl float wx = (x2 - x1) / 2.0f; float wy = (y2 - y1) / 2.0f; StrongRef body(newBody(world, wx, wy, type), Acquire::NORETAIN); - StrongRef shape(newEdgeShape(x1 - wx, y1 - wy, x2 - wx, y2 - wy, oneSided), Acquire::NORETAIN); - StrongRef fixture(newFixture(body, shape, 1.0f), Acquire::NORETAIN); + StrongRef shape(newEdgeShape(body, x1 - wx, y1 - wy, x2 - wx, y2 - wy, oneSided), Acquire::NORETAIN); body->retain(); return body.get(); } @@ -122,44 +119,75 @@ Body *Physics::newChainBody(World *world, Body::Type type, bool loop, const Vect localcoords.push_back(coords[i] - origin); StrongRef body(newBody(world, origin.x, origin.y, type), Acquire::NORETAIN); - StrongRef shape(newChainShape(loop, localcoords.data(), count), Acquire::NORETAIN); - StrongRef fixture(newFixture(body, shape, 1.0f), Acquire::NORETAIN); + StrongRef shape(newChainShape(body, loop, localcoords.data(), count), Acquire::NORETAIN); body->retain(); return body.get(); } -CircleShape *Physics::newCircleShape(float x, float y, float radius) +Shape *Physics::newAttachedShape(Body *body, Shape *prototype, float density) { - b2CircleShape *s = new b2CircleShape(); - s->m_p = Physics::scaleDown(b2Vec2(x, y)); - s->m_radius = Physics::scaleDown(radius); - return new CircleShape(s); + if (prototype->isValid()) + throw love::Exception("The given Shape must not be part of the World."); + + Shape *shape = nullptr; + + switch (prototype->getType()) + { + case Shape::SHAPE_CIRCLE: + shape = new CircleShape(body, *(b2CircleShape *) prototype->shape); + break; + case Shape::SHAPE_POLYGON: + shape = new PolygonShape(body, *(b2PolygonShape *) prototype->shape); + break; + case Shape::SHAPE_EDGE: + shape = new EdgeShape(body, *(b2EdgeShape *) prototype->shape); + break; + case Shape::SHAPE_CHAIN: + shape = new ChainShape(body, *(b2ChainShape *) prototype->shape); + break; + default: + throw love::Exception("Unknown shape type."); + break; + } + + shape->setDensity(density); + body->resetMassData(); + + return shape; } -PolygonShape *Physics::newRectangleShape(float x, float y, float w, float h, float angle) +CircleShape *Physics::newCircleShape(Body *body, float x, float y, float radius) { - b2PolygonShape *s = new b2PolygonShape(); - s->SetAsBox(Physics::scaleDown(w/2.0f), Physics::scaleDown(h/2.0f), Physics::scaleDown(b2Vec2(x, y)), angle); - return new PolygonShape(s); + b2CircleShape s; + s.m_p = Physics::scaleDown(b2Vec2(x, y)); + s.m_radius = Physics::scaleDown(radius); + return new CircleShape(body, s); } -EdgeShape *Physics::newEdgeShape(float x1, float y1, float x2, float y2, bool oneSided) +PolygonShape *Physics::newRectangleShape(Body *body, float x, float y, float w, float h, float angle) { - b2EdgeShape *s = new b2EdgeShape(); + b2PolygonShape s; + s.SetAsBox(Physics::scaleDown(w/2.0f), Physics::scaleDown(h/2.0f), Physics::scaleDown(b2Vec2(x, y)), angle); + return new PolygonShape(body, s); +} + +EdgeShape *Physics::newEdgeShape(Body *body, float x1, float y1, float x2, float y2, bool oneSided) +{ + b2EdgeShape s; if (oneSided) { b2Vec2 v1 = Physics::scaleDown(b2Vec2(x1, y1)); b2Vec2 v2 = Physics::scaleDown(b2Vec2(x2, y2)); - s->SetOneSided(v1, v1, v2, v2); + s.SetOneSided(v1, v1, v2, v2); } else { - s->SetTwoSided(Physics::scaleDown(b2Vec2(x1, y1)), Physics::scaleDown(b2Vec2(x2, y2))); + s.SetTwoSided(Physics::scaleDown(b2Vec2(x1, y1)), Physics::scaleDown(b2Vec2(x2, y2))); } - return new EdgeShape(s); + return new EdgeShape(body, s); } -PolygonShape *Physics::newPolygonShape(const Vector2 *coords, int count) +PolygonShape *Physics::newPolygonShape(Body *body, const Vector2 *coords, int count) { // 3 to 8 (b2_maxPolygonVertices) vertices if (count < 3) @@ -172,44 +200,28 @@ PolygonShape *Physics::newPolygonShape(const Vector2 *coords, int count) for (int i = 0; i < count; i++) vecs[i] = Physics::scaleDown(b2Vec2(coords[i].x, coords[i].y)); - b2PolygonShape *s = new b2PolygonShape(); + b2PolygonShape s; - try - { - s->Set(vecs, count); - } - catch (love::Exception &) - { - delete s; - throw; - } + s.Set(vecs, count); - return new PolygonShape(s); + return new PolygonShape(body, s); } -ChainShape *Physics::newChainShape(bool loop, const Vector2 *coords, int count) +ChainShape *Physics::newChainShape(Body *body, bool loop, const Vector2 *coords, int count) { std::vector vecs; for (int i = 0; i < count; i++) vecs.push_back(Physics::scaleDown(b2Vec2(coords[i].x, coords[i].y))); - b2ChainShape *s = new b2ChainShape(); + b2ChainShape s; - try - { - if (loop) - s->CreateLoop(vecs.data(), count); - else - s->CreateChain(vecs.data(), count, vecs[0], vecs[count - 1]); - } - catch (love::Exception &) - { - delete s; - throw; - } + if (loop) + s.CreateLoop(vecs.data(), count); + else + s.CreateChain(vecs.data(), count, vecs[0], vecs[count - 1]); - return new ChainShape(s); + return new ChainShape(body, s); } DistanceJoint *Physics::newDistanceJoint(Body *body1, Body *body2, float x1, float y1, float x2, float y2, bool collideConnected) @@ -287,16 +299,10 @@ MotorJoint *Physics::newMotorJoint(Body *body1, Body *body2, float correctionFac return new MotorJoint(body1, body2, correctionFactor, collideConnected); } - -Fixture *Physics::newFixture(Body *body, Shape *shape, float density) -{ - return new Fixture(body, shape, density); -} - int Physics::getDistance(lua_State *L) { - Fixture *fixtureA = luax_checktype(L, 1); - Fixture *fixtureB = luax_checktype(L, 2); + Shape *shapeA = luax_checktype(L, 1); + Shape *shapeB = luax_checktype(L, 2); b2DistanceProxy pA, pB; b2DistanceInput i; b2DistanceOutput o; @@ -304,12 +310,15 @@ int Physics::getDistance(lua_State *L) c.count = 0; luax_catchexcept(L, [&]() { - pA.Set(fixtureA->fixture->GetShape(), 0); - pB.Set(fixtureB->fixture->GetShape(), 0); + if (!shapeA->isValid() || !shapeB->isValid()) + throw love::Exception("The given Shape is not active in the physics World."); + + pA.Set(shapeA->fixture->GetShape(), 0); + pB.Set(shapeB->fixture->GetShape(), 0); i.proxyA = pA; i.proxyB = pB; - i.transformA = fixtureA->fixture->GetBody()->GetTransform(); - i.transformB = fixtureB->fixture->GetBody()->GetTransform(); + i.transformA = shapeA->fixture->GetBody()->GetTransform(); + i.transformB = shapeB->fixture->GetBody()->GetTransform(); i.useRadii = true; b2Distance(&o, &c, &i); }); diff --git a/src/modules/physics/box2d/Physics.h b/src/modules/physics/box2d/Physics.h index 9c81ffe41..c198a7b78 100644 --- a/src/modules/physics/box2d/Physics.h +++ b/src/modules/physics/box2d/Physics.h @@ -28,7 +28,6 @@ #include "World.h" #include "Contact.h" #include "Body.h" -#include "Fixture.h" #include "Shape.h" #include "CircleShape.h" #include "PolygonShape.h" @@ -95,9 +94,9 @@ public: Body *newBody(World *world, Body::Type type); /** - * Convenience functions for creating a Body, Shape, and Fixture all in one - * call. The body's world position is the center/average of the given - * coordinates, and the shape is centered at the local origin. + * Convenience functions for creating a Body and Shape all in one call. The + * body's world position is the center/average of the given coordinates, + * and the shape is centered at the local origin. **/ Body *newCircleBody(World *world, Body::Type type, float x, float y, float radius); Body *newRectangleBody(World *world, Body::Type type, float x, float y, float w, float h, float angle); @@ -105,13 +104,16 @@ public: Body *newEdgeBody(World *world, Body::Type type, float x1, float y1, float x2, float y2, bool oneSided); Body *newChainBody(World *world, Body::Type type, bool loop, const Vector2 *coords, int count); + // Necessary to support the deprecated newFixture API. + Shape *newAttachedShape(Body *body, Shape *prototype, float density); + /** * Creates a new CircleShape at (x,y) in local coordinates. * @param x The offset along the x-axis. * @param y The offset along the y-axis. * @param radius The radius of the circle. **/ - CircleShape *newCircleShape(float x, float y, float radius); + CircleShape *newCircleShape(Body *body, float x, float y, float radius); /** * Shorthand for creating rectangular PolygonShapes. The rectangle @@ -122,7 +124,7 @@ public: * @param h The height of the rectangle. * @param angle The angle of the rectangle. (rad) **/ - PolygonShape *newRectangleShape(float x, float y, float w, float h, float angle); + PolygonShape *newRectangleShape(Body *body, float x, float y, float w, float h, float angle); /** * Creates a new EdgeShape. The edge will be created from @@ -132,18 +134,17 @@ public: * @param x2 The x coordinate of the second point. * @param y2 The y coordinate of the second point. **/ - EdgeShape *newEdgeShape(float x1, float y1, float x2, float y2, bool oneSided); + EdgeShape *newEdgeShape(Body *body, float x1, float y1, float x2, float y2, bool oneSided); /** * Creates a new PolygonShape from a variable number of vertices. **/ - //int newPolygonShape(lua_State *L); - PolygonShape *newPolygonShape(const Vector2 *coords, int count); + PolygonShape *newPolygonShape(Body *body, const Vector2 *coords, int count); /** * Creates a new ChainShape from a variable number of vertices. **/ - ChainShape *newChainShape(bool loop, const Vector2 *coords, int count); + ChainShape *newChainShape(Body *body, bool loop, const Vector2 *coords, int count); /** * Creates a new DistanceJoint connecting body1 with body2. @@ -263,15 +264,6 @@ public: MotorJoint *newMotorJoint(Body *body1, Body *body2); MotorJoint *newMotorJoint(Body *body1, Body *body2, float correctionFactor, bool collideConnected); - /** - * Creates a new Fixture attaching shape to body. - * @param body The body to attach the Fixture to. - * @param shape The shape to attach to the Fixture, - * @param density The density of the Fixture. - **/ - - Fixture *newFixture(Body *body, Shape *shape, float density); - /** * Calculates the distance between two Fixtures. * @param fixtureA The first Fixture. @@ -393,10 +385,15 @@ public: **/ static void computeAngularFrequency(float &frequency, float &ratio, float stiffness, float damping, b2Body *bodyA, b2Body *bodyB); + b2BlockAllocator *getBlockAllocator() { return &blockAllocator; } + private: // The length of one meter in pixels. static float meter; + + b2BlockAllocator blockAllocator; + }; // Physics } // box2d diff --git a/src/modules/physics/box2d/PolygonShape.cpp b/src/modules/physics/box2d/PolygonShape.cpp index 4655c8cc4..12b314f02 100644 --- a/src/modules/physics/box2d/PolygonShape.cpp +++ b/src/modules/physics/box2d/PolygonShape.cpp @@ -34,8 +34,8 @@ namespace box2d love::Type PolygonShape::type("PolygonShape", &Shape::type); -PolygonShape::PolygonShape(b2PolygonShape *p, bool own) - : Shape(p, own) +PolygonShape::PolygonShape(Body *body, const b2PolygonShape &p) + : Shape(body, p) { } @@ -45,6 +45,7 @@ PolygonShape::~PolygonShape() int PolygonShape::getPoints(lua_State *L) { + throwIfShapeNotValid(); love::luax_assert_argc(L, 0); b2PolygonShape *p = (b2PolygonShape *)shape; int count = p->m_count; @@ -59,6 +60,7 @@ int PolygonShape::getPoints(lua_State *L) bool PolygonShape::validate() const { + throwIfShapeNotValid(); b2PolygonShape *p = (b2PolygonShape *)shape; return p->Validate(); } diff --git a/src/modules/physics/box2d/PolygonShape.h b/src/modules/physics/box2d/PolygonShape.h index 9a632ae6d..5d400553f 100644 --- a/src/modules/physics/box2d/PolygonShape.h +++ b/src/modules/physics/box2d/PolygonShape.h @@ -48,7 +48,7 @@ public: * Create a new PolygonShape from a Box2D polygon definition. * @param p The polygon definition. **/ - PolygonShape(b2PolygonShape *p, bool own = true); + PolygonShape(Body *body, const b2PolygonShape &p); virtual ~PolygonShape(); diff --git a/src/modules/physics/box2d/Shape.cpp b/src/modules/physics/box2d/Shape.cpp index e65807582..c47c4c7ff 100644 --- a/src/modules/physics/box2d/Shape.cpp +++ b/src/modules/physics/box2d/Shape.cpp @@ -35,54 +35,348 @@ namespace physics namespace box2d { -Shape::Shape() +Shape::Shape(Body *body, const b2Shape &shape) : shape(nullptr) , own(false) + , shapeType(SHAPE_INVALID) + , body(body) + , fixture(nullptr) { -} + if (body) + { + b2FixtureDef def; + def.shape = &shape; + def.userData.pointer = (uintptr_t)this; + def.density = 1.0f; + fixture = body->body->CreateFixture(&def); + this->shape = fixture->GetShape(); + retain(); // Shape::destroy does the release(). + } + else + { + // Path to support deprecated APIs. + auto physics = Module::getInstance(Module::M_PHYSICS); + this->shape = shape.Clone(physics->getBlockAllocator()); + own = true; + } -Shape::Shape(b2Shape *shape, bool own) - : shape(shape) - , own(own) -{ + switch (this->shape->GetType()) + { + case b2Shape::e_circle: + shapeType = SHAPE_CIRCLE; + break; + case b2Shape::e_polygon: + shapeType = SHAPE_POLYGON; + break; + case b2Shape::e_edge: + shapeType = SHAPE_EDGE; + break; + case b2Shape::e_chain: + shapeType = SHAPE_CHAIN; + break; + default: + shapeType = SHAPE_INVALID; + break; + } } Shape::~Shape() { if (shape && own) - delete shape; + { + auto physics = Module::getInstance(Module::M_PHYSICS); + auto allocator = physics->getBlockAllocator(); + + // Taken from b2Fixture::Destroy. Not very pretty... + switch (shapeType) + { + case SHAPE_CIRCLE: + { + b2CircleShape *s = (b2CircleShape*)shape; + s->~b2CircleShape(); + allocator->Free(s, sizeof(b2CircleShape)); + break; + } + case SHAPE_EDGE: + { + b2EdgeShape *s = (b2EdgeShape*)shape; + s->~b2EdgeShape(); + allocator->Free(s, sizeof(b2EdgeShape)); + break; + } + case SHAPE_POLYGON: + { + b2PolygonShape *s = (b2PolygonShape*)shape; + s->~b2PolygonShape(); + allocator->Free(s, sizeof(b2PolygonShape)); + break; + } + case SHAPE_CHAIN: + { + b2ChainShape *s = (b2ChainShape*)shape; + s->~b2ChainShape(); + allocator->Free(s, sizeof(b2ChainShape)); + break; + } + default: + break; + } + } + + if (ref) + delete ref; +} + +void Shape::destroy(bool implicit) +{ + if (fixture == nullptr) + return; + + if (body->world->world->IsLocked()) + { + // Called during time step. Save reference for destruction afterwards. + this->retain(); + body->world->destructShapes.push_back(this); + return; + } + + if (!implicit && fixture != nullptr) + body->body->DestroyFixture(fixture); + + fixture = nullptr; shape = nullptr; + body = nullptr; + + // Remove userdata reference to avoid it sticking around after GC + if (ref) + ref->unref(); + + // Box2D fixture destroyed. Release its reference to the love Shape. + release(); +} + +void Shape::throwIfFixtureNotValid() const +{ + if (fixture == nullptr) + throw love::Exception("Shape must be active in the physics World to use this method."); +} + +void Shape::throwIfShapeNotValid() const +{ + if (shape == nullptr) + throw love::Exception("Cannot call this method on a destroyed Shape."); } Shape::Type Shape::getType() const { - switch (shape->GetType()) - { - case b2Shape::e_circle: - return SHAPE_CIRCLE; - case b2Shape::e_polygon: - return SHAPE_POLYGON; - case b2Shape::e_edge: - return SHAPE_EDGE; - case b2Shape::e_chain: - return SHAPE_CHAIN; - default: - return SHAPE_INVALID; - } + return shapeType; +} + +void Shape::setFriction(float friction) +{ + throwIfFixtureNotValid(); + fixture->SetFriction(friction); +} + +void Shape::setRestitution(float restitution) +{ + throwIfFixtureNotValid(); + fixture->SetRestitution(restitution); +} + +void Shape::setDensity(float density) +{ + throwIfFixtureNotValid(); + fixture->SetDensity(density); +} + +void Shape::setSensor(bool sensor) +{ + throwIfFixtureNotValid(); + fixture->SetSensor(sensor); +} + +float Shape::getFriction() const +{ + throwIfFixtureNotValid(); + return fixture->GetFriction(); +} + +float Shape::getRestitution() const +{ + throwIfFixtureNotValid(); + return fixture->GetRestitution(); +} + +float Shape::getDensity() const +{ + throwIfFixtureNotValid(); + return fixture->GetDensity(); +} + +bool Shape::isSensor() const +{ + throwIfFixtureNotValid(); + return fixture->IsSensor(); +} + +Body *Shape::getBody() const +{ + return body; } float Shape::getRadius() const { + throwIfShapeNotValid(); return Physics::scaleUp(shape->m_radius); } int Shape::getChildCount() const { + throwIfShapeNotValid(); return shape->GetChildCount(); } +void Shape::setFilterData(int *v) +{ + throwIfFixtureNotValid(); + b2Filter f; + f.categoryBits = (uint16) v[0]; + f.maskBits = (uint16) v[1]; + f.groupIndex = (int16) v[2]; + fixture->SetFilterData(f); +} + +void Shape::getFilterData(int *v) +{ + throwIfFixtureNotValid(); + b2Filter f = fixture->GetFilterData(); + v[0] = (int) f.categoryBits; + v[1] = (int) f.maskBits; + v[2] = (int) f.groupIndex; +} + +int Shape::setCategory(lua_State *L) +{ + throwIfFixtureNotValid(); + b2Filter f = fixture->GetFilterData(); + f.categoryBits = (uint16)getBits(L); + fixture->SetFilterData(f); + return 0; +} + +int Shape::setMask(lua_State *L) +{ + throwIfFixtureNotValid(); + b2Filter f = fixture->GetFilterData(); + f.maskBits = ~(uint16)getBits(L); + fixture->SetFilterData(f); + return 0; +} + +void Shape::setGroupIndex(int index) +{ + throwIfFixtureNotValid(); + b2Filter f = fixture->GetFilterData(); + f.groupIndex = (uint16)index; + fixture->SetFilterData(f); +} + +int Shape::getGroupIndex() const +{ + throwIfFixtureNotValid(); + b2Filter f = fixture->GetFilterData(); + return f.groupIndex; +} + +int Shape::getCategory(lua_State *L) +{ + throwIfFixtureNotValid(); + return pushBits(L, fixture->GetFilterData().categoryBits); +} + +int Shape::getMask(lua_State *L) +{ + throwIfFixtureNotValid(); + return pushBits(L, ~(fixture->GetFilterData().maskBits)); +} + +uint16 Shape::getBits(lua_State *L) +{ + // Get number of args. + bool istable = lua_istable(L, 1); + int argc = istable ? (int) luax_objlen(L, 1) : lua_gettop(L); + + // The new bitset. + std::bitset<16> b; + + for (int i = 1; i <= argc; i++) + { + size_t bpos = 0; + + if (istable) + { + lua_rawgeti(L, 1, i); + bpos = (size_t) (lua_tointeger(L, -1) - 1); + lua_pop(L, 1); + } + else + bpos = (size_t) (lua_tointeger(L, i) - 1); + + if (bpos >= 16) + luaL_error(L, "Values must be in range 1-16."); + + b.set(bpos, true); + } + + return (uint16)b.to_ulong(); +} + +int Shape::pushBits(lua_State *L, uint16 bits) +{ + // Create a bitset. + std::bitset<16> b((int)bits); + + // Push all set bits. + for (int i = 0; i<16; i++) + if (b.test(i)) + lua_pushinteger(L, i+1); + + // Count number of set bits. + return (int)b.count(); +} + +int Shape::setUserData(lua_State *L) +{ + love::luax_assert_argc(L, 1, 1); + + if(!ref) + ref = new Reference(); + + ref->ref(L); + + return 0; +} + +int Shape::getUserData(lua_State *L) +{ + if (ref != nullptr) + ref->push(L); + else + lua_pushnil(L); + + return 1; +} + +bool Shape::testPoint(float x, float y) const +{ + throwIfFixtureNotValid(); + return fixture->TestPoint(Physics::scaleDown(b2Vec2(x, y))); +} + bool Shape::testPoint(float x, float y, float r, float px, float py) const { + throwIfShapeNotValid(); b2Vec2 point(px, py); b2Transform transform(Physics::scaleDown(b2Vec2(x, y)), b2Rot(r)); return shape->TestPoint(transform, Physics::scaleDown(point)); @@ -95,18 +389,34 @@ int Shape::rayCast(lua_State *L) const float p2x = Physics::scaleDown((float)luaL_checknumber(L, 3)); float p2y = Physics::scaleDown((float)luaL_checknumber(L, 4)); float maxFraction = (float)luaL_checknumber(L, 5); - float x = Physics::scaleDown((float)luaL_checknumber(L, 6)); - float y = Physics::scaleDown((float)luaL_checknumber(L, 7)); - float r = (float)luaL_checknumber(L, 8); - int childIndex = (int) luaL_optinteger(L, 9, 1) - 1; // Convert from 1-based index + b2RayCastInput input; + b2RayCastOutput output; input.p1.Set(p1x, p1y); input.p2.Set(p2x, p2y); input.maxFraction = maxFraction; - b2Transform transform(b2Vec2(x, y), b2Rot(r)); - b2RayCastOutput output; - if (!shape->RayCast(&output, input, transform, childIndex)) - return 0; // No hit. + + if (lua_isnoneornil(L, 7)) + { + throwIfFixtureNotValid(); + int childIndex = (int) luaL_optinteger(L, 6, 1) - 1; // Convert from 1-based index + if (!fixture->RayCast(&output, input, childIndex)) + return 0; // Nothing hit. + } + else + { + throwIfShapeNotValid(); + float x = Physics::scaleDown((float)luaL_checknumber(L, 6)); + float y = Physics::scaleDown((float)luaL_checknumber(L, 7)); + float r = (float)luaL_checknumber(L, 8); + int childIndex = (int) luaL_optinteger(L, 9, 1) - 1; // Convert from 1-based index + + b2Transform transform(b2Vec2(x, y), b2Rot(r)); + + if (!shape->RayCast(&output, input, transform, childIndex)) + return 0; // No hit. + } + lua_pushnumber(L, output.normal.x); lua_pushnumber(L, output.normal.y); lua_pushnumber(L, output.fraction); @@ -115,6 +425,7 @@ int Shape::rayCast(lua_State *L) const int Shape::computeAABB(lua_State *L) const { + throwIfShapeNotValid(); float x = Physics::scaleDown((float)luaL_checknumber(L, 1)); float y = Physics::scaleDown((float)luaL_checknumber(L, 2)); float r = (float)luaL_checknumber(L, 3); @@ -132,6 +443,7 @@ int Shape::computeAABB(lua_State *L) const int Shape::computeMass(lua_State *L) const { + throwIfShapeNotValid(); float density = (float)luaL_checknumber(L, 1); b2MassData data; shape->ComputeMass(&data, density); @@ -143,6 +455,33 @@ int Shape::computeMass(lua_State *L) const return 4; } +int Shape::getBoundingBox(lua_State *L) const +{ + throwIfFixtureNotValid(); + int childIndex = (int) luaL_optinteger(L, 1, 1) - 1; // Convert from 1-based index + b2AABB box; + luax_catchexcept(L, [&]() { box = fixture->GetAABB(childIndex); }); + box = Physics::scaleUp(box); + lua_pushnumber(L, box.lowerBound.x); + lua_pushnumber(L, box.lowerBound.y); + lua_pushnumber(L, box.upperBound.x); + lua_pushnumber(L, box.upperBound.y); + return 4; +} + +int Shape::getMassData(lua_State *L) const +{ + throwIfFixtureNotValid(); + b2MassData data; + fixture->GetMassData(&data); + b2Vec2 center = Physics::scaleUp(data.center); + lua_pushnumber(L, center.x); + lua_pushnumber(L, center.y); + lua_pushnumber(L, data.mass); + lua_pushnumber(L, data.I); + return 4; +} + } // box2d } // physics } // love diff --git a/src/modules/physics/box2d/Shape.h b/src/modules/physics/box2d/Shape.h index 94b314dc9..6eb4e0586 100644 --- a/src/modules/physics/box2d/Shape.h +++ b/src/modules/physics/box2d/Shape.h @@ -24,6 +24,7 @@ // LOVE #include "physics/Shape.h" #include "physics/box2d/Body.h" +#include "common/Reference.h" // Box2D #include @@ -45,34 +46,155 @@ class Shape : public love::physics::Shape { public: - friend class Fixture; + friend class Physics; /** * Creates a Shape. **/ - Shape(); - Shape(b2Shape *shape, bool own = true); + Shape(Body *body, const b2Shape &shape); virtual ~Shape(); + void destroy(bool implicit = false); + + /** + * Returns true if the shape is active in a Box2D world. + **/ + bool isValid() const { return fixture != nullptr; } + + /** + * Returns true if the shape has not been destroyed. + **/ + bool isShapeValid() const { return shape != nullptr; } + + /** + * Checks whether this Shape acts as a sensor. + **/ + bool isSensor() const; + + /** + * Set whether this Shape should be a sensor or not. + **/ + void setSensor(bool sensor); + + /** + * Gets the Body this Shape is attached to. + **/ + Body *getBody() const; + + /** + * Sets the filter data. An integer array is used even though the + * first two elements are unsigned shorts. The elements are: + * category (16-bits), mask (16-bits) and group (32-bits/int). + **/ + void setFilterData(int *v); + + /** + * Gets the filter data. An integer array is used even though the + * first two elements are unsigned shorts. The elements are: + * category (16-bits), mask (16-bits) and group (32-bits/int). + **/ + void getFilterData(int *v); + + /** + * This function stores an in-C reference to + * arbitrary Lua data in the Shape object. + **/ + int setUserData(lua_State *L); + + /** + * Gets the data set with setUserData. If no + * data is set, nil is returned. + **/ + int getUserData(lua_State *L); + + /** + * Sets the friction of the Shape. + **/ + void setFriction(float friction); + + /** + * Sets the restitution for the Shape. + **/ + void setRestitution(float restitution); + + /** + * Sets the density of the Shape. + **/ + void setDensity(float density); + + /** + * Gets the friction of the Shape. + **/ + float getFriction() const; + + /** + * Gets the restitution of the Shape. + **/ + float getRestitution() const; + + /** + * Gets the density of the Shape. + **/ + float getDensity() const; + + /** + * Checks if a point is inside the Shape. + **/ + bool testPoint(float x, float y) const; + bool testPoint(float x, float y, float r, float px, float py) const; + /** * Gets the type of Shape. Useful for * debug drawing. **/ Type getType() const; + float getRadius() const; int getChildCount() const; - bool testPoint(float x, float y, float r, float px, float py) const; int rayCast(lua_State *L) const; int computeAABB(lua_State *L) const; int computeMass(lua_State *L) const; + void setGroupIndex(int index); + int getGroupIndex() const; + + int setCategory(lua_State *L); + int setMask(lua_State *L); + int getCategory(lua_State *L); + int getMask(lua_State *L); + uint16 getBits(lua_State *L); + int pushBits(lua_State *L, uint16 bits); + + /** + * Gets the bounding box for this Shape. + **/ + int getBoundingBox(lua_State *L) const; + + /** + * Gets the mass data for this Shape. + * This operation may be expensive. + **/ + int getMassData(lua_State *L) const; + + void throwIfFixtureNotValid() const; + void throwIfShapeNotValid() const; + protected: // The Box2D shape. b2Shape *shape; bool own; -}; + + Shape::Type shapeType; + + Body *body; + b2Fixture *fixture; + + // Reference to arbitrary data. + Reference* ref = nullptr; + +}; // Shape } // box2d } // physics diff --git a/src/modules/physics/box2d/World.cpp b/src/modules/physics/box2d/World.cpp index 8e37940c7..b90c4a3c7 100644 --- a/src/modules/physics/box2d/World.cpp +++ b/src/modules/physics/box2d/World.cpp @@ -20,7 +20,6 @@ #include "World.h" -#include "Fixture.h" #include "Shape.h" #include "Contact.h" #include "Physics.h" @@ -28,6 +27,7 @@ // Needed for World::getJoints. It should be moved to wrapper code... #include "wrap_Joint.h" +#include "wrap_Shape.h" namespace love { @@ -58,22 +58,22 @@ void World::ContactCallback::process(b2Contact *contact, const b2ContactImpulse { ref->push(L); - // Push first fixture. + // Push first shape. { - Fixture *a = (Fixture *)(contact->GetFixtureA()->GetUserData().pointer); + Shape *a = (Shape *)(contact->GetFixtureA()->GetUserData().pointer); if (a != nullptr) - luax_pushtype(L, a); + luax_pushshape(L, a); else - throw love::Exception("A fixture has escaped Memoizer!"); + throw love::Exception("A Shape has escaped Memoizer!"); } - // Push second fixture. + // Push second shape. { - Fixture *b = (Fixture *)(contact->GetFixtureB()->GetUserData().pointer); + Shape *b = (Shape *)(contact->GetFixtureB()->GetUserData().pointer); if (b != nullptr) - luax_pushtype(L, b); + luax_pushshape(L, b); else - throw love::Exception("A fixture has escaped Memoizer!"); + throw love::Exception("A Shape has escaped Memoizer!"); } Contact *cobj = (Contact *)world->findObject(contact); @@ -112,7 +112,7 @@ World::ContactFilter::~ContactFilter() delete ref; } -bool World::ContactFilter::process(Fixture *a, Fixture *b) +bool World::ContactFilter::process(Shape *a, Shape *b) { // Handle masks, reimplemented from the manual int filterA[3], filterB[3]; @@ -133,8 +133,8 @@ bool World::ContactFilter::process(Fixture *a, Fixture *b) if (ref != nullptr && L != nullptr) { ref->push(L); - luax_pushtype(L, a); - luax_pushtype(L, b); + luax_pushshape(L, a); + luax_pushshape(L, b); lua_call(L, 2, 1); return luax_toboolean(L, -1); } @@ -159,10 +159,10 @@ bool World::QueryCallback::ReportFixture(b2Fixture *fixture) if (L != nullptr) { lua_pushvalue(L, funcidx); - Fixture *f = (Fixture *)(fixture->GetUserData().pointer); + Shape *f = (Shape *)(fixture->GetUserData().pointer); if (!f) - throw love::Exception("A fixture has escaped Memoizer!"); - luax_pushtype(L, f); + throw love::Exception("A Shape has escaped Memoizer!"); + luax_pushshape(L, f); for (int i = 1; i <= userargs; i++) lua_pushvalue(L, funcidx + i); lua_call(L, 1 + userargs, 1); @@ -191,10 +191,10 @@ bool World::CollectCallback::ReportFixture(b2Fixture *f) if (categoryMask != 0xFFFF && (categoryMask & f->GetFilterData().categoryBits) == 0) return true; - Fixture *fixture = (Fixture *)(f->GetUserData().pointer); - if (!fixture) - throw love::Exception("A fixture has escaped Memoizer!"); - luax_pushtype(L, fixture); + Shape *shape = (Shape *)(f->GetUserData().pointer); + if (!shape) + throw love::Exception("A Shape has escaped Memoizer!"); + luax_pushshape(L, shape); lua_rawseti(L, -2, i); i++; return true; @@ -218,10 +218,10 @@ float World::RayCastCallback::ReportFixture(b2Fixture *fixture, const b2Vec2 &po if (L != nullptr) { lua_pushvalue(L, funcidx); - Fixture *f = (Fixture *)(fixture->GetUserData().pointer); + Shape *f = (Shape *)(fixture->GetUserData().pointer); if (!f) - throw love::Exception("A fixture has escaped Memoizer!"); - luax_pushtype(L, f); + throw love::Exception("A Shape has escaped Memoizer!"); + luax_pushshape(L, f); b2Vec2 scaledPoint = Physics::scaleUp(point); lua_pushnumber(L, scaledPoint.x); lua_pushnumber(L, scaledPoint.y); @@ -267,9 +267,9 @@ float World::RayCastOneCallback::ReportFixture(b2Fixture *fixture, const b2Vec2 void World::SayGoodbye(b2Fixture *fixture) { - Fixture *f = (Fixture *)(fixture->GetUserData().pointer); + Shape *s = (Shape *)(fixture->GetUserData().pointer); // Hint implicit destruction with true. - if (f) f->destroy(true); + if (s) s->destroy(true); } void World::SayGoodbye(b2Joint *joint) @@ -336,11 +336,11 @@ void World::update(float dt, int velocityIterations, int positionIterations) // Release for reference in vector. b->release(); } - for (Fixture *f : destructFixtures) + for (Shape *s : destructShapes) { - if (f->isValid()) f->destroy(); + if (s->isValid()) s->destroy(); // Release for reference in vector. - f->release(); + s->release(); } for (Joint *j : destructJoints) { @@ -349,7 +349,7 @@ void World::update(float dt, int velocityIterations, int positionIterations) j->release(); } destructBodies.clear(); - destructFixtures.clear(); + destructShapes.clear(); destructJoints.clear(); if (destructWorld) @@ -384,11 +384,11 @@ void World::PostSolve(b2Contact *contact, const b2ContactImpulse *impulse) bool World::ShouldCollide(b2Fixture *fixtureA, b2Fixture *fixtureB) { - // Fixtures should be memoized, if we created them - Fixture *a = (Fixture *)(fixtureA->GetUserData().pointer); - Fixture *b = (Fixture *)(fixtureB->GetUserData().pointer); + // Shapes should be memoized, if we created them + Shape *a = (Shape *)(fixtureA->GetUserData().pointer); + Shape *b = (Shape *)(fixtureB->GetUserData().pointer); if (!a || !b) - throw love::Exception("A fixture has escaped Memoizer!"); + throw love::Exception("A Shape has escaped Memoizer!"); return filter.process(a, b); } @@ -597,7 +597,7 @@ b2Body *World::getGroundBody() const return groundBody; } -int World::queryFixturesInArea(lua_State *L) +int World::queryShapesInArea(lua_State *L) { b2AABB box; float lx = (float)luaL_checknumber(L, 1); @@ -612,7 +612,7 @@ int World::queryFixturesInArea(lua_State *L) return 0; } -int World::getFixturesInArea(lua_State *L) +int World::getShapesInArea(lua_State *L) { float lx = (float)luaL_checknumber(L, 1); float ly = (float)luaL_checknumber(L, 2); @@ -654,10 +654,10 @@ int World::rayCastAny(lua_State *L) world->RayCast(&raycast, v1, v2); if (raycast.hitFixture) { - Fixture *f = (Fixture *)(raycast.hitFixture->GetUserData().pointer); + Shape *f = (Shape *)(raycast.hitFixture->GetUserData().pointer); if (f == nullptr) - return luaL_error(L, "A fixture has escaped Memoizer!"); - luax_pushtype(L, f); + return luaL_error(L, "A Shape has escaped Memoizer!"); + luax_pushshape(L, f); b2Vec2 hitPoint = Physics::scaleUp(raycast.hitPoint); lua_pushnumber(L, hitPoint.x); @@ -683,10 +683,10 @@ int World::rayCastClosest(lua_State *L) world->RayCast(&raycast, v1, v2); if (raycast.hitFixture) { - Fixture *f = (Fixture *)(raycast.hitFixture->GetUserData().pointer); + Shape *f = (Shape *)(raycast.hitFixture->GetUserData().pointer); if (f == nullptr) - return luaL_error(L, "A fixture has escaped Memoizer!"); - luax_pushtype(L, f); + return luaL_error(L, "A Shape has escaped Memoizer!"); + luax_pushshape(L, f); b2Vec2 hitPoint = Physics::scaleUp(raycast.hitPoint); lua_pushnumber(L, hitPoint.x); diff --git a/src/modules/physics/box2d/World.h b/src/modules/physics/box2d/World.h index 94d2a1e09..2c7eb78b7 100644 --- a/src/modules/physics/box2d/World.h +++ b/src/modules/physics/box2d/World.h @@ -42,7 +42,6 @@ namespace box2d class Contact; class Body; -class Fixture; class Joint; /** @@ -65,7 +64,7 @@ public: friend class DistanceJoint; friend class MouseJoint; friend class Body; - friend class Fixture; + friend class Shape; static love::Type type; @@ -87,7 +86,7 @@ public: lua_State *L; ContactFilter(); ~ContactFilter(); - bool process(Fixture *a, Fixture *b); + bool process(Shape *a, Shape *b); }; class QueryCallback : public b2QueryCallback @@ -302,14 +301,14 @@ public: b2Body *getGroundBody() const; /** - * Calls a callback on all fixtures that overlap a given bounding box. + * Calls a callback on all Shapes that overlap a given bounding box. **/ - int queryFixturesInArea(lua_State *L); + int queryShapesInArea(lua_State *L); /** - * Gets all fixtures that overlap a given bounding box. + * Gets all Shapes that overlap a given bounding box. **/ - int getFixturesInArea(lua_State *L); + int getShapesInArea(lua_State *L); /** * Raycasts the World for all Fixtures in the path of the ray. @@ -338,7 +337,7 @@ private: // The list of to be destructed bodies. std::vector destructBodies; - std::vector destructFixtures; + std::vector destructShapes; std::vector destructJoints; bool destructWorld; diff --git a/src/modules/physics/box2d/wrap_Body.cpp b/src/modules/physics/box2d/wrap_Body.cpp index 6ed39ef2e..f0d4dd865 100644 --- a/src/modules/physics/box2d/wrap_Body.cpp +++ b/src/modules/physics/box2d/wrap_Body.cpp @@ -20,6 +20,7 @@ #include "wrap_Body.h" #include "wrap_Physics.h" +#include "wrap_Shape.h" namespace love { @@ -599,26 +600,32 @@ int w_Body_getWorld(lua_State *L) return 1; } -int w_Body_getFixture(lua_State *L) +int w_Body_getShape(lua_State *L) { Body *t = luax_checkbody(L, 1); - Fixture *f = t->getFixture(); - if (f) - luax_pushtype(L, f); + Shape *s = t->getShape(); + if (s) + luax_pushshape(L, s); else lua_pushnil(L); return 1; } -int w_Body_getFixtures(lua_State *L) +int w_Body_getShapes(lua_State *L) { Body *t = luax_checkbody(L, 1); lua_remove(L, 1); int n = 0; - luax_catchexcept(L, [&](){ n = t->getFixtures(L); }); + luax_catchexcept(L, [&](){ n = t->getShapes(L); }); return n; } +int w_Body_getFixtures(lua_State *L) +{ + luax_markdeprecated(L, 1, "Body:getFixtures", API_METHOD, DEPRECATED_REPLACED, "Body:getShapes"); + return w_Body_getShapes(L); +} + int w_Body_getJoints(lua_State *L) { Body *t = luax_checkbody(L, 1); @@ -724,8 +731,8 @@ static const luaL_Reg w_Body_functions[] = { "isFixedRotation", w_Body_isFixedRotation }, { "isTouching", w_Body_isTouching }, { "getWorld", w_Body_getWorld }, - { "getFixture", w_Body_getFixture }, - { "getFixtures", w_Body_getFixtures }, + { "getShape", w_Body_getShape }, + { "getShapes", w_Body_getShapes }, { "getJoints", w_Body_getJoints }, { "getContacts", w_Body_getContacts }, { "destroy", w_Body_destroy }, @@ -733,6 +740,9 @@ static const luaL_Reg w_Body_functions[] = { "setUserData", w_Body_setUserData }, { "getUserData", w_Body_getUserData }, + // Deprecated + { "getFixtures", w_Body_getFixtures }, + { 0, 0 } }; diff --git a/src/modules/physics/box2d/wrap_ChainShape.cpp b/src/modules/physics/box2d/wrap_ChainShape.cpp index 52c94ef70..d0597e778 100644 --- a/src/modules/physics/box2d/wrap_ChainShape.cpp +++ b/src/modules/physics/box2d/wrap_ChainShape.cpp @@ -54,9 +54,10 @@ int w_ChainShape_setPreviousVertex(lua_State *L) int w_ChainShape_getChildEdge(lua_State *L) { + luax_markdeprecated(L, 1, "ChainShape:getChildEdge", API_METHOD, DEPRECATED_NO_REPLACEMENT, nullptr); ChainShape *c = luax_checkchainshape(L, 1); int index = (int) luaL_checkinteger(L, 2) - 1; // Convert from 1-based index - EdgeShape *e = 0; + EdgeShape *e = nullptr; luax_catchexcept(L, [&](){ e = c->getChildEdge(index); }); luax_pushtype(L, e); e->release(); @@ -66,7 +67,8 @@ int w_ChainShape_getChildEdge(lua_State *L) int w_ChainShape_getVertexCount(lua_State *L) { ChainShape *c = luax_checkchainshape(L, 1); - int count = c->getVertexCount(); + int count = 0; + luax_catchexcept(L, [&]() { count = c->getVertexCount(); }); lua_pushinteger(L, count); return 1; } @@ -85,7 +87,8 @@ int w_ChainShape_getPoint(lua_State *L) int w_ChainShape_getNextVertex(lua_State *L) { ChainShape *c = luax_checkchainshape(L, 1); - b2Vec2 v = c->getNextVertex(); + b2Vec2 v; + luax_catchexcept(L, [&]() { v = c->getNextVertex(); }); lua_pushnumber(L, v.x); lua_pushnumber(L, v.y); return 2; @@ -94,7 +97,8 @@ int w_ChainShape_getNextVertex(lua_State *L) int w_ChainShape_getPreviousVertex(lua_State *L) { ChainShape *c = luax_checkchainshape(L, 1); - b2Vec2 v = c->getPreviousVertex(); + b2Vec2 v; + luax_catchexcept(L, [&]() { v = c->getPreviousVertex(); }); lua_pushnumber(L, v.x); lua_pushnumber(L, v.y); return 2; @@ -103,7 +107,8 @@ int w_ChainShape_getPreviousVertex(lua_State *L) int w_ChainShape_getPoints(lua_State *L) { ChainShape *c = luax_checkchainshape(L, 1); - const b2Vec2 *verts = c->getPoints(); + const b2Vec2 *verts; + luax_catchexcept(L, [&]() { verts = c->getPoints(); }); int count = c->getVertexCount(); if (!lua_checkstack(L, count*2)) return luaL_error(L, "Too many return values"); diff --git a/src/modules/physics/box2d/wrap_CircleShape.cpp b/src/modules/physics/box2d/wrap_CircleShape.cpp index f9ec8394a..99bc524d6 100644 --- a/src/modules/physics/box2d/wrap_CircleShape.cpp +++ b/src/modules/physics/box2d/wrap_CircleShape.cpp @@ -35,7 +35,9 @@ CircleShape *luax_checkcircleshape(lua_State *L, int idx) int w_CircleShape_getRadius(lua_State *L) { CircleShape *c = luax_checkcircleshape(L, 1); - lua_pushnumber(L, c->getRadius()); + float r = 0; + luax_catchexcept(L, [&]() { r = c->getRadius(); }); + lua_pushnumber(L, r); return 1; } @@ -43,7 +45,7 @@ int w_CircleShape_setRadius(lua_State *L) { CircleShape *c = luax_checkcircleshape(L, 1); float r = (float)luaL_checknumber(L, 2); - c->setRadius(r); + luax_catchexcept(L, [&]() { c->setRadius(r); }); return 0; } @@ -51,7 +53,7 @@ int w_CircleShape_getPoint(lua_State *L) { CircleShape *c = luax_checkcircleshape(L, 1); float x, y; - c->getPoint(x, y); + luax_catchexcept(L, [&]() { c->getPoint(x, y); }); lua_pushnumber(L, x); lua_pushnumber(L, y); return 2; diff --git a/src/modules/physics/box2d/wrap_Contact.cpp b/src/modules/physics/box2d/wrap_Contact.cpp index d18d39402..a61c6a72b 100644 --- a/src/modules/physics/box2d/wrap_Contact.cpp +++ b/src/modules/physics/box2d/wrap_Contact.cpp @@ -19,7 +19,7 @@ **/ #include "wrap_Contact.h" -#include "Fixture.h" +#include "wrap_Shape.h" namespace love { @@ -139,18 +139,24 @@ int w_Contact_getChildren(lua_State *L) return 2; } -int w_Contact_getFixtures(lua_State *L) +int w_Contact_getShapes(lua_State *L) { Contact *t = luax_checkcontact(L, 1); - Fixture *a = nullptr; - Fixture *b = nullptr; - luax_catchexcept(L, [&](){ t->getFixtures(a, b); }); + Shape *a = nullptr; + Shape *b = nullptr; + luax_catchexcept(L, [&](){ t->getShapes(a, b); }); - luax_pushtype(L, a); - luax_pushtype(L, b); + luax_pushshape(L, a); + luax_pushshape(L, b); return 2; } +int w_Contact_getFixtures(lua_State *L) +{ + luax_markdeprecated(L, 1, "Contact:getFixtures", API_METHOD, DEPRECATED_REPLACED, "Contact:getShapes"); + return w_Contact_getShapes(L); +} + int w_Contact_isDestroyed(lua_State *L) { Contact *c = luax_checktype(L, 1); @@ -174,8 +180,12 @@ static const luaL_Reg w_Contact_functions[] = { "setTangentSpeed", w_Contact_setTangentSpeed }, { "getTangentSpeed", w_Contact_getTangentSpeed }, { "getChildren", w_Contact_getChildren }, - { "getFixtures", w_Contact_getFixtures }, + { "getShapes", w_Contact_getShapes }, { "isDestroyed", w_Contact_isDestroyed }, + + // Deprecated + { "getFixtures", w_Contact_getFixtures }, + { 0, 0 } }; diff --git a/src/modules/physics/box2d/wrap_EdgeShape.cpp b/src/modules/physics/box2d/wrap_EdgeShape.cpp index fbc0c0574..a97b115a5 100644 --- a/src/modules/physics/box2d/wrap_EdgeShape.cpp +++ b/src/modules/physics/box2d/wrap_EdgeShape.cpp @@ -37,7 +37,7 @@ int w_EdgeShape_setNextVertex(lua_State *L) EdgeShape *t = luax_checkedgeshape(L, 1); float x = (float)luaL_checknumber(L, 2); float y = (float)luaL_checknumber(L, 3); - t->setNextVertex(x, y); + luax_catchexcept(L, [&]() { t->setNextVertex(x, y); }); return 0; } @@ -46,14 +46,15 @@ int w_EdgeShape_setPreviousVertex(lua_State *L) EdgeShape *t = luax_checkedgeshape(L, 1); float x = (float)luaL_checknumber(L, 2); float y = (float)luaL_checknumber(L, 3); - t->setPreviousVertex(x, y); + luax_catchexcept(L, [&]() { t->setPreviousVertex(x, y); }); return 0; } int w_EdgeShape_getNextVertex(lua_State *L) { EdgeShape *t = luax_checkedgeshape(L, 1); - b2Vec2 v = t->getNextVertex(); + b2Vec2 v; + luax_catchexcept(L, [&]() { v = t->getNextVertex(); }); lua_pushnumber(L, v.x); lua_pushnumber(L, v.y); return 2; @@ -62,7 +63,8 @@ int w_EdgeShape_getNextVertex(lua_State *L) int w_EdgeShape_getPreviousVertex(lua_State *L) { EdgeShape *t = luax_checkedgeshape(L, 1); - b2Vec2 v = t->getPreviousVertex(); + b2Vec2 v; + luax_catchexcept(L, [&]() { v = t->getPreviousVertex(); }); lua_pushnumber(L, v.x); lua_pushnumber(L, v.y); return 2; @@ -72,7 +74,9 @@ int w_EdgeShape_getPoints(lua_State *L) { EdgeShape *t = luax_checkedgeshape(L, 1); lua_remove(L, 1); - return t->getPoints(L); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->getPoints(L); }); + return ret; } static const luaL_Reg w_EdgeShape_functions[] = diff --git a/src/modules/physics/box2d/wrap_Fixture.cpp b/src/modules/physics/box2d/wrap_Fixture.cpp deleted file mode 100644 index 4056874c9..000000000 --- a/src/modules/physics/box2d/wrap_Fixture.cpp +++ /dev/null @@ -1,311 +0,0 @@ -/** - * Copyright (c) 2006-2023 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -#include "wrap_Fixture.h" -#include "common/StringMap.h" - -namespace love -{ -namespace physics -{ -namespace box2d -{ - -Fixture *luax_checkfixture(lua_State *L, int idx) -{ - Fixture *f = luax_checktype(L, idx); - if (!f->isValid()) - luaL_error(L, "Attempt to use destroyed fixture."); - return f; -} - -int w_Fixture_getType(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - const char *type = ""; - Shape::getConstant(t->getType(), type); - lua_pushstring(L, type); - return 1; -} - -int w_Fixture_setFriction(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - float arg1 = (float)luaL_checknumber(L, 2); - t->setFriction(arg1); - return 0; -} - -int w_Fixture_setRestitution(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - float arg1 = (float)luaL_checknumber(L, 2); - t->setRestitution(arg1); - return 0; -} - -int w_Fixture_setDensity(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - float arg1 = (float)luaL_checknumber(L, 2); - luax_catchexcept(L, [&](){ t->setDensity(arg1); }); - return 0; -} - -int w_Fixture_setSensor(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - bool arg1 = luax_checkboolean(L, 2); - t->setSensor(arg1); - return 0; -} - -int w_Fixture_getFriction(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_pushnumber(L, t->getFriction()); - return 1; -} - -int w_Fixture_getRestitution(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_pushnumber(L, t->getRestitution()); - return 1; -} - -int w_Fixture_getDensity(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_pushnumber(L, t->getDensity()); - return 1; -} - -int w_Fixture_isSensor(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - luax_pushboolean(L, t->isSensor()); - return 1; -} - -int w_Fixture_getBody(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - Body *body = t->getBody(); - if (body == 0) - return 0; - luax_pushtype(L, body); - return 1; -} - -int w_Fixture_getShape(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - Shape * shape = t->getShape(); - if (shape == nullptr) - return 0; - switch (shape->getType()) - { - case Shape::SHAPE_EDGE: - luax_pushtype(L, dynamic_cast(shape)); - break; - case Shape::SHAPE_CHAIN: - luax_pushtype(L, dynamic_cast(shape)); - break; - case Shape::SHAPE_CIRCLE: - luax_pushtype(L, dynamic_cast(shape)); - break; - case Shape::SHAPE_POLYGON: - luax_pushtype(L, dynamic_cast(shape)); - break; - default: - luax_pushtype(L, shape); - break; - } - return 1; -} - -int w_Fixture_testPoint(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - float x = (float)luaL_checknumber(L, 2); - float y = (float)luaL_checknumber(L, 3); - luax_pushboolean(L, t->testPoint(x, y)); - return 1; -} - -int w_Fixture_rayCast(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_remove(L, 1); - int ret = 0; - luax_catchexcept(L, [&](){ ret = t->rayCast(L); }); - return ret; -} - -int w_Fixture_setFilterData(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - int v[3]; - v[0] = (int) luaL_checkinteger(L, 2); - v[1] = (int) luaL_checkinteger(L, 3); - v[2] = (int) luaL_checkinteger(L, 4); - t->setFilterData(v); - return 0; -} - -int w_Fixture_getFilterData(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - int v[3]; - t->getFilterData(v); - lua_pushinteger(L, v[0]); - lua_pushinteger(L, v[1]); - lua_pushinteger(L, v[2]); - return 3; -} - -int w_Fixture_setCategory(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_remove(L, 1); - return t->setCategory(L); -} - -int w_Fixture_getCategory(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_remove(L, 1); - return t->getCategory(L); -} - -int w_Fixture_setMask(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_remove(L, 1); - return t->setMask(L); -} - -int w_Fixture_getMask(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_remove(L, 1); - return t->getMask(L); -} - -int w_Fixture_setUserData(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_remove(L, 1); - return t->setUserData(L); -} - -int w_Fixture_getUserData(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_remove(L, 1); - return t->getUserData(L); -} - -int w_Fixture_getBoundingBox(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_remove(L, 1); - return t->getBoundingBox(L); -} - -int w_Fixture_getMassData(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_remove(L, 1); - return t->getMassData(L); -} - -int w_Fixture_getGroupIndex(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - int i = t->getGroupIndex(); - lua_pushinteger(L, i); - return 1; -} - -int w_Fixture_setGroupIndex(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - int i = (int) luaL_checkinteger(L, 2); - t->setGroupIndex(i); - return 0; -} - -int w_Fixture_destroy(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - luax_catchexcept(L, [&](){ t->destroy(); }); - return 0; -} - -int w_Fixture_isDestroyed(lua_State *L) -{ - Fixture *f = luax_checktype(L, 1); - luax_pushboolean(L, !f->isValid()); - return 1; -} - -static const luaL_Reg w_Fixture_functions[] = -{ - { "getType", w_Fixture_getType }, - { "setFriction", w_Fixture_setFriction }, - { "setRestitution", w_Fixture_setRestitution }, - { "setDensity", w_Fixture_setDensity }, - { "setSensor", w_Fixture_setSensor }, - { "getFriction", w_Fixture_getFriction }, - { "getRestitution", w_Fixture_getRestitution }, - { "getDensity", w_Fixture_getDensity }, - { "getBody", w_Fixture_getBody }, - { "getShape", w_Fixture_getShape }, - { "isSensor", w_Fixture_isSensor }, - { "testPoint", w_Fixture_testPoint }, - { "rayCast", w_Fixture_rayCast }, - { "setFilterData", w_Fixture_setFilterData }, - { "getFilterData", w_Fixture_getFilterData }, - { "setCategory", w_Fixture_setCategory }, - { "getCategory", w_Fixture_getCategory }, - { "setMask", w_Fixture_setMask }, - { "getMask", w_Fixture_getMask }, - { "setUserData", w_Fixture_setUserData }, - { "getUserData", w_Fixture_getUserData }, - { "getBoundingBox", w_Fixture_getBoundingBox }, - { "getMassData", w_Fixture_getMassData }, - { "getGroupIndex", w_Fixture_getGroupIndex }, - { "setGroupIndex", w_Fixture_setGroupIndex }, - { "destroy", w_Fixture_destroy }, - { "isDestroyed", w_Fixture_isDestroyed }, - { 0, 0 } -}; - -extern "C" int luaopen_fixture(lua_State *L) -{ - return luax_register_type(L, &Fixture::type, w_Fixture_functions, nullptr); -} - -} // box2d -} // physics -} // love - diff --git a/src/modules/physics/box2d/wrap_Fixture.h b/src/modules/physics/box2d/wrap_Fixture.h deleted file mode 100644 index 0d31d6fa0..000000000 --- a/src/modules/physics/box2d/wrap_Fixture.h +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (c) 2006-2023 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -#ifndef LOVE_PHYSICS_BOX2D_WRAP_FIXTURE_H -#define LOVE_PHYSICS_BOX2D_WRAP_FIXTURE_H - -// LOVE -#include "common/runtime.h" -#include "Fixture.h" -#include "wrap_Physics.h" - -namespace love -{ -namespace physics -{ -namespace box2d -{ - -Fixture *luax_checkfixture(lua_State *L, int idx); -extern "C" int luaopen_fixture(lua_State *L); - -} // box2d -} // physics -} // love - -#endif // LOVE_PHYSICS_BOX2D_WRAP_FIXTURE_H diff --git a/src/modules/physics/box2d/wrap_Physics.cpp b/src/modules/physics/box2d/wrap_Physics.cpp index 7b755f92e..917cdf812 100644 --- a/src/modules/physics/box2d/wrap_Physics.cpp +++ b/src/modules/physics/box2d/wrap_Physics.cpp @@ -23,7 +23,6 @@ #include "wrap_World.h" #include "wrap_Contact.h" #include "wrap_Body.h" -#include "wrap_Fixture.h" #include "wrap_Shape.h" #include "wrap_CircleShape.h" #include "wrap_PolygonShape.h" @@ -256,36 +255,56 @@ int w_newChainBody(lua_State *L) int w_newFixture(lua_State *L) { + luax_markdeprecated(L, 1, "love.physics.newFixture", API_FUNCTION, DEPRECATED_REPLACED, "love.physics.newCircle/Rectangle/Polygon/Edge/ChainShape"); + Body *body = luax_checkbody(L, 1); Shape *shape = luax_checkshape(L, 2); float density = (float)luaL_optnumber(L, 3, 1.0f); - Fixture *fixture; - luax_catchexcept(L, [&](){ fixture = instance()->newFixture(body, shape, density); }); - luax_pushtype(L, fixture); - fixture->release(); + + Shape *newShape; + luax_catchexcept(L, [&]() { + newShape = instance()->newAttachedShape(body, shape, density); + newShape->setDensity(density); + body->resetMassData(); + }); + + luax_pushshape(L, newShape); + newShape->release(); return 1; } +static Body *luax_optbodyforshape(lua_State *L, int idx, const char *name) +{ + if (luax_istype(L, idx, Body::type)) + return luax_checkbody(L, idx); + + luax_markdeprecated(L, 1, name, API_FUNCTION_VARIANT, DEPRECATED_REPLACED, "variant with Body parameter"); + return nullptr; +} + int w_newCircleShape(lua_State *L) { - int top = lua_gettop(L); + Body *body = luax_optbodyforshape(L, 1, "love.physics.newCircleShape"); + int bodyidx = body ? 1 : 0; + + int top = lua_gettop(L) - bodyidx; if (top == 1) { - float radius = (float)luaL_checknumber(L, 1); + float radius = (float)luaL_checknumber(L, bodyidx + 1); CircleShape *shape; - luax_catchexcept(L, [&](){ shape = instance()->newCircleShape(0, 0, radius); }); + luax_catchexcept(L, [&](){ shape = instance()->newCircleShape(body, 0, 0, radius); }); luax_pushtype(L, shape); shape->release(); return 1; } else if (top == 3) { - float x = (float)luaL_checknumber(L, 1); - float y = (float)luaL_checknumber(L, 2); - float radius = (float)luaL_checknumber(L, 3); + float x = (float)luaL_checknumber(L, bodyidx + 1); + float y = (float)luaL_checknumber(L, bodyidx + 2); + float radius = (float)luaL_checknumber(L, bodyidx + 3); CircleShape *shape; - luax_catchexcept(L, [&](){ shape = instance()->newCircleShape(x, y, radius); }); + luax_catchexcept(L, [&](){ shape = instance()->newCircleShape(body, x, y, radius); }); luax_pushtype(L, shape); shape->release(); return 1; @@ -296,27 +315,30 @@ int w_newCircleShape(lua_State *L) int w_newRectangleShape(lua_State *L) { - int top = lua_gettop(L); + Body *body = luax_optbodyforshape(L, 1, "love.physics.newRectangleShape"); + int bodyidx = body ? 1 : 0; + + int top = lua_gettop(L) - bodyidx; if (top == 2) { - float w = (float)luaL_checknumber(L, 1); - float h = (float)luaL_checknumber(L, 2); + float w = (float)luaL_checknumber(L, bodyidx + 1); + float h = (float)luaL_checknumber(L, bodyidx + 2); PolygonShape *shape; - luax_catchexcept(L, [&](){ shape = instance()->newRectangleShape(0, 0, w, h, 0); }); + luax_catchexcept(L, [&](){ shape = instance()->newRectangleShape(body, 0, 0, w, h, 0); }); luax_pushtype(L, shape); shape->release(); return 1; } else if (top == 4 || top == 5) { - float x = (float)luaL_checknumber(L, 1); - float y = (float)luaL_checknumber(L, 2); - float w = (float)luaL_checknumber(L, 3); - float h = (float)luaL_checknumber(L, 4); - float angle = (float)luaL_optnumber(L, 5, 0); + float x = (float)luaL_checknumber(L, bodyidx + 1); + float y = (float)luaL_checknumber(L, bodyidx + 2); + float w = (float)luaL_checknumber(L, bodyidx + 3); + float h = (float)luaL_checknumber(L, bodyidx + 4); + float angle = (float)luaL_optnumber(L, bodyidx + 5, 0); PolygonShape *shape; - luax_catchexcept(L, [&](){ shape = instance()->newRectangleShape(x, y, w, h, angle); }); + luax_catchexcept(L, [&](){ shape = instance()->newRectangleShape(body, x, y, w, h, angle); }); luax_pushtype(L, shape); shape->release(); return 1; @@ -327,13 +349,16 @@ int w_newRectangleShape(lua_State *L) int w_newEdgeShape(lua_State *L) { - 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); - bool oneSided = luax_optboolean(L, 5, false); + Body *body = luax_optbodyforshape(L, 1, "love.physics.newEdgeShape"); + int bodyidx = body ? 1 : 0; + + float x1 = (float)luaL_checknumber(L, bodyidx + 1); + float y1 = (float)luaL_checknumber(L, bodyidx + 2); + float x2 = (float)luaL_checknumber(L, bodyidx + 3); + float y2 = (float)luaL_checknumber(L, bodyidx + 4); + bool oneSided = luax_optboolean(L, bodyidx + 5, false); EdgeShape *shape; - luax_catchexcept(L, [&](){ shape = instance()->newEdgeShape(x1, y1, x2, y2, oneSided); }); + luax_catchexcept(L, [&](){ shape = instance()->newEdgeShape(body, x1, y1, x2, y2, oneSided); }); luax_pushtype(L, shape); shape->release(); return 1; @@ -341,12 +366,15 @@ int w_newEdgeShape(lua_State *L) int w_newPolygonShape(lua_State *L) { - int argc = lua_gettop(L); + Body *body = luax_optbodyforshape(L, 1, "love.physics.newPolygonShape"); + int bodyidx = body ? 1 : 0; - bool istable = lua_istable(L, 1); + int argc = lua_gettop(L) - bodyidx; + + bool istable = lua_istable(L, bodyidx + 1); if (istable) - argc = (int)luax_objlen(L, 1); + argc = (int)luax_objlen(L, bodyidx + 1); if (argc % 2 != 0) return luaL_error(L, "Number of vertex components must be a multiple of two."); @@ -358,8 +386,8 @@ int w_newPolygonShape(lua_State *L) { for (int i = 0; i < vcount; i++) { - lua_rawgeti(L, 1, 1 + i * 2); - lua_rawgeti(L, 1, 2 + i * 2); + lua_rawgeti(L, bodyidx + 1, 1 + i * 2); + lua_rawgeti(L, bodyidx + 1, 2 + i * 2); float x = (float)luaL_checknumber(L, -2); float y = (float)luaL_checknumber(L, -1); coords.emplace_back(x, y); @@ -370,14 +398,14 @@ int w_newPolygonShape(lua_State *L) { for (int i = 0; i < vcount; i++) { - float x = (float)luaL_checknumber(L, 1 + i * 2); - float y = (float)luaL_checknumber(L, 2 + i * 2); + float x = (float)luaL_checknumber(L, bodyidx + 1 + i * 2); + float y = (float)luaL_checknumber(L, bodyidx + 2 + i * 2); coords.emplace_back(x, y); } } PolygonShape *shape = nullptr; - luax_catchexcept(L, [&](){ shape = instance()->newPolygonShape(coords.data(), (int)coords.size()); }); + luax_catchexcept(L, [&](){ shape = instance()->newPolygonShape(body, coords.data(), (int)coords.size()); }); luax_pushtype(L, shape); shape->release(); return 1; @@ -385,26 +413,29 @@ int w_newPolygonShape(lua_State *L) int w_newChainShape(lua_State *L) { - int argc = lua_gettop(L) - 1; // first argument is looping + Body *body = luax_optbodyforshape(L, 1, "love.physics.newChainShape"); + int bodyidx = body ? 1 : 0; - bool istable = lua_istable(L, 2); + int argc = lua_gettop(L) - 1 - bodyidx; // first argument is looping + + bool istable = lua_istable(L, bodyidx + 2); if (istable) - argc = (int)luax_objlen(L, 2); + argc = (int)luax_objlen(L, bodyidx + 2); if (argc == 0 || argc % 2 != 0) return luaL_error(L, "Number of vertex components must be a multiple of two."); int vcount = argc / 2; - bool loop = luax_checkboolean(L, 1); + bool loop = luax_checkboolean(L, bodyidx + 1); std::vector coords; if (istable) { for (int i = 0; i < vcount; i++) { - lua_rawgeti(L, 2, 1 + i * 2); - lua_rawgeti(L, 2, 2 + i * 2); + lua_rawgeti(L, bodyidx + 2, 1 + i * 2); + lua_rawgeti(L, bodyidx + 2, 2 + i * 2); float x = (float)lua_tonumber(L, -2); float y = (float)lua_tonumber(L, -1); coords.emplace_back(x, y); @@ -415,14 +446,14 @@ int w_newChainShape(lua_State *L) { for (int i = 0; i < vcount; i++) { - float x = (float)luaL_checknumber(L, 2 + i * 2); - float y = (float)luaL_checknumber(L, 3 + i * 2); + float x = (float)luaL_checknumber(L, bodyidx + 2 + i * 2); + float y = (float)luaL_checknumber(L, bodyidx + 3 + i * 2); coords.emplace_back(x, y); } } ChainShape *shape = nullptr; - luax_catchexcept(L, [&]() { shape = instance()->newChainShape(loop, coords.data(), coords.size()); }); + luax_catchexcept(L, [&]() { shape = instance()->newChainShape(body, loop, coords.data(), coords.size()); }); luax_pushtype(L, shape); shape->release(); return 1; @@ -824,7 +855,6 @@ static const luaL_Reg functions[] = { "newPolygonBody", w_newPolygonBody }, { "newEdgeBody", w_newEdgeBody }, { "newChainBody", w_newChainBody }, - { "newFixture", w_newFixture }, { "newCircleShape", w_newCircleShape }, { "newRectangleShape", w_newRectangleShape }, { "newPolygonShape", w_newPolygonShape }, @@ -848,6 +878,10 @@ static const luaL_Reg functions[] = { "computeLinearFrequency", w_computeLinearFrequency }, { "computeAngularStiffness", w_computeAngularStiffness }, { "computeAngularFrequency", w_computeAngularFrequency }, + + // Deprecated + { "newFixture", w_newFixture }, + { 0, 0 }, }; @@ -856,7 +890,6 @@ static const lua_CFunction types[] = luaopen_world, luaopen_contact, luaopen_body, - luaopen_fixture, luaopen_shape, luaopen_circleshape, luaopen_polygonshape, diff --git a/src/modules/physics/box2d/wrap_PolygonShape.cpp b/src/modules/physics/box2d/wrap_PolygonShape.cpp index 522b1bf9f..e558f000e 100644 --- a/src/modules/physics/box2d/wrap_PolygonShape.cpp +++ b/src/modules/physics/box2d/wrap_PolygonShape.cpp @@ -36,13 +36,17 @@ int w_PolygonShape_getPoints(lua_State *L) { PolygonShape *t = luax_checkpolygonshape(L, 1); lua_remove(L, 1); - return t->getPoints(L); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->getPoints(L); }); + return ret; } int w_PolygonShape_validate(lua_State *L) { PolygonShape *t = luax_checkpolygonshape(L, 1); - luax_pushboolean(L, t->validate()); + bool valid = false; + luax_catchexcept(L, [&]() { valid = t->validate(); }); + luax_pushboolean(L, valid); return 1; } diff --git a/src/modules/physics/box2d/wrap_Shape.cpp b/src/modules/physics/box2d/wrap_Shape.cpp index 497f5d95f..7b32cac13 100644 --- a/src/modules/physics/box2d/wrap_Shape.cpp +++ b/src/modules/physics/box2d/wrap_Shape.cpp @@ -33,6 +33,35 @@ Shape *luax_checkshape(lua_State *L, int idx) return luax_checktype(L, idx); } +void luax_pushshape(lua_State *L, Shape *shape) +{ + if (shape != nullptr) + { + switch (shape->getType()) + { + case Shape::SHAPE_CIRCLE: + luax_pushtype(L, (CircleShape *) shape); + break; + case Shape::SHAPE_POLYGON: + luax_pushtype(L, (PolygonShape *) shape); + break; + case Shape::SHAPE_EDGE: + luax_pushtype(L, (EdgeShape *) shape); + break; + case Shape::SHAPE_CHAIN: + luax_pushtype(L, (ChainShape *) shape); + break; + default: + luax_pushtype(L, shape); + break; + } + } + else + { + lua_pushnil(L); + } +} + int w_Shape_getType(lua_State *L) { Shape *t = luax_checkshape(L, 1); @@ -45,7 +74,8 @@ int w_Shape_getType(lua_State *L) int w_Shape_getRadius(lua_State *L) { Shape *t = luax_checkshape(L, 1); - float radius = t->getRadius(); + float radius = 0; + luax_catchexcept(L, [&]() { radius = t->getRadius(); }); lua_pushnumber(L, radius); return 1; } @@ -53,20 +83,115 @@ int w_Shape_getRadius(lua_State *L) int w_Shape_getChildCount(lua_State *L) { Shape *t = luax_checkshape(L, 1); - int childCount = t->getChildCount(); + int childCount = 0; + luax_catchexcept(L, [&]() { childCount = t->getChildCount(); }); lua_pushinteger(L, childCount); return 1; } +int w_Shape_setFriction(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + float arg1 = (float)luaL_checknumber(L, 2); + luax_catchexcept(L, [&]() { t->setFriction(arg1); }); + return 0; +} + +int w_Shape_setRestitution(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + float arg1 = (float)luaL_checknumber(L, 2); + luax_catchexcept(L, [&]() { t->setRestitution(arg1); }); + return 0; +} + +int w_Shape_setDensity(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + float arg1 = (float)luaL_checknumber(L, 2); + luax_catchexcept(L, [&](){ t->setDensity(arg1); }); + return 0; +} + +int w_Shape_setSensor(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + bool arg1 = luax_checkboolean(L, 2); + luax_catchexcept(L, [&]() { t->setSensor(arg1); }); + return 0; +} + +int w_Shape_getFriction(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + float friction = 0; + luax_catchexcept(L, [&]() { friction = t->getFriction(); }); + lua_pushnumber(L, friction); + return 1; +} + +int w_Shape_getRestitution(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + float r = 0; + luax_catchexcept(L, [&]() { r = t->getRestitution(); }); + lua_pushnumber(L, r); + return 1; +} + +int w_Shape_getDensity(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + float d = 0; + luax_catchexcept(L, [&]() { d = t->getDensity(); }); + lua_pushnumber(L, d); + return 1; +} + +int w_Shape_isSensor(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + bool sensor = false; + luax_catchexcept(L, [&]() { sensor = t->isSensor(); }); + luax_pushboolean(L, sensor); + return 1; +} + +int w_Shape_getBody(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + Body *body = t->getBody(); + if (body == nullptr) + return 0; + luax_pushtype(L, body); + return 1; +} + +int w_Shape_getShape(lua_State *L) +{ + luax_markdeprecated(L, 1, "Fixture:getShape", API_METHOD, DEPRECATED_NO_REPLACEMENT, nullptr); + Shape *t = luax_checkshape(L, 1); + luax_pushshape(L, t); + return 1; +} + int w_Shape_testPoint(lua_State *L) { Shape *t = luax_checkshape(L, 1); float x = (float)luaL_checknumber(L, 2); float y = (float)luaL_checknumber(L, 3); - float r = (float)luaL_checknumber(L, 4); - float px = (float)luaL_checknumber(L, 5); - float py = (float)luaL_checknumber(L, 6); - bool result = t->testPoint(x, y, r, px, py); + bool result = false; + if (!lua_isnoneornil(L, 4)) + { + float r = (float)luaL_checknumber(L, 4); + float px = (float)luaL_checknumber(L, 5); + float py = (float)luaL_checknumber(L, 6); + result = luax_catchexcept(L, [&]() { t->testPoint(x, y, r, px, py); }); + } + else + { + result = luax_catchexcept(L, [&]() { t->testPoint(x, y); }); + } lua_pushboolean(L, result); return 1; } @@ -84,14 +209,143 @@ int w_Shape_computeAABB(lua_State *L) { Shape *t = luax_checkshape(L, 1); lua_remove(L, 1); - return t->computeAABB(L); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->computeAABB(L); }); + return ret; } int w_Shape_computeMass(lua_State *L) { Shape *t = luax_checkshape(L, 1); lua_remove(L, 1); - return t->computeMass(L); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->computeMass(L); }); + return ret; +} + +int w_Shape_setFilterData(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + int v[3]; + v[0] = (int) luaL_checkinteger(L, 2); + v[1] = (int) luaL_checkinteger(L, 3); + v[2] = (int) luaL_checkinteger(L, 4); + luax_catchexcept(L, [&]() { t->setFilterData(v); }); + return 0; +} + +int w_Shape_getFilterData(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + int v[3]; + luax_catchexcept(L, [&]() { t->getFilterData(v); }); + lua_pushinteger(L, v[0]); + lua_pushinteger(L, v[1]); + lua_pushinteger(L, v[2]); + return 3; +} + +int w_Shape_setCategory(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + lua_remove(L, 1); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->setCategory(L); }); + return ret; +} + +int w_Shape_getCategory(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + lua_remove(L, 1); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->getCategory(L); }); + return ret; +} + +int w_Shape_setMask(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + lua_remove(L, 1); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->setMask(L); }); + return ret; +} + +int w_Shape_getMask(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + lua_remove(L, 1); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->getMask(L); }); + return ret; +} + +int w_Shape_setUserData(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + lua_remove(L, 1); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->setUserData(L); }); + return ret; +} + +int w_Shape_getUserData(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + lua_remove(L, 1); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->getUserData(L); }); + return ret; +} + +int w_Shape_getBoundingBox(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + lua_remove(L, 1); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->getBoundingBox(L); }); + return ret; +} + +int w_Shape_getMassData(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + lua_remove(L, 1); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->getMassData(L); }); + return ret; +} + +int w_Shape_getGroupIndex(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + int i = 0; + luax_catchexcept(L, [&]() { i = t->getGroupIndex(); }); + lua_pushinteger(L, i); + return 1; +} + +int w_Shape_setGroupIndex(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + int i = (int) luaL_checkinteger(L, 2); + luax_catchexcept(L, [&]() { t->setGroupIndex(i); }); + return 0; +} + +int w_Shape_destroy(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + luax_catchexcept(L, [&](){ t->destroy(); }); + return 0; +} + +int w_Shape_isDestroyed(lua_State *L) +{ + Shape *f = luax_checktype(L, 1); + luax_pushboolean(L, !f->isValid()); + return 1; } const luaL_Reg w_Shape_functions[] = @@ -99,10 +353,33 @@ const luaL_Reg w_Shape_functions[] = { "getType", w_Shape_getType }, { "getRadius", w_Shape_getRadius }, { "getChildCount", w_Shape_getChildCount }, + { "setFriction", w_Shape_setFriction }, + { "setRestitution", w_Shape_setRestitution }, + { "setDensity", w_Shape_setDensity }, + { "setSensor", w_Shape_setSensor }, + { "getFriction", w_Shape_getFriction }, + { "getRestitution", w_Shape_getRestitution }, + { "getDensity", w_Shape_getDensity }, + { "getBody", w_Shape_getBody }, + { "isSensor", w_Shape_isSensor }, { "testPoint", w_Shape_testPoint }, { "rayCast", w_Shape_rayCast }, { "computeAABB", w_Shape_computeAABB }, { "computeMass", w_Shape_computeMass }, + { "setFilterData", w_Shape_setFilterData }, + { "getFilterData", w_Shape_getFilterData }, + { "setCategory", w_Shape_setCategory }, + { "getCategory", w_Shape_getCategory }, + { "setMask", w_Shape_setMask }, + { "getMask", w_Shape_getMask }, + { "setUserData", w_Shape_setUserData }, + { "getUserData", w_Shape_getUserData }, + { "getBoundingBox", w_Shape_getBoundingBox }, + { "getMassData", w_Shape_getMassData }, + { "getGroupIndex", w_Shape_getGroupIndex }, + { "setGroupIndex", w_Shape_setGroupIndex }, + { "destroy", w_Shape_destroy }, + { "isDestroyed", w_Shape_isDestroyed }, { 0, 0 } }; diff --git a/src/modules/physics/box2d/wrap_Shape.h b/src/modules/physics/box2d/wrap_Shape.h index e5cd01cbe..960945c1c 100644 --- a/src/modules/physics/box2d/wrap_Shape.h +++ b/src/modules/physics/box2d/wrap_Shape.h @@ -34,6 +34,7 @@ namespace box2d { Shape *luax_checkshape(lua_State *L, int idx); +void luax_pushshape(lua_State *L, Shape *shape); extern "C" int luaopen_shape(lua_State *L); extern const luaL_Reg w_Shape_functions[]; diff --git a/src/modules/physics/box2d/wrap_World.cpp b/src/modules/physics/box2d/wrap_World.cpp index b80b9ae65..1659374df 100644 --- a/src/modules/physics/box2d/wrap_World.cpp +++ b/src/modules/physics/box2d/wrap_World.cpp @@ -178,25 +178,25 @@ int w_World_getContacts(lua_State *L) return ret; } -int w_World_queryFixturesInArea(lua_State *L) +int w_World_queryShapesInArea(lua_State *L) { World *t = luax_checkworld(L, 1); lua_remove(L, 1); - return t->queryFixturesInArea(L); + return t->queryShapesInArea(L); } int w_World_queryBoundingBox(lua_State *L) { - luax_markdeprecated(L, 1, "World:queryBoundingBox", API_METHOD, DEPRECATED_RENAMED, "World:queryFixturesInArea"); - return w_World_queryFixturesInArea(L); + luax_markdeprecated(L, 1, "World:queryBoundingBox", API_METHOD, DEPRECATED_RENAMED, "World:queryShapesInArea"); + return w_World_queryShapesInArea(L); } -int w_World_getFixturesInArea(lua_State *L) +int w_World_getShapesInArea(lua_State *L) { World *t = luax_checkworld(L, 1); lua_remove(L, 1); int ret = 0; - luax_catchexcept(L, [&](){ ret = t->getFixturesInArea(L); }); + luax_catchexcept(L, [&](){ ret = t->getShapesInArea(L); }); return ret; } @@ -260,8 +260,8 @@ static const luaL_Reg w_World_functions[] = { "getBodies", w_World_getBodies }, { "getJoints", w_World_getJoints }, { "getContacts", w_World_getContacts }, - { "queryFixturesInArea", w_World_queryFixturesInArea }, - { "getFixturesInArea", w_World_getFixturesInArea }, + { "queryShapesInArea", w_World_queryShapesInArea }, + { "getShapesInArea", w_World_getShapesInArea }, { "rayCast", w_World_rayCast }, { "rayCastAny", w_World_rayCastAny }, { "rayCastClosest", w_World_rayCastClosest },