Browse Source

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).
Sasha Szpakowski 2 years ago
parent
commit
a37c2fb9a9

+ 8 - 3
src/modules/graphics/Mesh.cpp

@@ -140,7 +140,7 @@ void Mesh::setupAttachedAttributes()
 		if (getAttachedAttributeIndex(name) != -1)
 		if (getAttachedAttributeIndex(name) != -1)
 			throw love::Exception("Duplicate vertex attribute name: %s", name.c_str());
 			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;
 	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)
 	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.");
 		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])
 	if (step == STEP_PER_INSTANCE && !gfx->getCapabilities().features[Graphics::FEATURE_INSTANCING])
 		throw love::Exception("Vertex attribute instancing is not supported on this system.");
 		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 oldattrib = {};
 	BufferAttribute newattrib = {};
 	BufferAttribute newattrib = {};
 
 
@@ -231,6 +234,7 @@ void Mesh::attachAttribute(const std::string &name, Buffer *buffer, Mesh *mesh,
 	newattrib.mesh = mesh;
 	newattrib.mesh = mesh;
 	newattrib.enabled = oldattrib.buffer.get() ? oldattrib.enabled : true;
 	newattrib.enabled = oldattrib.buffer.get() ? oldattrib.enabled : true;
 	newattrib.indexInBuffer = buffer->getDataMemberIndex(attachname);
 	newattrib.indexInBuffer = buffer->getDataMemberIndex(attachname);
+	newattrib.startArrayIndex = startindex;
 	newattrib.step = step;
 	newattrib.step = step;
 
 
 	if (newattrib.indexInBuffer < 0)
 	if (newattrib.indexInBuffer < 0)
@@ -578,12 +582,13 @@ void Mesh::drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount)
 
 
 			uint16 offset = (uint16) member.offset;
 			uint16 offset = (uint16) member.offset;
 			uint16 stride = (uint16) buffer->getArrayStride();
 			uint16 stride = (uint16) buffer->getArrayStride();
+			size_t bufferoffset = (size_t) stride * attrib.startArrayIndex;
 
 
 			attributes.set(attributeindex, member.decl.format, offset, activebuffers);
 			attributes.set(attributeindex, member.decl.format, offset, activebuffers);
 			attributes.setBufferLayout(activebuffers, stride, attrib.step);
 			attributes.setBufferLayout(activebuffers, stride, attrib.step);
 
 
 			// TODO: Ideally we want to reuse buffers with the same stride+step.
 			// TODO: Ideally we want to reuse buffers with the same stride+step.
-			buffers.set(activebuffers, buffer, 0);
+			buffers.set(activebuffers, buffer, bufferoffset);
 			activebuffers++;
 			activebuffers++;
 		}
 		}
 	}
 	}

+ 2 - 1
src/modules/graphics/Mesh.h

@@ -57,6 +57,7 @@ public:
 		StrongRef<Buffer> buffer;
 		StrongRef<Buffer> buffer;
 		StrongRef<Mesh> mesh;
 		StrongRef<Mesh> mesh;
 		int indexInBuffer;
 		int indexInBuffer;
+		int startArrayIndex;
 		AttributeStep step;
 		AttributeStep step;
 		bool enabled;
 		bool enabled;
 	};
 	};
@@ -109,7 +110,7 @@ public:
 	 * to make sure this Mesh knows to flush the passed in Mesh's data to its
 	 * to make sure this Mesh knows to flush the passed in Mesh's data to its
 	 * buffer when drawing.
 	 * 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);
 	bool detachAttribute(const std::string &name);
 	const std::vector<BufferAttribute> &getAttachedAttributes() const;
 	const std::vector<BufferAttribute> &getAttachedAttributes() const;
 
 

+ 6 - 2
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);
 		return luax_enumerror(L, "vertex attribute step", getConstants(step), stepstr);
 
 
 	const char *attachname = luaL_optstring(L, 5, name);
 	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;
 	return 0;
 }
 }
 
 
@@ -340,7 +341,7 @@ int w_Mesh_getAttachedAttributes(lua_State *L)
 	{
 	{
 		const auto &attrib = attributes[i];
 		const auto &attrib = attributes[i];
 
 
-		lua_createtable(L, 4, 0);
+		lua_createtable(L, 5, 0);
 
 
 		luax_pushstring(L, attrib.name);
 		luax_pushstring(L, attrib.name);
 		lua_rawseti(L, -1, 1);
 		lua_rawseti(L, -1, 1);
@@ -358,6 +359,9 @@ int w_Mesh_getAttachedAttributes(lua_State *L)
 		luax_pushstring(L, member.decl.name);
 		luax_pushstring(L, member.decl.name);
 		lua_rawseti(L, -1, 4);
 		lua_rawseti(L, -1, 4);
 
 
+		lua_pushinteger(L, attrib.startArrayIndex + 1);
+		lua_rawseti(L, -1, 5);
+
 		lua_rawseti(L, -1, i + 1);
 		lua_rawseti(L, -1, i + 1);
 	}
 	}