diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 5df3d4d0a..3630e3216 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -53,6 +53,7 @@ Graphics::Graphics() , width(0) , height(0) , created(false) + , activeStencil(false) , savedState() { currentWindow = love::window::sdl::Window::createSingleton(); @@ -383,6 +384,8 @@ void Graphics::defineStencil() glEnable(GL_STENCIL_TEST); glStencilFunc(GL_ALWAYS, 1, 1); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + + activeStencil = true; } void Graphics::useStencil(bool invert) @@ -394,8 +397,12 @@ void Graphics::useStencil(bool invert) void Graphics::discardStencil() { + if (!activeStencil) + return; + setColorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]); glDisable(GL_STENCIL_TEST); + activeStencil = false; } Image *Graphics::newImage(love::image::ImageData *data, Texture::Format format) diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index b68755d08..7ab7560cd 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -482,6 +482,8 @@ private: int height; bool created; + bool activeStencil; + DisplayState savedState; }; // Graphics diff --git a/src/modules/graphics/opengl/Mesh.cpp b/src/modules/graphics/opengl/Mesh.cpp index 62b8275c3..10597568f 100644 --- a/src/modules/graphics/opengl/Mesh.cpp +++ b/src/modules/graphics/opengl/Mesh.cpp @@ -38,6 +38,7 @@ Mesh::Mesh(const std::vector &verts, Mesh::DrawMode mode) , vertex_count(0) , ibo(nullptr) , element_count(0) + , element_data_type(getGLDataTypeFromMax(verts.size())) , instance_count(1) , draw_mode(mode) , range_min(-1) @@ -53,6 +54,7 @@ Mesh::Mesh(int vertexcount, Mesh::DrawMode mode) , vertex_count(0) , ibo(nullptr) , element_count(0) + , element_data_type(getGLDataTypeFromMax(vertexcount)) , draw_mode(mode) , range_min(-1) , range_max(-1) @@ -151,15 +153,42 @@ size_t Mesh::getVertexCount() const return vertex_count; } +/** + * Copies index data from a vector to a mapped index buffer. + **/ +template +static void copyToIndexBuffer(const std::vector &indices, VertexBuffer::Mapper &buffermap, size_t maxval) +{ + T *elems = (T *) buffermap.get(); + + for (size_t i = 0; i < indices.size(); i++) + { + if (indices[i] >= maxval) + throw love::Exception("Invalid vertex map value: %d", indices[i] + 1); + + elems[i] = (T) indices[i]; + } +} + void Mesh::setVertexMap(const std::vector &map) { - for (size_t i = 0; i < map.size(); i++) - { - if (map[i] >= vertex_count) - throw love::Exception("Invalid vertex map value: %d", map[i] + 1); - } + GLenum datatype = getGLDataTypeFromMax(vertex_count); - size_t size = sizeof(uint32) * map.size(); + // Calculate the size in bytes of the index buffer data. + size_t size = map.size(); + switch (datatype) + { + case GL_UNSIGNED_BYTE: + size *= sizeof(uint8); + break; + case GL_UNSIGNED_SHORT: + size *= sizeof(uint16); + break; + case GL_UNSIGNED_INT: + default: + size *= sizeof(uint32); + break; + } if (ibo && size > ibo->getSize()) { @@ -175,27 +204,68 @@ void Mesh::setVertexMap(const std::vector &map) element_count = map.size(); - if (ibo && element_count > 0) - { - VertexBuffer::Bind ibo_bind(*ibo); - VertexBuffer::Mapper ibo_map(*ibo); + if (!ibo || element_count == 0) + return; - // Fill the buffer. - memcpy(ibo_map.get(), &map[0], size); + VertexBuffer::Bind ibo_bind(*ibo); + VertexBuffer::Mapper ibo_map(*ibo); + + // Fill the buffer with the index values from the vector. + switch (datatype) + { + case GL_UNSIGNED_BYTE: + copyToIndexBuffer(map, ibo_map, vertex_count); + break; + case GL_UNSIGNED_SHORT: + copyToIndexBuffer(map, ibo_map, vertex_count); + break; + case GL_UNSIGNED_INT: + default: + copyToIndexBuffer(map, ibo_map, vertex_count); + break; } + + element_data_type = datatype; } -const uint32 *Mesh::getVertexMap() const +/** + * Copies index data from a mapped buffer to a vector. + **/ +template +static void copyFromIndexBuffer(void *buffer, std::vector &indices, size_t maxval) { - if (ibo && element_count > 0) + T *elems = (T *) buffer; + for (size_t i = 0; i < maxval; i++) + indices.push_back((uint32) elems[i]); +} + +void Mesh::getVertexMap(std::vector &map) const +{ + if (!ibo || element_count == 0) + return; + + map.clear(); + map.reserve(element_count); + + VertexBuffer::Bind ibo_bind(*ibo); + + // We unmap the buffer in Mesh::draw and Mesh::setVertexMap. + void *buffer = ibo->map(); + + // Fill the vector from the buffer. + switch (element_data_type) { - VertexBuffer::Bind ibo_bind(*ibo); - - // We unmap the buffer in Mesh::draw and Mesh::setVertexMap. - return (uint32 *) ibo->map(); + case GL_UNSIGNED_BYTE: + copyFromIndexBuffer(buffer, map, vertex_count); + break; + case GL_UNSIGNED_SHORT: + copyFromIndexBuffer(buffer, map, vertex_count); + break; + case GL_UNSIGNED_INT: + default: + copyFromIndexBuffer(buffer, map, vertex_count); + break; } - - return nullptr; } size_t Mesh::getVertexMapCount() const @@ -335,7 +405,7 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo min = std::min(std::max(range_min, 0), max); const void *indices = ibo->getPointer(min * sizeof(uint32)); - GLenum type = GL_UNSIGNED_INT; + GLenum type = element_data_type; if (instance_count > 1) gl.drawElementsInstanced(mode, max - min + 1, type, indices, instance_count); @@ -375,7 +445,7 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo texture->postdraw(); } -GLenum Mesh::getGLDrawMode(Mesh::DrawMode mode) const +GLenum Mesh::getGLDrawMode(DrawMode mode) const { switch (mode) { @@ -394,6 +464,16 @@ GLenum Mesh::getGLDrawMode(Mesh::DrawMode mode) const return GL_TRIANGLES; } +GLenum Mesh::getGLDataTypeFromMax(size_t maxvalue) const +{ + if (maxvalue > LOVE_UINT16_MAX) + return GL_UNSIGNED_INT; + else if (maxvalue > LOVE_UINT8_MAX) + return GL_UNSIGNED_SHORT; + else + return GL_UNSIGNED_BYTE; +} + bool Mesh::getConstant(const char *in, Mesh::DrawMode &out) { return drawModes.find(in, out); diff --git a/src/modules/graphics/opengl/Mesh.h b/src/modules/graphics/opengl/Mesh.h index 5e6e974fe..da73af438 100644 --- a/src/modules/graphics/opengl/Mesh.h +++ b/src/modules/graphics/opengl/Mesh.h @@ -109,11 +109,10 @@ public: void setVertexMap(const std::vector &map); /** - * Gets a pointer to the vertex map array. The pointer is only valid until - * the next function call in the graphics module. - * May return null if the vertex map is empty. + * Fills the uint32 vector passed into the method with the previously set + * vertex map (index buffer) values. **/ - const uint32 *getVertexMap() const; + void getVertexMap(std::vector &map) const; /** * Gets the total number of elements in the vertex map array. @@ -171,6 +170,7 @@ public: private: GLenum getGLDrawMode(DrawMode mode) const; + GLenum getGLDataTypeFromMax(size_t maxvalue) const; // Vertex buffer. VertexBuffer *vbo; @@ -179,6 +179,7 @@ private: // Element (vertex index) buffer, for the vertex map. VertexBuffer *ibo; size_t element_count; + GLenum element_data_type; int instance_count; diff --git a/src/modules/graphics/opengl/wrap_Mesh.cpp b/src/modules/graphics/opengl/wrap_Mesh.cpp index e3e8800b9..92a0371cf 100644 --- a/src/modules/graphics/opengl/wrap_Mesh.cpp +++ b/src/modules/graphics/opengl/wrap_Mesh.cpp @@ -220,14 +220,15 @@ int w_Mesh_setVertexMap(lua_State *L) int w_Mesh_getVertexMap(lua_State *L) { Mesh *t = luax_checkmesh(L, 1); - const uint32 *vertex_map = 0; - EXCEPT_GUARD(vertex_map = t->getVertexMap();) - size_t elements = t->getVertexMapCount(); + std::vector vertex_map; + EXCEPT_GUARD(t->getVertexMap(vertex_map);) - lua_createtable(L, elements, 0); + size_t element_count = vertex_map.size(); - for (size_t i = 0; i < elements; i++) + lua_createtable(L, element_count, 0); + + for (size_t i = 0; i < element_count; i++) { lua_pushinteger(L, lua_Integer(vertex_map[i]) + 1); lua_rawseti(L, -2, i + 1);