Browse Source

love.physics: simplify Body and Shape API.

#1130

- Shapes are now directly attached to Bodies when they're created (similar to love 0.7 and older).
- Fixtures are removed.
- All methods that were in Fixtures now exist in Shapes.
- All APIs that used or returned a Fixture now do the same with a Shape.

- Add new love.physics.new*Shape variants that take a Body as the first parameter.
- Deprecate the new*Shape APIs that don't take a Body.
- Deprecate love.physics.newFixture (the deprecated function now returns a Shape).
- Replace Body:getFixture and Body:getFixtures with Body:getShape and Body:getShapes (Body:getFixtures is deprecated).
- Replace World:queryFixturesInArea and World:getFixturesInArea with World:queryShapesInArea and World:getShapesInArea (queryFixturesInArea is deprecated).
- Replace Contact:getFixtures with Contact:getShapes (Contact:getFixtures is deprecated).
- Replace all love.physics callback Fixture parameters with Shape parameters.
- Deprecate ChainShape:getChildEdge.
Sasha Szpakowski 1 year ago
parent
commit
ac9ae82524
35 changed files with 1139 additions and 1238 deletions
  1. 0 4
      CMakeLists.txt
  2. 6 0
      src/common/deprecation.cpp
  3. 2 0
      src/common/deprecation.h
  4. 11 11
      src/modules/physics/box2d/Body.cpp
  5. 4 7
      src/modules/physics/box2d/Body.h
  6. 16 17
      src/modules/physics/box2d/ChainShape.cpp
  7. 1 1
      src/modules/physics/box2d/ChainShape.h
  8. 6 2
      src/modules/physics/box2d/CircleShape.cpp
  9. 1 1
      src/modules/physics/box2d/CircleShape.h
  10. 8 9
      src/modules/physics/box2d/Contact.cpp
  11. 2 2
      src/modules/physics/box2d/Contact.h
  12. 7 4
      src/modules/physics/box2d/EdgeShape.cpp
  13. 1 1
      src/modules/physics/box2d/EdgeShape.h
  14. 0 349
      src/modules/physics/box2d/Fixture.cpp
  15. 0 216
      src/modules/physics/box2d/Fixture.h
  16. 72 63
      src/modules/physics/box2d/Physics.cpp
  17. 16 19
      src/modules/physics/box2d/Physics.h
  18. 4 2
      src/modules/physics/box2d/PolygonShape.cpp
  19. 1 1
      src/modules/physics/box2d/PolygonShape.h
  20. 367 28
      src/modules/physics/box2d/Shape.cpp
  21. 127 5
      src/modules/physics/box2d/Shape.h
  22. 40 40
      src/modules/physics/box2d/World.cpp
  23. 7 8
      src/modules/physics/box2d/World.h
  24. 18 8
      src/modules/physics/box2d/wrap_Body.cpp
  25. 10 5
      src/modules/physics/box2d/wrap_ChainShape.cpp
  26. 5 3
      src/modules/physics/box2d/wrap_CircleShape.cpp
  27. 18 8
      src/modules/physics/box2d/wrap_Contact.cpp
  28. 9 5
      src/modules/physics/box2d/wrap_EdgeShape.cpp
  29. 0 311
      src/modules/physics/box2d/wrap_Fixture.cpp
  30. 0 43
      src/modules/physics/box2d/wrap_Fixture.h
  31. 80 47
      src/modules/physics/box2d/wrap_Physics.cpp
  32. 6 2
      src/modules/physics/box2d/wrap_PolygonShape.cpp
  33. 285 8
      src/modules/physics/box2d/wrap_Shape.cpp
  34. 1 0
      src/modules/physics/box2d/wrap_Shape.h
  35. 8 8
      src/modules/physics/box2d/wrap_World.cpp

+ 0 - 4
CMakeLists.txt

