diff --git a/src/modules/graphics/Mesh.cpp b/src/modules/graphics/Mesh.cpp index 98fff062d..8897d6ac1 100644 --- a/src/modules/graphics/Mesh.cpp +++ b/src/modules/graphics/Mesh.cpp @@ -121,10 +121,13 @@ Mesh::Mesh(const std::vector &attributes, PrimitiveType d attachedAttributes = attributes; - vertexCount = LOVE_UINT32_MAX; + vertexCount = attachedAttributes.size() > 0 ? LOVE_UINT32_MAX : 0; for (const auto &attrib : attachedAttributes) { + if ((attrib.buffer->getTypeFlags() & Buffer::TYPEFLAG_VERTEX) == 0) + throw love::Exception("Buffer must be created with vertex buffer support to be used as a Mesh vertex attribute."); + if (getAttachedAttributeIndex(attrib.name) != -1) throw love::Exception("Duplicate vertex attribute name: %s", attrib.name.c_str()); @@ -268,17 +271,6 @@ const std::vector &Mesh::getVertexFormat() const return vertexFormat; } -int Mesh::getAttributeIndex(const std::string &name) const -{ - for (int i = 0; i < (int) vertexFormat.size(); i++) - { - if (vertexFormat[i].decl.name == name) - return i; - } - - return -1; -} - void Mesh::setAttributeEnabled(const std::string &name, bool enable) { int index = getAttachedAttributeIndex(name); @@ -317,10 +309,10 @@ void Mesh::attachAttribute(const std::string &name, Buffer *buffer, const std::s newattrib.buffer = buffer; newattrib.enabled = oldattrib.buffer.get() ? oldattrib.enabled : true; - newattrib.index = buffer->getDataMemberIndex(attachname); + newattrib.indexInBuffer = buffer->getDataMemberIndex(attachname); newattrib.step = step; - if (newattrib.index < 0) + if (newattrib.indexInBuffer < 0) throw love::Exception("The specified vertex buffer does not have a vertex attribute named '%s'", attachname.c_str()); if (oldindex != -1) @@ -337,7 +329,7 @@ bool Mesh::detachAttribute(const std::string &name) attachedAttributes.erase(attachedAttributes.begin() + index); - if (getAttributeIndex(name) != -1) + if (vertexBuffer.get() && vertexBuffer->getDataMemberIndex(name) != -1) attachAttribute(name, vertexBuffer, name); return true; @@ -594,9 +586,9 @@ void Mesh::drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount) // Make sure the buffer isn't mapped (sends data to GPU if needed.) buffer->unmap(); - const auto &member = buffer->getDataMember(attrib.index); + const auto &member = buffer->getDataMember(attrib.indexInBuffer); - uint16 offset = (uint16) buffer->getMemberOffset(attrib.index); + uint16 offset = (uint16) member.offset; uint16 stride = (uint16) buffer->getArrayStride(); attributes.set(attributeindex, member.decl.format, offset, activebuffers); diff --git a/src/modules/graphics/Mesh.h b/src/modules/graphics/Mesh.h index 0c81642fc..83165adf4 100644 --- a/src/modules/graphics/Mesh.h +++ b/src/modules/graphics/Mesh.h @@ -54,7 +54,7 @@ public: { std::string name; StrongRef buffer; - int index; + int indexInBuffer; AttributeStep step; bool enabled; }; @@ -101,7 +101,6 @@ public: * Gets the format of each vertex attribute stored in the Mesh. **/ const std::vector &getVertexFormat() const; - int getAttributeIndex(const std::string &name) const; /** * Sets whether a specific vertex attribute is used when drawing the Mesh. diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index 418a89e23..fa7895535 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -1557,7 +1557,7 @@ static Mesh *newStandardMesh(lua_State *L) PrimitiveType drawmode = luax_optmeshdrawmode(L, 2, PRIMITIVE_TRIANGLE_FAN); BufferUsage usage = luax_optmeshusage(L, 3, BUFFERUSAGE_DYNAMIC); - auto format = Mesh::getDefaultVertexFormat(); + std::vector format = Mesh::getDefaultVertexFormat(); // First argument is a table of standard vertices, or the number of // standard vertices. diff --git a/src/modules/graphics/wrap_Mesh.cpp b/src/modules/graphics/wrap_Mesh.cpp index f3b132594..15e32e71d 100644 --- a/src/modules/graphics/wrap_Mesh.cpp +++ b/src/modules/graphics/wrap_Mesh.cpp @@ -298,6 +298,8 @@ int w_Mesh_attachAttribute(lua_State *L) { Mesh *mesh = luax_checkmesh(L, 3); buffer = mesh->getVertexBuffer(); + if (buffer == nullptr) + return luaL_error(L, "Mesh does not have its own vertex buffer."); } AttributeStep step = STEP_PER_VERTEX; @@ -321,6 +323,41 @@ int w_Mesh_detachAttribute(lua_State *L) return 1; } +int w_Mesh_getAttachedAttributes(lua_State *L) +{ + Mesh *t = luax_checkmesh(L, 1); + const auto &attributes = t->getAttachedAttributes(); + + lua_createtable(L, (int) attributes.size(), 0); + + for (int i = 0; i < (int) attributes.size(); i++) + { + const auto &attrib = attributes[i]; + + lua_createtable(L, 4, 0); + + luax_pushstring(L, attrib.name); + lua_rawseti(L, -1, 1); + + luax_pushtype(L, attrib.buffer.get()); + lua_rawseti(L, -1, 2); + + const char *stepstr = nullptr; + if (!getConstant(attrib.step, stepstr)) + return luaL_error(L, "Invalid vertex attribute step."); + lua_pushstring(L, stepstr); + lua_rawseti(L, -1, 3); + + const Buffer::DataMember &member = attrib.buffer->getDataMember(attrib.indexInBuffer); + luax_pushstring(L, member.decl.name); + lua_rawseti(L, -1, 4); + + lua_rawseti(L, -1, i + 1); + } + + return 1; +} + int w_Mesh_flush(lua_State *L) { Mesh *t = luax_checkmesh(L, 1); @@ -507,6 +544,7 @@ static const luaL_Reg w_Mesh_functions[] = { "isAttributeEnabled", w_Mesh_isAttributeEnabled }, { "attachAttribute", w_Mesh_attachAttribute }, { "detachAttribute", w_Mesh_detachAttribute }, + { "getAttachedAttributes", w_Mesh_getAttachedAttributes }, { "flush", w_Mesh_flush }, { "setVertexMap", w_Mesh_setVertexMap }, { "getVertexMap", w_Mesh_getVertexMap },