#include "obj_parser.h" #include #include #include #include #include #include #include "math/vector.h" #include "o3d/mesh.h" #include "o3d/vertex_data.h" namespace engine { namespace { std::vector split(const std::string& s, char sep) { std::vector res; std::string::size_type last_ind = 0; for (std::string::size_type ind = 0; ind < s.length(); ind++) { if (s[ind] == sep) { res.push_back(s.substr(last_ind, ind - last_ind)); last_ind = ind + 1; } } res.push_back(s.substr(last_ind)); return res; } float parse_float(const std::string& s) { std::string::size_type ind = 0; bool positive = true; while (ind < s.length() && (s[ind] == '+' || s[ind] == '-')) if (s[ind++] == '-') positive = !positive; // TODO: improve error checking if (ind == s.length()) return 0.f; int n = 0; while (ind < s.length() && s[ind] >= '0' && s[ind] <= '9') n = n * 10 + static_cast(s[ind++]) - static_cast('0'); if (ind == s.length()) return (positive ? 1.f : -1.f) * static_cast(n); // TODO: improve error checking if (s[ind] != '.') return 0.f; ind++; float decimal_part = 0.f; float decimal_fac = .1f; while (ind < s.length() && s[ind] >= '0' && s[ind] <= '9') { decimal_part += decimal_fac * static_cast(static_cast(s[ind++]) - static_cast('0')); decimal_fac *= .1f; } // TODO: improve error checking if (ind != s.length()) return 0.f; return (positive ? 1.f : -1.f) * (static_cast(n) + decimal_part); } float parse_int(const std::string& s) { std::string::size_type ind = 0; bool positive = true; while (ind < s.length() && (s[ind] == '+' || s[ind] == '-')) if (s[ind++] == '-') positive = !positive; // TODO: improve error checking if (ind == s.length()) return 0.f; int n = 0; while (ind < s.length() && s[ind] >= '0' && s[ind] <= '9') n = n * 10 + static_cast(s[ind++]) - static_cast('0'); // TODO: improve error checking if (ind != s.length()) return 0.f; return (positive ? 1.f : -1.f) * n; } } o3d::Mesh parse_object(const std::string& obj_path) { o3d::Mesh mesh; std::ifstream obj_file(obj_path); std::string line; while (std::getline(obj_file, line)) { if (line.length() == 0 || line[0] == '#') continue; if (line.rfind("o ", 0) == 0) { // std::cout << "Object: " << line.substr(2) << std::endl; } else if (line.rfind("v ", 0) == 0) { auto s_coords = split(line.substr(2), ' '); math::Vector4 v{parse_float(s_coords[0]), parse_float(s_coords[1]), parse_float(s_coords[2]), 1.f}; // std::cout << "Vertex x: " << v.x << " y: " << v.y << " z: " << v.z << std::endl; mesh.vertices.push_back(v); } else if (line.rfind("vn ", 0) == 0) { auto s_coords = split(line.substr(3), ' '); math::Vector3 vn{parse_float(s_coords[0]), parse_float(s_coords[1]), parse_float(s_coords[2])}; // std::cout << "Vertex normal x: " << vn.x << " y: " << vn.y << " z: " << vn.z << std::endl; mesh.normals.push_back(vn); } else if (line.rfind("s ", 0) == 0) { // auto smooth = false; // auto s_smooth = line.substr(2); // if (s_smooth == "0" || s_smooth == "off") { // smooth = false; // } else if (s_smooth == "1" || s_smooth == "on") { // smooth = true; // } // std::cout << "Smooth: " << std::boolalpha << smooth << std::endl; } else if (line.rfind("f ", 0) == 0) { std::array, 3> indices; auto line_split = split(line.substr(2), ' '); for (int i = 0; i < 3; i++) { auto indices_s_group = split(line_split[i], '/'); indices[i][0] = parse_int(indices_s_group[0]) - 1; indices[i][1] = parse_int(indices_s_group[2]) - 1; } // std::cout << "Face:" // << " 1: vertex: " << indices[0][0] << " normal: " << indices[0][1] // << " 2: vertex: " << indices[1][0] << " normal: " << indices[1][1] // << " 3: vertex: " << indices[2][0] << " normal: " << indices[2][1] // << std::endl; mesh.indices.push_back(indices); } } return mesh; } }