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

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;

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();

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
src/coders/obj.cpp Normal file
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
src/coders/obj.hpp Normal file
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_

View File

@ -3,6 +3,7 @@
#include "../typedefs.hpp"
#include <cmath>
#include <string>
#include <vector>
#include <memory>
@ -47,6 +48,15 @@ namespace dynamic {
std::holds_alternative<integer_t>(value);
}
inline number_t as_number(const Value& value) {
if (auto num = std::get_if<number_t>(&value)) {
return *num;
} else if (auto num = std::get_if<integer_t>(&value)) {
return *num;
}
return NAN;
}
class List {
public:
std::vector<Value> values;

View File

@ -1,5 +1,7 @@
#include "Model.hpp"
#include <algorithm>
using namespace model;
inline constexpr glm::vec3 X(1, 0, 0);
@ -26,3 +28,14 @@ void Mesh::addBox(glm::vec3 pos, glm::vec3 size) {
addPlane(pos+X*size, -Z*size, Y*size, X);
addPlane(pos-X*size, Z*size, Y*size, -X);
}
void Model::clean() {
meshes.erase(
std::remove_if(meshes.begin(), meshes.end(),
[](const Mesh& mesh){
return mesh.vertices.empty();
}),
meshes.end()
);
}

View File

@ -23,10 +23,15 @@ namespace model {
struct Model {
std::vector<Mesh> meshes;
/// @brief Add mesh to the model
/// @param texture texture name
/// @return writeable Mesh
Mesh& addMesh(const std::string& texture) {
meshes.push_back({texture, {}});
return meshes[meshes.size()-1];
}
/// @brief Remove all empty meshes
void clean();
};
}

View File

@ -66,13 +66,19 @@ void ModelBatch::draw(const model::Model& model) {
} else {
blank->bind();
}
for (const auto& vert : mesh.vertices) {
auto norm = rotation * vert.normal;
float d = glm::dot(norm, SUN_VECTOR);
d = 0.8f + d * 0.2f;
auto color = lights * d;
vertex(vert.coord, vert.uv, color);
for (size_t i = 0; i < mesh.vertices.size() / 3; i++) {
if (index + VERTEX_SIZE * 3 > capacity) {
flush();
}
for (size_t j = 0; j < 3; j++) {
const auto& vert = mesh.vertices[i * 3 + j];
auto norm = rotation * vert.normal;
float d = glm::dot(norm, SUN_VECTOR);
d = 0.8f + d * 0.2f;
auto color = lights * d;
vertex(vert.coord, vert.uv, color);
}
}
flush();
}

View File

@ -7,10 +7,12 @@
#include "../../assets/Assets.hpp"
#include "../../content/Content.hpp"
#include "../../engine.hpp"
#include "../../coders/obj.hpp"
#include "../../frontend/LevelFrontend.hpp"
#include "../../items/Inventory.hpp"
#include "../../items/ItemDef.hpp"
#include "../../items/ItemStack.hpp"
#include "../../files/files.hpp"
#include "../../logic/PlayerController.hpp"
#include "../../maths/FrustumCulling.hpp"
#include "../../maths/voxmaths.hpp"
@ -70,6 +72,10 @@ WorldRenderer::WorldRenderer(Engine* engine, LevelFrontend* frontend, Player* pl
settings.graphics.skyboxResolution.get(),
assets->getShader("skybox_gen")
);
auto name = "dingus.obj";
auto text = files::read_string(fs::path(name));
model = obj::parse(name, text);
}
WorldRenderer::~WorldRenderer() {
@ -194,23 +200,13 @@ void WorldRenderer::renderLevel(
drawChunks(level->chunks.get(), camera, shader);
model::Model model {};
auto& mesh = model.addMesh("gui/warning");
mesh.addBox({}, glm::vec3(0.3f));
mesh.addBox({}, glm::vec3(0.6f));
auto& mesh2 = model.addMesh("gui/error");
mesh2.addBox({}, glm::vec3(0.7f));
mesh2.addBox({}, glm::vec3(0.9f));
float timer = static_cast<float>(Window::time());
assets->getTexture("gui/menubg")->bind();
shader->uniformMatrix("u_model", glm::mat4(1.0f));
modelBatch->translate({0, 86, 0});
modelBatch->scale(glm::vec3(glm::sin(timer*6)+1));
modelBatch->rotate(glm::vec3(1, 0, 0), timer);
modelBatch->draw(model);
modelBatch->popMatrix();
modelBatch->translate({0, 85, 0});
//modelBatch->scale(glm::vec3(glm::sin(timer*6)+10));
modelBatch->rotate(glm::vec3(0, 1, 0), timer*6);
modelBatch->draw(*model);
//modelBatch->popMatrix();
modelBatch->popMatrix();
modelBatch->popMatrix();

View File

@ -26,6 +26,10 @@ class DrawContext;
class ModelBatch;
struct EngineSettings;
namespace model {
struct Model;
}
class WorldRenderer {
Engine* engine;
Level* level;
@ -36,6 +40,8 @@ class WorldRenderer {
std::unique_ptr<Skybox> skybox;
std::unique_ptr<Batch3D> batch3d;
std::unique_ptr<ModelBatch> modelBatch;
std::unique_ptr<model::Model> model;
bool drawChunk(size_t index, Camera* camera, Shader* shader, bool culling);
void drawChunks(Chunks* chunks, Camera* camera, Shader* shader);