lovr/src/api/types/mesh.c

372 lines
11 KiB
C
Raw Normal View History

2017-03-11 22:13:49 +00:00
#include "api/lovr.h"
void luax_checkmeshformat(lua_State* L, int index, MeshFormat* format) {
if (!lua_istable(L, index)) {
return;
}
int length = lua_objlen(L, index);
for (int i = 0; i < length; i++) {
lua_rawgeti(L, index, i + 1);
if (!lua_istable(L, -1) || lua_objlen(L, -1) != 3) {
luaL_error(L, "Expected vertex format specified as tables containing name, data type, and size");
return;
}
lua_rawgeti(L, -1, 1);
lua_rawgeti(L, -2, 2);
lua_rawgeti(L, -3, 3);
const char* name = lua_tostring(L, -3);
MeshAttributeType* type = (MeshAttributeType*) luax_checkenum(L, -2, &MeshAttributeTypes, "mesh attribute type");
int count = lua_tointeger(L, -1);
MeshAttribute attribute = { .name = name, .type = *type, .count = count };
vec_push(format, attribute);
lua_pop(L, 4);
}
}
int l_lovrMeshDraw(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
float transform[16];
luax_readtransform(L, 2, transform);
lovrMeshDraw(mesh, transform);
return 0;
}
int l_lovrMeshGetVertexFormat(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
MeshFormat format = lovrMeshGetVertexFormat(mesh);
lua_newtable(L);
for (int i = 0; i < format.length; i++) {
MeshAttribute attribute = format.data[i];
lua_newtable(L);
// Name
lua_pushstring(L, attribute.name);
lua_rawseti(L, -2, 1);
// Type
luax_pushenum(L, &MeshAttributeTypes, attribute.type);
lua_rawseti(L, -2, 2);
// Count
lua_pushinteger(L, attribute.count);
lua_rawseti(L, -2, 3);
lua_rawseti(L, -2, i + 1);
}
return 1;
}
int l_lovrMeshGetDrawMode(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
luax_pushenum(L, &MeshDrawModes, lovrMeshGetDrawMode(mesh));
return 1;
}
int l_lovrMeshSetDrawMode(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
MeshDrawMode* drawMode = (MeshDrawMode*) luax_checkenum(L, 2, &MeshDrawModes, "mesh draw mode");
lovrMeshSetDrawMode(mesh, *drawMode);
return 0;
}
int l_lovrMeshGetVertexCount(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
lua_pushnumber(L, lovrMeshGetVertexCount(mesh));
return 1;
}
int l_lovrMeshGetVertex(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
int index = luaL_checkint(L, 2) - 1;
char* vertex = lovrMeshGetScratchVertex(mesh);
lovrMeshGetVertex(mesh, index, vertex);
MeshFormat format = lovrMeshGetVertexFormat(mesh);
int total = 0;
for (int i = 0; i < format.length; i++) {
MeshAttribute attribute = format.data[i];
total += attribute.count;
for (int j = 0; j < attribute.count; j++) {
switch (attribute.type) {
case MESH_FLOAT: lua_pushnumber(L, *((float*) vertex)); break;
case MESH_BYTE: lua_pushnumber(L, *((unsigned char*) vertex)); break;
case MESH_INT: lua_pushnumber(L, *((int*) vertex)); break;
}
vertex += sizeof(attribute.type);
}
}
return total;
}
int l_lovrMeshSetVertex(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
int index = luaL_checkint(L, 2) - 1;
MeshFormat format = lovrMeshGetVertexFormat(mesh);
char* vertex = lovrMeshGetScratchVertex(mesh);
if (index < 0 || index >= mesh->size) {
return luaL_error(L, "Invalid mesh vertex index: %d", index + 1);
}
// Unwrap table
int arg = 3;
if (lua_istable(L, 3)) {
arg++;
for (size_t i = 0; i < lua_objlen(L, 3); i++) {
lua_rawgeti(L, 3, i + 1);
}
}
for (int i = 0; i < format.length; i++) {
MeshAttribute attribute = format.data[i];
for (int j = 0; j < attribute.count; j++) {
switch (attribute.type) {
case MESH_FLOAT: *((float*) vertex) = luaL_optnumber(L, arg++, 0.f); break;
case MESH_BYTE: *((unsigned char*) vertex) = luaL_optint(L, arg++, 255); break;
case MESH_INT: *((int*) vertex) = luaL_optint(L, arg++, 0); break;
}
vertex += sizeof(attribute.type);
}
}
lovrMeshSetVertex(mesh, index, lovrMeshGetScratchVertex(mesh));
return 0;
}
int l_lovrMeshGetVertexAttribute(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
int vertexIndex = luaL_checkint(L, 2) - 1;
int attributeIndex = luaL_checkint(L, 3) - 1;
char* vertex = lovrMeshGetScratchVertex(mesh);
lovrMeshGetVertex(mesh, vertexIndex, vertex);
MeshFormat format = lovrMeshGetVertexFormat(mesh);
if (vertexIndex < 0 || vertexIndex >= mesh->size) {
return luaL_error(L, "Invalid mesh vertex index: %d", vertexIndex + 1);
} else if (attributeIndex < 0 || attributeIndex >= format.length) {
return luaL_error(L, "Invalid mesh attribute index: %d", attributeIndex + 1);
}
MeshAttribute attribute;
for (int i = 0; i <= attributeIndex; i++) {
attribute = format.data[i];
if (i == attributeIndex) {
for (int j = 0; j < attribute.count; j++) {
switch (attribute.type) {
case MESH_FLOAT: lua_pushnumber(L, *((float*) vertex)); break;
case MESH_BYTE: lua_pushinteger(L, *((unsigned char*) vertex)); break;
case MESH_INT: lua_pushinteger(L, *((int*) vertex)); break;
}
vertex += sizeof(attribute.type);
}
} else {
vertex += attribute.count * sizeof(attribute.type);
}
}
return attribute.count;
}
int l_lovrMeshSetVertexAttribute(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
int vertexIndex = luaL_checkint(L, 2) - 1;
int attributeIndex = luaL_checkint(L, 3) - 1;
char* vertex = lovrMeshGetScratchVertex(mesh);
lovrMeshGetVertex(mesh, vertexIndex, vertex);
MeshFormat format = lovrMeshGetVertexFormat(mesh);
if (vertexIndex < 0 || vertexIndex >= mesh->size) {
return luaL_error(L, "Invalid mesh vertex index: %d", vertexIndex + 1);
} else if (attributeIndex < 0 || attributeIndex >= format.length) {
return luaL_error(L, "Invalid mesh attribute index: %d", attributeIndex + 1);
}
int arg = 4;
for (int i = 0; i <= attributeIndex; i++) {
MeshAttribute attribute = format.data[i];
if (i == attributeIndex) {
for (int j = 0; j < attribute.count; j++) {
switch (attribute.type) {
case MESH_FLOAT: *((float*) vertex) = luaL_optnumber(L, arg++, 0.f); break;
case MESH_BYTE: *((unsigned char*) vertex) = luaL_optint(L, arg++, 255); break;
case MESH_INT: *((int*) vertex) = luaL_optint(L, arg++, 0); break;
}
vertex += sizeof(attribute.type);
}
} else {
vertex += attribute.count * sizeof(attribute.type);
}
}
lovrMeshSetVertex(mesh, vertexIndex, lovrMeshGetScratchVertex(mesh));
return 0;
}
int l_lovrMeshSetVertices(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
MeshFormat format = lovrMeshGetVertexFormat(mesh);
luaL_checktype(L, 2, LUA_TTABLE);
int vertexCount = lua_objlen(L, 2);
if (vertexCount > lovrMeshGetVertexCount(mesh)) {
return luaL_error(L, "Too many vertices for Mesh\n", lovrMeshGetVertexCount(mesh));
}
char* vertices = malloc(mesh->stride * vertexCount);
char* vertex = vertices;
for (int i = 0; i < vertexCount; i++) {
lua_rawgeti(L, 2, i + 1);
int component = 0;
for (int j = 0; j < format.length; j++) {
MeshAttribute attribute = format.data[j];
for (int k = 0; k < attribute.count; k++) {
lua_rawgeti(L, -1, ++component);
switch (attribute.type) {
case MESH_FLOAT: *((float*) vertex) = luaL_optnumber(L, -1, 0.f); break;
case MESH_BYTE: *((unsigned char*) vertex) = luaL_optint(L, -1, 255); break;
case MESH_INT: *((int*) vertex) = luaL_optint(L, -1, 0); break;
}
vertex += sizeof(attribute.type);
lua_pop(L, 1);
}
}
lua_pop(L, 1);
}
lovrMeshSetVertices(mesh, vertices, mesh->stride * vertexCount);
free(vertices);
return 0;
}
int l_lovrMeshGetVertexMap(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
int count;
unsigned int* indices = lovrMeshGetVertexMap(mesh, &count);
if (count == 0) {
lua_pushnil(L);
return 1;
}
lua_newtable(L);
for (int i = 0; i < count; i++) {
lua_pushinteger(L, indices[i]);
lua_rawseti(L, -2, i + 1);
}
return 1;
}
int l_lovrMeshSetVertexMap(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
if (lua_isnoneornil(L, 2)) {
lovrMeshSetVertexMap(mesh, NULL, 0);
return 0;
}
luaL_checktype(L, 2, LUA_TTABLE);
int count = lua_objlen(L, 2);
unsigned int* indices = malloc(count * sizeof(unsigned int));
for (int i = 0; i < count; i++) {
lua_rawgeti(L, 2, i + 1);
if (!lua_isnumber(L, -1)) {
free(indices);
return luaL_error(L, "Mesh vertex map index #%d must be numeric", i);
}
int index = lua_tointeger(L, -1);
if (index > mesh->size || index < 0) {
free(indices);
return luaL_error(L, "Invalid vertex map value: %d", index);
}
indices[i] = index - 1;
lua_pop(L, 1);
}
lovrMeshSetVertexMap(mesh, indices, count);
free(indices);
return 0;
}
int l_lovrMeshGetDrawRange(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
if (!lovrMeshIsRangeEnabled(mesh)) {
lua_pushnil(L);
return 1;
}
int start, count;
lovrMeshGetDrawRange(mesh, &start, &count);
lua_pushinteger(L, start + 1);
lua_pushinteger(L, count);
return 2;
}
int l_lovrMeshSetDrawRange(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
if (lua_isnoneornil(L, 2)) {
lovrMeshSetRangeEnabled(mesh, 0);
return 0;
}
lovrMeshSetRangeEnabled(mesh, 1);
int rangeStart = luaL_checkinteger(L, 2) - 1;
int rangeCount = luaL_checkinteger(L, 3);
if (lovrMeshSetDrawRange(mesh, rangeStart, rangeCount)) {
return luaL_error(L, "Invalid mesh draw range (%d, %d)", rangeStart + 1, rangeCount);
}
return 0;
}
int l_lovrMeshGetTexture(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
Texture* texture = lovrMeshGetTexture(mesh);
if (texture) {
luax_pushtype(L, Texture, texture);
} else {
lua_pushnil(L);
}
return 1;
}
int l_lovrMeshSetTexture(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
Texture* texture = lua_isnoneornil(L, 2) ? NULL : luax_checktype(L, 2, Texture);
lovrMeshSetTexture(mesh, texture);
return 0;
}
const luaL_Reg lovrMesh[] = {
{ "draw", l_lovrMeshDraw },
{ "getVertexFormat", l_lovrMeshGetVertexFormat },
{ "getVertexCount", l_lovrMeshGetVertexCount },
{ "getVertex", l_lovrMeshGetVertex },
{ "setVertex", l_lovrMeshSetVertex },
{ "getVertexAttribute", l_lovrMeshGetVertexAttribute },
{ "setVertexAttribute", l_lovrMeshSetVertexAttribute },
{ "setVertices", l_lovrMeshSetVertices },
{ "getVertexMap", l_lovrMeshGetVertexMap },
{ "setVertexMap", l_lovrMeshSetVertexMap },
{ "getDrawMode", l_lovrMeshGetDrawMode },
{ "setDrawMode", l_lovrMeshSetDrawMode },
{ "getDrawRange", l_lovrMeshGetDrawRange },
{ "setDrawRange", l_lovrMeshSetDrawRange },
{ "getTexture", l_lovrMeshGetTexture },
{ "setTexture", l_lovrMeshSetTexture },
{ NULL, NULL }
};