This commit is contained in:
bjorn 2023-06-10 22:06:29 -07:00
parent 5c322d3403
commit 4892d228b3
17 changed files with 898 additions and 170 deletions

View File

@ -431,6 +431,7 @@ if(LOVR_ENABLE_GRAPHICS)
src/api/l_graphics_shader.c
src/api/l_graphics_material.c
src/api/l_graphics_font.c
src/api/l_graphics_mesh.c
src/api/l_graphics_model.c
src/api/l_graphics_readback.c
src/api/l_graphics_pass.c

View File

@ -564,7 +564,15 @@ int luax_readmesh(lua_State* L, int index, float** vertices, uint32_t* vertexCou
*shouldFree = false;
return index + 1;
}
Mesh* mesh = luax_totype(L, index, Mesh);
if (mesh) {
lovrMeshGetTriangles(mesh, vertices, indices, vertexCount, indexCount);
*shouldFree = true;
return index + 1;
}
#endif
return luaL_argerror(L, index, "table or Model");
return luaL_argerror(L, index, "table, Mesh, or Model");
}

View File

@ -43,7 +43,8 @@ extern StringEntry lovrHeadsetDriver[];
extern StringEntry lovrHorizontalAlign[];
extern StringEntry lovrJointType[];
extern StringEntry lovrKeyboardKey[];
extern StringEntry lovrMeshMode[];
extern StringEntry lovrMeshStorage[];
extern StringEntry lovrModelDrawMode[];
extern StringEntry lovrOriginType[];
extern StringEntry lovrPassType[];
extern StringEntry lovrPermission[];

View File

