From a37c2fb9a9b1ebab7e6e9f22d43ef8b9d317f776 Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Sat, 10 Dec 2022 21:11:59 -0400 Subject: [PATCH] Mesh:attachAttribute: add an optional start array index parameter. Allows easier use of a single instance buffer with multiple draws when instanced attributes are used (#1878). --- src/modules/graphics/Mesh.cpp | 11 ++++++++--- src/modules/graphics/Mesh.h | 3 ++- src/modules/graphics/wrap_Mesh.cpp | 8 ++++++-- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/modules/graphics/Mesh.cpp b/src/modules/graphics/Mesh.cpp index adbde8a4d..da44759bc 100644 --- a/src/modules/graphics/Mesh.cpp +++ b/src/modules/graphics/Mesh.cpp @@ -140,7 +140,7 @@ void Mesh::setupAttachedAttributes() if (getAttachedAttributeIndex(name) != -1) throw love::Exception("Duplicate vertex attribute name: %s", name.c_str()); - attachedAttributes.push_back({name, vertexBuffer, nullptr, (int) i, STEP_PER_VERTEX, true}); + attachedAttributes.push_back({name, vertexBuffer, nullptr, (int) i, 0, STEP_PER_VERTEX, true}); } } @@ -208,7 +208,7 @@ bool Mesh::isAttributeEnabled(const std::string &name) const return attachedAttributes[index].enabled; } -void Mesh::attachAttribute(const std::string &name, Buffer *buffer, Mesh *mesh, const std::string &attachname, AttributeStep step) +void Mesh::attachAttribute(const std::string &name, Buffer *buffer, Mesh *mesh, const std::string &attachname, int startindex, AttributeStep step) { if ((buffer->getUsageFlags() & BUFFERUSAGEFLAG_VERTEX) == 0) throw love::Exception("Buffer must be created with vertex buffer support to be used as a Mesh vertex attribute."); @@ -217,6 +217,9 @@ void Mesh::attachAttribute(const std::string &name, Buffer *buffer, Mesh *mesh, if (step == STEP_PER_INSTANCE && !gfx->getCapabilities().features[Graphics::FEATURE_INSTANCING]) throw love::Exception("Vertex attribute instancing is not supported on this system."); + if (startindex < 0 || startindex >= (int) buffer->getArrayLength()) + throw love::Exception("Invalid start array index %d.", startindex + 1); + BufferAttribute oldattrib = {}; BufferAttribute newattrib = {}; @@ -231,6 +234,7 @@ void Mesh::attachAttribute(const std::string &name, Buffer *buffer, Mesh *mesh, newattrib.mesh = mesh; newattrib.enabled = oldattrib.buffer.get() ? oldattrib.enabled : true; newattrib.indexInBuffer = buffer->getDataMemberIndex(attachname); + newattrib.startArrayIndex = startindex; newattrib.step = step; if (newattrib.indexInBuffer < 0) @@ -578,12 +582,13 @@ void Mesh::drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount) uint16 offset = (uint16) member.offset; uint16 stride = (uint16) buffer->getArrayStride(); + size_t bufferoffset = (size_t) stride * attrib.startArrayIndex; attributes.set(attributeindex, member.decl.format, offset, activebuffers); attributes.setBufferLayout(activebuffers, stride, attrib.step); // TODO: Ideally we want to reuse buffers with the same stride+step. - buffers.set(activebuffers, buffer, 0); + buffers.set(activebuffers, buffer, bufferoffset); activebuffers++; } } diff --git a/src/modules/graphics/Mesh.h b/src/modules/graphics/Mesh.h index a3a67fa2f..47adc7dc2 100644 --- a/src/modules/graphics/Mesh.h +++ b/src/modules/graphics/Mesh.h @@ -57,6 +57,7 @@ public: StrongRef buffer; StrongRef mesh; int indexInBuffer; + int startArrayIndex; AttributeStep step; bool enabled; }; @@ -109,7 +110,7 @@ public: * to make sure this Mesh knows to flush the passed in Mesh's data to its * buffer when drawing. **/ - void attachAttribute(const std::string &name, Buffer *buffer, Mesh *mesh, const std::string &attachname, AttributeStep step = STEP_PER_VERTEX); + void attachAttribute(const std::string &name, Buffer *buffer, Mesh *mesh, const std::string &attachname, int startindex = 0, AttributeStep step = STEP_PER_VERTEX); bool detachAttribute(const std::string &name); const std::vector &getAttachedAttributes() const; diff --git a/src/modules/graphics/wrap_Mesh.cpp b/src/modules/graphics/wrap_Mesh.cpp index 8096c0509..709739c76 100644 --- a/src/modules/graphics/wrap_Mesh.cpp +++ b/src/modules/graphics/wrap_Mesh.cpp @@ -314,8 +314,9 @@ int w_Mesh_attachAttribute(lua_State *L) return luax_enumerror(L, "vertex attribute step", getConstants(step), stepstr); const char *attachname = luaL_optstring(L, 5, name); + int startindex = (int) luaL_optinteger(L, 6, 1) - 1; - luax_catchexcept(L, [&](){ t->attachAttribute(name, buffer, mesh, attachname, step); }); + luax_catchexcept(L, [&](){ t->attachAttribute(name, buffer, mesh, attachname, startindex, step); }); return 0; } @@ -340,7 +341,7 @@ int w_Mesh_getAttachedAttributes(lua_State *L) { const auto &attrib = attributes[i]; - lua_createtable(L, 4, 0); + lua_createtable(L, 5, 0); luax_pushstring(L, attrib.name); lua_rawseti(L, -1, 1); @@ -358,6 +359,9 @@ int w_Mesh_getAttachedAttributes(lua_State *L) luax_pushstring(L, member.decl.name); lua_rawseti(L, -1, 4); + lua_pushinteger(L, attrib.startArrayIndex + 1); + lua_rawseti(L, -1, 5); + lua_rawseti(L, -1, i + 1); }