mirror of https://github.com/bjornbytes/lovr.git
WIP;
This commit is contained in:
parent
5c322d3403
commit
4892d228b3
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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[];
|
||||
|
|
|
@ -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 }
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 }
|
||||
};
|
|
@ -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 }
|
||||
};
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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],
|
||||
|
|
Loading…
Reference in New Issue