@ -38,13 +38,13 @@ StringEntry lovrDefaultAttribute[] = {
{ 0 }
};
StringEntry lovrDrawMode[] = {
[DRAW_POINTS] = ENTRY("points"),
[DRAW_LINES] = ENTRY("lines"),
StringEntry lovrModelDrawMode[] = {
[DRAW_POINT_LIST] = ENTRY("points"),
[DRAW_LINE_LIST] = ENTRY("lines"),
[DRAW_LINE_STRIP] = ENTRY("linestrip"),
[DRAW_LINE_LOOP] = ENTRY("lineloop"),
[DRAW_TRIANGLE_LIST] = ENTRY("triangles"),
[DRAW_TRIANGLE_STRIP] = ENTRY("strip"),
[DRAW_TRIANGLES] = ENTRY("triangles"),
[DRAW_TRIANGLE_FAN] = ENTRY("fan"),
{ 0 }
};

View File

@ -289,7 +289,7 @@ static int l_lovrModelDataGetMeshDrawMode(lua_State* L) {
uint32_t index = luax_checku32(L, 2) - 1;
lovrCheck(index < model->primitiveCount, "Invalid mesh index '%d'", index + 1);
ModelPrimitive* mesh = &model->primitives[index];
luax_pushenum(L, DrawMode, mesh->mode);
luax_pushenum(L, ModelDrawMode, mesh->mode);
return 1;
}

View File

@ -62,6 +62,13 @@ StringEntry lovrDefaultShader[] = {
{ 0 }
};
StringEntry lovrDrawMode[] = {
[DRAW_POINTS] = ENTRY("points"),
[DRAW_LINES] = ENTRY("lines"),
[DRAW_TRIANGLES] = ENTRY("triangles"),
{ 0 }
};
StringEntry lovrDrawStyle[] = {
[STYLE_FILL] = ENTRY("fill"),
[STYLE_LINE] = ENTRY("line"),
@ -119,10 +126,9 @@ StringEntry lovrHorizontalAlign[] = {
{ 0 }
};
StringEntry lovrMeshMode[] = {
[MESH_POINTS] = ENTRY("points"),
[MESH_LINES] = ENTRY("lines"),
[MESH_TRIANGLES] = ENTRY("triangles"),
StringEntry lovrMeshStorage[] = {
[MESH_CPU] = ENTRY("cpu"),
[MESH_GPU] = ENTRY("gpu"),
{ 0 }
};
@ -299,7 +305,6 @@ void luax_checkdataformat(lua_State* L, int index, DataField* fields, uint32_t*
luax_checkdataformat(L, -1, fields, count, max);
lua_pop(L, 1);
size_t nameLength;
lua_getfield(L, -1, "name");
if (lua_isnil(L, -1)) {
lua_pop(L, 1);
@ -312,11 +317,9 @@ void luax_checkdataformat(lua_State* L, int index, DataField* fields, uint32_t*
}
}
if (lua_type(L, -1) == LUA_TSTRING) {
child->name = lua_tolstring(L, -1, &nameLength);
child->hash = (uint32_t) hash64(child->name, nameLength);
child->name = lua_tostring(L, -1);
} else {
child->name = NULL;
child->hash = 0;
}
lua_pop(L, 1);
@ -771,7 +774,7 @@ static int l_lovrGraphicsGetBuffer(lua_State* L) {
if (index) {
if (lua_istable(L, index)) {
DataField* format = lovrBufferGetInfo(buffer)->format;
const DataField* format = lovrBufferGetInfo(buffer)->format;
luax_checkbufferdata(L, index, format, pointer);
} else {
Blob* blob = luax_checktype(L, index, Blob);
@ -795,7 +798,7 @@ static int l_lovrGraphicsNewBuffer(lua_State* L) {
if (index) {
if (lua_istable(L, index)) {
DataField* format = lovrBufferGetInfo(buffer)->format;
const DataField* format = lovrBufferGetInfo(buffer)->format;
luax_checkbufferdata(L, index, format, pointer);
} else {
Blob* blob = luax_checktype(L, index, Blob);
@ -1352,6 +1355,89 @@ static int l_lovrGraphicsNewFont(lua_State* L) {
return 1;
}
static int l_lovrGraphicsNewMesh(lua_State* L) {
MeshInfo info = { 0 };
bool hasFormat = false;
if (lua_istable(L, 1)) {
lua_rawgeti(L, 1, 1);
if (lua_istable(L, -1)) {
lua_getfield(L, -1, "type");
lua_rawgeti(L, -2, 1);
if (lua_type(L, -2) == LUA_TSTRING || lua_type(L, -1) == LUA_TSTRING) {
luax_checkdataformat(L, 1, info.format, &info.fieldCount, COUNTOF(info.format));
hasFormat = true;
}
lua_pop(L, 2);
}
lua_pop(L, 1);
}
if (!hasFormat) {
DataField format[] = {
{ .stride = 32 },
{ .name = "VertexPosition", .type = TYPE_F32x3, .offset = 0 },
{ .name = "VertexNormal", .type = TYPE_F32x3, .offset = 12 },
{ .name = "VertexUV", .type = TYPE_F32x2, .offset = 24 }
};
memcpy(info.format, format, sizeof(format));
info.format->childCount = COUNTOF(format) - 1;
info.format->children = info.format + 1;
info.fieldCount = COUNTOF(format);
}
Blob* blob = NULL;
bool hasData = false;
int index = 1 + hasFormat;
switch (lua_type(L, index)) {
case LUA_TNUMBER: info.format->length = luax_checku32(L, index++); break;
case LUA_TTABLE: info.format->length = luax_len(L, index++); hasData = true; break;
case LUA_TUSERDATA:
if ((info.vertexBuffer = luax_totype(L, index++, Buffer)) != NULL) break;
if ((blob = luax_totype(L, index++, Blob)) != NULL) {
lovrCheck(blob->size % info.format->stride == 0, "Blob size must be a multiple of vertex size");
info.format->length = blob->size / info.format->stride;
hasData = true;
break;
}
default: return luax_typeerror(L, index, "number, table, Blob, or Buffer");
}
if (info.vertexBuffer || luax_totype(L, index, Buffer)) {
info.storage = MESH_GPU;
} else {
info.storage = luax_checkenum(L, index + (luax_totype(L, index, Blob) ? 2 : 1), MeshStorage, "cpu");
}
void* vertices = NULL;
Mesh* mesh = lovrMeshCreate(&info, hasData ? &vertices : NULL);
if (blob) {
memcpy(vertices, blob->data, blob->size);
} else if (hasData) {
luax_checkbufferdata(L, index - 1, lovrMeshGetVertexFormat(mesh), vertices);
}
if (!lua_isnoneornil(L, index)) {
luax_pushtype(L, Mesh, mesh);
lua_getfield(L, -1, "setIndices");
lua_pushvalue(L, -2);
lua_pushvalue(L, index);
if (luax_totype(L, -1, Blob)) {
lua_pushvalue(L, index + 1);
lua_call(L, 3, 0);
} else {
lua_call(L, 2, 0);
}
} else {
luax_pushtype(L, Mesh, mesh);
}
lovrRelease(mesh, lovrMeshDestroy);
return 1;
}
static int l_lovrGraphicsNewModel(lua_State* L) {
ModelInfo info = { 0 };
info.data = luax_totype(L, 1, ModelData);
@ -1430,6 +1516,7 @@ static const luaL_Reg lovrGraphics[] = {
{ "newShader", l_lovrGraphicsNewShader },
{ "newMaterial", l_lovrGraphicsNewMaterial },
{ "newFont", l_lovrGraphicsNewFont },
{ "newMesh", l_lovrGraphicsNewMesh },
{ "newModel", l_lovrGraphicsNewModel },
{ "newPass", l_lovrGraphicsNewPass },
{ "getPass", l_lovrGraphicsGetPass },
@ -1442,6 +1529,7 @@ extern const luaL_Reg lovrSampler[];
extern const luaL_Reg lovrShader[];
extern const luaL_Reg lovrMaterial[];
extern const luaL_Reg lovrFont[];
extern const luaL_Reg lovrMesh[];
extern const luaL_Reg lovrModel[];
extern const luaL_Reg lovrReadback[];
extern const luaL_Reg lovrPass[];
@ -1455,6 +1543,7 @@ int luaopen_lovr_graphics(lua_State* L) {
luax_registertype(L, Shader);
luax_registertype(L, Material);
luax_registertype(L, Font);
luax_registertype(L, Mesh);
luax_registertype(L, Model);
luax_registertype(L, Readback);
luax_registertype(L, Pass);

View File

@ -300,7 +300,8 @@ static int luax_pushcomponents(lua_State* L, const DataField* field, char* data)
static int luax_pushstruct(lua_State* L, const DataField* field, char* data) {
lua_createtable(L, 0, field->childCount);
for (uint32_t i = 0; i < field->childCount; i++) {
if (field->childCount > 0 || field->length > 0 || fieldComponents[field->type] == 1) {
const DataField* child = &field->children[i];
if (child->childCount > 0 || child->length > 0 || fieldComponents[child->type] == 1) {
luax_pushbufferdata(L, &field->children[i], data + field->children[i].offset);
} else {
int n = fieldComponents[field->type];
@ -320,7 +321,7 @@ int luax_pushbufferdata(lua_State* L, const DataField* field, char* data) {
lua_createtable(L, field->length, 0);
if (field->childCount > 0) {
for (uint32_t i = 0; i < field->length; i++) {
luax_pushstruct(L, &field->children[i], data);
luax_pushstruct(L, field, data);
lua_rawseti(L, -2, i + 1);
data += field->stride;
}

238
src/api/l_graphics_mesh.c Normal file
View File

@ -0,0 +1,238 @@
#include "api.h"
#include "graphics/graphics.h"
#include "data/blob.h"
#include "util.h"
#include <string.h>
static int l_lovrMeshGetVertexCount(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
const DataField* format = lovrMeshGetVertexFormat(mesh);
lua_pushinteger(L, format->length);
return 1;
}
static int l_lovrMeshGetVertexStride(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
const DataField* format = lovrMeshGetVertexFormat(mesh);
lua_pushinteger(L, format->stride);
return 1;
}
static int l_lovrMeshGetVertexFormat(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
const DataField* format = lovrMeshGetVertexFormat(mesh);
const DataField* attributes = format->childCount > 0 ? format->children : format;
uint32_t attributeCount = MAX(format->childCount, 1);
lua_createtable(L, (int) attributeCount, 0);
for (uint32_t i = 0; i < attributeCount; i++) {
const DataField* attribute = &attributes[i];
lua_createtable(L, 3, 0);
lua_pushstring(L, attribute->name);
lua_rawseti(L, -2, 1);
luax_pushenum(L, DataType, attribute->type);
lua_rawseti(L, -2, 2);
lua_rawseti(L, -2, (int) i + 1);
}
return 1;
}
static int l_lovrMeshGetVertexBuffer(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
Buffer* buffer = lovrMeshGetVertexBuffer(mesh);
luax_pushtype(L, Buffer, buffer);
return 1;
}
static int l_lovrMeshGetIndexBuffer(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
Buffer* buffer = lovrMeshGetIndexBuffer(mesh);
luax_pushtype(L, Buffer, buffer);
return 1;
}
static int l_lovrMeshSetIndexBuffer(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
Buffer* buffer = luax_checktype(L, 2, Buffer);
lovrMeshSetIndexBuffer(mesh, buffer);
return 0;
}
static int l_lovrMeshGetVertices(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
uint32_t index = luax_optu32(L, 2, 1) - 1;
uint32_t count = luax_optu32(L, 3, ~0u);
DataField format = *lovrMeshGetVertexFormat(mesh);
void* data = lovrMeshGetVertices(mesh, index, count);
format.length = count == ~0u ? format.length - index : count;
return luax_pushbufferdata(L, &format, data);
}
static int l_lovrMeshSetVertices(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
uint32_t index = luax_optu32(L, 3, 1) - 1;
uint32_t count = luax_optu32(L, 4, ~0u);
void* data = lovrMeshSetVertices(mesh, index, count);
luax_checkbufferdata(L, 2, lovrMeshGetVertexFormat(mesh), data);
return 0;
}
static int l_lovrMeshGetIndices(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
DataField format;
void* data = lovrMeshGetIndices(mesh, &format);
return luax_pushbufferdata(L, &format, data);
}
static int l_lovrMeshSetIndices(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
switch (lua_type(L, 2)) {
case LUA_TNONE:
case LUA_TNIL:
lovrMeshSetIndices(mesh, 0, TYPE_U16);
return 0;
case LUA_TTABLE: {
uint32_t count = luax_len(L, 2);
DataType type = lovrMeshGetVertexFormat(mesh)->length > 0xffff ? TYPE_INDEX32 : TYPE_INDEX16;
void* data = lovrMeshSetIndices(mesh, count, type);
DataField format = { .type = type, .length = count, .stride = type == TYPE_INDEX32 ? 4 : 2 };
luax_checkbufferdata(L, 2, &format, data);
break;
}
case LUA_TUSERDATA: {
Blob* blob = luax_checktype(L, 2, Blob);
DataType type = luax_checkenum(L, 3, DataType, NULL);
lovrCheck(type == TYPE_U16 || type == TYPE_U32, "Blob type must be u16 or u32");
size_t stride = type == TYPE_U16 ? 2 : 4;
uint32_t count = blob->size / stride;
void* data = lovrMeshSetIndices(mesh, count, type);
memcpy(data, blob->data, count * stride);
}
default: return luax_typeerror(L, 2, "nil, table, or Blob");
}
return 0;
}
static int l_lovrMeshGetBoundingBox(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
float box[6];
if (lovrMeshGetBoundingBox(mesh, box)) {
lua_pushnumber(L, box[0]);
lua_pushnumber(L, box[1]);
lua_pushnumber(L, box[2]);
lua_pushnumber(L, box[3]);
lua_pushnumber(L, box[4]);
lua_pushnumber(L, box[5]);
return 6;
} else {
lua_pushnil(L);
return 1;
}
}
static int l_lovrMeshSetBoundingBox(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
if (lua_isnoneornil(L, 2)) {
lovrMeshSetBoundingBox(mesh, NULL);
} else {
float box[6];
box[0] = luax_checkfloat(L, 2);
box[1] = luax_checkfloat(L, 3);
box[2] = luax_checkfloat(L, 4);
box[3] = luax_checkfloat(L, 5);
box[4] = luax_checkfloat(L, 6);
box[5] = luax_checkfloat(L, 7);
lovrMeshSetBoundingBox(mesh, box);
}
return 0;
}
static int l_lovrMeshComputeBoundingBox(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
bool updated = lovrMeshComputeBoundingBox(mesh);
lua_pushboolean(L, updated);
return 1;
}
static int l_lovrMeshGetDrawMode(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
DrawMode mode = lovrMeshGetDrawMode(mesh);
luax_pushenum(L, DrawMode, mode);
return 1;
}
static int l_lovrMeshSetDrawMode(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
DrawMode mode = luax_checkenum(L, 2, DrawMode, NULL);
lovrMeshSetDrawMode(mesh, mode);
return 0;
}
static int l_lovrMeshGetDrawRange(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
uint32_t start, count, offset;
lovrMeshGetDrawRange(mesh, &start, &count, &offset);
if (count == 0) {
return 0;
}
lua_pushinteger(L, start + 1);
lua_pushinteger(L, count);
lua_pushinteger(L, offset);
return 2;
}
static int l_lovrMeshSetDrawRange(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
if (lua_isnoneornil(L, 2)) {
lovrMeshSetDrawRange(mesh, 0, 0, 0);
} else {
uint32_t start = luax_checku32(L, 2) - 1;
uint32_t count = luax_checku32(L, 3);
uint32_t offset = luax_optu32(L, 3, 0);
lovrMeshSetDrawRange(mesh, start, count, offset);
}
return 0;
}
static int l_lovrMeshGetMaterial(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
Material* material = lovrMeshGetMaterial(mesh);
luax_pushtype(L, Material, material);
return 1;
}
static int l_lovrMeshSetMaterial(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
Material* material = luax_checktype(L, 2, Material);
lovrMeshSetMaterial(mesh, material);
return 0;
}
const luaL_Reg lovrMesh[] = {
{ "getVertexCount", l_lovrMeshGetVertexCount },
{ "getVertexStride", l_lovrMeshGetVertexStride },
{ "getVertexFormat", l_lovrMeshGetVertexFormat },
{ "getVertexBuffer", l_lovrMeshGetVertexBuffer },
{ "getIndexBuffer", l_lovrMeshGetIndexBuffer },
{ "setIndexBuffer", l_lovrMeshSetIndexBuffer },
{ "getVertices", l_lovrMeshGetVertices },
{ "setVertices", l_lovrMeshSetVertices },
{ "getIndices", l_lovrMeshGetIndices },
{ "setIndices", l_lovrMeshSetIndices },
{ "getBoundingBox", l_lovrMeshGetBoundingBox },
{ "setBoundingBox", l_lovrMeshSetBoundingBox },
{ "computeBoundingBox", l_lovrMeshComputeBoundingBox },
{ "getDrawMode", l_lovrMeshGetDrawMode },
{ "setDrawMode", l_lovrMeshSetDrawMode },
{ "getDrawRange", l_lovrMeshGetDrawRange },
{ "setDrawRange", l_lovrMeshSetDrawRange },
{ "getMaterial", l_lovrMeshGetMaterial },
{ "setMaterial", l_lovrMeshSetMaterial },
{ NULL, NULL }
};

View File

@ -77,32 +77,6 @@ static int l_lovrModelGetNodeChildren(lua_State* L) {
return luax_callmodeldata(L, "getNodeChildren", 1);
}
static int l_lovrModelGetNodeDrawCount(lua_State* L) {
Model* model = luax_checktype(L, 1, Model);
uint32_t node = luax_checknodeindex(L, 2, lovrModelGetInfo(model)->data);
uint32_t count = lovrModelGetNodeDrawCount(model, node);
lua_pushinteger(L, count);
return 1;
}
static int l_lovrModelGetNodeDraw(lua_State* L) {
Model* model = luax_checktype(L, 1, Model);
uint32_t node = luax_checknodeindex(L, 2, lovrModelGetInfo(model)->data);
uint32_t index = luax_optu32(L, 3, 1) - 1;
ModelDraw draw;
lovrModelGetNodeDraw(model, node, index, &draw);
luax_pushenum(L, MeshMode, draw.mode);
luax_pushtype(L, Material, draw.material);
lua_pushinteger(L, draw.start + 1);
lua_pushinteger(L, draw.count);
if (draw.indexed) {
lua_pushinteger(L, draw.base);
return 5;
} else {
return 4;
}
}
static int l_lovrModelGetNodePosition(lua_State* L) {
Model* model = luax_checktype(L, 1, Model);
uint32_t node = luax_checknodeindex(L, 2, lovrModelGetInfo(model)->data);
@ -354,6 +328,30 @@ static int l_lovrModelGetIndexBuffer(lua_State* L) {
return 1;
}
static int l_lovrModelGetMeshCount(lua_State* L) {
return luax_callmodeldata(L, "getMeshCount", 1);
}
static int l_lovrModelGetMesh(lua_State* L) {
Model* model = luax_checktype(L, 1, Model);
uint32_t index = luax_checku32(L, 3) - 1;
Mesh* mesh = lovrModelGetMesh(model, index);
luax_pushtype(L, Mesh, mesh);
return 1;
}
static int l_lovrModelGetTextureCount(lua_State* L) {
return luax_callmodeldata(L, "getImageCount", 1);
}
static int l_lovrModelGetTexture(lua_State* L) {
Model* model = luax_checktype(L, 1, Model);
uint32_t index = luax_checku32(L, 2) - 1;
Texture* texture = lovrModelGetTexture(model, index);
luax_pushtype(L, Texture, texture);
return 1;
}
static int l_lovrModelGetMaterialCount(lua_State* L) {
return luax_callmodeldata(L, "getMaterialCount", 1);
}
@ -362,10 +360,6 @@ static int l_lovrModelGetMaterialName(lua_State* L) {
return luax_callmodeldata(L, "getMaterialName", 1);
}
static int l_lovrModelGetTextureCount(lua_State* L) {
return luax_callmodeldata(L, "getImageCount", 1);
}
static int l_lovrModelGetMaterial(lua_State* L) {
Model* model = luax_checktype(L, 1, Model);
uint32_t index = luax_checkmaterialindex(L, 2, lovrModelGetInfo(model)->data);
@ -374,14 +368,6 @@ static int l_lovrModelGetMaterial(lua_State* L) {
return 1;
}
static int l_lovrModelGetTexture(lua_State* L) {
Model* model = luax_checktype(L, 1, Model);
uint32_t index = luaL_checkinteger(L, 2);
Texture* texture = lovrModelGetTexture(model, index);
luax_pushtype(L, Texture, texture);
return 1;
}
const luaL_Reg lovrModel[] = {
{ "clone", l_lovrModelClone },
{ "getData", l_lovrModelGetData },
@ -391,8 +377,6 @@ const luaL_Reg lovrModel[] = {
{ "getNodeName", l_lovrModelGetNodeName },
{ "getNodeParent", l_lovrModelGetNodeParent },
{ "getNodeChildren", l_lovrModelGetNodeChildren },
{ "getNodeDrawCount", l_lovrModelGetNodeDrawCount },
{ "getNodeDraw", l_lovrModelGetNodeDraw },
{ "getNodePosition", l_lovrModelGetNodePosition },
{ "setNodePosition", l_lovrModelSetNodePosition },
{ "getNodeOrientation", l_lovrModelGetNodeOrientation },
@ -425,10 +409,12 @@ const luaL_Reg lovrModel[] = {
{ "getBoundingSphere", l_lovrModelGetBoundingSphere },
{ "getVertexBuffer", l_lovrModelGetVertexBuffer },
{ "getIndexBuffer", l_lovrModelGetIndexBuffer },
{ "getMeshCount", l_lovrModelGetMeshCount },
{ "getMesh", l_lovrModelGetMesh },
{ "getTextureCount", l_lovrModelGetTextureCount },
{ "getTexture", l_lovrModelGetTexture },
{ "getMaterialCount", l_lovrModelGetMaterialCount },
{ "getMaterialName", l_lovrModelGetMaterialName },
{ "getTextureCount", l_lovrModelGetTextureCount },
{ "getMaterial", l_lovrModelGetMaterial },
{ "getTexture", l_lovrModelGetTexture },
{ NULL, NULL }
};

View File

@ -551,7 +551,7 @@ static int l_lovrPassSetMaterial(lua_State* L) {
static int l_lovrPassSetMeshMode(lua_State* L) {
Pass* pass = luax_checktype(L, 1, Pass);
MeshMode mode = luax_checkenum(L, 2, MeshMode, NULL);
DrawMode mode = luax_checkenum(L, 2, DrawMode, NULL);
lovrPassSetMeshMode(pass, mode);
return 0;
}
@ -938,10 +938,17 @@ static int l_lovrPassDraw(lua_State* L) {
if (model) {
int index = luax_readmat4(L, 3, transform, 1);
uint32_t node = lua_isnoneornil(L, index) ? ~0u : luax_checknodeindex(L, index, lovrModelGetInfo(model)->data);
bool recurse = lua_isnoneornil(L, index + 1) ? true : lua_toboolean(L, index + 1);
uint32_t instances = lua_isnoneornil(L, index + 2) ? 1 : luax_checku32(L, index + 2);
lovrPassDrawModel(pass, model, transform, node, recurse, instances);
uint32_t instances = luax_optu32(L, index + 1, 1);
lovrPassDrawModel(pass, model, transform, instances);
return 0;
}
Mesh* mesh = luax_totype(L, 2, Mesh);
if (mesh) {
int index = luax_readmat4(L, 3, transform, 1);
uint32_t instances = luax_optu32(L, index, 1);
lovrPassDrawMesh(pass, mesh, transform, instances);
return 0;
}
@ -954,7 +961,7 @@ static int l_lovrPassDraw(lua_State* L) {
return 0;
}
return luax_typeerror(L, 2, "Model or Texture");
return luax_typeerror(L, 2, "Mesh, Model, or Texture");
}
static int l_lovrPassMesh(lua_State* L) {

View File

@ -68,21 +68,21 @@ typedef struct {
} ModelBlendData;
typedef enum {
DRAW_POINTS,
DRAW_LINES,
DRAW_POINT_LIST,
DRAW_LINE_LIST,
DRAW_LINE_LOOP,
DRAW_LINE_STRIP,
DRAW_TRIANGLES,
DRAW_TRIANGLE_LIST,
DRAW_TRIANGLE_STRIP,
DRAW_TRIANGLE_FAN
} DrawMode;
} ModelDrawMode;
typedef struct {
ModelAttribute* attributes[MAX_DEFAULT_ATTRIBUTES];
ModelAttribute* indices;
ModelBlendData* blendShapes;
uint32_t blendShapeCount;
DrawMode mode;
ModelDrawMode mode;
uint32_t material;
uint32_t skin;
} ModelPrimitive;

View File

@ -826,7 +826,7 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO* io
gltfString key = NOM_STR(json, token);
if (STR_EQ(key, "primitives")) {
for (uint32_t j = (token++)->size; j > 0; j--, primitive++) {
primitive->mode = DRAW_TRIANGLES;
primitive->mode = DRAW_TRIANGLE_LIST;
primitive->material = ~0u;
for (int k2 = (token++)->size; k2 > 0; k2--) {
@ -838,11 +838,11 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO* io
lovrAssert(primitive->indices->type != U8, "Unsigned byte indices are not supported (must be unsigned shorts or unsigned ints)");
} else if (STR_EQ(key, "mode")) {
switch (NOM_INT(json, token)) {
case 0: primitive->mode = DRAW_POINTS; break;
case 1: primitive->mode = DRAW_LINES; break;
case 0: primitive->mode = DRAW_POINT_LIST; break;
case 1: primitive->mode = DRAW_LINE_LIST; break;
case 2: primitive->mode = DRAW_LINE_LOOP; break;
case 3: primitive->mode = DRAW_LINE_STRIP; break;
case 4: primitive->mode = DRAW_TRIANGLES; break;
case 4: primitive->mode = DRAW_TRIANGLE_LIST; break;
case 5: primitive->mode = DRAW_TRIANGLE_STRIP; break;
case 6: primitive->mode = DRAW_TRIANGLE_FAN; break;
default: lovrThrow("Unknown primitive mode");

View File

@ -362,7 +362,7 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source, ModelDataIO* io)
for (size_t i = 0; i < groups.length; i++) {
objGroup* group = &groups.data[i];
model->primitives[i] = (ModelPrimitive) {
.mode = DRAW_TRIANGLES,
.mode = DRAW_TRIANGLE_LIST,
.attributes = {
[ATTR_POSITION] = &model->attributes[0],
[ATTR_NORMAL] = &model->attributes[1],

View File

@ -33,7 +33,7 @@ static ModelData* lovrModelDataInitStlBinary(ModelData* model, Blob* source, Mod
model->attributes[0] = (ModelAttribute) { .count = vertexCount, .components = 3, .type = F32, .offset = 0 * sizeof(float) };
model->attributes[1] = (ModelAttribute) { .count = vertexCount, .components = 3, .type = F32, .offset = 3 * sizeof(float) };
model->primitives[0] = (ModelPrimitive) {
.mode = DRAW_TRIANGLES,
.mode = DRAW_TRIANGLE_LIST,
.material = ~0u,
.attributes = {
[ATTR_POSITION] = &model->attributes[0],

View File

@ -174,6 +174,25 @@ struct Font {
uint32_t atlasY;
};
struct Mesh {
uint32_t ref;
MeshStorage storage;
Buffer* vertexBuffer;
Buffer* indexBuffer;
uint32_t indexCount;
uint32_t dirtyVertices[2];
bool dirtyIndices;
void* vertices;
void* indices;
float bounds[6];
bool hasBounds;
DrawMode mode;
uint32_t drawStart;
uint32_t drawCount;
uint32_t baseVertex;
Material* material;
};
typedef struct {
float transform[16];
float cofactor[12];
@ -191,7 +210,7 @@ typedef enum {
typedef struct {
uint64_t hash;
MeshMode mode;
DrawMode mode;
DefaultShader shader;
Material* material;
float* transform;
@ -234,6 +253,7 @@ struct Model {
Buffer* indexBuffer;
Buffer* blendBuffer;
Buffer* skinBuffer;
Mesh** meshes;
Texture** textures;
Material** materials;
NodeTransform* localTransforms;
@ -392,7 +412,7 @@ typedef struct {
typedef struct {
bool dirty;
bool viewCull;
MeshMode mode;
DrawMode mode;
float color[4];
Buffer* lastVertexBuffer;
VertexFormat lastVertexFormat;
@ -1767,13 +1787,14 @@ static uint32_t lovrBufferInit(Buffer* buffer, const BufferInfo* info, size_t ch
memcpy(format, info->format, info->fieldCount * sizeof(DataField));
// Copy names, fixup children pointers
// Copy names, hash names, fixup children pointers
for (uint32_t i = 0; i < info->fieldCount; i++) {
if (format[i].name) {
size_t length = strlen(format[i].name);
memcpy(names, format[i].name, length);
names[length] = '\0';
format[i].name = names;
format[i].hash = (uint32_t) hash64(format[i].name, length);
names += length + 1;
}
@ -3610,6 +3631,331 @@ void lovrFontGetVertices(Font* font, ColoredString* strings, uint32_t count, flo
*material = font->material;
}
// Mesh
Mesh* lovrMeshCreate(const MeshInfo* info, void** vertices) {
const DataField* format = info->vertexBuffer ? info->vertexBuffer->info.format : info->format;
const DataField* attributes = format->childCount > 0 ? format->children : format;
uint32_t attributeCount = format->childCount > 0 ? format->childCount : 1;
lovrCheck(format, "Mesh vertex buffer must have been created with format information");
lovrCheck(format->length > 0, "Mesh vertex buffer must have an array format (length > 0)");
lovrCheck(format->stride <= state.limits.vertexBufferStride, "Mesh vertex buffer stride exceeds the vertexBufferStride limit of this GPU");
for (uint32_t i = 0; i < attributeCount; i++) {
const DataField* attribute = &attributes[i];
lovrCheck(attribute->offset < 256, "Max Mesh attribute offset is 255"); // Limited by 8 bit gpu_attribute offset
lovrCheck(attribute == format || attribute->length == 0, "Mesh attributes can not use array types");
lovrCheck(attribute == format || attribute->childCount == 0, "Mesh attributes can not use struct types");
lovrCheck(attribute->type < TYPE_MAT2 || attribute->type > TYPE_MAT4, "Currently, Mesh attributes can not use matrix types");
lovrCheck(attribute->type < TYPE_INDEX16 || attribute->type > TYPE_INDEX32, "Mesh attributes can not use index types");
}
Mesh* mesh = calloc(1, sizeof(Mesh));
lovrAssert(mesh, "Out of memory");
mesh->ref = 1;
mesh->storage = info->storage;
mesh->mode = DRAW_TRIANGLES;
if (info->vertexBuffer) {
mesh->vertexBuffer = info->vertexBuffer;
lovrRetain(mesh->vertexBuffer);
} else {
BufferInfo bufferInfo = { .format = info->format, .fieldCount = info->fieldCount };
mesh->vertexBuffer = lovrBufferCreate(&bufferInfo, mesh->storage == MESH_GPU ? vertices : NULL);
if (!vertices) {
lovrBufferClear(mesh->vertexBuffer, 0, ~0u);
}
if (mesh->storage == MESH_CPU) {
uint32_t size = mesh->vertexBuffer->info.size;
mesh->vertices = vertices ? malloc(size) : calloc(1, size);
lovrAssert(mesh->vertices, "Out of memory");
if (vertices) {
*vertices = mesh->vertices;
mesh->dirtyVertices[0] = 0;
mesh->dirtyVertices[1] = info->format->length;
} else {
mesh->dirtyVertices[0] = ~0u;
mesh->dirtyVertices[1] = 0;
}
}
}
return mesh;
}
void lovrMeshDestroy(void* ref) {
Mesh* mesh = ref;
lovrRelease(mesh->vertexBuffer, lovrBufferDestroy);
lovrRelease(mesh->indexBuffer, lovrBufferDestroy);
lovrRelease(mesh->material, lovrMaterialDestroy);
free(mesh->vertices);
free(mesh->indices);
free(mesh);
}
const DataField* lovrMeshGetVertexFormat(Mesh* mesh) {
return mesh->vertexBuffer->info.format;
}
Buffer* lovrMeshGetVertexBuffer(Mesh* mesh) {
return mesh->storage == MESH_CPU ? NULL : mesh->vertexBuffer;
}
Buffer* lovrMeshGetIndexBuffer(Mesh* mesh) {
return mesh->storage == MESH_CPU ? NULL : mesh->indexBuffer;
}
void lovrMeshSetIndexBuffer(Mesh* mesh, Buffer* buffer) {
lovrCheck(mesh->storage == MESH_GPU, "Mesh can only use a Buffer for indices if it was created with 'gpu' storage mode");
const DataField* format = buffer->info.format;
lovrCheck(format && format->length > 0, "Mesh index buffer must have an array format");
switch (format->type) {
case TYPE_U16:
case TYPE_INDEX16:
if (format->stride == 2 && format->offset == 0 && format->childCount == 0) break;
case TYPE_U32:
case TYPE_INDEX32:
if (format->stride == 4 && format->offset == 0 && format->childCount == 0) break;
default:
lovrThrow("Mesh index buffer must be a tightly packed array of u16, u32, index16, or index32 types");
}
lovrRelease(mesh->indexBuffer, lovrBufferDestroy);
mesh->indexBuffer = buffer;
mesh->indexCount = format->length;
lovrRetain(buffer);
}
void* lovrMeshGetVertices(Mesh* mesh, uint32_t index, uint32_t count) {
const DataField* format = lovrMeshGetVertexFormat(mesh);
if (count == ~0u) count = format->length - index;
lovrCheck(index < format->length && count <= format->length - index, "Mesh vertex range [%d,%d] overflows mesh capacity", index + 1, index + 1 + count - 1);
if (mesh->storage == MESH_CPU) {
return (char*) mesh->vertices + index * format->stride;
} else {
return lovrBufferGetData(mesh->vertexBuffer, index * format->stride, count * format->stride);
}
}
void* lovrMeshSetVertices(Mesh* mesh, uint32_t index, uint32_t count) {
const DataField* format = lovrMeshGetVertexFormat(mesh);
if (count == ~0u) count = format->length - index;
lovrCheck(index < format->length && count <= format->length - index, "Mesh vertex range [%d,%d] overflows mesh capacity", index + 1, index + 1 + count - 1);
if (mesh->storage == MESH_CPU) {
mesh->dirtyVertices[0] = MIN(mesh->dirtyVertices[0], index);
mesh->dirtyVertices[1] = MAX(mesh->dirtyVertices[1], index + count);
return (char*) mesh->vertices + index * format->stride;
} else {
return lovrBufferSetData(mesh->vertexBuffer, index * format->stride, count * format->stride);
}
}
void* lovrMeshGetIndices(Mesh* mesh, DataField* format) {
if (mesh->indexCount == 0 || !mesh->indexBuffer) {
return NULL;
}
*format = *mesh->indexBuffer->info.format;
format->length = mesh->indexCount;
if (mesh->storage == MESH_CPU) {
return mesh->indices;
} else {
return lovrBufferGetData(mesh->indexBuffer, 0, mesh->indexCount * format->stride);
}
}
void* lovrMeshSetIndices(Mesh* mesh, uint32_t count, DataType type) {
const DataField* format = mesh->indexBuffer ? mesh->indexBuffer->info.format : NULL;
mesh->indexCount = count;
mesh->dirtyIndices = true;
if (!mesh->indexBuffer || count > format->length || type != format->type) {
lovrRelease(mesh->indexBuffer, lovrBufferDestroy);
DataField field = { .type = type, .length = count };
BufferInfo info = { .fieldCount = 1, .format = &field };
if (mesh->storage == MESH_CPU) {
mesh->indexBuffer = lovrBufferCreate(&info, NULL);
mesh->indices = realloc(mesh->indices, count * mesh->indexBuffer->info.format->stride);
lovrAssert(mesh->indices, "Out of memory");
return mesh->indices;
} else {
void* data = NULL;
mesh->indexBuffer = lovrBufferCreate(&info, &data);
return data;
}
} else if (mesh->storage == MESH_CPU) {
return mesh->indices;
} else {
return lovrBufferSetData(mesh->indexBuffer, 0, count * format->stride);
}
}
static float* lovrMeshGetPositions(Mesh* mesh) {
if (mesh->storage == MESH_GPU) return NULL;
const DataField* format = lovrMeshGetVertexFormat(mesh);
const DataField* attributes = format->childCount > 0 ? format->children : format;
uint32_t attributeCount = format->childCount > 0 ? format->childCount : 1;
uint32_t positionHash = (uint32_t) hash64("VertexPosition", strlen("VertexPosition"));
for (uint32_t i = 0; i < attributeCount; i++) {
const DataField* attribute = &attributes[i];
if (attribute->type != TYPE_F32x3) continue;
if ((attribute->location == LOCATION_POSITION || attribute->hash == positionHash)) {
return (float*) ((char*) mesh->vertices + attribute->offset);
}
}
return NULL;
}
void lovrMeshGetTriangles(Mesh* mesh, float** vertices, uint32_t** indices, uint32_t* vertexCount, uint32_t* indexCount) {
float* position = lovrMeshGetPositions(mesh);
lovrCheck(mesh->storage == MESH_CPU, "Mesh storage mode must be 'cpu'");
lovrCheck(mesh->mode == DRAW_TRIANGLES, "Mesh draw mode must be 'triangles'");
lovrCheck(position, "Mesh has no VertexPosition attribute with vec3 type");
const DataField* format = lovrMeshGetVertexFormat(mesh);
*vertices = malloc(format->length * 3 * sizeof(float));
lovrAssert(*vertices, "Out of memory");
for (uint32_t i = 0; i < format->length; i++) {
vec3_init(*vertices, position);
position = (float*) ((char*) position + format->stride);
*vertices += 3;
}
if (mesh->indexCount > 0) {
*indexCount = mesh->indexCount;
*indices = malloc(*indexCount * sizeof(uint32_t));
lovrAssert(*indices, "Out of memory");
if (mesh->indexBuffer->info.format->type == TYPE_U16 || mesh->indexBuffer->info.format->type == TYPE_INDEX16) {
for (uint32_t i = 0; i < mesh->indexCount; i++) {
*indices[i] = (uint32_t) ((uint16_t*) mesh->indices)[i];
}
} else {
memcpy(*indices, mesh->indices, mesh->indexCount * sizeof(uint32_t));
}
} else {
*indexCount = format->length;
*indices = malloc(*indexCount * sizeof(uint32_t));
lovrAssert(*indices, "Out of memory");
lovrCheck(format->length >= 3 && format->length % 3 == 0, "Mesh vertex count must be divisible by 3");
for (uint32_t i = 0; i < format->length; i++) {
**indices = i;
*indices += 1;
}
}
}
bool lovrMeshGetBoundingBox(Mesh* mesh, float box[6]) {
box[0] = mesh->bounds[0] - mesh->bounds[3];
box[1] = mesh->bounds[1] - mesh->bounds[4];
box[2] = mesh->bounds[2] - mesh->bounds[5];
box[3] = mesh->bounds[0] + mesh->bounds[3];
box[4] = mesh->bounds[1] + mesh->bounds[4];
box[5] = mesh->bounds[2] + mesh->bounds[5];
return mesh->hasBounds;
}
void lovrMeshSetBoundingBox(Mesh* mesh, float box[6]) {
if (box) {
mesh->bounds[0] = (box[0] + box[3]) / 2.f;
mesh->bounds[1] = (box[1] + box[4]) / 2.f;
mesh->bounds[2] = (box[2] + box[5]) / 2.f;
mesh->bounds[3] = (box[3] - box[0]) / 2.f;
mesh->bounds[4] = (box[4] - box[1]) / 2.f;
mesh->bounds[5] = (box[5] - box[2]) / 2.f;
mesh->hasBounds = true;
} else {
mesh->hasBounds = false;
}
}
bool lovrMeshComputeBoundingBox(Mesh* mesh) {
const DataField* format = lovrMeshGetVertexFormat(mesh);
float* position = lovrMeshGetPositions(mesh);
if (!position) {
return false;
}
float box[6] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MIN, FLT_MIN, FLT_MIN };
for (uint32_t i = 0; i < format->length; i++, position = (float*) ((char*) position + format->stride)) {
box[0] = MIN(box[0], position[0]);
box[1] = MIN(box[1], position[1]);
box[2] = MIN(box[2], position[2]);
box[3] = MAX(box[3], position[0]);
box[4] = MAX(box[4], position[1]);
box[5] = MAX(box[5], position[2]);
}
lovrMeshSetBoundingBox(mesh, box);
return true;
}
DrawMode lovrMeshGetDrawMode(Mesh* mesh) {
return mesh->mode;
}
void lovrMeshSetDrawMode(Mesh* mesh, DrawMode mode) {
mesh->mode = mode;
}
void lovrMeshGetDrawRange(Mesh* mesh, uint32_t* start, uint32_t* count, uint32_t* offset) {
*start = mesh->drawStart;
*count = mesh->drawCount;
*offset = mesh->baseVertex;
}
void lovrMeshSetDrawRange(Mesh* mesh, uint32_t start, uint32_t count, uint32_t offset) {
uint32_t vertexCount = mesh->vertexBuffer->info.format->length;
uint32_t extent = mesh->indexCount > 0 ? mesh->indexCount : vertexCount;
lovrCheck(start < extent && count <= extent - start, "Invalid draw range [%d,%d]", start + 1, start + 1 + count);
lovrCheck(offset < vertexCount, "Mesh vertex offset must be less than the vertex count");
mesh->drawStart = start;
mesh->drawCount = count;
mesh->baseVertex = offset;
}
Material* lovrMeshGetMaterial(Mesh* mesh) {
return mesh->material;
}
void lovrMeshSetMaterial(Mesh* mesh, Material* material) {
lovrRelease(mesh->material, lovrMaterialDestroy);
mesh->material = material;
lovrRetain(material);
}
static void lovrMeshFlush(Mesh* mesh) {
if (mesh->storage == MESH_GPU) {
return;
}
if (mesh->dirtyVertices[1] > mesh->dirtyVertices[0]) {
uint32_t stride = mesh->vertexBuffer->info.format->stride;
uint32_t offset = mesh->dirtyVertices[0] * stride;
uint32_t extent = (mesh->dirtyVertices[1] - mesh->dirtyVertices[0]) * stride;
void* data = lovrBufferSetData(mesh->vertexBuffer, offset, extent);
memcpy(data, (char*) mesh->vertices + offset, extent);
mesh->dirtyVertices[0] = ~0u;
mesh->dirtyVertices[1] = 0;
}
if (mesh->dirtyIndices) {
uint32_t stride = mesh->indexBuffer->info.format->stride;
void* data = lovrBufferSetData(mesh->indexBuffer, 0, mesh->indexCount * stride);
memcpy(data, mesh->indices, mesh->indexCount * stride);
mesh->dirtyIndices = false;
}
}
// Model
Model* lovrModelCreate(const ModelInfo* info) {
@ -3798,9 +4144,9 @@ Model* lovrModelCreate(const ModelInfo* info) {
DrawInfo* draw = &model->draws[primitiveOrder[i] & ~0u];
switch (primitive->mode) {
case DRAW_POINTS: draw->mode = MESH_POINTS; break;
case DRAW_LINES: draw->mode = MESH_LINES; break;
case DRAW_TRIANGLES: draw->mode = MESH_TRIANGLES; break;
case DRAW_POINT_LIST: draw->mode = DRAW_POINTS; break;
case DRAW_LINE_LIST: draw->mode = DRAW_LINES; break;
case DRAW_TRIANGLE_LIST: draw->mode = DRAW_TRIANGLES; break;
default: lovrThrow("Model uses an unsupported draw mode (lineloop, linestrip, strip, fan)");
}
@ -3977,6 +4323,7 @@ void lovrModelDestroy(void* ref) {
lovrRelease(model->vertexBuffer, lovrBufferDestroy);
free(model->localTransforms);
free(model->globalTransforms);
free(model->meshes);
free(model->draws);
free(model);
return;
@ -4003,6 +4350,7 @@ void lovrModelDestroy(void* ref) {
free(model->boundingBoxes);
free(model->blendShapeWeights);
free(model->blendGroups);
free(model->meshes);
free(model->draws);
free(model);
}
@ -4011,23 +4359,6 @@ const ModelInfo* lovrModelGetInfo(Model* model) {
return &model->info;
}
uint32_t lovrModelGetNodeDrawCount(Model* model, uint32_t node) {
ModelData* data = model->info.data;
return data->nodes[node].primitiveCount;
}
void lovrModelGetNodeDraw(Model* model, uint32_t node, uint32_t index, ModelDraw* mesh) {
ModelData* data = model->info.data;
lovrCheck(index < data->nodes[node].primitiveCount, "Invalid model node draw index %d", index + 1);
DrawInfo* draw = &model->draws[data->nodes[node].primitiveIndex + index];
mesh->mode = draw->mode;
mesh->material = draw->material;
mesh->start = draw->start;
mesh->count = draw->count;
mesh->base = draw->base;
mesh->indexed = draw->index.buffer;
}
void lovrModelResetNodeTransforms(Model* model) {
ModelData* data = model->info.data;
for (uint32_t i = 0; i < data->nodeCount; i++) {
@ -4196,18 +4527,6 @@ void lovrModelSetNodeTransform(Model* model, uint32_t node, float position[3], f
model->transformsDirty = true;
}
Texture* lovrModelGetTexture(Model* model, uint32_t index) {
ModelData* data = model->info.data;
lovrAssert(index < data->imageCount, "Invalid texture index '%d' (Model has %d texture%s)", index, data->imageCount, data->imageCount == 1 ? "" : "s");
return model->textures[index];
}
Material* lovrModelGetMaterial(Model* model, uint32_t index) {
ModelData* data = model->info.data;
lovrAssert(index < data->materialCount, "Invalid material index '%d' (Model has %d material%s)", index, data->materialCount, data->materialCount == 1 ? "" : "s");
return model->materials[index];
}
Buffer* lovrModelGetVertexBuffer(Model* model) {
return model->rawVertexBuffer;
}
@ -4216,6 +4535,43 @@ Buffer* lovrModelGetIndexBuffer(Model* model) {
return model->indexBuffer;
}
Mesh* lovrModelGetMesh(Model* model, uint32_t index) {
ModelData* data = model->info.data;
lovrCheck(index < data->primitiveCount, "Invalid mesh index '%d' (Model has %d mesh%s)", index + 1, data->primitiveCount, data->primitiveCount == 1 ? "" : "es");
if (!model->meshes) {
model->meshes = calloc(data->primitiveCount, sizeof(Mesh*));
lovrAssert(model->meshes, "Out of memory");
}
if (!model->meshes[index]) {
DrawInfo* draw = &model->draws[index];
MeshInfo info = { .vertexBuffer = model->vertexBuffer, .storage = MESH_GPU };
Mesh* mesh = lovrMeshCreate(&info, NULL);
if (draw->index.buffer) lovrMeshSetIndexBuffer(mesh, model->indexBuffer);
lovrMeshSetDrawMode(mesh, draw->mode);
lovrMeshSetDrawRange(mesh, draw->start, draw->count, draw->base);
lovrMeshSetMaterial(mesh, draw->material);
memcpy(mesh->bounds, draw->bounds, sizeof(mesh->bounds));
mesh->hasBounds = true;
model->meshes[index] = mesh;
}
return model->meshes[index];
}
Texture* lovrModelGetTexture(Model* model, uint32_t index) {
ModelData* data = model->info.data;
lovrAssert(index < data->imageCount, "Invalid texture index '%d' (Model has %d texture%s)", index + 1, data->imageCount, data->imageCount == 1 ? "" : "s");
return model->textures[index];
}
Material* lovrModelGetMaterial(Model* model, uint32_t index) {
ModelData* data = model->info.data;
lovrAssert(index < data->materialCount, "Invalid material index '%d' (Model has %d material%s)", index + 1, data->materialCount, data->materialCount == 1 ? "" : "s");
return model->materials[index];
}
static void lovrModelAnimateVertices(Model* model) {
ModelData* data = model->info.data;
@ -4622,7 +4978,7 @@ void lovrPassReset(Pass* pass) {
pass->pipelineIndex = 0;
memset(pass->pipeline, 0, sizeof(Pipeline));
pass->pipeline->mode = MESH_TRIANGLES;
pass->pipeline->mode = DRAW_TRIANGLES;
pass->pipeline->lastVertexFormat = ~0u;
pass->pipeline->color[0] = 1.f;
pass->pipeline->color[1] = 1.f;
@ -5262,7 +5618,7 @@ void lovrPassSetMaterial(Pass* pass, Material* material, Texture* texture) {
}
}
void lovrPassSetMeshMode(Pass* pass, MeshMode mode) {
void lovrPassSetMeshMode(Pass* pass, DrawMode mode) {
pass->pipeline->mode = mode;
}
@ -5529,8 +5885,8 @@ static void lovrPassResolvePipeline(Pass* pass, DrawInfo* info, Draw* draw) {
pipeline->lastVertexBuffer = info->vertex.buffer;
pipeline->dirty = true;
DataField* format = info->vertex.buffer->info.format;
DataField* fields = format->childCount > 0 ? format->children : format;
const DataField* format = info->vertex.buffer->info.format;
const DataField* fields = format->childCount > 0 ? format->children : format;
uint32_t fieldCount = format->childCount > 0 ? format->childCount : 1;
pipeline->info.vertex.bufferCount = 2;
@ -5745,7 +6101,7 @@ void lovrPassDraw(Pass* pass, DrawInfo* info) {
void lovrPassPoints(Pass* pass, uint32_t count, float** points) {
lovrPassDraw(pass, &(DrawInfo) {
.mode = MESH_POINTS,
.mode = DRAW_POINTS,
.vertex.format = VERTEX_POINT,
.vertex.pointer = (void**) points,
.vertex.count = count
@ -5758,7 +6114,7 @@ void lovrPassLine(Pass* pass, uint32_t count, float** points) {
uint16_t* indices;
lovrPassDraw(pass, &(DrawInfo) {
.mode = MESH_LINES,
.mode = DRAW_LINES,
.vertex.format = VERTEX_POINT,
.vertex.pointer = (void**) points,
.vertex.count = count,
@ -5785,7 +6141,7 @@ void lovrPassPlane(Pass* pass, float* transform, DrawStyle style, uint32_t cols,
lovrPassDraw(pass, &(DrawInfo) {
.hash = hash64(key, sizeof(key)),
.mode = MESH_LINES,
.mode = DRAW_LINES,
.transform = transform,
.bounds = (float[6]) { 0.f, 0.f, 0.f, .5f, .5f, 0.f },
.vertex.pointer = (void**) &vertices,
@ -5798,7 +6154,7 @@ void lovrPassPlane(Pass* pass, float* transform, DrawStyle style, uint32_t cols,
lovrPassDraw(pass, &(DrawInfo) {
.hash = hash64(key, sizeof(key)),
.mode = MESH_TRIANGLES,
.mode = DRAW_TRIANGLES,
.transform = transform,
.bounds = (float[6]) { 0.f, 0.f, 0.f, .5f, .5f, 0.f },
.vertex.pointer = (void**) &vertices,
@ -5884,7 +6240,7 @@ void lovrPassRoundrect(Pass* pass, float* transform, float r, uint32_t segments)
uint16_t* indices;
lovrPassDraw(pass, &(DrawInfo) {
.mode = MESH_TRIANGLES,
.mode = DRAW_TRIANGLES,
.transform = transform,
.bounds = (float[6]) { 0.f, 0.f, 0.f, .5f, .5f, .5f },
.vertex.pointer = (void**) &vertices,
@ -6013,7 +6369,7 @@ void lovrPassBox(Pass* pass, float* transform, DrawStyle style) {
lovrPassDraw(pass, &(DrawInfo) {
.hash = hash64(key, sizeof(key)),
.mode = MESH_LINES,
.mode = DRAW_LINES,
.transform = transform,
.bounds = (float[6]) { 0.f, 0.f, 0.f, .5f, .5f, .5f },
.vertex.pointer = (void**) &vertices,
@ -6065,7 +6421,7 @@ void lovrPassBox(Pass* pass, float* transform, DrawStyle style) {
lovrPassDraw(pass, &(DrawInfo) {
.hash = hash64(key, sizeof(key)),
.mode = MESH_TRIANGLES,
.mode = DRAW_TRIANGLES,
.transform = transform,
.bounds = (float[6]) { 0.f, 0.f, 0.f, .5f, .5f, .5f },
.vertex.pointer = (void**) &vertices,
@ -6097,7 +6453,7 @@ void lovrPassCircle(Pass* pass, float* transform, DrawStyle style, float angle1,
lovrPassDraw(pass, &(DrawInfo) {
.hash = hash64(key, sizeof(key)),
.mode = MESH_LINES,
.mode = DRAW_LINES,
.transform = transform,
.bounds = (float[6]) { 0.f, 0.f, 0.f, 1.f, 1.f, 0.f },
.vertex.pointer = (void**) &vertices,
@ -6115,7 +6471,7 @@ void lovrPassCircle(Pass* pass, float* transform, DrawStyle style, float angle1,
lovrPassDraw(pass, &(DrawInfo) {
.hash = hash64(key, sizeof(key)),
.mode = MESH_TRIANGLES,
.mode = DRAW_TRIANGLES,
.transform = transform,
.bounds = (float[6]) { 0.f, 0.f, 0.f, 1.f, 1.f, 0.f },
.vertex.pointer = (void**) &vertices,
@ -6165,7 +6521,7 @@ void lovrPassSphere(Pass* pass, float* transform, uint32_t segmentsH, uint32_t s
lovrPassDraw(pass, &(DrawInfo) {
.hash = hash64(key, sizeof(key)),
.mode = MESH_TRIANGLES,
.mode = DRAW_TRIANGLES,
.transform = transform,
.bounds = (float[6]) { 0.f, 0.f, 0.f, 1.f, 1.f, 1.f },
.vertex.pointer = (void**) &vertices,
@ -6251,7 +6607,7 @@ void lovrPassCylinder(Pass* pass, float* transform, bool capped, float angle1, f
lovrPassDraw(pass, &(DrawInfo) {
.hash = hash64(key, sizeof(key)),
.mode = MESH_TRIANGLES,
.mode = DRAW_TRIANGLES,
.transform = transform,
.bounds = (float[6]) { 0.f, 0.f, 0.f, 1.f, 1.f, .5f },
.vertex.pointer = (void**) &vertices,
@ -6324,7 +6680,7 @@ void lovrPassCone(Pass* pass, float* transform, uint32_t segments) {
lovrPassDraw(pass, &(DrawInfo) {
.hash = hash64(key, sizeof(key)),
.mode = MESH_TRIANGLES,
.mode = DRAW_TRIANGLES,
.transform = transform,
.bounds = (float[6]) { 0.0f, 0.f, -.5f, 1.f, 1.f, .5f },
.vertex.pointer = (void**) &vertices,
@ -6389,7 +6745,7 @@ void lovrPassCapsule(Pass* pass, float* transform, uint32_t segments) {
lovrPassDraw(pass, &(DrawInfo) {
.hash = hash64(key, sizeof(key)),
.mode = MESH_TRIANGLES,
.mode = DRAW_TRIANGLES,
.transform = transform,
.bounds = (float[6]) { 0.f, 0.f, 0.f, radius, radius, length + radius },
.vertex.pointer = (void**) &vertices,
@ -6482,7 +6838,7 @@ void lovrPassTorus(Pass* pass, float* transform, uint32_t segmentsT, uint32_t se
lovrPassDraw(pass, &(DrawInfo) {
.hash = hash64(key, sizeof(key)),
.mode = MESH_TRIANGLES,
.mode = DRAW_TRIANGLES,
.transform = transform,
.bounds = (float[6]) { 0.f, 0.f, 0.f, radius + thickness, radius + thickness, thickness },
.vertex.pointer = (void**) &vertices,
@ -6553,7 +6909,7 @@ void lovrPassText(Pass* pass, ColoredString* strings, uint32_t count, float* tra
GlyphVertex* vertexPointer;
uint16_t* indices;
lovrPassDraw(pass, &(DrawInfo) {
.mode = MESH_TRIANGLES,
.mode = DRAW_TRIANGLES,
.shader = SHADER_FONT,
.material = font->material,
.transform = transform,
@ -6577,7 +6933,7 @@ void lovrPassText(Pass* pass, ColoredString* strings, uint32_t count, float* tra
void lovrPassSkybox(Pass* pass, Texture* texture) {
lovrPassDraw(pass, &(DrawInfo) {
.mode = MESH_TRIANGLES,
.mode = DRAW_TRIANGLES,
.shader = texture->info.type == TEXTURE_2D ? SHADER_EQUIRECT : SHADER_CUBEMAP,
.material = lovrTextureGetMaterial(texture),
.vertex.format = VERTEX_EMPTY,
@ -6587,7 +6943,7 @@ void lovrPassSkybox(Pass* pass, Texture* texture) {
void lovrPassFill(Pass* pass, Texture* texture) {
lovrPassDraw(pass, &(DrawInfo) {
.mode = MESH_TRIANGLES,
.mode = DRAW_TRIANGLES,
.shader = texture && texture->info.type == TEXTURE_ARRAY ? SHADER_FILL_ARRAY : SHADER_FILL_2D,
.material = texture ? lovrTextureGetMaterial(texture) : NULL,
.vertex.format = VERTEX_EMPTY,
@ -6603,7 +6959,7 @@ void lovrPassMonkey(Pass* pass, float* transform) {
lovrPassDraw(pass, &(DrawInfo) {
.hash = hash64(key, sizeof(key)),
.mode = MESH_TRIANGLES,
.mode = DRAW_TRIANGLES,
.vertex.pointer = (void**) &vertices,
.vertex.count = vertexCount,
.index.pointer = (void**) &indices,
@ -6631,7 +6987,27 @@ void lovrPassMonkey(Pass* pass, float* transform) {
memcpy(indices, monkey_indices, sizeof(monkey_indices));
}
static void renderNode(Pass* pass, Model* model, uint32_t index, bool recurse, uint32_t instances) {
void lovrPassDrawMesh(Pass* pass, Mesh* mesh, float* transform, uint32_t instances) {
uint32_t extent = mesh->indexCount > 0 ? mesh->indexCount : mesh->vertexBuffer->info.format->length;
uint32_t start = MIN(mesh->drawStart, extent - 1);
uint32_t count = mesh->drawCount > 0 ? MIN(mesh->drawCount, extent - start) : extent - start;
lovrMeshFlush(mesh);
lovrPassDraw(pass, &(DrawInfo) {
.mode = mesh->mode,
.transform = transform,
.bounds = mesh->hasBounds ? mesh->bounds : NULL,
.material = mesh->material,
.vertex.buffer = mesh->vertexBuffer,
.index.buffer = mesh->indexBuffer,
.start = start,
.count = count,
.instances = instances
});
}
static void drawNode(Pass* pass, Model* model, uint32_t index, uint32_t instances) {
ModelNode* node = &model->info.data->nodes[index];
mat4 globalTransform = model->globalTransforms + 16 * index;
@ -6642,14 +7018,12 @@ static void renderNode(Pass* pass, Model* model, uint32_t index, bool recurse, u
lovrPassDraw(pass, &draw);
}
if (recurse) {
for (uint32_t i = 0; i < node->childCount; i++) {
renderNode(pass, model, node->children[i], true, instances);
}
for (uint32_t i = 0; i < node->childCount; i++) {
drawNode(pass, model, node->children[i], instances);
}
}
void lovrPassDrawModel(Pass* pass, Model* model, float* transform, uint32_t node, bool recurse, uint32_t instances) {
void lovrPassDrawModel(Pass* pass, Model* model, float* transform, uint32_t instances) {
lovrModelAnimateVertices(model);
if (model->transformsDirty) {
@ -6657,13 +7031,9 @@ void lovrPassDrawModel(Pass* pass, Model* model, float* transform, uint32_t node
model->transformsDirty = false;
}
if (node == ~0u) {
node = model->info.data->rootNode;
}
lovrPassPush(pass, STACK_TRANSFORM);
lovrPassTransform(pass, transform);
renderNode(pass, model, node, recurse, instances);
drawNode(pass, model, model->info.data->rootNode, instances);
lovrPassPop(pass, STACK_TRANSFORM);
}
@ -6683,7 +7053,7 @@ void lovrPassDrawTexture(Pass* pass, Texture* texture, float* transform) {
lovrPassDraw(pass, &(DrawInfo) {
.hash = hash64(key, sizeof(key)),
.mode = MESH_TRIANGLES,
.mode = DRAW_TRIANGLES,
.transform = transform,
.material = lovrTextureGetMaterial(texture),
.vertex.pointer = (void**) &vertices,

View File

@ -15,6 +15,7 @@ typedef struct Sampler Sampler;
typedef struct Shader Shader;
typedef struct Material Material;
typedef struct Font Font;
typedef struct Mesh Mesh;
typedef struct Model Model;
typedef struct Readback Readback;
typedef struct Pass Pass;
@ -172,7 +173,7 @@ typedef struct DataField {
typedef struct {
uint32_t size;
DataField* format;
const DataField* format;
uint32_t fieldCount;
DataLayout layout;
const char* label;
@ -417,6 +418,47 @@ float lovrFontGetWidth(Font* font, ColoredString* strings, uint32_t count);
void lovrFontGetLines(Font* font, ColoredString* strings, uint32_t count, float wrap, void (*callback)(void* context, const char* string, size_t length), void* context);
void lovrFontGetVertices(Font* font, ColoredString* strings, uint32_t count, float wrap, HorizontalAlign halign, VerticalAlign valign, GlyphVertex* vertices, uint32_t* glyphCount, uint32_t* lineCount, Material** material, bool flip);
// Mesh
typedef enum {
MESH_CPU,
MESH_GPU
} MeshStorage;
typedef enum {
DRAW_POINTS,
DRAW_LINES,
DRAW_TRIANGLES
} DrawMode;
typedef struct {
uint32_t fieldCount;
DataField format[16];
Buffer* vertexBuffer;
MeshStorage storage;
} MeshInfo;
Mesh* lovrMeshCreate(const MeshInfo* info, void** data);
void lovrMeshDestroy(void* ref);
const DataField* lovrMeshGetVertexFormat(Mesh* mesh);
Buffer* lovrMeshGetVertexBuffer(Mesh* mesh);
Buffer* lovrMeshGetIndexBuffer(Mesh* mesh);
void lovrMeshSetIndexBuffer(Mesh* mesh, Buffer* buffer);
void* lovrMeshGetVertices(Mesh* mesh, uint32_t index, uint32_t count);
void* lovrMeshSetVertices(Mesh* mesh, uint32_t index, uint32_t count);
void* lovrMeshGetIndices(Mesh* mesh, DataField* format);
void* lovrMeshSetIndices(Mesh* mesh, uint32_t count, DataType type);
void lovrMeshGetTriangles(Mesh* mesh, float** vertices, uint32_t** indices, uint32_t* vertexCount, uint32_t* indexCount);
bool lovrMeshGetBoundingBox(Mesh* mesh, float box[6]);
void lovrMeshSetBoundingBox(Mesh* mesh, float box[6]);
bool lovrMeshComputeBoundingBox(Mesh* mesh);
DrawMode lovrMeshGetDrawMode(Mesh* mesh);
void lovrMeshSetDrawMode(Mesh* mesh, DrawMode mode);
void lovrMeshGetDrawRange(Mesh* mesh, uint32_t* start, uint32_t* count, uint32_t* offset);
void lovrMeshSetDrawRange(Mesh* mesh, uint32_t start, uint32_t count, uint32_t offset);
Material* lovrMeshGetMaterial(Mesh* mesh);
void lovrMeshSetMaterial(Mesh* mesh, Material* material);
// Model
typedef struct {
@ -430,37 +472,21 @@ typedef enum {
ORIGIN_PARENT
} OriginType;
typedef enum {
MESH_POINTS,
MESH_LINES,
MESH_TRIANGLES
} MeshMode;
typedef struct {
MeshMode mode;
Material* material;
uint32_t start;
uint32_t count;
uint32_t base;
bool indexed;
} ModelDraw;
Model* lovrModelCreate(const ModelInfo* info);
Model* lovrModelClone(Model* model);
void lovrModelDestroy(void* ref);
const ModelInfo* lovrModelGetInfo(Model* model);
uint32_t lovrModelGetNodeDrawCount(Model* model, uint32_t node);
void lovrModelGetNodeDraw(Model* model, uint32_t node, uint32_t index, ModelDraw* draw);
void lovrModelResetNodeTransforms(Model* model);
void lovrModelAnimate(Model* model, uint32_t animationIndex, float time, float alpha);
float lovrModelGetBlendShapeWeight(Model* model, uint32_t index);
void lovrModelSetBlendShapeWeight(Model* model, uint32_t index, float weight);
void lovrModelGetNodeTransform(Model* model, uint32_t node, float position[3], float scale[3], float rotation[4], OriginType origin);
void lovrModelSetNodeTransform(Model* model, uint32_t node, float position[3], float scale[3], float rotation[4], float alpha);
Texture* lovrModelGetTexture(Model* model, uint32_t index);
Material* lovrModelGetMaterial(Model* model, uint32_t index);
Buffer* lovrModelGetVertexBuffer(Model* model);
Buffer* lovrModelGetIndexBuffer(Model* model);
Mesh* lovrModelGetMesh(Model* model, uint32_t index);
Texture* lovrModelGetTexture(Model* model, uint32_t index);
Material* lovrModelGetMaterial(Model* model, uint32_t index);
// Readback
@ -584,7 +610,7 @@ void lovrPassSetDepthClamp(Pass* pass, bool clamp);
void lovrPassSetFaceCull(Pass* pass, CullMode mode);
void lovrPassSetFont(Pass* pass, Font* font);
void lovrPassSetMaterial(Pass* pass, Material* material, Texture* texture);
void lovrPassSetMeshMode(Pass* pass, MeshMode mode);
void lovrPassSetMeshMode(Pass* pass, DrawMode mode);
void lovrPassSetSampler(Pass* pass, Sampler* sampler);
void lovrPassSetShader(Pass* pass, Shader* shader);
void lovrPassSetStencilTest(Pass* pass, CompareMode test, uint8_t value, uint8_t mask);
@ -613,7 +639,8 @@ void lovrPassText(Pass* pass, ColoredString* strings, uint32_t count, float* tra
void lovrPassSkybox(Pass* pass, Texture* texture);
void lovrPassFill(Pass* pass, Texture* texture);
void lovrPassMonkey(Pass* pass, float* transform);
void lovrPassDrawModel(Pass* pass, Model* model, float* transform, uint32_t node, bool recurse, uint32_t instances);
void lovrPassDrawModel(Pass* pass, Model* model, float* transform, uint32_t instances);
void lovrPassDrawMesh(Pass* pass, Mesh* mesh, float* transform, uint32_t instances);
void lovrPassDrawTexture(Pass* pass, Texture* texture, float* transform);
void lovrPassMesh(Pass* pass, Buffer* vertices, Buffer* indices, float* transform, uint32_t start, uint32_t count, uint32_t instances, uint32_t base);
void lovrPassMeshIndirect(Pass* pass, Buffer* vertices, Buffer* indices, Buffer* indirect, uint32_t count, uint32_t offset, uint32_t stride);

View File

@ -2063,7 +2063,7 @@ static ModelData* openxr_newModelDataFB(XrHandTrackerEXT tracker, bool animated)
model->attributes[5] = (ModelAttribute) { .buffer = 5, .type = U16, .count = indexCount };
model->primitives[0] = (ModelPrimitive) {
.mode = DRAW_TRIANGLES,
.mode = DRAW_TRIANGLE_LIST,
.attributes = {
[ATTR_POSITION] = &model->attributes[0],
[ATTR_NORMAL] = &model->attributes[1],