#include #include #include #include #include namespace psemek::gfx { obj_data parse_obj(std::istream & is) { std::vector> positions; std::vector> texcoords; std::vector> normals; obj_data result; std::string line; std::size_t line_count = 0; auto fail = [&](auto const & ... args){ throw std::runtime_error(util::to_string("Error parsing OBJ data, line ", line_count, ": ", args...)); }; while (std::getline(is >> std::ws, line)) { ++line_count; if (line.empty()) continue; if (line[0] == '#') continue; std::istringstream ls(std::move(line)); std::string tag; ls >> tag; if (tag == "v") { auto & p = positions.emplace_back(); ls >> p[0] >> p[1] >> p[2]; } else if (tag == "vt") { auto & t = texcoords.emplace_back(); ls >> t[0] >> t[1]; } else if (tag == "vn") { auto & n = normals.emplace_back(); ls >> n[0] >> n[1] >> n[2]; } else if (tag == "f") { std::vector vertices; while (ls) { std::size_t ip, it, in; ls >> ip; if (ls.eof()) break; if (!ls || ls.get() != '/') fail("expected '/'"); ls >> it; if (!ls || ls.get() != '/') fail("expected '/'"); ls >> in; --ip; --it; --in; if (ip >= positions.size()) fail("bad position index (", ip, ")"); if (it >= texcoords.size()) fail("bad texcoord index (", ip, ")"); if (in >= normals.size()) fail("bad normal index (", ip, ")"); auto & v = vertices.emplace_back(); v.position = positions[ip]; v.texcoord = texcoords[it]; v.normal = normals[in]; } for (std::size_t i = 1; i + 1 < vertices.size(); ++i) { result.triangles.push_back({{vertices[0], vertices[i], vertices[i + 1]}}); } } } return result; } }