mirror of
https://github.com/love2d/love.git
synced 2026-08-12 16:40:57 +02:00
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:
@@ -1,33 +0,0 @@
|
||||
#include "math.h"
|
||||
#include <limits>
|
||||
#include <cmath>
|
||||
|
||||
namespace
|
||||
{
|
||||
// The Box–Muller transform generates two random numbers, one of which we
|
||||
// cache here. A value of +infinity is used to signal the cache is invalid
|
||||
// and that new numbers have to be generated.
|
||||
float last_randnormal = std::numeric_limits<float>::infinity();
|
||||
}
|
||||
|
||||
namespace love
|
||||
{
|
||||
|
||||
float random_normal(float o)
|
||||
{
|
||||
// number in cache?
|
||||
if (last_randnormal != std::numeric_limits<float>::infinity())
|
||||
{
|
||||
float r = last_randnormal;
|
||||
last_randnormal = std::numeric_limits<float>::infinity();
|
||||
return r * o;
|
||||
}
|
||||
|
||||
// else: generate numbers using the Box-Muller transform
|
||||
float a = sqrt(-2.0f * log(1. - random()));
|
||||
float b = float(LOVE_M_PI) * 2.0f * (1. - random());
|
||||
last_randnormal = a * cos(b);
|
||||
return a * sin(b) * o;
|
||||
}
|
||||
|
||||
} // namespace love
|
||||
+8
-36
@@ -68,6 +68,14 @@ struct vertex
|
||||
float s, t;
|
||||
};
|
||||
|
||||
struct Triangle
|
||||
{
|
||||
Triangle(const vertex &x, const vertex &y, const vertex &z)
|
||||
: a(x), b(y), c(z)
|
||||
{}
|
||||
vertex a, b, c;
|
||||
};
|
||||
|
||||
inline int next_p2(int x)
|
||||
{
|
||||
x += (x == 0);
|
||||
@@ -81,42 +89,6 @@ inline float next_p2(float x)
|
||||
return static_cast<float>(next_p2(static_cast<int>(x)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a random number from a uniform distribution.
|
||||
* @returns Uniformly distributed random number in [0:1).
|
||||
*/
|
||||
inline float random()
|
||||
{
|
||||
// to satisfy picky compilers...
|
||||
return float(double(rand() % RAND_MAX) / double(RAND_MAX));
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a random number from a uniform distribution.
|
||||
* @return Uniformly distributed random number in [0:max).
|
||||
*/
|
||||
inline float random(float max)
|
||||
{
|
||||
return random() * max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a random number from a uniform distribution.
|
||||
* @return Uniformly distributed random number in [min:max).
|
||||
*/
|
||||
inline float random(float min, float max)
|
||||
{
|
||||
return random(max - min) + min;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a random number from a normal/gaussian distribution.
|
||||
* @param o Standard deviation of the distribution.
|
||||
* @returns Normal distributed random number with mean 0 and variance o^2.
|
||||
*/
|
||||
float random_normal(float o = 1.);
|
||||
#define random_gaussian random_normal
|
||||
|
||||
} // love
|
||||
|
||||
#endif // LOVE_MATH_H
|
||||
|
||||
@@ -21,11 +21,14 @@
|
||||
#include "ParticleSystem.h"
|
||||
|
||||
#include "common/math.h"
|
||||
#include "modules/math/Math.h"
|
||||
|
||||
#include "OpenGL.h"
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
|
||||
using love::math::Math;
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace graphics
|
||||
@@ -45,7 +48,7 @@ float calculate_variation(float inner, float outer, float var)
|
||||
{
|
||||
float low = inner - (outer/2.0f)*var;
|
||||
float high = inner + (outer/2.0f)*var;
|
||||
float r = random();
|
||||
float r = Math::instance.random();
|
||||
return low*(1-r)+high*r;
|
||||
}
|
||||
|
||||
@@ -124,7 +127,7 @@ void ParticleSystem::add()
|
||||
if (min == max)
|
||||
pLast->life = min;
|
||||
else
|
||||
pLast->life = random(min, max);
|
||||
pLast->life = Math::instance.random(min, max);
|
||||
pLast->lifetime = pLast->life;
|
||||
|
||||
pLast->position[0] = position.getX();
|
||||
@@ -133,12 +136,12 @@ void ParticleSystem::add()
|
||||
switch (areaSpreadDistribution)
|
||||
{
|
||||
case DISTRIBUTION_UNIFORM:
|
||||
pLast->position[0] += random(-areaSpread.getX(), areaSpread.getX());
|
||||
pLast->position[1] += random(-areaSpread.getY(), areaSpread.getY());
|
||||
pLast->position[0] += Math::instance.random(-areaSpread.getX(), areaSpread.getX());
|
||||
pLast->position[1] += Math::instance.random(-areaSpread.getY(), areaSpread.getY());
|
||||
break;
|
||||
case DISTRIBUTION_NORMAL:
|
||||
pLast->position[0] += random_normal(areaSpread.getX());
|
||||
pLast->position[1] += random_normal(areaSpread.getY());
|
||||
pLast->position[0] += Math::instance.randnormal(areaSpread.getX());
|
||||
pLast->position[1] += Math::instance.randnormal(areaSpread.getY());
|
||||
break;
|
||||
case DISTRIBUTION_NONE:
|
||||
default:
|
||||
@@ -147,37 +150,37 @@ void ParticleSystem::add()
|
||||
|
||||
min = direction - spread/2.0f;
|
||||
max = direction + spread/2.0f;
|
||||
pLast->direction = random(min, max);
|
||||
pLast->direction = Math::instance.random(min, max);
|
||||
|
||||
pLast->origin = position;
|
||||
|
||||
min = speedMin;
|
||||
max = speedMax;
|
||||
float speed = random(min, max);
|
||||
float speed = Math::instance.random(min, max);
|
||||
pLast->speed = love::Vector(cos(pLast->direction), sin(pLast->direction));
|
||||
pLast->speed *= speed;
|
||||
|
||||
min = gravityMin;
|
||||
max = gravityMax;
|
||||
pLast->gravity = random(min, max);
|
||||
pLast->gravity = Math::instance.random(min, max);
|
||||
|
||||
min = radialAccelerationMin;
|
||||
max = radialAccelerationMax;
|
||||
pLast->radialAcceleration = random(min, max);
|
||||
pLast->radialAcceleration = Math::instance.random(min, max);
|
||||
|
||||
min = tangentialAccelerationMin;
|
||||
max = tangentialAccelerationMax;
|
||||
pLast->tangentialAcceleration = random(min, max);
|
||||
pLast->tangentialAcceleration = Math::instance.random(min, max);
|
||||
|
||||
pLast->sizeOffset = random(sizeVariation); // time offset for size change
|
||||
pLast->sizeIntervalSize = (1.0f - random(sizeVariation)) - pLast->sizeOffset;
|
||||
pLast->sizeOffset = Math::instance.random(sizeVariation); // time offset for size change
|
||||
pLast->sizeIntervalSize = (1.0f - Math::instance.random(sizeVariation)) - pLast->sizeOffset;
|
||||
pLast->size = sizes[(size_t)(pLast->sizeOffset - .5f) * (sizes.size() - 1)];
|
||||
|
||||
min = rotationMin;
|
||||
max = rotationMax;
|
||||
pLast->spinStart = calculate_variation(spinStart, spinEnd, spinVariation);
|
||||
pLast->spinEnd = calculate_variation(spinEnd, spinStart, spinVariation);
|
||||
pLast->rotation = random(min, max);
|
||||
pLast->rotation = Math::instance.random(min, max);
|
||||
|
||||
pLast->color = colors[0];
|
||||
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2013 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 "modules/math/Math.h"
|
||||
#include "common/math.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <list>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using love::vertex;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// check if an angle is oriented counter clockwise
|
||||
inline bool is_oriented_ccw(const vertex &a, const vertex &b, const vertex &c)
|
||||
{
|
||||
// return det(b-a, c-a) >= 0
|
||||
return ((b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x)) >= 0;
|
||||
}
|
||||
|
||||
// check if a and b are on the same side of the line c->d
|
||||
bool on_same_side(const vertex &a, const vertex &b, const vertex &c, const vertex &d)
|
||||
{
|
||||
float px = d.x - c.x, py = d.y - c.y;
|
||||
// return det(p, a-c) * det(p, b-c) >= 0
|
||||
float l = px * (a.y - c.y) - py * (a.x - c.x);
|
||||
float m = px * (b.y - c.y) - py * (b.x - c.x);
|
||||
return l * m >= 0;
|
||||
}
|
||||
|
||||
// checks is p is contained in the triangle abc
|
||||
inline bool point_in_triangle(const vertex &p, const vertex &a, const vertex &b, const vertex &c)
|
||||
{
|
||||
return on_same_side(p,a, b,c) && on_same_side(p,b, a,c) && on_same_side(p,c, a,b);
|
||||
}
|
||||
|
||||
// checks if any vertex in `vertices' is in the triangle abc.
|
||||
bool any_point_in_triangle(const list<const vertex *> &vertices, const vertex &a, const vertex &b, const vertex &c)
|
||||
{
|
||||
list<const vertex *>::const_iterator it, end = vertices.end();
|
||||
for (it = vertices.begin(); it != end; ++it)
|
||||
{
|
||||
const vertex *p = *it;
|
||||
if ((p != &a) && (p != &b) && (p != &c) && point_in_triangle(*p, a,b,c)) // oh god...
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool is_ear(const vertex &a, const vertex &b, const vertex &c, const list<const vertex *> &vertices)
|
||||
{
|
||||
return is_oriented_ccw(a,b,c) && !any_point_in_triangle(vertices, a,b,c);
|
||||
}
|
||||
}
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace math
|
||||
{
|
||||
|
||||
Math Math::instance;
|
||||
|
||||
// 64 bit Xorshift implementation taken from the end of Sec. 3 (page 4) in
|
||||
// George Marsaglia, "Xorshift RNGs", Journal of Statistical Software, Vol.8 (Issue 14), 2003
|
||||
Math::Math()
|
||||
: last_randnormal(numeric_limits<double>::infinity())
|
||||
{
|
||||
// because it is too big for some compilers to handle ... if you know what
|
||||
// i mean
|
||||
union
|
||||
{
|
||||
uint64_t b64;
|
||||
struct
|
||||
{
|
||||
uint32_t a;
|
||||
uint32_t b;
|
||||
} b32;
|
||||
} converter;
|
||||
|
||||
#ifdef LOVE_BIG_ENDIAN
|
||||
converter.b32.a = 0x0139408D;
|
||||
converter.b32.b = 0xCBBF7A44;
|
||||
#else
|
||||
converter.b32.b = 0x0139408D;
|
||||
converter.b32.a = 0xCBBF7A44;
|
||||
#endif
|
||||
rng_state = converter.b64;
|
||||
|
||||
// prevent the runtime from free()-ing this
|
||||
retain();
|
||||
}
|
||||
|
||||
uint32_t Math::rand()
|
||||
{
|
||||
rng_state ^= (rng_state << 13);
|
||||
rng_state ^= (rng_state >> 7);
|
||||
rng_state ^= (rng_state << 17);
|
||||
return rng_state;
|
||||
}
|
||||
|
||||
// Box–Muller transform
|
||||
double Math::randnormal(double stddev)
|
||||
{
|
||||
// use cached number if possible
|
||||
if (last_randnormal != numeric_limits<double>::infinity())
|
||||
{
|
||||
double r = last_randnormal;
|
||||
last_randnormal = numeric_limits<double>::infinity();
|
||||
return r * stddev;
|
||||
}
|
||||
|
||||
double r = sqrt(-2.0 * log(1. - random()));
|
||||
double phi = 2.0 * LOVE_M_PI * (1. - random());
|
||||
|
||||
last_randnormal = r * cos(phi);
|
||||
return r * sin(phi) * stddev;
|
||||
}
|
||||
|
||||
vector<Triangle> Math::triangulate(const vector<vertex> &polygon)
|
||||
{
|
||||
if (polygon.size() < 3)
|
||||
throw love::Exception("Not a ploygon");
|
||||
else if (polygon.size() == 3)
|
||||
return vector<Triangle>(1, Triangle(polygon[0], polygon[1], polygon[2]));
|
||||
|
||||
vector<size_t> next_vertex(polygon.size()), prev_vertex(polygon.size());
|
||||
|
||||
// collect list of connections
|
||||
for (size_t i = 0; i < polygon.size(); ++i)
|
||||
{
|
||||
next_vertex[i] = i+1;
|
||||
prev_vertex[i] = i-1;
|
||||
}
|
||||
next_vertex[next_vertex.size()-1] = 0;
|
||||
prev_vertex[0] = prev_vertex.size()-1;
|
||||
|
||||
// collect list of concave polygons
|
||||
list<const vertex *> concave_vertices;
|
||||
for (size_t i = 0; i < polygon.size(); ++i)
|
||||
{
|
||||
if (!is_oriented_ccw(polygon[prev_vertex[i]], polygon[i], polygon[next_vertex[i]]))
|
||||
concave_vertices.push_back(&polygon[i]);
|
||||
}
|
||||
|
||||
// triangulation according to kong
|
||||
vector<Triangle> triangles;
|
||||
size_t n_vertices = polygon.size();
|
||||
size_t current = 1, skipped = 0, next, prev;
|
||||
while (n_vertices > 3)
|
||||
{
|
||||
next = next_vertex[current];
|
||||
prev = prev_vertex[current];
|
||||
const vertex &a = polygon[prev], &b = polygon[current], &c = polygon[next];
|
||||
if (is_ear(a,b,c, concave_vertices))
|
||||
{
|
||||
triangles.push_back(Triangle(a,b,c));
|
||||
next_vertex[prev] = next;
|
||||
prev_vertex[next] = prev;
|
||||
concave_vertices.remove(&b);
|
||||
--n_vertices;
|
||||
skipped = 0;
|
||||
}
|
||||
else if (++skipped > n_vertices)
|
||||
{
|
||||
throw love::Exception("Cannot triangulate polygon.");
|
||||
}
|
||||
current = next;
|
||||
}
|
||||
next = next_vertex[current];
|
||||
prev = prev_vertex[current];
|
||||
triangles.push_back(Triangle(polygon[prev], polygon[current], polygon[next]));
|
||||
|
||||
return triangles;
|
||||
}
|
||||
|
||||
} // math
|
||||
} // love
|
||||
@@ -23,21 +23,23 @@
|
||||
|
||||
// LOVE
|
||||
#include "common/Module.h"
|
||||
#include "common/math.h"
|
||||
|
||||
// STL
|
||||
#include <limits>
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace math
|
||||
{
|
||||
|
||||
class ModMath : public Module
|
||||
class Math : public Module
|
||||
{
|
||||
public:
|
||||
ModMath();
|
||||
virtual ~ModMath() {}
|
||||
virtual ~Math()
|
||||
{}
|
||||
|
||||
/** Set pseudo random seed.
|
||||
*
|
||||
@@ -47,7 +49,7 @@ public:
|
||||
*/
|
||||
inline void randomseed(uint64_t seed)
|
||||
{
|
||||
RNGState.seed = seed;
|
||||
rng_state = seed;
|
||||
}
|
||||
|
||||
/** Return uniformly distributed pseudo random integer.
|
||||
@@ -65,6 +67,24 @@ public:
|
||||
return double(rand()) / (double(std::numeric_limits<uint32_t>::max()) + 1.0);
|
||||
}
|
||||
|
||||
/** Get uniformly distributed pseudo random number in [0,max).
|
||||
*
|
||||
* @returns Pseudo random number in [0,max).
|
||||
*/
|
||||
inline double random(double max)
|
||||
{
|
||||
return random() * max;
|
||||
}
|
||||
|
||||
/** Get uniformly distributed pseudo random number in [min, max).
|
||||
*
|
||||
* @returns Pseudo random number in [min, max).
|
||||
*/
|
||||
inline double random(double min, double max)
|
||||
{
|
||||
return random() * (max - min) + min;
|
||||
}
|
||||
|
||||
/** Get normally distributed pseudo random number.
|
||||
*
|
||||
* @param stddev Standard deviation of the distribution.
|
||||
@@ -77,12 +97,19 @@ public:
|
||||
return "love.math";
|
||||
}
|
||||
|
||||
/** Triangulate a simple polygon.
|
||||
* @param polygon Polygon to triangulate. Must not intersect itself.
|
||||
* @returns List of triangles the polygon is composed of.
|
||||
*/
|
||||
std::vector<Triangle> triangulate(const std::vector<vertex> &polygon);
|
||||
|
||||
static Math instance;
|
||||
|
||||
private:
|
||||
struct
|
||||
{
|
||||
uint64_t seed;
|
||||
double last_randnormal;
|
||||
} RNGState;
|
||||
Math();
|
||||
|
||||
uint64_t rng_state;
|
||||
double last_randnormal;
|
||||
};
|
||||
|
||||
} // math
|
||||
@@ -1,66 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2013 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 "ModMath.h"
|
||||
#include "common/math.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace math
|
||||
{
|
||||
|
||||
// 64 bit Xorshift implementation taken from the end of Sec. 3 (page 4) in
|
||||
// George Marsaglia, "Xorshift RNGs", Journal of Statistical Software, Vol.8 (Issue 14), 2003
|
||||
ModMath::ModMath()
|
||||
{
|
||||
RNGState.seed = 0x0139408DCBBF7A44;
|
||||
RNGState.last_randnormal = std::numeric_limits<double>::infinity();
|
||||
}
|
||||
|
||||
uint32_t ModMath::rand()
|
||||
{
|
||||
uint64_t &x = RNGState.seed;
|
||||
x ^= (x << 13);
|
||||
x ^= (x >> 7);
|
||||
x ^= (x << 17);
|
||||
return x;
|
||||
}
|
||||
|
||||
// Box–Muller transform
|
||||
double ModMath::randnormal(double stddev)
|
||||
{
|
||||
if (RNGState.last_randnormal != std::numeric_limits<double>::infinity())
|
||||
{
|
||||
double r = RNGState.last_randnormal;
|
||||
RNGState.last_randnormal = std::numeric_limits<double>::infinity();
|
||||
return r * stddev;
|
||||
}
|
||||
|
||||
double r = sqrt(-2.0 * log(1. - random()));
|
||||
double phi = 2.0 * LOVE_M_PI * (1. - random());
|
||||
|
||||
RNGState.last_randnormal = r * cos(phi);
|
||||
return r * sin(phi) * stddev;
|
||||
}
|
||||
|
||||
} // math
|
||||
} // love
|
||||
@@ -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;
|
||||
|
||||
@@ -33,6 +33,7 @@ namespace math
|
||||
int w_randomseed(lua_State *L);
|
||||
int w_random(lua_State *L);
|
||||
int w_randnormal(lua_State *L);
|
||||
int w_triangulate(lua_State *L);
|
||||
extern "C" LOVE_EXPORT int luaopen_love_math(lua_State *L);
|
||||
|
||||
} // random
|
||||
|
||||
Reference in New Issue
Block a user