Make love.math a singleton. Remove code duplication. Add love.math.triangulate.

love::math::Math is now a singleton, so other modules can use it via
love::math::Math::instance.


Removed duplicate implementations of various rng helper functions.
ParticleSystem now uses love::math::Math's RNG.


New function: love.math.triangulate(vertices)

Accepts a table or list of x/y coordinate pairs and returns a table of tables.
The inner tables are the triangles the polygon is composed of.

Works on all *simple* polygons, i.e. a closed chain of vertices that does not
intersect itself. Attempting to triangulate non-simple polygons is undefined
behavior - in the best case it throws an error, in the worst case it returns
an invalid triangulation.

Polygons must be ordered in *clockwise order* with respect to the love
coordinate system. Attempting to triangulate a ccw polygon will throw an
error.

Examples:

  triangles = love.math.triangulate(0,0, 1,1, 2,0, 2,2, 0,2)
  triangles == {
      {1,1, 2,0, 2,2},
      {1,1, 2,2, 0,2},
      {1,1, 0,2, 0,0},
  }

  triangles = love.math.triangulate({0,0, 1,1, 2,0, 2,2, 0,2})
  -- same as above

  triangles = love.math.triangulate(0,2, 2,2, 2,0, 1,1, 0,0)
  -- error - polygons is in counterclockwise order

  triangles = love.math.triangulate(0,0, 1,3, 2,0, 2,2, 0,2)
  -- undefined behavior - polygon intersects itself (because of edge 1,3)
This commit is contained in:
vrld
2013-03-13 20:48:39 +01:00
parent d383434edf
commit ece4ff6472
8 changed files with 347 additions and 185 deletions
+87 -27
View File
@@ -19,40 +19,32 @@
**/
#include "wrap_Math.h"
#include "ModMath.h"
#include "modules/math/Math.h"
#include <cmath>
#include <iostream>
namespace
{
union SeedConverter
{
double seed_double;
uint64_t seed_uint;
};
} // anonymous namespace
namespace love
{
namespace math
{
static ModMath *instance = 0;
int w_randomseed(lua_State *L)
{
SeedConverter s;
union
{
double seed_double;
uint64_t seed_uint;
} s;
s.seed_double = luaL_checknumber(L, 1);
instance->randomseed(s.seed_uint);
Math::instance.randomseed(s.seed_uint);
return 0;
}
int w_random(lua_State *L)
{
double r = instance->random();
double r = Math::instance.random();
int l, u;
// verbatim from lua 5.1.4 source code: lmathlib.c:185 ff.
switch (lua_gettop(L))
@@ -90,17 +82,92 @@ int w_randnormal(lua_State *L)
stddev = luaL_optnumber(L, 1, 1.);
}
double r = instance->randnormal(stddev);
double r = Math::instance.randnormal(stddev);
lua_pushnumber(L, r + mean);
return 1;
}
int w_triangulate(lua_State *L)
{
std::vector<vertex> vertices;
if (lua_istable(L, 1))
{
size_t top = lua_objlen(L, 1);
vertices.reserve(top / 2);
for (size_t i = 1; i <= top; i += 2)
{
lua_rawgeti(L, 1, i);
lua_rawgeti(L, 1, i+1);
vertex v;
v.x = luaL_checknumber(L, -2);
v.y = luaL_checknumber(L, -1);
vertices.push_back(v);
lua_pop(L, 2);
}
}
else
{
size_t top = lua_gettop(L);
vertices.reserve(top / 2);
for (size_t i = 1; i <= top; i += 2)
{
vertex v;
v.x = luaL_checknumber(L, i);
v.y = luaL_checknumber(L, i+1);
vertices.push_back(v);
}
}
if (vertices.size() < 3)
return luaL_error(L, "Need at least 3 vertices to triangulate");
std::vector<Triangle> triangles;
try
{
if (vertices.size() == 3)
triangles.push_back(Triangle(vertices[0], vertices[1], vertices[2]));
else
triangles = Math::instance.triangulate(vertices);
}
catch (love::Exception &e)
{
return luaL_error(L, e.what());
}
lua_createtable(L, triangles.size(), 0);
for (size_t i = 0; i < triangles.size(); ++i)
{
Triangle &tri = triangles[i];
lua_createtable(L, 6, 0);
lua_pushnumber(L, tri.a.x);
lua_rawseti(L, -2, 1);
lua_pushnumber(L, tri.a.y);
lua_rawseti(L, -2, 2);
lua_pushnumber(L, tri.b.x);
lua_rawseti(L, -2, 3);
lua_pushnumber(L, tri.b.y);
lua_rawseti(L, -2, 4);
lua_pushnumber(L, tri.c.x);
lua_rawseti(L, -2, 5);
lua_pushnumber(L, tri.c.y);
lua_rawseti(L, -2, 6);
lua_rawseti(L, -2, i+1);
}
return 1;
}
// List of functions to wrap.
static const luaL_Reg functions[] =
{
{ "randomseed", w_randomseed },
{ "random", w_random },
{ "randnormal", w_randnormal },
{ "triangulate", w_triangulate },
{ 0, 0 }
};
@@ -111,16 +178,9 @@ static const lua_CFunction types[] =
extern "C" int luaopen_love_math(lua_State *L)
{
if (instance == 0)
instance = new love::math::ModMath();
else
instance->retain();
if (instance == 0)
return luaL_error(L, "Could not open module math.");
Math::instance.retain();
WrappedModule w;
w.module = instance;
w.module = &Math::instance;
w.name = "math";
w.flags = MODULE_T;
w.functions = functions;