#include "scene_tree.h" #include "glm_bindings.h" int honey_node_mt_ref = LUA_NOREF; void honey_setup_scene_tree(lua_State* L) { honey_lua_create_table (L, 1, HONEY_TABLE, "__index", 6, HONEY_FUNCTION, "updateTransform", honey_node_update_transform, HONEY_FUNCTION, "updateCascade", honey_node_update_cascade, HONEY_FUNCTION, "drawCascade", honey_node_draw_cascade, HONEY_FUNCTION, "translate", honey_node_translate, HONEY_FUNCTION, "rotate", honey_node_rotate, HONEY_FUNCTION, "scale", honey_node_scale); honey_node_mt_ref = luaL_ref(L, LUA_REGISTRYINDEX); lua_rawgeti(L, LUA_REGISTRYINDEX, honey_node_mt_ref); lua_setfield(L, -2, "nodeMetatable"); lua_pushcfunction(L, honey_node_new); lua_setfield(L, -2, "node"); } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Basic node functions * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ int honey_node_new(lua_State* L) { honey_glm_array *position, *rotation, *scale; honey_lua_parse_arguments (L, 1, 4, HONEY_ANY, NULL, HONEY_USERDATA, &position, HONEY_USERDATA, &rotation, HONEY_USERDATA, &scale); lua_createtable(L, 5, 0); lua_rawgeti(L, LUA_REGISTRYINDEX, honey_node_mt_ref); lua_setmetatable(L, -2); if (lua_istable(L, 1)) { /* add self to parent.children */ lua_getfield(L, 1, "children"); int length = lua_objlen(L, -1); lua_pushinteger(L, length+1); lua_pushvalue(L, -3); lua_settable(L, -3); lua_pop(L, 1); lua_pushvalue(L, 1); lua_setfield(L, -2, "parent"); } if (position->type != VEC3) honey_lua_throw_error (L, "position vector must be of type VEC3 (%d); got %d instead", VEC3, position->type); lua_pushvalue(L, 2); lua_setfield(L, -2, "position"); if (rotation->type != VEC3) honey_lua_throw_error (L, "rotation vector must be of type VEC3 (%d); got %d instead", VEC3, rotation->type); lua_pushvalue(L, 3); lua_setfield(L, -2, "rotation"); if (scale->type != VEC3) honey_lua_throw_error (L, "scale vector must be of type VEC3 (%d); got %d instead", VEC3, scale->type); lua_pushvalue(L, 4); lua_setfield(L, -2, "scale"); /* create transform */ lua_pushcfunction(L, honey_glm_new_mat4); honey_lua_pcall(L, 0, 1); /* call honey.glm.eye() */ lua_pushcfunction(L, honey_glm_mat4_eye); lua_pushvalue(L, -2); honey_lua_pcall(L, 1, 0); lua_setfield(L, -2, "transform"); /* call node:updateTransform() */ lua_getfield(L, -1, "updateTransform"); lua_pushvalue(L, -2); honey_lua_pcall(L, 1, 0); /* create children */ lua_createtable(L, 0, 0); lua_setfield(L, -2, "children"); return 1; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ int honey_node_update_transform(lua_State* L) { honey_lua_parse_arguments(L, 1, 1, HONEY_TABLE, NULL); honey_glm_array *transform, *position, *rotation, *parent_transform; lua_getfield(L, 1, "transform"); transform = lua_touserdata(L, -1); lua_pop(L, 1); lua_getfield(L, 1, "position"); position = lua_touserdata(L, -1); lua_pop(L, 1); lua_getfield(L, 1, "rotation"); rotation = lua_touserdata(L, -1); lua_pop(L, 1); glm_mat4_identity(transform->data); glm_translate(transform->data, position->data); glm_rotate_z(transform->data, rotation->data[2], transform->data); glm_rotate_y(transform->data, rotation->data[1], transform->data); glm_rotate_x(transform->data, rotation->data[0], transform->data); lua_getfield(L, 1, "parent"); if (lua_istable(L, -1)) { lua_getfield(L, -1, "transform"); parent_transform = lua_touserdata(L, -1); lua_pop(L, 1); glm_mat4_mul(parent_transform->data, transform->data, transform->data); } lua_pop(L, 1); return 0; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ int honey_node_update_cascade(lua_State* L) { float dt; honey_lua_parse_arguments(L, 1, 2, HONEY_TABLE, NULL, HONEY_NUMBER, &dt); /* call self.update if it exists */ lua_getfield(L, 1, "update"); if (!lua_isnil(L, -1)) { lua_pushvalue(L, 1); lua_pushnumber(L, dt); honey_lua_pcall(L, 2, 0); } else lua_pop(L, 1); lua_pushcfunction(L, honey_node_update_transform); lua_pushvalue(L, 1); honey_lua_pcall(L, 1, 0); /* update cascade for each child node */ lua_getfield(L, 1, "children"); int n_children = lua_objlen(L, -1); for (int i=0; idata[0] += v->data[0]; position->data[1] += v->data[1]; position->data[2] += v->data[2]; return 0; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ int honey_node_rotate(lua_State* L) { char* axisName; float angle; int index; honey_lua_parse_arguments (L, 1, 3, HONEY_TABLE, NULL, HONEY_STRING, &axisName, HONEY_NUMBER, &angle); switch (axisName[0]) { case 'x': index = 0; break; case 'y': index = 1; break; case 'z': index = 2; break; default: honey_lua_throw_error (L, "axis string must be one of 'x', 'y', or 'z'; got '%s' instead", axisName); } lua_getfield(L, 1, "rotation"); honey_glm_array* rotation = lua_touserdata(L, -1); lua_pop(L, 1); rotation->data[index] += angle; return 0; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ int honey_node_scale(lua_State* L) { char* axisName; float s; int index; int choice = honey_lua_parse_arguments (L, 2, 2, HONEY_TABLE, NULL, HONEY_NUMBER, &s, 3, HONEY_TABLE, NULL, HONEY_STRING, &axisName, HONEY_NUMBER, &s); lua_getfield(L, 1, "scale"); honey_glm_array* scale = lua_touserdata(L, -1); lua_pop(L, 1); if (choice == 0) { for (int i=0; i<3; i++) scale->data[i] *= s; } else { switch (axisName[0]) { case 'x': index = 0; break; case 'y': index = 1; break; case 'z': index = 2; break; default: honey_lua_throw_error (L, "axis string must be one of 'x', 'y', or 'z'; got '%s' instead", axisName); } scale->data[index] *= s; } return 0; }