summaryrefslogtreecommitdiff
path: root/src/import
diff options
context:
space:
mode:
authorsanine <sanine.not@pm.me>2022-09-22 18:30:08 -0500
committersanine <sanine.not@pm.me>2022-09-22 18:30:08 -0500
commitdc6c3052e4df6eecd60ded1b913e7e6476eb9921 (patch)
treef4d25c457fe0cbd5d417bcd1beab894e65689adb /src/import
parentdb0bc36c52a223f96bf0b517ef1053ba6b6b16d9 (diff)
add basic recursive aiNode push
Diffstat (limited to 'src/import')
-rw-r--r--src/import/CMakeLists.txt2
-rw-r--r--src/import/import.c37
-rw-r--r--src/import/import.test.c572
-rw-r--r--src/import/import.test.h18
-rw-r--r--src/import/import_mesh.test.c570
-rw-r--r--src/import/import_node.test.c116
6 files changed, 742 insertions, 573 deletions
diff --git a/src/import/CMakeLists.txt b/src/import/CMakeLists.txt
index fc35779..5b9238b 100644
--- a/src/import/CMakeLists.txt
+++ b/src/import/CMakeLists.txt
@@ -7,4 +7,6 @@ target_sources(honey PUBLIC
target_sources(test PUBLIC
${CMAKE_CURRENT_LIST_DIR}/import.test.c
+ ${CMAKE_CURRENT_LIST_DIR}/import_mesh.test.c
+ ${CMAKE_CURRENT_LIST_DIR}/import_node.test.c
)
diff --git a/src/import/import.c b/src/import/import.c
index d58de0f..400f1d9 100644
--- a/src/import/import.c
+++ b/src/import/import.c
@@ -4,7 +4,7 @@
#include "import.h"
-void push_vector(lua_State *L, struct aiVector3D vec)
+static void push_vector(lua_State *L, struct aiVector3D vec)
{
hs_create_table(L,
hs_str_num("x", vec.x),
@@ -14,7 +14,7 @@ void push_vector(lua_State *L, struct aiVector3D vec)
}
-void push_face(lua_State *L, struct aiFace face)
+static void push_face(lua_State *L, struct aiFace face)
{
lua_createtable(L, face.mNumIndices, 0);
int tbl = lua_gettop(L);
@@ -27,7 +27,7 @@ void push_face(lua_State *L, struct aiFace face)
}
-void push_aistring(lua_State *L, struct aiString str)
+static void push_aistring(lua_State *L, struct aiString str)
{
lua_pushstring(L, str.data);
}
@@ -57,7 +57,7 @@ void push_aistring(lua_State *L, struct aiString str)
* mPrimitiveTypes
* mTextureCoordsNames
*/
-void push_mesh(lua_State *L, struct aiMesh mesh)
+static void push_mesh(lua_State *L, struct aiMesh mesh)
{
/* --=== create mesh table ===-- */
lua_createtable(L, 0, 1);
@@ -196,3 +196,32 @@ void push_mesh(lua_State *L, struct aiMesh mesh)
/* --=== clean up ===-- */
lua_pop(L, pop_count);
}
+
+
+static void push_node(lua_State *L, struct aiNode *node)
+{
+ lua_createtable(L, 0, 0);
+ int nodetbl = lua_gettop(L);
+
+ int pop_count = 0;
+
+ if (node->mMeshes != NULL) {
+ lua_createtable(L, node->mNumMeshes, 0);
+ int meshes = lua_gettop(L);
+ for (int i=0; i<node->mNumMeshes; i++) {
+ lua_pushinteger(L, node->mMeshes[i]+1);
+ lua_rawseti(L, meshes, i+1);
+ }
+ lua_setfield(L, nodetbl, "meshes");
+ }
+
+ if (node->mChildren != NULL) {
+ lua_createtable(L, node->mNumChildren, 0);
+ int children = lua_gettop(L);
+ for (int i=0; i<node->mNumChildren; i++) {
+ push_node(L, node->mChildren[i]);
+ lua_rawseti(L, children, i+1);
+ }
+ lua_setfield(L, nodetbl, "children");
+ }
+}
diff --git a/src/import/import.test.c b/src/import/import.test.c
index bd15205..558398a 100644
--- a/src/import/import.test.c
+++ b/src/import/import.test.c
@@ -1,573 +1,5 @@
-#include <string.h>
-#include <lua.h>
-#include <lauxlib.h>
-#include <honeysuckle.h>
#include "test/honey-test.h"
-
-
-#include "import.c"
-
-
-void test_push_vector()
-{
- lua_State *L = luaL_newstate();
- struct aiVector3D v;
- v.x = 1.5;
- v.y = 2.0;
- v.z = 3.6;
-
- push_vector(L, v);
-
- lily_assert_int_equal(lua_type(L, -1), LUA_TTABLE);
-
- lua_getfield(L, -1, "x");
- lily_assert_int_equal(lua_type(L, -1), LUA_TNUMBER);
- lily_assert_float_equal(lua_tonumber(L, -1), 1.5, 0.1);
- lua_pop(L, 1);
-
- lua_getfield(L, -1, "y");
- lily_assert_int_equal(lua_type(L, -1), LUA_TNUMBER);
- lily_assert_float_equal(lua_tonumber(L, -1), 2.0, 0.1);
- lua_pop(L, 1);
-
- lua_getfield(L, -1, "z");
- lily_assert_int_equal(lua_type(L, -1), LUA_TNUMBER);
- lily_assert_float_equal(lua_tonumber(L, -1), 3.6, 0.1);
- lua_pop(L, 1);
-
- lua_close(L);
-}
-
-
-void test_push_face()
-{
- lua_State *L = luaL_newstate();
- struct aiFace face;
- int indices[] = { 0, 1, 2, 3, 4, 5 };
- face.mIndices = indices;
- face.mNumIndices = 6;
-
- push_face(L, face);
-
- lily_assert_int_equal(lua_type(L, -1), LUA_TTABLE);
- int facetbl = lua_gettop(L);
- lily_assert_int_equal(lua_objlen(L, facetbl), 6);
-
- /* the numbers should be one higher because of lua's 1-indexing */
- lua_rawgeti(L, facetbl, 1);
- lily_assert_int_equal(lua_tointeger(L, -1), 1);
- lua_rawgeti(L, facetbl, 2);
- lily_assert_int_equal(lua_tointeger(L, -1), 2);
- lua_rawgeti(L, facetbl, 3);
- lily_assert_int_equal(lua_tointeger(L, -1), 3);
- lua_rawgeti(L, facetbl, 4);
- lily_assert_int_equal(lua_tointeger(L, -1), 4);
- lua_rawgeti(L, facetbl, 5);
- lily_assert_int_equal(lua_tointeger(L, -1), 5);
- lua_rawgeti(L, facetbl, 6);
- lily_assert_int_equal(lua_tointeger(L, -1), 6);
-
- lua_close(L);
-}
-
-
-void test_push_aistring()
-{
- lua_State *L = luaL_newstate();
- struct aiString str;
- strcpy(str.data, "hello, world!");
-
- push_aistring(L, str);
-
- lily_assert_int_equal(lua_type(L, -1), LUA_TSTRING);
- lily_assert_string_equal((char*) lua_tostring(L, -1), "hello, world!");
-
- lua_close(L);
-}
-
-
-/* --===== mesh tests =====-- */
-
-
-void create_vertices(struct aiMesh *mesh);
-void test_vertices(lua_State *L, int meshtbl);
-
-void create_faces(struct aiMesh *mesh);
-void test_faces(lua_State *L, int meshtbl);
-
-void create_normals(struct aiMesh *mesh);
-void test_normals(lua_State *L, int meshtbl);
-
-void create_tangents(struct aiMesh *mesh);
-void test_tangents(lua_State *L, int meshtbl);
-
-void create_uvs(struct aiMesh *mesh);
-void test_uvs(lua_State *L, int meshtbl);
-
-void test_nil(lua_State *L, int meshtbl, const char *field);
-
-
-#define NUM_MESH_VERTICES 4
-#define NUM_MESH_FACES 2
-
-
-#define ALLOCATE_MEMORY() \
- struct aiVector3D vertices[NUM_MESH_VERTICES]; \
- mesh.mVertices = vertices; \
- struct aiVector3D normals[NUM_MESH_VERTICES]; \
- mesh.mNormals = normals; \
- struct aiVector3D tangents[NUM_MESH_VERTICES]; \
- struct aiVector3D bitangents[NUM_MESH_VERTICES]; \
- mesh.mTangents = tangents; \
- mesh.mBitangents = bitangents; \
- struct aiVector3D uvs[AI_MAX_NUMBER_OF_TEXTURECOORDS * NUM_MESH_VERTICES]; \
- for (int i=0; i<AI_MAX_NUMBER_OF_TEXTURECOORDS; i++) \
- mesh.mTextureCoords[i] = uvs + (i*NUM_MESH_VERTICES); \
- struct aiFace faces[NUM_MESH_FACES]; \
- unsigned int index_array[3*NUM_MESH_FACES]; \
- for (int i=0; i<NUM_MESH_FACES; i++) \
- faces[i].mIndices = index_array + (3*i); \
- mesh.mFaces = faces;
-
-
-
-void test_push_mesh()
-{
- lua_State *L = luaL_newstate();
- struct aiMesh mesh;
- mesh.mNumVertices = NUM_MESH_VERTICES;
- mesh.mNumFaces = 0;
-
- /* allocate memory */
- ALLOCATE_MEMORY();
- mesh.mNormals = NULL;
- mesh.mTangents = NULL;
- mesh.mBitangents = NULL;
- for (int i=0; i<AI_MAX_NUMBER_OF_TEXTURECOORDS; i++)
- mesh.mTextureCoords[i] = NULL;
-
- /* setup mesh */
- create_vertices(&mesh);
-
- /* push */
- int top_before = lua_gettop(L);
- push_mesh(L, mesh);
- int meshtbl = lua_gettop(L);
-
- /* check output */
- lily_assert_int_equal(lua_type(L, meshtbl), LUA_TTABLE);
- lily_assert_int_equal(meshtbl - top_before, 1); /* make sure we cleaned up correctly */
- test_vertices(L, meshtbl);
- test_nil(L, meshtbl, "faces");
-
- lua_close(L);
-}
-
-
-void test_push_mesh_faces()
-{
- lua_State *L = luaL_newstate();
- struct aiMesh mesh;
- mesh.mNumVertices = NUM_MESH_VERTICES;
- mesh.mNumFaces = NUM_MESH_FACES;
-
- /* allocate memory */
- ALLOCATE_MEMORY();
- mesh.mNormals = NULL;
- mesh.mTangents = NULL;
- mesh.mBitangents = NULL;
- for (int i=0; i<AI_MAX_NUMBER_OF_TEXTURECOORDS; i++)
- mesh.mTextureCoords[i] = NULL;
-
- /* setup mesh */
- create_vertices(&mesh);
- create_faces(&mesh);
-
- /* push */
- int top_before = lua_gettop(L);
- push_mesh(L, mesh);
- int meshtbl = lua_gettop(L);
-
- /* check output */
- lily_assert_int_equal(lua_type(L, meshtbl), LUA_TTABLE);
- lily_assert_int_equal(meshtbl - top_before, 1); /* make sure we cleaned up correctly */
- test_vertices(L, meshtbl);
- test_faces(L, meshtbl);
-
- lua_close(L);
-}
-
-
-void test_push_mesh_normals()
-{
- lua_State *L = luaL_newstate();
- struct aiMesh mesh;
- mesh.mNumVertices = NUM_MESH_VERTICES;
- mesh.mNumFaces = NUM_MESH_FACES;
-
- /* allocate memory */
- ALLOCATE_MEMORY();
- mesh.mTangents = NULL;
- mesh.mBitangents = NULL;
- for (int i=0; i<AI_MAX_NUMBER_OF_TEXTURECOORDS; i++)
- mesh.mTextureCoords[i] = NULL;
-
- /* setup mesh */
- create_vertices(&mesh);
- create_faces(&mesh);
- create_normals(&mesh);
-
- /* push */
- int top_before = lua_gettop(L);
- push_mesh(L, mesh);
- int meshtbl = lua_gettop(L);
-
- /* check output */
- lily_assert_int_equal(lua_type(L, meshtbl), LUA_TTABLE);
- lily_assert_int_equal(meshtbl - top_before, 1); /* make sure we cleaned up correctly */
- test_vertices(L, meshtbl);
- test_faces(L, meshtbl);
- test_normals(L, meshtbl);
-
- lua_close(L);
-}
-
-
-void test_push_mesh_tangents()
-{
- lua_State *L = luaL_newstate();
- struct aiMesh mesh;
- mesh.mNumVertices = NUM_MESH_VERTICES;
- mesh.mNumFaces = NUM_MESH_FACES;
-
- /* allocate memory */
- ALLOCATE_MEMORY();
- for (int i=0; i<AI_MAX_NUMBER_OF_TEXTURECOORDS; i++)
- mesh.mTextureCoords[i] = NULL;
-
- /* setup mesh */
- create_vertices(&mesh);
- create_faces(&mesh);
- create_normals(&mesh);
- create_tangents(&mesh);
-
- /* push */
- int top_before = lua_gettop(L);
- push_mesh(L, mesh);
- int meshtbl = lua_gettop(L);
-
- /* check output */
- lily_assert_int_equal(lua_type(L, meshtbl), LUA_TTABLE);
- lily_assert_int_equal(meshtbl - top_before, 1); /* make sure we cleaned up correctly */
- test_vertices(L, meshtbl);
- test_faces(L, meshtbl);
- test_normals(L, meshtbl);
- test_tangents(L, meshtbl);
-
- lua_close(L);
-
-}
-
-
-void test_push_mesh_uvs()
-{
- lua_State *L = luaL_newstate();
- struct aiMesh mesh;
- mesh.mNumVertices = NUM_MESH_VERTICES;
- mesh.mNumFaces = NUM_MESH_FACES;
-
- /* allocate memory */
- ALLOCATE_MEMORY();
-
- /* setup mesh */
- create_vertices(&mesh);
- create_faces(&mesh);
- create_normals(&mesh);
- create_tangents(&mesh);
- create_uvs(&mesh);
-
- /* push */
- int top_before = lua_gettop(L);
- push_mesh(L, mesh);
- int meshtbl = lua_gettop(L);
-
- /* check output */
- lily_assert_int_equal(lua_type(L, meshtbl), LUA_TTABLE);
- lily_assert_int_equal(meshtbl - top_before, 1); /* make sure we cleaned up correctly */
- test_vertices(L, meshtbl);
- test_faces(L, meshtbl);
- test_normals(L, meshtbl);
- test_tangents(L, meshtbl);
- test_uvs(L, meshtbl);
-
- lua_close(L);
-
-}
-
-
-void create_vertices(struct aiMesh *mesh)
-{
- mesh->mVertices[0] = (struct aiVector3D) { 0, 0, 0 };
- mesh->mVertices[1] = (struct aiVector3D) { 0, 0, 1 };
- mesh->mVertices[2] = (struct aiVector3D) { 1, 0, 0 };
- mesh->mVertices[3] = (struct aiVector3D) { 1, 0, 1 };
-}
-
-
-static int check_vector(lua_State *L, int meshtbl, const char *field, int index,
- float x, float y, float z)
-{
- lua_getfield(L, meshtbl, field);
- lily_assert(lua_type(L, -1) == LUA_TTABLE, "field '%s' is not a table!", field);
- lua_rawgeti(L, -1, index);
- lily_assert(lua_type(L, -1) == LUA_TTABLE, "%s[%d] is not a table!", field, index);
-
- lua_getfield(L, -1, "x");
- lily_assert(lua_type(L, -1) == LUA_TNUMBER, "%s[%d].x is not a number!", field, index);
- float vx = lua_tonumber(L, -1);
- lua_pop(L, 1);
-
- lua_getfield(L, -1, "y");
- lily_assert(lua_type(L, -1) == LUA_TNUMBER, "%s[%d].y is not a number!", field, index);
- float vy = lua_tonumber(L, -1);
- lua_pop(L, 1);
-
- lua_getfield(L, -1, "z");
- lily_assert(lua_type(L, -1) == LUA_TNUMBER, "%s[%d].z is not a number!", field, index);
- float vz = lua_tonumber(L, -1);
- lua_pop(L, 1);
-
- lua_pop(L, 2);
- lily_assert(
- (fabs(vx - x) < 0.1) &&
- (fabs(vy - y) < 0.1) &&
- (fabs(vz - z) < 0.1),
- "%s[%d] is [%f, %f, %f], but expected [%f, %f, %f]!",
- field, index,
- vx, vy, vz,
- x, y, z
- );
-}
-
-
-void test_vertices(lua_State *L, int meshtbl)
-{
- check_vector(L, meshtbl, "vertices", 1, 0, 0, 0);
- check_vector(L, meshtbl, "vertices", 2, 0, 0, 1);
- check_vector(L, meshtbl, "vertices", 3, 1, 0, 0);
- check_vector(L, meshtbl, "vertices", 4, 1, 0, 1);
-}
-
-
-static void setup_face(struct aiFace *face, int v0, int v1, int v2)
-{
- face->mNumIndices = 3;
- face->mIndices[0] = v0;
- face->mIndices[1] = v1;
- face->mIndices[2] = v2;
-}
-
-
-void create_faces(struct aiMesh *mesh)
-{
- setup_face(mesh->mFaces + 0, 0, 1, 3);
- setup_face(mesh->mFaces + 1, 0, 3, 2);
-}
-
-
-static int check_face(lua_State *L, int meshtbl, const char *field, int index,
- int v0, int v1, int v2)
-{
- lua_getfield(L, meshtbl, field);
- lily_assert(lua_type(L, -1) == LUA_TTABLE, "field '%s' is not a table!", field);
- lua_rawgeti(L, -1, index);
- lily_assert(lua_type(L, -1) == LUA_TTABLE, "%s[%d] is not a table!", field, index);
-
- lua_rawgeti(L, -1, 1);
- lily_assert(lua_type(L, -1) == LUA_TNUMBER, "%s[%d][1] is not a number!", field, index);
- int vv0 = lua_tointeger(L, -1);
- lua_pop(L, 1);
-
- lua_rawgeti(L, -1, 2);
- lily_assert(lua_type(L, -1) == LUA_TNUMBER, "%s[%d][2] is not a number!", field, index);
- int vv1 = lua_tointeger(L, -1);
- lua_pop(L, 1);
-
- lua_rawgeti(L, -1, 3);
- lily_assert(lua_type(L, -1) == LUA_TNUMBER, "%s[%d][3] is not a number!", field, index);
- int vv2 = lua_tointeger(L, -1);
- lua_pop(L, 1);
-
- lua_pop(L, 2);
- lily_assert(
- (v0 == vv0) &&
- (v1 == vv1) &&
- (v2 == vv2),
- "%s[%d] is [%d, %d, %d], but expected [%d, %d, %d]!",
- field, index,
- vv0, vv1, vv2,
- v0, v1, v2
- );
-}
-
-
-void test_faces(lua_State *L, int meshtbl)
-{
- check_face(L, meshtbl, "faces", 1, 1, 2, 4);
- check_face(L, meshtbl, "faces", 2, 1, 4, 3);
-}
-
-
-void create_normals(struct aiMesh *mesh)
-{
- /* these normals are deliberately not, uh, normalized
- * in order to distinguish them for the purposes of testing.
- * (this could also happen in real life -- assimp won't normalize
- * normals taken straight from the object file)
- */
- mesh->mNormals[0] = (struct aiVector3D) { 0, 0.1, 0 };
- mesh->mNormals[1] = (struct aiVector3D) { 0, 0.2, 0 };
- mesh->mNormals[2] = (struct aiVector3D) { 0, 0.4, 0 };
- mesh->mNormals[3] = (struct aiVector3D) { 0, 1.0, 0 };
-}
-
-
-void test_normals(lua_State *L, int meshtbl)
-{
- check_vector(L, meshtbl, "normals", 1, 0, 0.1, 0);
- check_vector(L, meshtbl, "normals", 2, 0, 0.2, 0);
- check_vector(L, meshtbl, "normals", 3, 0, 0.4, 0);
- check_vector(L, meshtbl, "normals", 4, 0, 1.0, 0);
-}
-
-
-void create_tangents(struct aiMesh *mesh)
-{
- /* these tangents are not normalized -- see note in create_normals */
- mesh->mTangents[0] = (struct aiVector3D) { 0.1, 0, 0 };
- mesh->mTangents[1] = (struct aiVector3D) { 0.2, 0, 0 };
- mesh->mTangents[2] = (struct aiVector3D) { 0.4, 0, 0 };
- mesh->mTangents[3] = (struct aiVector3D) { 1.0, 0, 0 };
-
- mesh->mBitangents[0] = (struct aiVector3D) { 0, 0, 0.1 };
- mesh->mBitangents[1] = (struct aiVector3D) { 0, 0, 0.2 };
- mesh->mBitangents[2] = (struct aiVector3D) { 0, 0, 0.4 };
- mesh->mBitangents[3] = (struct aiVector3D) { 0, 0, 1.0 };
-}
-
-
-void test_tangents(lua_State *L, int meshtbl)
-{
- check_vector(L, meshtbl, "tangents", 1, 0.1, 0, 0);
- check_vector(L, meshtbl, "tangents", 2, 0.2, 0, 0);
- check_vector(L, meshtbl, "tangents", 3, 0.4, 0, 0);
- check_vector(L, meshtbl, "tangents", 4, 1.0, 0, 0);
-
- check_vector(L, meshtbl, "bitangents", 1, 0, 0, 0.1);
- check_vector(L, meshtbl, "bitangents", 2, 0, 0, 0.2);
- check_vector(L, meshtbl, "bitangents", 3, 0, 0, 0.4);
- check_vector(L, meshtbl, "bitangents", 4, 0, 0, 1.0);
-}
-
-
-void create_uvs(struct aiMesh *mesh)
-{
- mesh->mNumUVComponents[0] = 2;
- mesh->mTextureCoords[0][0] = (struct aiVector3D) { 0, 0, 0 };
- mesh->mTextureCoords[0][1] = (struct aiVector3D) { 0, 1, 0 };
- mesh->mTextureCoords[0][2] = (struct aiVector3D) { 1, 0, 0 };
- mesh->mTextureCoords[0][3] = (struct aiVector3D) { 1, 1, 0 };
-
- mesh->mNumUVComponents[1] = 1;
- mesh->mTextureCoords[1][0] = (struct aiVector3D) { 0.0, 0, 0 };
- mesh->mTextureCoords[1][1] = (struct aiVector3D) { 0.2, 0, 0 };
- mesh->mTextureCoords[1][2] = (struct aiVector3D) { 0.4, 0, 0 };
- mesh->mTextureCoords[1][3] = (struct aiVector3D) { 0.8, 0, 0 };
-
- for (int i=2; i<AI_MAX_NUMBER_OF_TEXTURECOORDS; i++)
- mesh->mTextureCoords[i] = NULL;
-}
-
-
-static int check_uv(lua_State *L, int meshtbl, int channel, int index,
- float x, float y, float z)
-{
- lua_getfield(L, meshtbl, "uvs");
- lily_assert(lua_type(L, -1) == LUA_TTABLE, "field 'uvs' is not a table!");
- lua_rawgeti(L, -1, channel);
- lily_assert(lua_type(L, -1) == LUA_TTABLE, "uvs[%d] is not a table!", channel);
- lua_rawgeti(L, -1, index);
- lily_assert(lua_type(L, -1) == LUA_TTABLE, "uvs[%d][%d] is not a table!", channel, index);
-
- lua_getfield(L, -1, "x");
- lily_assert(lua_type(L, -1) == LUA_TNUMBER, "uvs[%d][%d].x is not a number!", channel, index);
- float vx = lua_tonumber(L, -1);
- lua_pop(L, 1);
-
- lua_getfield(L, -1, "y");
- lily_assert(lua_type(L, -1) == LUA_TNUMBER, "uvs[%d][%d].y is not a number!", channel, index);
- float vy = lua_tonumber(L, -1);
- lua_pop(L, 1);
-
- lua_getfield(L, -1, "z");
- lily_assert(lua_type(L, -1) == LUA_TNUMBER, "uvs[%d][%d].z is not a number!", channel, index);
- float vz = lua_tonumber(L, -1);
- lua_pop(L, 1);
-
- lua_pop(L, 3);
- lily_assert(
- (fabs(vx - x) < 0.1) &&
- (fabs(vy - y) < 0.1) &&
- (fabs(vz - z) < 0.1),
- "uvs[%d][%d] is [%f, %f, %f], but expected [%f, %f, %f]!",
- channel, index,
- vx, vy, vz,
- x, y, z
- );
-}
-
-
-void test_uvs(lua_State *L, int meshtbl)
-{
- lua_getfield(L, meshtbl, "numUvComponents");
- lily_assert(lua_type(L, -1) == LUA_TTABLE, "field 'numUvComponents' is not a table!");
- lua_rawgeti(L, -1, 1);
- lily_assert_int_equal(lua_tointeger(L, -1), 2);
- lua_pop(L, 1);
- lua_rawgeti(L, -1, 2);
- lily_assert_int_equal(lua_tointeger(L, -1), 1);
- lua_pop(L, 1);
-
- check_uv(L, meshtbl, 1, 1, 0, 0, 0);
- check_uv(L, meshtbl, 1, 2, 0, 1, 0);
- check_uv(L, meshtbl, 1, 3, 1, 0, 0);
- check_uv(L, meshtbl, 1, 4, 1, 1, 0);
-
- check_uv(L, meshtbl, 2, 1, 0.0, 0, 0);
- check_uv(L, meshtbl, 2, 2, 0.2, 0, 0);
- check_uv(L, meshtbl, 2, 3, 0.4, 0, 0);
- check_uv(L, meshtbl, 2, 4, 0.8, 0, 0);
-
- lua_getfield(L, meshtbl, "uvs");
- int uvtbl = lua_gettop(L);
- for (int i=2; i<AI_MAX_NUMBER_OF_TEXTURECOORDS; i++) {
- lua_rawgeti(L, uvtbl, i+1);
- lily_assert(lua_type(L, -1) == LUA_TNIL, "uv channel %d is non-nil!", i+1);
- lua_pop(L, 1);
- }
- lua_pop(L, 1);
-}
-
-void test_nil(lua_State *L, int meshtbl, const char *field)
-{
- lua_getfield(L, meshtbl, field);
- lily_assert(lua_type(L, -1) == LUA_TNIL, "field '%s' is not nil!");
- lua_pop(L, 1);
-}
-
-
-/* --===== end mesh tests =====-- */
-
+#include "import.test.h"
void suite_import()
{
@@ -580,4 +12,6 @@ void suite_import()
lily_run_test(test_push_mesh_normals);
lily_run_test(test_push_mesh_tangents);
lily_run_test(test_push_mesh_uvs);
+
+ lily_run_test(test_push_node);
}
diff --git a/src/import/import.test.h b/src/import/import.test.h
new file mode 100644
index 0000000..5aafdb3
--- /dev/null
+++ b/src/import/import.test.h
@@ -0,0 +1,18 @@
+#ifndef HONEY_IMPORT_TEST_H
+#define HONEY_IMPORT_TEST_H
+
+void test_push_vector();
+void test_push_face();
+void test_push_aistring();
+
+/* mesh tests */
+void test_push_mesh();
+void test_push_mesh_faces();
+void test_push_mesh_normals();
+void test_push_mesh_tangents();
+void test_push_mesh_uvs();
+
+/* node tests */
+void test_push_node();
+
+#endif
diff --git a/src/import/import_mesh.test.c b/src/import/import_mesh.test.c
new file mode 100644
index 0000000..07400fd
--- /dev/null
+++ b/src/import/import_mesh.test.c
@@ -0,0 +1,570 @@
+#include <string.h>
+#include <lua.h>
+#include <lauxlib.h>
+#include <honeysuckle.h>
+#include "test/honey-test.h"
+#include "import.test.h"
+
+
+#include "import.c"
+
+
+void test_push_vector()
+{
+ lua_State *L = luaL_newstate();
+ struct aiVector3D v;
+ v.x = 1.5;
+ v.y = 2.0;
+ v.z = 3.6;
+
+ push_vector(L, v);
+
+ lily_assert_int_equal(lua_type(L, -1), LUA_TTABLE);
+
+ lua_getfield(L, -1, "x");
+ lily_assert_int_equal(lua_type(L, -1), LUA_TNUMBER);
+ lily_assert_float_equal(lua_tonumber(L, -1), 1.5, 0.1);
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "y");
+ lily_assert_int_equal(lua_type(L, -1), LUA_TNUMBER);
+ lily_assert_float_equal(lua_tonumber(L, -1), 2.0, 0.1);
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "z");
+ lily_assert_int_equal(lua_type(L, -1), LUA_TNUMBER);
+ lily_assert_float_equal(lua_tonumber(L, -1), 3.6, 0.1);
+ lua_pop(L, 1);
+
+ lua_close(L);
+}
+
+
+void test_push_face()
+{
+ lua_State *L = luaL_newstate();
+ struct aiFace face;
+ int indices[] = { 0, 1, 2, 3, 4, 5 };
+ face.mIndices = indices;
+ face.mNumIndices = 6;
+
+ push_face(L, face);
+
+ lily_assert_int_equal(lua_type(L, -1), LUA_TTABLE);
+ int facetbl = lua_gettop(L);
+ lily_assert_int_equal(lua_objlen(L, facetbl), 6);
+
+ /* the numbers should be one higher because of lua's 1-indexing */
+ lua_rawgeti(L, facetbl, 1);
+ lily_assert_int_equal(lua_tointeger(L, -1), 1);
+ lua_rawgeti(L, facetbl, 2);
+ lily_assert_int_equal(lua_tointeger(L, -1), 2);
+ lua_rawgeti(L, facetbl, 3);
+ lily_assert_int_equal(lua_tointeger(L, -1), 3);
+ lua_rawgeti(L, facetbl, 4);
+ lily_assert_int_equal(lua_tointeger(L, -1), 4);
+ lua_rawgeti(L, facetbl, 5);
+ lily_assert_int_equal(lua_tointeger(L, -1), 5);
+ lua_rawgeti(L, facetbl, 6);
+ lily_assert_int_equal(lua_tointeger(L, -1), 6);
+
+ lua_close(L);
+}
+
+
+void test_push_aistring()
+{
+ lua_State *L = luaL_newstate();
+ struct aiString str;
+ strcpy(str.data, "hello, world!");
+
+ push_aistring(L, str);
+
+ lily_assert_int_equal(lua_type(L, -1), LUA_TSTRING);
+ lily_assert_string_equal((char*) lua_tostring(L, -1), "hello, world!");
+
+ lua_close(L);
+}
+
+
+/* --===== mesh tests =====-- */
+
+
+void create_vertices(struct aiMesh *mesh);
+void test_vertices(lua_State *L, int meshtbl);
+
+void create_faces(struct aiMesh *mesh);
+void test_faces(lua_State *L, int meshtbl);
+
+void create_normals(struct aiMesh *mesh);
+void test_normals(lua_State *L, int meshtbl);
+
+void create_tangents(struct aiMesh *mesh);
+void test_tangents(lua_State *L, int meshtbl);
+
+void create_uvs(struct aiMesh *mesh);
+void test_uvs(lua_State *L, int meshtbl);
+
+void test_nil(lua_State *L, int meshtbl, const char *field);
+
+
+#define NUM_MESH_VERTICES 4
+#define NUM_MESH_FACES 2
+
+
+#define ALLOCATE_MEMORY() \
+ struct aiVector3D vertices[NUM_MESH_VERTICES]; \
+ mesh.mVertices = vertices; \
+ struct aiVector3D normals[NUM_MESH_VERTICES]; \
+ mesh.mNormals = normals; \
+ struct aiVector3D tangents[NUM_MESH_VERTICES]; \
+ struct aiVector3D bitangents[NUM_MESH_VERTICES]; \
+ mesh.mTangents = tangents; \
+ mesh.mBitangents = bitangents; \
+ struct aiVector3D uvs[AI_MAX_NUMBER_OF_TEXTURECOORDS * NUM_MESH_VERTICES]; \
+ for (int i=0; i<AI_MAX_NUMBER_OF_TEXTURECOORDS; i++) \
+ mesh.mTextureCoords[i] = uvs + (i*NUM_MESH_VERTICES); \
+ struct aiFace faces[NUM_MESH_FACES]; \
+ unsigned int index_array[3*NUM_MESH_FACES]; \
+ for (int i=0; i<NUM_MESH_FACES; i++) \
+ faces[i].mIndices = index_array + (3*i); \
+ mesh.mFaces = faces;
+
+
+
+void test_push_mesh()
+{
+ lua_State *L = luaL_newstate();
+ struct aiMesh mesh;
+ mesh.mNumVertices = NUM_MESH_VERTICES;
+ mesh.mNumFaces = 0;
+
+ /* allocate memory */
+ ALLOCATE_MEMORY();
+ mesh.mNormals = NULL;
+ mesh.mTangents = NULL;
+ mesh.mBitangents = NULL;
+ for (int i=0; i<AI_MAX_NUMBER_OF_TEXTURECOORDS; i++)
+ mesh.mTextureCoords[i] = NULL;
+
+ /* setup mesh */
+ create_vertices(&mesh);
+
+ /* push */
+ int top_before = lua_gettop(L);
+ push_mesh(L, mesh);
+ int meshtbl = lua_gettop(L);
+
+ /* check output */
+ lily_assert_int_equal(lua_type(L, meshtbl), LUA_TTABLE);
+ lily_assert_int_equal(meshtbl - top_before, 1); /* make sure we cleaned up correctly */
+ test_vertices(L, meshtbl);
+ test_nil(L, meshtbl, "faces");
+
+ lua_close(L);
+}
+
+
+void test_push_mesh_faces()
+{
+ lua_State *L = luaL_newstate();
+ struct aiMesh mesh;
+ mesh.mNumVertices = NUM_MESH_VERTICES;
+ mesh.mNumFaces = NUM_MESH_FACES;
+
+ /* allocate memory */
+ ALLOCATE_MEMORY();
+ mesh.mNormals = NULL;
+ mesh.mTangents = NULL;
+ mesh.mBitangents = NULL;
+ for (int i=0; i<AI_MAX_NUMBER_OF_TEXTURECOORDS; i++)
+ mesh.mTextureCoords[i] = NULL;
+
+ /* setup mesh */
+ create_vertices(&mesh);
+ create_faces(&mesh);
+
+ /* push */
+ int top_before = lua_gettop(L);
+ push_mesh(L, mesh);
+ int meshtbl = lua_gettop(L);
+
+ /* check output */
+ lily_assert_int_equal(lua_type(L, meshtbl), LUA_TTABLE);
+ lily_assert_int_equal(meshtbl - top_before, 1); /* make sure we cleaned up correctly */
+ test_vertices(L, meshtbl);
+ test_faces(L, meshtbl);
+
+ lua_close(L);
+}
+
+
+void test_push_mesh_normals()
+{
+ lua_State *L = luaL_newstate();
+ struct aiMesh mesh;
+ mesh.mNumVertices = NUM_MESH_VERTICES;
+ mesh.mNumFaces = NUM_MESH_FACES;
+
+ /* allocate memory */
+ ALLOCATE_MEMORY();
+ mesh.mTangents = NULL;
+ mesh.mBitangents = NULL;
+ for (int i=0; i<AI_MAX_NUMBER_OF_TEXTURECOORDS; i++)
+ mesh.mTextureCoords[i] = NULL;
+
+ /* setup mesh */
+ create_vertices(&mesh);
+ create_faces(&mesh);
+ create_normals(&mesh);
+
+ /* push */
+ int top_before = lua_gettop(L);
+ push_mesh(L, mesh);
+ int meshtbl = lua_gettop(L);
+
+ /* check output */
+ lily_assert_int_equal(lua_type(L, meshtbl), LUA_TTABLE);
+ lily_assert_int_equal(meshtbl - top_before, 1); /* make sure we cleaned up correctly */
+ test_vertices(L, meshtbl);
+ test_faces(L, meshtbl);
+ test_normals(L, meshtbl);
+
+ lua_close(L);
+}
+
+
+void test_push_mesh_tangents()
+{
+ lua_State *L = luaL_newstate();
+ struct aiMesh mesh;
+ mesh.mNumVertices = NUM_MESH_VERTICES;
+ mesh.mNumFaces = NUM_MESH_FACES;
+
+ /* allocate memory */
+ ALLOCATE_MEMORY();
+ for (int i=0; i<AI_MAX_NUMBER_OF_TEXTURECOORDS; i++)
+ mesh.mTextureCoords[i] = NULL;
+
+ /* setup mesh */
+ create_vertices(&mesh);
+ create_faces(&mesh);
+ create_normals(&mesh);
+ create_tangents(&mesh);
+
+ /* push */
+ int top_before = lua_gettop(L);
+ push_mesh(L, mesh);
+ int meshtbl = lua_gettop(L);
+
+ /* check output */
+ lily_assert_int_equal(lua_type(L, meshtbl), LUA_TTABLE);
+ lily_assert_int_equal(meshtbl - top_before, 1); /* make sure we cleaned up correctly */
+ test_vertices(L, meshtbl);
+ test_faces(L, meshtbl);
+ test_normals(L, meshtbl);
+ test_tangents(L, meshtbl);
+
+ lua_close(L);
+
+}
+
+
+void test_push_mesh_uvs()
+{
+ lua_State *L = luaL_newstate();
+ struct aiMesh mesh;
+ mesh.mNumVertices = NUM_MESH_VERTICES;
+ mesh.mNumFaces = NUM_MESH_FACES;
+
+ /* allocate memory */
+ ALLOCATE_MEMORY();
+
+ /* setup mesh */
+ create_vertices(&mesh);
+ create_faces(&mesh);
+ create_normals(&mesh);
+ create_tangents(&mesh);
+ create_uvs(&mesh);
+
+ /* push */
+ int top_before = lua_gettop(L);
+ push_mesh(L, mesh);
+ int meshtbl = lua_gettop(L);
+
+ /* check output */
+ lily_assert_int_equal(lua_type(L, meshtbl), LUA_TTABLE);
+ lily_assert_int_equal(meshtbl - top_before, 1); /* make sure we cleaned up correctly */
+ test_vertices(L, meshtbl);
+ test_faces(L, meshtbl);
+ test_normals(L, meshtbl);
+ test_tangents(L, meshtbl);
+ test_uvs(L, meshtbl);
+
+ lua_close(L);
+
+}
+
+
+void create_vertices(struct aiMesh *mesh)
+{
+ mesh->mVertices[0] = (struct aiVector3D) { 0, 0, 0 };
+ mesh->mVertices[1] = (struct aiVector3D) { 0, 0, 1 };
+ mesh->mVertices[2] = (struct aiVector3D) { 1, 0, 0 };
+ mesh->mVertices[3] = (struct aiVector3D) { 1, 0, 1 };
+}
+
+
+static int check_vector(lua_State *L, int meshtbl, const char *field, int index,
+ float x, float y, float z)
+{
+ lua_getfield(L, meshtbl, field);
+ lily_assert(lua_type(L, -1) == LUA_TTABLE, "field '%s' is not a table!", field);
+ lua_rawgeti(L, -1, index);
+ lily_assert(lua_type(L, -1) == LUA_TTABLE, "%s[%d] is not a table!", field, index);
+
+ lua_getfield(L, -1, "x");
+ lily_assert(lua_type(L, -1) == LUA_TNUMBER, "%s[%d].x is not a number!", field, index);
+ float vx = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "y");
+ lily_assert(lua_type(L, -1) == LUA_TNUMBER, "%s[%d].y is not a number!", field, index);
+ float vy = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "z");
+ lily_assert(lua_type(L, -1) == LUA_TNUMBER, "%s[%d].z is not a number!", field, index);
+ float vz = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+
+ lua_pop(L, 2);
+ lily_assert(
+ (fabs(vx - x) < 0.1) &&
+ (fabs(vy - y) < 0.1) &&
+ (fabs(vz - z) < 0.1),
+ "%s[%d] is [%f, %f, %f], but expected [%f, %f, %f]!",
+ field, index,
+ vx, vy, vz,
+ x, y, z
+ );
+}
+
+
+void test_vertices(lua_State *L, int meshtbl)
+{
+ check_vector(L, meshtbl, "vertices", 1, 0, 0, 0);
+ check_vector(L, meshtbl, "vertices", 2, 0, 0, 1);
+ check_vector(L, meshtbl, "vertices", 3, 1, 0, 0);
+ check_vector(L, meshtbl, "vertices", 4, 1, 0, 1);
+}
+
+
+static void setup_face(struct aiFace *face, int v0, int v1, int v2)
+{
+ face->mNumIndices = 3;
+ face->mIndices[0] = v0;
+ face->mIndices[1] = v1;
+ face->mIndices[2] = v2;
+}
+
+
+void create_faces(struct aiMesh *mesh)
+{
+ setup_face(mesh->mFaces + 0, 0, 1, 3);
+ setup_face(mesh->mFaces + 1, 0, 3, 2);
+}
+
+
+static int check_face(lua_State *L, int meshtbl, const char *field, int index,
+ int v0, int v1, int v2)
+{
+ lua_getfield(L, meshtbl, field);
+ lily_assert(lua_type(L, -1) == LUA_TTABLE, "field '%s' is not a table!", field);
+ lua_rawgeti(L, -1, index);
+ lily_assert(lua_type(L, -1) == LUA_TTABLE, "%s[%d] is not a table!", field, index);
+
+ lua_rawgeti(L, -1, 1);
+ lily_assert(lua_type(L, -1) == LUA_TNUMBER, "%s[%d][1] is not a number!", field, index);
+ int vv0 = lua_tointeger(L, -1);
+ lua_pop(L, 1);
+
+ lua_rawgeti(L, -1, 2);
+ lily_assert(lua_type(L, -1) == LUA_TNUMBER, "%s[%d][2] is not a number!", field, index);
+ int vv1 = lua_tointeger(L, -1);
+ lua_pop(L, 1);
+
+ lua_rawgeti(L, -1, 3);
+ lily_assert(lua_type(L, -1) == LUA_TNUMBER, "%s[%d][3] is not a number!", field, index);
+ int vv2 = lua_tointeger(L, -1);
+ lua_pop(L, 1);
+
+ lua_pop(L, 2);
+ lily_assert(
+ (v0 == vv0) &&
+ (v1 == vv1) &&
+ (v2 == vv2),
+ "%s[%d] is [%d, %d, %d], but expected [%d, %d, %d]!",
+ field, index,
+ vv0, vv1, vv2,
+ v0, v1, v2
+ );
+}
+
+
+void test_faces(lua_State *L, int meshtbl)
+{
+ check_face(L, meshtbl, "faces", 1, 1, 2, 4);
+ check_face(L, meshtbl, "faces", 2, 1, 4, 3);
+}
+
+
+void create_normals(struct aiMesh *mesh)
+{
+ /* these normals are deliberately not, uh, normalized
+ * in order to distinguish them for the purposes of testing.
+ * (this could also happen in real life -- assimp won't normalize
+ * normals taken straight from the object file)
+ */
+ mesh->mNormals[0] = (struct aiVector3D) { 0, 0.1, 0 };
+ mesh->mNormals[1] = (struct aiVector3D) { 0, 0.2, 0 };
+ mesh->mNormals[2] = (struct aiVector3D) { 0, 0.4, 0 };
+ mesh->mNormals[3] = (struct aiVector3D) { 0, 1.0, 0 };
+}
+
+
+void test_normals(lua_State *L, int meshtbl)
+{
+ check_vector(L, meshtbl, "normals", 1, 0, 0.1, 0);
+ check_vector(L, meshtbl, "normals", 2, 0, 0.2, 0);
+ check_vector(L, meshtbl, "normals", 3, 0, 0.4, 0);
+ check_vector(L, meshtbl, "normals", 4, 0, 1.0, 0);
+}
+
+
+void create_tangents(struct aiMesh *mesh)
+{
+ /* these tangents are not normalized -- see note in create_normals */
+ mesh->mTangents[0] = (struct aiVector3D) { 0.1, 0, 0 };
+ mesh->mTangents[1] = (struct aiVector3D) { 0.2, 0, 0 };
+ mesh->mTangents[2] = (struct aiVector3D) { 0.4, 0, 0 };
+ mesh->mTangents[3] = (struct aiVector3D) { 1.0, 0, 0 };
+
+ mesh->mBitangents[0] = (struct aiVector3D) { 0, 0, 0.1 };
+ mesh->mBitangents[1] = (struct aiVector3D) { 0, 0, 0.2 };
+ mesh->mBitangents[2] = (struct aiVector3D) { 0, 0, 0.4 };
+ mesh->mBitangents[3] = (struct aiVector3D) { 0, 0, 1.0 };
+}
+
+
+void test_tangents(lua_State *L, int meshtbl)
+{
+ check_vector(L, meshtbl, "tangents", 1, 0.1, 0, 0);
+ check_vector(L, meshtbl, "tangents", 2, 0.2, 0, 0);
+ check_vector(L, meshtbl, "tangents", 3, 0.4, 0, 0);
+ check_vector(L, meshtbl, "tangents", 4, 1.0, 0, 0);
+
+ check_vector(L, meshtbl, "bitangents", 1, 0, 0, 0.1);
+ check_vector(L, meshtbl, "bitangents", 2, 0, 0, 0.2);
+ check_vector(L, meshtbl, "bitangents", 3, 0, 0, 0.4);
+ check_vector(L, meshtbl, "bitangents", 4, 0, 0, 1.0);
+}
+
+
+void create_uvs(struct aiMesh *mesh)
+{
+ mesh->mNumUVComponents[0] = 2;
+ mesh->mTextureCoords[0][0] = (struct aiVector3D) { 0, 0, 0 };
+ mesh->mTextureCoords[0][1] = (struct aiVector3D) { 0, 1, 0 };
+ mesh->mTextureCoords[0][2] = (struct aiVector3D) { 1, 0, 0 };
+ mesh->mTextureCoords[0][3] = (struct aiVector3D) { 1, 1, 0 };
+
+ mesh->mNumUVComponents[1] = 1;
+ mesh->mTextureCoords[1][0] = (struct aiVector3D) { 0.0, 0, 0 };
+ mesh->mTextureCoords[1][1] = (struct aiVector3D) { 0.2, 0, 0 };
+ mesh->mTextureCoords[1][2] = (struct aiVector3D) { 0.4, 0, 0 };
+ mesh->mTextureCoords[1][3] = (struct aiVector3D) { 0.8, 0, 0 };
+
+ for (int i=2; i<AI_MAX_NUMBER_OF_TEXTURECOORDS; i++)
+ mesh->mTextureCoords[i] = NULL;
+}
+
+
+static int check_uv(lua_State *L, int meshtbl, int channel, int index,
+ float x, float y, float z)
+{
+ lua_getfield(L, meshtbl, "uvs");
+ lily_assert(lua_type(L, -1) == LUA_TTABLE, "field 'uvs' is not a table!");
+ lua_rawgeti(L, -1, channel);
+ lily_assert(lua_type(L, -1) == LUA_TTABLE, "uvs[%d] is not a table!", channel);
+ lua_rawgeti(L, -1, index);
+ lily_assert(lua_type(L, -1) == LUA_TTABLE, "uvs[%d][%d] is not a table!", channel, index);
+
+ lua_getfield(L, -1, "x");
+ lily_assert(lua_type(L, -1) == LUA_TNUMBER, "uvs[%d][%d].x is not a number!", channel, index);
+ float vx = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "y");
+ lily_assert(lua_type(L, -1) == LUA_TNUMBER, "uvs[%d][%d].y is not a number!", channel, index);
+ float vy = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "z");
+ lily_assert(lua_type(L, -1) == LUA_TNUMBER, "uvs[%d][%d].z is not a number!", channel, index);
+ float vz = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+
+ lua_pop(L, 3);
+ lily_assert(
+ (fabs(vx - x) < 0.1) &&
+ (fabs(vy - y) < 0.1) &&
+ (fabs(vz - z) < 0.1),
+ "uvs[%d][%d] is [%f, %f, %f], but expected [%f, %f, %f]!",
+ channel, index,
+ vx, vy, vz,
+ x, y, z
+ );
+}
+
+
+void test_uvs(lua_State *L, int meshtbl)
+{
+ lua_getfield(L, meshtbl, "numUvComponents");
+ lily_assert(lua_type(L, -1) == LUA_TTABLE, "field 'numUvComponents' is not a table!");
+ lua_rawgeti(L, -1, 1);
+ lily_assert_int_equal(lua_tointeger(L, -1), 2);
+ lua_pop(L, 1);
+ lua_rawgeti(L, -1, 2);
+ lily_assert_int_equal(lua_tointeger(L, -1), 1);
+ lua_pop(L, 1);
+
+ check_uv(L, meshtbl, 1, 1, 0, 0, 0);
+ check_uv(L, meshtbl, 1, 2, 0, 1, 0);
+ check_uv(L, meshtbl, 1, 3, 1, 0, 0);
+ check_uv(L, meshtbl, 1, 4, 1, 1, 0);
+
+ check_uv(L, meshtbl, 2, 1, 0.0, 0, 0);
+ check_uv(L, meshtbl, 2, 2, 0.2, 0, 0);
+ check_uv(L, meshtbl, 2, 3, 0.4, 0, 0);
+ check_uv(L, meshtbl, 2, 4, 0.8, 0, 0);
+
+ lua_getfield(L, meshtbl, "uvs");
+ int uvtbl = lua_gettop(L);
+ for (int i=2; i<AI_MAX_NUMBER_OF_TEXTURECOORDS; i++) {
+ lua_rawgeti(L, uvtbl, i+1);
+ lily_assert(lua_type(L, -1) == LUA_TNIL, "uv channel %d is non-nil!", i+1);
+ lua_pop(L, 1);
+ }
+ lua_pop(L, 1);
+}
+
+void test_nil(lua_State *L, int meshtbl, const char *field)
+{
+ lua_getfield(L, meshtbl, field);
+ lily_assert(lua_type(L, -1) == LUA_TNIL, "field '%s' is not nil!");
+ lua_pop(L, 1);
+}
+
+
+/* --===== end mesh tests =====-- */
diff --git a/src/import/import_node.test.c b/src/import/import_node.test.c
new file mode 100644
index 0000000..4d5c9ef
--- /dev/null
+++ b/src/import/import_node.test.c
@@ -0,0 +1,116 @@
+#include <assimp/scene.h>
+#include <lua.h>
+#include <lauxlib.h>
+#include <honeysuckle.h>
+#include "test/lily-test.h"
+#include "import.test.h"
+
+
+#include "import.c"
+
+
+#define MESH_COUNT 13
+void test_push_node()
+{
+ lua_State *L = luaL_newstate();
+
+ int meshes[MESH_COUNT];
+ for (int i=0; i<MESH_COUNT; i++)
+ meshes[i] = i;
+
+ /* first layer node */
+ struct aiNode root;
+ root.mParent = NULL;
+ root.mMeshes = meshes;
+ root.mNumMeshes = 3;
+
+ /* second layer nodes */
+ struct aiNode nodeA, nodeB;
+ struct aiNode *root_children[] = { &nodeA, &nodeB };
+ root.mChildren = root_children;
+ root.mNumChildren = 2;
+
+ nodeA.mMeshes = meshes + 3;
+ nodeA.mNumMeshes = 2;
+ nodeA.mChildren = NULL;
+
+ nodeB.mMeshes = meshes + 5;
+ nodeB.mNumMeshes = 2;
+ nodeB.mChildren = NULL;
+
+ /* push */
+ int top = lua_gettop(L);
+ push_node(L, &root);
+
+ /* check */
+ lily_assert_int_equal(top+1, lua_gettop(L));
+ lily_assert_int_equal(lua_type(L, -1), LUA_TTABLE);
+
+ int nodetbl = lua_gettop(L);
+
+ /* check meshes */
+ lua_getfield(L, nodetbl, "meshes");
+ lily_assert_int_equal(lua_type(L, -1), LUA_TTABLE);
+
+ lua_rawgeti(L, -1, 1);
+ lily_assert_int_equal(lua_type(L, -1), LUA_TNUMBER);
+ lily_assert_int_equal(lua_tointeger(L, -1), 1);
+ lua_pop(L, 1);
+
+ lua_rawgeti(L, -1, 2);
+ lily_assert_int_equal(lua_type(L, -1), LUA_TNUMBER);
+ lily_assert_int_equal(lua_tointeger(L, -1), 2);
+ lua_pop(L, 1);
+
+ lua_rawgeti(L, -1, 3);
+ lily_assert_int_equal(lua_type(L, -1), LUA_TNUMBER);
+ lily_assert_int_equal(lua_tointeger(L, -1), 3);
+ lua_pop(L, 1);
+
+ /* check children */
+ lua_getfield(L, nodetbl, "children");
+ int childrentbl = lua_gettop(L);
+ lily_assert_int_equal(lua_type(L, -1), LUA_TTABLE);
+
+ lua_rawgeti(L, childrentbl, 1);
+ lily_assert_int_equal(lua_type(L, -1), LUA_TTABLE);
+ int atbl = lua_gettop(L);
+ lua_getfield(L, atbl, "meshes");
+ lily_assert_int_equal(lua_type(L, -1), LUA_TTABLE);
+
+ lua_rawgeti(L, -1, 1);
+ lily_assert_int_equal(lua_type(L, -1), LUA_TNUMBER);
+ lily_assert_int_equal(lua_tointeger(L, -1), 4);
+ lua_pop(L, 1);
+
+ lua_rawgeti(L, -1, 2);
+ lily_assert_int_equal(lua_type(L, -1), LUA_TNUMBER);
+ lily_assert_int_equal(lua_tointeger(L, -1), 5);
+ lua_pop(L, 2);
+
+ lua_getfield(L, atbl, "children");
+ lily_assert_int_equal(lua_type(L, -1), LUA_TNIL);
+ lua_pop(L, 2);
+
+ lua_rawgeti(L, childrentbl, 2);
+ lily_assert_int_equal(lua_type(L, -1), LUA_TTABLE);
+ int btbl = lua_gettop(L);
+ lua_getfield(L, btbl, "meshes");
+ lily_assert_int_equal(lua_type(L, -1), LUA_TTABLE);
+
+ lua_rawgeti(L, -1, 1);
+ lily_assert_int_equal(lua_type(L, -1), LUA_TNUMBER);
+ lily_assert_int_equal(lua_tointeger(L, -1), 6);
+ lua_pop(L, 1);
+
+ lua_rawgeti(L, -1, 2);
+ lily_assert_int_equal(lua_type(L, -1), LUA_TNUMBER);
+ lily_assert_int_equal(lua_tointeger(L, -1), 7);
+ lua_pop(L, 2);
+
+ lua_getfield(L, btbl, "children");
+ lily_assert_int_equal(lua_type(L, -1), LUA_TNIL);
+ lua_pop(L, 2);
+
+ lua_close(L);
+}