#include "api.h" #include "graphics/graphics.h" #include "data/modelData.h" #include "core/maf.h" #include "util.h" // This adds about 2-3us of overhead, which sucks, but the reduction in complexity is large static int luax_callmodeldata(lua_State* L, const char* method, int nrets) { int nargs = lua_gettop(L); Model* model = luax_checktype(L, 1, Model); ModelData* data = lovrModelGetInfo(model)->data; luax_pushtype(L, ModelData, data); lua_pushstring(L, method); lua_gettable(L, -2); lua_insert(L, 1); lua_replace(L, 2); lua_call(L, nargs, nrets); return nrets; } uint32_t luax_checkblendshape(lua_State* L, int index, Model* model) { switch (lua_type(L, index)) { case LUA_TSTRING: { size_t length; const char* name = lua_tolstring(L, index, &length); ModelData* data = lovrModelGetInfo(model)->data; uint64_t blendShapeIndex = map_get(&data->blendShapeMap, hash64(name, length)); lovrCheck(blendShapeIndex != MAP_NIL, "ModelData has no blend shape named '%s'", name); return (uint32_t) blendShapeIndex; } case LUA_TNUMBER: { uint32_t blendShape = luax_checku32(L, index) - 1; ModelData* data = lovrModelGetInfo(model)->data; lovrCheck(blendShape < data->blendShapeCount, "Invalid blend shape index '%d'", blendShape + 1); return blendShape; } default: return luax_typeerror(L, index, "number or string"), ~0u; } } static int l_lovrModelClone(lua_State* L) { Model* model = luax_checktype(L, 1, Model); Model* clone = lovrModelClone(model); luax_pushtype(L, Model, clone); lovrRelease(clone, lovrModelDestroy); return 1; } static int l_lovrModelGetData(lua_State* L) { Model* model = luax_checktype(L, 1, Model); ModelData* data = lovrModelGetInfo(model)->data; luax_pushtype(L, ModelData, data); return 1; } static int l_lovrModelGetMetadata(lua_State* L) { return luax_callmodeldata(L, "getMetadata", 1); } static int l_lovrModelGetRootNode(lua_State* L) { return luax_callmodeldata(L, "getRootNode", 1); } static int l_lovrModelGetNodeCount(lua_State* L) { return luax_callmodeldata(L, "getNodeCount", 1); } static int l_lovrModelGetNodeName(lua_State* L) { return luax_callmodeldata(L, "getNodeName", 1); } static int l_lovrModelGetNodeParent(lua_State* L) { return luax_callmodeldata(L, "getNodeParent", 1); } static int l_lovrModelGetNodeChildren(lua_State* L) { return luax_callmodeldata(L, "getNodeChildren", 1); } static int l_lovrModelGetNodePosition(lua_State* L) { Model* model = luax_checktype(L, 1, Model); uint32_t node = luax_checknodeindex(L, 2, lovrModelGetInfo(model)->data); OriginType origin = luax_checkenum(L, 3, OriginType, "root"); float position[3], scale[3], rotation[4]; lovrModelGetNodeTransform(model, node, position, scale, rotation, origin); lua_pushnumber(L, position[0]); lua_pushnumber(L, position[1]); lua_pushnumber(L, position[2]); return 3; } static int l_lovrModelSetNodePosition(lua_State* L) { Model* model = luax_checktype(L, 1, Model); uint32_t node = luax_checknodeindex(L, 2, lovrModelGetInfo(model)->data); float position[3]; int index = luax_readvec3(L, 3, position, NULL); float alpha = luax_optfloat(L, index, 1.f); lovrModelSetNodeTransform(model, node, position, NULL, NULL, alpha); return 0; } static int l_lovrModelGetNodeScale(lua_State* L) { Model* model = luax_checktype(L, 1, Model); uint32_t node = luax_checknodeindex(L, 2, lovrModelGetInfo(model)->data); OriginType origin = luax_checkenum(L, 3, OriginType, "root"); float position[3], scale[3], rotation[4]; lovrModelGetNodeTransform(model, node, position, scale, rotation, origin); lua_pushnumber(L, scale[0]); lua_pushnumber(L, scale[1]); lua_pushnumber(L, scale[2]); return 3; } static int l_lovrModelSetNodeScale(lua_State* L) { Model* model = luax_checktype(L, 1, Model); uint32_t node = luax_checknodeindex(L, 2, lovrModelGetInfo(model)->data); float scale[3]; int index = luax_readscale(L, 3, scale, 3, NULL); float alpha = luax_optfloat(L, index, 1.f); lovrModelSetNodeTransform(model, node, NULL, scale, NULL, alpha); return 0; } static int l_lovrModelGetNodeOrientation(lua_State* L) { Model* model = luax_checktype(L, 1, Model); uint32_t node = luax_checknodeindex(L, 2, lovrModelGetInfo(model)->data); OriginType origin = luax_checkenum(L, 3, OriginType, "root"); float position[3], scale[3], rotation[4], angle, ax, ay, az; lovrModelGetNodeTransform(model, node, position, scale, rotation, origin); quat_getAngleAxis(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_lovrModelSetNodeOrientation(lua_State* L) { Model* model = luax_checktype(L, 1, Model); uint32_t node = luax_checknodeindex(L, 2, lovrModelGetInfo(model)->data); float rotation[4]; int index = luax_readquat(L, 3, rotation, NULL); float alpha = luax_optfloat(L, index, 1.f); lovrModelSetNodeTransform(model, node, NULL, NULL, rotation, alpha); return 0; } static int l_lovrModelGetNodePose(lua_State* L) { Model* model = luax_checktype(L, 1, Model); uint32_t node = luax_checknodeindex(L, 2, lovrModelGetInfo(model)->data); OriginType origin = luax_checkenum(L, 3, OriginType, "root"); float position[3], scale[3], rotation[4], angle, ax, ay, az; lovrModelGetNodeTransform(model, node, position, scale, rotation, origin); quat_getAngleAxis(rotation, &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); return 7; } static int l_lovrModelSetNodePose(lua_State* L) { Model* model = luax_checktype(L, 1, Model); uint32_t node = luax_checknodeindex(L, 2, lovrModelGetInfo(model)->data); int index = 3; float position[3], rotation[4]; index = luax_readvec3(L, index, position, NULL); index = luax_readquat(L, index, rotation, NULL); float alpha = luax_optfloat(L, index, 1.f); lovrModelSetNodeTransform(model, node, position, NULL, rotation, alpha); return 0; } static int l_lovrModelGetNodeTransform(lua_State* L) { Model* model = luax_checktype(L, 1, Model); uint32_t node = luax_checknodeindex(L, 2, lovrModelGetInfo(model)->data); OriginType origin = luax_checkenum(L, 3, OriginType, "root"); float position[3], scale[3], rotation[4], angle, ax, ay, az; lovrModelGetNodeTransform(model, node, position, scale, rotation, origin); quat_getAngleAxis(rotation, &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); return 10; } static int l_lovrModelSetNodeTransform(lua_State* L) { Model* model = luax_checktype(L, 1, Model); uint32_t node = luax_checknodeindex(L, 2, lovrModelGetInfo(model)->data); int index = 3; VectorType type; float position[3], scale[3], rotation[4]; float* m = luax_tovector(L, index, &type); if (m && type == V_MAT4) { mat4_getPosition(m, position); mat4_getScale(m, scale); mat4_getOrientation(m, rotation); index = 4; } else { index = luax_readvec3(L, index, position, NULL); index = luax_readscale(L, index, scale, 3, NULL); index = luax_readquat(L, index, rotation, NULL); } float alpha = luax_optfloat(L, index, 1.f); lovrModelSetNodeTransform(model, node, position, scale, rotation, alpha); return 0; } static int l_lovrModelResetNodeTransforms(lua_State* L) { Model* model = luax_checktype(L, 1, Model); lovrModelResetNodeTransforms(model); return 0; } static int l_lovrModelGetAnimationCount(lua_State* L) { return luax_callmodeldata(L, "getAnimationCount", 1); } static int l_lovrModelGetAnimationName(lua_State* L) { return luax_callmodeldata(L, "getAnimationName", 1); } static int l_lovrModelGetAnimationDuration(lua_State* L) { return luax_callmodeldata(L, "getAnimationDuration", 1); } static int l_lovrModelHasJoints(lua_State* L) { Model* model = luax_checktype(L, 1, Model); ModelData* data = lovrModelGetInfo(model)->data; lua_pushboolean(L, data->skinCount > 0); return 1; } static int l_lovrModelAnimate(lua_State* L) { Model* model = luax_checktype(L, 1, Model); uint32_t animation = luax_checkanimationindex(L, 2, lovrModelGetInfo(model)->data); float time = luax_checkfloat(L, 3); float alpha = luax_optfloat(L, 4, 1.f); lovrModelAnimate(model, animation, time, alpha); return 0; } static int l_lovrModelGetBlendShapeCount(lua_State* L) { return luax_callmodeldata(L, "getBlendShapeCount", 1); } static int l_lovrModelGetBlendShapeName(lua_State* L) { return luax_callmodeldata(L, "getBlendShapeName", 1); } static int l_lovrModelGetBlendShapeWeight(lua_State* L) { Model* model = luax_checktype(L, 1, Model); uint32_t blendShape = luax_checkblendshape(L, 2, model); float weight = lovrModelGetBlendShapeWeight(model, blendShape); lua_pushnumber(L, weight); return 1; } static int l_lovrModelSetBlendShapeWeight(lua_State* L) { Model* model = luax_checktype(L, 1, Model); uint32_t blendShape = luax_checkblendshape(L, 2, model); float weight = luax_checkfloat(L, 3); lovrModelSetBlendShapeWeight(model, blendShape, weight); return 0; } static int l_lovrModelResetBlendShapes(lua_State* L) { Model* model = luax_checktype(L, 1, Model); lovrModelResetBlendShapes(model); return 0; } static int l_lovrModelGetTriangles(lua_State* L) { return luax_callmodeldata(L, "getTriangles", 2); } static int l_lovrModelGetTriangleCount(lua_State* L) { return luax_callmodeldata(L, "getTriangleCount", 1); } static int l_lovrModelGetVertexCount(lua_State* L) { return luax_callmodeldata(L, "getVertexCount", 1); } static int l_lovrModelGetWidth(lua_State* L) { return luax_callmodeldata(L, "getWidth", 1); } static int l_lovrModelGetHeight(lua_State* L) { return luax_callmodeldata(L, "getHeight", 1); } static int l_lovrModelGetDepth(lua_State* L) { return luax_callmodeldata(L, "getDepth", 1); } static int l_lovrModelGetDimensions(lua_State* L) { return luax_callmodeldata(L, "getDimensions", 3); } static int l_lovrModelGetCenter(lua_State* L) { return luax_callmodeldata(L, "getCenter", 3); } static int l_lovrModelGetBoundingBox(lua_State* L) { return luax_callmodeldata(L, "getBoundingBox", 6); } static int l_lovrModelGetBoundingSphere(lua_State* L) { return luax_callmodeldata(L, "getBoundingSphere", 4); } static int l_lovrModelGetVertexBuffer(lua_State* L) { Model* model = luax_checktype(L, 1, Model); Buffer* buffer = lovrModelGetVertexBuffer(model); luax_pushtype(L, Buffer, buffer); return 1; } static int l_lovrModelGetIndexBuffer(lua_State* L) { Model* model = luax_checktype(L, 1, Model); Buffer* buffer = lovrModelGetIndexBuffer(model); luax_pushtype(L, Buffer, buffer); 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); } static int l_lovrModelGetMaterialName(lua_State* L) { return luax_callmodeldata(L, "getMaterialName", 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); Material* material = lovrModelGetMaterial(model, index); luax_pushtype(L, Material, material); return 1; } const luaL_Reg lovrModel[] = { { "clone", l_lovrModelClone }, { "getData", l_lovrModelGetData }, { "getMetadata", l_lovrModelGetMetadata }, { "getRootNode", l_lovrModelGetRootNode }, { "getNodeCount", l_lovrModelGetNodeCount }, { "getNodeName", l_lovrModelGetNodeName }, { "getNodeParent", l_lovrModelGetNodeParent }, { "getNodeChildren", l_lovrModelGetNodeChildren }, { "getNodePosition", l_lovrModelGetNodePosition }, { "setNodePosition", l_lovrModelSetNodePosition }, { "getNodeOrientation", l_lovrModelGetNodeOrientation }, { "setNodeOrientation", l_lovrModelSetNodeOrientation }, { "getNodeScale", l_lovrModelGetNodeScale }, { "setNodeScale", l_lovrModelSetNodeScale }, { "getNodePose", l_lovrModelGetNodePose }, { "setNodePose", l_lovrModelSetNodePose }, { "getNodeTransform", l_lovrModelGetNodeTransform }, { "setNodeTransform", l_lovrModelSetNodeTransform }, { "resetNodeTransforms", l_lovrModelResetNodeTransforms }, { "getAnimationCount", l_lovrModelGetAnimationCount }, { "getAnimationName", l_lovrModelGetAnimationName }, { "getAnimationDuration", l_lovrModelGetAnimationDuration }, { "hasJoints", l_lovrModelHasJoints }, { "animate", l_lovrModelAnimate }, { "getBlendShapeCount", l_lovrModelGetBlendShapeCount }, { "getBlendShapeName", l_lovrModelGetBlendShapeName }, { "getBlendShapeWeight", l_lovrModelGetBlendShapeWeight }, { "setBlendShapeWeight", l_lovrModelSetBlendShapeWeight }, { "resetBlendShapes", l_lovrModelResetBlendShapes }, { "getTriangles", l_lovrModelGetTriangles }, { "getTriangleCount", l_lovrModelGetTriangleCount }, { "getVertexCount", l_lovrModelGetVertexCount }, { "getWidth", l_lovrModelGetWidth }, { "getHeight", l_lovrModelGetHeight }, { "getDepth", l_lovrModelGetDepth }, { "getDimensions", l_lovrModelGetDimensions }, { "getCenter", l_lovrModelGetCenter }, { "getBoundingBox", l_lovrModelGetBoundingBox }, { "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 }, { "getMaterial", l_lovrModelGetMaterial }, { NULL, NULL } };