@@ -837,8 +837,6 @@ set(LOVE_SRC_MODULE_PHYSICS_BOX2D
 	src/modules/physics/box2d/DistanceJoint.h
 	src/modules/physics/box2d/DistanceJoint.h
 	src/modules/physics/box2d/EdgeShape.cpp
 	src/modules/physics/box2d/EdgeShape.cpp
 	src/modules/physics/box2d/EdgeShape.h
 	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.cpp
 	src/modules/physics/box2d/FrictionJoint.h
 	src/modules/physics/box2d/FrictionJoint.h
 	src/modules/physics/box2d/GearJoint.cpp
 	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_DistanceJoint.h
 	src/modules/physics/box2d/wrap_EdgeShape.cpp
 	src/modules/physics/box2d/wrap_EdgeShape.cpp
 	src/modules/physics/box2d/wrap_EdgeShape.h
 	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.cpp
 	src/modules/physics/box2d/wrap_FrictionJoint.h
 	src/modules/physics/box2d/wrap_FrictionJoint.h
 	src/modules/physics/box2d/wrap_GearJoint.cpp
 	src/modules/physics/box2d/wrap_GearJoint.cpp

+ 6 - 0
src/common/deprecation.cpp

@@ -107,8 +107,12 @@ std::string getDeprecationNotice(const DeprecationInfo &info, bool usewhere)
 
 
 	if (info.apiType == API_FUNCTION)
 	if (info.apiType == API_FUNCTION)
 		notice << "function ";
 		notice << "function ";
+	else if (info.apiType == API_FUNCTION_VARIANT)
+		notice << "function variant in ";
 	else if (info.apiType == API_METHOD)
 	else if (info.apiType == API_METHOD)
 		notice << "method ";
 		notice << "method ";
+	else if (info.apiType == API_METHOD_VARIANT)
+		notice << "method variant in ";
 	else if (info.apiType == API_CALLBACK)
 	else if (info.apiType == API_CALLBACK)
 		notice << "callback ";
 		notice << "callback ";
 	else if (info.apiType == API_FIELD)
 	else if (info.apiType == API_FIELD)
@@ -188,7 +192,9 @@ MarkDeprecated::~MarkDeprecated()
 STRINGMAP_BEGIN(APIType, API_MAX_ENUM, apiType)
 STRINGMAP_BEGIN(APIType, API_MAX_ENUM, apiType)
 {
 {
 	{ "function", API_FUNCTION },
 	{ "function", API_FUNCTION },
+	{ "functionvariant", API_FUNCTION_VARIANT },
 	{ "method",   API_METHOD   },
 	{ "method",   API_METHOD   },
+	{ "methodvariant", API_METHOD_VARIANT },
 	{ "callback", API_CALLBACK },
 	{ "callback", API_CALLBACK },
 	{ "field",    API_FIELD    },
 	{ "field",    API_FIELD    },
 	{ "constant", API_CONSTANT },
 	{ "constant", API_CONSTANT },

+ 2 - 0
src/common/deprecation.h

@@ -32,7 +32,9 @@ namespace love
 enum APIType
 enum APIType
 {
 {
 	API_FUNCTION,
 	API_FUNCTION,
+	API_FUNCTION_VARIANT,
 	API_METHOD,
 	API_METHOD,
+	API_METHOD_VARIANT,
 	API_CALLBACK,
 	API_CALLBACK,
 	API_FIELD,
 	API_FIELD,
 	API_CONSTANT,
 	API_CONSTANT,

+ 11 - 11
src/modules/physics/box2d/Body.cpp

@@ -23,12 +23,12 @@
 #include "common/math.h"
 #include "common/math.h"
 
 
 #include "Shape.h"
 #include "Shape.h"
-#include "Fixture.h"
 #include "World.h"
 #include "World.h"
 #include "Physics.h"
 #include "Physics.h"
 
 
 // Needed for luax_pushjoint.
 // Needed for luax_pushjoint.
 #include "wrap_Joint.h"
 #include "wrap_Joint.h"
+#include "wrap_Shape.h"
 
 
 namespace love
 namespace love
 {
 {
@@ -461,20 +461,20 @@ World *Body::getWorld() const
 	return world;
 	return world;
 }
 }
 
 
-Fixture *Body::getFixture() const
+Shape *Body::getShape() const
 {
 {
 	b2Fixture *f = body->GetFixtureList();
 	b2Fixture *f = body->GetFixtureList();
 	if (f == nullptr)
 	if (f == nullptr)
 		return 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);
 	lua_newtable(L);
 	b2Fixture *f = body->GetFixtureList();
 	b2Fixture *f = body->GetFixtureList();
@@ -483,10 +483,10 @@ int Body::getFixtures(lua_State *L) const
 	{
 	{
 		if (!f)
 		if (!f)
 			break;
 			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);
 		lua_rawseti(L, -2, i);
 		i++;
 		i++;
 	}
 	}

+ 4 - 7
src/modules/physics/box2d/Body.h

@@ -39,7 +39,6 @@ namespace box2d
 // Forward declarations.
 // Forward declarations.
 class World;
 class World;
 class Shape;
 class Shape;
-class Fixture;
 
 
 /**
 /**
  * A Body is an entity which has position and orientation
  * A Body is an entity which has position and orientation
@@ -57,7 +56,6 @@ public:
 	friend class CircleShape;
 	friend class CircleShape;
 	friend class PolygonShape;
 	friend class PolygonShape;
 	friend class Shape;
 	friend class Shape;
-	friend class Fixture;
 
 
 	// Public because joints et al ask for b2body
 	// Public because joints et al ask for b2body
 	b2Body *body;
 	b2Body *body;
@@ -391,15 +389,14 @@ public:
 	World *getWorld() const;
 	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.
 	 * Get an array of all Joints attached to this Body.

+ 16 - 17
src/modules/physics/box2d/ChainShape.cpp

@@ -34,8 +34,8 @@ namespace box2d
 
 
 love::Type ChainShape::type("ChainShape", &Shape::type);
 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)
 void ChainShape::setNextVertex(float x, float y)
 {
 {
+	throwIfShapeNotValid();
 	b2Vec2 v(x, y);
 	b2Vec2 v(x, y);
 	b2ChainShape *c = (b2ChainShape *)shape;
 	b2ChainShape *c = (b2ChainShape *)shape;
 	c->m_nextVertex = Physics::scaleDown(v);
 	c->m_nextVertex = Physics::scaleDown(v);
@@ -52,6 +53,7 @@ void ChainShape::setNextVertex(float x, float y)
 
 
 void ChainShape::setPreviousVertex(float x, float y)
 void ChainShape::setPreviousVertex(float x, float y)
 {
 {
+	throwIfShapeNotValid();
 	b2Vec2 v(x, y);
 	b2Vec2 v(x, y);
 	b2ChainShape *c = (b2ChainShape *)shape;
 	b2ChainShape *c = (b2ChainShape *)shape;
 	c->m_prevVertex = Physics::scaleDown(v);
 	c->m_prevVertex = Physics::scaleDown(v);
@@ -59,44 +61,40 @@ void ChainShape::setPreviousVertex(float x, float y)
 
 
 b2Vec2 ChainShape::getNextVertex() const
 b2Vec2 ChainShape::getNextVertex() const
 {
 {
+	throwIfShapeNotValid();
 	b2ChainShape *c = (b2ChainShape *)shape;
 	b2ChainShape *c = (b2ChainShape *)shape;
-
 	return Physics::scaleUp(c->m_nextVertex);
 	return Physics::scaleUp(c->m_nextVertex);
 }
 }
 
 
 b2Vec2 ChainShape::getPreviousVertex() const
 b2Vec2 ChainShape::getPreviousVertex() const
 {
 {
+	throwIfShapeNotValid();
 	b2ChainShape *c = (b2ChainShape *)shape;
 	b2ChainShape *c = (b2ChainShape *)shape;
-
 	return Physics::scaleUp(c->m_prevVertex);
 	return Physics::scaleUp(c->m_prevVertex);
 }
 }
 
 
 EdgeShape *ChainShape::getChildEdge(int index) const
 EdgeShape *ChainShape::getChildEdge(int index) const
 {
 {
+	throwIfShapeNotValid();
+
 	b2ChainShape *c = (b2ChainShape *)shape;
 	b2ChainShape *c = (b2ChainShape *)shape;
-	b2EdgeShape *e = new b2EdgeShape;
-
-	try
-	{
-		c->GetChildEdge(e, index);
-	}
-	catch (love::Exception &)
-	{
-		delete e;
-		throw;
-	}
-
-	return new EdgeShape(e, true);
+
+	b2EdgeShape e;
+	c->GetChildEdge(&e, index);
+
+	return new EdgeShape(nullptr, e);
 }
 }
 
 
 int ChainShape::getVertexCount() const
 int ChainShape::getVertexCount() const
 {
 {
+	throwIfShapeNotValid();
 	b2ChainShape *c = (b2ChainShape *)shape;
 	b2ChainShape *c = (b2ChainShape *)shape;
 	return c->m_count;
 	return c->m_count;
 }
 }
 
 
 b2Vec2 ChainShape::getPoint(int index) const
 b2Vec2 ChainShape::getPoint(int index) const
 {
 {
+	throwIfShapeNotValid();
 	b2ChainShape *c = (b2ChainShape *)shape;
 	b2ChainShape *c = (b2ChainShape *)shape;
 	if (index < 0 || index >= c->m_count)
 	if (index < 0 || index >= c->m_count)
 		throw love::Exception("Physics error: index out of bounds");
 		throw love::Exception("Physics error: index out of bounds");
@@ -106,6 +104,7 @@ b2Vec2 ChainShape::getPoint(int index) const
 
 
 const b2Vec2 *ChainShape::getPoints() const
 const b2Vec2 *ChainShape::getPoints() const
 {
 {
+	throwIfShapeNotValid();
 	b2ChainShape *c = (b2ChainShape *)shape;
 	b2ChainShape *c = (b2ChainShape *)shape;
 	return c->m_vertices;
 	return c->m_vertices;
 }
 }

+ 1 - 1
src/modules/physics/box2d/ChainShape.h

@@ -45,7 +45,7 @@ public:
 	 * Create a new ChainShape from a Box2D chain shape.
 	 * Create a new ChainShape from a Box2D chain shape.
 	 * @param c The chain shape.
 	 * @param c The chain shape.
 	 **/
 	 **/
-	ChainShape(b2ChainShape *c, bool own = true);
+	ChainShape(Body *body, const b2ChainShape &c);
 
 
 	virtual ~ChainShape();
 	virtual ~ChainShape();
 
 

+ 6 - 2
src/modules/physics/box2d/CircleShape.cpp

@@ -34,8 +34,8 @@ namespace box2d
 
 
 love::Type CircleShape::type("CircleShape", &Shape::type);
 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
 float CircleShape::getRadius() const
 {
 {
+	throwIfShapeNotValid();
 	return Physics::scaleUp(shape->m_radius);
 	return Physics::scaleUp(shape->m_radius);
 }
 }
 
 
 void CircleShape::setRadius(float r)
 void CircleShape::setRadius(float r)
 {
 {
+	throwIfShapeNotValid();
 	shape->m_radius = Physics::scaleDown(r);
 	shape->m_radius = Physics::scaleDown(r);
 }
 }
 
 
 void CircleShape::getPoint(float &x_o, float &y_o) const
 void CircleShape::getPoint(float &x_o, float &y_o) const
 {
 {
+	throwIfShapeNotValid();
 	b2CircleShape *c = (b2CircleShape *) shape;
 	b2CircleShape *c = (b2CircleShape *) shape;
 	x_o = Physics::scaleUp(c->m_p.x);
 	x_o = Physics::scaleUp(c->m_p.x);
 	y_o = Physics::scaleUp(c->m_p.y);
 	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)
 void CircleShape::setPoint(float x, float y)
 {
 {
+	throwIfShapeNotValid();
 	b2CircleShape *c = (b2CircleShape *) shape;
 	b2CircleShape *c = (b2CircleShape *) shape;
 	c->m_p = Physics::scaleDown(b2Vec2(x, y));
 	c->m_p = Physics::scaleDown(b2Vec2(x, y));
 }
 }

+ 1 - 1
src/modules/physics/box2d/CircleShape.h

@@ -50,7 +50,7 @@ public:
 	 * Create a new CircleShape from the a Box2D CircleShape definition.
 	 * Create a new CircleShape from the a Box2D CircleShape definition.
 	 * @param c The CircleShape definition.
 	 * @param c The CircleShape definition.
 	 **/
 	 **/
-	CircleShape(b2CircleShape *c, bool own = true);
+	CircleShape(Body *body, const b2CircleShape &c);
 
 
 	virtual ~CircleShape();
 	virtual ~CircleShape();
 
 

+ 8 - 9
src/modules/physics/box2d/Contact.cpp

@@ -35,7 +35,6 @@ Contact::Contact(World *world, b2Contact *contact)
 	: contact(contact)
 	: contact(contact)
 	, world(world)
 	, world(world)
 {
 {
-	//contact->user
 	world->registerObject(contact, this);
 	world->registerObject(contact, this);
 }
 }
 
 
@@ -46,16 +45,16 @@ Contact::~Contact()
 
 
 void Contact::invalidate()
 void Contact::invalidate()
 {
 {
-	if (contact != NULL)
+	if (contact != nullptr)
 	{
 	{
 		world->unregisterObject(contact);
 		world->unregisterObject(contact);
-		contact = NULL;
+		contact = nullptr;
 	}
 	}
 }
 }
 
 
 bool Contact::isValid()
 bool Contact::isValid()
 {
 {
-	return contact != NULL;
+	return contact != nullptr;
 }
 }
 
 
 int Contact::getPositions(lua_State *L)
 int Contact::getPositions(lua_State *L)
@@ -144,13 +143,13 @@ void Contact::getChildren(int &childA, int &childB)
 	childB = contact->GetChildIndexB();
 	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
 } // box2d

+ 2 - 2
src/modules/physics/box2d/Contact.h

@@ -151,9 +151,9 @@ public:
 	void getChildren(int &childA, int &childB);
 	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:
 private:
 
 

+ 7 - 4
src/modules/physics/box2d/EdgeShape.cpp

@@ -34,8 +34,8 @@ namespace box2d
 
 
 love::Type EdgeShape::type("EdgeShape", &Shape::type);
 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)
 void EdgeShape::setNextVertex(float x, float y)
 {
 {
+	throwIfShapeNotValid();
 	b2EdgeShape *e = (b2EdgeShape *)shape;
 	b2EdgeShape *e = (b2EdgeShape *)shape;
 	b2Vec2 v(x, y);
 	b2Vec2 v(x, y);
 	e->m_vertex3 = Physics::scaleDown(v);
 	e->m_vertex3 = Physics::scaleDown(v);
@@ -52,13 +53,14 @@ void EdgeShape::setNextVertex(float x, float y)
 
 
 b2Vec2 EdgeShape::getNextVertex() const
 b2Vec2 EdgeShape::getNextVertex() const
 {
 {
+	throwIfShapeNotValid();
 	b2EdgeShape *e = (b2EdgeShape *)shape;
 	b2EdgeShape *e = (b2EdgeShape *)shape;
-
 	return Physics::scaleUp(e->m_vertex3);
 	return Physics::scaleUp(e->m_vertex3);
 }
 }
 
 
 void EdgeShape::setPreviousVertex(float x, float y)
 void EdgeShape::setPreviousVertex(float x, float y)
 {
 {
+	throwIfShapeNotValid();
 	b2EdgeShape *e = (b2EdgeShape *)shape;
 	b2EdgeShape *e = (b2EdgeShape *)shape;
 	b2Vec2 v(x, y);
 	b2Vec2 v(x, y);
 	e->m_vertex0 = Physics::scaleDown(v);
 	e->m_vertex0 = Physics::scaleDown(v);
@@ -66,13 +68,14 @@ void EdgeShape::setPreviousVertex(float x, float y)
 
 
 b2Vec2 EdgeShape::getPreviousVertex() const
 b2Vec2 EdgeShape::getPreviousVertex() const
 {
 {
+	throwIfShapeNotValid();
 	b2EdgeShape *e = (b2EdgeShape *)shape;
 	b2EdgeShape *e = (b2EdgeShape *)shape;
-
 	return Physics::scaleUp(e->m_vertex0);
 	return Physics::scaleUp(e->m_vertex0);
 }
 }
 
 
 int EdgeShape::getPoints(lua_State *L)
 int EdgeShape::getPoints(lua_State *L)
 {
 {
+	throwIfShapeNotValid();
 	b2EdgeShape *e = (b2EdgeShape *)shape;
 	b2EdgeShape *e = (b2EdgeShape *)shape;
 	b2Vec2 v1 = Physics::scaleUp(e->m_vertex1);
 	b2Vec2 v1 = Physics::scaleUp(e->m_vertex1);
 	b2Vec2 v2 = Physics::scaleUp(e->m_vertex2);
 	b2Vec2 v2 = Physics::scaleUp(e->m_vertex2);

+ 1 - 1
src/modules/physics/box2d/EdgeShape.h

@@ -45,7 +45,7 @@ public:
 	 * Create a new EdgeShape from a Box2D edge shape.
 	 * Create a new EdgeShape from a Box2D edge shape.
 	 * @param e The edge shape.
 	 * @param e The edge shape.
 	 **/
 	 **/
-	EdgeShape(b2EdgeShape *e, bool own = true);
+	EdgeShape(Body *body, const b2EdgeShape &e);
 
 
 	virtual ~EdgeShape();
 	virtual ~EdgeShape();
 
 

+ 0 - 349
src/modules/physics/box2d/Fixture.cpp

@@ -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 <bitset>
-
-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

+ 0 - 216
src/modules/physics/box2d/Fixture.h

@@ -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 <box2d/Box2D.h>
-
-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> shape;
-
-};
-
-} // box2d
-} // physics
-} // love
-
-#endif // LOVE_PHYSICS_BOX2D_FIXTURE_H

+ 72 - 63
src/modules/physics/box2d/Physics.cpp

@@ -35,6 +35,7 @@ namespace box2d
 float Physics::meter = Physics::DEFAULT_METER;
 float Physics::meter = Physics::DEFAULT_METER;
 
 
 Physics::Physics()
 Physics::Physics()
+	: blockAllocator()
 {
 {
 	meter = DEFAULT_METER;
 	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)
 Body *Physics::newCircleBody(World *world, Body::Type type, float x, float y, float radius)
 {
 {
 	StrongRef<Body> body(newBody(world, x, y, type), Acquire::NORETAIN);
 	StrongRef<Body> body(newBody(world, x, y, type), Acquire::NORETAIN);
-	StrongRef<CircleShape> shape(newCircleShape(0, 0, radius), Acquire::NORETAIN);
-	StrongRef<Fixture> fixture(newFixture(body, shape, 1.0f), Acquire::NORETAIN);
+	StrongRef<CircleShape> shape(newCircleShape(body, 0, 0, radius), Acquire::NORETAIN);
 	body->retain();
 	body->retain();
 	return body.get();
 	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)
 Body *Physics::newRectangleBody(World *world, Body::Type type, float x, float y, float w, float h, float angle)
 {
 {
 	StrongRef<Body> body(newBody(world, x, y, type), Acquire::NORETAIN);
 	StrongRef<Body> body(newBody(world, x, y, type), Acquire::NORETAIN);
-	StrongRef<PolygonShape> shape(newRectangleShape(0, 0, w, h, angle), Acquire::NORETAIN);
-	StrongRef<Fixture> fixture(newFixture(body, shape, 1.0f), Acquire::NORETAIN);
+	StrongRef<PolygonShape> shape(newRectangleShape(body, 0, 0, w, h, angle), Acquire::NORETAIN);
 	body->retain();
 	body->retain();
 	return body.get();
 	return body.get();
 }
 }
@@ -93,8 +92,7 @@ Body *Physics::newPolygonBody(World *world, Body::Type type, const Vector2 *coor
 		localcoords.push_back(coords[i] - origin);
 		localcoords.push_back(coords[i] - origin);
 
 
 	StrongRef<Body> body(newBody(world, origin.x, origin.y, type), Acquire::NORETAIN);
 	StrongRef<Body> body(newBody(world, origin.x, origin.y, type), Acquire::NORETAIN);
-	StrongRef<PolygonShape> shape(newPolygonShape(localcoords.data(), count), Acquire::NORETAIN);
-	StrongRef<Fixture> fixture(newFixture(body, shape, 1.0f), Acquire::NORETAIN);
+	StrongRef<PolygonShape> shape(newPolygonShape(body, localcoords.data(), count), Acquire::NORETAIN);
 	body->retain();
 	body->retain();
 	return body.get();
 	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 wx = (x2 - x1) / 2.0f;
 	float wy = (y2 - y1) / 2.0f;
 	float wy = (y2 - y1) / 2.0f;
 	StrongRef<Body> body(newBody(world, wx, wy, type), Acquire::NORETAIN);
 	StrongRef<Body> body(newBody(world, wx, wy, type), Acquire::NORETAIN);
-	StrongRef<EdgeShape> shape(newEdgeShape(x1 - wx, y1 - wy, x2 - wx, y2 - wy, oneSided), Acquire::NORETAIN);
-	StrongRef<Fixture> fixture(newFixture(body, shape, 1.0f), Acquire::NORETAIN);
+	StrongRef<EdgeShape> shape(newEdgeShape(body, x1 - wx, y1 - wy, x2 - wx, y2 - wy, oneSided), Acquire::NORETAIN);
 	body->retain();
 	body->retain();
 	return body.get();
 	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);
 		localcoords.push_back(coords[i] - origin);
 
 
 	StrongRef<Body> body(newBody(world, origin.x, origin.y, type), Acquire::NORETAIN);
 	StrongRef<Body> body(newBody(world, origin.x, origin.y, type), Acquire::NORETAIN);
-	StrongRef<ChainShape> shape(newChainShape(loop, localcoords.data(), count), Acquire::NORETAIN);
-	StrongRef<Fixture> fixture(newFixture(body, shape, 1.0f), Acquire::NORETAIN);
+	StrongRef<ChainShape> shape(newChainShape(body, loop, localcoords.data(), count), Acquire::NORETAIN);
 	body->retain();
 	body->retain();
 	return body.get();
 	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)
 	if (oneSided)
 	{
 	{
 		b2Vec2 v1 = Physics::scaleDown(b2Vec2(x1, y1));
 		b2Vec2 v1 = Physics::scaleDown(b2Vec2(x1, y1));
 		b2Vec2 v2 = Physics::scaleDown(b2Vec2(x2, y2));
 		b2Vec2 v2 = Physics::scaleDown(b2Vec2(x2, y2));
-		s->SetOneSided(v1, v1, v2, v2);
+		s.SetOneSided(v1, v1, v2, v2);
 	}
 	}
 	else
 	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
 	// 3 to 8 (b2_maxPolygonVertices) vertices
 	if (count < 3)
 	if (count < 3)
@@ -172,44 +200,28 @@ PolygonShape *Physics::newPolygonShape(const Vector2 *coords, int count)
 	for (int i = 0; i < count; i++)
 	for (int i = 0; i < count; i++)
 		vecs[i] = Physics::scaleDown(b2Vec2(coords[i].x, coords[i].y));
 		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<b2Vec2> vecs;
 	std::vector<b2Vec2> vecs;
 
 
 	for (int i = 0; i < count; i++)
 	for (int i = 0; i < count; i++)
 		vecs.push_back(Physics::scaleDown(b2Vec2(coords[i].x, coords[i].y)));
 		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)
 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);
 	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)
 int Physics::getDistance(lua_State *L)
 {
 {
-	Fixture *fixtureA = luax_checktype<Fixture>(L, 1);
-	Fixture *fixtureB = luax_checktype<Fixture>(L, 2);
+	Shape *shapeA = luax_checktype<Shape>(L, 1);
+	Shape *shapeB = luax_checktype<Shape>(L, 2);
 	b2DistanceProxy pA, pB;
 	b2DistanceProxy pA, pB;
 	b2DistanceInput i;
 	b2DistanceInput i;
 	b2DistanceOutput o;
 	b2DistanceOutput o;
@@ -304,12 +310,15 @@ int Physics::getDistance(lua_State *L)
 	c.count = 0;
 	c.count = 0;
 
 
 	luax_catchexcept(L, [&]() {
 	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.proxyA = pA;
 		i.proxyB = pB;
 		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;
 		i.useRadii = true;
 		b2Distance(&o, &c, &i);
 		b2Distance(&o, &c, &i);
 	});
 	});

+ 16 - 19
src/modules/physics/box2d/Physics.h

@@ -28,7 +28,6 @@
 #include "World.h"
 #include "World.h"
 #include "Contact.h"
 #include "Contact.h"
 #include "Body.h"
 #include "Body.h"
-#include "Fixture.h"
 #include "Shape.h"
 #include "Shape.h"
 #include "CircleShape.h"
 #include "CircleShape.h"
 #include "PolygonShape.h"
 #include "PolygonShape.h"
@@ -95,9 +94,9 @@ public:
 	Body *newBody(World *world, Body::Type type);
 	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 *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);
 	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 *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);
 	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.
 	 * Creates a new CircleShape at (x,y) in local coordinates.
 	 * @param x The offset along the x-axis.
 	 * @param x The offset along the x-axis.
 	 * @param y The offset along the y-axis.
 	 * @param y The offset along the y-axis.
 	 * @param radius The radius of the circle.
 	 * @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
 	 * Shorthand for creating rectangular PolygonShapes. The rectangle
@@ -122,7 +124,7 @@ public:
 	 * @param h The height of the rectangle.
 	 * @param h The height of the rectangle.
 	 * @param angle The angle of the rectangle. (rad)
 	 * @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
 	 * 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 x2 The x coordinate of the second point.
 	 * @param y2 The y 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.
 	 * 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.
 	 * 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.
 	 * 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);
 	MotorJoint *newMotorJoint(Body *body1, Body *body2, float correctionFactor, bool collideConnected);
 	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.
 	 * Calculates the distance between two Fixtures.
 	 * @param fixtureA The first Fixture.
 	 * @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);
 	static void computeAngularFrequency(float &frequency, float &ratio, float stiffness, float damping, b2Body *bodyA, b2Body *bodyB);
 
 
