nngn
Loading...
Searching...
No Matches
obj.h
Go to the documentation of this file.
1#ifndef NNGN_RENDER_OBJ_H
2#define NNGN_RENDER_OBJ_H
3
4#include <concepts>
5#include <iomanip>
6#include <istream>
7#include <ranges>
8#include <sstream>
9
10#include "math/vec3.h"
11#include "utils/log.h"
12#include "utils/span.h"
13
14namespace nngn {
15
16namespace detail {
17
18bool obj_invalid(std::size_t i, std::string_view line);
19std::string_view obj_parse_line(const char *p, std::streamsize n);
20bool obj_read_vec(
21 std::size_t line, std::string_view args, const char *name, vec3 *v);
23 std::size_t line, std::string_view args,
24 std::string_view *ps, zvec3 *pv);
25
26}
27
53bool parse_obj(
54 std::istream *f,
55 std::span<char> buffer,
56 std::invocable<vec3> auto &&vertex,
57 std::invocable<vec3> auto &&tex,
58 std::invocable<vec3> auto &&normal,
59 // TODO negative indices?
60 std::invocable<std::array<zvec3, 3>> auto &&face);
61
62inline bool parse_obj(
63 std::istream *f,
64 std::span<char> buffer,
65 std::invocable<vec3> auto &&vertex,
66 std::invocable<vec3> auto &&tex,
67 std::invocable<vec3> auto &&normal,
68 std::invocable<std::array<zvec3, 3>> auto &&face)
69{
71 constexpr auto read_vec = [](
72 std::size_t line, std::string_view args, const char *name, auto &&fn)
73 {
74 vec3 v = {};
75 return detail::obj_read_vec(line, args, name, &v)
76 && (FWD(fn)(v), true);
77 };
78 constexpr auto read_face = [](
79 std::size_t line, std::string_view args, auto &&fn)
80 {
81 constexpr auto read = detail::obj_read_face_indices;
82 constexpr auto dec = [](auto *v) { for(auto &x : *v) --x; };
83 std::string_view s = args;
84 zvec3 f0 = {}, f1 = {}, f2 = {};
85 if(!(
86 read(line, args, &s, &f0)
87 && read(line, args, &s, &f1)
88 && read(line, args, &s, &f2)
89 ))
90 return false;
91 dec(&f0), dec(&f1), dec(&f2);
92 FWD(fn)(std::array{f0, f1, f2});
93 while(!s.empty()) {
94 if(!read(line, args, &s, &f1))
95 return false;
96 dec(&f1);
97 std::swap(f1, f2);
98 FWD(fn)(std::array{f0, f1, f2});
99 }
100 return true;
101 };
102 using namespace std::string_view_literals;
103 constexpr std::array ignored = {
104 "g"sv, "mtl"sv, "mtllib"sv, "o"sv, "s"sv, "usemtl"sv,
105 };
106 static_assert(std::ranges::is_sorted(ignored));
107 const auto max = static_cast<std::streamsize>(buffer.size());
108 for(std::size_t line = 1;; ++line) {
109 if(!f->getline(buffer.data(), max)) {
110 if(f->eof())
111 return true;
112 Log::l() << "line " << line << " too long (max: " << max << ")\n";
113 return false;
114 }
115 const auto s = detail::obj_parse_line(buffer.data(), f->gcount());
116 if(s.empty())
117 continue;
118 const auto [cmd, args] = split(s, std::ranges::find(s, ' '));
119 if(cmd == "v") {
120 if(!read_vec(line, args, "vertex", FWD(vertex)))
121 return false;
122 } else if(cmd == "vt") {
123 if(!read_vec(line, args, "texture coordinates", FWD(tex)))
124 return false;
125 } else if(cmd == "vn") {
126 if(!read_vec(line, args, "vertex normal", FWD(normal)))
127 return false;
128 } else if(cmd == "f") {
129 if(!read_face(line, args, FWD(face)))
130 return false;
131 } else if(!std::ranges::binary_search(ignored, cmd))
132 return detail::obj_invalid(line, s);
133 }
134}
135
136}
137
138#endif
static std::ostream & l()
Definition: log.cpp:56
for i
Definition: font.lua:5
name
Definition: cathedral.lua:11
n
Definition: dump_lights.lua:5
ps
Definition: configure.lua:4
p
Definition: input.lua:29
function f()) end
v[1]
Definition: math.lua:19
std::chrono::seconds s
Definition: timing.cpp:6
#define NNGN_LOG_CONTEXT_F()
Definition: log.h:10
#define FWD(...)
Definition: utils.h:18
bool obj_read_vec(std::size_t line, std::string_view args, const char *name, vec3 *v)
Definition: obj.cpp:29
bool obj_read_face_indices(std::size_t line, std::string_view args, std::string_view *ps, zvec3 *pv)
Definition: obj.cpp:49
std::string_view obj_parse_line(const char *p, std::streamsize n)
Definition: obj.cpp:16
bool obj_invalid(std::size_t i, std::string_view line)
Definition: obj.cpp:9
Definition: audio.cpp:7
vec3_base< std::size_t > zvec3
Definition: vec3.h:50
bool parse_obj(std::istream *f, std::span< char > buffer, std::invocable< vec3 > auto &&vertex, std::invocable< vec3 > auto &&tex, std::invocable< vec3 > auto &&normal, std::invocable< std::array< zvec3, 3 > > auto &&face)
Processes an OBJ file using the callable arguments.
Definition: obj.h:62
auto split(std::span< T > s, std::size_t i)
Definition: span.h:24
vec3_base< float > vec3
Definition: vec3.h:51