add src/coders/obj

This commit is contained in:
MihailRis
2024-06-22 20:24:35 +03:00
parent a9640fff36
commit e4f9bd03b7
11 changed files with 241 additions and 28 deletions
+35
View File
@@ -163,6 +163,28 @@ void BasicParser::goBack(size_t count) {
}
}
void BasicParser::reset() {
pos = 0;
}
char BasicParser::peekInLine() {
while (hasNext()) {
char next = source[pos];
if (next == '\n') {
return next;
}
if (is_whitespace(next)) {
pos++;
} else {
break;
}
}
if (pos >= source.length()) {
throw error("unexpected end");
}
return source[pos];
}
char BasicParser::peek() {
skipWhitespace();
if (pos >= source.length()) {
@@ -226,6 +248,19 @@ int64_t BasicParser::parseSimpleInt(int base) {
return value;
}
dynamic::Value BasicParser::parseNumber() {
switch (peek()) {
case '-':
skip(1);
return parseNumber(-1);
case '+':
skip(1);
return parseNumber(1);
default:
return parseNumber(1);
}
}
dynamic::Value BasicParser::parseNumber(int sign) {
char c = peek();
int base = 10;
+3
View File
@@ -87,9 +87,11 @@ protected:
bool isNext(const std::string& substring);
void expectNewLine();
void goBack(size_t count=1);
void reset();
int64_t parseSimpleInt(int base);
dynamic::Value parseNumber(int sign);
dynamic::Value parseNumber();
std::string parseString(char chr, bool closeRequired=true);
parsing_error error(const std::string& message);
@@ -99,6 +101,7 @@ public:
std::string parseName();
bool hasNext();
char peek();
char peekInLine();
char peekNoJump();
char nextChar();
+2 -6
View File
@@ -209,9 +209,8 @@ std::unique_ptr<List> Parser::parseList() {
Value Parser::parseValue() {
char next = peek();
if (next == '-' || next == '+') {
pos++;
return parseNumber(next == '-' ? -1 : 1);
if (next == '-' || next == '+' || is_digit(next)) {
return parseNumber();
}
if (is_identifier_start(next)) {
std::string literal = parseName();
@@ -232,9 +231,6 @@ Value Parser::parseValue() {
if (next == '[') {
return List_sptr(parseList().release());
}
if (is_digit(next)) {
return parseNumber(1);
}
if (next == '"' || next == '\'') {
pos++;
return parseString(next);
+124
View File
@@ -0,0 +1,124 @@
#include "obj.hpp"
#include "commons.hpp"
#include "../graphics/core/Model.hpp"
using namespace model;
class ObjParser : BasicParser {
std::vector<glm::vec3> coords {{0, 0, 0}};
std::vector<glm::vec2> uvs {{0, 0}};
std::vector<glm::vec3> normals {{0, 1, 0}};
void parseFace(Mesh& mesh) {
std::vector<Vertex> vertices;
while (hasNext()) {
auto c = peekInLine();
if (c == '\n') {
break;
} else {
uint indices[3] {};
uint i = 0;
do {
char next = peekInLine();
if (is_digit(next)) {
indices[i] = parseSimpleInt(10);
if (peekInLine() == '/') {
pos++;
}
} else if (next == '/') {
pos++;
} else {
break;
}
} while (peekInLine() != '\n' && ++i < 3);
vertices.push_back(Vertex {
coords[indices[0]], uvs[indices[1]], normals[indices[2]]
});
}
}
if (peekInLine() != '\n' && hasNext()) {
skipLine();
}
if (vertices.size() >= 3) {
for (size_t j = 0; j < vertices.size() - 2; j++) {
mesh.vertices.push_back(vertices[0]);
for (size_t i = 1; i < 3; i++) {
mesh.vertices.push_back(vertices[i + j]);
}
}
}
}
public:
ObjParser(const std::string_view file, const std::string_view src) : BasicParser(file, src) {
}
std::unique_ptr<Model> parse() {
// first iteration - collecting vertex data
while (hasNext()) {
if (peek() == '#') {
skipLine();
continue;
}
auto cmd = parseName();
if (cmd == "v") {
float x = dynamic::as_number(parseNumber());
float y = dynamic::as_number(parseNumber());
float z = dynamic::as_number(parseNumber());
coords.emplace_back(x, y, z);
} else if (cmd == "vt") {
float u = dynamic::as_number(parseNumber());
float v = dynamic::as_number(parseNumber());
uvs.emplace_back(u, v);
} else if (cmd == "vn") {
float x = dynamic::as_number(parseNumber());
float y = dynamic::as_number(parseNumber());
float z = dynamic::as_number(parseNumber());
normals.emplace_back(x, y, z);
} else {
skipLine();
}
}
// second iteration - building meshes
reset();
auto model = std::make_unique<Model>();
std::string texture;
while (hasNext()) {
if (peek() != '#' && parseName() == "usemtl") {
skipWhitespace();
texture = readUntil('\n');
break;
}
skipLine();
}
do {
Mesh* mesh = &model->addMesh(texture);
while (hasNext()) {
if (peek() == '#') {
skipLine();
continue;
}
auto cmd = parseName();
if (cmd == "usemtl") {
skipWhitespace();
texture = readUntil('\n');
mesh = &model->addMesh(texture);
break;
} else if (cmd == "f") {
parseFace(*mesh);
}
skipLine();
}
} while(hasNext());
model->clean();
return model;
}
};
std::unique_ptr<Model> obj::parse(
const std::string_view file, const std::string_view src
) {
return ObjParser(file, src).parse();
}
+19
View File
@@ -0,0 +1,19 @@
#ifndef CODERS_OBJ_HPP_
#define CODERS_OBJ_HPP_
#include <string>
#include <memory>
/// Wavefont OBJ files parser
namespace model {
struct Model;
}
namespace obj {
std::unique_ptr<model::Model> parse(
const std::string_view file, const std::string_view src
);
}
#endif // CODERS_OBJ_HPP_