RtB/src/Mesh.cpp

226 lines
6.9 KiB
C++

#include "Mesh.hpp"
#include <stdio.h> // fscanf
#include <string.h> // strcmp
#include <stdlib.h> // atof
Mesh::Mesh() {
vbo = vao = tex = 0;
flags = 0;
mode = GL_STATIC_DRAW;
}
Mesh::Mesh(Vec3 *in_vertices, int v_count, Vec2 *in_uvs, int uv_count, Vec3 *in_normals, int n_count) {
loadArrays(in_vertices, v_count, in_uvs, uv_count, in_normals, n_count);
}
Mesh::~Mesh() {
if (flags & MESH_BUILT) destroyMesh();
}
int Mesh::loadObj(const char *filename) {
std::vector <Vec3> temp_vertices;
std::vector <Vec2> temp_uvs;
std::vector <Vec3> temp_normals;
std::vector <unsigned int> vertex_indices;
std::vector <unsigned int> uv_indices;
std::vector <unsigned int> normal_indices;
int ret;
#ifdef _WIN32
FILE *file;
fopen_s(&file, filename, "r");
#else
FILE *file = fopen(filename, "r");
#endif
if (file == NULL) {
// TODO: error report
return 1;
}
char word[32];
#ifdef _WIN32
while ((ret = fscanf_s(file, "%s ", word)) != EOF) {
#else
while ((ret = fscanf(file, "%s ", word)) != EOF) {
#endif
if (strcmp(word, "v") == 0) { // vertices
// "x y z w" as floats, with "w" being optional
Vec3 vec; // our vertex
char word[32];
char ch;
int pos = 0, w_i = 0;
while ((ch = fgetc(file)) != EOF) {
if (ch == ' ' || ch == '\n') {
if (pos == 0) { // x
word[w_i] = '\0';
vec.x = (float)atof(word);
} else if (pos == 1) { // y
word[w_i] = '\0';
vec.y = (float)atof(word);
} else if (pos == 2) { // z
word[w_i] = '\0';
vec.z = (float)atof(word);
/*} else if (pos == 3) { // w
word[w_i] = '\0';
vec.w = atof(word);*/
}
pos++;
w_i = 0;
}
if (ch == '\n') break;
word[w_i++] = ch;
}
temp_vertices.push_back(vec);
} else if (strcmp(word, "vt") == 0) { // texture coordinates
// "u v [w]" as floats, with "w" being optional
Vec2 vec; // our texture coord
char word[32];
char ch;
int pos = 0, w_i = 0;
while ((ch = fgetc(file)) != EOF) {
if (ch == ' ' || ch == '\n') {
if (pos == 0) { // x
word[w_i] = '\0';
vec.x = (float)atof(word);
} else if (pos == 1) { // y
word[w_i] = '\0';
vec.y = (float)atof(word);
/*} else if (pos == 3) { // w
word[w_i] = '\0';
vec.w = atof(word);*/
}
pos++;
w_i = 0;
}
if (ch == '\n') break;
word[w_i++] = ch;
}
temp_uvs.push_back(vec);
} else if (strcmp(word, "vn") == 0) { // normals
// "x y z" as floats
Vec3 vec; // our normal
char word[32];
char ch;
int pos = 0, w_i = 0;
while ((ch = fgetc(file)) != EOF) {
if (ch == ' ' || ch == '\n') {
if (pos == 0) { // x
word[w_i] = '\0';
vec.x = (float)atof(word);
} else if (pos == 1) { // y
word[w_i] = '\0';
vec.y = (float)atof(word);
} else if (pos == 2) { // z
word[w_i] = '\0';
vec.z = (float)atof(word);
/*} else if (pos == 3) { // w
word[w_i] = '\0';
vec.w = atof(word);*/
}
pos++;
w_i = 0;
}
if (ch == '\n') break;
word[w_i++] = ch;
}
temp_normals.push_back(vec);
/*} else if (strcmp(word, "vp") == 0) { // parameter space vertices
// "u v w", with 'v' and 'w' being optional*/
} else if (strcmp(word, "f") == 0) { // face definitions
// "v1 v2 v3" for plain vertex indices
// "v1/vt1 v2/vt2 v3/vt3" for vertex/texture-coordinate indices
// "v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3" for vertex/texture-coordinate/normal indices
// "v1//vn1 v2//vn2 v3//vn3" for vertex/normal indices
char word[32];
char ch;
int w_i = 0, mode = 0;
// read in our faces into our index vectors
while ((ch = fgetc(file)) != EOF) {
if (ch == ' ' || ch == '\n') {
word[w_i] = '\0';
if (mode == 0) { // was in vertex, now in texture-coords
vertex_indices.push_back(atoi(word));
} else if (mode == 1) { // was in texture-coords, now in normal
uv_indices.push_back(atoi(word));
} else if (mode == 2) { // was in normal, write it out
normal_indices.push_back(atoi(word));
}
w_i = 0;
mode = 0; // reset our mode
} else if (ch == '/') {
word[w_i] = '\0';
if (mode == 0) { // was in vertex, now in texture-coords
vertex_indices.push_back(atoi(word));
} else if (mode == 1) { // was in texture-coords, now in normal
if (w_i > 0) uv_indices.push_back(atoi(word));
}
mode++;
w_i = 0;
} else {
word[w_i++] = ch;
}
if (ch == '\n') break;
}
//} else if (strcmp(word, "#") == 0) { // comment
//} else if (strcmp(word, "o") == 0) { // object name
//} else if (strcmp(word, "g") == 0) { // group name
//} else if (Strmcpmp(word, "s") == 0) { // smooth
// "s 1" or "s off"
} else { // ergo, newline noms
char ch;
while ((ch = fgetc(file)) != EOF) {
if (ch == '\n') break;
}
}
}
fclose(file);
// we're done, let's convert our face-derived indices to our actual mesh
int i;
int indices = vertex_indices.size();
// TODO: vertex index access should be checked for validity (>= 0 < temp_vertices.size())
for (i = 0; i < indices; i++) {
Vec3 vertex = temp_vertices[vertex_indices[i]-1];
vertices.push_back(vertex);
}
indices = uv_indices.size();
for (i = 0; i < indices; i++) {
printf("%d/%d\n", i, indices);
printf("%d\n", uv_indices[i]);
Vec2 uv = temp_uvs[uv_indices[i]-1];
uvs.push_back(uv);
}
indices = normal_indices.size();
for (i = 0; i < indices; i++) {
Vec3 normal = temp_normals[normal_indices[i]-1];
normals.push_back(normal);
}
flags |= MESH_LOADED;
return 0;
}
int Mesh::loadArrays(Vec3 *in_vertices, int v_count, Vec2 *in_uvs, int uv_count, Vec3 *in_normals, int n_count) {
if (v_count > 0) {
vertices.assign(in_vertices, in_vertices + v_count);
flags |= MESH_LOADED;
}
if (uv_count > 0) {
uvs.assign(in_uvs, in_uvs + uv_count);
}
if (n_count > 0) {
normals.assign(in_normals, in_normals + n_count);
}
return 0;
}
int Mesh::buildMesh() {
if (!(flags & MESH_LOADED)) return 1;
if (flags & MESH_BUILT) destroyMesh();
// generate our vertex buffer object from our given points
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(Vec3), &vertices[0], mode);
flags |= MESH_BUILT;
return 0;
}
int Mesh::destroyMesh() {
glDeleteBuffers(1, &vbo);
//glDeleteVertexArrays(1, &vao);
flags &= ~MESH_BUILT;
return 0;
}