summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--demo/main.lua14
-rw-r--r--src/glm_bindings.c41
-rw-r--r--src/glm_bindings.h4
-rw-r--r--src/honey.c2
-rw-r--r--src/scene_tree.h23
-rw-r--r--src/scene_tree_node.c320
7 files changed, 403 insertions, 2 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index aeeb8ff..7bd7243 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -28,6 +28,7 @@ set(SOURCE_FILES
src/mesh.c
src/primitives.c
src/shader.c
+ src/scene_tree_node.c
src/texture.c
src/window.c)
diff --git a/demo/main.lua b/demo/main.lua
index 3fabe00..ec0bac1 100644
--- a/demo/main.lua
+++ b/demo/main.lua
@@ -1,9 +1,19 @@
+local root = honey.node(nil,
+ honey.glm.vec3{0,0,0},
+ honey.glm.vec3{0,0,0},
+ honey.glm.vec3{1,1,1})
+
+local child = honey.node(root,
+ honey.glm.vec3{0,0,0},
+ honey.glm.vec3{0,0,0},
+ honey.glm.vec3{1,1,1})
+
local v = honey.glm.vec3{1, 2, 3}
-local M = honey.glm.mat3()
+local M = honey.glm.mat4()
M:set(1,3, 1)
-print(M:mulv(v))
+print(M:mul(M))
print(v)
print(honey.glm.vec3{2, 0.001, 0})
diff --git a/src/glm_bindings.c b/src/glm_bindings.c
index 173e2eb..6893534 100644
--- a/src/glm_bindings.c
+++ b/src/glm_bindings.c
@@ -5,6 +5,33 @@ int honey_glm_vec4_mt_ref = LUA_NOREF;
int honey_glm_mat3_mt_ref = LUA_NOREF;
int honey_glm_mat4_mt_ref = LUA_NOREF;
+int honey_glm_UNIT_X_ref = LUA_NOREF;
+int honey_glm_UNIT_Y_ref = LUA_NOREF;
+int honey_glm_UNIT_Z_ref = LUA_NOREF;
+
+static void create_vec3(lua_State* L,
+ int x, int y, int z,
+ int* ref)
+{
+ lua_createtable(L, 3, 0);
+
+ lua_pushnumber(L, x);
+ lua_rawseti(L, -2, 1);
+
+ lua_pushnumber(L, y);
+ lua_rawseti(L, -2, 2);
+
+ lua_pushnumber(L, z);
+ lua_rawseti(L, -2, 3);
+
+ lua_pushcfunction(L, honey_glm_new_vec3);
+ lua_pushvalue(L, -2);
+ honey_lua_pcall(L, 1, 1);
+
+ *ref = luaL_ref(L, LUA_REGISTRYINDEX);
+ lua_pop(L, 1);
+}
+
void honey_setup_glm(lua_State* L)
{
/* vec3 metatable */
@@ -127,6 +154,10 @@ void honey_setup_glm(lua_State* L)
HONEY_FUNCTION, "__gc", honey_glm_array_destroy);
honey_glm_mat4_mt_ref = luaL_ref(L, LUA_REGISTRYINDEX);
+
+ create_vec3(L, 1, 0, 0, &honey_glm_UNIT_X_ref);
+ create_vec3(L, 0, 1, 0, &honey_glm_UNIT_Y_ref);
+ create_vec3(L, 0, 0, 1, &honey_glm_UNIT_Z_ref);
/* glm table */
honey_lua_create_table
@@ -135,6 +166,16 @@ void honey_setup_glm(lua_State* L)
HONEY_FUNCTION, "vec4", honey_glm_new_vec4,
HONEY_FUNCTION, "mat3", honey_glm_new_mat3,
HONEY_FUNCTION, "mat4", honey_glm_new_mat4);
+
+ lua_rawgeti(L, LUA_REGISTRYINDEX, honey_glm_UNIT_X_ref);
+ lua_setfield(L, -2, "UNIT_X");
+
+ lua_rawgeti(L, LUA_REGISTRYINDEX, honey_glm_UNIT_Y_ref);
+ lua_setfield(L, -2, "UNIT_Y");
+
+ lua_rawgeti(L, LUA_REGISTRYINDEX, honey_glm_UNIT_Z_ref);
+ lua_setfield(L, -2, "UNIT_Z");
+
lua_setfield(L, -2, "glm");
}
diff --git a/src/glm_bindings.h b/src/glm_bindings.h
index 1b86de2..b04016e 100644
--- a/src/glm_bindings.h
+++ b/src/glm_bindings.h
@@ -12,6 +12,10 @@ extern int honey_glm_vec4_mt_ref;
extern int honey_glm_mat3_mt_ref;
extern int honey_glm_mat4_mt_ref;
+extern honey_glm_array UNIT_X;
+extern honey_glm_array UNIT_Y;
+extern honey_glm_array UNIT_Z;
+
/** @brief Push the honey glm binding functions to the lua stack.
*
* @returns Nothing.
diff --git a/src/honey.c b/src/honey.c
index 4757f53..f58be3e 100644
--- a/src/honey.c
+++ b/src/honey.c
@@ -131,6 +131,8 @@ bool honey_setup(lua_State** L)
honey_setup_texture(*L);
+ honey_setup_scene_tree(*L);
+
lua_pushcfunction(*L, honey_exit);
lua_setfield(*L, -2, "exit");
diff --git a/src/scene_tree.h b/src/scene_tree.h
new file mode 100644
index 0000000..ea1e37b
--- /dev/null
+++ b/src/scene_tree.h
@@ -0,0 +1,23 @@
+#include "common.h"
+
+/* @file Defines the basic scene tree nodes and functions to manipulate them. */
+
+extern int honey_node_mt_ref;
+
+void honey_setup_scene_tree(lua_State* L);
+
+int honey_node_new(lua_State* L);
+
+int honey_node_update_transform(lua_State* L);
+
+int honey_node_update_cascade(lua_State* L);
+
+int honey_node_draw_cascade(lua_State* L);
+
+int honey_node_translate(lua_State* L);
+
+int honey_node_rotate(lua_State* L);
+
+int honey_node_scale(lua_State* L);
+
+
diff --git a/src/scene_tree_node.c b/src/scene_tree_node.c
new file mode 100644
index 0000000..a3ca27e
--- /dev/null
+++ b/src/scene_tree_node.c
@@ -0,0 +1,320 @@
+#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_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);
+
+ lua_pushvalue(L, 1);
+ if (!lua_isnil(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, 5);
+ lua_settable(L, -3);
+ lua_pop(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);
+
+ /* self.transform:eye() */
+ lua_pushcfunction(L, honey_glm_mat4_eye);
+ lua_getfield(L, 1, "transform");
+ lua_pushvalue(L, -1);
+ honey_lua_pcall(L, 1, 0);
+
+ /* self.transform:translate(self.position) */
+ lua_pushcfunction(L, honey_glm_translate);
+ lua_pushvalue(L, 2);
+ lua_getfield(L, 1, "position");
+ honey_lua_pcall(L, 2, 0);
+
+ /* self.transform:rotateZ(self.rotation:at(2)) */
+ lua_pushcfunction(L, honey_glm_rotate_z);
+ lua_pushvalue(L, 2);
+ lua_getfield(L, 1, "position");
+ honey_glm_array* position = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+ lua_pushnumber(L, position->data[2]);
+ honey_lua_pcall(L, 2, 0);
+
+ /* self.transform:rotateY(self.rotation:at(1)) */
+ lua_pushcfunction(L, honey_glm_rotate_y);
+ lua_pushvalue(L, 2);
+ lua_pushnumber(L, position->data[1]);
+ honey_lua_pcall(L, 2, 0);
+
+ /* self.transform:rotateX(self.rotation:at(0)) */
+ lua_pushcfunction(L, honey_glm_rotate_x);
+ lua_pushvalue(L, 2);
+ lua_pushnumber(L, position->data[0]);
+ honey_lua_pcall(L, 2, 0);
+
+ lua_getfield(L, 1, "parent");
+ if (!lua_isnil(L, -1)) {
+ lua_pushcfunction(L, honey_glm_mat4_mul);
+ lua_getfield(L, -2, "transform");
+ lua_pushvalue(L, 2);
+ lua_pushvalue(L, -1);
+ honey_lua_pcall(L, 3, 0);
+ }
+ 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; i<n_children; i++) {
+ lua_rawgeti(L, -1, i+1);
+ lua_pushcfunction(L, honey_node_update_cascade);
+ lua_pushvalue(L, -2);
+ lua_pushnumber(L, dt);
+ honey_lua_pcall(L, 2, 0);
+ lua_pop(L, 1);
+ }
+
+ return 0;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int honey_node_draw_cascade(lua_State* L)
+{
+ honey_lua_parse_arguments(L, 1, 1, HONEY_TABLE, NULL);
+
+ /* call self.draw if it exists */
+ lua_getfield(L, 1, "draw");
+ if (!lua_isnil(L, -1)) {
+ lua_pushvalue(L, 1);
+ honey_lua_pcall(L, 1, 0);
+ }
+ else
+ lua_pop(L, 1);
+
+ /* draw cascade for each child node */
+ lua_getfield(L, 1, "children");
+ int n_children = lua_objlen(L, -1);
+ for (int i=0; i<n_children; i++) {
+ lua_rawgeti(L, -1, i+1);
+ lua_pushcfunction(L, honey_node_draw_cascade);
+ lua_pushvalue(L, -2);
+ honey_lua_pcall(L, 1, 0);
+ lua_pop(L, 1);
+ }
+
+ return 0;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int honey_node_translate(lua_State* L)
+{
+ honey_glm_array* v;
+ honey_lua_parse_arguments(L, 1, 2, HONEY_TABLE, NULL, HONEY_USERDATA, &v);
+
+ lua_pushcfunction(L, honey_glm_vec3_add);
+ lua_getfield(L, 1, "transform");
+ lua_pushvalue(L, 2);
+ lua_pushvalue(L, -2);
+ honey_lua_pcall(L, 3, 0);
+
+ 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;
+}