mirror of https://github.com/bjornbytes/lovr.git
291 lines
8.9 KiB
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 }
|
|
};
|