diff options
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | demo/Primitives.lua | 20 | ||||
-rw-r--r-- | demo/SpatialShader.lua | 2 | ||||
-rw-r--r-- | demo/main.lua | 20 | ||||
-rw-r--r-- | src/honey.c | 2 | ||||
-rw-r--r-- | src/honey.h | 1 | ||||
-rw-r--r-- | src/mesh.c | 455 | ||||
-rw-r--r-- | src/mesh.h | 9 |
8 files changed, 365 insertions, 145 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a4db6c..dc5807a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,6 @@ set(SOURCE_FILES src/input.c src/honey_lua.c src/mesh.c - src/primitives.c src/shader.c src/texture.c src/window.c) diff --git a/demo/Primitives.lua b/demo/Primitives.lua new file mode 100644 index 0000000..09142a5 --- /dev/null +++ b/demo/Primitives.lua @@ -0,0 +1,20 @@ +local Primitives = {} + +function Primitives.plane(width, height) + return honey.buildMesh{ position = { 0, 0, 0, + width, 0, 0, + 0, height, 0, + width, height, 0 }, + normal = { 0, 0, 1, + 0, 0, 1, + 0, 0, 1, + 0, 0, 1 }, + uv = { 0, 0, + 1, 0, + 0, 1, + 1, 1 }, + faces = { 1, 2, 3, + 4, 2, 1 } } +end + +return Primitives diff --git a/demo/SpatialShader.lua b/demo/SpatialShader.lua index 0c65176..b15859f 100644 --- a/demo/SpatialShader.lua +++ b/demo/SpatialShader.lua @@ -3,7 +3,7 @@ local VertexCode = [[ layout(location = 0) in vec3 position; layout(location = 1) in vec3 normal; -layout(location = 2) in vec2 uv; +layout(location = 4) in vec2 uv; uniform mat4 model; uniform mat4 view; diff --git a/demo/main.lua b/demo/main.lua index 8e8d3d3..6aa5775 100644 --- a/demo/main.lua +++ b/demo/main.lua @@ -1,7 +1,8 @@ local Node = require('Node') local FPSCamera = require('FPSCamera') local SpatialShader = require('SpatialShader') -local ScreenQuad = require('ScreenQuad') +local Primitives = require('Primitives') +-- local ScreenQuad = require('ScreenQuad') local MeshInstance = require('MeshInstance') FPSCamera.movement_speed = 5 @@ -20,25 +21,26 @@ local lightDirection = honey.glm.vec3{1,1,1} lightDirection:normalize() shader:setVec3('directional_lights[0].direction', lightDirection) shader:setVec3('directional_lights[0].color', honey.glm.vec3{0,1,0}) -local meshes = honey.mesh('Suzanne.obj') +local meshes = honey.loadMesh('Suzanne.obj') local suzanne = MeshInstance.new(sceneRoot, honey.glm.vec3{0,0,3}, honey.glm.vec3{0,math.pi,0}, honey.glm.vec3{0.5,1,0.5}, meshes[1], shader) +print(suzanne.mesh) local plane = MeshInstance.new(suzanne, honey.glm.vec3{1,0,0}, honey.glm.vec3{0,0,0}, honey.glm.vec3{1,1,1}, - honey.primitives.plane(4,4), + Primitives.plane(4,4), shader) -local plane2 = MeshInstance.new(suzanne, - honey.glm.vec3{5,0,0}, - honey.glm.vec3{0,math.pi,0}, - honey.glm.vec3{1,1,1}, - honey.primitives.plane(4,4), - shader) +-- local plane2 = MeshInstance.new(suzanne, +-- honey.glm.vec3{5,0,0}, +-- honey.glm.vec3{0,math.pi,0}, +-- honey.glm.vec3{1,1,1}, +-- honey.primitives.plane(4,4), +-- shader) suzanne.update = function(self, dt) self:rotate('y', dt) diff --git a/src/honey.c b/src/honey.c index dc716a4..fef75d7 100644 --- a/src/honey.c +++ b/src/honey.c @@ -127,8 +127,6 @@ bool honey_setup(lua_State** L) honey_setup_mesh(*L); - honey_setup_primitives(*L); - honey_setup_texture(*L); lua_pushcfunction(*L, honey_exit); diff --git a/src/honey.h b/src/honey.h index 66a61a4..38a2562 100644 --- a/src/honey.h +++ b/src/honey.h @@ -11,7 +11,6 @@ #include "glm_bindings.h" #include "input.h" #include "mesh.h" -#include "primitives.h" #include "shader.h" #include "texture.h" #include "window.h" @@ -2,6 +2,27 @@ int honey_mesh_mt_ref = LUA_NOREF; +struct vertex { + float position[3]; + float normal[3]; + float tangent[3]; + float bitangent[3]; + float uv[2]; + float color[4]; + + unsigned int bones[4]; + float weights[4]; +}; + +struct mesh { + unsigned int n_vertices; + struct vertex* vertices; + unsigned int n_indices; + unsigned int* indices; +}; + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + static int honey_mesh_lua_draw(lua_State* L) { honey_mesh* mesh; @@ -21,6 +42,150 @@ static int honey_mesh_lua_delete(lua_State* L) return 0; } +static float get_number(lua_State* L, const char* field, int index) +{ + lua_rawgeti(L, -1, index); + if (!lua_isnumber(L, -1)) + honey_lua_throw_error(L, "all elements of '%s' must be numbers; got %s at %d instead", + field, lua_typename(L, lua_type(L, -1)), index); + + float number = lua_tonumber(L, -1); + lua_pop(L, 1); + return number; +} + +static bool load_field(lua_State* L, const char* field, int length, int fields) +{ + lua_getfield(L, 1, field); + if (lua_isnil(L, -1)) { + return false; + } + if (!lua_istable(L, -1)) + honey_lua_throw_error(L, "expected '%s' to be a table; got %s instead", + field, + lua_typename(L, lua_type(L, -1))); + + int table_len = lua_objlen(L, -1); + if (table_len != fields*length) + honey_lua_throw_error(L, "expected field '%s' to contain %d elements; got %d instead", + field, table_len, fields*length); + + return true; +} + +static int honey_mesh_lua_build(lua_State* L) +{ + honey_lua_parse_arguments(L, 1, 1, HONEY_TABLE, NULL); + + lua_getfield(L, 1, "position"); + if (lua_isnil(L, -1)) + honey_lua_throw_error(L, "a 'position' table is required but was not found"); + int n_vertices = lua_objlen(L, -1)/3; + lua_pop(L, 1); + + lua_getfield(L, 1, "faces"); + if (lua_isnil(L, -1)) + honey_lua_throw_error(L, "a 'faces' table is required but was not found"); + int n_indices = lua_objlen(L, -1); + lua_pop(L, 1); + + + struct mesh m; + m.n_vertices = n_vertices; + m.n_indices = n_indices; + m.vertices = malloc(sizeof(struct vertex) * m.n_vertices); + m.indices = malloc(sizeof(unsigned int) * m.n_indices); + + load_field(L, "position", m.n_vertices, 3); + for (int i=0; i<m.n_vertices; i++) { + m.vertices[i].position[0] = get_number(L, "position", 3*i+1); + m.vertices[i].position[1] = get_number(L, "position", 3*i+2); + m.vertices[i].position[2] = get_number(L, "position", 3*i+3); + } + lua_pop(L, 1); + + load_field(L, "faces", m.n_indices, 1); + for (int i=0; i<m.n_indices; i++) { + m.indices[i] = get_number(L, "faces", i+1); + } + lua_pop(L, 1); + + if (load_field(L, "normal", m.n_vertices, 3)) { + for (int i=0; i<m.n_vertices; i++) { + m.vertices[i].normal[0] = get_number(L, "normal", 3*i+1); + m.vertices[i].normal[1] = get_number(L, "normal", 3*i+2); + m.vertices[i].normal[2] = get_number(L, "normal", 3*i+3); + } + } + lua_pop(L, 1); + + if (load_field(L, "tangent", m.n_vertices, 3)) { + for (int i=0; i<m.n_vertices; i++) { + m.vertices[i].tangent[0] = get_number(L, "tangent", 3*i+1); + m.vertices[i].tangent[1] = get_number(L, "tangent", 3*i+2); + m.vertices[i].tangent[2] = get_number(L, "tangent", 3*i+3); + } + } + lua_pop(L, 1); + + if (load_field(L, "bitangent", m.n_vertices, 3)) { + for (int i=0; i<m.n_vertices; i++) { + m.vertices[i].bitangent[0] = get_number(L, "bitangent", 3*i+1); + m.vertices[i].bitangent[1] = get_number(L, "bitangent", 3*i+2); + m.vertices[i].bitangent[2] = get_number(L, "bitangent", 3*i+3); + } + } + lua_pop(L, 1); + + if (load_field(L, "uv", m.n_vertices, 2)) { + for (int i=0; i<m.n_vertices; i++) { + m.vertices[i].uv[0] = get_number(L, "uv", 2*i+1); + m.vertices[i].uv[1] = get_number(L, "uv", 2*i+2); + } + } + lua_pop(L, 1); + + if (load_field(L, "color", m.n_vertices, 4)) { + for (int i=0; i<4 * m.n_vertices; i++) { + m.vertices[i].color[0] = get_number(L, "color", 4*i+1); + m.vertices[i].color[1] = get_number(L, "color", 4*i+2); + m.vertices[i].color[2] = get_number(L, "color", 4*i+3); + m.vertices[i].color[3] = get_number(L, "color", 4*i+4); + } + } + lua_pop(L, 1); + + if (load_field(L, "bones", m.n_vertices, 4)) { + for (int i=0; i<4 * m.n_vertices; i++) { + m.vertices[i].bones[0] = get_number(L, "bones", 4*i+1); + m.vertices[i].bones[1] = get_number(L, "bones", 4*i+2); + m.vertices[i].bones[2] = get_number(L, "bones", 4*i+3); + m.vertices[i].bones[3] = get_number(L, "bones", 4*i+4); + } + } + lua_pop(L, 1); + + if (load_field(L, "weights", m.n_vertices, 4)) { + for (int i=0; i<4 * m.n_vertices; i++) { + m.vertices[i].weights[0] = get_number(L, "weights", 4*i+1); + m.vertices[i].weights[1] = get_number(L, "weights", 4*i+2); + m.vertices[i].weights[2] = get_number(L, "weights", 4*i+3); + m.vertices[i].weights[3] = get_number(L, "weights", 4*i+4); + } + } + lua_pop(L, 1); + + honey_mesh* mesh = lua_newuserdata(L, sizeof(honey_mesh)); + honey_result result = honey_mesh_new(mesh, m); + lua_rawgeti(L, LUA_REGISTRYINDEX, honey_mesh_mt_ref); + lua_setmetatable(L, -2); + + free(m.vertices); + free(m.indices); + + return 1; +} + void honey_setup_mesh(lua_State* L) { honey_lua_create_table @@ -32,98 +197,110 @@ void honey_setup_mesh(lua_State* L) honey_mesh_mt_ref = luaL_ref(L, LUA_REGISTRYINDEX); lua_pushcfunction(L, honey_mesh_load); - lua_setfield(L, -2, "mesh"); + lua_setfield(L, -2, "loadMesh"); + + lua_pushcfunction(L, honey_mesh_lua_build); + lua_setfield(L, -2, "buildMesh"); } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -static honey_mesh assimp_to_honey_mesh(struct aiMesh* mesh, +static honey_mesh assimp_to_honey_mesh(struct aiMesh* ai_mesh, struct aiScene* scene) { - unsigned int vertex_step = 6; - bool mesh_has_uvs = false; - unsigned int n_vertices = mesh->mNumVertices; - - if (mesh->mTextureCoords[0]) { - mesh_has_uvs = true; - vertex_step = 8; - } - - float* vertices = malloc(sizeof(float) * vertex_step * n_vertices); - for (int i=0; i<n_vertices; i++) { - int j = i*vertex_step; - /* positions */ - vertices[j+0] = mesh->mVertices[i].x; - vertices[j+1] = mesh->mVertices[i].y; - vertices[j+2] = mesh->mVertices[i].z; - - /* normals */ - vertices[j+3] = mesh->mNormals[i].x; - vertices[j+4] = mesh->mNormals[i].y; - vertices[j+5] = mesh->mNormals[i].z; - - /* uvs? */ - if (mesh_has_uvs) { - vertices[j+6] = mesh->mTextureCoords[0][i].x; - vertices[j+7] = mesh->mTextureCoords[0][i].y; - } - } - - unsigned int n_indices = mesh->mNumFaces*3; - unsigned int* indices = malloc(sizeof(unsigned int) * n_indices); - for (int i=0; i<mesh->mNumFaces; i++) { - int j = 3*i; - struct aiFace face = mesh->mFaces[i]; - indices[j+0] = face.mIndices[0]; - indices[j+1] = face.mIndices[1]; - indices[j+2] = face.mIndices[2]; - } - - honey_mesh result; - - if (mesh_has_uvs) { - unsigned int n_attributes = 3; - unsigned int attribute_sizes[] = { 3, 3, 2 }; - honey_mesh_new(&result, - vertices, n_vertices, - n_attributes, attribute_sizes, - indices, n_indices); - } - else { - unsigned int n_attributes = 2; - unsigned int attribute_sizes[] = { 3, 3 }; - honey_mesh_new(&result, - vertices, n_vertices, - n_attributes, attribute_sizes, - indices, n_indices); - } - - free(vertices); - free(indices); - - return result; + struct mesh m; + bool has_normals = ai_mesh->mNormals != NULL; + bool has_tangents = ai_mesh->mTangents != NULL; + bool has_uvs = ai_mesh->mTextureCoords != NULL; + bool has_colors = ai_mesh->mColors != NULL; + + m.n_vertices = ai_mesh->mNumVertices; + + m.vertices = malloc(m.n_vertices * sizeof(struct vertex)); + for (int i=0; i<m.n_vertices; i++) { + m.vertices[i].position[0] = ai_mesh->mVertices[i].x; + m.vertices[i].position[1] = ai_mesh->mVertices[i].y; + m.vertices[i].position[2] = ai_mesh->mVertices[i].z; + + if (has_normals) { + m.vertices[i].normal[0] = ai_mesh->mNormals[i].x; + m.vertices[i].normal[1] = ai_mesh->mNormals[i].y; + m.vertices[i].normal[2] = ai_mesh->mNormals[i].z; + } + else { + m.vertices[i].normal[0] = 0; + m.vertices[i].normal[1] = 0; + m.vertices[i].normal[2] = 0; + } + + if (has_tangents) { + m.vertices[i].tangent[0] = ai_mesh->mTangents[i].x; + m.vertices[i].tangent[1] = ai_mesh->mTangents[i].y; + m.vertices[i].tangent[2] = ai_mesh->mTangents[i].z; + + m.vertices[i].bitangent[0] = ai_mesh->mBitangents[i].x; + m.vertices[i].bitangent[1] = ai_mesh->mBitangents[i].y; + m.vertices[i].bitangent[2] = ai_mesh->mBitangents[i].z; + } + else { + m.vertices[i].tangent[0] = 0; + m.vertices[i].tangent[1] = 0; + m.vertices[i].tangent[2] = 0; + + m.vertices[i].bitangent[0] = 0; + m.vertices[i].bitangent[1] = 0; + m.vertices[i].bitangent[2] = 0; + } + + if (has_uvs) { + m.vertices[i].uv[0] = ai_mesh->mTextureCoords[0][i].x; + m.vertices[i].uv[1] = ai_mesh->mTextureCoords[0][i].y; + } + else { + m.vertices[i].uv[0] = 0; + m.vertices[i].uv[1] = 0; + } + } + + m.n_indices = ai_mesh->mNumFaces*3; + m.indices = malloc(sizeof(unsigned int) * m.n_indices); + for (int i=0; i<ai_mesh->mNumFaces; i++) { + int j = 3*i; + struct aiFace face = ai_mesh->mFaces[i]; + m.indices[j+0] = face.mIndices[0]; + m.indices[j+1] = face.mIndices[1]; + m.indices[j+2] = face.mIndices[2]; + } + + honey_mesh result; + honey_mesh_new(&result, m); + + free(m.vertices); + free(m.indices); + + return result; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ static void process_nodes_recursively(lua_State* L, - struct aiScene* scene, - struct aiNode* node, - int* n_meshes) + struct aiScene* scene, + struct aiNode* node, + int* n_meshes) { for (int i=0; i<node->mNumMeshes; i++) { - honey_mesh* mesh = lua_newuserdata(L, sizeof(honey_mesh)); + honey_mesh* mesh = lua_newuserdata(L, sizeof(honey_mesh)); lua_rawgeti(L, LUA_REGISTRYINDEX, honey_mesh_mt_ref); lua_setmetatable(L, -2); - struct aiMesh* assimp_mesh = scene->mMeshes[node->mMeshes[i]]; - *mesh = assimp_to_honey_mesh(assimp_mesh, scene); - lua_rawseti(L, -2, *n_meshes); - (*n_meshes)++; + struct aiMesh* assimp_mesh = scene->mMeshes[node->mMeshes[i]]; + *mesh = assimp_to_honey_mesh(assimp_mesh, scene); + lua_rawseti(L, -2, *n_meshes); + (*n_meshes)++; } for (int i=0; i<node->mNumChildren; i++) { - process_nodes_recursively(L, scene, node->mChildren[i], n_meshes); + process_nodes_recursively(L, scene, node->mChildren[i], n_meshes); } } @@ -137,23 +314,23 @@ int honey_mesh_load(lua_State* L) int n_meshes = 1; struct aiScene* scene = aiImportFile(filename, - aiProcess_Triangulate | - aiProcess_FlipUVs); + aiProcess_Triangulate | + aiProcess_FlipUVs); if (scene == NULL) { - char* error; - honey_format_string(&error, "could not open file '%s'", filename); - lua_pushstring(L, error); - free(error); - lua_error(L); + char* error; + honey_format_string(&error, "could not open file '%s'", filename); + lua_pushstring(L, error); + free(error); + lua_error(L); } if (scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || - scene->mRootNode == NULL) { - char* error; - honey_format_string(&error, "could not read mesh(es) in '%s'", filename); - lua_pushstring(L, error); - free(error); - lua_error(L); + scene->mRootNode == NULL) { + char* error; + honey_format_string(&error, "could not read mesh(es) in '%s'", filename); + lua_pushstring(L, error); + free(error); + lua_error(L); } lua_createtable(L, 0, 0); @@ -166,56 +343,84 @@ int honey_mesh_load(lua_State* L) /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ honey_result honey_mesh_new(honey_mesh* mesh, - float* vertices, - unsigned int n_vertices, - unsigned int n_attributes, - unsigned int* attribute_sizes, - unsigned int* indices, - unsigned int n_indices) { - if (vertices == NULL || n_vertices == 0) { - return HONEY_MESH_BAD_VERTEX_DATA; - } - if (indices == NULL || n_indices == 0) { - return HONEY_MESH_BAD_INDEX_DATA; + struct mesh m) +{ + if (m.vertices == NULL || m.n_vertices == 0) { + return HONEY_MESH_BAD_VERTEX_DATA; } - - unsigned int vertex_size = 0; - for (int i=0; i<n_attributes; i++) { - vertex_size += attribute_sizes[i]; + if (m.indices == NULL || m.n_indices == 0) { + return HONEY_MESH_BAD_INDEX_DATA; } - (*mesh).n_vertices = n_vertices; - (*mesh).n_indices = n_indices; + mesh->n_vertices = m.n_vertices; + mesh->n_indices = m.n_indices; - glGenVertexArrays(1, &((*mesh).vertex_array)); - glGenBuffers(1, &((*mesh).vertex_buffer)); - glGenBuffers(1, &((*mesh).element_buffer)); + glGenVertexArrays(1, &(mesh->vertex_array)); + glGenBuffers(1, &(mesh->vertex_buffer)); + glGenBuffers(1, &(mesh->element_buffer)); - glBindVertexArray((*mesh).vertex_array); + glBindVertexArray(mesh->vertex_array); - glBindBuffer(GL_ARRAY_BUFFER, (*mesh).vertex_buffer); + glBindBuffer(GL_ARRAY_BUFFER, mesh->vertex_buffer); glBufferData(GL_ARRAY_BUFFER, - vertex_size * n_vertices * sizeof(float), - vertices, GL_STATIC_DRAW); + m.n_vertices * sizeof(struct vertex), + m.vertices, GL_STATIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (*mesh).element_buffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->element_buffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, - n_indices * sizeof(unsigned int), - indices, GL_STATIC_DRAW); + m.n_indices * sizeof(unsigned int), + m.indices, GL_STATIC_DRAW); /* set up vertex attributes */ - unsigned int offset = 0; - for (int i=0; i<n_attributes; i++) { - glEnableVertexAttribArray(i); - glVertexAttribPointer(i, - attribute_sizes[i], - GL_FLOAT, - GL_FALSE, - vertex_size*sizeof(float), - (void*) (offset*sizeof(float))); - offset += attribute_sizes[i]; - } - + size_t offset = 0; + /* position */ + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, + sizeof(struct vertex), offset); + offset += 3*sizeof(float); + + /* normal */ + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, + sizeof(struct vertex), offset); + offset += 3*sizeof(float); + + /* tangent */ + glEnableVertexAttribArray(2); + glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, + sizeof(struct vertex), offset); + offset += 3*sizeof(float); + + /* bitangent */ + glEnableVertexAttribArray(3); + glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, + sizeof(struct vertex), offset); + offset += 3*sizeof(float); + + /* UV */ + glEnableVertexAttribArray(4); + glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, + sizeof(struct vertex), offset); + offset += 2*sizeof(float); + + /* color */ + glEnableVertexAttribArray(5); + glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, + sizeof(struct vertex), offset); + offset += 4*sizeof(float); + + /* bone indices */ + glEnableVertexAttribArray(6); + glVertexAttribPointer(6, 4, GL_UNSIGNED_INT, GL_FALSE, + sizeof(struct vertex), offset); + offset += 4*sizeof(unsigned int); + + /* bone weights */ + glEnableVertexAttribArray(7); + glVertexAttribPointer(7, 4, GL_FLOAT, GL_FALSE, + sizeof(struct vertex), offset); + + /* done */ glBindVertexArray(0); return HONEY_OK; @@ -26,6 +26,8 @@ void honey_setup_mesh(lua_State* L); */ int honey_mesh_load(lua_State* L); +struct mesh; + /** @brief Create a new mesh from vertex and index arrays. * * Note that this function creates copies of the vertex and index arrays, @@ -40,12 +42,7 @@ int honey_mesh_load(lua_State* L); * @param[in] n_indices The number of elements in the index array */ honey_result honey_mesh_new(honey_mesh* mesh, - float* vertices, - unsigned int n_vertices, - unsigned int n_attributes, - unsigned int* attribute_sizes, - unsigned int* indices, - unsigned int n_indices); + struct mesh m); /** @brief Draw a mesh on screen. * |