diff --git a/src/modules/graphics/opengl/Mesh.cpp b/src/modules/graphics/opengl/Mesh.cpp index 7a71c03c5..56450e2c5 100644 --- a/src/modules/graphics/opengl/Mesh.cpp +++ b/src/modules/graphics/opengl/Mesh.cpp @@ -69,7 +69,7 @@ Mesh::Mesh(const std::vector &vertexformat, const void *data, size , ibo(nullptr) , useIndexBuffer(false) , elementCount(0) - , elementDataType(0) + , elementDataType(INDEX_UINT16) , drawMode(drawmode) , rangeStart(-1) , rangeCount(-1) @@ -78,7 +78,7 @@ Mesh::Mesh(const std::vector &vertexformat, const void *data, size calculateAttributeSizes(); vertexCount = datasize / vertexStride; - elementDataType = getGLDataTypeFromMax(vertexCount); + elementDataType = getIndexTypeFromMax(vertexCount); if (vertexCount == 0) throw love::Exception("Data size is too small for specified vertex attribute formats."); @@ -96,7 +96,7 @@ Mesh::Mesh(const std::vector &vertexformat, int vertexcount, DrawM , ibo(nullptr) , useIndexBuffer(false) , elementCount(0) - , elementDataType(getGLDataTypeFromMax(vertexcount)) + , elementDataType(getIndexTypeFromMax(vertexcount)) , drawMode(drawmode) , rangeStart(-1) , rangeCount(-1) @@ -406,10 +406,10 @@ void Mesh::setVertexMap(const std::vector &map) { size_t maxval = getVertexCount(); - GLenum datatype = getGLDataTypeFromMax(maxval); + IndexDataType datatype = getIndexTypeFromMax(maxval); // Calculate the size in bytes of the index buffer data. - size_t size = map.size() * getGLDataTypeSize(datatype); + size_t size = map.size() * vertex::getIndexDataSize(datatype); if (ibo && size > ibo->getSize()) { @@ -431,10 +431,10 @@ void Mesh::setVertexMap(const std::vector &map) // Fill the buffer with the index values from the vector. switch (datatype) { - case GL_UNSIGNED_SHORT: + case INDEX_UINT16: copyToIndexBuffer(map, ibomap, maxval); break; - case GL_UNSIGNED_INT: + case INDEX_UINT32: default: copyToIndexBuffer(map, ibomap, maxval); break; @@ -443,6 +443,29 @@ void Mesh::setVertexMap(const std::vector &map) elementDataType = datatype; } +void Mesh::setVertexMap(IndexDataType datatype, const void *data, size_t datasize) +{ + if (ibo && datasize > ibo->getSize()) + { + delete ibo; + ibo = nullptr; + } + + if (!ibo && datasize > 0) + ibo = new GLBuffer(datasize, nullptr, BUFFER_INDEX, vbo->getUsage()); + + elementCount = datasize / vertex::getIndexDataSize(datatype); + + if (!ibo || elementCount == 0) + return; + + GLBuffer::Mapper ibomap(*ibo); + memcpy(ibomap.get(), data, datasize); + + useIndexBuffer = true; + elementDataType = datatype; +} + void Mesh::setVertexMap() { useIndexBuffer = false; @@ -476,10 +499,10 @@ bool Mesh::getVertexMap(std::vector &map) const // Fill the vector from the buffer. switch (elementDataType) { - case GL_UNSIGNED_SHORT: + case INDEX_UINT16: copyFromIndexBuffer(buffer, elementCount, map); break; - case GL_UNSIGNED_INT: + case INDEX_UINT32: default: copyFromIndexBuffer(buffer, elementCount, map); break; @@ -626,8 +649,9 @@ void Mesh::draw(Graphics *gfx, const Matrix4 &m) count = std::min(count, (int) elementCount - start); - GLenum type = elementDataType; - const void *indices = ibo->getPointer(start * getGLDataTypeSize(type)); + size_t elementsize = vertex::getIndexDataSize(elementDataType); + const void *indices = ibo->getPointer(start * elementsize); + GLenum type = OpenGL::getGLIndexDataType(elementDataType); if (count > 0) gl.drawElements(getGLDrawMode(drawMode), count, type, indices); @@ -690,27 +714,12 @@ GLenum Mesh::getGLDataType(DataType type) } } -GLenum Mesh::getGLDataTypeFromMax(size_t maxvalue) +IndexDataType Mesh::getIndexTypeFromMax(size_t maxvalue) { if (maxvalue > LOVE_UINT16_MAX) - return GL_UNSIGNED_INT; + return INDEX_UINT32; else - return GL_UNSIGNED_SHORT; -} - -size_t Mesh::getGLDataTypeSize(GLenum datatype) -{ - switch (datatype) - { - case GL_UNSIGNED_BYTE: - return sizeof(uint8); - case GL_UNSIGNED_SHORT: - return sizeof(uint16); - case GL_UNSIGNED_INT: - return sizeof(uint32); - default: - return 0; - } + return INDEX_UINT16; } bool Mesh::getConstant(const char *in, Mesh::DrawMode &out) diff --git a/src/modules/graphics/opengl/Mesh.h b/src/modules/graphics/opengl/Mesh.h index 71c23fcba..282fa3d3b 100644 --- a/src/modules/graphics/opengl/Mesh.h +++ b/src/modules/graphics/opengl/Mesh.h @@ -150,6 +150,7 @@ public: * {0, 1, 2, 3, 4, ...} **/ void setVertexMap(const std::vector &map); + void setVertexMap(IndexDataType datatype, const void *data, size_t datasize); void setVertexMap(); /** @@ -215,10 +216,10 @@ private: static size_t getAttribFormatSize(const AttribFormat &format); + static IndexDataType getIndexTypeFromMax(size_t maxvalue); + static GLenum getGLDrawMode(DrawMode mode); static GLenum getGLDataType(DataType type); - static GLenum getGLDataTypeFromMax(size_t maxvalue); - static size_t getGLDataTypeSize(GLenum datatype); std::vector vertexFormat; std::vector attributeSizes; @@ -238,7 +239,7 @@ private: GLBuffer *ibo; bool useIndexBuffer; size_t elementCount; - GLenum elementDataType; + IndexDataType elementDataType; DrawMode drawMode; diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index 38c301f6e..f3b079956 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -379,6 +379,19 @@ GLenum OpenGL::getGLBufferType(BufferType type) } } +GLenum OpenGL::getGLIndexDataType(IndexDataType type) +{ + switch (type) + { + case INDEX_UINT16: + return GL_UNSIGNED_SHORT; + case INDEX_UINT32: + return GL_UNSIGNED_INT; + default: + return GL_ZERO; + } +} + GLenum OpenGL::getGLBufferUsage(vertex::Usage usage) { switch (usage) diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index 51f2ba9ce..b7f5a5167 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/src/modules/graphics/opengl/OpenGL.h @@ -361,6 +361,7 @@ public: Vendor getVendor() const; static GLenum getGLBufferType(BufferType type); + static GLenum getGLIndexDataType(IndexDataType type); static GLenum getGLBufferUsage(vertex::Usage usage); static GLint getGLWrapMode(Texture::WrapMode wmode); diff --git a/src/modules/graphics/opengl/wrap_Mesh.cpp b/src/modules/graphics/opengl/wrap_Mesh.cpp index 0085b9b81..17aad520f 100644 --- a/src/modules/graphics/opengl/wrap_Mesh.cpp +++ b/src/modules/graphics/opengl/wrap_Mesh.cpp @@ -371,6 +371,26 @@ int w_Mesh_setVertexMap(lua_State *L) return 0; } + if (luax_istype(L, 2, Data::type)) + { + Data *d = luax_totype(L, 2, Data::type); + + const char *indextypestr = luaL_checkstring(L, 3); + IndexDataType indextype; + if (!vertex::getConstant(indextypestr, indextype)) + return luaL_error(L, "Invalid index data type: %s", indextypestr); + + size_t datatypesize = vertex::getIndexDataSize(indextype); + + int indexcount = (int) luaL_optnumber(L, 4, d->getSize() / datatypesize); + + if (indexcount < 1 || indexcount * datatypesize > d->getSize()) + return luaL_error(L, "Invalid index count: %d", indexcount); + + luax_catchexcept(L, [&]() { t->setVertexMap(indextype, d->getData(), indexcount * datatypesize); }); + return 0; + } + bool is_table = lua_istable(L, 2); int nargs = is_table ? (int) luax_objlen(L, 2) : lua_gettop(L) - 1; diff --git a/src/modules/graphics/vertex.cpp b/src/modules/graphics/vertex.cpp index 626489516..96b2c2039 100644 --- a/src/modules/graphics/vertex.cpp +++ b/src/modules/graphics/vertex.cpp @@ -53,6 +53,19 @@ size_t getFormatStride(CommonFormat format) } } +size_t getIndexDataSize(IndexDataType type) +{ + switch (type) + { + case INDEX_UINT16: + return sizeof(uint16); + case INDEX_UINT32: + return sizeof(uint32); + default: + return 0; + } +} + int getIndexCount(TriangleIndexMode mode, int vertexCount) { switch (mode) @@ -130,6 +143,14 @@ void fillIndices(TriangleIndexMode mode, uint32 vertexStart, uint32 vertexCount, fillIndicesT(mode, vertexStart, vertexCount, indices); } +static StringMap::Entry indexTypeEntries[] = +{ + { "uint16", INDEX_UINT16 }, + { "uint32", INDEX_UINT32 }, +}; + +static StringMap indexTypes(indexTypeEntries, sizeof(indexTypeEntries)); + static StringMap::Entry usageEntries[] = { { "stream", USAGE_STREAM }, @@ -139,6 +160,16 @@ static StringMap::Entry usageEntries[] = static StringMap usages(usageEntries, sizeof(usageEntries)); +bool getConstant(const char *in, IndexDataType &out) +{ + return indexTypes.find(in, out); +} + +bool getConstant(IndexDataType in, const char *&out) +{ + return indexTypes.find(in, out); +} + bool getConstant(const char *in, Usage &out) { return usages.find(in, out); diff --git a/src/modules/graphics/vertex.h b/src/modules/graphics/vertex.h index 2be6a5e1a..eba88b6f3 100644 --- a/src/modules/graphics/vertex.h +++ b/src/modules/graphics/vertex.h @@ -58,6 +58,13 @@ enum BufferType BUFFER_MAX_ENUM }; +enum IndexDataType +{ + INDEX_UINT16, + INDEX_UINT32, + INDEX_MAX_ENUM +}; + namespace vertex { @@ -115,12 +122,16 @@ struct XYf_STus_RGBAub }; size_t getFormatStride(CommonFormat format); +size_t getIndexDataSize(IndexDataType type); int getIndexCount(TriangleIndexMode mode, int vertexCount); void fillIndices(TriangleIndexMode mode, uint16 vertexStart, uint16 vertexCount, uint16 *indices); void fillIndices(TriangleIndexMode mode, uint32 vertexStart, uint32 vertexCount, uint32 *indices); +bool getConstant(const char *in, IndexDataType &out); +bool getConstant(IndexDataType in, const char *&out); + bool getConstant(const char *in, Usage &out); bool getConstant(Usage in, const char *&out);