226 lines
6.9 KiB
C++
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;
|
|
} |