125 lines
3.4 KiB
C++
125 lines
3.4 KiB
C++
#include <cassert>
|
|
#include <glad/glad.h>
|
|
#include "util.hpp"
|
|
#include "body.hpp"
|
|
#include "shaders.hpp"
|
|
|
|
enum class ParserState {
|
|
PREFIX,
|
|
VERTEX,
|
|
FACE,
|
|
FACE_SKIP,
|
|
};
|
|
|
|
bool load_body(Body* out_body, const char* obj_filepath) {
|
|
Array<char> source;
|
|
if (!read_file(&source, obj_filepath)) {
|
|
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) {
|
|
printf(
|
|
"Obj file appears incomplete or corrupted. Num verts %zu. Num Faces %zu.\n", verts.len, faces.len);
|
|
return false;
|
|
}
|
|
|
|
uint vao, vbo, ebo;
|
|
vao = 0;
|
|
vbo = 0;
|
|
ebo = 0;
|
|
|
|
glGenVertexArrays(1, &vao);
|
|
glGenBuffers(1, &vbo);
|
|
glGenBuffers(1, &ebo);
|
|
|
|
glBindVertexArray(vao);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
|
glBufferData(GL_ARRAY_BUFFER, verts.len * sizeof(float), verts.data, GL_STATIC_DRAW);
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
|
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, faces.len * sizeof(int), faces.data, GL_STATIC_DRAW);
|
|
|
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
|
|
glEnableVertexAttribArray(0);
|
|
|
|
*out_body = { .pose = glm::mat4(1),
|
|
.scale = 1.0f,
|
|
.ebo = ebo,
|
|
.vao = vao,
|
|
.vbo = vbo,
|
|
.shader = 0,
|
|
.verts = verts,
|
|
.faces = faces,
|
|
.color = glm::vec4(0.5, 0.5, 0.5, 1)
|
|
};
|
|
|
|
return true;
|
|
}
|
|
|
|
void draw_body(const Body& b) {
|
|
use_shader(b.shader);
|
|
set_uniform(b.shader, "global_t", b.scale*b.pose);
|
|
set_uniform(b.shader, "color", b.color);
|
|
glBindVertexArray(b.vao);
|
|
glDrawElements(GL_TRIANGLES, b.faces.len, GL_UNSIGNED_INT, 0);
|
|
//glDisableVertexAttribArray(0);
|
|
}
|