Add love.graphics.newMesh variant to create a Mesh from existing Buffers.

This allows a Mesh to be created that doesn't have its own internal vertex buffer and purely references other vertex buffers instead.

The prototype looks like this:
mesh = love.graphics.newMesh(attributelist, drawmode)

where attributelist is an array of tables each with the following fields, similar to Mesh:attachAttribute:
{
    buffer = vertexbuffer,
    name = "VertexPosition", -- the name this vertex attribute will use in a shader
    nameinbuffer = nil, -- the name of the attribute in the vertex buffer. Defaults to the name field.
    step = nil, -- vertex attribute step ("pervertex" or "perinstance"), defaults to "pervertex".
    startindex = nil, -- 1-based array index within the given vertex buffer where the attribute data will start being pulled from during rendering. Defaults to 1.
}
This commit is contained in:
Sasha Szpakowski
2023-09-30 20:12:43 -03:00
parent 691d910c3e
commit dbc7d7f3ca
3 changed files with 110 additions and 17 deletions
+32 -16
View File
@@ -107,15 +107,18 @@ Mesh::Mesh(const std::vector<Mesh::BufferAttribute> &attributes, PrimitiveType d
throw love::Exception("At least one buffer attribute must be specified in this constructor.");
attachedAttributes = attributes;
vertexCount = attachedAttributes.size() > 0 ? LOVE_UINT32_MAX : 0;
for (const auto &attrib : attachedAttributes)
{
if ((attrib.buffer->getUsageFlags() & BUFFERUSAGEFLAG_VERTEX) == 0)
throw love::Exception("Buffer must be created with vertex buffer support to be used as a Mesh vertex attribute.");
auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
if (getAttachedAttributeIndex(attrib.name) != -1)
for (int i = 0; i < (int) attachedAttributes.size(); i++)
{
auto &attrib = attachedAttributes[i];
finalizeAttribute(gfx, attrib);
int attributeIndex = getAttachedAttributeIndex(attrib.name);
if (attributeIndex != i && attributeIndex != -1)
throw love::Exception("Duplicate vertex attribute name: %s", attrib.name.c_str());
vertexCount = std::min(vertexCount, attrib.buffer->getArrayLength());
@@ -140,7 +143,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, 0, STEP_PER_VERTEX, true});
attachedAttributes.push_back({name, vertexBuffer, nullptr, name, (int) i, 0, STEP_PER_VERTEX, true});
}
}
@@ -155,6 +158,24 @@ int Mesh::getAttachedAttributeIndex(const std::string &name) const
return -1;
}
void Mesh::finalizeAttribute(Graphics *gfx, BufferAttribute &attrib) const
{
if ((attrib.buffer->getUsageFlags() & BUFFERUSAGEFLAG_VERTEX) == 0)
throw love::Exception("Buffer must be created with vertex buffer support to be used as a Mesh vertex attribute.");
if (attrib.step == STEP_PER_INSTANCE && !gfx->getCapabilities().features[Graphics::FEATURE_INSTANCING])
throw love::Exception("Vertex attribute instancing is not supported on this system.");
if (attrib.startArrayIndex < 0 || attrib.startArrayIndex >= (int)attrib.buffer->getArrayLength())
throw love::Exception("Invalid start array index %d.", attrib.startArrayIndex + 1);
int indexInBuffer = attrib.buffer->getDataMemberIndex(attrib.nameInBuffer);
if (indexInBuffer < 0)
throw love::Exception("Buffer does not have a vertex attribute with name '%s'.", attrib.nameInBuffer.c_str());
attrib.indexInBuffer = indexInBuffer;
}
void *Mesh::checkVertexDataOffset(size_t vertindex, size_t *byteoffset)
{
if (vertindex >= vertexCount)
@@ -210,15 +231,7 @@ bool Mesh::isAttributeEnabled(const std::string &name) const
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.");
auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
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 = {};
@@ -233,10 +246,13 @@ void Mesh::attachAttribute(const std::string &name, Buffer *buffer, Mesh *mesh,
newattrib.buffer = buffer;
newattrib.mesh = mesh;
newattrib.enabled = oldattrib.buffer.get() ? oldattrib.enabled : true;
newattrib.indexInBuffer = buffer->getDataMemberIndex(attachname);
newattrib.nameInBuffer = attachname;
newattrib.indexInBuffer = -1;
newattrib.startArrayIndex = startindex;
newattrib.step = step;
finalizeAttribute(gfx, newattrib);
if (newattrib.indexInBuffer < 0)
throw love::Exception("The specified vertex buffer does not have a vertex attribute named '%s'", attachname.c_str());