Internal restructuring of some Mesh code

This commit is contained in:
Alex Szpakowski
2020-02-23 22:39:18 -04:00
parent 2c90ccabb3
commit 4197a364fd
7 changed files with 158 additions and 112 deletions
+7 -12
View File
@@ -268,26 +268,21 @@ Buffer *Graphics::newBuffer(const Buffer::Settings &settings, DataFormat format,
return newBuffer(settings, dataformat, data, size, arraylength);
}
Mesh *Graphics::newMesh(const std::vector<Vertex> &vertices, PrimitiveType drawmode, BufferUsage usage)
{
return newMesh(Mesh::getDefaultVertexFormat(), &vertices[0], vertices.size() * sizeof(Vertex), drawmode, usage);
}
Mesh *Graphics::newMesh(int vertexcount, PrimitiveType drawmode, BufferUsage usage)
{
return newMesh(Mesh::getDefaultVertexFormat(), vertexcount, drawmode, usage);
}
love::graphics::Mesh *Graphics::newMesh(const std::vector<Buffer::DataDeclaration> &vertexformat, int vertexcount, PrimitiveType drawmode, BufferUsage usage)
Mesh *Graphics::newMesh(const std::vector<Buffer::DataDeclaration> &vertexformat, int vertexcount, PrimitiveType drawmode, BufferUsage usage)
{
return new Mesh(this, vertexformat, vertexcount, drawmode, usage);
}
love::graphics::Mesh *Graphics::newMesh(const std::vector<Buffer::DataDeclaration> &vertexformat, const void *data, size_t datasize, PrimitiveType drawmode, BufferUsage usage)
Mesh *Graphics::newMesh(const std::vector<Buffer::DataDeclaration> &vertexformat, const void *data, size_t datasize, PrimitiveType drawmode, BufferUsage usage)
{
return new Mesh(this, vertexformat, data, datasize, drawmode, usage);
}
Mesh *Graphics::newMesh(const std::vector<Mesh::BufferAttribute> &attributes, PrimitiveType drawmode)
{
return new Mesh(attributes, drawmode);
}
love::graphics::Text *Graphics::newText(graphics::Font *font, const std::vector<Font::ColoredString> &text)
{
return new Text(font, text);
+1 -2
View File
@@ -442,10 +442,9 @@ public:
virtual Buffer *newBuffer(const Buffer::Settings &settings, const std::vector<Buffer::DataDeclaration> &format, const void *data, size_t size, size_t arraylength) = 0;
virtual Buffer *newBuffer(const Buffer::Settings &settings, DataFormat format, const void *data, size_t size, size_t arraylength);
Mesh *newMesh(const std::vector<Vertex> &vertices, PrimitiveType drawmode, BufferUsage usage);
Mesh *newMesh(int vertexcount, PrimitiveType drawmode, BufferUsage usage);
Mesh *newMesh(const std::vector<Buffer::DataDeclaration> &vertexformat, int vertexcount, PrimitiveType drawmode, BufferUsage usage);
Mesh *newMesh(const std::vector<Buffer::DataDeclaration> &vertexformat, const void *data, size_t datasize, PrimitiveType drawmode, BufferUsage usage);
Mesh *newMesh(const std::vector<Mesh::BufferAttribute> &attributes, PrimitiveType drawmode);
Text *newText(Font *font, const std::vector<Font::ColoredString> &text = {});
+100 -54
View File
@@ -34,27 +34,13 @@ namespace love
namespace graphics
{
static const char *getBuiltinAttribName(BuiltinVertexAttribute attribid)
{
const char *name = "";
getConstant(attribid, name);
return name;
}
static_assert(offsetof(Vertex, x) == sizeof(float) * 0, "Incorrect position offset in Vertex struct");
static_assert(offsetof(Vertex, s) == sizeof(float) * 2, "Incorrect texture coordinate offset in Vertex struct");
static_assert(offsetof(Vertex, color.r) == sizeof(float) * 4, "Incorrect color offset in Vertex struct");
std::vector<Buffer::DataDeclaration> Mesh::getDefaultVertexFormat()
{
// Corresponds to the love::Vertex struct.
std::vector<Buffer::DataDeclaration> vertexformat = {
{ getBuiltinAttribName(ATTRIB_POS), DATAFORMAT_FLOAT_VEC2, 0 },
{ getBuiltinAttribName(ATTRIB_TEXCOORD), DATAFORMAT_FLOAT_VEC2, 0 },
{ getBuiltinAttribName(ATTRIB_COLOR), DATAFORMAT_UNORM8_VEC4, 0 },
};
return vertexformat;
return Buffer::getCommonFormatDeclaration(CommonFormat::XYf_STf_RGBAub);
}
love::Type Mesh::type("Mesh", &Drawable::type);
@@ -63,6 +49,7 @@ Mesh::Mesh(graphics::Graphics *gfx, const std::vector<Buffer::DataDeclaration> &
: vertexBuffer(nullptr)
, vertexCount(0)
, vertexStride(0)
, vertexScratchBuffer(nullptr)
, indexBuffer(nullptr)
, useIndexBuffer(false)
, indexCount(0)
@@ -89,6 +76,7 @@ Mesh::Mesh(graphics::Graphics *gfx, const std::vector<Buffer::DataDeclaration> &
: vertexBuffer(nullptr)
, vertexCount((size_t) vertexcount)
, vertexStride(0)
, vertexScratchBuffer(nullptr)
, indexBuffer(nullptr)
, useIndexBuffer(false)
, indexCount(0)
@@ -115,6 +103,37 @@ Mesh::Mesh(graphics::Graphics *gfx, const std::vector<Buffer::DataDeclaration> &
vertexScratchBuffer = new char[vertexStride];
}
Mesh::Mesh(const std::vector<Mesh::BufferAttribute> &attributes, PrimitiveType drawmode)
: vertexBuffer(nullptr)
, vertexCount(0)
, vertexStride(0)
, vertexScratchBuffer(nullptr)
, indexBuffer(nullptr)
, useIndexBuffer(false)
, indexCount(0)
, indexDataType(INDEX_UINT16)
, primitiveType(drawmode)
, rangeStart(-1)
, rangeCount(-1)
{
if (attributes.size() == 0)
throw love::Exception("At least one buffer attribute must be specified in this constructor.");
attachedAttributes = attributes;
vertexCount = LOVE_UINT32_MAX;
for (const auto &attrib : attachedAttributes)
{
if (getAttachedAttributeIndex(attrib.name) != -1)
throw love::Exception("Duplicate vertex attribute name: %s", attrib.name.c_str());
vertexCount = std::min(vertexCount, attrib.buffer->getArrayLength());
}
indexDataType = getIndexDataTypeFromMax(vertexCount);
}
Mesh::~Mesh()
{
delete vertexScratchBuffer;
@@ -126,18 +145,32 @@ void Mesh::setupAttachedAttributes()
{
const std::string &name = vertexFormat[i].decl.name;
if (attachedAttributes.find(name) != attachedAttributes.end())
if (getAttachedAttributeIndex(name) != -1)
throw love::Exception("Duplicate vertex attribute name: %s", name.c_str());
attachedAttributes[name] = {vertexBuffer, (int) i, STEP_PER_VERTEX, true};
attachedAttributes.push_back({name, vertexBuffer, (int) i, STEP_PER_VERTEX, true});
}
}
int Mesh::getAttachedAttributeIndex(const std::string &name) const
{
for (int i = 0; i < (int) attachedAttributes.size(); i++)
{
if (attachedAttributes[i].name == name)
return i;
}
return -1;
}
void Mesh::setVertex(size_t vertindex, const void *data, size_t datasize)
{
if (vertindex >= vertexCount)
throw love::Exception("Invalid vertex index: %ld", vertindex + 1);
if (vertexBuffer.get() == nullptr)
throw love::Exception("setVertex can only be called on a Mesh which owns its own vertex buffer.");
size_t offset = vertindex * vertexStride;
size_t size = std::min(datasize, vertexStride);
@@ -152,6 +185,9 @@ size_t Mesh::getVertex(size_t vertindex, void *data, size_t datasize)
if (vertindex >= vertexCount)
throw love::Exception("Invalid vertex index: %ld", vertindex + 1);
if (vertexBuffer.get() == nullptr)
throw love::Exception("getVertex can only be called on a Mesh which owns its own vertex buffer.");
size_t offset = vertindex * vertexStride;
size_t size = std::min(datasize, vertexStride);
@@ -175,6 +211,9 @@ void Mesh::setVertexAttribute(size_t vertindex, int attribindex, const void *dat
if (attribindex >= (int) vertexFormat.size())
throw love::Exception("Invalid vertex attribute index: %d", attribindex + 1);
if (vertexBuffer.get() == nullptr)
throw love::Exception("setVertexAttribute can only be called on a Mesh which owns its own vertex buffer.");
const auto &member = vertexFormat[attribindex];
size_t offset = vertindex * vertexStride + member.offset;
@@ -194,6 +233,9 @@ size_t Mesh::getVertexAttribute(size_t vertindex, int attribindex, void *data, s
if (attribindex >= (int) vertexFormat.size())
throw love::Exception("Invalid vertex attribute index: %d", attribindex + 1);
if (vertexBuffer.get() == nullptr)
throw love::Exception("getVertexAttribute can only be called on a Mesh which owns its own vertex buffer.");
const auto &member = vertexFormat[attribindex];
size_t offset = vertindex * vertexStride + member.offset;
@@ -239,39 +281,37 @@ int Mesh::getAttributeIndex(const std::string &name) const
void Mesh::setAttributeEnabled(const std::string &name, bool enable)
{
auto it = attachedAttributes.find(name);
if (it == attachedAttributes.end())
int index = getAttachedAttributeIndex(name);
if (index == -1)
throw love::Exception("Mesh does not have an attached vertex attribute named '%s'", name.c_str());
it->second.enabled = enable;
attachedAttributes[index].enabled = enable;
}
bool Mesh::isAttributeEnabled(const std::string &name) const
{
const auto it = attachedAttributes.find(name);
if (it == attachedAttributes.end())
int index = getAttachedAttributeIndex(name);
if (index == -1)
throw love::Exception("Mesh does not have an attached vertex attribute named '%s'", name.c_str());
return it->second.enabled;
return attachedAttributes[index].enabled;
}
void Mesh::attachAttribute(const std::string &name, Buffer *buffer, const std::string &attachname, AttributeStep step)
{
if ((buffer->getTypeFlags() & Buffer::TYPEFLAG_VERTEX) == 0)
throw love::Exception("GraphicsBuffer 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.");
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.");
AttachedAttribute oldattrib = {};
AttachedAttribute newattrib = {};
BufferAttribute oldattrib = {};
BufferAttribute newattrib = {};
auto it = attachedAttributes.find(name);
if (it != attachedAttributes.end())
oldattrib = it->second;
int oldindex = getAttachedAttributeIndex(name);
if (oldindex != -1)
oldattrib = attachedAttributes[oldindex];
else if (attachedAttributes.size() + 1 > VertexAttributes::MAX)
throw love::Exception("A maximum of %d attributes can be attached at once.", VertexAttributes::MAX);
@@ -283,42 +323,46 @@ void Mesh::attachAttribute(const std::string &name, Buffer *buffer, const std::s
if (newattrib.index < 0)
throw love::Exception("The specified vertex buffer does not have a vertex attribute named '%s'", attachname.c_str());
attachedAttributes[name] = newattrib;
if (oldindex != -1)
attachedAttributes[oldindex] = newattrib;
else
attachedAttributes.push_back(newattrib);
}
bool Mesh::detachAttribute(const std::string &name)
{
auto it = attachedAttributes.find(name);
int index = getAttachedAttributeIndex(name);
if (index == -1)
return false;
if (it != attachedAttributes.end())
{
attachedAttributes.erase(it);
attachedAttributes.erase(attachedAttributes.begin() + index);
if (getAttributeIndex(name) != -1)
attachAttribute(name, vertexBuffer, name);
if (getAttributeIndex(name) != -1)
attachAttribute(name, vertexBuffer, name);
return true;
}
return false;
return true;
}
void *Mesh::mapVertexData()
{
return vertexBuffer->map();
return vertexBuffer.get() != nullptr ? vertexBuffer->map() : nullptr;
}
void Mesh::unmapVertexData(size_t modifiedoffset, size_t modifiedsize)
{
if (!vertexBuffer.get())
return;
vertexBuffer->setMappedRangeModified(modifiedoffset, modifiedsize);
vertexBuffer->unmap();
}
void Mesh::flush()
{
vertexBuffer->unmap();
if (vertexBuffer.get())
vertexBuffer->unmap();
if (indexBuffer != nullptr)
if (indexBuffer.get())
indexBuffer->unmap();
}
@@ -352,7 +396,8 @@ void Mesh::setVertexMap(const std::vector<uint32> &map)
if (indexBuffer.get() == nullptr || size > indexBuffer->getSize() || indexBuffer->getDataMember(0).decl.format != dataformat)
{
auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
Buffer::Settings settings(Buffer::TYPEFLAG_INDEX, Buffer::MAP_READ, vertexBuffer->getUsage());
auto usage = vertexBuffer.get() ? vertexBuffer->getUsage() : BUFFERUSAGE_DYNAMIC;
Buffer::Settings settings(Buffer::TYPEFLAG_INDEX, Buffer::MAP_READ, usage);
indexBuffer.set(gfx->newBuffer(settings, dataformat, nullptr, size, 0), Acquire::NORETAIN);
}
@@ -386,7 +431,8 @@ void Mesh::setVertexMap(IndexDataType datatype, const void *data, size_t datasiz
if (indexBuffer.get() == nullptr || datasize > indexBuffer->getSize() || indexBuffer->getDataMember(0).decl.format != dataformat)
{
auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
Buffer::Settings settings(Buffer::TYPEFLAG_INDEX, Buffer::MAP_READ, vertexBuffer->getUsage());
auto usage = vertexBuffer.get() ? vertexBuffer->getUsage() : BUFFERUSAGE_DYNAMIC;
Buffer::Settings settings(Buffer::TYPEFLAG_INDEX, Buffer::MAP_READ, usage);
indexBuffer.set(gfx->newBuffer(settings, dataformat, nullptr, datasize, 0), Acquire::NORETAIN);
}
@@ -529,32 +575,32 @@ void Mesh::drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount)
for (const auto &attrib : attachedAttributes)
{
if (!attrib.second.enabled)
if (!attrib.enabled)
continue;
Buffer *buffer = attrib.second.buffer.get();
Buffer *buffer = attrib.buffer.get();
int attributeindex = -1;
// If the attribute is one of the LOVE-defined ones, use the constant
// attribute index for it, otherwise query the index from the shader.
BuiltinVertexAttribute builtinattrib;
if (getConstant(attrib.first.c_str(), builtinattrib))
if (getConstant(attrib.name.c_str(), builtinattrib))
attributeindex = (int) builtinattrib;
else if (Shader::current)
attributeindex = Shader::current->getVertexAttributeIndex(attrib.first);
attributeindex = Shader::current->getVertexAttributeIndex(attrib.name);
if (attributeindex >= 0)
{
// Make sure the buffer isn't mapped (sends data to GPU if needed.)
buffer->unmap();
const auto &member = buffer->getDataMember(attrib.second.index);
const auto &member = buffer->getDataMember(attrib.index);
uint16 offset = (uint16) buffer->getMemberOffset(attrib.second.index);
uint16 offset = (uint16) buffer->getMemberOffset(attrib.index);
uint16 stride = (uint16) buffer->getArrayStride();
attributes.set(attributeindex, member.decl.format, offset, activebuffers);
attributes.setBufferLayout(activebuffers, stride, attrib.second.step);
attributes.setBufferLayout(activebuffers, stride, attrib.step);
// TODO: Ideally we want to reuse buffers with the same stride+step.
buffers.set(activebuffers, buffer, 0);
+13 -9
View File
@@ -50,10 +50,20 @@ class Mesh : public Drawable
{
public:
struct BufferAttribute
{
std::string name;
StrongRef<Buffer> buffer;
int index;
AttributeStep step;
bool enabled;
};
static love::Type type;
Mesh(Graphics *gfx, const std::vector<Buffer::DataDeclaration> &vertexformat, const void *data, size_t datasize, PrimitiveType drawmode, BufferUsage usage);
Mesh(Graphics *gfx, const std::vector<Buffer::DataDeclaration> &vertexformat, int vertexcount, PrimitiveType drawmode, BufferUsage usage);
Mesh(const std::vector<BufferAttribute> &attributes, PrimitiveType drawmode);
virtual ~Mesh();
@@ -105,6 +115,7 @@ public:
**/
void attachAttribute(const std::string &name, Buffer *buffer, const std::string &attachname, AttributeStep step = STEP_PER_VERTEX);
bool detachAttribute(const std::string &name);
const std::vector<BufferAttribute> &getAttachedAttributes();
void *mapVertexData();
void unmapVertexData(size_t modifiedoffset = 0, size_t modifiedsize = -1);
@@ -172,19 +183,12 @@ private:
friend class SpriteBatch;
struct AttachedAttribute
{
StrongRef<Buffer> buffer;
int index;
AttributeStep step;
bool enabled;
};
void setupAttachedAttributes();
int getAttachedAttributeIndex(const std::string &name) const;
std::vector<Buffer::DataMember> vertexFormat;
std::unordered_map<std::string, AttachedAttribute> attachedAttributes;
std::vector<BufferAttribute> attachedAttributes;
// Vertex buffer, for the vertex data.
StrongRef<Buffer> vertexBuffer;
-8
View File
@@ -358,14 +358,6 @@ DEFINE_STRINGMAP_BEGIN(AttributeStep, STEP_MAX_ENUM, attributeStep)
}
DEFINE_STRINGMAP_END(AttributeStep, STEP_MAX_ENUM, attributeStep)
DEFINE_STRINGMAP_BEGIN(DataTypeDeprecated, DATADEPRECATED_MAX_ENUM, dataType)
{
{ "unorm8", DATADEPRECATED_UNORM8 },
{ "unorm16", DATADEPRECATED_UNORM16 },
{ "float", DATADEPRECATED_FLOAT },
}
DEFINE_STRINGMAP_END(DataTypeDeprecated, DATADEPRECATED_MAX_ENUM, dataType)
DEFINE_STRINGMAP_BEGIN(DataFormat, DATAFORMAT_MAX_ENUM, dataFormat)
{
{ "float", DATAFORMAT_FLOAT },
-9
View File
@@ -102,14 +102,6 @@ enum BufferUsage
BUFFERUSAGE_MAX_ENUM
};
enum DataTypeDeprecated
{
DATADEPRECATED_UNORM8,
DATADEPRECATED_UNORM16,
DATADEPRECATED_FLOAT,
DATADEPRECATED_MAX_ENUM
};
// Value types used when interfacing with the GPU (vertex and shader data).
// The order of this enum affects the dataFormatInfo array.
enum DataFormat
@@ -387,7 +379,6 @@ DECLARE_STRINGMAP(IndexDataType);
DECLARE_STRINGMAP(BufferUsage);
DECLARE_STRINGMAP(PrimitiveType);
DECLARE_STRINGMAP(AttributeStep);
DECLARE_STRINGMAP(DataTypeDeprecated);
DECLARE_STRINGMAP(DataFormat);
DECLARE_STRINGMAP(DataBaseType);
DECLARE_STRINGMAP(CullMode);
+37 -18
View File
@@ -1557,6 +1557,8 @@ 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();
// First argument is a table of standard vertices, or the number of
// standard vertices.
if (lua_istable(L, 1))
@@ -1595,12 +1597,12 @@ static Mesh *newStandardMesh(lua_State *L)
vertices.push_back(v);
}
luax_catchexcept(L, [&](){ t = instance()->newMesh(vertices, drawmode, usage); });
luax_catchexcept(L, [&](){ t = instance()->newMesh(format, vertices.data(), vertices.size() * sizeof(Vertex), drawmode, usage); });
}
else
{
int count = (int) luaL_checkinteger(L, 1);
luax_catchexcept(L, [&](){ t = instance()->newMesh(count, drawmode, usage); });
luax_catchexcept(L, [&](){ t = instance()->newMesh(format, count, drawmode, usage); });
}
return t;
@@ -1641,24 +1643,41 @@ static Mesh *newCustomMesh(lua_State *L)
if (!getConstant(tname, format))
{
DataTypeDeprecated legacyType = DATADEPRECATED_FLOAT;
if (strcmp(tname, "byte") == 0) // Legacy name.
legacyType = DATADEPRECATED_UNORM8;
else if (!getConstant(tname, legacyType))
{
luax_enumerror(L, "Mesh vertex data format name", getConstants(format), tname);
return nullptr;
}
int components = (int) luaL_checkinteger(L, -1);
if (components <= 0 || components > 4)
{
luaL_error(L, "Number of vertex attribute components must be between 1 and 4 (got %d)", components);
return nullptr;
}
// TODO: convert legacy type+components to new format enum.
// Check deprecated format names.
if (strcmp(tname, "byte") == 0 || strcmp(tname, "unorm8") == 0)
{
if (components == 4)
format = DATAFORMAT_UNORM8_VEC4;
else
luaL_error(L, "Invalid component count (%d) for vertex data type %s", components, tname);
}
else if (strcmp(tname, "unorm16") == 0)
{
if (components == 2)
format = DATAFORMAT_UNORM16_VEC2;
else if (components == 4)
format = DATAFORMAT_UNORM16_VEC4;
else
luaL_error(L, "Invalid component count (%d) for vertex data type %s", components, tname);
}
else if (strcmp(tname, "float") == 0)
{
if (components == 1)
format = DATAFORMAT_FLOAT;
else if (components == 2)
format = DATAFORMAT_FLOAT_VEC2;
else if (components == 3)
format = DATAFORMAT_FLOAT_VEC3;
else if (components == 4)
format = DATAFORMAT_FLOAT_VEC4;
else
luaL_error(L, "Invalid component count (%d) for vertex data type %s", components, tname);
}
else
luax_enumerror(L, "vertex data format", getConstants(format), tname);
}
lua_pop(L, 4);