+	b2BlockAllocator *getBlockAllocator() { return &blockAllocator; }
+
 private:
 private:
 
 
 	// The length of one meter in pixels.
 	// The length of one meter in pixels.
 	static float meter;
 	static float meter;
+
+	b2BlockAllocator blockAllocator;
+
 }; // Physics
 }; // Physics
 
 
 } // box2d
 } // box2d

+ 4 - 2
src/modules/physics/box2d/PolygonShape.cpp

@@ -34,8 +34,8 @@ namespace box2d
 
 
 love::Type PolygonShape::type("PolygonShape", &Shape::type);
 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)
 int PolygonShape::getPoints(lua_State *L)
 {
 {
+	throwIfShapeNotValid();
 	love::luax_assert_argc(L, 0);
 	love::luax_assert_argc(L, 0);
 	b2PolygonShape *p = (b2PolygonShape *)shape;
 	b2PolygonShape *p = (b2PolygonShape *)shape;
 	int count = p->m_count;
 	int count = p->m_count;
@@ -59,6 +60,7 @@ int PolygonShape::getPoints(lua_State *L)
 
 
 bool PolygonShape::validate() const
 bool PolygonShape::validate() const
 {
 {
+	throwIfShapeNotValid();
 	b2PolygonShape *p = (b2PolygonShape *)shape;
 	b2PolygonShape *p = (b2PolygonShape *)shape;
 	return p->Validate();
 	return p->Validate();
 }
 }

+ 1 - 1
src/modules/physics/box2d/PolygonShape.h

@@ -48,7 +48,7 @@ public:
 	 * Create a new PolygonShape from a Box2D polygon definition.
 	 * Create a new PolygonShape from a Box2D polygon definition.
 	 * @param p The polygon definition.
 	 * @param p The polygon definition.
 	 **/
 	 **/
-	PolygonShape(b2PolygonShape *p, bool own = true);
+	PolygonShape(Body *body, const b2PolygonShape &p);
 
 
 	virtual ~PolygonShape();
 	virtual ~PolygonShape();
 
 

+ 367 - 28
src/modules/physics/box2d/Shape.cpp

@@ -35,54 +35,348 @@ namespace physics
 namespace box2d
 namespace box2d
 {
 {
 
 
-Shape::Shape()
+Shape::Shape(Body *body, const b2Shape &shape)
 	: shape(nullptr)
 	: shape(nullptr)
 	, own(false)
 	, 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<Physics>(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()
 Shape::~Shape()
 {
 {
 	if (shape && own)
 	if (shape && own)
-		delete shape;
-	shape = nullptr;
+	{
+		auto physics = Module::getInstance<Physics>(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;
 }
 }
 
 
-Shape::Type Shape::getType() const
+void Shape::destroy(bool implicit)
 {
 {
-	switch (shape->GetType())
+	if (fixture == nullptr)
+		return;
+
+	if (body->world->world->IsLocked())
 	{
 	{
-	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;
+		// 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
+{
+	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
 float Shape::getRadius() const
 {
 {
+	throwIfShapeNotValid();
 	return Physics::scaleUp(shape->m_radius);
 	return Physics::scaleUp(shape->m_radius);
 }
 }
 
 
 int Shape::getChildCount() const
 int Shape::getChildCount() const
 {
 {
+	throwIfShapeNotValid();
 	return shape->GetChildCount();
 	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
 bool Shape::testPoint(float x, float y, float r, float px, float py) const
 {
 {
+	throwIfShapeNotValid();
 	b2Vec2 point(px, py);
 	b2Vec2 point(px, py);
 	b2Transform transform(Physics::scaleDown(b2Vec2(x, y)), b2Rot(r));
 	b2Transform transform(Physics::scaleDown(b2Vec2(x, y)), b2Rot(r));
 	return shape->TestPoint(transform, Physics::scaleDown(point));
 	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 p2x = Physics::scaleDown((float)luaL_checknumber(L, 3));
 	float p2y = Physics::scaleDown((float)luaL_checknumber(L, 4));
 	float p2y = Physics::scaleDown((float)luaL_checknumber(L, 4));
 	float maxFraction = (float)luaL_checknumber(L, 5);
 	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;
 	b2RayCastInput input;
+	b2RayCastOutput output;
 	input.p1.Set(p1x, p1y);
 	input.p1.Set(p1x, p1y);
 	input.p2.Set(p2x, p2y);
 	input.p2.Set(p2x, p2y);
 	input.maxFraction = maxFraction;
 	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.x);
 	lua_pushnumber(L, output.normal.y);
 	lua_pushnumber(L, output.normal.y);
 	lua_pushnumber(L, output.fraction);
 	lua_pushnumber(L, output.fraction);
@@ -115,6 +425,7 @@ int Shape::rayCast(lua_State *L) const
 
 
 int Shape::computeAABB(lua_State *L) const
 int Shape::computeAABB(lua_State *L) const
 {
 {
+	throwIfShapeNotValid();
 	float x = Physics::scaleDown((float)luaL_checknumber(L, 1));
 	float x = Physics::scaleDown((float)luaL_checknumber(L, 1));
 	float y = Physics::scaleDown((float)luaL_checknumber(L, 2));
 	float y = Physics::scaleDown((float)luaL_checknumber(L, 2));
 	float r = (float)luaL_checknumber(L, 3);
 	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
 int Shape::computeMass(lua_State *L) const
 {
 {
+	throwIfShapeNotValid();
 	float density = (float)luaL_checknumber(L, 1);
 	float density = (float)luaL_checknumber(L, 1);
 	b2MassData data;
 	b2MassData data;
 	shape->ComputeMass(&data, density);
 	shape->ComputeMass(&data, density);
@@ -143,6 +455,33 @@ int Shape::computeMass(lua_State *L) const
 	return 4;
 	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
 } // box2d
 } // physics
 } // physics
 } // love
 } // love

+ 127 - 5
src/modules/physics/box2d/Shape.h

@@ -24,6 +24,7 @@
 // LOVE
 // LOVE
 #include "physics/Shape.h"
 #include "physics/Shape.h"
 #include "physics/box2d/Body.h"
 #include "physics/box2d/Body.h"
+#include "common/Reference.h"
 
 
 // Box2D
 // Box2D
 #include <box2d/Box2D.h>
 #include <box2d/Box2D.h>
@@ -45,34 +46,155 @@ class Shape : public love::physics::Shape
 {
 {
 public:
 public:
 
 
-	friend class Fixture;
+	friend class Physics;
 
 
 	/**
 	/**
 	 * Creates a Shape.
 	 * Creates a Shape.
 	 **/
 	 **/
-	Shape();
-	Shape(b2Shape *shape, bool own = true);
+	Shape(Body *body, const b2Shape &shape);
 
 
 	virtual ~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
 	 * Gets the type of Shape. Useful for
 	 * debug drawing.
 	 * debug drawing.
 	 **/
 	 **/
 	Type getType() const;
 	Type getType() const;
+
 	float getRadius() const;
 	float getRadius() const;
 	int getChildCount() const;
 	int getChildCount() const;
-	bool testPoint(float x, float y, float r, float px, float py) const;
 	int rayCast(lua_State *L) const;
 	int rayCast(lua_State *L) const;
 	int computeAABB(lua_State *L) const;
 	int computeAABB(lua_State *L) const;
 	int computeMass(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:
 protected:
 
 
 	// The Box2D shape.
 	// The Box2D shape.
 	b2Shape *shape;
 	b2Shape *shape;
 	bool own;
 	bool own;
-};
+
+	Shape::Type shapeType;
+
+	Body *body;
+	b2Fixture *fixture;
+
+	// Reference to arbitrary data.
+	Reference* ref = nullptr;
+
+}; // Shape
 
 
 } // box2d
 } // box2d
 } // physics
 } // physics

+ 40 - 40
src/modules/physics/box2d/World.cpp

@@ -20,7 +20,6 @@
 
 
 #include "World.h"
 #include "World.h"
 
 
-#include "Fixture.h"
 #include "Shape.h"
 #include "Shape.h"
 #include "Contact.h"
 #include "Contact.h"
 #include "Physics.h"
 #include "Physics.h"
@@ -28,6 +27,7 @@
 
 
 // Needed for World::getJoints. It should be moved to wrapper code...
 // Needed for World::getJoints. It should be moved to wrapper code...
 #include "wrap_Joint.h"
 #include "wrap_Joint.h"
+#include "wrap_Shape.h"
 
 
 namespace love
 namespace love
 {
 {
@@ -58,22 +58,22 @@ void World::ContactCallback::process(b2Contact *contact, const b2ContactImpulse
 	{
 	{
 		ref->push(L);
 		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)
 			if (a != nullptr)
-				luax_pushtype(L, a);
+				luax_pushshape(L, a);
 			else
 			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)
 			if (b != nullptr)
-				luax_pushtype(L, b);
+				luax_pushshape(L, b);
 			else
 			else
-				throw love::Exception("A fixture has escaped Memoizer!");
+				throw love::Exception("A Shape has escaped Memoizer!");
 		}
 		}
 
 
 		Contact *cobj = (Contact *)world->findObject(contact);
 		Contact *cobj = (Contact *)world->findObject(contact);
@@ -112,7 +112,7 @@ World::ContactFilter::~ContactFilter()
 		delete ref;
 		delete ref;
 }
 }
 
 
-bool World::ContactFilter::process(Fixture *a, Fixture *b)
+bool World::ContactFilter::process(Shape *a, Shape *b)
 {
 {
 	// Handle masks, reimplemented from the manual
 	// Handle masks, reimplemented from the manual
 	int filterA[3], filterB[3];
 	int filterA[3], filterB[3];
@@ -133,8 +133,8 @@ bool World::ContactFilter::process(Fixture *a, Fixture *b)
 	if (ref != nullptr && L != nullptr)
 	if (ref != nullptr && L != nullptr)
 	{
 	{
 		ref->push(L);
 		ref->push(L);
-		luax_pushtype(L, a);
-		luax_pushtype(L, b);
+		luax_pushshape(L, a);
+		luax_pushshape(L, b);
 		lua_call(L, 2, 1);
 		lua_call(L, 2, 1);
 		return luax_toboolean(L, -1);
 		return luax_toboolean(L, -1);
 	}
 	}
@@ -159,10 +159,10 @@ bool World::QueryCallback::ReportFixture(b2Fixture *fixture)
 	if (L != nullptr)
 	if (L != nullptr)
 	{
 	{
 		lua_pushvalue(L, funcidx);
 		lua_pushvalue(L, funcidx);
-		Fixture *f = (Fixture *)(fixture->GetUserData().pointer);
+		Shape *f = (Shape *)(fixture->GetUserData().pointer);
 		if (!f)
 		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++)
 		for (int i = 1; i <= userargs; i++)
 			lua_pushvalue(L, funcidx + i);
 			lua_pushvalue(L, funcidx + i);
 		lua_call(L, 1 + userargs, 1);
 		lua_call(L, 1 + userargs, 1);
@@ -191,10 +191,10 @@ bool World::CollectCallback::ReportFixture(b2Fixture *f)
 	if (categoryMask != 0xFFFF && (categoryMask & f->GetFilterData().categoryBits) == 0)
 	if (categoryMask != 0xFFFF && (categoryMask & f->GetFilterData().categoryBits) == 0)
 		return true;
 		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);
 	lua_rawseti(L, -2, i);
 	i++;
 	i++;
 	return true;
 	return true;
@@ -218,10 +218,10 @@ float World::RayCastCallback::ReportFixture(b2Fixture *fixture, const b2Vec2 &po
 	if (L != nullptr)
 	if (L != nullptr)
 	{
 	{
 		lua_pushvalue(L, funcidx);
 		lua_pushvalue(L, funcidx);
-		Fixture *f = (Fixture *)(fixture->GetUserData().pointer);
+		Shape *f = (Shape *)(fixture->GetUserData().pointer);
 		if (!f)
 		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);
 		b2Vec2 scaledPoint = Physics::scaleUp(point);
 		lua_pushnumber(L, scaledPoint.x);
 		lua_pushnumber(L, scaledPoint.x);
 		lua_pushnumber(L, scaledPoint.y);
 		lua_pushnumber(L, scaledPoint.y);
@@ -267,9 +267,9 @@ float World::RayCastOneCallback::ReportFixture(b2Fixture *fixture, const b2Vec2
 
 
 void World::SayGoodbye(b2Fixture *fixture)
 void World::SayGoodbye(b2Fixture *fixture)
 {
 {
-	Fixture *f = (Fixture *)(fixture->GetUserData().pointer);
+	Shape *s = (Shape *)(fixture->GetUserData().pointer);
 	// Hint implicit destruction with true.
 	// Hint implicit destruction with true.
-	if (f) f->destroy(true);
+	if (s) s->destroy(true);
 }
 }
 
 
 void World::SayGoodbye(b2Joint *joint)
 void World::SayGoodbye(b2Joint *joint)
@@ -336,11 +336,11 @@ void World::update(float dt, int velocityIterations, int positionIterations)
 		// Release for reference in vector.
 		// Release for reference in vector.
 		b->release();
 		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.
 		// Release for reference in vector.
-		f->release();
+		s->release();
 	}
 	}
 	for (Joint *j : destructJoints)
 	for (Joint *j : destructJoints)
 	{
 	{
@@ -349,7 +349,7 @@ void World::update(float dt, int velocityIterations, int positionIterations)
 		j->release();
 		j->release();
 	}
 	}
 	destructBodies.clear();
 	destructBodies.clear();
-	destructFixtures.clear();
+	destructShapes.clear();
 	destructJoints.clear();
 	destructJoints.clear();
 
 
 	if (destructWorld)
 	if (destructWorld)
@@ -384,11 +384,11 @@ void World::PostSolve(b2Contact *contact, const b2ContactImpulse *impulse)
 
 
 bool World::ShouldCollide(b2Fixture *fixtureA, b2Fixture *fixtureB)
 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)
 	if (!a || !b)
-		throw love::Exception("A fixture has escaped Memoizer!");
+		throw love::Exception("A Shape has escaped Memoizer!");
 	return filter.process(a, b);
 	return filter.process(a, b);
 }
 }
 
 
@@ -597,7 +597,7 @@ b2Body *World::getGroundBody() const
 	return groundBody;
 	return groundBody;
 }
 }
 
 
-int World::queryFixturesInArea(lua_State *L)
+int World::queryShapesInArea(lua_State *L)
 {
 {
 	b2AABB box;
 	b2AABB box;
 	float lx = (float)luaL_checknumber(L, 1);
 	float lx = (float)luaL_checknumber(L, 1);
@@ -612,7 +612,7 @@ int World::queryFixturesInArea(lua_State *L)
 	return 0;
 	return 0;
 }
 }
 
 
-int World::getFixturesInArea(lua_State *L)
+int World::getShapesInArea(lua_State *L)
 {
 {
 	float lx = (float)luaL_checknumber(L, 1);
 	float lx = (float)luaL_checknumber(L, 1);
 	float ly = (float)luaL_checknumber(L, 2);
 	float ly = (float)luaL_checknumber(L, 2);
@@ -654,10 +654,10 @@ int World::rayCastAny(lua_State *L)
 	world->RayCast(&raycast, v1, v2);
 	world->RayCast(&raycast, v1, v2);
 	if (raycast.hitFixture)
 	if (raycast.hitFixture)
 	{
 	{
-		Fixture *f = (Fixture *)(raycast.hitFixture->GetUserData().pointer);
+		Shape *f = (Shape *)(raycast.hitFixture->GetUserData().pointer);
 		if (f == nullptr)
 		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);
 		b2Vec2 hitPoint = Physics::scaleUp(raycast.hitPoint);
 		lua_pushnumber(L, hitPoint.x);
 		lua_pushnumber(L, hitPoint.x);
@@ -683,10 +683,10 @@ int World::rayCastClosest(lua_State *L)
 	world->RayCast(&raycast, v1, v2);
 	world->RayCast(&raycast, v1, v2);
 	if (raycast.hitFixture)
 	if (raycast.hitFixture)
 	{
 	{
-		Fixture *f = (Fixture *)(raycast.hitFixture->GetUserData().pointer);
+		Shape *f = (Shape *)(raycast.hitFixture->GetUserData().pointer);
 		if (f == nullptr)
 		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);
 		b2Vec2 hitPoint = Physics::scaleUp(raycast.hitPoint);
 		lua_pushnumber(L, hitPoint.x);
 		lua_pushnumber(L, hitPoint.x);

+ 7 - 8
src/modules/physics/box2d/World.h

@@ -42,7 +42,6 @@ namespace box2d
 
 
 class Contact;
 class Contact;
 class Body;
 class Body;
-class Fixture;
 class Joint;
 class Joint;
 
 
 /**
 /**
@@ -65,7 +64,7 @@ public:
 	friend class DistanceJoint;
 	friend class DistanceJoint;
 	friend class MouseJoint;
 	friend class MouseJoint;
 	friend class Body;
 	friend class Body;
-	friend class Fixture;
+	friend class Shape;
 
 
 	static love::Type type;
 	static love::Type type;
 
 
@@ -87,7 +86,7 @@ public:
 		lua_State *L;
 		lua_State *L;
 		ContactFilter();
 		ContactFilter();
 		~ContactFilter();
 		~ContactFilter();
-		bool process(Fixture *a, Fixture *b);
+		bool process(Shape *a, Shape *b);
 	};
 	};
 
 
 	class QueryCallback : public b2QueryCallback
 	class QueryCallback : public b2QueryCallback
@@ -302,14 +301,14 @@ public:
 	b2Body *getGroundBody() const;
 	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.
 	 * Raycasts the World for all Fixtures in the path of the ray.
@@ -338,7 +337,7 @@ private:
 
 
 	// The list of to be destructed bodies.
 	// The list of to be destructed bodies.
 	std::vector<Body *> destructBodies;
 	std::vector<Body *> destructBodies;
-	std::vector<Fixture *> destructFixtures;
+	std::vector<Shape *> destructShapes;
 	std::vector<Joint *> destructJoints;
 	std::vector<Joint *> destructJoints;
 	bool destructWorld;
 	bool destructWorld;
 
 

+ 18 - 8
src/modules/physics/box2d/wrap_Body.cpp

@@ -20,6 +20,7 @@
 
 
 #include "wrap_Body.h"
 #include "wrap_Body.h"
 #include "wrap_Physics.h"
 #include "wrap_Physics.h"
+#include "wrap_Shape.h"
 
 
 namespace love
 namespace love
 {
 {
@@ -599,26 +600,32 @@ int w_Body_getWorld(lua_State *L)
 	return 1;
 	return 1;
 }
 }
 
 
-int w_Body_getFixture(lua_State *L)
+int w_Body_getShape(lua_State *L)
 {
 {
 	Body *t = luax_checkbody(L, 1);
 	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
 	else
 		lua_pushnil(L);
 		lua_pushnil(L);
 	return 1;
 	return 1;
 }
 }
 
 
-int w_Body_getFixtures(lua_State *L)
+int w_Body_getShapes(lua_State *L)
 {
 {
 	Body *t = luax_checkbody(L, 1);
 	Body *t = luax_checkbody(L, 1);
 	lua_remove(L, 1);
 	lua_remove(L, 1);
 	int n = 0;
 	int n = 0;
-	luax_catchexcept(L, [&](){ n = t->getFixtures(L); });
+	luax_catchexcept(L, [&](){ n = t->getShapes(L); });
 	return n;
 	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)
 int w_Body_getJoints(lua_State *L)
 {
 {
 	Body *t = luax_checkbody(L, 1);
 	Body *t = luax_checkbody(L, 1);
@@ -724,8 +731,8 @@ static const luaL_Reg w_Body_functions[] =
 	{ "isFixedRotation", w_Body_isFixedRotation },
 	{ "isFixedRotation", w_Body_isFixedRotation },
 	{ "isTouching", w_Body_isTouching },
 	{ "isTouching", w_Body_isTouching },
 	{ "getWorld", w_Body_getWorld },
 	{ "getWorld", w_Body_getWorld },
-	{ "getFixture", w_Body_getFixture },
-	{ "getFixtures", w_Body_getFixtures },
+	{ "getShape", w_Body_getShape },
+	{ "getShapes", w_Body_getShapes },
 	{ "getJoints", w_Body_getJoints },
 	{ "getJoints", w_Body_getJoints },
 	{ "getContacts", w_Body_getContacts },
 	{ "getContacts", w_Body_getContacts },
 	{ "destroy", w_Body_destroy },
 	{ "destroy", w_Body_destroy },
@@ -733,6 +740,9 @@ static const luaL_Reg w_Body_functions[] =
 	{ "setUserData", w_Body_setUserData },
 	{ "setUserData", w_Body_setUserData },
 	{ "getUserData", w_Body_getUserData },
 	{ "getUserData", w_Body_getUserData },
 
 
+	// Deprecated
+	{ "getFixtures", w_Body_getFixtures },
+
 	{ 0, 0 }
 	{ 0, 0 }
 };
 };
 
 

+ 10 - 5
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)
 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);
 	ChainShape *c = luax_checkchainshape(L, 1);
 	int index = (int) luaL_checkinteger(L, 2) - 1; // Convert from 1-based index
 	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_catchexcept(L, [&](){ e = c->getChildEdge(index); });
 	luax_pushtype(L, e);
 	luax_pushtype(L, e);
 	e->release();
 	e->release();
@@ -66,7 +67,8 @@ int w_ChainShape_getChildEdge(lua_State *L)
 int w_ChainShape_getVertexCount(lua_State *L)
 int w_ChainShape_getVertexCount(lua_State *L)
 {
 {
 	ChainShape *c = luax_checkchainshape(L, 1);
 	ChainShape *c = luax_checkchainshape(L, 1);
-	int count = c->getVertexCount();
+	int count = 0;
+	luax_catchexcept(L, [&]() { count = c->getVertexCount(); });
 	lua_pushinteger(L, count);
 	lua_pushinteger(L, count);
 	return 1;
 	return 1;
 }
 }
@@ -85,7 +87,8 @@ int w_ChainShape_getPoint(lua_State *L)
 int w_ChainShape_getNextVertex(lua_State *L)
 int w_ChainShape_getNextVertex(lua_State *L)
 {
 {
 	ChainShape *c = luax_checkchainshape(L, 1);
 	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.x);
 	lua_pushnumber(L, v.y);
 	lua_pushnumber(L, v.y);
 	return 2;
 	return 2;
@@ -94,7 +97,8 @@ int w_ChainShape_getNextVertex(lua_State *L)
 int w_ChainShape_getPreviousVertex(lua_State *L)
 int w_ChainShape_getPreviousVertex(lua_State *L)
 {
 {
 	ChainShape *c = luax_checkchainshape(L, 1);
 	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.x);
 	lua_pushnumber(L, v.y);
 	lua_pushnumber(L, v.y);
 	return 2;
 	return 2;
@@ -103,7 +107,8 @@ int w_ChainShape_getPreviousVertex(lua_State *L)
 int w_ChainShape_getPoints(lua_State *L)
 int w_ChainShape_getPoints(lua_State *L)
 {
 {
 	ChainShape *c = luax_checkchainshape(L, 1);
 	ChainShape *c = luax_checkchainshape(L, 1);
-	const b2Vec2 *verts = c->getPoints();
+	const b2Vec2 *verts;
+	luax_catchexcept(L, [&]() { verts = c->getPoints(); });
 	int count = c->getVertexCount();
 	int count = c->getVertexCount();
 	if (!lua_checkstack(L, count*2))
 	if (!lua_checkstack(L, count*2))
 		return luaL_error(L, "Too many return values");
 		return luaL_error(L, "Too many return values");

+ 5 - 3
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)
 int w_CircleShape_getRadius(lua_State *L)
 {
 {
 	CircleShape *c = luax_checkcircleshape(L, 1);
 	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;
 	return 1;
 }
 }
 
 
@@ -43,7 +45,7 @@ int w_CircleShape_setRadius(lua_State *L)
 {
 {
 	CircleShape *c = luax_checkcircleshape(L, 1);
 	CircleShape *c = luax_checkcircleshape(L, 1);
 	float r = (float)luaL_checknumber(L, 2);
 	float r = (float)luaL_checknumber(L, 2);
-	c->setRadius(r);
+	luax_catchexcept(L, [&]() { c->setRadius(r); });
 	return 0;
 	return 0;
 }
 }
 
 
@@ -51,7 +53,7 @@ int w_CircleShape_getPoint(lua_State *L)
 {
 {
 	CircleShape *c = luax_checkcircleshape(L, 1);
 	CircleShape *c = luax_checkcircleshape(L, 1);
 	float x, y;
 	float x, y;
-	c->getPoint(x, y);
+	luax_catchexcept(L, [&]() { c->getPoint(x, y); });
 	lua_pushnumber(L, x);
 	lua_pushnumber(L, x);
 	lua_pushnumber(L, y);
 	lua_pushnumber(L, y);
 	return 2;
 	return 2;

+ 18 - 8
src/modules/physics/box2d/wrap_Contact.cpp

@@ -19,7 +19,7 @@
  **/
  **/
 
 
 #include "wrap_Contact.h"
 #include "wrap_Contact.h"
-#include "Fixture.h"
+#include "wrap_Shape.h"
 
 
 namespace love
 namespace love
 {
 {
@@ -139,18 +139,24 @@ int w_Contact_getChildren(lua_State *L)
 	return 2;
 	return 2;
 }
 }
 
 
-int w_Contact_getFixtures(lua_State *L)
+int w_Contact_getShapes(lua_State *L)
 {
 {
 	Contact *t = luax_checkcontact(L, 1);
 	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;
 	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)
 int w_Contact_isDestroyed(lua_State *L)
 {
 {
 	Contact *c = luax_checktype<Contact>(L, 1);
 	Contact *c = luax_checktype<Contact>(L, 1);
@@ -174,8 +180,12 @@ static const luaL_Reg w_Contact_functions[] =
 	{ "setTangentSpeed", w_Contact_setTangentSpeed },
 	{ "setTangentSpeed", w_Contact_setTangentSpeed },
 	{ "getTangentSpeed", w_Contact_getTangentSpeed },
 	{ "getTangentSpeed", w_Contact_getTangentSpeed },
 	{ "getChildren", w_Contact_getChildren },
 	{ "getChildren", w_Contact_getChildren },
-	{ "getFixtures", w_Contact_getFixtures },
+	{ "getShapes", w_Contact_getShapes },
 	{ "isDestroyed", w_Contact_isDestroyed },
 	{ "isDestroyed", w_Contact_isDestroyed },
+
+	// Deprecated
+	{ "getFixtures", w_Contact_getFixtures },
+
 	{ 0, 0 }
 	{ 0, 0 }
 };
 };
 
 

+ 9 - 5
src/modules/physics/box2d/wrap_EdgeShape.cpp

@@ -37,7 +37,7 @@ int w_EdgeShape_setNextVertex(lua_State *L)
 	EdgeShape *t = luax_checkedgeshape(L, 1);
 	EdgeShape *t = luax_checkedgeshape(L, 1);
 	float x = (float)luaL_checknumber(L, 2);
 	float x = (float)luaL_checknumber(L, 2);
 	float y = (float)luaL_checknumber(L, 3);
 	float y = (float)luaL_checknumber(L, 3);
-	t->setNextVertex(x, y);
+	luax_catchexcept(L, [&]() { t->setNextVertex(x, y); });
 	return 0;
 	return 0;
 }
 }
 
 
@@ -46,14 +46,15 @@ int w_EdgeShape_setPreviousVertex(lua_State *L)
 	EdgeShape *t = luax_checkedgeshape(L, 1);
 	EdgeShape *t = luax_checkedgeshape(L, 1);
 	float x = (float)luaL_checknumber(L, 2);
 	float x = (float)luaL_checknumber(L, 2);
 	float y = (float)luaL_checknumber(L, 3);
 	float y = (float)luaL_checknumber(L, 3);
-	t->setPreviousVertex(x, y);
+	luax_catchexcept(L, [&]() { t->setPreviousVertex(x, y); });
 	return 0;
 	return 0;
 }
 }
 
 
 int w_EdgeShape_getNextVertex(lua_State *L)
 int w_EdgeShape_getNextVertex(lua_State *L)
 {
 {
 	EdgeShape *t = luax_checkedgeshape(L, 1);
 	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.x);
 	lua_pushnumber(L, v.y);
 	lua_pushnumber(L, v.y);
 	return 2;
 	return 2;
@@ -62,7 +63,8 @@ int w_EdgeShape_getNextVertex(lua_State *L)
 int w_EdgeShape_getPreviousVertex(lua_State *L)
 int w_EdgeShape_getPreviousVertex(lua_State *L)
 {
 {
 	EdgeShape *t = luax_checkedgeshape(L, 1);
 	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.x);
 	lua_pushnumber(L, v.y);
 	lua_pushnumber(L, v.y);
 	return 2;
 	return 2;
@@ -72,7 +74,9 @@ int w_EdgeShape_getPoints(lua_State *L)
 {
 {
 	EdgeShape *t = luax_checkedgeshape(L, 1);
 	EdgeShape *t = luax_checkedgeshape(L, 1);
 	lua_remove(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[] =
 static const luaL_Reg w_EdgeShape_functions[] =

+ 0 - 311
src/modules/physics/box2d/wrap_Fixture.cpp

@@ -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<Fixture>(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<EdgeShape *>(shape));
-		break;
-	case Shape::SHAPE_CHAIN:
-		luax_pushtype(L, dynamic_cast<ChainShape *>(shape));
-		break;
-	case Shape::SHAPE_CIRCLE:
-		luax_pushtype(L, dynamic_cast<CircleShape *>(shape));
-		break;
-	case Shape::SHAPE_POLYGON:
-		luax_pushtype(L, dynamic_cast<PolygonShape *>(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<Fixture>(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
-

+ 0 - 43
src/modules/physics/box2d/wrap_Fixture.h

@@ -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

+ 80 - 47
src/modules/physics/box2d/wrap_Physics.cpp

@@ -23,7 +23,6 @@
 #include "wrap_World.h"
 #include "wrap_World.h"
 #include "wrap_Contact.h"
 #include "wrap_Contact.h"
 #include "wrap_Body.h"
 #include "wrap_Body.h"
-#include "wrap_Fixture.h"
 #include "wrap_Shape.h"
 #include "wrap_Shape.h"
 #include "wrap_CircleShape.h"
 #include "wrap_CircleShape.h"
 #include "wrap_PolygonShape.h"
 #include "wrap_PolygonShape.h"
@@ -256,36 +255,56 @@ int w_newChainBody(lua_State *L)
 
 
 int w_newFixture(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);
 	Body *body = luax_checkbody(L, 1);
 	Shape *shape = luax_checkshape(L, 2);
 	Shape *shape = luax_checkshape(L, 2);
 	float density = (float)luaL_optnumber(L, 3, 1.0f);
 	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;
 	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 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)
 	if (top == 1)
 	{
 	{
-		float radius = (float)luaL_checknumber(L, 1);
+		float radius = (float)luaL_checknumber(L, bodyidx + 1);
 		CircleShape *shape;
 		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);
 		luax_pushtype(L, shape);
 		shape->release();
 		shape->release();
 		return 1;
 		return 1;
 	}
 	}
 	else if (top == 3)
 	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;
 		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);
 		luax_pushtype(L, shape);
 		shape->release();
 		shape->release();
 		return 1;
 		return 1;
@@ -296,27 +315,30 @@ int w_newCircleShape(lua_State *L)
 
 
 int w_newRectangleShape(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)
 	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;
 		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);
 		luax_pushtype(L, shape);
 		shape->release();
 		shape->release();
 		return 1;
 		return 1;
 	}
 	}
 	else if (top == 4 || top == 5)
 	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;
 		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);
 		luax_pushtype(L, shape);
 		shape->release();
 		shape->release();
 		return 1;
 		return 1;
@@ -327,13 +349,16 @@ int w_newRectangleShape(lua_State *L)
 
 
 int w_newEdgeShape(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;
 	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);
 	luax_pushtype(L, shape);
 	shape->release();
 	shape->release();
 	return 1;
 	return 1;
@@ -341,12 +366,15 @@ int w_newEdgeShape(lua_State *L)
 
 
 int w_newPolygonShape(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)
 	if (istable)
-		argc = (int)luax_objlen(L, 1);
+		argc = (int)luax_objlen(L, bodyidx + 1);
 
 
 	if (argc % 2 != 0)
 	if (argc % 2 != 0)
 		return luaL_error(L, "Number of vertex components must be a multiple of two.");
 		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++)
 		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 x = (float)luaL_checknumber(L, -2);
 			float y = (float)luaL_checknumber(L, -1);
 			float y = (float)luaL_checknumber(L, -1);
 			coords.emplace_back(x, y);
 			coords.emplace_back(x, y);
@@ -370,14 +398,14 @@ int w_newPolygonShape(lua_State *L)
 	{
 	{
 		for (int i = 0; i < vcount; i++)
 		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);
 			coords.emplace_back(x, y);
 		}
 		}
 	}
 	}
 
 
 	PolygonShape *shape = nullptr;
 	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);
 	luax_pushtype(L, shape);
 	shape->release();
 	shape->release();
 	return 1;
 	return 1;
@@ -385,26 +413,29 @@ int w_newPolygonShape(lua_State *L)
 
 
 int w_newChainShape(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;
+
+	int argc = lua_gettop(L) - 1 - bodyidx; // first argument is looping
 
 
-	bool istable = lua_istable(L, 2);
+	bool istable = lua_istable(L, bodyidx + 2);
 
 
 	if (istable)
 	if (istable)
-		argc = (int)luax_objlen(L, 2);
+		argc = (int)luax_objlen(L, bodyidx + 2);
 
 
 	if (argc == 0 || argc % 2 != 0)
 	if (argc == 0 || argc % 2 != 0)
 		return luaL_error(L, "Number of vertex components must be a multiple of two.");
 		return luaL_error(L, "Number of vertex components must be a multiple of two.");
 
 
 	int vcount = argc / 2;
 	int vcount = argc / 2;
-	bool loop = luax_checkboolean(L, 1);
+	bool loop = luax_checkboolean(L, bodyidx + 1);
 	std::vector<Vector2> coords;
 	std::vector<Vector2> coords;
 
 
 	if (istable)
 	if (istable)
 	{
 	{
 		for (int i = 0; i < vcount; i++)
 		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 x = (float)lua_tonumber(L, -2);
 			float y = (float)lua_tonumber(L, -1);
 			float y = (float)lua_tonumber(L, -1);
 			coords.emplace_back(x, y);
 			coords.emplace_back(x, y);
@@ -415,14 +446,14 @@ int w_newChainShape(lua_State *L)
 	{
 	{
 		for (int i = 0; i < vcount; i++)
 		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);
 			coords.emplace_back(x, y);
 		}
 		}
 	}
 	}
 
 
 	ChainShape *shape = nullptr;
 	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);
 	luax_pushtype(L, shape);
 	shape->release();
 	shape->release();
 	return 1;
 	return 1;
@@ -824,7 +855,6 @@ static const luaL_Reg functions[] =
 	{ "newPolygonBody", w_newPolygonBody },
 	{ "newPolygonBody", w_newPolygonBody },
 	{ "newEdgeBody", w_newEdgeBody },
 	{ "newEdgeBody", w_newEdgeBody },
 	{ "newChainBody", w_newChainBody },
 	{ "newChainBody", w_newChainBody },
-	{ "newFixture", w_newFixture },
 	{ "newCircleShape", w_newCircleShape },
 	{ "newCircleShape", w_newCircleShape },
 	{ "newRectangleShape", w_newRectangleShape },
 	{ "newRectangleShape", w_newRectangleShape },
 	{ "newPolygonShape", w_newPolygonShape },
 	{ "newPolygonShape", w_newPolygonShape },
@@ -848,6 +878,10 @@ static const luaL_Reg functions[] =
 	{ "computeLinearFrequency", w_computeLinearFrequency },
 	{ "computeLinearFrequency", w_computeLinearFrequency },
 	{ "computeAngularStiffness", w_computeAngularStiffness },
 	{ "computeAngularStiffness", w_computeAngularStiffness },
 	{ "computeAngularFrequency", w_computeAngularFrequency },
 	{ "computeAngularFrequency", w_computeAngularFrequency },
+
+	// Deprecated
+	{ "newFixture", w_newFixture },
+
 	{ 0, 0 },
 	{ 0, 0 },
 };
 };
 
 
@@ -856,7 +890,6 @@ static const lua_CFunction types[] =
 	luaopen_world,
 	luaopen_world,
 	luaopen_contact,
 	luaopen_contact,
 	luaopen_body,
 	luaopen_body,
-	luaopen_fixture,
 	luaopen_shape,
 	luaopen_shape,
 	luaopen_circleshape,
 	luaopen_circleshape,
 	luaopen_polygonshape,
 	luaopen_polygonshape,

+ 6 - 2
src/modules/physics/box2d/wrap_PolygonShape.cpp

@@ -36,13 +36,17 @@ int w_PolygonShape_getPoints(lua_State *L)
 {
 {
 	PolygonShape *t = luax_checkpolygonshape(L, 1);
 	PolygonShape *t = luax_checkpolygonshape(L, 1);
 	lua_remove(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)
 int w_PolygonShape_validate(lua_State *L)
 {
 {
 	PolygonShape *t = luax_checkpolygonshape(L, 1);
 	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;
 	return 1;
 }
 }
 
 

+ 285 - 8
src/modules/physics/box2d/wrap_Shape.cpp

@@ -33,6 +33,35 @@ Shape *luax_checkshape(lua_State *L, int idx)
 	return luax_checktype<Shape>(L, idx);
 	return luax_checktype<Shape>(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)
 int w_Shape_getType(lua_State *L)
 {
 {
 	Shape *t = luax_checkshape(L, 1);
 	Shape *t = luax_checkshape(L, 1);
@@ -45,7 +74,8 @@ int w_Shape_getType(lua_State *L)
 int w_Shape_getRadius(lua_State *L)
 int w_Shape_getRadius(lua_State *L)
 {
 {
 	Shape *t = luax_checkshape(L, 1);
 	Shape *t = luax_checkshape(L, 1);
-	float radius = t->getRadius();
+	float radius = 0;
+	luax_catchexcept(L, [&]() { radius = t->getRadius(); });
 	lua_pushnumber(L, radius);
 	lua_pushnumber(L, radius);
 	return 1;
 	return 1;
 }
 }
@@ -53,20 +83,115 @@ int w_Shape_getRadius(lua_State *L)
 int w_Shape_getChildCount(lua_State *L)
 int w_Shape_getChildCount(lua_State *L)
 {
 {
 	Shape *t = luax_checkshape(L, 1);
 	Shape *t = luax_checkshape(L, 1);
-	int childCount = t->getChildCount();
+	int childCount = 0;
+	luax_catchexcept(L, [&]() { childCount = t->getChildCount(); });
 	lua_pushinteger(L, childCount);
 	lua_pushinteger(L, childCount);
 	return 1;
 	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)
 int w_Shape_testPoint(lua_State *L)
 {
 {
 	Shape *t = luax_checkshape(L, 1);
 	Shape *t = luax_checkshape(L, 1);
 	float x = (float)luaL_checknumber(L, 2);
 	float x = (float)luaL_checknumber(L, 2);
 	float y = (float)luaL_checknumber(L, 3);
 	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);
 	lua_pushboolean(L, result);
 	return 1;
 	return 1;
 }
 }
@@ -84,14 +209,143 @@ int w_Shape_computeAABB(lua_State *L)
 {
 {
 	Shape *t = luax_checkshape(L, 1);
 	Shape *t = luax_checkshape(L, 1);
 	lua_remove(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)
 int w_Shape_computeMass(lua_State *L)
 {
 {
 	Shape *t = luax_checkshape(L, 1);
 	Shape *t = luax_checkshape(L, 1);
 	lua_remove(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<Shape>(L, 1);
+	luax_pushboolean(L, !f->isValid());
+	return 1;
 }
 }
 
 
 const luaL_Reg w_Shape_functions[] =
 const luaL_Reg w_Shape_functions[] =
@@ -99,10 +353,33 @@ const luaL_Reg w_Shape_functions[] =
 	{ "getType", w_Shape_getType },
 	{ "getType", w_Shape_getType },
 	{ "getRadius", w_Shape_getRadius },
 	{ "getRadius", w_Shape_getRadius },
 	{ "getChildCount", w_Shape_getChildCount },
 	{ "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 },
 	{ "testPoint", w_Shape_testPoint },
 	{ "rayCast", w_Shape_rayCast },
 	{ "rayCast", w_Shape_rayCast },
 	{ "computeAABB", w_Shape_computeAABB },
 	{ "computeAABB", w_Shape_computeAABB },
 	{ "computeMass", w_Shape_computeMass },
 	{ "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 }
 	{ 0, 0 }
 };
 };
 
 

+ 1 - 0
src/modules/physics/box2d/wrap_Shape.h

@@ -34,6 +34,7 @@ namespace box2d
 {
 {
 
 
 Shape *luax_checkshape(lua_State *L, int idx);
 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 "C" int luaopen_shape(lua_State *L);
 
 
 extern const luaL_Reg w_Shape_functions[];
 extern const luaL_Reg w_Shape_functions[];

+ 8 - 8
src/modules/physics/box2d/wrap_World.cpp

@@ -178,25 +178,25 @@ int w_World_getContacts(lua_State *L)
 	return ret;
 	return ret;
 }
 }
 
 
-int w_World_queryFixturesInArea(lua_State *L)
+int w_World_queryShapesInArea(lua_State *L)
 {
 {
 	World *t = luax_checkworld(L, 1);
 	World *t = luax_checkworld(L, 1);
 	lua_remove(L, 1);
 	lua_remove(L, 1);
-	return t->queryFixturesInArea(L);
+	return t->queryShapesInArea(L);
 }
 }
 
 
 int w_World_queryBoundingBox(lua_State *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);
 	World *t = luax_checkworld(L, 1);
 	lua_remove(L, 1);
 	lua_remove(L, 1);
 	int ret = 0;
 	int ret = 0;
-	luax_catchexcept(L, [&](){ ret = t->getFixturesInArea(L); });
+	luax_catchexcept(L, [&](){ ret = t->getShapesInArea(L); });
 	return ret;
 	return ret;
 }
 }
 
 
@@ -260,8 +260,8 @@ static const luaL_Reg w_World_functions[] =
 	{ "getBodies", w_World_getBodies },
 	{ "getBodies", w_World_getBodies },
 	{ "getJoints", w_World_getJoints },
 	{ "getJoints", w_World_getJoints },
 	{ "getContacts", w_World_getContacts },
 	{ "getContacts", w_World_getContacts },
-	{ "queryFixturesInArea", w_World_queryFixturesInArea },
-	{ "getFixturesInArea", w_World_getFixturesInArea },
+	{ "queryShapesInArea", w_World_queryShapesInArea },
+	{ "getShapesInArea", w_World_getShapesInArea },
 	{ "rayCast", w_World_rayCast },
 	{ "rayCast", w_World_rayCast },
 	{ "rayCastAny", w_World_rayCastAny },
 	{ "rayCastAny", w_World_rayCastAny },
 	{ "rayCastClosest", w_World_rayCastClosest },
 	{ "rayCastClosest", w_World_rayCastClosest },