rm VertexData;

This commit is contained in:
bjorn 2019-01-27 14:29:06 -08:00 committed by Bjorn Swenson
parent 4373e29bea
commit a02d4eb659
20 changed files with 413 additions and 653 deletions

View File

@ -385,7 +385,6 @@ if(LOVR_ENABLE_DATA)
src/data/rasterizer.c
src/data/soundData.c
src/data/textureData.c
src/data/vertexData.c
src/api/data.c
src/api/types/audioStream.c
src/api/types/blob.c
@ -393,7 +392,6 @@ if(LOVR_ENABLE_DATA)
src/api/types/rasterizer.c
src/api/types/soundData.c
src/api/types/textureData.c
src/api/types/vertexData.c
src/lib/stb/stb_image.c
src/lib/stb/stb_image_write.c
src/lib/stb/stb_truetype.c

View File

@ -53,7 +53,6 @@ extern const luaL_Reg lovrTexture[];
extern const luaL_Reg lovrTextureData[];
extern const luaL_Reg lovrThread[];
extern const luaL_Reg lovrVec3[];
extern const luaL_Reg lovrVertexData[];
extern const luaL_Reg lovrWorld[];
// Enums

View File

@ -5,8 +5,6 @@
#include "data/rasterizer.h"
#include "data/soundData.h"
#include "data/textureData.h"
#include "data/vertexData.h"
#include "filesystem/filesystem.h"
static int l_lovrDataNewBlob(lua_State* L) {
size_t size;
@ -45,11 +43,9 @@ static int l_lovrDataNewAudioStream(lua_State* L) {
return 1;
}
static ModelDataIO modelDataIO = { lovrFilesystemRead };
static int l_lovrDataNewModelData(lua_State* L) {
Blob* blob = luax_readblob(L, 1, "Model");
ModelData* modelData = lovrModelDataCreate(blob, modelDataIO);
ModelData* modelData = lovrModelDataCreate(blob);
luax_pushobject(L, modelData);
lovrRelease(blob);
lovrRelease(modelData);
@ -121,42 +117,6 @@ static int l_lovrDataNewTextureData(lua_State* L) {
return 1;
}
static int l_lovrDataNewVertexData(lua_State* L) {
uint32_t count;
int dataIndex = 0;
bool hasFormat = false;
VertexFormat format;
vertexFormatInit(&format);
if (lua_isnumber(L, 1)) {
count = lua_tointeger(L, 1);
} else if (lua_istable(L, 1)) {
if (lua_isnumber(L, 2)) {
hasFormat = luax_checkvertexformat(L, 1, &format);
count = lua_tointeger(L, 2);
dataIndex = 0;
} else if (lua_istable(L, 2)) {
hasFormat = luax_checkvertexformat(L, 1, &format);
count = lua_objlen(L, 2);
dataIndex = 2;
} else {
count = lua_objlen(L, 1);
dataIndex = 1;
}
} else {
return luaL_argerror(L, 1, "table or number expected");
}
VertexData* vertexData = lovrVertexDataCreate(count, hasFormat ? &format : NULL);
if (dataIndex) {
luax_loadvertices(L, dataIndex, &vertexData->format, (AttributePointer) { .raw = vertexData->blob.data });
}
luax_pushobject(L, vertexData);
lovrRelease(vertexData);
return 1;
}
static const luaL_Reg lovrData[] = {
{ "newBlob", l_lovrDataNewBlob },
{ "newAudioStream", l_lovrDataNewAudioStream },
@ -164,7 +124,6 @@ static const luaL_Reg lovrData[] = {
{ "newRasterizer", l_lovrDataNewRasterizer },
{ "newSoundData", l_lovrDataNewSoundData },
{ "newTextureData", l_lovrDataNewTextureData },
{ "newVertexData", l_lovrDataNewVertexData },
{ NULL, NULL }
};
@ -177,6 +136,5 @@ int luaopen_lovr_data(lua_State* L) {
luax_registertype(L, "Rasterizer", lovrRasterizer);
luax_extendtype(L, "Blob", "SoundData", lovrBlob, lovrSoundData);
luax_extendtype(L, "Blob", "TextureData", lovrBlob, lovrTextureData);
luax_extendtype(L, "Blob", "VertexData", lovrBlob, lovrVertexData);
return 1;
}

View File

@ -1,12 +1,3 @@
#include "data/blob.h"
#include "data/vertexData.h"
#include <stdbool.h>
int luax_loadvertices(lua_State* L, int index, VertexFormat* format, AttributePointer vertices);
bool luax_checkvertexformat(lua_State* L, int index, VertexFormat* format);
int luax_pushvertexformat(lua_State* L, VertexFormat* format);
int luax_pushvertexattribute(lua_State* L, AttributePointer* vertex, Attribute attribute);
int luax_pushvertex(lua_State* L, AttributePointer* vertex, VertexFormat* format);
void luax_setvertexattribute(lua_State* L, int index, AttributePointer* vertex, Attribute attribute);
void luax_setvertex(lua_State* L, int index, AttributePointer* vertex, VertexFormat* format);
Blob* luax_readblob(lua_State* L, int index, const char* debug);

View File

@ -11,7 +11,6 @@
#include "data/modelData.h"
#include "data/rasterizer.h"
#include "data/textureData.h"
#include "data/vertexData.h"
#include "filesystem/filesystem.h"
#include "util.h"
#define _USE_MATH_DEFINES
@ -26,13 +25,13 @@ const char* ArcModes[] = {
};
const char* AttributeTypes[] = {
[I8] = "i8",
[U8] = "u8",
[I16] = "i16",
[U16] = "u16",
[I32] = "i32",
[U32] = "u32",
[F32] = "f32",
[I8] = "byte",
[U8] = "ubyte",
[I16] = "short",
[U16] = "ushort",
[I32] = "int",
[U32] = "uint",
[F32] = "float",
NULL
};
@ -1124,70 +1123,136 @@ static int l_lovrGraphicsNewMaterial(lua_State* L) {
static int l_lovrGraphicsNewMesh(lua_State* L) {
uint32_t count;
int dataIndex = 0;
int formatIndex = 0;
int drawModeIndex = 2;
VertexData* vertexData = NULL;
bool hasFormat = false;
VertexFormat format;
vertexFormatInit(&format);
if (lua_isnumber(L, 1)) {
count = lua_tointeger(L, 1);
} else if (lua_istable(L, 1)) {
if (lua_isnumber(L, 2)) {
drawModeIndex++;
hasFormat = luax_checkvertexformat(L, 1, &format);
formatIndex = 1;
count = lua_tointeger(L, 2);
dataIndex = 0;
} else if (lua_istable(L, 2)) {
drawModeIndex++;
hasFormat = luax_checkvertexformat(L, 1, &format);
formatIndex = 1;
count = lua_objlen(L, 2);
dataIndex = 2;
} else {
count = lua_objlen(L, 1);
dataIndex = 1;
}
} else if (lua_isuserdata(L, 1)) {
vertexData = luax_checktype(L, 1, VertexData);
format = vertexData->format;
count = vertexData->count;
hasFormat = true;
} else {
luaL_argerror(L, 1, "table or number expected");
return 0;
}
if (!hasFormat) {
vertexFormatAppend(&format, "lovrPosition", F32, 3);
vertexFormatAppend(&format, "lovrNormal", F32, 3);
vertexFormatAppend(&format, "lovrTexCoord", F32, 2);
MeshAttribute attributes[MAX_ATTRIBUTES];
const char* attributeNames[MAX_ATTRIBUTES];
int attributeCount = 0;
size_t stride = 0;
if (formatIndex == 0) {
stride = 32;
attributeCount = 3;
attributes[0] = (MeshAttribute) { .offset = 0, .stride = stride, .type = F32, .components = 3 };
attributes[1] = (MeshAttribute) { .offset = 12, .stride = stride, .type = F32, .components = 3 };
attributes[2] = (MeshAttribute) { .offset = 24, .stride = stride, .type = F32, .components = 2 };
attributeNames[0] = "lovrPosition";
attributeNames[1] = "lovrNormal";
attributeNames[2] = "lovrTexCoord";
} else {
attributeCount = lua_objlen(L, formatIndex);
lovrAssert(attributeCount >= 0 && attributeCount <= MAX_ATTRIBUTES, "Attribute count must be between 0 and %d", MAX_ATTRIBUTES);
for (int i = 0; i < attributeCount; i++) {
lua_rawgeti(L, formatIndex, i + 1);
lovrAssert(lua_type(L, -1) == LUA_TTABLE, "Attribute definitions must be tables containing name, type, and component count");
lua_rawgeti(L, -1, 3);
lua_rawgeti(L, -1, 2);
lua_rawgeti(L, -1, 1);
attributeNames[i] = lua_tostring(L, -1);
attributes[i].offset = stride;
attributes[i].type = luaL_checkoption(L, -2, "float", AttributeTypes);
attributes[i].components = luaL_optinteger(L, -3, 1);
switch (attributes[i].type) {
case I8:
case U8:
stride += 1 * attributes[i].components;
break;
case I16:
case U16:
stride += 2 * attributes[i].components;
break;
case I32:
case U32:
case F32:
stride += 4 * attributes[i].components;
break;
}
lua_pop(L, 3);
}
}
DrawMode mode = luaL_checkoption(L, drawModeIndex, "fan", DrawModes);
BufferUsage usage = luaL_checkoption(L, drawModeIndex + 1, "dynamic", BufferUsages);
bool readable = lua_toboolean(L, drawModeIndex + 2);
size_t bufferSize = count * format.stride;
size_t bufferSize = attributeCount * stride;
Buffer* vertexBuffer = lovrBufferCreate(bufferSize, NULL, BUFFER_VERTEX, usage, readable);
Mesh* mesh = lovrMeshCreate(mode, format, vertexBuffer, count);
Mesh* mesh = lovrMeshCreate(mode, vertexBuffer, count);
for (int i = 0; i < attributeCount; i++) {
lovrMeshAttachAttribute(mesh, attributeNames[i], &(MeshAttribute) {
.buffer = vertexBuffer,
.offset = attributes[i].offset,
.stride = stride,
.type = attributes[i].type,
.components = attributes[i].components
});
}
lovrMeshAttachAttribute(mesh, "lovrDrawID", &(MeshAttribute) {
.buffer = lovrGraphicsGetIdentityBuffer(),
.type = U8,
.components = 1,
.divisor = 1,
.integer = true,
.enabled = true
.integer = true
});
if (dataIndex) {
AttributePointer vertices = { .raw = lovrBufferMap(vertexBuffer, 0) };
luax_loadvertices(L, dataIndex, lovrMeshGetVertexFormat(mesh), vertices);
} else if (vertexData) {
void* vertices = lovrBufferMap(vertexBuffer, 0);
memcpy(vertices, vertexData->blob.data, vertexData->count * vertexData->format.stride);
AttributeData data = { .raw = lovrBufferMap(vertexBuffer, 0) };
for (uint32_t i = 0; i < count; i++) {
lua_rawgeti(L, dataIndex, i + 1);
lovrAssert(lua_istable(L, -1), "Vertices should be specified as a table of tables");
int component = 0;
for (int j = 0; j < attributeCount; j++) {
MeshAttribute* attribute = &attributes[j];
for (int k = 0; k < attribute->components; k++) {
lua_rawgeti(L, -1, ++component);
switch (attribute->type) {
case I8: *data.i8++ = luaL_optinteger(L, -1, 0); break;
case U8: *data.u8++ = luaL_optinteger(L, -1, 0); break;
case I16: *data.i16++ = luaL_optinteger(L, -1, 0); break;
case U16: *data.u16++ = luaL_optinteger(L, -1, 0); break;
case I32: *data.i32++ = luaL_optinteger(L, -1, 0); break;
case U32: *data.u32++ = luaL_optinteger(L, -1, 0); break;
case F32: *data.u32++ = luaL_optnumber(L, -1, 0.); break;
}
lua_pop(L, 1);
}
}
lua_pop(L, 1);
}
}
lovrBufferMarkRange(vertexBuffer, 0, count * format.stride);
lovrBufferMarkRange(vertexBuffer, 0, count * stride);
lovrRelease(vertexBuffer);
luax_pushobject(L, mesh);
@ -1200,8 +1265,7 @@ static int l_lovrGraphicsNewModel(lua_State* L) {
if (!modelData) {
Blob* blob = luax_readblob(L, 1, "Model");
static ModelDataIO io = { lovrFilesystemRead };
modelData = lovrModelDataCreate(blob, io);
modelData = lovrModelDataCreate(blob);
lovrRelease(blob);
}

View File

@ -9,25 +9,24 @@ int l_lovrMeshAttachAttributes(lua_State* L) {
Mesh* other = luax_checktype(L, 2, Mesh);
int instanceDivisor = luaL_optinteger(L, 3, 0);
if (lua_isnoneornil(L, 4)) {
VertexFormat* format = lovrMeshGetVertexFormat(other);
for (int i = 0; i < format->count; i++) {
const char* name = format->attributes[i].name;
MeshAttribute* attribute = lovrMeshGetAttribute(other, name);
MeshAttribute attachment = *attribute;
int count = 0;
for (int i = 0; i < other->attributeCount; i++) {
MeshAttribute attachment = other->attributes[i];
if (attachment.buffer != other->vertexBuffer) {
break;
}
attachment.divisor = instanceDivisor;
attachment.enabled = true;
lovrMeshAttachAttribute(mesh, name, &attachment);
lovrMeshAttachAttribute(mesh, other->attributeNames[i], &attachment);
}
} else if (lua_istable(L, 4)) {
int length = lua_objlen(L, 4);
for (int i = 0; i < length; i++) {
lua_rawgeti(L, 4, i + 1);
const char* name = lua_tostring(L, -1);
MeshAttribute* attribute = lovrMeshGetAttribute(other, name);
const MeshAttribute* attribute = lovrMeshGetAttribute(other, name);
lovrAssert(attribute, "Tried to attach non-existent attribute %s", name);
MeshAttribute attachment = *attribute;
attachment.divisor = instanceDivisor;
attachment.enabled = true;
lovrMeshAttachAttribute(mesh, name, &attachment);
lua_pop(L, 1);
}
@ -35,11 +34,10 @@ int l_lovrMeshAttachAttributes(lua_State* L) {
int top = lua_gettop(L);
for (int i = 4; i <= top; i++) {
const char* name = lua_tostring(L, i);
MeshAttribute* attribute = lovrMeshGetAttribute(other, name);
const MeshAttribute* attribute = lovrMeshGetAttribute(other, name);
lovrAssert(attribute, "Tried to attach non-existent attribute %s", name);
MeshAttribute attachment = *attribute;
attachment.divisor = instanceDivisor;
attachment.enabled = true;
lovrMeshAttachAttribute(mesh, name, &attachment);
}
}
@ -51,9 +49,12 @@ int l_lovrMeshDetachAttributes(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
if (lua_isuserdata(L, 2)) {
Mesh* other = luax_checktype(L, 2, Mesh);
VertexFormat* format = lovrMeshGetVertexFormat(other);
for (int i = 0; i < format->count; i++) {
lovrMeshDetachAttribute(mesh, format->attributes[i].name);
for (int i = 0; i < other->attributeCount; i++) {
const MeshAttribute* attachment = &other->attributes[i];
if (attachment->buffer != other->vertexBuffer) {
break;
}
lovrMeshDetachAttribute(mesh, other->attributeNames[i]);
}
} else if (lua_istable(L, 2)) {
int length = lua_objlen(L, 2);
@ -111,8 +112,22 @@ int l_lovrMeshSetDrawMode(lua_State* L) {
int l_lovrMeshGetVertexFormat(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
VertexFormat* format = lovrMeshGetVertexFormat(mesh);
return luax_pushvertexformat(L, format);
lua_createtable(L, mesh->attributeCount, 0);
for (int i = 0; i < mesh->attributeCount; i++) {
const MeshAttribute* attribute = &mesh->attributes[i];
if (attribute->buffer != mesh->vertexBuffer) {
break;
}
lua_createtable(L, 3, 0);
lua_pushstring(L, mesh->attributeNames[i]);
lua_rawseti(L, -2, 1);
lua_pushstring(L, AttributeTypes[attribute->type]);
lua_rawseti(L, -2, 2);
lua_pushinteger(L, attribute->components);
lua_rawseti(L, -2, 3);
lua_rawseti(L, -2, i + 1);
}
return 1;
}
int l_lovrMeshGetVertexCount(lua_State* L) {
@ -123,23 +138,78 @@ 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;
Buffer* buffer = lovrMeshGetVertexBuffer(mesh);
lovrAssert(lovrBufferIsReadable(buffer), "Mesh:getVertex can only be used if the Mesh was created with the readable flag");
VertexFormat* format = lovrMeshGetVertexFormat(mesh);
AttributePointer vertex = { .raw = lovrBufferMap(buffer, index * format->stride) };
return luax_pushvertex(L, &vertex, format);
int index = luaL_checkinteger(L, 2) - 1;
if (!mesh->vertexBuffer || mesh->attributeCount == 0 || mesh->attributes[0].buffer != mesh->vertexBuffer) {
lovrThrow("Mesh does not have a vertex buffer");
}
lovrAssert(lovrBufferIsReadable(mesh->vertexBuffer), "Mesh:getVertex can only be used if the Mesh was created with the readable flag");
AttributeData data = { .raw = lovrBufferMap(mesh->vertexBuffer, index * mesh->attributes[0].stride) };
int components = 0;
for (int i = 0; i < mesh->attributeCount; i++) {
const MeshAttribute* attribute = &mesh->attributes[i];
if (attribute->buffer != mesh->vertexBuffer) {
break;
}
for (int j = 0; j < attribute->components; j++, components++) {
switch (attribute->type) {
case I8: lua_pushinteger(L, *data.i8++); break;
case U8: lua_pushinteger(L, *data.u8++); break;
case I16: lua_pushinteger(L, *data.i16++); break;
case U16: lua_pushinteger(L, *data.u16++); break;
case I32: lua_pushinteger(L, *data.i32++); break;
case U32: lua_pushinteger(L, *data.u32++); break;
case F32: lua_pushnumber(L, *data.f32++); break;
}
}
}
return components;
}
int l_lovrMeshSetVertex(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
uint32_t index = luaL_checkinteger(L, 2) - 1;
lovrAssert(index >= 0 && index < lovrMeshGetVertexCount(mesh), "Invalid mesh vertex index: %d", index + 1);
Buffer* buffer = lovrMeshGetVertexBuffer(mesh);
VertexFormat* format = lovrMeshGetVertexFormat(mesh);
AttributePointer vertex = { .raw = lovrBufferMap(buffer, index * format->stride) };
luax_setvertex(L, 3, &vertex, format);
lovrBufferMarkRange(buffer, index * format->stride, (index + 1) * format->stride);
bool table = lua_istable(L, 3);
if (!mesh->vertexBuffer || mesh->attributeCount == 0 || mesh->attributes[0].buffer != mesh->vertexBuffer) {
lovrThrow("Mesh does not have a vertex buffer");
}
size_t stride = mesh->attributes[0].stride;
AttributeData data = { .raw = lovrBufferMap(mesh->vertexBuffer, index * stride) };
int component = 0;
for (int i = 0; i < mesh->attributeCount; i++) {
const MeshAttribute* attribute = &mesh->attributes[i];
if (attribute->buffer != mesh->vertexBuffer) {
break;
}
for (int j = 0; j < attribute->components; j++) {
int k = 3 + j;
if (table) {
lua_rawgeti(L, 3, ++component);
k = -1;
}
switch (attribute->type) {
case I8: *data.i8++ = luaL_optinteger(L, k, 0); break;
case U8: *data.u8++ = luaL_optinteger(L, k, 0); break;
case I16: *data.i16++ = luaL_optinteger(L, k, 0); break;
case U16: *data.u16++ = luaL_optinteger(L, k, 0); break;
case I32: *data.i32++ = luaL_optinteger(L, k, 0); break;
case U32: *data.u32++ = luaL_optinteger(L, k, 0); break;
case F32: *data.f32++ = luaL_optnumber(L, k, 0.); break;
}
if (table) {
lua_pop(L, 1);
}
}
}
lovrBufferMarkRange(mesh->vertexBuffer, index * stride, (index + 1) * stride);
return 0;
}
@ -148,67 +218,108 @@ int l_lovrMeshGetVertexAttribute(lua_State* L) {
uint32_t vertexIndex = luaL_checkinteger(L, 2) - 1;
int attributeIndex = luaL_checkinteger(L, 3) - 1;
Buffer* buffer = lovrMeshGetVertexBuffer(mesh);
VertexFormat* format = lovrMeshGetVertexFormat(mesh);
lovrAssert(lovrBufferIsReadable(buffer), "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];
AttributePointer vertex = { .raw = lovrBufferMap(buffer, vertexIndex * format->stride + attribute.offset) };
return luax_pushvertexattribute(L, &vertex, attribute);
lovrAssert(attributeIndex >= 0 && attributeIndex < mesh->attributeCount, "Invalid mesh attribute: %d", attributeIndex + 1);
lovrAssert(mesh->attributes[attributeIndex].buffer == mesh->vertexBuffer, "Invalid mesh attribute: %d", attributeIndex + 1);
MeshAttribute* attribute = &mesh->attributes[attributeIndex];
AttributeData data = { .raw = lovrBufferMap(buffer, vertexIndex * attribute->stride + attribute->offset) };
for (int i = 0; i < attribute->components; i++) {
switch (attribute->type) {
case I8: lua_pushinteger(L, *data.i8++); break;
case U8: lua_pushinteger(L, *data.u8++); break;
case I16: lua_pushinteger(L, *data.i16++); break;
case U16: lua_pushinteger(L, *data.u16++); break;
case I32: lua_pushinteger(L, *data.i32++); break;
case U32: lua_pushinteger(L, *data.u32++); break;
case F32: lua_pushnumber(L, *data.f32++); break;
}
}
return attribute->components;
}
int l_lovrMeshSetVertexAttribute(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
uint32_t vertexIndex = luaL_checkinteger(L, 2) - 1;
int attributeIndex = luaL_checkinteger(L, 3) - 1;
VertexFormat* format = lovrMeshGetVertexFormat(mesh);
bool table = lua_istable(L, 4);
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];
Buffer* buffer = lovrMeshGetVertexBuffer(mesh);
AttributePointer vertex = { .raw = lovrBufferMap(buffer, vertexIndex * format->stride + attribute.offset) };
luax_setvertexattribute(L, 4, &vertex, attribute);
lovrBufferMarkRange(buffer, vertexIndex * format->stride + attribute.offset, vertexIndex * format->stride + attribute.offset + attribute.size);
lovrAssert(attributeIndex >= 0 && attributeIndex < mesh->attributeCount, "Invalid mesh attribute: %d", attributeIndex + 1);
lovrAssert(mesh->attributes[attributeIndex].buffer == mesh->vertexBuffer, "Invalid mesh attribute: %d", attributeIndex + 1);
MeshAttribute* attribute = &mesh->attributes[attributeIndex];
AttributeData data = { .raw = lovrBufferMap(mesh->vertexBuffer, vertexIndex * attribute->stride + attribute->offset) };
for (int i = 0; i < attribute->components; i++) {
int index = 4 + i;
if (table) {
lua_rawgeti(L, 4, i + 1);
index = -1;
}
switch (attribute->type) {
case I8: *data.i8++ = luaL_optinteger(L, index, 0); break;
case U8: *data.u8++ = luaL_optinteger(L, index, 0); break;
case I16: *data.i16++ = luaL_optinteger(L, index, 0); break;
case U16: *data.u16++ = luaL_optinteger(L, index, 0); break;
case I32: *data.i32++ = luaL_optinteger(L, index, 0); break;
case U32: *data.u32++ = luaL_optinteger(L, index, 0); break;
case F32: *data.f32++ = luaL_optnumber(L, index, 0.); break;
}
if (table) {
lua_pop(L, 1);
}
}
lovrBufferMarkRange(mesh->vertexBuffer, vertexIndex * attribute->stride, (vertexIndex + 1) * attribute->stride);
return 0;
}
int l_lovrMeshSetVertices(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
VertexFormat* format = lovrMeshGetVertexFormat(mesh);
uint32_t capacity = lovrMeshGetVertexCount(mesh);
VertexData* vertexData = NULL;
uint32_t sourceSize;
if (lua_istable(L, 2)) {
sourceSize = lua_objlen(L, 2);
} else {
vertexData = luax_checktype(L, 2, VertexData);
sourceSize = vertexData->count;
bool sameFormat = !memcmp(&vertexData->format, format, sizeof(VertexFormat));
lovrAssert(sameFormat, "Mesh and VertexData must have the same format to copy vertices");
}
luaL_checktype(L, 2, LUA_TTABLE);
uint32_t sourceSize = lua_objlen(L, 2);
uint32_t start = luaL_optinteger(L, 3, 1) - 1;
uint32_t count = luaL_optinteger(L, 4, sourceSize);
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);
Buffer* buffer = lovrMeshGetVertexBuffer(mesh);
AttributePointer vertices = { .raw = lovrBufferMap(buffer, start * format->stride) };
if (vertexData) {
memcpy(vertices.raw, vertexData->blob.data, count * format->stride);
} else {
for (uint32_t i = 0; i < count; i++) {
lua_rawgeti(L, 2, i + 1);
luaL_checktype(L, -1, LUA_TTABLE);
luax_setvertex(L, -1, &vertices, format);
lua_pop(L, 1);
}
if (!mesh->vertexBuffer || mesh->attributeCount == 0 || mesh->attributes[0].buffer != mesh->vertexBuffer) {
lovrThrow("Mesh does not have a vertex buffer");
}
lovrBufferMarkRange(buffer, start * format->stride, (start + count) * format->stride);
size_t stride = mesh->attributes[0].stride;
AttributeData data = { .raw = lovrBufferMap(mesh->vertexBuffer, start * stride) };
for (uint32_t i = 0; i < count; i++) {
lua_rawgeti(L, 2, i + 1);
luaL_checktype(L, -1, LUA_TTABLE);
int component = 0;
for (int j = 0; j < mesh->attributeCount; j++) {
const MeshAttribute* attribute = &mesh->attributes[j];
if (attribute->buffer != mesh->vertexBuffer) {
break;
}
for (int k = 0; k < attribute->components; k++) {
lua_rawgeti(L, -1, ++component);
switch (attribute->type) {
case I8: *data.i8++ = luaL_optinteger(L, -1, 0); break;
case U8: *data.u8++ = luaL_optinteger(L, -1, 0); break;
case I16: *data.i16++ = luaL_optinteger(L, -1, 0); break;
case U16: *data.u16++ = luaL_optinteger(L, -1, 0); break;
case I32: *data.i32++ = luaL_optinteger(L, -1, 0); break;
case U32: *data.u32++ = luaL_optinteger(L, -1, 0); break;
case F32: *data.f32++ = luaL_optnumber(L, -1, 0.); break;
}
lua_pop(L, 1);
}
}
lua_pop(L, 1);
}
lovrBufferMarkRange(mesh->vertexBuffer, start * stride, (start + count) * stride);
return 0;
}
@ -224,7 +335,7 @@ int l_lovrMeshGetVertexMap(lua_State* L) {
}
lovrAssert(lovrBufferIsReadable(buffer), "Mesh:getVertexMap can only be used if the Mesh was created with the readable flag");
IndexPointer indices = { .raw = lovrBufferMap(buffer, 0) };
union { void* raw; uint16_t* shorts; uint32_t* ints; } indices = { .raw = lovrBufferMap(buffer, 0) };
if (lua_istable(L, 2)) {
lua_settop(L, 2);
@ -286,7 +397,7 @@ int l_lovrMeshSetVertexMap(lua_State* L) {
indexBuffer = lovrBufferCreate(count * size, NULL, BUFFER_INDEX, usage, readable);
}
IndexPointer indices = { .raw = lovrBufferMap(indexBuffer, 0) };
union { void* raw; uint16_t* shorts; uint32_t* ints; } indices = { .raw = lovrBufferMap(indexBuffer, 0) };
for (uint32_t i = 0; i < count; i++) {
lua_rawgeti(L, 2, i + 1);

View File

@ -1,242 +0,0 @@
#include "api.h"
#include "api/data.h"
int luax_loadvertices(lua_State* L, int index, VertexFormat* format, AttributePointer vertices) {
uint32_t count = lua_objlen(L, index);
for (uint32_t i = 0; i < count; i++) {
lua_rawgeti(L, index, i + 1);
if (!lua_istable(L, -1)) {
return luaL_error(L, "Vertex information should be specified as a table");
}
int component = 0;
for (int j = 0; j < format->count; j++) {
Attribute attribute = format->attributes[j];
for (int k = 0; k < attribute.count; k++) {
lua_rawgeti(L, -1, ++component);
switch (attribute.type) {
case I8: *vertices.i8++ = luaL_optinteger(L, -1, 0); break;
case U8: *vertices.u8++ = luaL_optinteger(L, -1, 0); break;
case I16: *vertices.i16++ = luaL_optinteger(L, -1, 0); break;
case U16: *vertices.u16++ = luaL_optinteger(L, -1, 0); break;
case I32: *vertices.i32++ = luaL_optinteger(L, -1, 0); break;
case U32: *vertices.u32++ = luaL_optinteger(L, -1, 0); break;
case F32: *vertices.u32++ = luaL_optnumber(L, -1, 0); break;
}
lua_pop(L, 1);
}
}
lua_pop(L, 1);
}
return 0;
}
bool luax_checkvertexformat(lua_State* L, int index, VertexFormat* format) {
if (!lua_istable(L, index)) {
return false;
}
int length = lua_objlen(L, index);
lovrAssert(length <= 8, "Up to 8 vertex attributes are supported");
for (int i = 0; i < length; i++) {
lua_rawgeti(L, index, i + 1);
if (!lua_istable(L, -1) || lua_objlen(L, -1) != 3) {
luaL_error(L, "Expected vertex format specified as tables containing name, data type, and size");
return false;
}
lua_rawgeti(L, -1, 1);
lua_rawgeti(L, -2, 2);
lua_rawgeti(L, -3, 3);
const char* name = lua_tostring(L, -3);
AttributeType type = luaL_checkoption(L, -2, NULL, AttributeTypes);
int count = lua_tointeger(L, -1);
lovrAssert(count >= 1 || count <= 4, "Vertex attribute counts must be between 1 and 4");
vertexFormatAppend(format, name, type, count);
lua_pop(L, 4);
}
return true;
}
int luax_pushvertexformat(lua_State* L, VertexFormat* format) {
lua_newtable(L);
for (int i = 0; i < format->count; i++) {
Attribute attribute = format->attributes[i];
lua_newtable(L);
// Name
lua_pushstring(L, attribute.name);
lua_rawseti(L, -2, 1);
// Type
lua_pushstring(L, AttributeTypes[attribute.type]);
lua_rawseti(L, -2, 2);
// Count
lua_pushinteger(L, attribute.count);
lua_rawseti(L, -2, 3);
lua_rawseti(L, -2, i + 1);
}
return 1;
}
int luax_pushvertexattribute(lua_State* L, AttributePointer* vertex, Attribute attribute) {
for (int i = 0; i < attribute.count; i++) {
switch (attribute.type) {
case I8: lua_pushinteger(L, *vertex->i8++); break;
case U8: lua_pushinteger(L, *vertex->u8++); break;
case I16: lua_pushinteger(L, *vertex->i16++); break;
case U16: lua_pushinteger(L, *vertex->u16++); break;
case I32: lua_pushinteger(L, *vertex->i32++); break;
case U32: lua_pushinteger(L, *vertex->u32++); break;
case F32: lua_pushnumber(L, *vertex->f32++); break;
}
}
return attribute.count;
}
int luax_pushvertex(lua_State* L, AttributePointer* vertex, VertexFormat* format) {
int count = 0;
for (int i = 0; i < format->count; i++) {
count += luax_pushvertexattribute(L, vertex, format->attributes[i]);
}
return count;
}
void luax_setvertexattribute(lua_State* L, int index, AttributePointer* vertex, Attribute attribute) {
for (int i = 0; i < attribute.count; i++) {
switch (attribute.type) {
case I8: *vertex->i8++ = luaL_optinteger(L, index++, 0); break;
case U8: *vertex->u8++ = luaL_optinteger(L, index++, 0); break;
case I16: *vertex->i16++ = luaL_optinteger(L, index++, 0); break;
case U16: *vertex->u16++ = luaL_optinteger(L, index++, 0); break;
case I32: *vertex->i32++ = luaL_optinteger(L, index++, 0); break;
case U32: *vertex->u32++ = luaL_optinteger(L, index++, 0); break;
case F32: *vertex->f32++ = luaL_optnumber(L, index++, 0.); break;
}
}
}
void luax_setvertex(lua_State* L, int index, AttributePointer* vertex, VertexFormat* format) {
if (lua_istable(L, index)) {
int component = 0;
for (int i = 0; i < format->count; i++) {
Attribute attribute = format->attributes[i];
for (int j = 0; j < attribute.count; j++) {
lua_rawgeti(L, index, ++component);
switch (attribute.type) {
case I8: *vertex->i8++ = luaL_optinteger(L, -1, 0); break;
case U8: *vertex->u8++ = luaL_optinteger(L, -1, 0); break;
case I16: *vertex->i16++ = luaL_optinteger(L, -1, 0); break;
case U16: *vertex->u16++ = luaL_optinteger(L, -1, 0); break;
case I32: *vertex->i32++ = luaL_optinteger(L, -1, 0); break;
case U32: *vertex->u32++ = luaL_optinteger(L, -1, 0); break;
case F32: *vertex->f32++ = luaL_optnumber(L, -1, 0.); break;
}
lua_pop(L, 1);
}
}
} else {
for (int i = 0; i < format->count; i++) {
luax_setvertexattribute(L, index, vertex, format->attributes[i]);
index += format->attributes[i].count;
}
}
}
//
int l_lovrVertexDataGetCount(lua_State* L) {
VertexData* vertexData = luax_checktype(L, 1, VertexData);
uint32_t count = vertexData->count;
lua_pushinteger(L, count);
return 1;
}
int l_lovrVertexDataGetFormat(lua_State* L) {
VertexData* vertexData = luax_checktype(L, 1, VertexData);
return luax_pushvertexformat(L, &vertexData->format);
}
int l_lovrVertexDataGetVertex(lua_State* L) {
VertexData* vertexData = luax_checktype(L, 1, VertexData);
uint32_t index = (uint32_t) luaL_checkint(L, 2) - 1;
AttributePointer vertex = { .raw = (uint8_t*) vertexData->blob.data + index * vertexData->format.stride };
return luax_pushvertex(L, &vertex, &vertexData->format);
}
int l_lovrVertexDataSetVertex(lua_State* L) {
VertexData* vertexData = luax_checktype(L, 1, VertexData);
uint32_t index = (uint32_t) luaL_checkint(L, 2) - 1;
lovrAssert(index < vertexData->count, "Invalid vertex index: %d", index + 1);
VertexFormat* format = &vertexData->format;
AttributePointer vertex = { .raw = vertexData->blob.data };
vertex.u8 += index * format->stride;
luax_setvertex(L, 3, &vertex, format);
return 0;
}
int l_lovrVertexDataGetVertexAttribute(lua_State* L) {
VertexData* vertexData = luax_checktype(L, 1, VertexData);
uint32_t vertexIndex = (uint32_t) luaL_checkint(L, 2) - 1;
int attributeIndex = luaL_checkint(L, 3) - 1;
VertexFormat* format = &vertexData->format;
lovrAssert(vertexIndex < vertexData->count, "Invalid vertex index: %d", vertexIndex + 1);
lovrAssert(attributeIndex >= 0 && attributeIndex < format->count, "Invalid attribute index: %d", attributeIndex + 1);
Attribute attribute = format->attributes[attributeIndex];
AttributePointer vertex = { .raw = vertexData->blob.data };
vertex.u8 += vertexIndex * format->stride + attribute.offset;
return luax_pushvertexattribute(L, &vertex, attribute);
}
int l_lovrVertexDataSetVertexAttribute(lua_State* L) {
VertexData* vertexData = luax_checktype(L, 1, VertexData);
uint32_t vertexIndex = (uint32_t) luaL_checkint(L, 2) - 1;
int attributeIndex = luaL_checkint(L, 3) - 1;
VertexFormat* format = &vertexData->format;
lovrAssert(vertexIndex < vertexData->count, "Invalid vertex index: %d", vertexIndex + 1);
lovrAssert(attributeIndex >= 0 && attributeIndex < format->count, "Invalid attribute index: %d", attributeIndex + 1);
Attribute attribute = format->attributes[attributeIndex];
AttributePointer vertex = { .raw = vertexData->blob.data };
vertex.u8 += vertexIndex * format->stride + attribute.offset;
luax_setvertexattribute(L, 4, &vertex, attribute);
return 0;
}
int l_lovrVertexDataSetVertices(lua_State* L) {
VertexData* vertexData = luax_checktype(L, 1, VertexData);
VertexFormat* format = &vertexData->format;
luaL_checktype(L, 2, LUA_TTABLE);
uint32_t vertexCount = lua_objlen(L, 2);
int start = luaL_optinteger(L, 3, 1) - 1;
lovrAssert(start + vertexCount <= vertexData->count, "VertexData can only hold %d vertices", vertexData->count);
AttributePointer vertices = { .raw = vertexData->blob.data };
vertices.u8 += start * format->stride;
for (uint32_t i = 0; i < vertexCount; i++) {
lua_rawgeti(L, 2, i + 1);
luaL_checktype(L, -1, LUA_TTABLE);
luax_setvertex(L, -1, &vertices, format);
lua_pop(L, 1);
}
return 0;
}
const luaL_Reg lovrVertexData[] = {
{ "getCount", l_lovrVertexDataGetCount },
{ "getFormat", l_lovrVertexDataGetFormat },
{ "getVertex", l_lovrVertexDataGetVertex },
{ "setVertex", l_lovrVertexDataSetVertex },
{ "getVertexAttribute", l_lovrVertexDataGetVertexAttribute },
{ "setVertexAttribute", l_lovrVertexDataSetVertexAttribute },
{ "setVertices", l_lovrVertexDataSetVertices },
{ NULL, NULL }
};

View File

@ -1,9 +1,9 @@
#include "data/modelData.h"
ModelData* lovrModelDataInit(ModelData* model, Blob* source, ModelDataIO io) {
if (lovrModelDataInitGltf(model, source, io)) {
ModelData* lovrModelDataInit(ModelData* model, Blob* source) {
if (lovrModelDataInitGltf(model, source)) {
return model;
} else if (lovrModelDataInitObj(model, source, io)) {
} else if (lovrModelDataInitObj(model, source)) {
return model;
}

View File

@ -1,8 +1,6 @@
#include "data/blob.h"
#include "data/textureData.h"
#include "util.h"
#include "lib/map/map.h"
#include "lib/vec/vec.h"
#pragma once
@ -90,6 +88,17 @@ typedef enum {
typedef enum { I8, U8, I16, U16, I32, U32, F32 } AttributeType;
typedef union {
void* raw;
int8_t* i8;
uint8_t* u8;
int16_t* i16;
uint16_t* u16;
int32_t* i32;
uint32_t* u32;
float* f32;
} AttributeData;
typedef struct {
char* data;
size_t size;
@ -196,13 +205,9 @@ typedef struct {
int charCount;
} ModelData;
typedef struct {
void* (*read)(const char* path, size_t* bytesRead);
} ModelDataIO;
ModelData* lovrModelDataInit(ModelData* model, Blob* blob, ModelDataIO io);
ModelData* lovrModelDataInitGltf(ModelData* model, Blob* blob, ModelDataIO io);
ModelData* lovrModelDataInitObj(ModelData* model, Blob* blob, ModelDataIO io);
ModelData* lovrModelDataInit(ModelData* model, Blob* blob);
#define lovrModelDataCreate(...) lovrModelDataInit(lovrAlloc(ModelData), __VA_ARGS__)
ModelData* lovrModelDataInitGltf(ModelData* model, Blob* blob);
ModelData* lovrModelDataInitObj(ModelData* model, Blob* blob);
void lovrModelDataDestroy(void* ref);
void lovrModelDataAllocate(ModelData* model);

View File

@ -1,4 +1,5 @@
#include "data/modelData.h"
#include "filesystem/filesystem.h"
#include "lib/math.h"
#include "lib/jsmn/jsmn.h"
#include <stdbool.h>
@ -111,7 +112,7 @@ static jsmntok_t* resolveTexture(const char* json, jsmntok_t* token, ModelMateri
return token;
}
ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO io) {
ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source) {
uint8_t* data = source->data;
gltfHeader* header = (gltfHeader*) data;
bool glb = header->magic == MAGIC_glTF;
@ -422,7 +423,7 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO io)
char filename[1024];
lovrAssert(uri.length < 1024, "Buffer filename is too long");
snprintf(filename, 1023, "%s/%.*s", basePath, (int) uri.length, uri.data);
*blob = lovrBlobCreate(io.read(filename, &bytesRead), size, NULL);
*blob = lovrBlobCreate(lovrFilesystemRead(filename, &bytesRead), size, NULL);
lovrAssert((*blob)->data && bytesRead == size, "Unable to read %s", filename);
} else {
lovrAssert(glb, "Buffer is missing URI");

View File

@ -1,6 +1,8 @@
#include "data/modelData.h"
#include "filesystem/filesystem.h"
#include "lib/math.h"
#include "lib/map/map.h"
#include "lib/vec/vec.h"
#include <stdio.h>
#include <ctype.h>

View File

@ -1,43 +0,0 @@
#include "data/vertexData.h"
#include <string.h>
static const size_t attributeTypeSizes[] = {
[I8] = 1,
[U8] = 1,
[I16] = 2,
[U16] = 2,
[I32] = 4,
[U32] = 4,
[F32] = 4
};
void vertexFormatInit(VertexFormat* format) {
memset(format, 0, sizeof(*format));
}
void vertexFormatAppend(VertexFormat* format, const char* name, AttributeType type, int count) {
size_t size = attributeTypeSizes[type];
Attribute attribute = { name, type, count, size, format->stride };
format->attributes[format->count++] = attribute;
format->stride += size * count;
}
VertexData* lovrVertexDataInit(VertexData* vertexData, uint32_t count, VertexFormat* format) {
if (format) {
vertexData->format = *format;
} else {
format = &vertexData->format;
vertexFormatInit(&vertexData->format);
vertexFormatAppend(&vertexData->format, "lovrPosition", F32, 3);
vertexFormatAppend(&vertexData->format, "lovrNormal", F32, 3);
vertexFormatAppend(&vertexData->format, "lovrTexCoord", F32, 2);
vertexFormatAppend(&vertexData->format, "lovrVertexColor", U8, 4);
}
size_t size = format->stride * count;
vertexData->blob.data = calloc(1, size);
vertexData->blob.size = size;
vertexData->count = count;
return vertexData;
}

View File

@ -1,50 +0,0 @@
#include "blob.h"
#include "data/modelData.h"
#include <stdlib.h>
#include <stdint.h>
#pragma once
typedef struct {
const char* name;
AttributeType type;
int count;
size_t size;
size_t offset;
} Attribute;
typedef struct {
Attribute attributes[8];
size_t stride;
int count;
} VertexFormat;
typedef union {
void* raw;
int8_t* i8;
uint8_t* u8;
int16_t* i16;
uint16_t* u16;
int32_t* i32;
uint32_t* u32;
float* f32;
} AttributePointer;
typedef union {
void* raw;
uint16_t* shorts;
uint32_t* ints;
} IndexPointer;
typedef struct {
Blob blob;
VertexFormat format;
uint32_t count;
} VertexData;
void vertexFormatInit(VertexFormat* format);
void vertexFormatAppend(VertexFormat* format, const char* name, AttributeType type, int count);
VertexData* lovrVertexDataInit(VertexData* vertexData, uint32_t count, VertexFormat* format);
#define lovrVertexDataCreate(...) lovrVertexDataInit(lovrAlloc(VertexData), __VA_ARGS__)
#define lovrVertexDataDestroy NULL

View File

@ -67,22 +67,22 @@ static void lovrGraphicsInitBuffers() {
for (int i = 0; i < 256; i++) id[i] = i;
lovrBufferFlushRange(state.identityBuffer, 0, 256);
VertexFormat empty = { .count = 0 };
Buffer* vertexBuffer = state.buffers[STREAM_VERTEX];
size_t stride = BUFFER_STRIDES[STREAM_VERTEX];
MeshAttribute position = { vertexBuffer, 0, stride, F32, 3, .enabled = true };
MeshAttribute normal = { vertexBuffer, 12, stride, F32, 3, .enabled = true };
MeshAttribute texCoord = { vertexBuffer, 24, stride, F32, 2, .enabled = true };
MeshAttribute drawId = { state.buffers[STREAM_DRAW_ID], 0, 0, U8, 1, .integer = true, .enabled = true };
MeshAttribute identity = { state.identityBuffer, 0, 0, U8, 1, .divisor = 1, .integer = true, .enabled = true };
state.mesh = lovrMeshCreate(DRAW_TRIANGLES, empty, NULL, 0);
MeshAttribute position = { .buffer = vertexBuffer, .offset = 0, .stride = stride, .type = F32, .components = 3 };
MeshAttribute normal = { .buffer = vertexBuffer, .offset = 12, .stride = stride, .type = F32, .components = 3 };
MeshAttribute texCoord = { .buffer = vertexBuffer, .offset = 24, .stride = stride, .type = F32, .components = 2 };
MeshAttribute drawId = { .buffer = state.buffers[STREAM_DRAW_ID], .type = U8, .components = 1, .integer = true };
MeshAttribute identity = { .buffer = state.identityBuffer, .type = U8, .components = 1, .divisor = 1, .integer = true };
state.mesh = lovrMeshCreate(DRAW_TRIANGLES, NULL, 0);
lovrMeshAttachAttribute(state.mesh, "lovrPosition", &position);
lovrMeshAttachAttribute(state.mesh, "lovrNormal", &normal);
lovrMeshAttachAttribute(state.mesh, "lovrTexCoord", &texCoord);
lovrMeshAttachAttribute(state.mesh, "lovrDrawID", &drawId);
state.instancedMesh = lovrMeshCreate(DRAW_TRIANGLES, empty, NULL, 0);
state.instancedMesh = lovrMeshCreate(DRAW_TRIANGLES, NULL, 0);
lovrMeshAttachAttribute(state.instancedMesh, "lovrPosition", &position);
lovrMeshAttachAttribute(state.instancedMesh, "lovrNormal", &normal);
lovrMeshAttachAttribute(state.instancedMesh, "lovrTexCoord", &texCoord);

View File

@ -1,10 +1,6 @@
#include "graphics/mesh.h"
#include "graphics/graphics.h"
VertexFormat* lovrMeshGetVertexFormat(Mesh* mesh) {
return &mesh->format;
}
Buffer* lovrMeshGetVertexBuffer(Mesh* mesh) {
return mesh->vertexBuffer;
}
@ -25,39 +21,59 @@ size_t lovrMeshGetIndexSize(Mesh* mesh) {
return mesh->indexSize;
}
int lovrMeshGetAttributeCount(Mesh* mesh) {
return mesh->attributeCount;
}
void lovrMeshAttachAttribute(Mesh* mesh, const char* name, MeshAttribute* attribute) {
lovrAssert(!map_get(&mesh->attributes, name), "Mesh already has an attribute named '%s'", name);
lovrAssert(attribute->divisor >= 0, "Divisor can't be negative");
lovrAssert(!map_get(&mesh->attributeMap, name), "Mesh already has an attribute named '%s'", name);
lovrAssert(mesh->attributeCount < MAX_ATTRIBUTES, "Mesh already has the max number of attributes (%d)", MAX_ATTRIBUTES);
lovrGraphicsFlushMesh(mesh);
map_set(&mesh->attributes, name, *attribute);
int index = mesh->attributeCount++;
mesh->attributes[index] = *attribute;
mesh->attributeNames[index] = name;
map_set(&mesh->attributeMap, name, index);
lovrRetain(attribute->buffer);
}
void lovrMeshDetachAttribute(Mesh* mesh, const char* name) {
MeshAttribute* attribute = map_get(&mesh->attributes, name);
lovrAssert(attribute, "No attached attribute '%s' was found", name);
lovrAssert(attribute->buffer != mesh->vertexBuffer, "Attribute '%s' was not attached from another Mesh", name);
int* index = map_get(&mesh->attributeMap, name);
lovrAssert(index, "No attached attribute named '%s' was found", name);
MeshAttribute* attribute = &mesh->attributes[*index];
lovrGraphicsFlushMesh(mesh);
lovrRelease(attribute->buffer);
map_remove(&mesh->attributes, name);
map_remove(&mesh->attributeMap, name);
mesh->attributeNames[*index] = NULL;
memmove(mesh->attributeNames + *index, mesh->attributeNames + *index + 1, (mesh->attributeCount - *index - 1) * sizeof(char*));
memmove(mesh->attributes + *index, mesh->attributes + *index + 1, (mesh->attributeCount - *index - 1) * sizeof(MeshAttribute));
mesh->attributeCount--;
for (int i = 0; i < MAX_ATTRIBUTES; i++) {
if (mesh->locations[i] > *index) {
mesh->locations[i]--;
} else if (mesh->locations[i] == *index) {
mesh->locations[i] = 0xff;
}
}
}
MeshAttribute* lovrMeshGetAttribute(Mesh* mesh, const char* name) {
return map_get(&mesh->attributes, name);
const MeshAttribute* lovrMeshGetAttribute(Mesh* mesh, const char* name) {
int* index = map_get(&mesh->attributeMap, name);
return index ? &mesh->attributes[*index] : NULL;
}
bool lovrMeshIsAttributeEnabled(Mesh* mesh, const char* name) {
MeshAttribute* attribute = map_get(&mesh->attributes, name);
lovrAssert(attribute, "Mesh does not have an attribute named '%s'", name);
return attribute->enabled;
int* index = map_get(&mesh->attributeMap, name);
lovrAssert(index, "Mesh does not have an attribute named '%s'", name);
return !mesh->attributes[*index].disabled;
}
void lovrMeshSetAttributeEnabled(Mesh* mesh, const char* name, bool enable) {
MeshAttribute* attribute = map_get(&mesh->attributes, name);
lovrAssert(attribute, "Mesh does not have an attribute named '%s'", name);
if (attribute->enabled != enable) {
bool disable = !enable;
int* index = map_get(&mesh->attributeMap, name);
lovrAssert(index, "Mesh does not have an attribute named '%s'", name);
if (mesh->attributes[*index].disabled != disable) {
lovrGraphicsFlushMesh(mesh);
attribute->enabled = enable;
mesh->attributes[*index].disabled = disable;
}
}

View File

@ -2,7 +2,6 @@
#include "graphics/material.h"
#include "graphics/shader.h"
#include "graphics/opengl.h"
#include "data/vertexData.h"
#include "lib/map/map.h"
#include <stdbool.h>
@ -12,21 +11,26 @@
typedef struct {
Buffer* buffer;
size_t offset;
size_t stride;
AttributeType type;
uint8_t components;
uint8_t divisor;
bool integer;
bool enabled;
uint32_t offset;
unsigned stride : 8;
unsigned divisor : 8;
unsigned type : 3; // AttributeType
unsigned components : 3;
unsigned normalized : 1;
unsigned integer : 1;
unsigned disabled : 1;
} MeshAttribute;
typedef map_t(MeshAttribute) map_attribute_t;
typedef struct {
Ref ref;
DrawMode mode;
VertexFormat format;
const char* attributeNames[MAX_ATTRIBUTES];
MeshAttribute attributes[MAX_ATTRIBUTES];
uint8_t locations[MAX_ATTRIBUTES];
uint16_t enabledLocations;
uint16_t divisors[MAX_ATTRIBUTES];
map_int_t attributeMap;
int attributeCount;
Buffer* vertexBuffer;
Buffer* indexBuffer;
uint32_t vertexCount;
@ -36,18 +40,12 @@ typedef struct {
uint32_t drawStart;
uint32_t drawCount;
Material* material;
map_attribute_t attributes;
MeshAttribute layout[MAX_ATTRIBUTES];
uint16_t divisors[MAX_ATTRIBUTES];
GPU_MESH_FIELDS
} Mesh;
Mesh* lovrMeshInit(Mesh* mesh, DrawMode mode, VertexFormat format, Buffer* vertexBuffer, uint32_t vertexCount);
Mesh* lovrMeshInitEmpty(Mesh* mesh, DrawMode drawMode);
Mesh* lovrMeshInit(Mesh* mesh, DrawMode mode, Buffer* vertexBuffer, uint32_t vertexCount);
#define lovrMeshCreate(...) lovrMeshInit(lovrAlloc(Mesh), __VA_ARGS__)
#define lovrMeshCreateEmpty(...) lovrMeshInitEmpty(lovrAlloc(Mesh), __VA_ARGS__)
void lovrMeshDestroy(void* ref);
VertexFormat* lovrMeshGetVertexFormat(Mesh* mesh);
Buffer* lovrMeshGetVertexBuffer(Mesh* mesh);
Buffer* lovrMeshGetIndexBuffer(Mesh* mesh);
void lovrMeshSetIndexBuffer(Mesh* mesh, Buffer* buffer, uint32_t indexCount, size_t indexSize, size_t offset);
@ -56,7 +54,7 @@ uint32_t lovrMeshGetIndexCount(Mesh* mesh);
size_t lovrMeshGetIndexSize(Mesh* mesh);
void lovrMeshAttachAttribute(Mesh* mesh, const char* name, MeshAttribute* attribute);
void lovrMeshDetachAttribute(Mesh* mesh, const char* name);
MeshAttribute* lovrMeshGetAttribute(Mesh* mesh, const char* name);
const MeshAttribute* lovrMeshGetAttribute(Mesh* mesh, const char* name);
bool lovrMeshIsAttributeEnabled(Mesh* mesh, const char* name);
void lovrMeshSetAttributeEnabled(Mesh* mesh, const char* name, bool enabled);
DrawMode lovrMeshGetDrawMode(Mesh* mesh);

View File

@ -80,7 +80,7 @@ Model* lovrModelInit(Model* model, ModelData* data) {
model->meshes = calloc(data->primitiveCount, sizeof(Mesh*));
for (int i = 0; i < data->primitiveCount; i++) {
ModelPrimitive* primitive = &data->primitives[i];
model->meshes[i] = lovrMeshCreateEmpty(primitive->mode);
model->meshes[i] = lovrMeshCreate(primitive->mode, NULL, 0);
bool setDrawRange = false;
for (int j = 0; j < MAX_DEFAULT_ATTRIBUTES; j++) {
@ -98,8 +98,7 @@ Model* lovrModelInit(Model* model, ModelData* data) {
.stride = data->buffers[attribute->buffer].stride,
.type = attribute->type,
.components = attribute->components,
.integer = j == ATTR_BONES,
.enabled = true
.integer = j == ATTR_BONES
});
if (!setDrawRange && !primitive->indices) {
@ -114,8 +113,7 @@ Model* lovrModelInit(Model* model, ModelData* data) {
.type = U8,
.components = 1,
.divisor = 1,
.integer = true,
.enabled = true
.integer = true
});
if (primitive->indices) {

View File

@ -479,19 +479,13 @@ static void lovrGpuBindImage(Image* image, int slot) {
}
#endif
static void lovrGpuBindMesh(Mesh* mesh, Shader* shader, int divisorMultiplier) {
const char* key;
map_iter_t iter = map_iter(&mesh->attachments);
MeshAttribute layout[MAX_ATTRIBUTES];
memset(layout, 0, MAX_ATTRIBUTES * sizeof(MeshAttribute));
static void lovrGpuBindMesh(Mesh* mesh, Shader* shader, int baseDivisor) {
lovrGpuBindVertexArray(mesh);
if (mesh->indexBuffer && mesh->indexCount > 0) {
lovrGpuBindBuffer(BUFFER_INDEX, mesh->indexBuffer->id);
lovrBufferFlush(mesh->indexBuffer);
#ifndef LOVR_GL
#ifdef LOVR_GL
uint32_t primitiveRestart = mesh->indexSize == 4 ? 0xffffffff : 0xffff;
if (state.primitiveRestart != primitiveRestart) {
state.primitiveRestart = primitiveRestart;
@ -500,68 +494,51 @@ static void lovrGpuBindMesh(Mesh* mesh, Shader* shader, int divisorMultiplier) {
#endif
}
while ((key = map_next(&mesh->attributes, &iter)) != NULL) {
int location = lovrShaderGetAttributeId(shader, key);
uint16_t enabledLocations = 0;
for (int i = 0; i < mesh->attributeCount; i++) {
MeshAttribute* attribute;
int location;
if (location >= 0) {
MeshAttribute* attribute = map_get(&mesh->attributes, key);
layout[location] = *attribute;
if ((attribute = &mesh->attributes[i])->disabled) { continue; }
if ((location = lovrShaderGetAttributeLocation(shader, mesh->attributeNames[i])) < 0) { continue; }
lovrBufferFlush(attribute->buffer);
enabledLocations |= (1 << location);
uint16_t divisor = attribute->divisor * baseDivisor;
if (mesh->divisors[location] != divisor) {
glVertexAttribDivisor(location, divisor);
mesh->divisors[location] = divisor;
}
if (mesh->locations[location] == i) { continue; }
mesh->locations[location] = i;
lovrGpuBindBuffer(BUFFER_VERTEX, attribute->buffer->id);
GLenum type = convertAttributeType(attribute->type);
GLvoid* offset = (GLvoid*) (intptr_t) attribute->offset;
if (attribute->integer) {
glVertexAttribIPointer(location, attribute->components, type, attribute->stride, offset);
} else {
glVertexAttribPointer(location, attribute->components, type, attribute->normalized, attribute->stride, offset);
}
}
for (int i = 0; i < MAX_ATTRIBUTES; i++) {
MeshAttribute previous = mesh->layout[i];
MeshAttribute current = layout[i];
if (current.enabled) {
lovrBufferFlush(current.buffer);
}
uint16_t divisor = current.divisor * divisorMultiplier;
if (!memcmp(&previous, &current, sizeof(MeshAttribute)) && mesh->divisors[i] == divisor) {
continue;
}
if (previous.enabled != current.enabled) {
if (current.enabled) {
glEnableVertexAttribArray(i);
} else {
glDisableVertexAttribArray(i);
mesh->layout[i] = current;
continue;
uint16_t diff = enabledLocations ^ mesh->enabledLocations;
if (diff != 0) {
for (int i = 0; i < MAX_ATTRIBUTES; i++) {
if (diff & (1 << i)) {
if (enabledLocations & (1 << i)) {
glEnableVertexAttribArray(i);
} else {
glDisableVertexAttribArray(i);
}
}
}
if (mesh->divisors[i] != divisor) {
glVertexAttribDivisor(i, divisor);
mesh->divisors[i] = divisor;
}
bool changed =
previous.buffer != current.buffer ||
previous.type != current.type ||
previous.components != current.components ||
previous.offset != current.offset ||
previous.stride != current.stride;
if (changed) {
lovrGpuBindBuffer(BUFFER_VERTEX, current.buffer->id);
int count = current.components;
int stride = current.stride;
GLvoid* offset = (GLvoid*) current.offset;
GLenum type = convertAttributeType(current.type);
// TODO
if (current.integer) {
glVertexAttribIPointer(i, count, type, stride, offset);
} else {
glVertexAttribPointer(i, count, type, GL_TRUE, stride, offset);
}
}
mesh->enabledLocations = enabledLocations;
}
memcpy(mesh->layout, layout, MAX_ATTRIBUTES * sizeof(MeshAttribute));
}
static void lovrGpuBindCanvas(Canvas* canvas, bool willDraw) {
@ -1962,34 +1939,14 @@ void lovrShaderDestroy(void* ref) {
// Mesh
Mesh* lovrMeshInit(Mesh* mesh, DrawMode mode, VertexFormat format, Buffer* vertexBuffer, uint32_t vertexCount) {
Mesh* lovrMeshInit(Mesh* mesh, DrawMode mode, Buffer* vertexBuffer, uint32_t vertexCount) {
mesh->mode = mode;
mesh->format = format;
mesh->vertexBuffer = vertexBuffer;
mesh->vertexCount = vertexCount;
lovrRetain(mesh->vertexBuffer);
glGenVertexArrays(1, &mesh->vao);
map_init(&mesh->attributes);
for (int i = 0; i < format.count; i++) {
lovrRetain(mesh->vertexBuffer);
map_set(&mesh->attributes, format.attributes[i].name, ((MeshAttribute) {
.buffer = mesh->vertexBuffer,
.offset = format.attributes[i].offset,
.stride = format.stride,
.type = format.attributes[i].type,
.components = format.attributes[i].count,
.enabled = true
}));
}
return mesh;
}
Mesh* lovrMeshInitEmpty(Mesh* mesh, DrawMode mode) {
mesh->mode = mode;
glGenVertexArrays(1, &mesh->vao);
map_init(&mesh->attributes);
map_init(&mesh->attributeMap);
memset(mesh->locations, 0xff, MAX_ATTRIBUTES * sizeof(uint8_t));
return mesh;
}
@ -1997,13 +1954,10 @@ void lovrMeshDestroy(void* ref) {
Mesh* mesh = ref;
lovrGraphicsFlushMesh(mesh);
glDeleteVertexArrays(1, &mesh->vao);
const char* key;
map_iter_t iter = map_iter(&mesh->attributes);
while ((key = map_next(&mesh->attributes, &iter)) != NULL) {
MeshAttribute* attribute = map_get(&mesh->attributes, key);
lovrRelease(attribute->buffer);
for (int i = 0; i < mesh->attributeCount; i++) {
lovrRelease(mesh->attributes[i].buffer);
}
map_deinit(&mesh->attributes);
map_deinit(&mesh->attributeMap);
lovrRelease(mesh->vertexBuffer);
lovrRelease(mesh->indexBuffer);
lovrRelease(mesh->material);

View File

@ -71,9 +71,9 @@ ShaderType lovrShaderGetType(Shader* shader) {
return shader->type;
}
int lovrShaderGetAttributeId(Shader* shader, const char* name) {
int* id = map_get(&shader->attributes, name);
return id ? *id : -1;
int lovrShaderGetAttributeLocation(Shader* shader, const char* name) {
int* location = map_get(&shader->attributes, name);
return location ? *location : -1;
}
bool lovrShaderHasUniform(Shader* shader, const char* name) {

View File

@ -114,7 +114,7 @@ Shader* lovrShaderInitDefault(Shader* shader, DefaultShader type);
#define lovrShaderCreateDefault(...) lovrShaderInitDefault(lovrAlloc(Shader), __VA_ARGS__)
void lovrShaderDestroy(void* ref);
ShaderType lovrShaderGetType(Shader* shader);
int lovrShaderGetAttributeId(Shader* shader, const char* name);
int lovrShaderGetAttributeLocation(Shader* shader, const char* name);
bool lovrShaderHasUniform(Shader* shader, const char* name);
const Uniform* lovrShaderGetUniform(Shader* shader, const char* name);
void lovrShaderSetFloats(Shader* shader, const char* name, float* data, int start, int count);