From e4d073947d09634e95325ddaf8f1615f85e85901 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sat, 15 Feb 2020 01:36:41 +0100 Subject: Load texture in obj model loader.. broken --- src/Image.cpp | 48 ++++++++ src/RenderBackend/OpenGL/DeviceMemory.cpp | 28 ++--- src/RenderBackend/OpenGL/Image.cpp | 48 -------- src/RenderBackend/OpenGL/Shader.cpp | 1 + src/RenderBackend/OpenGL/ShaderProgram.cpp | 4 +- src/RenderBackend/OpenGL/Texture2D.cpp | 52 ++++++++- src/RenderBackend/OpenGL/Uniform.cpp | 10 ++ src/main.cpp | 111 ++++++++++++------ src/model_loader/ObjModelLoader.cpp | 176 ++++++++++++++++++++++++----- 9 files changed, 342 insertions(+), 136 deletions(-) create mode 100644 src/Image.cpp delete mode 100644 src/RenderBackend/OpenGL/Image.cpp (limited to 'src') diff --git a/src/Image.cpp b/src/Image.cpp new file mode 100644 index 0000000..c312f88 --- /dev/null +++ b/src/Image.cpp @@ -0,0 +1,48 @@ +#include "../../../include/Image.hpp" +#include + +using namespace std; + +namespace amalgine +{ + Image::Image(unsigned char *_imageData, i32 _width, i32 _height) : imageData(_imageData), width(_width), height(_height) + { + + } + + Result Image::loadFromFile(const char *filepath) + { + int width; + int height; + unsigned char *imageData = SOIL_load_image(filepath, &width, &height, 0, SOIL_LOAD_RGB); + if(!imageData) + { + string errMsg = "Failed to load image from file: "; + errMsg += filepath; + errMsg += "; SOIL error message: "; + errMsg += SOIL_last_result(); + return Result::Err(errMsg); + } + return Result::Ok(new Image(imageData, width, height)); + } + + const unsigned char* Image::getData() const + { + return imageData; + } + + i32 Image::getWidth() const + { + return width; + } + + i32 Image::getHeight() const + { + return height; + } + + Image::~Image() + { + SOIL_free_image_data(imageData); + } +} diff --git a/src/RenderBackend/OpenGL/DeviceMemory.cpp b/src/RenderBackend/OpenGL/DeviceMemory.cpp index f071cd8..a82cdaa 100644 --- a/src/RenderBackend/OpenGL/DeviceMemory.cpp +++ b/src/RenderBackend/OpenGL/DeviceMemory.cpp @@ -15,24 +15,6 @@ namespace amalgine } } - u32 getOpenglPrimitiveType(DeviceMemory::PrimitiveType primitiveType) - { - switch(primitiveType) - { - case DeviceMemory::PrimitiveType::TRIANGLE: return GL_TRIANGLES; - default: assert(false); return -1; - } - } - - u32 getPrimitiveTypePointsPerVertices(DeviceMemory::PrimitiveType primitiveType) - { - switch(primitiveType) - { - case DeviceMemory::PrimitiveType::TRIANGLE: return 3; - default: assert(false); return -1; - } - } - DeviceMemory::DeviceMemory() : primitiveType(0), numVertices(0), type(DeviceMemoryType::NONE) { glGenBuffers(1, &vertexBufferObjectId); @@ -57,12 +39,20 @@ namespace amalgine numVertices = getPrimitiveTypePointsPerVertices(primitiveType); } */ + void DeviceMemory::copy(const DataView &texture_coords, StorageType storageType) { + glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjectId); + glBufferData(GL_ARRAY_BUFFER, texture_coords.getByteSize(), texture_coords.data, getOpenglStorageType(storageType)); + primitiveType = GL_TRIANGLES; + numVertices = texture_coords.size * 2; + type = DeviceMemoryType::VEC2; + } + void DeviceMemory::copy(const DataView &triangles, StorageType storageType) { glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjectId); glBufferData(GL_ARRAY_BUFFER, triangles.getByteSize(), triangles.data, getOpenglStorageType(storageType)); primitiveType = GL_TRIANGLES; - numVertices = triangles.size * 3; + numVertices = triangles.size * 2; type = DeviceMemoryType::VEC2; } diff --git a/src/RenderBackend/OpenGL/Image.cpp b/src/RenderBackend/OpenGL/Image.cpp deleted file mode 100644 index 128a580..0000000 --- a/src/RenderBackend/OpenGL/Image.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "../../../include/RenderBackend/OpenGL/Image.hpp" -#include - -using namespace std; - -namespace amalgine -{ - Image::Image(unsigned char *_imageData, i32 _width, i32 _height) : imageData(_imageData), width(_width), height(_height) - { - - } - - Result Image::loadFromFile(const char *filepath) - { - int width; - int height; - unsigned char *imageData = SOIL_load_image(filepath, &width, &height, 0, SOIL_LOAD_RGB); - if(!imageData) - { - string errMsg = "Failed to load image from file: "; - errMsg += filepath; - errMsg += "; SOIL error message: "; - errMsg += SOIL_last_result(); - return Result::Err(errMsg); - } - return Result::Ok(new Image(imageData, width, height)); - } - - const unsigned char* Image::getData() const - { - return imageData; - } - - i32 Image::getWidth() const - { - return width; - } - - i32 Image::getHeight() const - { - return height; - } - - Image::~Image() - { - SOIL_free_image_data(imageData); - } -} diff --git a/src/RenderBackend/OpenGL/Shader.cpp b/src/RenderBackend/OpenGL/Shader.cpp index 3b6563f..32e2fe6 100644 --- a/src/RenderBackend/OpenGL/Shader.cpp +++ b/src/RenderBackend/OpenGL/Shader.cpp @@ -10,6 +10,7 @@ namespace amalgine { return GL_FRAGMENT_SHADER; } assert(false); + return 0; } static std::string get_shader_compile_log(GLuint shaderId) diff --git a/src/RenderBackend/OpenGL/ShaderProgram.cpp b/src/RenderBackend/OpenGL/ShaderProgram.cpp index 389a929..14b15aa 100644 --- a/src/RenderBackend/OpenGL/ShaderProgram.cpp +++ b/src/RenderBackend/OpenGL/ShaderProgram.cpp @@ -73,7 +73,7 @@ namespace amalgine { return Result::Ok(std::move(uniform)); } - int ShaderProgram::set_vertex_input(const char *name, const DeviceMemory &data) { + int ShaderProgram::set_input_data(const char *name, const DeviceMemory &data) { GLint attrib_location = glGetAttribLocation(program_id, name); if(attrib_location == -1) { fprintf(stderr, "No such attribute in shader: %s\n", name); @@ -81,6 +81,7 @@ namespace amalgine { } data.use(); + glEnableVertexAttribArray(attrib_location); switch(data.get_type()) { case DeviceMemoryType::NONE: return -1; @@ -93,7 +94,6 @@ namespace amalgine { break; } } - glEnableVertexAttribArray(attrib_location); return 0; } diff --git a/src/RenderBackend/OpenGL/Texture2D.cpp b/src/RenderBackend/OpenGL/Texture2D.cpp index 07d807a..a561f6e 100644 --- a/src/RenderBackend/OpenGL/Texture2D.cpp +++ b/src/RenderBackend/OpenGL/Texture2D.cpp @@ -1,15 +1,54 @@ #include "../../../include/RenderBackend/OpenGL/Texture2D.hpp" -#include "../../../include/RenderBackend/OpenGL/Image.hpp" #include "../../../include/RenderBackend/OpenGL/opengl.hpp" +#include "../../../include/Image.hpp" +#include #include -namespace amalgine -{ +namespace amalgine { + struct TextureIdAllocator { + TextureIdAllocator(){ + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_units); + if(max_texture_units < 1) + max_texture_units = 1; + printf("max texture units: %d\n", max_texture_units); + } + + u32 get_free_texture_id() { + if(!free_spots.empty()) { + u32 texture_id = free_spots.top(); + free_spots.pop(); + return texture_id; + } + + if(texture_id_counter + 1 == max_texture_units) { + fprintf(stderr, "Error: No free spot left for textures, resetting counter\n"); + texture_id_counter = 0; + } + + return texture_id_counter++; + } + + void free_texture_id(i32 texture_id) { + free_spots.push(texture_id); + } + + std::stack free_spots; + i32 texture_id_counter = 0; + i32 max_texture_units = 0; + }; + + static TextureIdAllocator *texture_id_allocator = nullptr; + Texture2D::Texture2D(Image *image) { assert(image); - glGenTextures(1, &textureId); - glBindTexture(GL_TEXTURE_2D, textureId); + if(!texture_id_allocator) + texture_id_allocator = new TextureIdAllocator(); + + texture_id = texture_id_allocator->get_free_texture_id(); + glGenTextures(1, &texture_ref); + glActiveTexture(GL_TEXTURE0 + texture_id); + glBindTexture(GL_TEXTURE_2D, texture_ref); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image->getWidth(), image->getHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, image->getData()); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -21,6 +60,7 @@ namespace amalgine Texture2D::~Texture2D() { - glDeleteTextures(1, &textureId); + texture_id_allocator->free_texture_id(texture_id); + glDeleteTextures(1, &texture_ref); } } diff --git a/src/RenderBackend/OpenGL/Uniform.cpp b/src/RenderBackend/OpenGL/Uniform.cpp index 67cf3c6..5f68bc6 100644 --- a/src/RenderBackend/OpenGL/Uniform.cpp +++ b/src/RenderBackend/OpenGL/Uniform.cpp @@ -4,6 +4,11 @@ namespace amalgine { Uniform::~Uniform() {} + void Uniform::set(float value) { + use(); + glUniform1f(uniform_id, value); + } + void Uniform::set(const vec3f &value) { use(); glUniform3f(uniform_id, value.x, value.y, value.z); @@ -14,6 +19,11 @@ namespace amalgine { glUniformMatrix4fv(uniform_id, 1, GL_FALSE, glm::value_ptr(value)); } + void Uniform::set(const Texture2D &texture) { + use(); + glUniform1i(uniform_id, texture.get_texture_id()); + } + Uniform::Uniform(i32 uniform_id, u32 shader_program_id) : uniform_id(uniform_id), program_id(shader_program_id) { } diff --git a/src/main.cpp b/src/main.cpp index 6f825b1..5845332 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,6 +3,8 @@ #include "../include/RenderBackend/OpenGL/ShaderProgram.hpp" #include "../include/RenderBackend/OpenGL/DeviceMemory.hpp" #include "../include/RenderBackend/OpenGL/DeviceFrame.hpp" +#include "../include/RenderBackend/OpenGL/Texture2D.hpp" +#include "../include/Image.hpp" #include "../include/Triangle.hpp" #include "../include/model_loader/ObjModelLoader.hpp" @@ -27,6 +29,29 @@ struct Userdata { float cam_dist; }; +static std::vector generate_sand() { + const int rows = 50; + const int columns = 50; + std::vector vertices(rows * columns * 2); + int i = 0; + float div = 0.3f; + for(int y = 0; y < rows; ++y) { + for(int x = 0; x < columns; ++x) { + vertices[i++] = { + Vertex3D{x * div + 0.0f, y * div + 0.0f, 0.0f}, + Vertex3D{x * div + 1.0f * div, y * div + 0.0f, 0.0f}, + Vertex3D{x * div + 0.0f, y * div + 1.0f * div, 0.0f} + }; + vertices[i++] = { + Vertex3D{x * div + 1.0f * div, y * div + 0.0f, 0.0f}, + Vertex3D{x * div + 1.0f * div, y * div + 1.0f * div, 0.0f}, + Vertex3D{x * div + 0.0f, y * div + 1.0f * div, 0.0f} + }; + } + } + return vertices; +} + int main() { initGlfw(); @@ -38,40 +63,50 @@ int main() DeviceFrame frame; - std::array cpuTriangle = { - Triangle3D( - Vertex3D(0.0f, 0.0f, 0.0f), - Vertex3D(1.0f, 0.0f, 0.0f), - Vertex3D(0.0f, 1.0f, 0.0f) - ), - Triangle3D( - Vertex3D(1.0f, 0.0f, 0.0f), - Vertex3D(1.0f, 1.0f, 0.0f), - Vertex3D(0.0f, 1.0f, 0.0f) - ), - }; - //DataView cpuTriangles(cpuTriangle.data(), cpuTriangle.size()); + std::vector cpu_sand = generate_sand(); + DeviceMemory *gpuSand = frame.alloc(); + gpuSand->copy({cpu_sand.data(), cpu_sand.size()}, DeviceMemory::StorageType::STATIC); + + std::unique_ptr sand_vertex_shader = load_shader_from_file("shaders/sand_vertex.vert", Shader::Type::VERTEX); + std::unique_ptr sand_pixel_shader = load_shader_from_file("shaders/sand_fragment.frag", Shader::Type::PIXEL); + std::unique_ptr sand_shader_program = build_shader_program_from_shaders({ sand_vertex_shader.get(), sand_pixel_shader.get() }); + 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); + std::vector texture_coords; + Image *image; + ObjModelLoader::load_from_file("/home/dec05eba/Downloads/ELI4OS.obj", triangles, texture_coords, &image); + DeviceMemory *gpuModel = frame.alloc(); + gpuModel->copy({triangles.data(), triangles.size()}, DeviceMemory::StorageType::STATIC); + + Texture2D model_texture(image); + DeviceMemory *model_gpu_texture = frame.alloc(); + model_gpu_texture->copy({texture_coords.data(), texture_coords.size()}, DeviceMemory::StorageType::STATIC); std::unique_ptr vertex_shader = load_shader_from_file("shaders/vertex.vert", Shader::Type::VERTEX); std::unique_ptr pixel_shader = load_shader_from_file("shaders/fragment.frag", Shader::Type::PIXEL); std::unique_ptr shader_program = build_shader_program_from_shaders({ vertex_shader.get(), pixel_shader.get() }); - shader_program->set_vertex_input("position", *gpuTriangle); - - Result proj_uniform = shader_program->get_uniform_by_name("proj"); glm::mat4 proj = glm::perspective(glm::radians(75.0f), (float)window_width / (float)window_height, 0.2f, 1000.0f); - proj_uniform->set(proj); + vec3f triangle_color = { 1.0f, 0.0f, 0.0f }; - Result triangle_color_uniform = shader_program->get_uniform_by_name("triangle_color"); - triangle_color_uniform->set(vec3f{ 1.0f, 0.0f, 0.0f }); + Result sand_proj_uniform = sand_shader_program->get_uniform_by_name("proj"); + Result sand_view_uniform = sand_shader_program->get_uniform_by_name("view"); + Result sand_model_uniform = sand_shader_program->get_uniform_by_name("model"); + Result sand_time = sand_shader_program->get_uniform_by_name("time"); + Result sand_triangle_color_uniform = sand_shader_program->get_uniform_by_name("triangle_color"); + Result proj_uniform = shader_program->get_uniform_by_name("proj"); Result view_uniform = shader_program->get_uniform_by_name("view"); Result model_uniform = shader_program->get_uniform_by_name("model"); + Result tex_uniform = shader_program->get_uniform_by_name("tex"); + + sand_proj_uniform->set(proj); + sand_triangle_color_uniform->set(triangle_color); + + proj_uniform->set(proj); + + shader_program->set_input_data("texcoord_vert", *model_gpu_texture); + tex_uniform->set(model_texture); Userdata userdata; userdata.cam_dist = 3.0f; @@ -85,7 +120,8 @@ int main() userdata->cam_dist += yoffset; }); - //glEnable(GL_CULL_FACE); + glEnable(GL_CULL_FACE); + float time = 0.0f; while(!glfwWindowShouldClose(window)) { glfwPollEvents(); if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) @@ -94,6 +130,7 @@ int main() auto t_now = std::chrono::high_resolution_clock::now(); float time_delta = std::chrono::duration_cast>(t_now - t_start).count(); t_start = t_now; + time += time_delta; float move_speed = time_delta * 3.0f; if(glfwGetKey(window, GLFW_KEY_W)) @@ -112,6 +149,7 @@ int main() character_pos - glm::vec3(0.0f, 3.0f, 3.0f), glm::vec3(0.0f, 0.0f, 1.0f) ); + sand_view_uniform->set(view); view_uniform->set(view); glm::mat4 model = glm::mat4(1.0f); @@ -120,18 +158,32 @@ int main() 0.0f, glm::vec3(0.0f, 0.0f, 1.0f) ); + sand_model_uniform->set(model); model_uniform->set(model); + //printf("now: %f\n", time); + sand_time->set(time); + // Set color for clearing 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); + //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + shader_program->set_input_data("position", *gpuModel); frame.draw(shader_program.get()); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + sand_shader_program->set_input_data("position", *gpuSand); + frame.draw(sand_shader_program.get()); + + //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glfwSwapBuffers(window); } + delete model_gpu_texture; + delete image; + delete gpuModel; + delete gpuSand; glfwTerminate(); return 0; } @@ -166,13 +218,8 @@ 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); + GLFWwindow *window = glfwCreateWindow(1920, 1080, "Amalgine", nullptr, nullptr); if(!window) { fprintf(stderr, "Failed to open GLFW window\n"); diff --git a/src/model_loader/ObjModelLoader.cpp b/src/model_loader/ObjModelLoader.cpp index 1bae458..51d8a74 100644 --- a/src/model_loader/ObjModelLoader.cpp +++ b/src/model_loader/ObjModelLoader.cpp @@ -1,25 +1,20 @@ #include "../../include/model_loader/ObjModelLoader.hpp" #include "../../include/File.hpp" #include "../../include/DataView.hpp" +#include "../../include/Image.hpp" #include #include #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) { @@ -44,13 +39,13 @@ namespace amalgine { } // Return the number of columns, limited by @output_size - static int split_columns(const StringView &str, StringView *output, int output_size) { + static int split_columns(const StringView &str, char split_char, 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); + char *found_ptr = (char*)memchr(data, split_char, size); if(!found_ptr) found_ptr = data + size; @@ -75,17 +70,32 @@ namespace amalgine { return static_cast(found_ptr - str.data); } - void ObjModelLoader::load_from_file(const char *filepath, std::vector &triangles) { + struct Material { + Image *image; + }; + + static Result load_material_from_file(const char *filepath); + + void ObjModelLoader::load_from_file(const char *filepath, std::vector &triangles, std::vector &texture_coords, Image **image) { + triangles.clear(); + texture_coords.clear(); + *image = nullptr; + size_t file_size; char *file_data = file_get_content(filepath, &file_size); - triangles.clear(); if(!file_data) return; - const int max_columns = 12; + std::string dir_path = filepath; + dirname(&dir_path[0]); + const int dir_path_size = strlen(dir_path.c_str()); + dir_path.resize(dir_path_size); + + const int max_columns = 8; StringView columns[max_columns]; std::vector vertices; + std::vector temp_texture_coords; char *data = file_data; ssize_t size = file_size; @@ -94,9 +104,9 @@ namespace amalgine { 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 }; + StringView column_data = { line_data.data + 2, line_data.size - 2 }; - int num_columns = split_columns(column_data, columns, max_columns); + 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'; @@ -105,33 +115,140 @@ namespace amalgine { } } 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 }; + StringView column_data = { line_data.data + 2, line_data.size - 2 }; - int num_columns = split_columns(column_data, columns, max_columns); + int num_columns = split_columns(column_data, ' ', columns, max_columns); if(num_columns == 3 || num_columns == 4) { bool valid = true; - int indices[4]; + int vertex_indices[4]; + int texture_coord_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()) { + const int max_attributes = 3; + StringView attributes[max_attributes]; + int num_attributes = split_columns(columns[i], '/', attributes, max_attributes); + assert(num_attributes == 3); + + attributes[0].data[attributes[0].size] = '\0'; + attributes[1].data[attributes[1].size] = '\0'; + attributes[2].data[attributes[2].size] = '\0'; + + vertex_indices[i] = atoi(attributes[0].data); + texture_coord_indices[i] = atoi(attributes[1].data); + + if(vertex_indices[i] < 1 || vertex_indices[i] > vertices.size()) { valid = false; + abort(); break; } - --indices[i]; + + if(texture_coord_indices[i] < 1 || texture_coord_indices[i] > temp_texture_coords.size()) { + valid = false; + abort(); + break; + } + + --vertex_indices[i]; + --texture_coord_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]] }); + if(num_columns == 3) { // Triangle + triangles.push_back({ vertices[vertex_indices[0]], vertices[vertex_indices[1]], vertices[vertex_indices[2]] }); + + texture_coords.push_back(temp_texture_coords[texture_coord_indices[0]]); + texture_coords.push_back(temp_texture_coords[texture_coord_indices[1]]); + texture_coords.push_back(temp_texture_coords[texture_coord_indices[2]]); + } else if(num_columns == 4) { // Quad, convert to triangle. TODO: Support rendering quads instead of converting to triangles + triangles.push_back({ vertices[vertex_indices[0]], vertices[vertex_indices[1]], vertices[vertex_indices[3]] }); + triangles.push_back({ vertices[vertex_indices[3]], vertices[vertex_indices[2]], vertices[vertex_indices[1]] }); + + texture_coords.push_back(temp_texture_coords[texture_coord_indices[0]]); + texture_coords.push_back(temp_texture_coords[texture_coord_indices[1]]); + texture_coords.push_back(temp_texture_coords[texture_coord_indices[3]]); + + texture_coords.push_back(temp_texture_coords[texture_coord_indices[3]]); + texture_coords.push_back(temp_texture_coords[texture_coord_indices[2]]); + texture_coords.push_back(temp_texture_coords[texture_coord_indices[1]]); } } } + } else if(line_data.size > 3 && memcmp(line_data.data, "vt ", 3) == 0) { + StringView column_data = { line_data.data + 3, line_data.size - 3 }; + int num_columns = split_columns(column_data, ' ', columns, max_columns); + if(num_columns == 2) { + columns[0].data[columns[0].size] = '\0'; + columns[1].data[columns[1].size] = '\0'; + temp_texture_coords.push_back({ atof(columns[0].data), atof(columns[1].data) }); + } + } else if(line_data.size > 7 && memcmp(line_data.data, "mtllib ", 7) == 0) { + StringView column_data = { line_data.data + 7, line_data.size - 7 }; + int num_columns = split_columns(column_data, ' ', columns, max_columns); + if(num_columns == 1) { + std::string material_path; + material_path.resize(dir_path_size + 1 + columns[0].size); + memcpy(&material_path[0], dir_path.data(), dir_path_size); + material_path[dir_path_size] = '/'; + memcpy(&material_path[dir_path_size + 1], columns[0].data, columns[0].size); + printf("mtl file: %.*s\n", material_path.size(), material_path.data()); + + assert(!*image); + Result material = load_material_from_file(material_path.c_str()); + if(!material) { + fprintf(stderr, "Error: %s\n", material.getErrorMsg().c_str()); + abort(); + goto cleanup; + } + + *image = material->image; + } + } + + data += (line_data.size + 1); + size -= (line_data.size + 1); + } + + printf("num tex coords: %d\n", texture_coords.size()); + + cleanup: + free(file_data); + } + + Result load_material_from_file(const char *filepath) { + size_t file_size; + char *file_data = file_get_content(filepath, &file_size); + if(!file_data) + return Result::Err("Failed to load material: " + std::string(filepath)); + + std::string dir_path = filepath; + dirname(&dir_path[0]); + const int dir_path_size = strlen(dir_path.c_str()); + dir_path.resize(dir_path_size); + + Image *image = nullptr; + + char *data = file_data; + ssize_t size = file_size; + while(size > 0) { + StringView line_data = get_line(data, size); + + if(line_data.size > 7 && memcmp(line_data.data, "map_Kd ", 7) == 0) { + StringView texture_file = { line_data.data + 7, line_data.size - 7 }; + line_data.data[line_data.size] = '\0'; + + std::string texture_path; + texture_path.resize(dir_path_size + 1 + texture_file.size); + memcpy(&texture_path[0], dir_path.data(), dir_path_size); + texture_path[dir_path_size] = '/'; + memcpy(&texture_path[dir_path_size + 1], texture_file.data, texture_file.size); + printf("texture file: |%.*s|\n", texture_path.size(), texture_path.data()); + + Result image_result = Image::loadFromFile(texture_path.c_str()); + if(!image_result) + return Result::Err("Failed to load texture: " + texture_path); + + image = image_result.unwrap(); + break; } data += (line_data.size + 1); @@ -139,5 +256,6 @@ namespace amalgine { } free(file_data); + return Result::Ok({ image }); } } \ No newline at end of file -- cgit v1.2.3