diff --git a/include/blt/gfx/loader/obj_loader.h b/include/blt/gfx/loader/obj_loader.h index 048ce21..e43614d 100644 --- a/include/blt/gfx/loader/obj_loader.h +++ b/include/blt/gfx/loader/obj_loader.h @@ -46,6 +46,28 @@ namespace blt::gfx std::int32_t vertex, uv, normal; }; + static inline bool operator==(const face_t& f1, const face_t& f2) + { + return f1.vertex == f2.vertex && f1.uv == f2.uv && f1.normal == f2.normal; + } + + struct face_hash + { + size_t operator()(const face_t& face) const + { + std::hash hasher; + return hasher(face.vertex) ^ hasher(face.uv) ^ hasher(face.normal); + } + }; + + struct face_eq + { + bool operator()(const face_t& f1, const face_t& f2) const + { + return f1 == f2; + } + }; + struct constructed_vertex_t { vertex_t vertex; @@ -55,33 +77,33 @@ namespace blt::gfx struct triangle_t { - std::int32_t v1, v2, v3; + std::int32_t v[3]; }; - class obj_loader; - - class obj_object_t + struct object_data + { + std::string object_name; + std::vector indices; + }; + + class obj_objects_t { - friend obj_loader; private: - // TODO: shared VBO? - std::string object_name; - std::vector vertices_; - std::vector indices_; - - obj_object_t(std::string_view name, std::vector vertices, std::vector indices): - object_name(name), vertices_(std::move(vertices)), indices_(std::move(indices)) - {} - + std::vector vertex_data_; + std::vector objects_; public: - inline const std::vector& vertices() + obj_objects_t(std::vector&& vertex_data, std::vector&& objects): + vertex_data_(vertex_data), objects_(objects) + {} + + inline const std::vector& vertex_data() { - return vertices_; + return vertex_data_; }; - inline const std::vector& indices() + inline const std::vector& objects() { - return indices_; + return objects_; }; }; @@ -94,24 +116,23 @@ namespace blt::gfx std::vector uvs; std::vector normals; - // maps between vertex indices -> face (constructed vertex) - //HASHMAP vertex_data; + // maps between face (constructed vertex) -> vertex indices + HASHMAP vertex_map; std::vector vertex_data; - struct object_data - { - std::string object_name; - std::vector indices; - }; + object_data current_object; std::vector data; private: bool handle_vertex_and_normals(float x, float y, float z, char type); + void parse_extra_line(char_tokenizer& tokenizer); + void parse_face(char_tokenizer& tokenizer); + public: - void parseFile(std::string_view file); + obj_objects_t parseFile(std::string_view file); }; - std::vector quick_load(std::string_view file); + obj_objects_t quick_load(std::string_view file); } diff --git a/src/blt/gfx/loader/obj_loader.cpp b/src/blt/gfx/loader/obj_loader.cpp index 80b8d46..d87003b 100644 --- a/src/blt/gfx/loader/obj_loader.cpp +++ b/src/blt/gfx/loader/obj_loader.cpp @@ -119,15 +119,13 @@ namespace blt::gfx return true; } - std::vector quick_load(std::string_view file) + obj_objects_t quick_load(std::string_view file) { - std::vector objects; - - - return objects; + obj_loader loader; + return loader.parseFile(file); } - void obj_loader::parseFile(std::string_view file) + obj_objects_t obj_loader::parseFile(std::string_view file) { auto lines = blt::fs::getLinesFromFile(std::string(file)); for (const auto& line : lines) @@ -147,10 +145,16 @@ namespace blt::gfx break; case 'o': { + if (!current_object.indices.empty()) + data.push_back(current_object); + current_object = {}; + current_object.object_name = token.read_fully(); break; } } } + data.push_back(current_object); + return {std::move(vertex_data), std::move(data)}; } void obj_loader::parse_face(char_tokenizer& tokenizer) @@ -158,13 +162,31 @@ namespace blt::gfx auto vertexes = blt::string::split(std::string(tokenizer.read_fully()), ' '); if (vertexes.size() == 3) { - for (const auto& v : vertexes) + triangle_t triangle{}; + for (const auto& pair : blt::enumerate(vertexes)) { - auto indices = blt::string::split(v, '/'); + auto indices = blt::string::split(pair.second, '/'); BLT_ASSERT(indices.size() == 3 && "Must have vertex, uv, and normal indices!!"); - vertex_data.push_back( - {vertices[get(indices[0])], uvs[get(indices[1])], normals[get(indices[2])]}); + + auto vi = get(indices[0]); + auto ui = get(indices[1]); + auto ni = get(indices[2]); + + face_t face{vi, ui, ni}; + + auto loc = vertex_map.find(face); + if (loc == vertex_map.end()) + { + auto index = static_cast(vertex_data.size()); + vertex_data.push_back({vertices[vi], uvs[ui], normals[ni]}); + vertex_map.insert({face, index}); + triangle.v[pair.first] = index; + } else + { + triangle.v[pair.first] = loc->second; + } } + current_object.indices.push_back(triangle); } else if (vertexes.size() == 4) { BLT_WARN("Currently unable to process non-triangulated meshes!");