diff --git a/changes.txt b/changes.txt index 4b06f81d8..a4efdb4d4 100644 --- a/changes.txt +++ b/changes.txt @@ -28,6 +28,7 @@ Released: N/A * Added Text objects and love.graphics.newText. * Added BMFont bitmap font file support to love.graphics.newFont and love.font. * Added love.window.maximize. + * Added BezierCurve:renderSegment and BezierCurve:removePoint. * Removed love.filesystem.exists (use love.filesystem.isFile or love.filesystem.isDirectory instead.) * Removed the "wu" and "wd" constants for love.mousepressed (replaced by love.wheelmoved.) @@ -315,7 +316,7 @@ LOVE 0.9.0 [Baby Inspector] * Added love.window.getIcon. * Added t.window.icon to love.conf. * Added love.mousefocus and love.window.hasMouseFocus. - * Added custom hardware cursors via love.mouse.newCursor. + * Added custom hardware cursors via love.mouse.newCursor. * Added love.mouse.setX/setY. * Added Joystick objects. * Added love.joystick.getJoystick. diff --git a/src/modules/math/BezierCurve.cpp b/src/modules/math/BezierCurve.cpp index 04a0c4ff2..4cbe984dd 100644 --- a/src/modules/math/BezierCurve.cpp +++ b/src/modules/math/BezierCurve.cpp @@ -104,35 +104,46 @@ BezierCurve BezierCurve::getDerivative() const const Vector &BezierCurve::getControlPoint(int i) const { - if (i < 0) + while (i < 0) i += controlPoints.size(); - if (i < 0 || (size_t) i >= controlPoints.size()) - throw Exception("Invalid control point index"); + while ((size_t) i >= controlPoints.size()) + i -= controlPoints.size(); return controlPoints[i]; } void BezierCurve::setControlPoint(int i, const Vector &point) { - if (i < 0) + while (i < 0) i += controlPoints.size(); - if (i < 0 || (size_t) i >= controlPoints.size()) - throw Exception("Invalid control point index"); + while ((size_t) i >= controlPoints.size()) + i -= controlPoints.size(); controlPoints[i] = point; } -void BezierCurve::insertControlPoint(const Vector &point, int pos) +void BezierCurve::insertControlPoint(const Vector &point, int i) { - if (pos < 0) - pos += controlPoints.size() + 1; + while (i < 0) + i += controlPoints.size(); - if (pos < 0 ||(size_t) pos > controlPoints.size()) - throw Exception("Invalid control point index"); + while ((size_t) i > controlPoints.size()) + i -= controlPoints.size(); - controlPoints.insert(controlPoints.begin() + pos, point); + controlPoints.insert(controlPoints.begin() + i, point); +} + +void BezierCurve::removeControlPoint(int i) +{ + while (i < 0) + i += controlPoints.size(); + + while ((size_t) i >= controlPoints.size()) + i -= controlPoints.size(); + + controlPoints.erase(controlPoints.begin() + i); } void BezierCurve::translate(const Vector &t) @@ -170,7 +181,7 @@ Vector BezierCurve::evaluate(double t) const for (size_t step = 1; step < controlPoints.size(); ++step) for (size_t i = 0; i < controlPoints.size() - step; ++i) points[i] = points[i] * (1-t) + points[i+1] * t; - + return points[0]; } @@ -183,6 +194,30 @@ vector BezierCurve::render(int accuracy) const return vertices; } +vector BezierCurve::renderSegment(double start, double end, size_t accuracy) const +{ + if (controlPoints.size() < 2) + throw Exception("Invalid Bezier curve: Not enough control points."); + vector vertices(controlPoints); + subdivide(vertices, accuracy); + if (start == end) + { + vertices.clear(); + } + else if (start < end) + { + size_t start_idx = size_t(start * vertices.size()); + size_t end_idx = size_t(end * vertices.size() + 0.5); + return std::vector(vertices.begin() + start_idx, vertices.begin() + end_idx); + } + else if (end > start) + { + size_t start_idx = size_t(end * vertices.size() + 0.5); + size_t end_idx = size_t(start * vertices.size()); + return std::vector(vertices.begin() + start_idx, vertices.begin() + end_idx); + } + return vertices; +} } // namespace math } // namespace love diff --git a/src/modules/math/BezierCurve.h b/src/modules/math/BezierCurve.h index 29dc589bf..1dad02a2a 100644 --- a/src/modules/math/BezierCurve.h +++ b/src/modules/math/BezierCurve.h @@ -73,6 +73,12 @@ public: **/ void insertControlPoint(const Vector &point, int pos = -1); + /** + * Remove the i'th control point from the curve. + * @param i Control point to remove + **/ + void removeControlPoint(int i); + /** * @returns Number of control points. **/ @@ -114,6 +120,15 @@ public: **/ std::vector render(int accuracy = 4) const; + /** + * Renders a segment of the curve by subdivision. + * @param start The starting point (between 0 and 1) on the curve. + * @param end The ending point on the curve. + * @param accuracy The 'fineness' of the curve. + * @returns A polygon chain that approximates the segment along the curve + **/ + std::vector renderSegment(double start, double end, size_t accuracy = 4) const; + private: std::vector controlPoints; }; diff --git a/src/modules/math/wrap_BezierCurve.cpp b/src/modules/math/wrap_BezierCurve.cpp index bf367d255..e7524b1b2 100644 --- a/src/modules/math/wrap_BezierCurve.cpp +++ b/src/modules/math/wrap_BezierCurve.cpp @@ -94,6 +94,18 @@ int w_BezierCurve_insertControlPoint(lua_State *L) return 0; } +int w_BezierCurve_removeControlPoint(lua_State *L) +{ + BezierCurve *curve = luax_checkbeziercurve(L, 1); + int idx = luaL_checkint(L, 2); + + if (idx > 0) // 1-indexing + idx--; + + luax_catchexcept(L, [&](){ curve->removeControlPoint(idx); }); + return 0; +} + int w_BezierCurve_getControlPointCount(lua_State *L) { BezierCurve *curve = luax_checkbeziercurve(L, 1); @@ -165,6 +177,28 @@ int w_BezierCurve_render(lua_State *L) return 1; } +int w_BezierCurve_renderSegment(lua_State *L) +{ + BezierCurve *curve = luax_checkbeziercurve(L, 1); + double start = luaL_checknumber(L, 2); + double end = luaL_checknumber(L, 3); + int accuracy = luaL_optinteger(L, 4, 5); + + std::vector points; + luax_catchexcept(L, [&](){ points = curve->renderSegment(start, end, accuracy); }); + + lua_createtable(L, points.size()*2, 0); + for (size_t i = 0; i < points.size(); ++i) + { + lua_pushnumber(L, points[i].x); + lua_rawseti(L, -2, 2*i+1); + lua_pushnumber(L, points[i].y); + lua_rawseti(L, -2, 2*i+2); + } + + return 1; +} + static const luaL_Reg functions[] = { {"getDegree", w_BezierCurve_getDegree}, @@ -172,12 +206,14 @@ static const luaL_Reg functions[] = {"getControlPoint", w_BezierCurve_getControlPoint}, {"setControlPoint", w_BezierCurve_setControlPoint}, {"insertControlPoint", w_BezierCurve_insertControlPoint}, + {"removeControlPoint", w_BezierCurve_removeControlPoint}, {"getControlPointCount", w_BezierCurve_getControlPointCount}, {"translate", w_BezierCurve_translate}, {"rotate", w_BezierCurve_rotate}, {"scale", w_BezierCurve_scale}, {"evaluate", w_BezierCurve_evaluate}, {"render", w_BezierCurve_render}, + {"renderSegment", w_BezierCurve_renderSegment}, { 0, 0 } }; diff --git a/src/modules/math/wrap_BezierCurve.h b/src/modules/math/wrap_BezierCurve.h index 9fd0fbd12..110f7751a 100644 --- a/src/modules/math/wrap_BezierCurve.h +++ b/src/modules/math/wrap_BezierCurve.h @@ -36,12 +36,14 @@ int w_BezierCurve_getDerivative(lua_State *L); int w_BezierCurve_getControlPoint(lua_State *L); int w_BezierCurve_setControlPoint(lua_State *L); int w_BezierCurve_insertControlPoint(lua_State *L); +int w_BezierCurve_removeControlPoint(lua_State *L); int w_BezierCurve_getControlPointCount(lua_State *L); int w_BezierCurve_translate(lua_State *L); int w_BezierCurve_rotate(lua_State *L); int w_BezierCurve_scale(lua_State *L); int w_BezierCurve_evaluate(lua_State *L); int w_BezierCurve_render(lua_State *L); +int w_BezierCurve_renderSegment(lua_State *L); extern "C" int luaopen_beziercurve(lua_State *L); } // math