From a2e1fd8972974d231bfe5dd3cd40823cb7668d7e Mon Sep 17 00:00:00 2001 From: bjorn Date: Sat, 11 Mar 2017 14:13:49 -0800 Subject: [PATCH] Rename Buffer to Mesh; --- src/api/graphics.c | 172 +++++++++---------- src/api/lovr.h | 12 +- src/api/types/buffer.c | 371 ---------------------------------------- src/api/types/mesh.c | 371 ++++++++++++++++++++++++++++++++++++++++ src/graphics/buffer.c | 237 ------------------------- src/graphics/buffer.h | 73 -------- src/graphics/graphics.h | 2 +- src/graphics/mesh.c | 237 +++++++++++++++++++++++++ src/graphics/mesh.h | 73 ++++++++ src/graphics/model.c | 20 +-- src/graphics/model.h | 4 +- 11 files changed, 786 insertions(+), 786 deletions(-) delete mode 100644 src/api/types/buffer.c create mode 100644 src/api/types/mesh.c delete mode 100644 src/graphics/buffer.c delete mode 100644 src/graphics/buffer.h create mode 100644 src/graphics/mesh.c create mode 100644 src/graphics/mesh.h diff --git a/src/api/graphics.c b/src/api/graphics.c index 133b4979..a83285f2 100644 --- a/src/api/graphics.c +++ b/src/api/graphics.c @@ -6,9 +6,9 @@ #include "filesystem/filesystem.h" #include -map_int_t BufferAttributeTypes; -map_int_t BufferDrawModes; -map_int_t BufferUsages; +map_int_t MeshAttributeTypes; +map_int_t MeshDrawModes; +map_int_t MeshUsages; map_int_t CompareModes; map_int_t DrawModes; map_int_t FilterModes; @@ -64,28 +64,28 @@ static Texture* luax_readtexture(lua_State* L, int index) { int l_lovrGraphicsInit(lua_State* L) { lua_newtable(L); luaL_register(L, NULL, lovrGraphics); - luax_registertype(L, "Buffer", lovrBuffer); + luax_registertype(L, "Mesh", lovrMesh); luax_registertype(L, "Font", lovrFont); luax_registertype(L, "Model", lovrModel); luax_registertype(L, "Shader", lovrShader); luax_registertype(L, "Skybox", lovrSkybox); luax_registertype(L, "Texture", lovrTexture); - map_init(&BufferAttributeTypes); - map_set(&BufferAttributeTypes, "float", BUFFER_FLOAT); - map_set(&BufferAttributeTypes, "byte", BUFFER_BYTE); - map_set(&BufferAttributeTypes, "int", BUFFER_INT); + map_init(&MeshAttributeTypes); + map_set(&MeshAttributeTypes, "float", MESH_FLOAT); + map_set(&MeshAttributeTypes, "byte", MESH_BYTE); + map_set(&MeshAttributeTypes, "int", MESH_INT); - map_init(&BufferDrawModes); - map_set(&BufferDrawModes, "points", BUFFER_POINTS); - map_set(&BufferDrawModes, "strip", BUFFER_TRIANGLE_STRIP); - map_set(&BufferDrawModes, "triangles", BUFFER_TRIANGLES); - map_set(&BufferDrawModes, "fan", BUFFER_TRIANGLE_FAN); + map_init(&MeshDrawModes); + map_set(&MeshDrawModes, "points", MESH_POINTS); + map_set(&MeshDrawModes, "strip", MESH_TRIANGLE_STRIP); + map_set(&MeshDrawModes, "triangles", MESH_TRIANGLES); + map_set(&MeshDrawModes, "fan", MESH_TRIANGLE_FAN); - map_init(&BufferUsages); - map_set(&BufferUsages, "static", BUFFER_STATIC); - map_set(&BufferUsages, "dynamic", BUFFER_DYNAMIC); - map_set(&BufferUsages, "stream", BUFFER_STREAM); + map_init(&MeshUsages); + map_set(&MeshUsages, "static", MESH_STATIC); + map_set(&MeshUsages, "dynamic", MESH_DYNAMIC); + map_set(&MeshUsages, "stream", MESH_STREAM); map_init(&DrawModes); map_set(&DrawModes, "fill", DRAW_MODE_FILL); @@ -515,74 +515,6 @@ int l_lovrGraphicsPrint(lua_State* L) { // Types -int l_lovrGraphicsNewBuffer(lua_State* L) { - int size; - int dataIndex = 0; - int drawModeIndex = 2; - BufferFormat format; - vec_init(&format); - - if (lua_isnumber(L, 1)) { - size = lua_tointeger(L, 1); - } else if (lua_istable(L, 1)) { - if (lua_isnumber(L, 2)) { - drawModeIndex++; - luax_checkbufferformat(L, 1, &format); - size = lua_tointeger(L, 2); - dataIndex = 0; - } else if (lua_istable(L, 2)) { - drawModeIndex++; - luax_checkbufferformat(L, 1, &format); - size = lua_objlen(L, 2); - dataIndex = 2; - } else { - size = lua_objlen(L, 1); - dataIndex = 1; - } - } else { - luaL_argerror(L, 1, "table or number expected"); - return 0; - } - - BufferDrawMode* drawMode = (BufferDrawMode*) luax_optenum(L, drawModeIndex, "fan", &BufferDrawModes, "buffer draw mode"); - BufferUsage* usage = (BufferUsage*) luax_optenum(L, drawModeIndex + 1, "dynamic", &BufferUsages, "buffer usage"); - Buffer* buffer = lovrBufferCreate(size, format.length ? &format : NULL, *drawMode, *usage); - - if (dataIndex) { - BufferFormat format = lovrBufferGetVertexFormat(buffer); - for (size_t i = 0; i < lua_objlen(L, dataIndex); i++) { - lua_rawgeti(L, dataIndex, i + 1); - if (!lua_istable(L, -1)) { - return luaL_error(L, "Vertex information should be specified as a table"); - } - - int component = 0; - char* vertex = lovrBufferGetScratchVertex(buffer); - for (int j = 0; j < format.length; j++) { - BufferAttribute attribute = format.data[j]; - for (int k = 0; k < attribute.count; k++) { - lua_rawgeti(L, -1, ++component); - switch (attribute.type) { - case BUFFER_FLOAT: *((float*) vertex) = luaL_optnumber(L, -1, 0.f); break; - case BUFFER_BYTE: *((unsigned char*) vertex) = luaL_optint(L, -1, 255); break; - case BUFFER_INT: *((int*) vertex) = luaL_optint(L, -1, 0); break; - } - vertex += sizeof(attribute.type); - lua_pop(L, 1); - } - } - - lovrBufferSetVertex(buffer, i, lovrBufferGetScratchVertex(buffer)); - lua_pop(L, 1); - } - } - - vec_deinit(&format); - luax_pushtype(L, Buffer, buffer); - lovrRelease(&buffer->ref); - return 1; -} - int l_lovrGraphicsNewFont(lua_State* L) { void* data = NULL; size_t size = 0; @@ -609,6 +541,74 @@ int l_lovrGraphicsNewFont(lua_State* L) { return 1; } +int l_lovrGraphicsNewMesh(lua_State* L) { + int size; + int dataIndex = 0; + int drawModeIndex = 2; + MeshFormat format; + vec_init(&format); + + if (lua_isnumber(L, 1)) { + size = lua_tointeger(L, 1); + } else if (lua_istable(L, 1)) { + if (lua_isnumber(L, 2)) { + drawModeIndex++; + luax_checkmeshformat(L, 1, &format); + size = lua_tointeger(L, 2); + dataIndex = 0; + } else if (lua_istable(L, 2)) { + drawModeIndex++; + luax_checkmeshformat(L, 1, &format); + size = lua_objlen(L, 2); + dataIndex = 2; + } else { + size = lua_objlen(L, 1); + dataIndex = 1; + } + } else { + luaL_argerror(L, 1, "table or number expected"); + return 0; + } + + MeshDrawMode* drawMode = (MeshDrawMode*) luax_optenum(L, drawModeIndex, "fan", &MeshDrawModes, "mesh draw mode"); + MeshUsage* usage = (MeshUsage*) luax_optenum(L, drawModeIndex + 1, "dynamic", &MeshUsages, "mesh usage"); + Mesh* mesh = lovrMeshCreate(size, format.length ? &format : NULL, *drawMode, *usage); + + if (dataIndex) { + MeshFormat format = lovrMeshGetVertexFormat(mesh); + for (size_t i = 0; i < lua_objlen(L, dataIndex); i++) { + lua_rawgeti(L, dataIndex, i + 1); + if (!lua_istable(L, -1)) { + return luaL_error(L, "Vertex information should be specified as a table"); + } + + int component = 0; + char* vertex = lovrMeshGetScratchVertex(mesh); + for (int j = 0; j < format.length; j++) { + MeshAttribute attribute = format.data[j]; + for (int k = 0; k < attribute.count; k++) { + lua_rawgeti(L, -1, ++component); + switch (attribute.type) { + case MESH_FLOAT: *((float*) vertex) = luaL_optnumber(L, -1, 0.f); break; + case MESH_BYTE: *((unsigned char*) vertex) = luaL_optint(L, -1, 255); break; + case MESH_INT: *((int*) vertex) = luaL_optint(L, -1, 0); break; + } + vertex += sizeof(attribute.type); + lua_pop(L, 1); + } + } + + lovrMeshSetVertex(mesh, i, lovrMeshGetScratchVertex(mesh)); + lua_pop(L, 1); + } + } + + vec_deinit(&format); + luax_pushtype(L, Mesh, mesh); + lovrRelease(&mesh->ref); + return 1; +} + int l_lovrGraphicsNewModel(lua_State* L) { const char* path = lua_tostring(L, 1); size_t size; @@ -757,8 +757,8 @@ const luaL_Reg lovrGraphics[] = { { "getWidth", l_lovrGraphicsGetWidth }, { "getHeight", l_lovrGraphicsGetHeight }, { "getDimensions", l_lovrGraphicsGetDimensions }, - { "newBuffer", l_lovrGraphicsNewBuffer }, { "newFont", l_lovrGraphicsNewFont }, + { "newMesh", l_lovrGraphicsNewMesh }, { "newModel", l_lovrGraphicsNewModel }, { "newShader", l_lovrGraphicsNewShader }, { "newSkybox", l_lovrGraphicsNewSkybox }, diff --git a/src/api/lovr.h b/src/api/lovr.h index 77b94fdd..5fb5681b 100644 --- a/src/api/lovr.h +++ b/src/api/lovr.h @@ -1,5 +1,5 @@ #include "luax.h" -#include "graphics/buffer.h" +#include "graphics/mesh.h" #include "math/math.h" #include "lib/map/map.h" @@ -12,7 +12,6 @@ int l_lovrMathInit(lua_State* L); int l_lovrTimerInit(lua_State* L); extern const luaL_Reg lovrAudio[]; -extern const luaL_Reg lovrBuffer[]; extern const luaL_Reg lovrController[]; extern const luaL_Reg lovrEvent[]; extern const luaL_Reg lovrFilesystem[]; @@ -20,6 +19,7 @@ extern const luaL_Reg lovrFont[]; extern const luaL_Reg lovrGraphics[]; extern const luaL_Reg lovrHeadset[]; extern const luaL_Reg lovrMath[]; +extern const luaL_Reg lovrMesh[]; extern const luaL_Reg lovrModel[]; extern const luaL_Reg lovrShader[]; extern const luaL_Reg lovrSkybox[]; @@ -28,9 +28,9 @@ extern const luaL_Reg lovrTexture[]; extern const luaL_Reg lovrTimer[]; extern const luaL_Reg lovrTransform[]; -extern map_int_t BufferAttributeTypes; -extern map_int_t BufferDrawModes; -extern map_int_t BufferUsages; +extern map_int_t MeshAttributeTypes; +extern map_int_t MeshDrawModes; +extern map_int_t MeshUsages; extern map_int_t CompareModes; extern map_int_t ControllerAxes; extern map_int_t ControllerButtons; @@ -43,5 +43,5 @@ extern map_int_t TextureProjections; extern map_int_t TimeUnits; extern map_int_t WrapModes; -void luax_checkbufferformat(lua_State* L, int index, BufferFormat* format); +void luax_checkmeshformat(lua_State* L, int index, MeshFormat* format); void luax_readtransform(lua_State* L, int i, mat4 transform); diff --git a/src/api/types/buffer.c b/src/api/types/buffer.c deleted file mode 100644 index df6f9b14..00000000 --- a/src/api/types/buffer.c +++ /dev/null @@ -1,371 +0,0 @@ -#include "api/lovr.h" - -void luax_checkbufferformat(lua_State* L, int index, BufferFormat* format) { - if (!lua_istable(L, index)) { - return; - } - - int length = lua_objlen(L, index); - 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; - } - - lua_rawgeti(L, -1, 1); - lua_rawgeti(L, -2, 2); - lua_rawgeti(L, -3, 3); - - const char* name = lua_tostring(L, -3); - BufferAttributeType* type = (BufferAttributeType*) luax_checkenum(L, -2, &BufferAttributeTypes, "buffer attribute type"); - int count = lua_tointeger(L, -1); - BufferAttribute attribute = { .name = name, .type = *type, .count = count }; - vec_push(format, attribute); - lua_pop(L, 4); - } -} - -int l_lovrBufferDraw(lua_State* L) { - Buffer* buffer = luax_checktype(L, 1, Buffer); - float transform[16]; - luax_readtransform(L, 2, transform); - lovrBufferDraw(buffer, transform); - return 0; -} - -int l_lovrBufferGetVertexFormat(lua_State* L) { - Buffer* buffer = luax_checktype(L, 1, Buffer); - BufferFormat format = lovrBufferGetVertexFormat(buffer); - lua_newtable(L); - for (int i = 0; i < format.length; i++) { - BufferAttribute attribute = format.data[i]; - lua_newtable(L); - - // Name - lua_pushstring(L, attribute.name); - lua_rawseti(L, -2, 1); - - // Type - luax_pushenum(L, &BufferAttributeTypes, 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 l_lovrBufferGetDrawMode(lua_State* L) { - Buffer* buffer = luax_checktype(L, 1, Buffer); - luax_pushenum(L, &BufferDrawModes, lovrBufferGetDrawMode(buffer)); - return 1; -} - -int l_lovrBufferSetDrawMode(lua_State* L) { - Buffer* buffer = luax_checktype(L, 1, Buffer); - BufferDrawMode* drawMode = (BufferDrawMode*) luax_checkenum(L, 2, &BufferDrawModes, "buffer draw mode"); - lovrBufferSetDrawMode(buffer, *drawMode); - return 0; -} - -int l_lovrBufferGetVertexCount(lua_State* L) { - Buffer* buffer = luax_checktype(L, 1, Buffer); - lua_pushnumber(L, lovrBufferGetVertexCount(buffer)); - return 1; -} - -int l_lovrBufferGetVertex(lua_State* L) { - Buffer* buffer = luax_checktype(L, 1, Buffer); - int index = luaL_checkint(L, 2) - 1; - char* vertex = lovrBufferGetScratchVertex(buffer); - lovrBufferGetVertex(buffer, index, vertex); - BufferFormat format = lovrBufferGetVertexFormat(buffer); - - int total = 0; - for (int i = 0; i < format.length; i++) { - BufferAttribute attribute = format.data[i]; - total += attribute.count; - for (int j = 0; j < attribute.count; j++) { - switch (attribute.type) { - case BUFFER_FLOAT: lua_pushnumber(L, *((float*) vertex)); break; - case BUFFER_BYTE: lua_pushnumber(L, *((unsigned char*) vertex)); break; - case BUFFER_INT: lua_pushnumber(L, *((int*) vertex)); break; - } - - vertex += sizeof(attribute.type); - } - } - - return total; -} - -int l_lovrBufferSetVertex(lua_State* L) { - Buffer* buffer = luax_checktype(L, 1, Buffer); - int index = luaL_checkint(L, 2) - 1; - BufferFormat format = lovrBufferGetVertexFormat(buffer); - char* vertex = lovrBufferGetScratchVertex(buffer); - - if (index < 0 || index >= buffer->size) { - return luaL_error(L, "Invalid buffer vertex index: %d", index + 1); - } - - // Unwrap table - int arg = 3; - if (lua_istable(L, 3)) { - arg++; - for (size_t i = 0; i < lua_objlen(L, 3); i++) { - lua_rawgeti(L, 3, i + 1); - } - } - - for (int i = 0; i < format.length; i++) { - BufferAttribute attribute = format.data[i]; - for (int j = 0; j < attribute.count; j++) { - switch (attribute.type) { - case BUFFER_FLOAT: *((float*) vertex) = luaL_optnumber(L, arg++, 0.f); break; - case BUFFER_BYTE: *((unsigned char*) vertex) = luaL_optint(L, arg++, 255); break; - case BUFFER_INT: *((int*) vertex) = luaL_optint(L, arg++, 0); break; - } - - vertex += sizeof(attribute.type); - } - } - - lovrBufferSetVertex(buffer, index, lovrBufferGetScratchVertex(buffer)); - return 0; -} - -int l_lovrBufferGetVertexAttribute(lua_State* L) { - Buffer* buffer = luax_checktype(L, 1, Buffer); - int vertexIndex = luaL_checkint(L, 2) - 1; - int attributeIndex = luaL_checkint(L, 3) - 1; - char* vertex = lovrBufferGetScratchVertex(buffer); - lovrBufferGetVertex(buffer, vertexIndex, vertex); - BufferFormat format = lovrBufferGetVertexFormat(buffer); - - if (vertexIndex < 0 || vertexIndex >= buffer->size) { - return luaL_error(L, "Invalid buffer vertex index: %d", vertexIndex + 1); - } else if (attributeIndex < 0 || attributeIndex >= format.length) { - return luaL_error(L, "Invalid buffer attribute index: %d", attributeIndex + 1); - } - - BufferAttribute attribute; - for (int i = 0; i <= attributeIndex; i++) { - attribute = format.data[i]; - if (i == attributeIndex) { - for (int j = 0; j < attribute.count; j++) { - switch (attribute.type) { - case BUFFER_FLOAT: lua_pushnumber(L, *((float*) vertex)); break; - case BUFFER_BYTE: lua_pushinteger(L, *((unsigned char*) vertex)); break; - case BUFFER_INT: lua_pushinteger(L, *((int*) vertex)); break; - } - vertex += sizeof(attribute.type); - } - } else { - vertex += attribute.count * sizeof(attribute.type); - } - } - - return attribute.count; -} - -int l_lovrBufferSetVertexAttribute(lua_State* L) { - Buffer* buffer = luax_checktype(L, 1, Buffer); - int vertexIndex = luaL_checkint(L, 2) - 1; - int attributeIndex = luaL_checkint(L, 3) - 1; - char* vertex = lovrBufferGetScratchVertex(buffer); - lovrBufferGetVertex(buffer, vertexIndex, vertex); - BufferFormat format = lovrBufferGetVertexFormat(buffer); - - if (vertexIndex < 0 || vertexIndex >= buffer->size) { - return luaL_error(L, "Invalid buffer vertex index: %d", vertexIndex + 1); - } else if (attributeIndex < 0 || attributeIndex >= format.length) { - return luaL_error(L, "Invalid buffer attribute index: %d", attributeIndex + 1); - } - - int arg = 4; - for (int i = 0; i <= attributeIndex; i++) { - BufferAttribute attribute = format.data[i]; - if (i == attributeIndex) { - for (int j = 0; j < attribute.count; j++) { - switch (attribute.type) { - case BUFFER_FLOAT: *((float*) vertex) = luaL_optnumber(L, arg++, 0.f); break; - case BUFFER_BYTE: *((unsigned char*) vertex) = luaL_optint(L, arg++, 255); break; - case BUFFER_INT: *((int*) vertex) = luaL_optint(L, arg++, 0); break; - } - vertex += sizeof(attribute.type); - } - } else { - vertex += attribute.count * sizeof(attribute.type); - } - } - - lovrBufferSetVertex(buffer, vertexIndex, lovrBufferGetScratchVertex(buffer)); - return 0; -} - -int l_lovrBufferSetVertices(lua_State* L) { - Buffer* buffer = luax_checktype(L, 1, Buffer); - BufferFormat format = lovrBufferGetVertexFormat(buffer); - luaL_checktype(L, 2, LUA_TTABLE); - int vertexCount = lua_objlen(L, 2); - - if (vertexCount > lovrBufferGetVertexCount(buffer)) { - return luaL_error(L, "Too many vertices for Buffer\n", lovrBufferGetVertexCount(buffer)); - } - - char* vertices = malloc(buffer->stride * vertexCount); - char* vertex = vertices; - - for (int i = 0; i < vertexCount; i++) { - lua_rawgeti(L, 2, i + 1); - int component = 0; - for (int j = 0; j < format.length; j++) { - BufferAttribute attribute = format.data[j]; - for (int k = 0; k < attribute.count; k++) { - lua_rawgeti(L, -1, ++component); - switch (attribute.type) { - case BUFFER_FLOAT: *((float*) vertex) = luaL_optnumber(L, -1, 0.f); break; - case BUFFER_BYTE: *((unsigned char*) vertex) = luaL_optint(L, -1, 255); break; - case BUFFER_INT: *((int*) vertex) = luaL_optint(L, -1, 0); break; - } - vertex += sizeof(attribute.type); - lua_pop(L, 1); - } - } - lua_pop(L, 1); - } - - lovrBufferSetVertices(buffer, vertices, buffer->stride * vertexCount); - free(vertices); - return 0; -} - -int l_lovrBufferGetVertexMap(lua_State* L) { - Buffer* buffer = luax_checktype(L, 1, Buffer); - int count; - unsigned int* indices = lovrBufferGetVertexMap(buffer, &count); - - if (count == 0) { - lua_pushnil(L); - return 1; - } - - lua_newtable(L); - for (int i = 0; i < count; i++) { - lua_pushinteger(L, indices[i]); - lua_rawseti(L, -2, i + 1); - } - - return 1; -} - -int l_lovrBufferSetVertexMap(lua_State* L) { - Buffer* buffer = luax_checktype(L, 1, Buffer); - - if (lua_isnoneornil(L, 2)) { - lovrBufferSetVertexMap(buffer, NULL, 0); - return 0; - } - - luaL_checktype(L, 2, LUA_TTABLE); - int count = lua_objlen(L, 2); - unsigned int* indices = malloc(count * sizeof(unsigned int)); - - for (int i = 0; i < count; i++) { - lua_rawgeti(L, 2, i + 1); - if (!lua_isnumber(L, -1)) { - free(indices); - return luaL_error(L, "Buffer vertex map index #%d must be numeric", i); - } - - int index = lua_tointeger(L, -1); - if (index > buffer->size || index < 0) { - free(indices); - return luaL_error(L, "Invalid vertex map value: %d", index); - } - - indices[i] = index - 1; - lua_pop(L, 1); - } - - lovrBufferSetVertexMap(buffer, indices, count); - free(indices); - return 0; -} - -int l_lovrBufferGetDrawRange(lua_State* L) { - Buffer* buffer = luax_checktype(L, 1, Buffer); - if (!lovrBufferIsRangeEnabled(buffer)) { - lua_pushnil(L); - return 1; - } - - int start, count; - lovrBufferGetDrawRange(buffer, &start, &count); - lua_pushinteger(L, start + 1); - lua_pushinteger(L, count); - return 2; -} - -int l_lovrBufferSetDrawRange(lua_State* L) { - Buffer* buffer = luax_checktype(L, 1, Buffer); - if (lua_isnoneornil(L, 2)) { - lovrBufferSetRangeEnabled(buffer, 0); - return 0; - } - - lovrBufferSetRangeEnabled(buffer, 1); - int rangeStart = luaL_checkinteger(L, 2) - 1; - int rangeCount = luaL_checkinteger(L, 3); - if (lovrBufferSetDrawRange(buffer, rangeStart, rangeCount)) { - return luaL_error(L, "Invalid buffer draw range (%d, %d)", rangeStart + 1, rangeCount); - } - - return 0; -} - -int l_lovrBufferGetTexture(lua_State* L) { - Buffer* buffer = luax_checktype(L, 1, Buffer); - Texture* texture = lovrBufferGetTexture(buffer); - - if (texture) { - luax_pushtype(L, Texture, texture); - } else { - lua_pushnil(L); - } - - return 1; -} - -int l_lovrBufferSetTexture(lua_State* L) { - Buffer* buffer = luax_checktype(L, 1, Buffer); - Texture* texture = lua_isnoneornil(L, 2) ? NULL : luax_checktype(L, 2, Texture); - lovrBufferSetTexture(buffer, texture); - return 0; -} - -const luaL_Reg lovrBuffer[] = { - { "draw", l_lovrBufferDraw }, - { "getVertexFormat", l_lovrBufferGetVertexFormat }, - { "getVertexCount", l_lovrBufferGetVertexCount }, - { "getVertex", l_lovrBufferGetVertex }, - { "setVertex", l_lovrBufferSetVertex }, - { "getVertexAttribute", l_lovrBufferGetVertexAttribute }, - { "setVertexAttribute", l_lovrBufferSetVertexAttribute }, - { "setVertices", l_lovrBufferSetVertices }, - { "getVertexMap", l_lovrBufferGetVertexMap }, - { "setVertexMap", l_lovrBufferSetVertexMap }, - { "getDrawMode", l_lovrBufferGetDrawMode }, - { "setDrawMode", l_lovrBufferSetDrawMode }, - { "getDrawRange", l_lovrBufferGetDrawRange }, - { "setDrawRange", l_lovrBufferSetDrawRange }, - { "getTexture", l_lovrBufferGetTexture }, - { "setTexture", l_lovrBufferSetTexture }, - { NULL, NULL } -}; diff --git a/src/api/types/mesh.c b/src/api/types/mesh.c new file mode 100644 index 00000000..71fe0922 --- /dev/null +++ b/src/api/types/mesh.c @@ -0,0 +1,371 @@ +#include "api/lovr.h" + +void luax_checkmeshformat(lua_State* L, int index, MeshFormat* format) { + if (!lua_istable(L, index)) { + return; + } + + int length = lua_objlen(L, index); + 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; + } + + lua_rawgeti(L, -1, 1); + lua_rawgeti(L, -2, 2); + lua_rawgeti(L, -3, 3); + + const char* name = lua_tostring(L, -3); + MeshAttributeType* type = (MeshAttributeType*) luax_checkenum(L, -2, &MeshAttributeTypes, "mesh attribute type"); + int count = lua_tointeger(L, -1); + MeshAttribute attribute = { .name = name, .type = *type, .count = count }; + vec_push(format, attribute); + lua_pop(L, 4); + } +} + +int l_lovrMeshDraw(lua_State* L) { + Mesh* mesh = luax_checktype(L, 1, Mesh); + float transform[16]; + luax_readtransform(L, 2, transform); + lovrMeshDraw(mesh, transform); + return 0; +} + +int l_lovrMeshGetVertexFormat(lua_State* L) { + Mesh* mesh = luax_checktype(L, 1, Mesh); + MeshFormat format = lovrMeshGetVertexFormat(mesh); + lua_newtable(L); + for (int i = 0; i < format.length; i++) { + MeshAttribute attribute = format.data[i]; + lua_newtable(L); + + // Name + lua_pushstring(L, attribute.name); + lua_rawseti(L, -2, 1); + + // Type + luax_pushenum(L, &MeshAttributeTypes, 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 l_lovrMeshGetDrawMode(lua_State* L) { + Mesh* mesh = luax_checktype(L, 1, Mesh); + luax_pushenum(L, &MeshDrawModes, lovrMeshGetDrawMode(mesh)); + return 1; +} + +int l_lovrMeshSetDrawMode(lua_State* L) { + Mesh* mesh = luax_checktype(L, 1, Mesh); + MeshDrawMode* drawMode = (MeshDrawMode*) luax_checkenum(L, 2, &MeshDrawModes, "mesh draw mode"); + lovrMeshSetDrawMode(mesh, *drawMode); + return 0; +} + +int l_lovrMeshGetVertexCount(lua_State* L) { + Mesh* mesh = luax_checktype(L, 1, Mesh); + lua_pushnumber(L, lovrMeshGetVertexCount(mesh)); + return 1; +} + +int l_lovrMeshGetVertex(lua_State* L) { + Mesh* mesh = luax_checktype(L, 1, Mesh); + int index = luaL_checkint(L, 2) - 1; + char* vertex = lovrMeshGetScratchVertex(mesh); + lovrMeshGetVertex(mesh, index, vertex); + MeshFormat format = lovrMeshGetVertexFormat(mesh); + + int total = 0; + for (int i = 0; i < format.length; i++) { + MeshAttribute attribute = format.data[i]; + total += attribute.count; + for (int j = 0; j < attribute.count; j++) { + switch (attribute.type) { + case MESH_FLOAT: lua_pushnumber(L, *((float*) vertex)); break; + case MESH_BYTE: lua_pushnumber(L, *((unsigned char*) vertex)); break; + case MESH_INT: lua_pushnumber(L, *((int*) vertex)); break; + } + + vertex += sizeof(attribute.type); + } + } + + return total; +} + +int l_lovrMeshSetVertex(lua_State* L) { + Mesh* mesh = luax_checktype(L, 1, Mesh); + int index = luaL_checkint(L, 2) - 1; + MeshFormat format = lovrMeshGetVertexFormat(mesh); + char* vertex = lovrMeshGetScratchVertex(mesh); + + if (index < 0 || index >= mesh->size) { + return luaL_error(L, "Invalid mesh vertex index: %d", index + 1); + } + + // Unwrap table + int arg = 3; + if (lua_istable(L, 3)) { + arg++; + for (size_t i = 0; i < lua_objlen(L, 3); i++) { + lua_rawgeti(L, 3, i + 1); + } + } + + for (int i = 0; i < format.length; i++) { + MeshAttribute attribute = format.data[i]; + for (int j = 0; j < attribute.count; j++) { + switch (attribute.type) { + case MESH_FLOAT: *((float*) vertex) = luaL_optnumber(L, arg++, 0.f); break; + case MESH_BYTE: *((unsigned char*) vertex) = luaL_optint(L, arg++, 255); break; + case MESH_INT: *((int*) vertex) = luaL_optint(L, arg++, 0); break; + } + + vertex += sizeof(attribute.type); + } + } + + lovrMeshSetVertex(mesh, index, lovrMeshGetScratchVertex(mesh)); + return 0; +} + +int l_lovrMeshGetVertexAttribute(lua_State* L) { + Mesh* mesh = luax_checktype(L, 1, Mesh); + int vertexIndex = luaL_checkint(L, 2) - 1; + int attributeIndex = luaL_checkint(L, 3) - 1; + char* vertex = lovrMeshGetScratchVertex(mesh); + lovrMeshGetVertex(mesh, vertexIndex, vertex); + MeshFormat format = lovrMeshGetVertexFormat(mesh); + + if (vertexIndex < 0 || vertexIndex >= mesh->size) { + return luaL_error(L, "Invalid mesh vertex index: %d", vertexIndex + 1); + } else if (attributeIndex < 0 || attributeIndex >= format.length) { + return luaL_error(L, "Invalid mesh attribute index: %d", attributeIndex + 1); + } + + MeshAttribute attribute; + for (int i = 0; i <= attributeIndex; i++) { + attribute = format.data[i]; + if (i == attributeIndex) { + for (int j = 0; j < attribute.count; j++) { + switch (attribute.type) { + case MESH_FLOAT: lua_pushnumber(L, *((float*) vertex)); break; + case MESH_BYTE: lua_pushinteger(L, *((unsigned char*) vertex)); break; + case MESH_INT: lua_pushinteger(L, *((int*) vertex)); break; + } + vertex += sizeof(attribute.type); + } + } else { + vertex += attribute.count * sizeof(attribute.type); + } + } + + return attribute.count; +} + +int l_lovrMeshSetVertexAttribute(lua_State* L) { + Mesh* mesh = luax_checktype(L, 1, Mesh); + int vertexIndex = luaL_checkint(L, 2) - 1; + int attributeIndex = luaL_checkint(L, 3) - 1; + char* vertex = lovrMeshGetScratchVertex(mesh); + lovrMeshGetVertex(mesh, vertexIndex, vertex); + MeshFormat format = lovrMeshGetVertexFormat(mesh); + + if (vertexIndex < 0 || vertexIndex >= mesh->size) { + return luaL_error(L, "Invalid mesh vertex index: %d", vertexIndex + 1); + } else if (attributeIndex < 0 || attributeIndex >= format.length) { + return luaL_error(L, "Invalid mesh attribute index: %d", attributeIndex + 1); + } + + int arg = 4; + for (int i = 0; i <= attributeIndex; i++) { + MeshAttribute attribute = format.data[i]; + if (i == attributeIndex) { + for (int j = 0; j < attribute.count; j++) { + switch (attribute.type) { + case MESH_FLOAT: *((float*) vertex) = luaL_optnumber(L, arg++, 0.f); break; + case MESH_BYTE: *((unsigned char*) vertex) = luaL_optint(L, arg++, 255); break; + case MESH_INT: *((int*) vertex) = luaL_optint(L, arg++, 0); break; + } + vertex += sizeof(attribute.type); + } + } else { + vertex += attribute.count * sizeof(attribute.type); + } + } + + lovrMeshSetVertex(mesh, vertexIndex, lovrMeshGetScratchVertex(mesh)); + return 0; +} + +int l_lovrMeshSetVertices(lua_State* L) { + Mesh* mesh = luax_checktype(L, 1, Mesh); + MeshFormat format = lovrMeshGetVertexFormat(mesh); + luaL_checktype(L, 2, LUA_TTABLE); + int vertexCount = lua_objlen(L, 2); + + if (vertexCount > lovrMeshGetVertexCount(mesh)) { + return luaL_error(L, "Too many vertices for Mesh\n", lovrMeshGetVertexCount(mesh)); + } + + char* vertices = malloc(mesh->stride * vertexCount); + char* vertex = vertices; + + for (int i = 0; i < vertexCount; i++) { + lua_rawgeti(L, 2, i + 1); + int component = 0; + for (int j = 0; j < format.length; j++) { + MeshAttribute attribute = format.data[j]; + for (int k = 0; k < attribute.count; k++) { + lua_rawgeti(L, -1, ++component); + switch (attribute.type) { + case MESH_FLOAT: *((float*) vertex) = luaL_optnumber(L, -1, 0.f); break; + case MESH_BYTE: *((unsigned char*) vertex) = luaL_optint(L, -1, 255); break; + case MESH_INT: *((int*) vertex) = luaL_optint(L, -1, 0); break; + } + vertex += sizeof(attribute.type); + lua_pop(L, 1); + } + } + lua_pop(L, 1); + } + + lovrMeshSetVertices(mesh, vertices, mesh->stride * vertexCount); + free(vertices); + return 0; +} + +int l_lovrMeshGetVertexMap(lua_State* L) { + Mesh* mesh = luax_checktype(L, 1, Mesh); + int count; + unsigned int* indices = lovrMeshGetVertexMap(mesh, &count); + + if (count == 0) { + lua_pushnil(L); + return 1; + } + + lua_newtable(L); + for (int i = 0; i < count; i++) { + lua_pushinteger(L, indices[i]); + lua_rawseti(L, -2, i + 1); + } + + return 1; +} + +int l_lovrMeshSetVertexMap(lua_State* L) { + Mesh* mesh = luax_checktype(L, 1, Mesh); + + if (lua_isnoneornil(L, 2)) { + lovrMeshSetVertexMap(mesh, NULL, 0); + return 0; + } + + luaL_checktype(L, 2, LUA_TTABLE); + int count = lua_objlen(L, 2); + unsigned int* indices = malloc(count * sizeof(unsigned int)); + + for (int i = 0; i < count; i++) { + lua_rawgeti(L, 2, i + 1); + if (!lua_isnumber(L, -1)) { + free(indices); + return luaL_error(L, "Mesh vertex map index #%d must be numeric", i); + } + + int index = lua_tointeger(L, -1); + if (index > mesh->size || index < 0) { + free(indices); + return luaL_error(L, "Invalid vertex map value: %d", index); + } + + indices[i] = index - 1; + lua_pop(L, 1); + } + + lovrMeshSetVertexMap(mesh, indices, count); + free(indices); + return 0; +} + +int l_lovrMeshGetDrawRange(lua_State* L) { + Mesh* mesh = luax_checktype(L, 1, Mesh); + if (!lovrMeshIsRangeEnabled(mesh)) { + lua_pushnil(L); + return 1; + } + + int start, count; + lovrMeshGetDrawRange(mesh, &start, &count); + lua_pushinteger(L, start + 1); + lua_pushinteger(L, count); + return 2; +} + +int l_lovrMeshSetDrawRange(lua_State* L) { + Mesh* mesh = luax_checktype(L, 1, Mesh); + if (lua_isnoneornil(L, 2)) { + lovrMeshSetRangeEnabled(mesh, 0); + return 0; + } + + lovrMeshSetRangeEnabled(mesh, 1); + int rangeStart = luaL_checkinteger(L, 2) - 1; + int rangeCount = luaL_checkinteger(L, 3); + if (lovrMeshSetDrawRange(mesh, rangeStart, rangeCount)) { + return luaL_error(L, "Invalid mesh draw range (%d, %d)", rangeStart + 1, rangeCount); + } + + return 0; +} + +int l_lovrMeshGetTexture(lua_State* L) { + Mesh* mesh = luax_checktype(L, 1, Mesh); + Texture* texture = lovrMeshGetTexture(mesh); + + if (texture) { + luax_pushtype(L, Texture, texture); + } else { + lua_pushnil(L); + } + + return 1; +} + +int l_lovrMeshSetTexture(lua_State* L) { + Mesh* mesh = luax_checktype(L, 1, Mesh); + Texture* texture = lua_isnoneornil(L, 2) ? NULL : luax_checktype(L, 2, Texture); + lovrMeshSetTexture(mesh, texture); + return 0; +} + +const luaL_Reg lovrMesh[] = { + { "draw", l_lovrMeshDraw }, + { "getVertexFormat", l_lovrMeshGetVertexFormat }, + { "getVertexCount", l_lovrMeshGetVertexCount }, + { "getVertex", l_lovrMeshGetVertex }, + { "setVertex", l_lovrMeshSetVertex }, + { "getVertexAttribute", l_lovrMeshGetVertexAttribute }, + { "setVertexAttribute", l_lovrMeshSetVertexAttribute }, + { "setVertices", l_lovrMeshSetVertices }, + { "getVertexMap", l_lovrMeshGetVertexMap }, + { "setVertexMap", l_lovrMeshSetVertexMap }, + { "getDrawMode", l_lovrMeshGetDrawMode }, + { "setDrawMode", l_lovrMeshSetDrawMode }, + { "getDrawRange", l_lovrMeshGetDrawRange }, + { "setDrawRange", l_lovrMeshSetDrawRange }, + { "getTexture", l_lovrMeshGetTexture }, + { "setTexture", l_lovrMeshSetTexture }, + { NULL, NULL } +}; diff --git a/src/graphics/buffer.c b/src/graphics/buffer.c deleted file mode 100644 index 695dfa61..00000000 --- a/src/graphics/buffer.c +++ /dev/null @@ -1,237 +0,0 @@ -#include "graphics/buffer.h" -#include "graphics/graphics.h" -#include "graphics/shader.h" -#include - -Buffer* lovrBufferCreate(int size, BufferFormat* format, BufferDrawMode drawMode, BufferUsage usage) { - Buffer* buffer = lovrAlloc(sizeof(Buffer), lovrBufferDestroy); - if (!buffer) return NULL; - - vec_init(&buffer->map); - vec_init(&buffer->format); - - if (format) { - vec_extend(&buffer->format, format); - } else { - BufferAttribute position = { .name = "lovrPosition", .type = BUFFER_FLOAT, .count = 3 }; - BufferAttribute normal = { .name = "lovrNormal", .type = BUFFER_FLOAT, .count = 3 }; - BufferAttribute texCoord = { .name = "lovrTexCoord", .type = BUFFER_FLOAT, .count = 2 }; - vec_push(&buffer->format, position); - vec_push(&buffer->format, normal); - vec_push(&buffer->format, texCoord); - } - - int stride = 0; - int i; - BufferAttribute attribute; - vec_foreach(&buffer->format, attribute, i) { - stride += attribute.count * sizeof(attribute.type); - } - - if (stride == 0) { - return NULL; - } - - buffer->size = size; - buffer->stride = stride; - buffer->data = malloc(buffer->size * buffer->stride); - buffer->scratchVertex = malloc(buffer->stride); - buffer->drawMode = drawMode; - buffer->usage = usage; - buffer->vao = 0; - buffer->vbo = 0; - buffer->ibo = 0; - buffer->isRangeEnabled = 0; - buffer->rangeStart = 0; - buffer->rangeCount = buffer->size; - buffer->texture = NULL; - - glGenBuffers(1, &buffer->vbo); - glBindBuffer(GL_ARRAY_BUFFER, buffer->vbo); - glBufferData(GL_ARRAY_BUFFER, buffer->size * buffer->stride, buffer->data, buffer->usage); - glGenVertexArrays(1, &buffer->vao); - glGenBuffers(1, &buffer->ibo); - - return buffer; -} - -void lovrBufferDestroy(const Ref* ref) { - Buffer* buffer = containerof(ref, Buffer); - if (buffer->texture) { - lovrRelease(&buffer->texture->ref); - } - glDeleteBuffers(1, &buffer->vbo); - glDeleteVertexArrays(1, &buffer->vao); - vec_deinit(&buffer->map); - vec_deinit(&buffer->format); - free(buffer->scratchVertex); - free(buffer->data); - free(buffer); -} - -void lovrBufferDraw(Buffer* buffer, mat4 transform) { - int usingIbo = buffer->map.length > 0; - - lovrGraphicsPush(); - lovrGraphicsMatrixTransform(transform); - lovrGraphicsBindTexture(buffer->texture); - lovrGraphicsPrepare(); - - glBindVertexArray(buffer->vao); - - // Figure out how many vertex attributes there are - int vertexAttributeCount; - glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &vertexAttributeCount); - - // Disable all vertex attributes - for (int i = 0; i < vertexAttributeCount; i++) { - glDisableVertexAttribArray(i); - } - - // Enable the vertex attributes in use and bind the correct data FIXME - Shader* shader = lovrGraphicsGetShader(); - if (shader) { - glBindBuffer(GL_ARRAY_BUFFER, buffer->vbo); - size_t offset = 0; - int i; - BufferAttribute attribute; - vec_foreach(&buffer->format, attribute, i) { - int location = lovrShaderGetAttributeId(shader, attribute.name); - if (location >= 0) { - glEnableVertexAttribArray(location); - if (attribute.type == BUFFER_INT) { - glVertexAttribIPointer(location, attribute.count, attribute.type, buffer->stride, (void*) offset); - } else { - glVertexAttribPointer(location, attribute.count, attribute.type, GL_FALSE, buffer->stride, (void*) offset); - } - } - offset += sizeof(attribute.type) * attribute.count; - } - } - - // Determine range of vertices to be rendered and whether we're using an IBO or not - int start, count; - if (buffer->isRangeEnabled) { - start = buffer->rangeStart; - count = buffer->rangeCount; - } else { - start = 0; - count = usingIbo ? buffer->map.length : buffer->size; - } - - // Render! Use the IBO if a draw range is set - if (usingIbo) { - uintptr_t startAddress = (uintptr_t) start; - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer->ibo); - glDrawElements(buffer->drawMode, count, GL_UNSIGNED_INT, (GLvoid*) startAddress); - } else { - glDrawArrays(buffer->drawMode, start, count); - } - - lovrGraphicsPop(); -} - -BufferFormat lovrBufferGetVertexFormat(Buffer* buffer) { - return buffer->format; -} - -BufferDrawMode lovrBufferGetDrawMode(Buffer* buffer) { - return buffer->drawMode; -} - -int lovrBufferSetDrawMode(Buffer* buffer, BufferDrawMode drawMode) { - buffer->drawMode = drawMode; - return 0; -} - -int lovrBufferGetVertexCount(Buffer* buffer) { - return buffer->size; -} - -int lovrBufferGetVertexSize(Buffer* buffer) { - return buffer->stride; -} - -void* lovrBufferGetScratchVertex(Buffer* buffer) { - return buffer->scratchVertex; -} - -void lovrBufferGetVertex(Buffer* buffer, int index, void* dest) { - if (index >= buffer->size) { - return; - } - - memcpy(dest, (char*) buffer->data + index * buffer->stride, buffer->stride); -} - -void lovrBufferSetVertex(Buffer* buffer, int index, void* vertex) { - memcpy((char*) buffer->data + index * buffer->stride, vertex, buffer->stride); - glBindBuffer(GL_ARRAY_BUFFER, buffer->vbo); - glBufferData(GL_ARRAY_BUFFER, buffer->size * buffer->stride, buffer->data, buffer->usage); -} - -void lovrBufferSetVertices(Buffer* buffer, void* vertices, int size) { - if (size > buffer->size * buffer->stride) { - error("Buffer is not big enough"); - } - - memcpy(buffer->data, vertices, size); - glBindBuffer(GL_ARRAY_BUFFER, buffer->vbo); - glBufferData(GL_ARRAY_BUFFER, buffer->size * buffer->stride, buffer->data, buffer->usage); -} - -unsigned int* lovrBufferGetVertexMap(Buffer* buffer, int* count) { - *count = buffer->map.length; - return buffer->map.data; -} - -void lovrBufferSetVertexMap(Buffer* buffer, unsigned int* map, int count) { - if (count == 0 || !map) { - vec_clear(&buffer->map); - } else { - vec_clear(&buffer->map); - vec_pusharr(&buffer->map, map, count); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer->ibo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, count * sizeof(unsigned int), buffer->map.data, GL_STATIC_DRAW); - } -} - -char lovrBufferIsRangeEnabled(Buffer* buffer) { - return buffer->isRangeEnabled; -} - -void lovrBufferSetRangeEnabled(Buffer* buffer, char isEnabled) { - buffer->isRangeEnabled = isEnabled; -} - -void lovrBufferGetDrawRange(Buffer* buffer, int* start, int* count) { - *start = buffer->rangeStart; - *count = buffer->rangeCount; -} - -int lovrBufferSetDrawRange(Buffer* buffer, int start, int count) { - if (start < 0 || count < 0 || start + count > buffer->size) { - return 1; - } - - buffer->rangeStart = start; - buffer->rangeCount = count; - - return 0; -} - -Texture* lovrBufferGetTexture(Buffer* buffer) { - return buffer->texture; -} - -void lovrBufferSetTexture(Buffer* buffer, Texture* texture) { - if (buffer->texture) { - lovrRelease(&buffer->texture->ref); - } - - buffer->texture = texture; - - if (buffer->texture) { - lovrRetain(&buffer->texture->ref); - } -} diff --git a/src/graphics/buffer.h b/src/graphics/buffer.h deleted file mode 100644 index 8357fe8c..00000000 --- a/src/graphics/buffer.h +++ /dev/null @@ -1,73 +0,0 @@ -#include "glfw.h" -#include "util.h" -#include "graphics/texture.h" -#include "math/math.h" - -#pragma once - -typedef enum { - BUFFER_POINTS = GL_POINTS, - BUFFER_TRIANGLE_STRIP = GL_TRIANGLE_STRIP, - BUFFER_TRIANGLES = GL_TRIANGLES, - BUFFER_TRIANGLE_FAN = GL_TRIANGLE_FAN -} BufferDrawMode; - -typedef enum { - BUFFER_STATIC = GL_STATIC_DRAW, - BUFFER_DYNAMIC = GL_DYNAMIC_DRAW, - BUFFER_STREAM = GL_STREAM_DRAW -} BufferUsage; - -typedef enum { - BUFFER_FLOAT = GL_FLOAT, - BUFFER_BYTE = GL_BYTE, - BUFFER_INT = GL_INT -} BufferAttributeType; - -typedef struct { - const char* name; - BufferAttributeType type; - int count; -} BufferAttribute; - -typedef vec_t(BufferAttribute) BufferFormat; - -typedef struct Buffer { - Ref ref; - int size; - int stride; - void* data; - void* scratchVertex; - BufferFormat format; - BufferDrawMode drawMode; - BufferUsage usage; - GLuint vao; - GLuint vbo; - GLuint ibo; - vec_uint_t map; - char isRangeEnabled; - int rangeStart; - int rangeCount; - Texture* texture; -} Buffer; - -Buffer* lovrBufferCreate(int size, BufferFormat* format, BufferDrawMode drawMode, BufferUsage usage); -void lovrBufferDestroy(const Ref* ref); -void lovrBufferDraw(Buffer* buffer, mat4 transform); -BufferFormat lovrBufferGetVertexFormat(Buffer* buffer); -BufferDrawMode lovrBufferGetDrawMode(Buffer* buffer); -int lovrBufferSetDrawMode(Buffer* buffer, BufferDrawMode drawMode); -int lovrBufferGetVertexCount(Buffer* buffer); -int lovrBufferGetVertexSize(Buffer* buffer); -void* lovrBufferGetScratchVertex(Buffer* buffer); -void lovrBufferGetVertex(Buffer* buffer, int index, void* dest); -void lovrBufferSetVertex(Buffer* buffer, int index, void* vertex); -void lovrBufferSetVertices(Buffer* buffer, void* vertices, int size); -unsigned int* lovrBufferGetVertexMap(Buffer* buffer, int* count); -void lovrBufferSetVertexMap(Buffer* buffer, unsigned int* map, int count); -char lovrBufferIsRangeEnabled(Buffer* buffer); -void lovrBufferSetRangeEnabled(Buffer* buffer, char isEnabled); -void lovrBufferGetDrawRange(Buffer* buffer, int* start, int* count); -int lovrBufferSetDrawRange(Buffer* buffer, int start, int count); -Texture* lovrBufferGetTexture(Buffer* buffer); -void lovrBufferSetTexture(Buffer* buffer, Texture* texture); diff --git a/src/graphics/graphics.h b/src/graphics/graphics.h index 4a701691..99756729 100644 --- a/src/graphics/graphics.h +++ b/src/graphics/graphics.h @@ -1,5 +1,5 @@ -#include "graphics/buffer.h" #include "graphics/font.h" +#include "graphics/mesh.h" #include "graphics/model.h" #include "graphics/shader.h" #include "graphics/skybox.h" diff --git a/src/graphics/mesh.c b/src/graphics/mesh.c new file mode 100644 index 00000000..183914af --- /dev/null +++ b/src/graphics/mesh.c @@ -0,0 +1,237 @@ +#include "graphics/mesh.h" +#include "graphics/graphics.h" +#include "graphics/shader.h" +#include + +Mesh* lovrMeshCreate(int size, MeshFormat* format, MeshDrawMode drawMode, MeshUsage usage) { + Mesh* mesh = lovrAlloc(sizeof(Mesh), lovrMeshDestroy); + if (!mesh) return NULL; + + vec_init(&mesh->map); + vec_init(&mesh->format); + + if (format) { + vec_extend(&mesh->format, format); + } else { + MeshAttribute position = { .name = "lovrPosition", .type = MESH_FLOAT, .count = 3 }; + MeshAttribute normal = { .name = "lovrNormal", .type = MESH_FLOAT, .count = 3 }; + MeshAttribute texCoord = { .name = "lovrTexCoord", .type = MESH_FLOAT, .count = 2 }; + vec_push(&mesh->format, position); + vec_push(&mesh->format, normal); + vec_push(&mesh->format, texCoord); + } + + int stride = 0; + int i; + MeshAttribute attribute; + vec_foreach(&mesh->format, attribute, i) { + stride += attribute.count * sizeof(attribute.type); + } + + if (stride == 0) { + return NULL; + } + + mesh->size = size; + mesh->stride = stride; + mesh->data = malloc(mesh->size * mesh->stride); + mesh->scratchVertex = malloc(mesh->stride); + mesh->drawMode = drawMode; + mesh->usage = usage; + mesh->vao = 0; + mesh->vbo = 0; + mesh->ibo = 0; + mesh->isRangeEnabled = 0; + mesh->rangeStart = 0; + mesh->rangeCount = mesh->size; + mesh->texture = NULL; + + glGenBuffers(1, &mesh->vbo); + glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo); + glBufferData(GL_ARRAY_BUFFER, mesh->size * mesh->stride, mesh->data, mesh->usage); + glGenVertexArrays(1, &mesh->vao); + glGenBuffers(1, &mesh->ibo); + + return mesh; +} + +void lovrMeshDestroy(const Ref* ref) { + Mesh* mesh = containerof(ref, Mesh); + if (mesh->texture) { + lovrRelease(&mesh->texture->ref); + } + glDeleteBuffers(1, &mesh->vbo); + glDeleteVertexArrays(1, &mesh->vao); + vec_deinit(&mesh->map); + vec_deinit(&mesh->format); + free(mesh->scratchVertex); + free(mesh->data); + free(mesh); +} + +void lovrMeshDraw(Mesh* mesh, mat4 transform) { + int usingIbo = mesh->map.length > 0; + + lovrGraphicsPush(); + lovrGraphicsMatrixTransform(transform); + lovrGraphicsBindTexture(mesh->texture); + lovrGraphicsPrepare(); + + glBindVertexArray(mesh->vao); + + // Figure out how many vertex attributes there are + int vertexAttributeCount; + glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &vertexAttributeCount); + + // Disable all vertex attributes + for (int i = 0; i < vertexAttributeCount; i++) { + glDisableVertexAttribArray(i); + } + + // Enable the vertex attributes in use and bind the correct data FIXME + Shader* shader = lovrGraphicsGetShader(); + if (shader) { + glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo); + size_t offset = 0; + int i; + MeshAttribute attribute; + vec_foreach(&mesh->format, attribute, i) { + int location = lovrShaderGetAttributeId(shader, attribute.name); + if (location >= 0) { + glEnableVertexAttribArray(location); + if (attribute.type == MESH_INT) { + glVertexAttribIPointer(location, attribute.count, attribute.type, mesh->stride, (void*) offset); + } else { + glVertexAttribPointer(location, attribute.count, attribute.type, GL_FALSE, mesh->stride, (void*) offset); + } + } + offset += sizeof(attribute.type) * attribute.count; + } + } + + // Determine range of vertices to be rendered and whether we're using an IBO or not + int start, count; + if (mesh->isRangeEnabled) { + start = mesh->rangeStart; + count = mesh->rangeCount; + } else { + start = 0; + count = usingIbo ? mesh->map.length : mesh->size; + } + + // Render! Use the IBO if a draw range is set + if (usingIbo) { + uintptr_t startAddress = (uintptr_t) start; + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->ibo); + glDrawElements(mesh->drawMode, count, GL_UNSIGNED_INT, (GLvoid*) startAddress); + } else { + glDrawArrays(mesh->drawMode, start, count); + } + + lovrGraphicsPop(); +} + +MeshFormat lovrMeshGetVertexFormat(Mesh* mesh) { + return mesh->format; +} + +MeshDrawMode lovrMeshGetDrawMode(Mesh* mesh) { + return mesh->drawMode; +} + +int lovrMeshSetDrawMode(Mesh* mesh, MeshDrawMode drawMode) { + mesh->drawMode = drawMode; + return 0; +} + +int lovrMeshGetVertexCount(Mesh* mesh) { + return mesh->size; +} + +int lovrMeshGetVertexSize(Mesh* mesh) { + return mesh->stride; +} + +void* lovrMeshGetScratchVertex(Mesh* mesh) { + return mesh->scratchVertex; +} + +void lovrMeshGetVertex(Mesh* mesh, int index, void* dest) { + if (index >= mesh->size) { + return; + } + + memcpy(dest, (char*) mesh->data + index * mesh->stride, mesh->stride); +} + +void lovrMeshSetVertex(Mesh* mesh, int index, void* vertex) { + memcpy((char*) mesh->data + index * mesh->stride, vertex, mesh->stride); + glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo); + glBufferData(GL_ARRAY_BUFFER, mesh->size * mesh->stride, mesh->data, mesh->usage); +} + +void lovrMeshSetVertices(Mesh* mesh, void* vertices, int size) { + if (size > mesh->size * mesh->stride) { + error("Mesh is not big enough"); + } + + memcpy(mesh->data, vertices, size); + glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo); + glBufferData(GL_ARRAY_BUFFER, mesh->size * mesh->stride, mesh->data, mesh->usage); +} + +unsigned int* lovrMeshGetVertexMap(Mesh* mesh, int* count) { + *count = mesh->map.length; + return mesh->map.data; +} + +void lovrMeshSetVertexMap(Mesh* mesh, unsigned int* map, int count) { + if (count == 0 || !map) { + vec_clear(&mesh->map); + } else { + vec_clear(&mesh->map); + vec_pusharr(&mesh->map, map, count); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->ibo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, count * sizeof(unsigned int), mesh->map.data, GL_STATIC_DRAW); + } +} + +char lovrMeshIsRangeEnabled(Mesh* mesh) { + return mesh->isRangeEnabled; +} + +void lovrMeshSetRangeEnabled(Mesh* mesh, char isEnabled) { + mesh->isRangeEnabled = isEnabled; +} + +void lovrMeshGetDrawRange(Mesh* mesh, int* start, int* count) { + *start = mesh->rangeStart; + *count = mesh->rangeCount; +} + +int lovrMeshSetDrawRange(Mesh* mesh, int start, int count) { + if (start < 0 || count < 0 || start + count > mesh->size) { + return 1; + } + + mesh->rangeStart = start; + mesh->rangeCount = count; + + return 0; +} + +Texture* lovrMeshGetTexture(Mesh* mesh) { + return mesh->texture; +} + +void lovrMeshSetTexture(Mesh* mesh, Texture* texture) { + if (mesh->texture) { + lovrRelease(&mesh->texture->ref); + } + + mesh->texture = texture; + + if (mesh->texture) { + lovrRetain(&mesh->texture->ref); + } +} diff --git a/src/graphics/mesh.h b/src/graphics/mesh.h new file mode 100644 index 00000000..f2ab4f38 --- /dev/null +++ b/src/graphics/mesh.h @@ -0,0 +1,73 @@ +#include "glfw.h" +#include "util.h" +#include "graphics/texture.h" +#include "math/math.h" + +#pragma once + +typedef enum { + MESH_POINTS = GL_POINTS, + MESH_TRIANGLE_STRIP = GL_TRIANGLE_STRIP, + MESH_TRIANGLES = GL_TRIANGLES, + MESH_TRIANGLE_FAN = GL_TRIANGLE_FAN +} MeshDrawMode; + +typedef enum { + MESH_STATIC = GL_STATIC_DRAW, + MESH_DYNAMIC = GL_DYNAMIC_DRAW, + MESH_STREAM = GL_STREAM_DRAW +} MeshUsage; + +typedef enum { + MESH_FLOAT = GL_FLOAT, + MESH_BYTE = GL_BYTE, + MESH_INT = GL_INT +} MeshAttributeType; + +typedef struct { + const char* name; + MeshAttributeType type; + int count; +} MeshAttribute; + +typedef vec_t(MeshAttribute) MeshFormat; + +typedef struct { + Ref ref; + int size; + int stride; + void* data; + void* scratchVertex; + MeshFormat format; + MeshDrawMode drawMode; + MeshUsage usage; + GLuint vao; + GLuint vbo; + GLuint ibo; + vec_uint_t map; + char isRangeEnabled; + int rangeStart; + int rangeCount; + Texture* texture; +} Mesh; + +Mesh* lovrMeshCreate(int size, MeshFormat* format, MeshDrawMode drawMode, MeshUsage usage); +void lovrMeshDestroy(const Ref* ref); +void lovrMeshDraw(Mesh* buffer, mat4 transform); +MeshFormat lovrMeshGetVertexFormat(Mesh* buffer); +MeshDrawMode lovrMeshGetDrawMode(Mesh* buffer); +int lovrMeshSetDrawMode(Mesh* buffer, MeshDrawMode drawMode); +int lovrMeshGetVertexCount(Mesh* buffer); +int lovrMeshGetVertexSize(Mesh* buffer); +void* lovrMeshGetScratchVertex(Mesh* buffer); +void lovrMeshGetVertex(Mesh* buffer, int index, void* dest); +void lovrMeshSetVertex(Mesh* buffer, int index, void* vertex); +void lovrMeshSetVertices(Mesh* buffer, void* vertices, int size); +unsigned int* lovrMeshGetVertexMap(Mesh* buffer, int* count); +void lovrMeshSetVertexMap(Mesh* buffer, unsigned int* map, int count); +char lovrMeshIsRangeEnabled(Mesh* buffer); +void lovrMeshSetRangeEnabled(Mesh* buffer, char isEnabled); +void lovrMeshGetDrawRange(Mesh* buffer, int* start, int* count); +int lovrMeshSetDrawRange(Mesh* buffer, int start, int count); +Texture* lovrMeshGetTexture(Mesh* buffer); +void lovrMeshSetTexture(Mesh* buffer, Texture* texture); diff --git a/src/graphics/model.c b/src/graphics/model.c index 72036755..63672c69 100644 --- a/src/graphics/model.c +++ b/src/graphics/model.c @@ -71,28 +71,28 @@ Model* lovrModelCreate(ModelData* modelData) { visitNode(modelData, modelData->root, NULL, &vertices, &indices); - BufferFormat format; + MeshFormat format; vec_init(&format); int components = 3; - BufferAttribute position = { .name = "lovrPosition", .type = BUFFER_FLOAT, .count = 3 }; + MeshAttribute position = { .name = "lovrPosition", .type = MESH_FLOAT, .count = 3 }; vec_push(&format, position); if (modelData->hasNormals) { - BufferAttribute normal = { .name = "lovrNormal", .type = BUFFER_FLOAT, .count = 3 }; + MeshAttribute normal = { .name = "lovrNormal", .type = MESH_FLOAT, .count = 3 }; vec_push(&format, normal); components += 3; } if (modelData->hasTexCoords) { - BufferAttribute texCoord = { .name = "lovrTexCoord", .type = BUFFER_FLOAT, .count = 2 }; + MeshAttribute texCoord = { .name = "lovrTexCoord", .type = MESH_FLOAT, .count = 2 }; vec_push(&format, texCoord); components += 2; } - model->buffer = lovrBufferCreate(vertices.length / components, &format, BUFFER_TRIANGLES, BUFFER_STATIC); - lovrBufferSetVertices(model->buffer, (void*) vertices.data, vertices.length * sizeof(float)); - lovrBufferSetVertexMap(model->buffer, indices.data, indices.length); + model->mesh = lovrMeshCreate(vertices.length / components, &format, MESH_TRIANGLES, MESH_STATIC); + lovrMeshSetVertices(model->mesh, (void*) vertices.data, vertices.length * sizeof(float)); + lovrMeshSetVertexMap(model->mesh, indices.data, indices.length); model->texture = NULL; @@ -108,12 +108,12 @@ void lovrModelDestroy(const Ref* ref) { lovrRelease(&model->texture->ref); } lovrModelDataDestroy(model->modelData); - lovrRelease(&model->buffer->ref); + lovrRelease(&model->mesh->ref); free(model); } void lovrModelDraw(Model* model, mat4 transform) { - lovrBufferDraw(model->buffer, transform); + lovrMeshDraw(model->mesh, transform); } Texture* lovrModelGetTexture(Model* model) { @@ -126,7 +126,7 @@ void lovrModelSetTexture(Model* model, Texture* texture) { } model->texture = texture; - lovrBufferSetTexture(model->buffer, model->texture); + lovrMeshSetTexture(model->mesh, model->texture); if (model->texture) { lovrRetain(&model->texture->ref); diff --git a/src/graphics/model.h b/src/graphics/model.h index 2a1d301e..b043977c 100644 --- a/src/graphics/model.h +++ b/src/graphics/model.h @@ -1,5 +1,5 @@ #include "loaders/model.h" -#include "graphics/buffer.h" +#include "graphics/mesh.h" #include "graphics/texture.h" #include "math/math.h" #include "glfw.h" @@ -10,7 +10,7 @@ typedef struct { Ref ref; ModelData* modelData; - Buffer* buffer; + Mesh* mesh; Texture* texture; } Model;