Mesh uses Buffer;

This commit is contained in:
bjorn 2018-12-07 15:57:45 -08:00
parent 9a0f7c919a
commit e2886d3bb5
8 changed files with 197 additions and 236 deletions

View File

@ -203,24 +203,24 @@ static uint32_t luax_readvertices(lua_State* L, int index) {
if (lua_type(L, -1) == LUA_TNUMBER) {
lua_pop(L, 1);
VertexPointer vertices = lovrGraphicsGetVertexPointer(count / 3);
float* vertices = lovrGraphicsGetVertexPointer(count / 3);
for (size_t i = 1; i <= count; i += 3) {
for (int j = 0; j < 3; j++) {
lua_rawgeti(L, index, i + j);
vertices.floats[j] = lua_tonumber(L, -1);
vertices[j] = lua_tonumber(L, -1);
lua_pop(L, 1);
}
vertices.floats += 8;
vertices += 8;
}
return count / 3;
} else {
lua_pop(L, 1);
VertexPointer vertices = lovrGraphicsGetVertexPointer(count);
float* vertices = lovrGraphicsGetVertexPointer(count);
for (size_t i = 1; i <= count; i++) {
lua_rawgeti(L, index, i);
vec3_init(vertices.floats, luax_checkmathtype(L, -1, MATH_VEC3, NULL));
vec3_init(vertices, luax_checkmathtype(L, -1, MATH_VEC3, NULL));
lua_pop(L, 1);
vertices.floats += 8;
vertices += 8;
}
return count;
}
@ -229,12 +229,12 @@ static uint32_t luax_readvertices(lua_State* L, int index) {
case LUA_TNUMBER: {
int top = lua_gettop(L);
uint32_t count = (top - index + 1) / 3;
VertexPointer vertices = lovrGraphicsGetVertexPointer(count);
float* vertices = lovrGraphicsGetVertexPointer(count);
for (int i = index; i <= top; i += 3) {
for (int j = 0; j < 3; j++) {
vertices.floats[j] = lua_tonumber(L, i + j);
vertices[j] = lua_tonumber(L, i + j);
}
vertices.floats += 8;
vertices += 8;
}
return count;
}
@ -242,10 +242,10 @@ static uint32_t luax_readvertices(lua_State* L, int index) {
default: {
int top = lua_gettop(L);
uint32_t count = top - index + 1;
VertexPointer vertices = lovrGraphicsGetVertexPointer(count);
float* vertices = lovrGraphicsGetVertexPointer(count);
for (int i = index; i <= top; i++) {
vec3_init(vertices.floats, luax_checkmathtype(L, i, MATH_VEC3, NULL));
vertices.floats += 8;
vec3_init(vertices, luax_checkmathtype(L, i, MATH_VEC3, NULL));
vertices += 8;
}
return count;
}
@ -1137,14 +1137,17 @@ static int l_lovrGraphicsNewMesh(lua_State* L) {
MeshDrawMode drawMode = luaL_checkoption(L, drawModeIndex, "fan", MeshDrawModes);
BufferUsage usage = luaL_checkoption(L, drawModeIndex + 1, "dynamic", BufferUsages);
Mesh* mesh = lovrMeshCreate(count, format, drawMode, usage);
bool readable = lua_toboolean(L, drawModeIndex + 2);
Mesh* mesh = lovrMeshCreate(count, format, drawMode, usage, readable);
if (dataIndex) {
VertexPointer vertices = lovrMeshMapVertices(mesh, 0, lua_objlen(L, dataIndex), false, true);
VertexPointer vertices = { .raw = lovrMeshMapVertices(mesh, 0) };
luax_loadvertices(L, dataIndex, lovrMeshGetVertexFormat(mesh), vertices);
lovrMeshFlushVertices(mesh, 0, count * format.stride);
} else if (vertexData) {
VertexPointer vertices = lovrMeshMapVertices(mesh, 0, count, false, true);
memcpy(vertices.raw, vertexData->blob.data, vertexData->count * vertexData->format.stride);
void* vertices = lovrMeshMapVertices(mesh, 0);
memcpy(vertices, vertexData->blob.data, vertexData->count * vertexData->format.stride);
lovrMeshFlushVertices(mesh, 0, count * format.stride);
}
luax_pushobject(L, mesh);

View File

@ -102,8 +102,9 @@ int l_lovrMeshGetVertexCount(lua_State* L) {
int l_lovrMeshGetVertex(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
int index = luaL_checkint(L, 2) - 1;
VertexPointer vertex = lovrMeshMapVertices(mesh, index, 1, true, false);
lovrAssert(lovrMeshIsReadable(mesh), "Mesh:getVertex can only be used if the Mesh was created with the readable flag");
VertexFormat* format = lovrMeshGetVertexFormat(mesh);
VertexPointer vertex = { .raw = lovrMeshMapVertices(mesh, index * format->stride) };
return luax_pushvertex(L, &vertex, format);
}
@ -112,8 +113,9 @@ int l_lovrMeshSetVertex(lua_State* L) {
int index = luaL_checkint(L, 2) - 1;
lovrAssert(index >= 0 && index < lovrMeshGetVertexCount(mesh), "Invalid mesh vertex index: %d", index + 1);
VertexFormat* format = lovrMeshGetVertexFormat(mesh);
VertexPointer vertex = lovrMeshMapVertices(mesh, index, 1, false, true);
VertexPointer vertex = { .raw = lovrMeshMapVertices(mesh, index * format->stride) };
luax_setvertex(L, 3, &vertex, format);
lovrMeshFlushVertices(mesh, index * format->stride, format->stride);
return 0;
}
@ -122,11 +124,11 @@ int l_lovrMeshGetVertexAttribute(lua_State* L) {
int vertexIndex = luaL_checkint(L, 2) - 1;
int attributeIndex = luaL_checkint(L, 3) - 1;
VertexFormat* format = lovrMeshGetVertexFormat(mesh);
lovrAssert(lovrMeshIsReadable(mesh), "Mesh:getVertex can only be used if the Mesh was created with the readable flag");
lovrAssert(vertexIndex >= 0 && vertexIndex < lovrMeshGetVertexCount(mesh), "Invalid mesh vertex: %d", vertexIndex + 1);
lovrAssert(attributeIndex >= 0 && attributeIndex < format->count, "Invalid mesh attribute: %d", attributeIndex + 1);
Attribute attribute = format->attributes[attributeIndex];
VertexPointer vertex = lovrMeshMapVertices(mesh, vertexIndex, 1, true, false);
vertex.bytes += attribute.offset;
VertexPointer vertex = { .raw = lovrMeshMapVertices(mesh, vertexIndex * format->stride + attribute.offset) };
return luax_pushvertexattribute(L, &vertex, attribute);
}
@ -138,9 +140,9 @@ int l_lovrMeshSetVertexAttribute(lua_State* L) {
lovrAssert(vertexIndex >= 0 && vertexIndex < lovrMeshGetVertexCount(mesh), "Invalid mesh vertex: %d", vertexIndex + 1);
lovrAssert(attributeIndex >= 0 && attributeIndex < format->count, "Invalid mesh attribute: %d", attributeIndex + 1);
Attribute attribute = format->attributes[attributeIndex];
VertexPointer vertex = lovrMeshMapVertices(mesh, vertexIndex, 1, false, true);
vertex.bytes += attribute.offset;
VertexPointer vertex = { .raw = lovrMeshMapVertices(mesh, vertexIndex * format->stride + attribute.offset) };
luax_setvertexattribute(L, 4, &vertex, attribute);
lovrMeshFlushVertices(mesh, vertexIndex * format->stride + attribute.offset, attribute.size);
return 0;
}
@ -165,7 +167,7 @@ int l_lovrMeshSetVertices(lua_State* L) {
lovrAssert(start + count <= capacity, "Overflow in Mesh:setVertices: Mesh can only hold %d vertices", capacity);
lovrAssert(count <= sourceSize, "Cannot set %d vertices on Mesh: source only has %d vertices", count, sourceSize);
VertexPointer vertices = lovrMeshMapVertices(mesh, start, count, false, true);
VertexPointer vertices = { .raw = lovrMeshMapVertices(mesh, start * format->stride) };
if (vertexData) {
memcpy(vertices.raw, vertexData->blob.data, count * format->stride);
@ -178,6 +180,8 @@ int l_lovrMeshSetVertices(lua_State* L) {
}
}
lovrMeshFlushVertices(mesh, start * format->stride, count * format->stride);
return 0;
}
@ -185,7 +189,7 @@ int l_lovrMeshGetVertexMap(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
uint32_t count;
size_t size;
IndexPointer indices = lovrMeshReadIndices(mesh, &count, &size);
IndexPointer indices = { .raw = lovrMeshReadIndices(mesh, &count, &size) };
if (count == 0 || !indices.raw) {
lua_pushnil(L);
@ -217,7 +221,7 @@ int l_lovrMeshSetVertexMap(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
if (lua_isnoneornil(L, 2)) {
lovrMeshWriteIndices(mesh, 0, 0);
lovrMeshMapIndices(mesh, 0, 0);
return 0;
}
@ -226,14 +230,14 @@ int l_lovrMeshSetVertexMap(lua_State* L) {
size_t size = luaL_optinteger(L, 3, 4);
lovrAssert(size == 2 || size == 4, "Size of Mesh indices should be 2 bytes or 4 bytes");
uint32_t count = blob->size / size;
IndexPointer indices = lovrMeshWriteIndices(mesh, count, size);
memcpy(indices.raw, blob->data, blob->size);
void* indices = lovrMeshMapIndices(mesh, count, size);
memcpy(indices, blob->data, blob->size);
} else {
luaL_checktype(L, 2, LUA_TTABLE);
uint32_t count = lua_objlen(L, 2);
uint32_t vertexCount = lovrMeshGetVertexCount(mesh);
size_t size = vertexCount > USHRT_MAX ? sizeof(uint32_t) : sizeof(uint16_t);
IndexPointer indices = lovrMeshWriteIndices(mesh, count, size);
IndexPointer indices = { .raw = lovrMeshMapIndices(mesh, count, size) };
for (uint32_t i = 0; i < count; i++) {
lua_rawgeti(L, 2, i + 1);
@ -256,6 +260,8 @@ int l_lovrMeshSetVertexMap(lua_State* L) {
}
}
lovrMeshFlushIndices(mesh);
return 0;
}

View File

@ -10,7 +10,7 @@ typedef enum {
typedef struct Buffer Buffer;
Buffer* lovrBufferCreate(size_t size, void* data, BufferUsage usage);
Buffer* lovrBufferCreate(size_t size, void* data, BufferUsage usage, bool readable);
void lovrBufferDestroy(void* ref);
size_t lovrBufferGetSize(Buffer* buffer);
BufferUsage lovrBufferGetUsage(Buffer* buffer);

View File

@ -75,7 +75,7 @@ void lovrGraphicsSetWindow(WindowFlags* flags) {
vertexFormatAppend(&format, "lovrPosition", ATTR_FLOAT, 3);
vertexFormatAppend(&format, "lovrNormal", ATTR_FLOAT, 3);
vertexFormatAppend(&format, "lovrTexCoord", ATTR_FLOAT, 2);
state.defaultMesh = lovrMeshCreate(64, format, MESH_TRIANGLES, USAGE_STREAM);
state.defaultMesh = lovrMeshCreate(65536, format, MESH_TRIANGLES, USAGE_STREAM, false);
lovrGraphicsReset();
state.initialized = true;
}
@ -331,9 +331,9 @@ void lovrGraphicsSetProjection(mat4 projection) {
// Rendering
VertexPointer lovrGraphicsGetVertexPointer(uint32_t count) {
lovrMeshResize(state.defaultMesh, count);
return lovrMeshMapVertices(state.defaultMesh, 0, count, false, true);
float* lovrGraphicsGetVertexPointer(uint32_t count) {
lovrAssert(count <= 65536, "Hey now! Up to 65536 vertices are allowed per-primitive...");
return lovrMeshMapVertices(state.defaultMesh, 0);
}
void lovrGraphicsClear(Color* color, float* depth, int* stencil) {
@ -351,19 +351,29 @@ void lovrGraphicsDiscard(bool color, bool depth, bool stencil) {
void lovrGraphicsDraw(DrawCommand* draw) {
Mesh* mesh = draw->mesh;
if (!mesh) {
int drawCount = draw->range.count ? draw->range.count : (draw->index.count ? draw->index.count : draw->vertex.count);
mesh = state.defaultMesh;
lovrMeshSetDrawMode(mesh, draw->mode);
lovrMeshSetDrawRange(mesh, draw->range.start, drawCount);
if (draw->vertex.count) {
VertexPointer vertexPointer = lovrGraphicsGetVertexPointer(draw->vertex.count);
memcpy(vertexPointer.raw, draw->vertex.data, draw->vertex.count * 8 * sizeof(float));
if (draw->index.count) {
IndexPointer indexPointer = lovrMeshWriteIndices(mesh, draw->index.count, sizeof(uint16_t));
memcpy(indexPointer.shorts, draw->index.data, draw->index.count * sizeof(uint16_t));
} else {
lovrMeshWriteIndices(mesh, 0, 0);
if (draw->index.count) {
if (draw->index.data) {
void* indices = lovrMeshMapIndices(mesh, draw->index.count, sizeof(uint16_t));
memcpy(indices, draw->index.data, draw->index.count * sizeof(uint16_t));
}
lovrMeshSetDrawRange(mesh, 0, draw->index.count);
lovrMeshFlushIndices(mesh);
} else {
lovrMeshSetDrawRange(mesh, 0, draw->vertex.count);
lovrMeshMapIndices(mesh, 0, 0);
}
if (draw->vertex.count) {
if (draw->vertex.data) {
void* vertices = lovrGraphicsGetVertexPointer(draw->vertex.count);
memcpy(vertices, draw->vertex.data, draw->vertex.count * 8 * sizeof(float));
}
lovrMeshFlushVertices(state.defaultMesh, 0, draw->vertex.count * 8 * sizeof(float));
} else {
return;
}
}
@ -478,14 +488,14 @@ void lovrGraphicsDraw(DrawCommand* draw) {
void lovrGraphicsPoints(uint32_t count) {
lovrGraphicsDraw(&(DrawCommand) {
.mode = MESH_POINTS,
.range = { 0, count }
.vertex.count = count
});
}
void lovrGraphicsLine(uint32_t count) {
lovrGraphicsDraw(&(DrawCommand) {
.mode = MESH_LINE_STRIP,
.range = { 0, count }
.vertex.count = count
});
}
@ -633,12 +643,12 @@ void lovrGraphicsArc(DrawMode mode, ArcMode arcMode, Material* material, mat4 tr
bool hasCenterPoint = arcMode == ARC_MODE_PIE && fabsf(theta1 - theta2) < 2 * M_PI;
uint32_t count = segments + 1 + hasCenterPoint;
VertexPointer vertices = lovrGraphicsGetVertexPointer(count);
lovrMeshWriteIndices(state.defaultMesh, 0, 0);
float* vertices = lovrGraphicsGetVertexPointer(count);
lovrMeshMapIndices(state.defaultMesh, 0, 0);
if (hasCenterPoint) {
memcpy(vertices.floats, ((float[]) { 0, 0, 0, 0, 0, 1, .5, .5 }), 8 * sizeof(float));
vertices.floats += 8;
memcpy(vertices, ((float[]) { 0, 0, 0, 0, 0, 1, .5, .5 }), 8 * sizeof(float));
vertices += 8;
}
float theta = theta1;
@ -647,8 +657,8 @@ void lovrGraphicsArc(DrawMode mode, ArcMode arcMode, Material* material, mat4 tr
for (int i = 0; i <= segments; i++) {
float x = cos(theta) * .5;
float y = sin(theta) * .5;
memcpy(vertices.floats, ((float[]) { x, y, 0, 0, 0, 1, x + .5, 1 - (y + .5) }), 8 * sizeof(float));
vertices.floats += 8;
memcpy(vertices, ((float[]) { x, y, 0, 0, 0, 1, x + .5, 1 - (y + .5) }), 8 * sizeof(float));
vertices += 8;
theta += angleShift;
}
@ -656,7 +666,7 @@ void lovrGraphicsArc(DrawMode mode, ArcMode arcMode, Material* material, mat4 tr
.transform = transform,
.material = material,
.mode = mode == DRAW_MODE_LINE ? (arcMode == ARC_MODE_OPEN ? MESH_LINE_STRIP : MESH_LINE_LOOP) : MESH_TRIANGLE_FAN,
.range = { 0, count }
.vertex.count = count
});
}
@ -673,9 +683,9 @@ void lovrGraphicsCylinder(Material* material, float x1, float y1, float z1, floa
uint32_t vertexCount = ((capped && r1) * (segments + 2) + (capped && r2) * (segments + 2) + 2 * (segments + 1));
uint32_t indexCount = 3 * segments * ((capped && r1) + (capped && r2) + 2);
VertexPointer vertices = lovrGraphicsGetVertexPointer(vertexCount);
IndexPointer indices = lovrMeshWriteIndices(state.defaultMesh, indexCount, sizeof(uint32_t));
float* baseVertex = vertices.floats;
float* vertices = lovrGraphicsGetVertexPointer(vertexCount);
uint16_t* indices = lovrMeshMapIndices(state.defaultMesh, indexCount, sizeof(uint32_t));
float* baseVertex = vertices;
vec3_init(p, n);
@ -694,18 +704,18 @@ void lovrGraphicsCylinder(Material* material, float x1, float y1, float z1, floa
vec3_normalize(axis);
#define PUSH_CYLINDER_VERTEX(x, y, z, nx, ny, nz) \
*vertices.floats++ = x; \
*vertices.floats++ = y; \
*vertices.floats++ = z; \
*vertices.floats++ = nx; \
*vertices.floats++ = ny; \
*vertices.floats++ = nz; \
*vertices.floats++ = 0; \
*vertices.floats++ = 0;
*vertices++ = x; \
*vertices++ = y; \
*vertices++ = z; \
*vertices++ = nx; \
*vertices++ = ny; \
*vertices++ = nz; \
*vertices++ = 0; \
*vertices++ = 0;
#define PUSH_CYLINDER_TRIANGLE(i1, i2, i3) \
*indices.ints++ = i1; \
*indices.ints++ = i2; \
*indices.ints++ = i3; \
*indices++ = i1; \
*indices++ = i2; \
*indices++ = i3; \
// Ring
for (int i = 0; i <= segments; i++) {
@ -757,13 +767,16 @@ void lovrGraphicsCylinder(Material* material, float x1, float y1, float z1, floa
lovrGraphicsDraw(&(DrawCommand) {
.material = material,
.mode = MESH_TRIANGLES,
.range = { 0, indexCount }
.vertex.count = vertexCount,
.index.count = indexCount
});
}
void lovrGraphicsSphere(Material* material, mat4 transform, int segments) {
VertexPointer vertices = lovrGraphicsGetVertexPointer((segments + 1) * (segments + 1));
IndexPointer indices = lovrMeshWriteIndices(state.defaultMesh, segments * segments * 6, sizeof(uint32_t));
uint32_t vertexCount = (segments + 1) * (segments + 1);
uint32_t indexCount = segments * segments * 6;
float* vertices = lovrGraphicsGetVertexPointer(vertexCount);
uint16_t* indices = lovrMeshMapIndices(state.defaultMesh, indexCount, sizeof(uint16_t));
for (int i = 0; i <= segments; i++) {
float v = i / (float) segments;
@ -773,19 +786,19 @@ void lovrGraphicsSphere(Material* material, mat4 transform, int segments) {
float x = sin(u * 2 * M_PI) * sin(v * M_PI);
float y = cos(v * M_PI);
float z = -cos(u * 2 * M_PI) * sin(v * M_PI);
memcpy(vertices.floats, ((float[]) { x, y, z, x, y, z, u, 1 - v }), 8 * sizeof(float));
vertices.floats += 8;
memcpy(vertices, ((float[]) { x, y, z, x, y, z, u, 1 - v }), 8 * sizeof(float));
vertices += 8;
}
}
for (int i = 0; i < segments; i++) {
unsigned int offset0 = i * (segments + 1);
unsigned int offset1 = (i + 1) * (segments + 1);
uint16_t offset0 = i * (segments + 1);
uint16_t offset1 = (i + 1) * (segments + 1);
for (int j = 0; j < segments; j++) {
unsigned int i0 = offset0 + j;
unsigned int i1 = offset1 + j;
memcpy(indices.ints, ((uint32_t[]) { i0, i1, i0 + 1, i1, i1 + 1, i0 + 1 }), 6 * sizeof(uint32_t));
indices.ints += 6;
uint16_t i0 = offset0 + j;
uint16_t i1 = offset1 + j;
memcpy(indices, ((uint16_t[]) { i0, i1, i0 + 1, i1, i1 + 1, i0 + 1 }), 6 * sizeof(uint16_t));
indices += 6;
}
}
@ -793,7 +806,8 @@ void lovrGraphicsSphere(Material* material, mat4 transform, int segments) {
.transform = transform,
.material = material,
.mode = MESH_TRIANGLES,
.range = { 0, segments * segments * 6 }
.vertex.count = vertexCount,
.index.count = indexCount
});
}
@ -824,9 +838,9 @@ void lovrGraphicsPrint(const char* str, mat4 transform, float wrap, HorizontalAl
float offsety;
uint32_t vertexCount;
uint32_t maxVertices = strlen(str) * 6;
VertexPointer vertexPointer = lovrGraphicsGetVertexPointer(maxVertices);
lovrFontRender(font, str, wrap, halign, valign, vertexPointer.floats, &offsety, &vertexCount);
lovrMeshWriteIndices(state.defaultMesh, 0, 0);
float* vertices = lovrGraphicsGetVertexPointer(maxVertices);
lovrFontRender(font, str, wrap, halign, valign, vertices, &offsety, &vertexCount);
lovrMeshMapIndices(state.defaultMesh, 0, 0);
lovrGraphicsPush();
lovrGraphicsMatrixTransform(transform);
@ -837,7 +851,7 @@ void lovrGraphicsPrint(const char* str, mat4 transform, float wrap, HorizontalAl
.shader = SHADER_FONT,
.textures[TEXTURE_DIFFUSE] = font->texture,
.mode = MESH_TRIANGLES,
.range = { 0, vertexCount }
.vertex.count = vertexCount
});
state.pipelines[state.pipeline].alphaCoverage = false;
lovrGraphicsPop();

View File

@ -124,10 +124,6 @@ typedef struct {
uint32_t count;
uint16_t* data;
} index;
struct {
int start;
int count;
} range;
DefaultShader shader;
Material* material;
Texture* textures[MAX_MATERIAL_TEXTURES];
@ -211,7 +207,7 @@ void lovrGraphicsMatrixTransform(mat4 transform);
void lovrGraphicsSetProjection(mat4 projection);
// Rendering
VertexPointer lovrGraphicsGetVertexPointer(uint32_t capacity);
float* lovrGraphicsGetVertexPointer(uint32_t capacity);
void lovrGraphicsClear(Color* color, float* depth, int* stencil);
void lovrGraphicsDiscard(bool color, bool depth, bool stencil);
void lovrGraphicsDraw(DrawCommand* draw);

View File

@ -19,13 +19,14 @@ typedef enum {
typedef struct Mesh Mesh;
Mesh* lovrMeshCreate(uint32_t count, VertexFormat format, MeshDrawMode drawMode, BufferUsage usage);
Mesh* lovrMeshCreate(uint32_t count, VertexFormat format, MeshDrawMode drawMode, BufferUsage usage, bool readable);
void lovrMeshDestroy(void* ref);
void lovrMeshAttachAttribute(Mesh* mesh, Mesh* other, const char* name, int divisor);
void lovrMeshDetachAttribute(Mesh* mesh, const char* name);
void lovrMeshBind(Mesh* mesh, Shader* shader, int divisorMultiplier);
void lovrMeshDraw(Mesh* mesh, int instances);
VertexFormat* lovrMeshGetVertexFormat(Mesh* mesh);
bool lovrMeshIsReadable(Mesh* mesh);
MeshDrawMode lovrMeshGetDrawMode(Mesh* mesh);
void lovrMeshSetDrawMode(Mesh* mesh, MeshDrawMode drawMode);
int lovrMeshGetVertexCount(Mesh* mesh);
@ -35,9 +36,8 @@ void lovrMeshGetDrawRange(Mesh* mesh, uint32_t* start, uint32_t* count);
void lovrMeshSetDrawRange(Mesh* mesh, uint32_t start, uint32_t count);
Material* lovrMeshGetMaterial(Mesh* mesh);
void lovrMeshSetMaterial(Mesh* mesh, Material* material);
VertexPointer lovrMeshMapVertices(Mesh* mesh, uint32_t start, uint32_t count, bool read, bool write);
void lovrMeshUnmapVertices(Mesh* mesh);
IndexPointer lovrMeshReadIndices(Mesh* mesh, uint32_t* count, size_t* size);
IndexPointer lovrMeshWriteIndices(Mesh* mesh, uint32_t count, size_t size);
void lovrMeshUnmapIndices(Mesh* mesh);
void lovrMeshResize(Mesh* mesh, uint32_t count);
void* lovrMeshMapVertices(Mesh* mesh, size_t offset);
void lovrMeshFlushVertices(Mesh* mesh, size_t offset, size_t size);
void* lovrMeshMapIndices(Mesh* mesh, uint32_t count, size_t indexSize);
void lovrMeshFlushIndices(Mesh* mesh);
void* lovrMeshReadIndices(Mesh* mesh, uint32_t* count, size_t* indexSize);

View File

@ -62,12 +62,14 @@ Model* lovrModelCreate(ModelData* modelData) {
model->modelData = modelData;
model->aabbDirty = true;
model->mesh = lovrMeshCreate(modelData->vertexData->count, modelData->vertexData->format, MESH_TRIANGLES, USAGE_STATIC);
VertexPointer vertices = lovrMeshMapVertices(model->mesh, 0, modelData->vertexData->count, false, true);
memcpy(vertices.raw, modelData->vertexData->blob.data, modelData->vertexData->count * modelData->vertexData->format.stride);
model->mesh = lovrMeshCreate(modelData->vertexData->count, modelData->vertexData->format, MESH_TRIANGLES, USAGE_STATIC, false);
void* vertices = lovrMeshMapVertices(model->mesh, 0);
memcpy(vertices, modelData->vertexData->blob.data, modelData->vertexData->count * modelData->vertexData->format.stride);
lovrMeshFlushVertices(model->mesh, 0, modelData->vertexData->count * modelData->vertexData->format.stride);
IndexPointer indices = lovrMeshWriteIndices(model->mesh, modelData->indexCount, modelData->indexSize);
memcpy(indices.raw, modelData->indices.raw, modelData->indexCount * modelData->indexSize);
void* indices = lovrMeshMapIndices(model->mesh, modelData->indexCount, modelData->indexSize);
memcpy(indices, modelData->indices.raw, modelData->indexCount * modelData->indexSize);
lovrMeshFlushIndices(model->mesh);
if (modelData->textures.length > 0) {
model->textures = calloc(modelData->textures.length, sizeof(Texture*));

View File

@ -147,8 +147,11 @@ struct Canvas {
};
typedef struct {
Mesh* mesh;
int attributeIndex;
Buffer* buffer;
AttributeType type;
int components;
size_t offset;
int stride;
int divisor;
bool enabled;
} MeshAttachment;
@ -157,27 +160,22 @@ typedef map_t(MeshAttachment) map_attachment_t;
struct Mesh {
Ref ref;
uint32_t vao;
uint32_t count;
VertexFormat format;
MeshDrawMode drawMode;
VertexFormat format;
bool readable;
BufferUsage usage;
VertexPointer data;
IndexPointer indices;
Buffer* vbo;
Buffer* ibo;
uint32_t indexCount;
size_t indexSize;
size_t indexCapacity;
bool mappedIndices;
uint32_t dirtyStart;
uint32_t dirtyEnd;
uint32_t rangeStart;
uint32_t rangeCount;
GLuint vao;
GLuint vbo;
GLuint ibo;
Material* material;
map_attachment_t attachments;
MeshAttachment layout[MAX_ATTACHMENTS];
bool isAttachment;
};
// Helper functions
@ -1496,7 +1494,7 @@ TextureData* lovrCanvasNewTextureData(Canvas* canvas, int index) {
// Buffer
Buffer* lovrBufferCreate(size_t size, void* data, BufferUsage usage) {
Buffer* lovrBufferCreate(size_t size, void* data, BufferUsage usage, bool readable) {
Buffer* buffer = lovrAlloc(Buffer, lovrBufferDestroy);
if (!buffer) return NULL;
@ -1507,12 +1505,9 @@ Buffer* lovrBufferCreate(size_t size, void* data, BufferUsage usage) {
#ifndef EMSCRIPTEN
if (GLAD_GL_ARB_buffer_storage) {
GLbitfield flags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT;
GLbitfield flags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | (readable ? GL_MAP_READ_BIT : 0);
glBufferStorage(GL_COPY_WRITE_BUFFER, size, data, flags);
if (usage != USAGE_STATIC) {
buffer->data = glMapBufferRange(GL_COPY_WRITE_BUFFER, 0, size, flags | GL_MAP_FLUSH_EXPLICIT_BIT);
}
buffer->data = glMapBufferRange(GL_COPY_WRITE_BUFFER, 0, size, flags | GL_MAP_FLUSH_EXPLICIT_BIT);
} else {
#endif
buffer->data = calloc(1, size);
@ -1550,7 +1545,6 @@ void* lovrBufferMap(Buffer* buffer, size_t offset) {
}
void lovrBufferFlush(Buffer* buffer, size_t offset, size_t size) {
lovrAssert(buffer->usage != USAGE_STATIC, "Static buffers may not be updated");
lovrGpuBindGenericBuffer(buffer->id);
#ifndef EMSCRIPTEN
if (GLAD_GL_ARB_buffer_storage) {
@ -1565,7 +1559,7 @@ void lovrBufferFlush(Buffer* buffer, size_t offset, size_t size) {
void lovrBufferLock(Buffer* buffer) {
#ifndef EMSCRIPTEN
if (!GLAD_GL_ARB_buffer_storage || buffer->usage == USAGE_STATIC) {
if (!GLAD_GL_ARB_buffer_storage) {
return;
}
@ -1576,7 +1570,7 @@ void lovrBufferLock(Buffer* buffer) {
void lovrBufferUnlock(Buffer* buffer) {
#ifndef EMSCRIPTEN
if (!GLAD_GL_ARB_buffer_storage || buffer->usage == USAGE_STATIC || !buffer->lock) {
if (!GLAD_GL_ARB_buffer_storage || !buffer->lock) {
return;
}
@ -2206,7 +2200,7 @@ ShaderBlock* lovrShaderBlockCreate(vec_uniform_t* uniforms, BlockType type, Buff
block->target = block->type == BLOCK_UNIFORM ? GL_UNIFORM_BUFFER : GL_SHADER_STORAGE_BUFFER;
#endif
block->type = type;
block->buffer = lovrBufferCreate(size, NULL, usage);
block->buffer = lovrBufferCreate(size, NULL, usage, false);
return block;
}
@ -2278,69 +2272,68 @@ Buffer* lovrShaderBlockGetBuffer(ShaderBlock* block) {
// Mesh
Mesh* lovrMeshCreate(uint32_t count, VertexFormat format, MeshDrawMode drawMode, BufferUsage usage) {
Mesh* lovrMeshCreate(uint32_t count, VertexFormat format, MeshDrawMode drawMode, BufferUsage usage, bool readable) {
Mesh* mesh = lovrAlloc(Mesh, lovrMeshDestroy);
if (!mesh) return NULL;
mesh->count = count;
mesh->format = format;
mesh->readable = readable;
mesh->drawMode = drawMode;
mesh->usage = usage;
glGenBuffers(1, &mesh->vbo);
glGenBuffers(1, &mesh->ibo);
lovrGpuBindVertexBuffer(mesh->vbo);
glBufferData(GL_ARRAY_BUFFER, count * format.stride, NULL, convertBufferUsage(mesh->usage));
mesh->vbo = lovrBufferCreate(count * format.stride, NULL, usage, readable);
glGenVertexArrays(1, &mesh->vao);
map_init(&mesh->attachments);
for (int i = 0; i < format.count; i++) {
map_set(&mesh->attachments, format.attributes[i].name, ((MeshAttachment) { mesh, i, 0, true }));
lovrRetain(mesh->vbo);
map_set(&mesh->attachments, format.attributes[i].name, ((MeshAttachment) {
.buffer = mesh->vbo,
.type = format.attributes[i].type,
.components = format.attributes[i].count,
.offset = format.attributes[i].offset,
.stride = format.stride,
.enabled = true
}));
}
mesh->data.raw = calloc(count, format.stride);
return mesh;
}
void lovrMeshDestroy(void* ref) {
Mesh* mesh = ref;
lovrRelease(mesh->material);
free(mesh->data.raw);
free(mesh->indices.raw);
glDeleteBuffers(1, &mesh->vbo);
glDeleteBuffers(1, &mesh->ibo);
glDeleteVertexArrays(1, &mesh->vao);
const char* key;
map_iter_t iter = map_iter(&mesh->attachments);
while ((key = map_next(&mesh->attachments, &iter)) != NULL) {
MeshAttachment* attachment = map_get(&mesh->attachments, key);
if (attachment->mesh != mesh) {
lovrRelease(attachment->mesh);
}
lovrRelease(attachment->buffer);
}
lovrRelease(mesh->vbo);
lovrRelease(mesh->ibo);
map_deinit(&mesh->attachments);
free(mesh);
}
void lovrMeshAttachAttribute(Mesh* mesh, Mesh* other, const char* name, int divisor) {
MeshAttachment* otherAttachment = map_get(&other->attachments, name);
lovrAssert(!mesh->isAttachment, "Attempted to attach to a mesh which is an attachment itself");
lovrAssert(otherAttachment, "No attribute named '%s' exists", name);
lovrAssert(!map_get(&mesh->attachments, name), "Mesh already has an attribute named '%s'", name);
lovrAssert(divisor >= 0, "Divisor can't be negative");
MeshAttachment attachment = { other, otherAttachment->attributeIndex, divisor, true };
MeshAttachment attachment = *otherAttachment;
attachment.divisor = divisor;
attachment.enabled = true;
map_set(&mesh->attachments, name, attachment);
other->isAttachment = true;
lovrRetain(other);
lovrRetain(attachment.buffer);
}
void lovrMeshDetachAttribute(Mesh* mesh, const char* name) {
MeshAttachment* attachment = map_get(&mesh->attachments, name);
lovrAssert(attachment, "No attached attribute '%s' was found", name);
lovrAssert(attachment->mesh != mesh, "Attribute '%s' was not attached from another Mesh", name);
lovrRelease(attachment->mesh);
lovrAssert(attachment->buffer != mesh->vbo, "Attribute '%s' was not attached from another Mesh", name);
lovrRelease(attachment->buffer);
map_remove(&mesh->attachments, name);
}
@ -2352,10 +2345,8 @@ void lovrMeshBind(Mesh* mesh, Shader* shader, int divisorMultiplier) {
memset(layout, 0, MAX_ATTACHMENTS * sizeof(MeshAttachment));
lovrGpuBindVertexArray(mesh->vao);
lovrMeshUnmapVertices(mesh);
lovrMeshUnmapIndices(mesh);
if (mesh->indexCount > 0) {
lovrGpuBindIndexBuffer(mesh->ibo);
lovrGpuBindIndexBuffer(mesh->ibo->id);
}
while ((key = map_next(&mesh->attachments, &iter)) != NULL) {
@ -2364,8 +2355,6 @@ void lovrMeshBind(Mesh* mesh, Shader* shader, int divisorMultiplier) {
if (location >= 0) {
MeshAttachment* attachment = map_get(&mesh->attachments, key);
layout[location] = *attachment;
lovrMeshUnmapVertices(attachment->mesh);
lovrMeshUnmapIndices(attachment->mesh);
}
}
@ -2391,31 +2380,31 @@ void lovrMeshBind(Mesh* mesh, Shader* shader, int divisorMultiplier) {
glVertexAttribDivisor(i, current.divisor * divisorMultiplier);
}
if (previous.mesh != current.mesh || previous.attributeIndex != current.attributeIndex) {
lovrGpuBindVertexBuffer(current.mesh->vbo);
VertexFormat* format = &current.mesh->format;
Attribute attribute = format->attributes[current.attributeIndex];
switch (attribute.type) {
case ATTR_FLOAT:
glVertexAttribPointer(i, attribute.count, GL_FLOAT, GL_TRUE, format->stride, (void*) attribute.offset);
break;
bool changed =
previous.buffer != current.buffer ||
previous.type != current.type ||
previous.components != current.components ||
previous.offset != current.offset ||
previous.stride != current.stride;
case ATTR_BYTE:
glVertexAttribPointer(i, attribute.count, GL_UNSIGNED_BYTE, GL_TRUE, format->stride, (void*) attribute.offset);
break;
case ATTR_INT:
glVertexAttribIPointer(i, attribute.count, GL_INT, format->stride, (void*) attribute.offset);
break;
if (changed) {
lovrGpuBindVertexBuffer(current.buffer->id);
int count = current.components;
int stride = current.stride;
GLvoid* offset = (GLvoid*) current.offset;
switch (current.type) {
case ATTR_FLOAT: glVertexAttribPointer(i, count, GL_FLOAT, GL_TRUE, stride, offset); break;
case ATTR_BYTE: glVertexAttribPointer(i, count, GL_UNSIGNED_BYTE, GL_TRUE, stride, offset); break;
case ATTR_INT: glVertexAttribIPointer(i, count, GL_INT, stride, offset); break;
}
}
mesh->layout[i] = current;
}
memcpy(mesh->layout, layout, MAX_ATTACHMENTS * sizeof(MeshAttachment));
}
void lovrMeshDraw(Mesh* mesh, int instances) {
GLenum glDrawMode = convertMeshDrawMode(lovrMeshGetDrawMode(mesh));
GLenum glDrawMode = convertMeshDrawMode(mesh->drawMode);
if (mesh->indexCount > 0) {
size_t count = mesh->rangeCount ? mesh->rangeCount : mesh->indexCount;
@ -2427,7 +2416,7 @@ void lovrMeshDraw(Mesh* mesh, int instances) {
glDrawElements(glDrawMode, count, indexType, (GLvoid*) offset);
}
} else {
size_t count = mesh->rangeCount ? mesh->rangeCount : lovrMeshGetVertexCount(mesh);
size_t count = mesh->rangeCount ? mesh->rangeCount : mesh->count;
if (instances > 1) {
glDrawArraysInstanced(glDrawMode, mesh->rangeStart, count, instances);
} else {
@ -2442,6 +2431,10 @@ VertexFormat* lovrMeshGetVertexFormat(Mesh* mesh) {
return &mesh->format;
}
bool lovrMeshIsReadable(Mesh* mesh) {
return mesh->readable;
}
MeshDrawMode lovrMeshGetDrawMode(Mesh* mesh) {
return mesh->drawMode;
}
@ -2490,88 +2483,35 @@ void lovrMeshSetMaterial(Mesh* mesh, Material* material) {
}
}
VertexPointer lovrMeshMapVertices(Mesh* mesh, uint32_t start, uint32_t count, bool read, bool write) {
if (write) {
mesh->dirtyStart = MIN(mesh->dirtyStart, start);
mesh->dirtyEnd = MAX(mesh->dirtyEnd, start + count);
}
return (VertexPointer) { .bytes = mesh->data.bytes + start * mesh->format.stride };
void* lovrMeshMapVertices(Mesh* mesh, size_t offset) {
return lovrBufferMap(mesh->vbo, offset);
}
void lovrMeshUnmapVertices(Mesh* mesh) {
if (mesh->dirtyEnd == 0) {
return;
}
size_t stride = mesh->format.stride;
lovrGpuBindVertexBuffer(mesh->vbo);
if (mesh->usage == USAGE_STREAM) {
glBufferData(GL_ARRAY_BUFFER, mesh->count * stride, mesh->data.bytes, convertBufferUsage(mesh->usage));
} else {
size_t offset = mesh->dirtyStart * stride;
size_t count = (mesh->dirtyEnd - mesh->dirtyStart) * stride;
glBufferSubData(GL_ARRAY_BUFFER, offset, count, mesh->data.bytes + offset);
}
mesh->dirtyStart = INT_MAX;
mesh->dirtyEnd = 0;
void lovrMeshFlushVertices(Mesh* mesh, size_t offset, size_t size) {
lovrBufferFlush(mesh->vbo, offset, size);
}
IndexPointer lovrMeshReadIndices(Mesh* mesh, uint32_t* count, size_t* size) {
*size = mesh->indexSize;
*count = mesh->indexCount;
if (mesh->indexCount == 0) {
return (IndexPointer) { .raw = NULL };
} else if (mesh->mappedIndices) {
lovrMeshUnmapIndices(mesh);
}
return mesh->indices;
}
IndexPointer lovrMeshWriteIndices(Mesh* mesh, uint32_t count, size_t size) {
if (mesh->mappedIndices) {
lovrMeshUnmapIndices(mesh);
}
mesh->indexSize = size;
void* lovrMeshMapIndices(Mesh* mesh, uint32_t count, size_t indexSize) {
mesh->indexSize = indexSize;
mesh->indexCount = count;
if (count == 0) {
return (IndexPointer) { .raw = NULL };
return NULL;
}
lovrGpuBindVertexArray(mesh->vao);
lovrGpuBindIndexBuffer(mesh->ibo);
mesh->mappedIndices = true;
if (mesh->indexCapacity < size * count) {
mesh->indexCapacity = nextPo2(size * count);
mesh->indices.raw = realloc(mesh->indices.raw, mesh->indexCapacity);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mesh->indexCapacity, NULL, convertBufferUsage(mesh->usage));
if (mesh->indexCapacity < indexSize * count) {
mesh->indexCapacity = nextPo2(indexSize * count);
lovrRelease(mesh->ibo);
mesh->ibo = lovrBufferCreate(mesh->indexCapacity, NULL, mesh->usage, mesh->readable);
}
return mesh->indices;
return lovrBufferMap(mesh->ibo, 0);
}
void lovrMeshUnmapIndices(Mesh* mesh) {
if (!mesh->mappedIndices) {
return;
}
mesh->mappedIndices = false;
lovrGpuBindIndexBuffer(mesh->ibo);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, mesh->indexCount * mesh->indexSize, mesh->indices.raw);
void lovrMeshFlushIndices(Mesh* mesh) {
lovrBufferFlush(mesh->ibo, 0, mesh->indexCount * mesh->indexSize);
}
void lovrMeshResize(Mesh* mesh, uint32_t count) {
if (mesh->count < count) {
count = nextPo2(count);
mesh->count = count;
lovrGpuBindVertexBuffer(mesh->vbo);
mesh->data.raw = realloc(mesh->data.raw, count * mesh->format.stride);
glBufferData(GL_ARRAY_BUFFER, count * mesh->format.stride, mesh->data.raw, convertBufferUsage(mesh->usage));
}
void* lovrMeshReadIndices(Mesh* mesh, uint32_t* count, size_t* indexSize) {
return *count = mesh->indexCount, *indexSize = mesh->indexSize, lovrBufferMap(mesh->ibo, 0);
}