From ba7e69d776a71f0589e61a2ae34cc0e6f1ba8184 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 21 Jan 2014 06:16:47 -0400 Subject: [PATCH] Added Mesh:setDrawRange(min, max) and Mesh:getDrawRange(). If no vertex map is set, this restricts the drawn vertices to those whose indices in the vertex array are between [min, max] inclusive. If a vertex map is set, this restricts the values used in the vertex map to those whose indices in the vertex map array are between [min, max] inclusive. Added Mesh constructor variant: love.graphics.newMesh(vertexcount, texture, drawmode). Creates a Mesh with a certain number of vertices with x,y,u,v,r,g,b,a values of (0,0,0,0,255,255,255,255). --- src/modules/graphics/opengl/Graphics.cpp | 5 + src/modules/graphics/opengl/Graphics.h | 1 + src/modules/graphics/opengl/Mesh.cpp | 89 ++++++++++++++--- src/modules/graphics/opengl/Mesh.h | 18 ++++ src/modules/graphics/opengl/wrap_Graphics.cpp | 96 ++++++++++--------- src/modules/graphics/opengl/wrap_Mesh.cpp | 34 +++++++ src/modules/graphics/opengl/wrap_Mesh.h | 2 + 7 files changed, 191 insertions(+), 54 deletions(-) diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 075887c4a..e6469a512 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -460,6 +460,11 @@ Mesh *Graphics::newMesh(const std::vector &vertices, Mesh::DrawMode mode return new Mesh(vertices, mode); } +Mesh *Graphics::newMesh(int vertexcount, Mesh::DrawMode mode) +{ + return new Mesh(vertexcount, mode); +} + void Graphics::setColor(const Color &c) { gl.setColor(c); diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index 1dc2c5c82..54e90e9e7 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -213,6 +213,7 @@ public: Shader *newShader(const Shader::ShaderSources &sources); Mesh *newMesh(const std::vector &vertices, Mesh::DrawMode mode = Mesh::DRAW_MODE_FAN); + Mesh *newMesh(int vertexcount, Mesh::DrawMode mode = Mesh::DRAW_MODE_FAN); /** * Sets the foreground color. diff --git a/src/modules/graphics/opengl/Mesh.cpp b/src/modules/graphics/opengl/Mesh.cpp index 12fa91d91..becae3596 100644 --- a/src/modules/graphics/opengl/Mesh.cpp +++ b/src/modules/graphics/opengl/Mesh.cpp @@ -23,6 +23,9 @@ #include "common/Matrix.h" #include "common/Exception.h" +// C++ +#include + namespace love { namespace graphics @@ -37,6 +40,8 @@ Mesh::Mesh(const std::vector &verts, Mesh::DrawMode mode) , element_count(0) , instance_count(1) , draw_mode(mode) + , range_min(-1) + , range_max(-1) , texture(nullptr) , colors_enabled(false) , wireframe(false) @@ -44,6 +49,35 @@ Mesh::Mesh(const std::vector &verts, Mesh::DrawMode mode) setVertices(verts); } +Mesh::Mesh(int vertexcount, Mesh::DrawMode mode) + : vbo(nullptr) + , vertex_count(0) + , ibo(nullptr) + , element_count(0) + , draw_mode(mode) + , range_min(-1) + , range_max(-1) + , texture(nullptr) + , colors_enabled(false) + , wireframe(false) +{ + if (vertexcount < 1) + throw love::Exception("Invalid number of vertices."); + + std::vector verts(vertexcount); + + // Default-initialized vertices should have a white opaque color. + for (size_t i = 0; i < verts.size(); i++) + { + verts[i].r = 255; + verts[i].g = 255; + verts[i].b = 255; + verts[i].a = 255; + } + + setVertices(verts); +} + Mesh::~Mesh() { delete vbo; @@ -163,7 +197,7 @@ const uint32 *Mesh::getVertexMap() const return (uint32 *) ibo->map(); } - return 0; + return nullptr; } size_t Mesh::getVertexMapCount() const @@ -173,10 +207,7 @@ size_t Mesh::getVertexMapCount() const void Mesh::setInstanceCount(int count) { - if (count < 1) - count = 1; - - instance_count = count; + instance_count = std::max(count, 1); } int Mesh::getInstanceCount() const @@ -217,6 +248,26 @@ Mesh::DrawMode Mesh::getDrawMode() const return draw_mode; } +void Mesh::setDrawRange(int min, int max) +{ + if (min < 0 || max < 0 || min > max) + throw love::Exception("Invalid draw range."); + + range_min = min; + range_max = max; +} + +void Mesh::setDrawRange() +{ + range_min = range_max = -1; +} + +void Mesh::getDrawRange(int &min, int &max) const +{ + min = range_min; + max = range_max; +} + void Mesh::setVertexColors(bool enable) { colors_enabled = enable; @@ -290,21 +341,37 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo // Make sure the index buffer isn't mapped (sends data to GPU if needed.) ibo->unmap(); - const void *indices = ibo->getPointer(0); - const GLenum type = GL_UNSIGNED_INT; + int max = element_count - 1; + if (range_max >= 0) + max = std::min(std::max(range_max, 0), (int) element_count - 1); + + int min = 0; + if (range_min >= 0) + min = std::min(std::max(range_min, 0), max); + + const void *indices = ibo->getPointer(min * sizeof(uint32)); + GLenum type = GL_UNSIGNED_INT; if (instance_count > 1) - gl.drawElementsInstanced(mode, element_count, type, indices, instance_count); + gl.drawElementsInstanced(mode, max - min + 1, type, indices, instance_count); else - glDrawElements(mode, element_count, type, indices); + glDrawElements(mode, max - min + 1, type, indices); } else { + int max = vertex_count - 1; + if (range_max >= 0) + max = std::min(std::max(range_max, 0), (int) vertex_count - 1); + + int min = 0; + if (range_min >= 0) + min = std::min(std::max(range_min, 0), max); + // Normal non-indexed drawing (no custom vertex map.) if (instance_count > 1) - gl.drawArraysInstanced(mode, 0, vertex_count, instance_count); + gl.drawArraysInstanced(mode, min, max - min + 1, instance_count); else - glDrawArrays(mode, 0, vertex_count); + glDrawArrays(mode, min, max - min + 1); } if (wireframe) diff --git a/src/modules/graphics/opengl/Mesh.h b/src/modules/graphics/opengl/Mesh.h index ab2c02967..7719c1c58 100644 --- a/src/modules/graphics/opengl/Mesh.h +++ b/src/modules/graphics/opengl/Mesh.h @@ -22,6 +22,7 @@ #define LOVE_GRAPHICS_OPENGL_MESH_H // LOVE +#include "common/config.h" #include "common/int.h" #include "common/math.h" #include "common/StringMap.h" @@ -64,6 +65,16 @@ public: * @param mode The draw mode to use when drawing the Mesh. **/ Mesh(const std::vector &verts, DrawMode mode = DRAW_MODE_FAN); + + /** + * Constructor. + * Creates a Mesh with a certain number of default-initialized (hidden) + * vertices. + * @param vertexcount The number of vertices to use in the Mesh. + * @param mode The draw mode to use when drawing the Mesh. + **/ + Mesh(int vertexcount, DrawMode mode = DRAW_MODE_FAN); + virtual ~Mesh(); /** @@ -140,6 +151,10 @@ public: void setDrawMode(DrawMode mode); DrawMode getDrawMode() const; + void setDrawRange(int min, int max); + void setDrawRange(); + void getDrawRange(int &min, int &max) const; + /** * Sets whether per-vertex colors are enabled. If this is disabled, the * global color (love.graphics.setColor) will be used for the entire Mesh. @@ -178,6 +193,9 @@ private: DrawMode draw_mode; + int range_min; + int range_max; + Texture *texture; // Whether the per-vertex colors are used when drawing. diff --git a/src/modules/graphics/opengl/wrap_Graphics.cpp b/src/modules/graphics/opengl/wrap_Graphics.cpp index 0fcf827b9..da0aac721 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -440,8 +440,10 @@ int w_newShader(lua_State *L) int w_newMesh(lua_State *L) { - // Check first argument: mandatory table of vertices. - luaL_checktype(L, 1, LUA_TTABLE); + // Check first argument: table of vertices or number of vertices. + int ttype = lua_type(L, 1); + if (ttype != LUA_TTABLE && ttype != LUA_TNUMBER) + luaL_argerror(L, 1, "table or number expected"); // Second argument: optional texture. Texture *tex = nullptr; @@ -456,52 +458,60 @@ int w_newMesh(lua_State *L) if (str && !Mesh::getConstant(str, mode)) return luaL_error(L, "Invalid mesh draw mode: %s", str); - size_t vertex_count = lua_objlen(L, 1); - std::vector vertices; - vertices.reserve(vertex_count); - - bool use_colors = false; - - // Get the vertices from the table. - for (size_t i = 1; i <= vertex_count; i++) - { - lua_rawgeti(L, 1, i); - - if (lua_type(L, -1) != LUA_TTABLE) - return luax_typerror(L, 1, "table of tables"); - - for (int j = 1; j <= 8; j++) - lua_rawgeti(L, -j, j); - - Vertex v; - - v.x = (float) luaL_checknumber(L, -8); - v.y = (float) luaL_checknumber(L, -7); - - v.s = (float) luaL_checknumber(L, -6); - v.t = (float) luaL_checknumber(L, -5); - - v.r = (unsigned char) luaL_optinteger(L, -4, 255); - v.g = (unsigned char) luaL_optinteger(L, -3, 255); - v.b = (unsigned char) luaL_optinteger(L, -2, 255); - v.a = (unsigned char) luaL_optinteger(L, -1, 255); - - // Enable per-vertex coloring if any color is not the default. - if (!use_colors && (v.r != 255 || v.g != 255 || v.b != 255 || v.a != 255)) - use_colors = true; - - lua_pop(L, 9); - vertices.push_back(v); - } - Mesh *t = nullptr; - EXCEPT_GUARD(t = instance->newMesh(vertices, mode);) + + if (ttype == LUA_TTABLE) + { + size_t vertex_count = lua_objlen(L, 1); + std::vector vertices; + vertices.reserve(vertex_count); + + bool use_colors = false; + + // Get the vertices from the table. + for (size_t i = 1; i <= vertex_count; i++) + { + lua_rawgeti(L, 1, i); + + if (lua_type(L, -1) != LUA_TTABLE) + return luax_typerror(L, 1, "table of tables"); + + for (int j = 1; j <= 8; j++) + lua_rawgeti(L, -j, j); + + Vertex v; + + v.x = (float) luaL_checknumber(L, -8); + v.y = (float) luaL_checknumber(L, -7); + + v.s = (float) luaL_checknumber(L, -6); + v.t = (float) luaL_checknumber(L, -5); + + v.r = (unsigned char) luaL_optinteger(L, -4, 255); + v.g = (unsigned char) luaL_optinteger(L, -3, 255); + v.b = (unsigned char) luaL_optinteger(L, -2, 255); + v.a = (unsigned char) luaL_optinteger(L, -1, 255); + + // Enable per-vertex coloring if any color is not the default. + if (!use_colors && (v.r != 255 || v.g != 255 || v.b != 255 || v.a != 255)) + use_colors = true; + + lua_pop(L, 9); + vertices.push_back(v); + } + + EXCEPT_GUARD(t = instance->newMesh(vertices, mode);) + t->setVertexColors(use_colors); + } + else + { + int count = luaL_checkint(L, 1); + EXCEPT_GUARD(t = instance->newMesh(count, mode);) + } if (tex) t->setTexture(tex); - t->setVertexColors(use_colors); - luax_pushtype(L, "Mesh", GRAPHICS_MESH_T, t); return 1; } diff --git a/src/modules/graphics/opengl/wrap_Mesh.cpp b/src/modules/graphics/opengl/wrap_Mesh.cpp index 84c5cfedd..4548030a1 100644 --- a/src/modules/graphics/opengl/wrap_Mesh.cpp +++ b/src/modules/graphics/opengl/wrap_Mesh.cpp @@ -315,6 +315,38 @@ int w_Mesh_getDrawMode(lua_State *L) return 1; } +int w_Mesh_setDrawRange(lua_State *L) +{ + Mesh *t = luax_checkmesh(L, 1); + + if (lua_isnoneornil(L, 2)) + t->setDrawRange(); + else + { + int rangemin = luaL_checkint(L, 2) - 1; + int rangemax = luaL_checkint(L, 3) - 1; + EXCEPT_GUARD(t->setDrawRange(rangemin, rangemax);) + } + + return 0; +} + +int w_Mesh_getDrawRange(lua_State *L) +{ + Mesh *t = luax_checkmesh(L, 1); + + int rangemin = -1; + int rangemax = -1; + t->getDrawRange(rangemin, rangemax); + + if (rangemin < 0 || rangemax < 0) + return 0; + + lua_pushinteger(L, rangemin + 1); + lua_pushinteger(L, rangemax + 1); + return 2; +} + int w_Mesh_setVertexColors(lua_State *L) { Mesh *t = luax_checkmesh(L, 1); @@ -358,6 +390,8 @@ static const luaL_Reg functions[] = { "getTexture", w_Mesh_getTexture }, { "setDrawMode", w_Mesh_setDrawMode }, { "getDrawMode", w_Mesh_getDrawMode }, + { "setDrawRange", w_Mesh_setDrawRange }, + { "getDrawRange", w_Mesh_getDrawRange }, { "setVertexColors", w_Mesh_setVertexColors }, { "hasVertexColors", w_Mesh_hasVertexColors }, { "setWireframe", w_Mesh_setWireframe }, diff --git a/src/modules/graphics/opengl/wrap_Mesh.h b/src/modules/graphics/opengl/wrap_Mesh.h index 2e3a381f2..9b4cdc77a 100644 --- a/src/modules/graphics/opengl/wrap_Mesh.h +++ b/src/modules/graphics/opengl/wrap_Mesh.h @@ -47,6 +47,8 @@ int w_Mesh_setTexture(lua_State *L); int w_Mesh_getTexture(lua_State *L); int w_Mesh_setDrawMode(lua_State *L); int w_Mesh_getDrawMode(lua_State *L); +int w_Mesh_setDrawRange(lua_State *L); +int w_Mesh_getDrawRange(lua_State *L); int w_Mesh_setVertexColors(lua_State *L); int w_Mesh_hasVertexColors(lua_State *L); int w_Mesh_setWireframe(lua_State *L);