lovr/src/api/l_graphics_mesh.c

291 lines
8.9 KiB
C

#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);
lua_createtable(L, (int) format->fieldCount, 0);
for (uint32_t i = 0; i < format->fieldCount; i++) {
const DataField* attribute = &format->fields[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_pushinteger(L, attribute->offset);
lua_rawseti(L, -2, 3);
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);
void* data = lovrMeshGetVertices(mesh, index, count);
const DataField* format = lovrMeshGetVertexFormat(mesh);
return luax_pushbufferdata(L, format, count == ~0u ? format->length - index : count, data);
}
static int l_lovrMeshSetVertices(lua_State* L) {
Blob* blob = NULL;
Mesh* mesh = luax_checktype(L, 1, Mesh);
const DataField* format = lovrMeshGetVertexFormat(mesh);
uint32_t index = luax_optu32(L, 3, 1) - 1;
if ((blob = luax_totype(L, 2, Blob)) != NULL) {
uint32_t limit = (uint32_t) MIN(blob->size / format->stride, format->length - index);
uint32_t count = luax_optu32(L, 4, limit);
lovrCheck(blob->size / format->stride >= count, "Tried to read past the end of the Blob");
void* data = lovrMeshSetVertices(mesh, index, count);
memcpy(data, blob->data, count * format->stride);
} else if (lua_istable(L, 2)) {
uint32_t length = luax_len(L, 2);
uint32_t limit = MIN(length, format->length - index);
uint32_t count = luax_optu32(L, 4, limit);
lovrCheck(length <= limit, "Table does not have enough data to set %d items", count);
void* data = lovrMeshSetVertices(mesh, index, count);
luax_checkbufferdata(L, 2, format, data);
} else {
return luax_typeerror(L, 2, "table or Blob");
}
return 0;
}
static int l_lovrMeshGetIndices(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
uint32_t count;
DataType type;
void* data = lovrMeshGetIndices(mesh, &count, &type);
if (!data) {
lua_pushnil(L);
return 1;
}
uint16_t* u16 = data;
uint32_t* u32 = data;
lua_createtable(L, (int) count, 0);
for (uint32_t i = 0; i < count; i++) {
switch (type) {
case TYPE_U16: lua_pushinteger(L, u16[i]); break;
case TYPE_U32: lua_pushinteger(L, u32[i]); break;
case TYPE_INDEX16: lua_pushinteger(L, u16[i] + 1); break;
case TYPE_INDEX32: lua_pushinteger(L, u32[i] + 1); break;
default: lovrUnreachable();
}
lua_rawseti(L, -2, i + 1);
}
return 1;
}
static int l_lovrMeshSetIndices(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
const DataField* format = lovrMeshGetVertexFormat(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);
if (format->length > 0xffff) {
uint32_t* data = lovrMeshSetIndices(mesh, count, TYPE_INDEX32);
for (uint32_t i = 0; i < count; i++) {
lua_rawgeti(L, 2, i + 1);
lua_Integer x = lua_tointeger(L, -1);
lovrCheck(x > 0 && x <= format->length, "Mesh index #%d is out of range", i + 1);
data[i] = x - 1;
lua_pop(L, 1);
}
} else {
uint16_t* data = lovrMeshSetIndices(mesh, count, TYPE_INDEX16);
for (uint32_t i = 0; i < count; i++) {
lua_rawgeti(L, 2, i + 1);
lua_Integer x = lua_tointeger(L, -1);
lovrCheck(x > 0 && x <= format->length, "Mesh index #%d is out of range", i + 1);
data[i] = x - 1;
lua_pop(L, 1);
}
}
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 = (uint32_t) MIN(blob->size / stride, UINT32_MAX);
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 3;
}
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_optmaterial(L, 2);
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 }
};