From b366f3d0c573468ecd0b59da43dfcbc847334b19 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Fri, 14 Feb 2020 17:09:48 +0100 Subject: Add obj parser --- include/DataView.hpp | 2 + include/File.hpp | 7 ++ include/model_loader/ObjModelLoader.hpp | 11 +++ src/File.cpp | 51 ++++++++++++ src/main.cpp | 45 ++++++++-- src/model_loader/ObjModelLoader.cpp | 143 ++++++++++++++++++++++++++++++++ 6 files changed, 253 insertions(+), 6 deletions(-) create mode 100644 include/File.hpp create mode 100644 include/model_loader/ObjModelLoader.hpp create mode 100644 src/File.cpp create mode 100644 src/model_loader/ObjModelLoader.cpp diff --git a/include/DataView.hpp b/include/DataView.hpp index c9e25e7..d4200c5 100644 --- a/include/DataView.hpp +++ b/include/DataView.hpp @@ -23,4 +23,6 @@ namespace amalgine T *data; usize size; }; + + using StringView = DataView; } diff --git a/include/File.hpp b/include/File.hpp new file mode 100644 index 0000000..6c5212f --- /dev/null +++ b/include/File.hpp @@ -0,0 +1,7 @@ +#pragma once + +#include + +namespace amalgine { + char* file_get_content(const char *filepath, size_t *filesize); +} \ No newline at end of file diff --git a/include/model_loader/ObjModelLoader.hpp b/include/model_loader/ObjModelLoader.hpp new file mode 100644 index 0000000..3cdeb7d --- /dev/null +++ b/include/model_loader/ObjModelLoader.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include "../Triangle.hpp" +#include + +namespace amalgine { + class ObjModelLoader { + public: + static void load_from_file(const char *filepath, std::vector &triangles); + }; +} \ No newline at end of file diff --git a/src/File.cpp b/src/File.cpp new file mode 100644 index 0000000..b41d0ca --- /dev/null +++ b/src/File.cpp @@ -0,0 +1,51 @@ +#include "../include/File.hpp" +#include +#include +#include +#include +#include +#include + +namespace amalgine { + char* file_get_content(const char *filepath, size_t *filesize) { + struct stat file_stat; + int fd = open(filepath, O_RDONLY); + char *result = NULL; + *filesize = 0; + if(fd == -1) { + perror(filepath); + return NULL; + } + + if(fstat(fd, &file_stat) == -1) { + perror(filepath); + goto cleanup; + } + + if(!S_ISREG(file_stat.st_mode)) { + fprintf(stderr, "Error: %s is not a file\n", filepath); + goto cleanup; + } + + *filesize = file_stat.st_size; + result = (char*)malloc(*filesize + 1); + if(!result) { + *filesize = 0; + fprintf(stderr, "Error: Failed to malloc %lu bytes from file %s\n", *filesize, filepath); + goto cleanup; + } + + result[*filesize] = '\0'; + if((size_t)read(fd, result, *filesize) != *filesize) { + free(result); + result = NULL; + *filesize = 0; + fprintf(stderr, "Error: Failed to read all data from file %s\n", filepath); + goto cleanup; + } + + cleanup: + close(fd); + return result; + } +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index c073a43..6f825b1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,6 +5,8 @@ #include "../include/RenderBackend/OpenGL/DeviceFrame.hpp" #include "../include/Triangle.hpp" +#include "../include/model_loader/ObjModelLoader.hpp" + #include #include @@ -21,6 +23,10 @@ static GLFWwindow *createWindow(); static std::unique_ptr load_shader_from_file(const char *filepath, Shader::Type shader_type); static std::unique_ptr build_shader_program_from_shaders(const std::vector &shaders); +struct Userdata { + float cam_dist; +}; + int main() { initGlfw(); @@ -44,7 +50,10 @@ int main() Vertex3D(0.0f, 1.0f, 0.0f) ), }; - DataView cpuTriangles(cpuTriangle.data(), cpuTriangle.size()); + //DataView cpuTriangles(cpuTriangle.data(), cpuTriangle.size()); + std::vector triangles; + ObjModelLoader::load_from_file("/home/dec05eba/Downloads/FinalBaseMesh.obj", triangles); + DataView cpuTriangles(triangles.data(), triangles.size()); DeviceMemory *gpuTriangle = frame.alloc(); gpuTriangle->copy(cpuTriangles, DeviceMemory::StorageType::STATIC); @@ -64,9 +73,19 @@ int main() Result view_uniform = shader_program->get_uniform_by_name("view"); Result model_uniform = shader_program->get_uniform_by_name("model"); - glm::vec3 character_pos(0.0f, 3.0f, 3.0f); + Userdata userdata; + userdata.cam_dist = 3.0f; + glm::vec3 character_pos(0.0f, 0.0f, userdata.cam_dist); auto t_start = std::chrono::high_resolution_clock::now(); + + glfwSetWindowUserPointer(window, &userdata); + + glfwSetScrollCallback(window, [](GLFWwindow *window, double xoffset, double yoffset){ + Userdata *userdata = (Userdata*)glfwGetWindowUserPointer(window); + userdata->cam_dist += yoffset; + }); + //glEnable(GL_CULL_FACE); while(!glfwWindowShouldClose(window)) { glfwPollEvents(); if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) @@ -76,10 +95,17 @@ int main() float time_delta = std::chrono::duration_cast>(t_now - t_start).count(); t_start = t_now; + float move_speed = time_delta * 3.0f; if(glfwGetKey(window, GLFW_KEY_W)) - character_pos.y -= time_delta; + character_pos.y -= move_speed; if(glfwGetKey(window, GLFW_KEY_S)) - character_pos.y += time_delta; + character_pos.y += move_speed; + if(glfwGetKey(window, GLFW_KEY_A)) + character_pos.x += move_speed; + if(glfwGetKey(window, GLFW_KEY_D)) + character_pos.x -= move_speed; + + character_pos.z = userdata.cam_dist; glm::mat4 view = glm::lookAt( character_pos, @@ -100,7 +126,9 @@ int main() glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Do the actual screen clearing, using the color set using glClearColor glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); frame.draw(shader_program.get()); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glfwSwapBuffers(window); } @@ -121,7 +149,7 @@ void initGlfw() exit(-1); } - glfwWindowHint(GLFW_SAMPLES, 4); + glfwWindowHint(GLFW_SAMPLES, 4); // anti aliasing glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); @@ -138,7 +166,12 @@ void initGlew() { } } +static void error_callback(int error, const char *description) { + fprintf(stderr, "Opengl error: %s (%d)\n", description, error); +} + GLFWwindow* createWindow() { + glfwSetErrorCallback(error_callback); GLFWwindow *window = glfwCreateWindow(1280, 720, "Amalgine", nullptr, nullptr); if(!window) { @@ -149,7 +182,7 @@ GLFWwindow* createWindow() { glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_FALSE); glfwMakeContextCurrent(window); - glfwSwapInterval(0); + glfwSwapInterval(1); // 1 = enable vsync initGlew(); return window; } diff --git a/src/model_loader/ObjModelLoader.cpp b/src/model_loader/ObjModelLoader.cpp new file mode 100644 index 0000000..1bae458 --- /dev/null +++ b/src/model_loader/ObjModelLoader.cpp @@ -0,0 +1,143 @@ +#include "../../include/model_loader/ObjModelLoader.hpp" +#include "../../include/File.hpp" +#include "../../include/DataView.hpp" +#include +#include +#include +#include + +namespace amalgine { + static StringView get_line(char *str, size_t size) { + #if 0 + char *found_ptr = (char*)memchr(str, '\n', size); + if(!found_ptr) + found_ptr = str + size; + return { str, static_cast(found_ptr - str) }; + #endif + for(size_t i = 0; i < size; ++i) { + char c = str[i]; + if(c == '\n') + return { str, i }; + } + return { str, size }; + } + + static bool is_whitespace(char c) { + switch(c) { + case ' ': + case '\t': + case '\n': + case '\r': + case '\v': + return true; + default: + return false; + } + } + + static bool contains_non_whitespace(const char *str, size_t size) { + for(size_t i = 0; i < size; ++i) { + if(!is_whitespace(str[i])) + return true; + } + return false; + } + + // Return the number of columns, limited by @output_size + static int split_columns(const StringView &str, StringView *output, int output_size) { + char *data = str.data; + ssize_t size = str.size; + + int column = 0; + while(size > 0) { + char *found_ptr = (char*)memchr(data, ' ', size); + if(!found_ptr) + found_ptr = data + size; + + size_t column_size = static_cast(found_ptr - data); + if(column_size > 0 && contains_non_whitespace(data, column_size)) { + output[column++] = { data, column_size }; + if(column == output_size) + break; + } + + data = found_ptr + 1; + size -= (column_size + 1); + } + + return column; + } + + static size_t find_or_end(const StringView &str, char c) { + char *found_ptr = (char*)memchr(str.data, c, str.size); + if(!found_ptr) + found_ptr = str.data + str.size; + return static_cast(found_ptr - str.data); + } + + void ObjModelLoader::load_from_file(const char *filepath, std::vector &triangles) { + size_t file_size; + char *file_data = file_get_content(filepath, &file_size); + triangles.clear(); + if(!file_data) + return; + + const int max_columns = 12; + StringView columns[max_columns]; + + std::vector vertices; + + char *data = file_data; + ssize_t size = file_size; + while(size > 0) { + StringView line_data = get_line(data, size); + + if(line_data.size > 2 && memcmp(line_data.data, "v ", 2) == 0) { + //printf("line: |%.*s|\n", line_data.size, line_data.data); + StringView column_data = { line_data.data + 1, line_data.size - 1 }; + + int num_columns = split_columns(column_data, columns, max_columns); + if(num_columns >= 3) { + columns[0].data[columns[0].size] = '\0'; + columns[1].data[columns[1].size] = '\0'; + columns[2].data[columns[2].size] = '\0'; + vertices.push_back({ atof(columns[0].data), atof(columns[1].data), atof(columns[2].data) }); + } + } else if(line_data.size > 2 && memcmp(line_data.data, "f ", 2) == 0) { + //printf("line: |%.*s|\n", line_data.size, line_data.data); + StringView column_data = { line_data.data + 1, line_data.size - 1 }; + + int num_columns = split_columns(column_data, columns, max_columns); + if(num_columns == 3 || num_columns == 4) { + bool valid = true; + int indices[4]; + for(int i = 0; i < num_columns; ++i) { + columns[i].size = find_or_end(columns[i], '/'); + columns[i].data[columns[i].size] = '\0'; + indices[i] = atoi(columns[i].data); + //printf("column[%d] = %.*s = %d\n", i, columns[i].size, columns[i].data, vertices.size()); + if(indices[i] < 1 || indices[i] > vertices.size()) { + valid = false; + break; + } + --indices[i]; + } + + if(valid) { + if(num_columns == 3) { + triangles.push_back({ vertices[indices[0]], vertices[indices[1]], vertices[indices[2]] }); + } else if(num_columns == 4) { + triangles.push_back({ vertices[indices[0]], vertices[indices[1]], vertices[indices[3]] }); + triangles.push_back({ vertices[indices[3]], vertices[indices[2]], vertices[indices[1]] }); + } + } + } + } + + data += (line_data.size + 1); + size -= (line_data.size + 1); + } + + free(file_data); + } +} \ No newline at end of file -- cgit v1.2.3