Add Wavefront OBJ file parser
This commit is contained in:
parent
6a64c36e01
commit
4a583d092c
2 changed files with 126 additions and 0 deletions
27
libs/gfx/include/psemek/gfx/obj_parser.hpp
Normal file
27
libs/gfx/include/psemek/gfx/obj_parser.hpp
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <psemek/geom/vector.hpp>
|
||||||
|
#include <psemek/geom/point.hpp>
|
||||||
|
#include <psemek/geom/simplex.hpp>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace psemek::gfx
|
||||||
|
{
|
||||||
|
|
||||||
|
struct obj_data
|
||||||
|
{
|
||||||
|
struct vertex
|
||||||
|
{
|
||||||
|
geom::point<float, 3> position;
|
||||||
|
geom::vector<float, 2> texcoord;
|
||||||
|
geom::vector<float, 3> normal;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<geom::triangle<vertex>> triangles;
|
||||||
|
};
|
||||||
|
|
||||||
|
obj_data parse_obj(std::istream & is);
|
||||||
|
|
||||||
|
}
|
||||||
99
libs/gfx/source/obj_parser.cpp
Normal file
99
libs/gfx/source/obj_parser.cpp
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
#include <psemek/gfx/obj_parser.hpp>
|
||||||
|
#include <psemek/util/to_string.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace psemek::gfx
|
||||||
|
{
|
||||||
|
|
||||||
|
obj_data parse_obj(std::istream & is)
|
||||||
|
{
|
||||||
|
std::vector<geom::point<float, 3>> positions;
|
||||||
|
std::vector<geom::vector<float, 2>> texcoords;
|
||||||
|
std::vector<geom::vector<float, 3>> 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<obj_data::vertex> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue