cleanup build. add demo project. add timing features to sync. switch to more std::string and std::vector usage over custom, hacky Array template

This commit is contained in:
2025-09-01 21:56:43 -05:00
parent b4e90dce4d
commit 75e72ba9ca
25 changed files with 663 additions and 1759 deletions

View File

@@ -1,9 +1,15 @@
#include <cassert>
#include <glad/glad.h>
#include <map>
#include <string>
#include <optional>
#include "util.hpp"
#include "body.hpp"
#include "shaders.hpp"
using namespace std;
enum class ParserState {
PREFIX,
VERTEX,
@@ -11,72 +17,29 @@ enum class ParserState {
FACE_SKIP,
};
static map<string, pair<vector<float>, vector<int>>> cache;
optional<pair<vector<float>, vector<int>>> _parse_obj(const char* obj_filepath);
bool load_body(Body* out_body, const char* obj_filepath) {
Array<char> source;
if (!read_file(&source, obj_filepath)) {
vector<float> verts;
vector<int> faces;
if (auto it = cache.find(obj_filepath); it != cache.end()) {
verts = it->second.first;
faces = it->second.second;
} else if (auto pair = _parse_obj(obj_filepath); pair.has_value()) {
verts = pair.value().first;
faces = pair.value().second;
cache[obj_filepath] = pair.value();
} else {
return false;
}
size_t num_verts = 0;
size_t num_faces = 0;
for (int i = 1; i < source.len; i++) {
if (source[i] == ' ' && source[i - 1] == 'v') {
num_verts++;
} else if (source[i] == ' ' && source[i - 1] == 'f') {
num_faces++;
}
}
Array<float> verts = { (float*)malloc(sizeof(float) * num_verts * 3), num_verts * 3 };
Array<int> faces = { (int*)malloc(sizeof(int) * num_faces * 3), num_faces*3 };
// Get ready for the parsing loop
ParserState state = ParserState::PREFIX;
int vert_i = 0;
int face_i = 0;
int start = 0;
for (int i = 1; i < source.len; i++) {
switch (state) {
case ParserState::PREFIX:
if (source[i - 1] == 'v' && source[i] == ' ') {
state = ParserState::VERTEX;
start = i + 1;
} else if (i > 0 && source[i - 1] == 'f' && source[i] == ' ') {
state = ParserState::FACE;
start = i + 1;
}
break;
case ParserState::VERTEX:
if (iswspace(source[i])) {
verts[vert_i] = atof(&source[start]);
vert_i++;
start = i + 1;
}
break;
case ParserState::FACE:
if (source[i] == '/') {
state = ParserState::FACE_SKIP;
faces[face_i] = atoi(&source[start]) - 1;
face_i++;
}
break;
case ParserState::FACE_SKIP:
if (iswspace(source[i])) {
state = ParserState::FACE;
start = i + 1;
}
}
if (source[i] == '\n' || source[i] == '\r') {
state = ParserState::PREFIX;
continue;
}
}
// Need a good validation check here. This is a stand in.
if (verts.len == 0 || faces.len == 0) {
if (verts.size() == 0 || faces.size() == 0) {
printf(
"Obj file appears incomplete or corrupted. Num verts %zu. Num Faces %zu.\n", verts.len, faces.len);
"Obj file appears incomplete or corrupted. Num verts %zu. Num Faces %zu.\n", verts.size(), faces.size());
return false;
}
@@ -92,10 +55,10 @@ bool load_body(Body* out_body, const char* obj_filepath) {
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, verts.len * sizeof(float), verts.data, GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, verts.size() * sizeof(float), &verts[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, faces.len * sizeof(int), faces.data, GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, faces.size() * sizeof(int), &faces[0], GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
@@ -116,10 +79,69 @@ void draw_body(const Body& b) {
set_uniform(b.shader, "global_t", glm::scale(b.pose, glm::vec3(b.scale)));
set_uniform(b.shader, "color", b.color);
glBindVertexArray(b.vao);
glDrawElements(GL_TRIANGLES, b.faces.len, GL_UNSIGNED_INT, 0);
glDrawElements(GL_TRIANGLES, b.faces.size(), GL_UNSIGNED_INT, 0);
}
void create_new_sphere(Body* b, float scale) {
assert(load_body(b, "Icosphere.obj"));
b->scale = scale;
}
optional<pair<vector<float>, vector<int>>> _parse_obj(const char* obj_filepath) {
string source;
if (!read_file(&source, obj_filepath)) {
return {};
}
size_t num_verts = 0;
size_t num_faces = 0;
for (int i = 1; i < source.size(); i++) {
if (source[i] == ' ' && source[i - 1] == 'v') {
num_verts++;
} else if (source[i] == ' ' && source[i - 1] == 'f') {
num_faces++;
}
}
vector<float> verts;
vector<int> faces;
// Get ready for the parsing loop
ParserState state = ParserState::PREFIX;
int start = 0;
for (int i = 1; i < source.size(); i++) {
switch (state) {
case ParserState::PREFIX:
if (source[i - 1] == 'v' && source[i] == ' ') {
state = ParserState::VERTEX;
start = i + 1;
} else if (i > 0 && source[i - 1] == 'f' && source[i] == ' ') {
state = ParserState::FACE;
start = i + 1;
}
break;
case ParserState::VERTEX:
if (iswspace(source[i])) {
verts.push_back(atof(&source[start]));
start = i + 1;
}
break;
case ParserState::FACE:
if (source[i] == '/') {
state = ParserState::FACE_SKIP;
faces.push_back(atoi(&source[start]) - 1);
}
break;
case ParserState::FACE_SKIP:
if (iswspace(source[i])) {
state = ParserState::FACE;
start = i + 1;
}
}
if (source[i] == '\n' || source[i] == '\r') {
state = ParserState::PREFIX;
continue;
}
}
}