diff --git a/src/modules/graphics/Geometry.cpp b/src/modules/graphics/Geometry.cpp index dc5783e60..b31cfbe49 100644 --- a/src/modules/graphics/Geometry.cpp +++ b/src/modules/graphics/Geometry.cpp @@ -35,18 +35,25 @@ namespace love namespace graphics { -Geometry::Geometry(const std::vector &polygon) +Geometry::Geometry(const std::vector &polygon, const std::vector &elements, Geometry::DrawMode mode) : vertexArray(NULL) + , vertexCount(polygon.size()) + , elementArray(NULL) + , elementCount(elements.size()) , x_min(std::numeric_limits::max()) , x_max(std::numeric_limits::min()) , y_min(std::numeric_limits::max()) , y_max(std::numeric_limits::min()) , vertexColors(false) + , drawMode(mode) { - if (!Math::instance.isConvex(polygon)) - throw love::Exception("Geometry must be convex"); + for (size_t i = 0; i < elementCount; i++) + { + // All values in the element array need to be a valid vertex index. + if (elements[i] >= vertexCount) + throw love::Exception("Invalid vertex map value"); + } - vertexCount = polygon.size(); vertexArray = new vertex[vertexCount]; for (size_t i = 0; i < vertexCount; ++i) { @@ -57,16 +64,25 @@ Geometry::Geometry(const std::vector &polygon) y_min = v.y < y_min ? v.y : y_min; y_max = v.y > y_max ? v.y : y_max; } + + if (elementCount > 0) + { + elementArray = new uint16[elementCount]; + memcpy(elementArray, &elements[0], elementCount * sizeof(uint16)); + } } Geometry::Geometry(float x, float y, float w, float h, float sw, float sh) : vertexArray(NULL) , vertexCount(4) + , elementArray(NULL) + , elementCount(0) , x_min(x) , x_max(x+w) , y_min(y) , y_max(y+h) , vertexColors(false) + , drawMode(DRAW_MODE_FAN) { vertexArray = new vertex[4]; float s0 = x/sw, s1 = (x+w)/sw, t0 = y/sh, t1 = (y+h)/sh; @@ -78,14 +94,22 @@ Geometry::Geometry(float x, float y, float w, float h, float sw, float sh) Geometry::Geometry(const Geometry &other) : vertexCount(other.vertexCount) + , elementCount(other.elementCount) , x_min(other.x_min) , x_max(other.x_max) , y_min(other.y_min) , y_max(other.y_max) , vertexColors(other.vertexColors) + , drawMode(other.drawMode) { vertexArray = new vertex[vertexCount]; memcpy(vertexArray, other.vertexArray, vertexCount * sizeof(vertex)); + + if (elementCount > 0) + { + elementArray = new uint16[elementCount]; + memcpy(elementArray, other.elementArray, elementCount * sizeof(uint16)); + } } Geometry &Geometry::operator=(const Geometry &other) @@ -94,25 +118,25 @@ Geometry &Geometry::operator=(const Geometry &other) { Geometry temp(other); std::swap(vertexArray, temp.vertexArray); + std::swap(elementArray, temp.elementArray); - vertexCount = temp.vertexCount; - x_min = temp.x_min; - x_max = temp.x_max; - y_min = temp.y_min; - y_max = temp.y_max; + vertexCount = temp.vertexCount; + elementCount = temp.elementCount; + x_min = temp.x_min; + x_max = temp.x_max; + y_min = temp.y_min; + y_max = temp.y_max; vertexColors = other.vertexColors; + drawMode = other.drawMode; } return *this; } Geometry::~Geometry() { - if (vertexArray) - { - delete[] vertexArray; - vertexArray = NULL; - } + delete[] vertexArray; + delete[] elementArray; } const vertex &Geometry::getVertex(size_t i) const @@ -148,10 +172,55 @@ void Geometry::flip(bool x, bool y) } } +void Geometry::setElementArray(const uint16 *elements, size_t count) +{ + if (count == 0 || elements == NULL) + { + delete[] elementArray; + elementArray = NULL; + elementCount = 0; + return; + } + + for (size_t i = 0; i < count; i++) + { + if (elements[i] >= vertexCount) + throw love::Exception("Invalid vertex map value"); + } + + if (count > elementCount) + { + delete[] elementArray; + elementArray = new uint16[count]; + } + + elementCount = count; + memcpy(elementArray, elements, elementCount * sizeof(uint16)); +} + void Geometry::setVertexColors(bool on) { vertexColors = on; } +bool Geometry::getConstant(const char *in, Geometry::DrawMode &out) +{ + return drawModes.find(in, out); +} + +bool Geometry::getConstant(Geometry::DrawMode in, const char *&out) +{ + return drawModes.find(in, out); +} + +StringMap::Entry Geometry::drawModeEntries[] = +{ + {"fan", Geometry::DRAW_MODE_FAN}, + {"strip", Geometry::DRAW_MODE_STRIP}, + {"triangles", Geometry::DRAW_MODE_TRIANGLES} +}; + +StringMap Geometry::drawModes(Geometry::drawModeEntries, sizeof(Geometry::drawModeEntries)); + } // graphics } // love diff --git a/src/modules/graphics/Geometry.h b/src/modules/graphics/Geometry.h index 6ca7fe26b..94b227529 100644 --- a/src/modules/graphics/Geometry.h +++ b/src/modules/graphics/Geometry.h @@ -24,8 +24,10 @@ // LOVE #include "common/Object.h" #include "common/math.h" +#include "common/StringMap.h" +#include "common/int.h" -// std +// stdlib #include namespace love @@ -36,11 +38,21 @@ namespace graphics class Geometry : public Object { public: + + // How the Geometry's vertices are used when drawing. + // http://escience.anu.edu.au/lecture/cg/surfaceModeling/image/surfaceModeling015.png + enum DrawMode + { + DRAW_MODE_FAN, + DRAW_MODE_STRIP, + DRAW_MODE_TRIANGLES, + DRAW_MODE_MAX_ENUM + }; + /** * Creates a new geometry object from a std::vector. - * @param v **/ - Geometry(const std::vector &polygon); + Geometry(const std::vector &polygon, const std::vector &elements, DrawMode mode = DRAW_MODE_FAN); /** * Creates a new geometry from (texture) quad information. @@ -65,7 +77,7 @@ public: /** * Returns a pointer to the vertex array. **/ - const vertex *getVertexArray() const + inline const vertex *getVertexArray() const { return vertexArray; } @@ -73,11 +85,23 @@ public: /** * Returns the size of the vertex array. **/ - size_t getVertexCount() const + inline size_t getVertexCount() const { return vertexCount; } + inline const uint16 *getElementArray() const + { + return elementArray; + } + + inline size_t getElementCount() const + { + return elementCount; + } + + void setElementArray(const uint16 *elements, size_t count); + /** * Sets whether this Geometry will use custom per-vertex colors. **/ @@ -86,15 +110,30 @@ public: /** * Returns whether this Geometry is using custom per-vertex colors. **/ - bool hasVertexColors() const + inline bool hasVertexColors() const { return vertexColors; }; + /** + * Returns the mode used when drawing this Geometry. + **/ + inline DrawMode getDrawMode() const + { + return drawMode; + } + + static bool getConstant(const char *in, DrawMode &out); + static bool getConstant(DrawMode in, const char *&out); + private: + vertex *vertexArray; size_t vertexCount; + uint16 *elementArray; + size_t elementCount; + float x_min; float x_max; @@ -102,6 +141,11 @@ private: float y_max; bool vertexColors; + + DrawMode drawMode; + + static StringMap::Entry drawModeEntries[]; + static StringMap drawModes; }; } // graphics diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index bc2468ced..29e45a853 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -626,7 +626,22 @@ void Canvas::drawg(love::graphics::Geometry *geom, float x, float y, float angle glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(vertex), (GLvoid *)&v->r); } - drawv(t, v, vcount, GL_TRIANGLE_FAN); + GLenum glmode; + switch (geom->getDrawMode()) + { + case Geometry::DRAW_MODE_FAN: + default: + glmode = GL_TRIANGLE_FAN; + break; + case Geometry::DRAW_MODE_STRIP: + glmode = GL_TRIANGLE_STRIP; + break; + case Geometry::DRAW_MODE_TRIANGLES: + glmode = GL_TRIANGLES; + break; + } + + drawv(t, v, vcount, glmode, geom->getElementArray(), geom->getElementCount()); if (geom->hasVertexColors()) { @@ -763,7 +778,7 @@ int Canvas::getHeight() return height; } -void Canvas::drawv(const Matrix &t, const vertex *v, GLsizei count, GLenum mode) const +void Canvas::drawv(const Matrix &t, const vertex *v, GLsizei count, GLenum mode, const uint16 *e, GLsizei ecount) const { glPushMatrix(); @@ -780,7 +795,11 @@ void Canvas::drawv(const Matrix &t, const vertex *v, GLsizei count, GLenum mode) // glDrawArrays(), drawg() needs to be updated accordingly! glVertexPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid *)&v[0].x); glTexCoordPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid *)&v[0].s); - glDrawArrays(mode, 0, count); + + if (e != 0 && ecount > 0) + glDrawElements(mode, ecount, GL_UNSIGNED_SHORT, (GLvoid *) e); + else + glDrawArrays(mode, 0, count); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); diff --git a/src/modules/graphics/opengl/Canvas.h b/src/modules/graphics/opengl/Canvas.h index b274398af..2eaf73475 100644 --- a/src/modules/graphics/opengl/Canvas.h +++ b/src/modules/graphics/opengl/Canvas.h @@ -142,7 +142,7 @@ private: std::vector attachedCanvases; void setupGrab(); - void drawv(const Matrix &t, const vertex *v, GLsizei count = 4, GLenum mode = GL_QUADS) const; + void drawv(const Matrix &t, const vertex *v, GLsizei count = 4, GLenum mode = GL_QUADS, const uint16 *e = 0, GLsizei ecount = 0) const; static StringMap::Entry textureTypeEntries[]; static StringMap textureTypes; diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 8d0fc723a..3352a769a 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -440,9 +440,9 @@ Image *Graphics::newImage(love::image::CompressedData *cdata) return image; } -Geometry *Graphics::newGeometry(const std::vector &vertices) +Geometry *Graphics::newGeometry(const std::vector &vertices, const std::vector &vertexmap, Geometry::DrawMode mode) { - return new Geometry(vertices); + return new Geometry(vertices, vertexmap, mode); } Geometry *Graphics::newQuad(float x, float y, float w, float h, float sw, float sh) diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index 527c3d3a4..d5eb4fa72 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -225,7 +225,7 @@ public: /** * Creates a Geometry object. **/ - Geometry *newGeometry(const std::vector &vertices); + Geometry *newGeometry(const std::vector &vertices, const std::vector &vertexmap, Geometry::DrawMode mode); /** * Creates a quadliteral Geometry object. diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp index 018bdd718..cb8f64fc4 100644 --- a/src/modules/graphics/opengl/Image.cpp +++ b/src/modules/graphics/opengl/Image.cpp @@ -120,7 +120,22 @@ void Image::drawg(love::graphics::Geometry *geom, float x, float y, float angle, glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(vertex), (GLvoid *) &v[0].r); } - drawv(t, v, geom->getVertexCount(), GL_TRIANGLE_FAN); + GLenum glmode; + switch (geom->getDrawMode()) + { + case Geometry::DRAW_MODE_FAN: + default: + glmode = GL_TRIANGLE_FAN; + break; + case Geometry::DRAW_MODE_STRIP: + glmode = GL_TRIANGLE_STRIP; + break; + case Geometry::DRAW_MODE_TRIANGLES: + glmode = GL_TRIANGLES; + break; + } + + drawv(t, v, geom->getVertexCount(), glmode, geom->getElementArray(), geom->getElementCount()); if (geom->hasVertexColors()) { @@ -536,7 +551,7 @@ bool Image::refresh() return true; } -void Image::drawv(const Matrix &t, const vertex *v, GLsizei count, GLenum mode) const +void Image::drawv(const Matrix &t, const vertex *v, GLsizei count, GLenum mode, const uint16 *e, GLsizei ecount) const { bind(); @@ -553,7 +568,11 @@ void Image::drawv(const Matrix &t, const vertex *v, GLsizei count, GLenum mode) // glDrawArrays(), drawg() needs to be updated accordingly! glVertexPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid *)&v[0].x); glTexCoordPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid *)&v[0].s); - glDrawArrays(mode, 0, count); + + if (e != 0 && ecount > 0) + glDrawElements(mode, ecount, GL_UNSIGNED_SHORT, (GLvoid *) e); + else + glDrawArrays(mode, 0, count); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); diff --git a/src/modules/graphics/opengl/Image.h b/src/modules/graphics/opengl/Image.h index c56d35e0e..5033c2f36 100644 --- a/src/modules/graphics/opengl/Image.h +++ b/src/modules/graphics/opengl/Image.h @@ -138,7 +138,7 @@ public: private: - void drawv(const Matrix &t, const vertex *v, GLsizei count = 4, GLenum mode = GL_QUADS) const; + void drawv(const Matrix &t, const vertex *v, GLsizei count = 4, GLenum mode = GL_QUADS, const uint16 *e = 0, GLsizei ecount = 0) const; friend class Shader; GLuint getTextureName() const diff --git a/src/modules/graphics/opengl/SpriteBatch.cpp b/src/modules/graphics/opengl/SpriteBatch.cpp index fbf26fe97..cc0db1848 100644 --- a/src/modules/graphics/opengl/SpriteBatch.cpp +++ b/src/modules/graphics/opengl/SpriteBatch.cpp @@ -133,17 +133,28 @@ int SpriteBatch::addg(Geometry *geom, float x, float y, float a, float sx, float if (vertexcount > 4) throw love::Exception("Cannot add Geometries with more than 4 vertices to SpriteBatch"); - // If the Geometry has 3 vertices, then 2 triangles will be rendered in the - // SpriteBatch: 0-1-2 and 0-2-0. 0-2-0 will get ignored during rasterization. - for (size_t i = 0; i < 4; i++) - sprite[i] = geom->getVertex(i % vertexcount); + // Which vertices to add to the SpriteBatch. + size_t vertex_indices[4] = {0, 1, 2, 3}; + + if (geom->getDrawMode() == Geometry::DRAW_MODE_STRIP) + { + // We have to do some vertex reordering shenanigans to get 4-vertex + // triangle strip Geometries to render properly. + std::swap(vertex_indices[0], vertex_indices[1]); + } + + // If the Geometry has 3 vertices, then 2 triangles will be added to the + // SpriteBatch: 0-1-2 and 0-2-0. 0-2-0 will get ignored during rasterization. + for (size_t i = geom->getVertexCount(); i < 4; i++) + vertex_indices[i] = vertex_indices[0]; + + for (size_t i = 0; i < 4; i++) + sprite[i] = geom->getVertex(vertex_indices[i]); - // Transform. static Matrix t; t.setTransformation(x, y, a, sx, sy, ox, oy, kx, ky); t.transform(sprite, sprite, 4); - // Set vertex colors to the constant color, if Geometry has no custom colors. if (color && !geom->hasVertexColors()) setColorv(sprite, *color); @@ -279,6 +290,9 @@ void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float const int vertex_offset = sizeof(unsigned char) * 4; const int texel_offset = sizeof(unsigned char) * 4 + sizeof(float) * 2; + if (next == 0) + return; + static Matrix t; glPushMatrix(); diff --git a/src/modules/graphics/opengl/wrap_Geometry.cpp b/src/modules/graphics/opengl/wrap_Geometry.cpp index 863429d8a..3759b5dfe 100644 --- a/src/modules/graphics/opengl/wrap_Geometry.cpp +++ b/src/modules/graphics/opengl/wrap_Geometry.cpp @@ -34,7 +34,6 @@ Geometry *luax_checkgeometry(lua_State *L, int idx) return luax_checktype(L, idx, "Geometry", GRAPHICS_GEOMETRY_T); } -// different name than in Geometry.cpp to make the triangulation transparent int w_Geometry_getVertexCount(lua_State *L) { Geometry *geom = luax_checkgeometry(L, 1); @@ -69,17 +68,37 @@ int w_Geometry_getVertex(lua_State *L) int w_Geometry_setVertex(lua_State *L) { Geometry *geom = luax_checkgeometry(L, 1); - size_t i = size_t(luaL_checkint(L, 2)); + size_t i = size_t(luaL_checkinteger(L, 2)); vertex v; - v.x = luaL_checknumber(L, 3); - v.y = luaL_checknumber(L, 4); - v.s = luaL_checknumber(L, 5); - v.t = luaL_checknumber(L, 6); - v.r = luaL_optint(L, 7, 255); - v.g = luaL_optint(L, 8, 255); - v.b = luaL_optint(L, 9, 255); - v.a = luaL_optint(L, 10, 255); + + if (lua_istable(L, 3)) + { + for (int i = 1; i <= 8; i++) + lua_rawgeti(L, 3, i); + + v.x = luaL_checknumber(L, -8); + v.y = luaL_checknumber(L, -7); + v.s = luaL_checknumber(L, -6); + v.t = luaL_checknumber(L, -5); + v.r = luaL_optinteger(L, -4, 255); + v.g = luaL_optinteger(L, -3, 255); + v.b = luaL_optinteger(L, -2, 255); + v.a = luaL_optinteger(L, -1, 255); + + lua_pop(L, 8); + } + else + { + v.x = luaL_checknumber(L, 3); + v.y = luaL_checknumber(L, 4); + v.s = luaL_checknumber(L, 5); + v.t = luaL_checknumber(L, 6); + v.r = luaL_optinteger(L, 7, 255); + v.g = luaL_optinteger(L, 8, 255); + v.b = luaL_optinteger(L, 9, 255); + v.a = luaL_optinteger(L, 10, 255); + } try { @@ -117,6 +136,82 @@ int w_Geometry_hasVertexColors(lua_State *L) return 1; } +int w_Geometry_getDrawMode(lua_State *L) +{ + Geometry *geom = luax_checkgeometry(L, 1); + + Geometry::DrawMode mode = geom->getDrawMode(); + const char *str; + + if (!Geometry::getConstant(mode, str)) + return luaL_error(L, "Unknown Geometry draw mode"); + + lua_pushstring(L, str); + + return 1; +} + +int w_Geometry_getVertexMap(lua_State *L) +{ + Geometry *g = luax_checkgeometry(L, 1); + + size_t elementcount = g->getElementCount(); + const uint16 *elements = g->getElementArray(); + + if (elementcount == 0 || elements == 0) + return 0; + + lua_createtable(L, elementcount, 0); + for (size_t i = 0; i < elementcount; i++) + { + lua_pushinteger(L, elements[i]); + lua_rawseti(L, -2, i + 1); + } + + return 1; +} + +int w_Geometry_setVertexMap(lua_State *L) +{ + Geometry *g = luax_checkgeometry(L, 1); + + for (int i = lua_gettop(L); i >= 2; i--) + { + if (lua_isnil(L, i)) + lua_pop(L, 1); + else + break; + } + + bool is_table = lua_istable(L, 2); + int nargs = is_table ? lua_objlen(L, 2) : lua_gettop(L) - 1; + + std::vector vertexmap; + vertexmap.reserve(nargs); + + for (int i = 0; i < nargs; i++) + { + if (is_table) + { + lua_rawgeti(L, 2, i + 1); + vertexmap.push_back(luaL_checkinteger(L, -1) - 1); + lua_pop(L, 1); + } + else + vertexmap.push_back(luaL_checkinteger(L, i + 2) - 1); + } + + try + { + g->setElementArray(&vertexmap[0], vertexmap.size()); + } + catch (love::Exception &e) + { + return luaL_error(L, "%s", e.what()); + } + return 0; +} + static const luaL_Reg w_Geometry_functions[] = { { "getVertexCount", w_Geometry_getVertexCount }, @@ -125,6 +220,9 @@ static const luaL_Reg w_Geometry_functions[] = { "flip", w_Geometry_flip }, { "setVertexColors", w_Geometry_setVertexColors }, { "hasVertexColors", w_Geometry_hasVertexColors }, + { "getDrawMode", w_Geometry_getDrawMode }, + { "getVertexMap", w_Geometry_getVertexMap }, + { "setVertexMap", w_Geometry_setVertexMap }, { 0, 0 } }; diff --git a/src/modules/graphics/opengl/wrap_Geometry.h b/src/modules/graphics/opengl/wrap_Geometry.h index c5415d37a..381d4609e 100644 --- a/src/modules/graphics/opengl/wrap_Geometry.h +++ b/src/modules/graphics/opengl/wrap_Geometry.h @@ -39,6 +39,9 @@ int w_Geometry_setVertex(lua_State *L); int w_Geometry_flip(lua_State *L); int w_Geometry_setVertexColors(lua_State *L); int w_Geometry_hasVertexColors(lua_State *L); +int w_Geometry_getDrawMode(lua_State *L); +int w_Geometry_getVertexMap(lua_State *L); +int w_Geometry_setVertexMap(lua_State *L); extern "C" int luaopen_geometry(lua_State *L); } // opengl diff --git a/src/modules/graphics/opengl/wrap_Graphics.cpp b/src/modules/graphics/opengl/wrap_Graphics.cpp index 8677db80f..a90639be6 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -234,22 +234,99 @@ int w_newImage(lua_State *L) int w_newGeometry(lua_State *L) { - std::vector vertices; luaL_checktype(L, 1, LUA_TTABLE); - size_t n = lua_objlen(L, 1); - if (n < 3) - return luaL_error(L, "Need at least three points to construct a geometry."); + // Determine whether a table of vertices is being given. We assume it is if + // type(args[1][1]) == "table", otherwise assume the args are the verts. + lua_rawgeti(L, 1, 1); + bool is_table = lua_istable(L, -1); + lua_pop(L, 1); + + // Get rid of any trailing nils in the arg list (it messes with our style.) + for (int i = lua_gettop(L); i >= 2; i--) + { + if (lua_isnil(L, i)) + lua_pop(L, 1); + else + break; + } + + Geometry::DrawMode mode = Geometry::DRAW_MODE_FAN; + std::string txt; + bool has_vertexmap = false; + + // The last argument (or second-last) may be an optional draw mode. + if (lua_type(L, -1) == LUA_TSTRING) + { + txt = luaL_checkstring(L, -1); + lua_remove(L, -1); + } + else if (lua_type(L, -2) == LUA_TSTRING && lua_istable(L, -1)) + { + txt = luaL_checkstring(L, -2); + lua_remove(L, -2); + + // If the draw mode is the second-last argument, the last argument will + // be the vertex map. + has_vertexmap = true; + } + + if (txt.length() > 0 && !Geometry::getConstant(txt.c_str(), mode)) + return luaL_error(L, "Invalid Geometry draw mode: %s", txt.c_str()); + + std::vector vertexmap; + + // Get the vertex map table, if it exists. + if (has_vertexmap) + { + // It will always be the last argument. + int tableidx = lua_gettop(L); + + size_t elementcount = lua_objlen(L, -1); + vertexmap.reserve(elementcount); + + for (size_t i = 0; i < elementcount; i++) + { + lua_rawgeti(L, tableidx, i + 1); + if (!lua_isnumber(L, -1)) + return luaL_argerror(L, tableidx + 1, "vertex index expected"); + + vertexmap.push_back(lua_tointeger(L, -1) - 1); + lua_pop(L, 1); + } + + // We don't want to read the vertex map as a vertex table later. + lua_remove(L, -1); + } + + size_t vertexcount = is_table ? lua_objlen(L, 1) : lua_gettop(L); + if (vertexcount < 3) + return luaL_error(L, "At least three points are needed to construct a Geometry."); + + if (!lua_checkstack(L, 9)) + return luaL_error(L, "Too many arguments!"); bool hasvertexcolors = false; - vertices.reserve(n); - for (size_t i = 0; i < n; ++i) + std::vector vertices; + vertices.reserve(vertexcount); + + for (size_t i = 0; i < vertexcount; ++i) { vertex v; - lua_rawgeti(L, 1, i+1); - if (!lua_istable(L, -1)) - return luax_typerror(L, 1, "table of tables"); + + if (is_table) + { + lua_rawgeti(L, 1, i+1); + if (!lua_istable(L, -1)) + return luaL_typerror(L, 1, "table of tables"); + } + else + { + // Push the vertex table at this arg index to the top of the stack. + luaL_checktype(L, i + 1, LUA_TTABLE); + lua_pushvalue(L, i + 1); + } for (int j = 1; j <= 8; j++) lua_rawgeti(L, -j, j); @@ -260,13 +337,15 @@ int w_newGeometry(lua_State *L) v.s = luaL_checknumber(L, -6); v.t = luaL_checknumber(L, -5); - v.r = luaL_optint(L, -4, 255); - v.g = luaL_optint(L, -3, 255); - v.b = luaL_optint(L, -2, 255); - v.a = luaL_optint(L, -1, 255); + v.r = luaL_optinteger(L, -4, 255); + v.g = luaL_optinteger(L, -3, 255); + v.b = luaL_optinteger(L, -2, 255); + v.a = luaL_optinteger(L, -1, 255); lua_pop(L, 9); + // Custom vertex colors are disabled by default unless a unique color + // is used for at least one vertex. if (v.r != 255 || v.g != 255 || v.b != 255 || v.a != 255) hasvertexcolors = true; @@ -276,7 +355,7 @@ int w_newGeometry(lua_State *L) Geometry *geom = 0; try { - geom = instance->newGeometry(vertices); + geom = instance->newGeometry(vertices, vertexmap, mode); } catch (love::Exception &e) { @@ -288,7 +367,7 @@ int w_newGeometry(lua_State *L) geom->setVertexColors(hasvertexcolors); - luax_newtype(L, "Geometry", GRAPHICS_GEOMETRY_T, (void *)geom); + luax_newtype(L, "Geometry", GRAPHICS_GEOMETRY_T, (void *) geom); return 1; }