mirror of https://github.com/bjornbytes/lovr.git
816 lines
29 KiB
C
816 lines
29 KiB
C
#include "api.h"
|
|
#include "data/modelData.h"
|
|
#include "core/maf.h"
|
|
#include "util.h"
|
|
|
|
uint32_t luax_checkanimationindex(lua_State* L, int index, ModelData* model) {
|
|
switch (lua_type(L, index)) {
|
|
case LUA_TNUMBER: {
|
|
uint32_t animation = luax_checku32(L, index) - 1;
|
|
lovrCheck(animation < model->animationCount, "Invalid animation index '%d'", animation + 1);
|
|
return animation;
|
|
}
|
|
case LUA_TSTRING: {
|
|
size_t length;
|
|
const char* name = lua_tolstring(L, index, &length);
|
|
uint64_t hash = hash64(name, length);
|
|
uint64_t entry = map_get(&model->animationMap, hash);
|
|
lovrCheck(entry != MAP_NIL, "Model has no animation named '%s'", name);
|
|
return (uint32_t) entry;
|
|
}
|
|
default: return luax_typeerror(L, index, "number or string"), ~0u;
|
|
}
|
|
}
|
|
|
|
uint32_t luax_checkmaterialindex(lua_State* L, int index, ModelData* model) {
|
|
switch (lua_type(L, index)) {
|
|
case LUA_TNUMBER: {
|
|
uint32_t material = luax_checku32(L, index) - 1;
|
|
lovrCheck(material < model->materialCount, "Invalid material index '%d'", material + 1);
|
|
return material;
|
|
}
|
|
case LUA_TSTRING: {
|
|
size_t length;
|
|
const char* name = lua_tolstring(L, index, &length);
|
|
uint64_t hash = hash64(name, length);
|
|
uint64_t entry = map_get(&model->materialMap, hash);
|
|
lovrCheck(entry != MAP_NIL, "Model has no material named '%s'", name);
|
|
return (uint32_t) entry;
|
|
}
|
|
default: return luax_typeerror(L, index, "number or string"), ~0u;
|
|
}
|
|
}
|
|
|
|
uint32_t luax_checknodeindex(lua_State* L, int index, ModelData* model) {
|
|
switch (lua_type(L, index)) {
|
|
case LUA_TNUMBER: {
|
|
uint32_t node = luax_checku32(L, index) - 1;
|
|
lovrCheck(node < model->nodeCount, "Invalid node index '%d'", node + 1);
|
|
return node;
|
|
}
|
|
case LUA_TSTRING: {
|
|
size_t length;
|
|
const char* name = lua_tolstring(L, index, &length);
|
|
uint64_t hash = hash64(name, length);
|
|
uint64_t entry = map_get(&model->nodeMap, hash);
|
|
lovrCheck(entry != MAP_NIL, "Model has no node named '%s'", name);
|
|
return (uint32_t) entry;
|
|
}
|
|
default: return luax_typeerror(L, index, "number or string"), ~0u;
|
|
}
|
|
}
|
|
|
|
static int l_lovrModelDataGetMetadata(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
|
|
if (!model->metadata || model->metadataSize == 0 || model->metadataType != META_GLTF_JSON) {
|
|
lua_pushnil(L);
|
|
} else {
|
|
lua_pushlstring(L, model->metadata, model->metadataSize);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetBlobCount(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
lua_pushinteger(L, model->blobCount);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetBlob(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
uint32_t index = luax_checku32(L, 2) - 1;
|
|
lovrCheck(index < model->blobCount, "Invalid blob index '%d'", index + 1);
|
|
luax_pushtype(L, Blob, model->blobs[index]);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetImageCount(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
lua_pushinteger(L, model->imageCount);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetImage(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
uint32_t index = luax_checku32(L, 2) - 1;
|
|
lovrCheck(index < model->imageCount, "Invalid image index '%d'", index + 1);
|
|
luax_pushtype(L, Image, model->images[index]);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetRootNode(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
lua_pushinteger(L, model->rootNode + 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetNodeCount(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
lua_pushinteger(L, model->nodeCount);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetNodeName(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
uint32_t index = luax_checku32(L, 2) - 1;
|
|
lovrCheck(index < model->nodeCount, "Invalid node index '%d'", index + 1);
|
|
lua_pushstring(L, model->nodes[index].name);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetNodeParent(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
ModelNode* node = &model->nodes[luax_checknodeindex(L, 2, model)];
|
|
if (node->parent == ~0u) {
|
|
lua_pushnil(L);
|
|
} else {
|
|
lua_pushinteger(L, node->parent + 1);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetNodeChildren(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
ModelNode* node = &model->nodes[luax_checknodeindex(L, 2, model)];
|
|
lua_createtable(L, node->childCount, 0);
|
|
for (uint32_t i = 0; i < node->childCount; i++) {
|
|
lua_pushinteger(L, node->children[i] + 1);
|
|
lua_rawseti(L, -2, i + 1);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetNodePosition(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
ModelNode* node = &model->nodes[luax_checknodeindex(L, 2, model)];
|
|
if (node->hasMatrix) {
|
|
float position[3];
|
|
mat4_getPosition(node->transform.matrix, position);
|
|
lua_pushnumber(L, position[0]);
|
|
lua_pushnumber(L, position[1]);
|
|
lua_pushnumber(L, position[2]);
|
|
return 3;
|
|
} else {
|
|
lua_pushnumber(L, node->transform.translation[0]);
|
|
lua_pushnumber(L, node->transform.translation[1]);
|
|
lua_pushnumber(L, node->transform.translation[2]);
|
|
return 3;
|
|
}
|
|
}
|
|
|
|
static int l_lovrModelDataGetNodeOrientation(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
ModelNode* node = &model->nodes[luax_checknodeindex(L, 2, model)];
|
|
float angle, ax, ay, az;
|
|
if (node->hasMatrix) {
|
|
mat4_getAngleAxis(node->transform.matrix, &angle, &ax, &ay, &az);
|
|
} else {
|
|
quat_getAngleAxis(node->transform.rotation, &angle, &ax, &ay, &az);
|
|
}
|
|
lua_pushnumber(L, angle);
|
|
lua_pushnumber(L, ax);
|
|
lua_pushnumber(L, ay);
|
|
lua_pushnumber(L, az);
|
|
return 4;
|
|
}
|
|
|
|
static int l_lovrModelDataGetNodeScale(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
ModelNode* node = &model->nodes[luax_checknodeindex(L, 2, model)];
|
|
if (node->hasMatrix) {
|
|
float scale[3];
|
|
mat4_getScale(node->transform.matrix, scale);
|
|
lua_pushnumber(L, scale[0]);
|
|
lua_pushnumber(L, scale[1]);
|
|
lua_pushnumber(L, scale[2]);
|
|
} else {
|
|
lua_pushnumber(L, node->transform.scale[0]);
|
|
lua_pushnumber(L, node->transform.scale[1]);
|
|
lua_pushnumber(L, node->transform.scale[2]);
|
|
}
|
|
return 3;
|
|
}
|
|
|
|
static int l_lovrModelDataGetNodePose(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
ModelNode* node = &model->nodes[luax_checknodeindex(L, 2, model)];
|
|
if (node->hasMatrix) {
|
|
float position[3], angle, ax, ay, az;
|
|
mat4_getPosition(node->transform.matrix, position);
|
|
mat4_getAngleAxis(node->transform.matrix, &angle, &ax, &ay, &az);
|
|
lua_pushnumber(L, position[0]);
|
|
lua_pushnumber(L, position[1]);
|
|
lua_pushnumber(L, position[2]);
|
|
lua_pushnumber(L, angle);
|
|
lua_pushnumber(L, ax);
|
|
lua_pushnumber(L, ay);
|
|
lua_pushnumber(L, az);
|
|
} else {
|
|
float angle, ax, ay, az;
|
|
quat_getAngleAxis(node->transform.rotation, &angle, &ax, &ay, &az);
|
|
lua_pushnumber(L, node->transform.translation[0]);
|
|
lua_pushnumber(L, node->transform.translation[1]);
|
|
lua_pushnumber(L, node->transform.translation[2]);
|
|
lua_pushnumber(L, angle);
|
|
lua_pushnumber(L, ax);
|
|
lua_pushnumber(L, ay);
|
|
lua_pushnumber(L, az);
|
|
}
|
|
return 7;
|
|
}
|
|
|
|
static int l_lovrModelDataGetNodeTransform(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
ModelNode* node = &model->nodes[luax_checknodeindex(L, 2, model)];
|
|
if (node->hasMatrix) {
|
|
float position[3], scale[4], angle, ax, ay, az;
|
|
mat4_getPosition(node->transform.matrix, position);
|
|
mat4_getScale(node->transform.matrix, scale);
|
|
mat4_getAngleAxis(node->transform.matrix, &angle, &ax, &ay, &az);
|
|
lua_pushnumber(L, position[0]);
|
|
lua_pushnumber(L, position[1]);
|
|
lua_pushnumber(L, position[2]);
|
|
lua_pushnumber(L, scale[0]);
|
|
lua_pushnumber(L, scale[1]);
|
|
lua_pushnumber(L, scale[2]);
|
|
lua_pushnumber(L, angle);
|
|
lua_pushnumber(L, ax);
|
|
lua_pushnumber(L, ay);
|
|
lua_pushnumber(L, az);
|
|
} else {
|
|
float angle, ax, ay, az;
|
|
quat_getAngleAxis(node->transform.rotation, &angle, &ax, &ay, &az);
|
|
lua_pushnumber(L, node->transform.translation[0]);
|
|
lua_pushnumber(L, node->transform.translation[1]);
|
|
lua_pushnumber(L, node->transform.translation[2]);
|
|
lua_pushnumber(L, node->transform.scale[0]);
|
|
lua_pushnumber(L, node->transform.scale[1]);
|
|
lua_pushnumber(L, node->transform.scale[2]);
|
|
lua_pushnumber(L, angle);
|
|
lua_pushnumber(L, ax);
|
|
lua_pushnumber(L, ay);
|
|
lua_pushnumber(L, az);
|
|
}
|
|
return 10;
|
|
}
|
|
|
|
static int l_lovrModelDataGetNodeMeshes(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
ModelNode* node = &model->nodes[luax_checknodeindex(L, 2, model)];
|
|
lua_createtable(L, node->primitiveCount, 0);
|
|
for (uint32_t i = 0; i < node->primitiveCount; i++) {
|
|
lua_pushinteger(L, node->primitiveIndex + i + 1);
|
|
lua_rawseti(L, -2, i + 1);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetNodeSkin(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
ModelNode* node = &model->nodes[luax_checknodeindex(L, 2, model)];
|
|
if (node->skin == ~0u) {
|
|
lua_pushnil(L);
|
|
} else {
|
|
lua_pushinteger(L, node->skin + 1);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetMeshCount(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
lua_pushinteger(L, model->primitiveCount);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetMeshDrawMode(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
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, ModelDrawMode, mesh->mode);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetMeshMaterial(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
uint32_t index = luax_checku32(L, 2) - 1;
|
|
lovrCheck(index < model->primitiveCount, "Invalid mesh index '%d'", index + 1);
|
|
ModelPrimitive* mesh = &model->primitives[index];
|
|
if (mesh->material == ~0u) {
|
|
lua_pushnil(L);
|
|
} else {
|
|
lua_pushinteger(L, mesh->material + 1);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetMeshVertexCount(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
uint32_t index = luax_checku32(L, 2) - 1;
|
|
lovrCheck(index < model->primitiveCount, "Invalid mesh index '%d'", index + 1);
|
|
ModelPrimitive* mesh = &model->primitives[index];
|
|
lua_pushinteger(L, mesh->attributes[ATTR_POSITION] ? mesh->attributes[ATTR_POSITION]->count : 0);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetMeshIndexCount(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
uint32_t index = luax_checku32(L, 2) - 1;
|
|
lovrCheck(index < model->primitiveCount, "Invalid mesh index '%d'", index + 1);
|
|
ModelPrimitive* mesh = &model->primitives[index];
|
|
lua_pushinteger(L, mesh->indices ? mesh->indices->count : 0);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetMeshVertexFormat(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
uint32_t index = luax_checku32(L, 2) - 1;
|
|
lovrCheck(index < model->primitiveCount, "Invalid mesh index '%d'", index + 1);
|
|
ModelPrimitive* mesh = &model->primitives[index];
|
|
lua_newtable(L);
|
|
uint32_t count = 0;
|
|
for (uint32_t i = 0; i < MAX_DEFAULT_ATTRIBUTES; i++) {
|
|
ModelAttribute* attribute = mesh->attributes[i];
|
|
if (!attribute) continue;
|
|
|
|
lua_createtable(L, 6, 0);
|
|
|
|
luax_pushenum(L, DefaultAttribute, i);
|
|
lua_rawseti(L, -2, 1);
|
|
|
|
luax_pushenum(L, AttributeType, attribute->type);
|
|
lua_rawseti(L, -2, 2);
|
|
|
|
lua_pushinteger(L, attribute->components);
|
|
lua_rawseti(L, -2, 3);
|
|
|
|
lua_pushinteger(L, model->buffers[attribute->buffer].blob + 1);
|
|
lua_rawseti(L, -2, 4);
|
|
|
|
lua_pushinteger(L, model->buffers[attribute->buffer].offset + attribute->offset);
|
|
lua_rawseti(L, -2, 5);
|
|
|
|
lua_pushinteger(L, model->buffers[attribute->buffer].stride);
|
|
lua_rawseti(L, -2, 6);
|
|
|
|
lua_rawseti(L, -2, ++count);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetMeshIndexFormat(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
uint32_t index = luax_checku32(L, 2) - 1;
|
|
lovrCheck(index < model->primitiveCount, "Invalid mesh index '%d'", index + 1);
|
|
ModelPrimitive* mesh = &model->primitives[index];
|
|
if (!mesh->indices) return lua_pushnil(L), 1;
|
|
luax_pushenum(L, AttributeType, mesh->indices->type);
|
|
lua_pushinteger(L, model->buffers[mesh->indices->buffer].blob + 1);
|
|
lua_pushinteger(L, model->buffers[mesh->indices->buffer].offset + mesh->indices->offset);
|
|
lua_pushinteger(L, model->buffers[mesh->indices->buffer].stride);
|
|
return 4;
|
|
}
|
|
|
|
static int l_lovrModelDataGetMeshVertex(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
uint32_t index = luax_checku32(L, 2) - 1;
|
|
lovrCheck(index < model->primitiveCount, "Invalid mesh index '%d'", index + 1);
|
|
ModelPrimitive* mesh = &model->primitives[index];
|
|
uint32_t vertex = luax_checku32(L, 3) - 1;
|
|
uint32_t vertexCount = mesh->attributes[ATTR_POSITION] ? mesh->attributes[ATTR_POSITION]->count : 0;
|
|
lovrCheck(vertex < vertexCount, "Invalid vertex index '%d'", vertex + 1);
|
|
uint32_t total = 0;
|
|
for (uint32_t i = 0; i < MAX_DEFAULT_ATTRIBUTES; i++) {
|
|
ModelAttribute* attribute = mesh->attributes[i];
|
|
if (!attribute) continue;
|
|
|
|
size_t stride = model->buffers[attribute->buffer].stride;
|
|
|
|
if (!stride) {
|
|
switch (attribute->type) {
|
|
case I8: case U8: stride = attribute->components * 1; break;
|
|
case I16: case U16: stride = attribute->components * 2; break;
|
|
case I32: case U32: case F32: stride = attribute->components * 4; break;
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
AttributeData data = { .raw = model->buffers[attribute->buffer].data };
|
|
data.u8 += attribute->offset;
|
|
data.u8 += vertex * stride;
|
|
|
|
for (uint32_t j = 0; j < attribute->components; j++) {
|
|
switch (attribute->type) {
|
|
case I8: lua_pushinteger(L, data.i8[j]); break;
|
|
case U8: lua_pushinteger(L, data.u8[j]); break;
|
|
case I16: lua_pushinteger(L, data.i16[j]); break;
|
|
case U16: lua_pushinteger(L, data.u16[j]); break;
|
|
case I32: lua_pushinteger(L, data.i32[j]); break;
|
|
case U32: lua_pushinteger(L, data.u32[j]); break;
|
|
case F32: lua_pushnumber(L, data.f32[j]); break;
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
total += attribute->components;
|
|
}
|
|
return total;
|
|
}
|
|
|
|
static int l_lovrModelDataGetMeshIndex(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
uint32_t meshIndex = luax_checku32(L, 2) - 1;
|
|
lovrCheck(meshIndex < model->primitiveCount, "Invalid mesh index '%d'", meshIndex + 1);
|
|
ModelPrimitive* mesh = &model->primitives[meshIndex];
|
|
uint32_t index = luax_checku32(L, 3) - 1;
|
|
uint32_t indexCount = mesh->indices ? mesh->indices->count : 0;
|
|
lovrCheck(index < indexCount, "Invalid index index '%d'", index + 1);
|
|
AttributeData data = { .raw = model->buffers[mesh->indices->buffer].data };
|
|
data.u8 += mesh->indices->offset;
|
|
switch (mesh->indices->type) {
|
|
case U16: lua_pushinteger(L, data.u16[index] + 1); return 1;
|
|
case U32: lua_pushinteger(L, data.u32[index] + 1); return 1;
|
|
default: lovrUnreachable();
|
|
}
|
|
}
|
|
|
|
static int l_lovrModelDataGetTriangles(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
|
|
float* vertices = NULL;
|
|
uint32_t* indices = NULL;
|
|
uint32_t vertexCount = 0;
|
|
uint32_t indexCount = 0;
|
|
lovrModelDataGetTriangles(model, &vertices, &indices, &vertexCount, &indexCount);
|
|
|
|
lua_createtable(L, vertexCount * 3, 0);
|
|
for (uint32_t i = 0; i < vertexCount * 3; i++) {
|
|
lua_pushnumber(L, vertices[i]);
|
|
lua_rawseti(L, -2, i + 1);
|
|
}
|
|
|
|
lua_createtable(L, indexCount, 0);
|
|
for (uint32_t i = 0; i < indexCount; i++) {
|
|
lua_pushinteger(L, indices[i] + 1);
|
|
lua_rawseti(L, -2, i + 1);
|
|
}
|
|
|
|
return 2;
|
|
}
|
|
|
|
static int l_lovrModelDataGetTriangleCount(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
uint32_t vertexCount, indexCount;
|
|
lovrModelDataGetTriangles(model, NULL, NULL, &vertexCount, &indexCount);
|
|
lua_pushinteger(L, indexCount / 3);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetVertexCount(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
uint32_t vertexCount, indexCount;
|
|
lovrModelDataGetTriangles(model, NULL, NULL, &vertexCount, &indexCount);
|
|
lua_pushinteger(L, vertexCount);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetWidth(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
float bounds[6];
|
|
lovrModelDataGetBoundingBox(model, bounds);
|
|
lua_pushnumber(L, bounds[1] - bounds[0]);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetHeight(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
float bounds[6];
|
|
lovrModelDataGetBoundingBox(model, bounds);
|
|
lua_pushnumber(L, bounds[3] - bounds[2]);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetDepth(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
float bounds[6];
|
|
lovrModelDataGetBoundingBox(model, bounds);
|
|
lua_pushnumber(L, bounds[5] - bounds[4]);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetDimensions(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
float bounds[6];
|
|
lovrModelDataGetBoundingBox(model, bounds);
|
|
lua_pushnumber(L, bounds[1] - bounds[0]);
|
|
lua_pushnumber(L, bounds[3] - bounds[2]);
|
|
lua_pushnumber(L, bounds[5] - bounds[4]);
|
|
return 3;
|
|
}
|
|
|
|
static int l_lovrModelDataGetCenter(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
float bounds[6];
|
|
lovrModelDataGetBoundingBox(model, bounds);
|
|
lua_pushnumber(L, (bounds[0] + bounds[1]) / 2.f);
|
|
lua_pushnumber(L, (bounds[2] + bounds[3]) / 2.f);
|
|
lua_pushnumber(L, (bounds[4] + bounds[5]) / 2.f);
|
|
return 3;
|
|
}
|
|
|
|
static int l_lovrModelDataGetBoundingBox(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
float bounds[6];
|
|
lovrModelDataGetBoundingBox(model, bounds);
|
|
lua_pushnumber(L, bounds[0]);
|
|
lua_pushnumber(L, bounds[1]);
|
|
lua_pushnumber(L, bounds[2]);
|
|
lua_pushnumber(L, bounds[3]);
|
|
lua_pushnumber(L, bounds[4]);
|
|
lua_pushnumber(L, bounds[5]);
|
|
return 6;
|
|
}
|
|
|
|
static int l_lovrModelDataGetBoundingSphere(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
float sphere[4];
|
|
lovrModelDataGetBoundingSphere(model, sphere);
|
|
lua_pushnumber(L, sphere[0]);
|
|
lua_pushnumber(L, sphere[1]);
|
|
lua_pushnumber(L, sphere[2]);
|
|
lua_pushnumber(L, sphere[3]);
|
|
return 4;
|
|
}
|
|
|
|
static int l_lovrModelDataGetMaterialCount(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
lua_pushinteger(L, model->materialCount);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetMaterialName(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
uint32_t index = luax_checku32(L, 2) - 1;
|
|
lovrCheck(index < model->nodeCount, "Invalid material index '%d'", index + 1);
|
|
lua_pushstring(L, model->materials[index].name);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetMaterial(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
ModelMaterial* material = &model->materials[luax_checkmaterialindex(L, 2, model)];
|
|
|
|
lua_newtable(L);
|
|
|
|
lua_createtable(L, 4, 0);
|
|
lua_pushnumber(L, material->color[0]);
|
|
lua_rawseti(L, -2, 1);
|
|
lua_pushnumber(L, material->color[1]);
|
|
lua_rawseti(L, -2, 2);
|
|
lua_pushnumber(L, material->color[2]);
|
|
lua_rawseti(L, -2, 3);
|
|
lua_pushnumber(L, material->color[3]);
|
|
lua_rawseti(L, -2, 4);
|
|
lua_setfield(L, -2, "color");
|
|
|
|
lua_createtable(L, 4, 0);
|
|
lua_pushnumber(L, material->glow[0]);
|
|
lua_rawseti(L, -2, 1);
|
|
lua_pushnumber(L, material->glow[1]);
|
|
lua_rawseti(L, -2, 2);
|
|
lua_pushnumber(L, material->glow[2]);
|
|
lua_rawseti(L, -2, 3);
|
|
lua_pushnumber(L, material->glow[3]);
|
|
lua_rawseti(L, -2, 4);
|
|
lua_setfield(L, -2, "glow");
|
|
|
|
lua_createtable(L, 2, 0);
|
|
lua_pushnumber(L, material->uvShift[0]);
|
|
lua_rawseti(L, -2, 1);
|
|
lua_pushnumber(L, material->uvShift[1]);
|
|
lua_rawseti(L, -2, 2);
|
|
lua_setfield(L, -2, "uvShift");
|
|
|
|
lua_createtable(L, 2, 0);
|
|
lua_pushnumber(L, material->uvShift[0]);
|
|
lua_rawseti(L, -2, 1);
|
|
lua_pushnumber(L, material->uvShift[1]);
|
|
lua_rawseti(L, -2, 2);
|
|
lua_setfield(L, -2, "uvScale");
|
|
|
|
lua_pushnumber(L, material->metalness), lua_setfield(L, -2, "metalness");
|
|
lua_pushnumber(L, material->roughness), lua_setfield(L, -2, "roughness");
|
|
lua_pushnumber(L, material->clearcoat), lua_setfield(L, -2, "clearcoat");
|
|
lua_pushnumber(L, material->clearcoatRoughness), lua_setfield(L, -2, "clearcoatRoughness");
|
|
lua_pushnumber(L, material->occlusionStrength), lua_setfield(L, -2, "occlusionStrength");
|
|
lua_pushnumber(L, material->normalScale), lua_setfield(L, -2, "normalScale");
|
|
lua_pushnumber(L, material->alphaCutoff), lua_setfield(L, -2, "alphaCutoff");
|
|
|
|
#define PUSH_IMAGE(t) if (material->t != ~0u) luax_pushtype(L, Image, model->images[material->t]), lua_setfield(L, -2, #t)
|
|
PUSH_IMAGE(texture);
|
|
PUSH_IMAGE(glowTexture);
|
|
PUSH_IMAGE(metalnessTexture);
|
|
PUSH_IMAGE(roughnessTexture);
|
|
PUSH_IMAGE(clearcoatTexture);
|
|
PUSH_IMAGE(occlusionTexture);
|
|
PUSH_IMAGE(normalTexture);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetAnimationCount(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
lua_pushinteger(L, model->animationCount);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetAnimationName(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
uint32_t index = luax_checku32(L, 2) - 1;
|
|
lovrCheck(index < model->animationCount, "Invalid animation index '%d'", index + 1);
|
|
lua_pushstring(L, model->animations[index].name);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetAnimationDuration(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
ModelAnimation* animation = &model->animations[luax_checkanimationindex(L, 2, model)];
|
|
lua_pushnumber(L, animation->duration);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetAnimationChannelCount(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
ModelAnimation* animation = &model->animations[luax_checkanimationindex(L, 2, model)];
|
|
lua_pushinteger(L, animation->channelCount);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetAnimationNode(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
ModelAnimation* animation = &model->animations[luax_checkanimationindex(L, 2, model)];
|
|
uint32_t index = luax_checku32(L, 3) - 1;
|
|
lovrCheck(index < animation->channelCount, "Invalid channel index '%d'", index + 1);
|
|
ModelAnimationChannel* channel = &animation->channels[index];
|
|
lua_pushinteger(L, channel->nodeIndex);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetAnimationProperty(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
ModelAnimation* animation = &model->animations[luax_checkanimationindex(L, 2, model)];
|
|
uint32_t index = luax_checku32(L, 3) - 1;
|
|
lovrCheck(index < animation->channelCount, "Invalid channel index '%d'", index + 1);
|
|
ModelAnimationChannel* channel = &animation->channels[index];
|
|
luax_pushenum(L, AnimationProperty, channel->property);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetAnimationSmoothMode(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
ModelAnimation* animation = &model->animations[luax_checkanimationindex(L, 2, model)];
|
|
uint32_t index = luax_checku32(L, 3) - 1;
|
|
lovrCheck(index < animation->channelCount, "Invalid channel index '%d'", index + 1);
|
|
ModelAnimationChannel* channel = &animation->channels[index];
|
|
luax_pushenum(L, SmoothMode, channel->smoothing);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetAnimationKeyframeCount(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
ModelAnimation* animation = &model->animations[luax_checkanimationindex(L, 2, model)];
|
|
uint32_t index = luax_checku32(L, 3) - 1;
|
|
lovrCheck(index < animation->channelCount, "Invalid channel index '%d'", index + 1);
|
|
ModelAnimationChannel* channel = &animation->channels[index];
|
|
lua_pushinteger(L, channel->keyframeCount);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetAnimationKeyframe(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
ModelAnimation* animation = &model->animations[luax_checkanimationindex(L, 2, model)];
|
|
uint32_t index = luax_checku32(L, 3) - 1;
|
|
lovrCheck(index < animation->channelCount, "Invalid channel index '%d'", index + 1);
|
|
ModelAnimationChannel* channel = &animation->channels[index];
|
|
uint32_t keyframe = luax_checku32(L, 4) - 1;
|
|
lovrCheck(keyframe < channel->keyframeCount, "Invalid keyframe index '%d'", keyframe + 1);
|
|
lua_pushnumber(L, channel->times[keyframe]);
|
|
int count;
|
|
switch (channel->property) {
|
|
case PROP_TRANSLATION: count = 3; break;
|
|
case PROP_ROTATION: count = 4; break;
|
|
case PROP_SCALE: count = 3; break;
|
|
case PROP_WEIGHTS: count = model->nodes[channel->nodeIndex].blendShapeCount; break;
|
|
}
|
|
for (int i = 0; i < count; i++) {
|
|
lua_pushnumber(L, channel->data[keyframe * count + i]);
|
|
}
|
|
return count + 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetSkinCount(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
lua_pushinteger(L, model->skinCount);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetSkinJoints(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
uint32_t index = luax_checku32(L, 2) - 1;
|
|
lovrCheck(index < model->skinCount, "Invalid skin index '%d'", index + 1);
|
|
ModelSkin* skin = &model->skins[index];
|
|
lua_createtable(L, skin->jointCount, 0);
|
|
for (uint32_t i = 0; i < skin->jointCount; i++) {
|
|
lua_pushinteger(L, skin->joints[i]);
|
|
lua_rawseti(L, -2, i + 1);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetSkinInverseBindMatrix(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
uint32_t index = luax_checku32(L, 2) - 1;
|
|
lovrCheck(index < model->skinCount, "Invalid skin index '%d'", index + 1);
|
|
ModelSkin* skin = &model->skins[index];
|
|
uint32_t joint = luax_checku32(L, 3) - 1;
|
|
lovrCheck(index < skin->jointCount, "Invalid joint index '%d'", joint + 1);
|
|
float* m = skin->inverseBindMatrices + joint * 16;
|
|
for (uint32_t i = 0; i < 16; i++) {
|
|
lua_pushnumber(L, m[i]);
|
|
}
|
|
return 16;
|
|
}
|
|
|
|
static int l_lovrModelDataGetBlendShapeCount(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
lua_pushinteger(L, model->blendShapeCount);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrModelDataGetBlendShapeName(lua_State* L) {
|
|
ModelData* model = luax_checktype(L, 1, ModelData);
|
|
uint32_t index = luax_checku32(L, 2) - 1;
|
|
lovrCheck(index < model->blendShapeCount, "Invalid blend shape index '%d'", index + 1);
|
|
lua_pushstring(L, model->blendShapes[index].name);
|
|
return 1;
|
|
}
|
|
|
|
const luaL_Reg lovrModelData[] = {
|
|
{ "getMetadata", l_lovrModelDataGetMetadata },
|
|
{ "getBlobCount", l_lovrModelDataGetBlobCount },
|
|
{ "getBlob", l_lovrModelDataGetBlob },
|
|
{ "getImageCount", l_lovrModelDataGetImageCount },
|
|
{ "getImage", l_lovrModelDataGetImage },
|
|
{ "getRootNode", l_lovrModelDataGetRootNode },
|
|
{ "getNodeCount", l_lovrModelDataGetNodeCount },
|
|
{ "getNodeName", l_lovrModelDataGetNodeName },
|
|
{ "getNodeParent", l_lovrModelDataGetNodeParent },
|
|
{ "getNodeChildren", l_lovrModelDataGetNodeChildren },
|
|
{ "getNodePosition", l_lovrModelDataGetNodePosition },
|
|
{ "getNodeOrientation", l_lovrModelDataGetNodeOrientation },
|
|
{ "getNodeScale", l_lovrModelDataGetNodeScale },
|
|
{ "getNodePose", l_lovrModelDataGetNodePose },
|
|
{ "getNodeTransform", l_lovrModelDataGetNodeTransform },
|
|
{ "getNodeMeshes", l_lovrModelDataGetNodeMeshes },
|
|
{ "getNodeSkin", l_lovrModelDataGetNodeSkin },
|
|
{ "getMeshCount", l_lovrModelDataGetMeshCount },
|
|
{ "getMeshDrawMode", l_lovrModelDataGetMeshDrawMode },
|
|
{ "getMeshMaterial", l_lovrModelDataGetMeshMaterial },
|
|
{ "getMeshVertexCount", l_lovrModelDataGetMeshVertexCount },
|
|
{ "getMeshIndexCount", l_lovrModelDataGetMeshIndexCount },
|
|
{ "getMeshVertexFormat", l_lovrModelDataGetMeshVertexFormat },
|
|
{ "getMeshIndexFormat", l_lovrModelDataGetMeshIndexFormat },
|
|
{ "getMeshVertex", l_lovrModelDataGetMeshVertex },
|
|
{ "getMeshIndex", l_lovrModelDataGetMeshIndex },
|
|
{ "getTriangles", l_lovrModelDataGetTriangles },
|
|
{ "getTriangleCount", l_lovrModelDataGetTriangleCount },
|
|
{ "getVertexCount", l_lovrModelDataGetVertexCount },
|
|
{ "getWidth", l_lovrModelDataGetWidth },
|
|
{ "getHeight", l_lovrModelDataGetHeight },
|
|
{ "getDepth", l_lovrModelDataGetDepth },
|
|
{ "getDimensions", l_lovrModelDataGetDimensions },
|
|
{ "getCenter", l_lovrModelDataGetCenter },
|
|
{ "getBoundingBox", l_lovrModelDataGetBoundingBox },
|
|
{ "getBoundingSphere", l_lovrModelDataGetBoundingSphere },
|
|
{ "getMaterialCount", l_lovrModelDataGetMaterialCount },
|
|
{ "getMaterialName", l_lovrModelDataGetMaterialName },
|
|
{ "getMaterial", l_lovrModelDataGetMaterial },
|
|
{ "getAnimationCount", l_lovrModelDataGetAnimationCount },
|
|
{ "getAnimationName", l_lovrModelDataGetAnimationName },
|
|
{ "getAnimationDuration", l_lovrModelDataGetAnimationDuration },
|
|
{ "getAnimationChannelCount", l_lovrModelDataGetAnimationChannelCount },
|
|
{ "getAnimationNode", l_lovrModelDataGetAnimationNode },
|
|
{ "getAnimationProperty", l_lovrModelDataGetAnimationProperty },
|
|
{ "getAnimationSmoothMode", l_lovrModelDataGetAnimationSmoothMode },
|
|
{ "getAnimationKeyframeCount", l_lovrModelDataGetAnimationKeyframeCount },
|
|
{ "getAnimationKeyframe", l_lovrModelDataGetAnimationKeyframe },
|
|
{ "getSkinCount", l_lovrModelDataGetSkinCount },
|
|
{ "getSkinJoints", l_lovrModelDataGetSkinJoints },
|
|
{ "getSkinInverseBindMatrix", l_lovrModelDataGetSkinInverseBindMatrix },
|
|
{ "getBlendShapeCount", l_lovrModelDataGetBlendShapeCount },
|
|
{ "getBlendShapeName", l_lovrModelDataGetBlendShapeName },
|
|
{ NULL, NULL }
|
|
};
|