-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathMesh.hpp
120 lines (111 loc) · 4.36 KB
/
Mesh.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#pragma once
class QuadMesh {
public:
// Represents a handle to the mesh sent to the GPU
struct compiled {
int count;
GLuint vao;
GLuint vbo;
GLuint ibo;
void draw(int ofs, int count) const {
if (ofs+count > this->count)
count = this->count-ofs;
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, (void *)ofs);
}
void draw() const { draw(0, count); }
};
compiled compile(compiled &&prev = {0,0,0,0}) {
compiled next = prev;
if (!next.vao) {
glGenBuffers(1, &next.vbo);
glGenBuffers(1, &next.ibo);
glGenVertexArrays(1, &next.vao);
glBindVertexArray(next.vao);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
glEnableVertexAttribArray(4);
glBindBuffer(GL_ARRAY_BUFFER, next.vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
sizeof(vertex), (void *)offsetof(vertex, loc));
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE,
sizeof(vertex), (void *)offsetof(vertex, uv));
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE,
sizeof(vertex), (void *)offsetof(vertex, id));
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE,
sizeof(vertex), (void *)offsetof(vertex, norm));
glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE,
sizeof(vertex), (void *)offsetof(vertex, area));
}
next.count = m_indices.size();
glBindVertexArray(next.vao);
glBindBuffer(GL_ARRAY_BUFFER, next.vbo);
glBufferData(GL_ARRAY_BUFFER,
m_verts.size()*sizeof(vertex),
m_verts.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, next.ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
m_indices.size()*sizeof(unsigned),
m_indices.data(), GL_STATIC_DRAW);
return next;
}
struct vertex {
glm::vec3 loc;
glm::vec2 uv;
float id;
glm::vec3 norm;
float area;
};
const vertex &vert(unsigned i) const { return m_verts.at(i); }
unsigned add_vert(vertex &&v)
{ m_verts.push_back(std::move(v)); return m_verts.size()-1; }
unsigned add_face(unsigned a, unsigned b, unsigned c, unsigned d)
// Convert to triangles implicitly, since OpenGL got rid of quads :(
{ m_indices.insert(m_indices.end(), {a,b,d, b,c,d}/*/{a,b,c, a,c,d}*/); return m_indices.size()-6; }
private:
std::vector<vertex> m_verts;
std::vector<unsigned> m_indices;
};
bool load_obj(QuadMesh &mesh, const char *fname)
{
std::ifstream is{fname};
if (!is)
return false;
std::string linebuf;
std::vector<glm::vec3> verts;
float id = 0;
while (std::getline(is, linebuf)) {
std::stringstream ls{linebuf};
std::string cmd;
if (!(ls >> cmd))
continue; // Ignore empty lines
if (cmd == "vt")
continue; // Ignore texture coordinates
else if (cmd == "vn")
continue; // Ignore normal coordinates
else if (cmd == "v") {
float x, y, z;
ls >> x >> y >> z;
verts.push_back({x, y, z});
}
else if (cmd == "f") {
int a, b, c, d;
ls >> a >> b >> c >> d;
glm::vec3 norm = glm::cross(verts[b-1]-verts[a-1], verts[d-1]-verts[a-1]);
float area = glm::length(norm); norm /= area;
auto a2 = mesh.add_vert({verts[a-1], glm::vec2{0.0f, 0.0f}, id, norm, area});
auto b2 = mesh.add_vert({verts[b-1], glm::vec2{1.0f, 0.0f}, id, norm, area});
auto c2 = mesh.add_vert({verts[c-1], glm::vec2{1.0f, 1.0f}, id, norm, area});
auto d2 = mesh.add_vert({verts[d-1], glm::vec2{0.0f, 1.0f}, id, norm, area});
mesh.add_face(a2, b2, c2, d2);
id++;
}
else
continue; // Silently ignore unrecognized commands
}
return true;
}