ctaza/mesh.cpp

148 lines
3.7 KiB
C++

#include "mesh.hpp"
glm::mat4 default_model = glm::rotate(glm::mat4(1.0f), glm::radians(-55.0f), glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 default_projection = glm::perspective(
glm::radians(45.0f),
(float)640 / (float)640,
0.1f,
100.0f);
std::vector<float>
load_obj(const std::string &path)
{
FILE *in = fopen(path.c_str(), "r");
if (in == NULL) {
// TODO: proper error
fprintf(stderr, "couldn't open model: %s\n", path.c_str());
return {};
}
char id[3];
float x, y, z;
int ibuf[9];
auto parse_line = [&]{
char c = fgetc(in);
fseek(in, -1L, SEEK_CUR);
if (c == EOF) {
return EOF;
}
else if (c == 'v') {
fscanf(in, "%s %f %f %f", id, &x, &y, &z);
}
else if (c == 'f') {
fscanf(in, "%s %d/%d/%d %d/%d/%d %d/%d/%d",
id,
&ibuf[0], &ibuf[1], &ibuf[2],
&ibuf[3], &ibuf[4], &ibuf[5],
&ibuf[6], &ibuf[7], &ibuf[8]);
}
else {
while (fgetc(in) != '\n');
return 0;
}
return 1;
};
std::vector<glm::vec3> vbuf;
std::vector<glm::vec2> vtbuf;
std::vector<glm::vec3> vnbuf;
std::vector<int> fbuf;
for (;;) {
int status = parse_line();
if (status == 1) {
if (!strcmp(id, "v")) {
vbuf.push_back(glm::vec3(x, y, z));
}
else if (!strcmp(id, "vt")) {
vtbuf.push_back(glm::vec2(x, y));
}
else if (!strcmp(id, "vn")) {
vnbuf.push_back(glm::vec3(x, y, z));
}
else if (!strcmp(id, "f")) {
for (int i = 0; i < 9; i++)
fbuf.push_back(ibuf[i]-1);
}
}
else if (status == EOF) break;
}
std::vector<float> product;
for (size_t i = 0; i < fbuf.size(); i += 3) {
product.push_back(vbuf[fbuf[i]].x);
product.push_back(vbuf[fbuf[i]].y);
product.push_back(vbuf[fbuf[i]].z);
product.push_back(vtbuf[fbuf[i+1]].x);
product.push_back(vtbuf[fbuf[i+1]].y);
product.push_back(vnbuf[fbuf[i+2]].x);
product.push_back(vnbuf[fbuf[i+2]].y);
product.push_back(vnbuf[fbuf[i+2]].z);
}
fclose(in);
return product;
}
Mesh::Mesh(
const std::vector<GLfloat> &vertices,
Shader *s)
:
vertex_num(vertices.size() / 8)
{
shader = std::shared_ptr<Shader>(s);
/* make the vao, vbo, and ebo */
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
glBindVertexArray(vao);
/* copy vertices into vertex buffer */
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(
GL_ARRAY_BUFFER,
vertices.size() * sizeof(GLfloat),
&vertices[0],
GL_STATIC_DRAW);
/* set vertex attributes */
/* position */
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), 0);
glEnableVertexAttribArray(0);
/* texture coordinate */
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float),
(void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
/* normal */
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float),
(void*)(5 * sizeof(float)));
glEnableVertexAttribArray(2);
shader->set_mat4("model", default_model);
shader->set_mat4("projection", default_projection);
}
Mesh::~Mesh()
{
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(1, &vbo);
}
void
Mesh::draw() const
{
shader->use();
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, vertex_num);
glBindVertexArray(0);
glUseProgram(0);
}