buffer allocation
[demo] / src / opengl / mesh-gl.cc
1 #include <GL/glew.h>
2 #include <GL/gl.h>
3 #include <gmath/gmath.h>
4
5 #include "mesh-gl.h"
6
7 MeshGL::MeshGL()
8 {
9         vao = 0;
10
11         vbo_vertices = 0;
12         vbo_normals = 0;
13         vbo_tex_coords = 0;
14         ibo = 0;
15
16         num_vertices = 0;
17         num_indices = 0;
18
19         /* draw normals */
20         nvao = nvbo = 0;
21 }
22
23 MeshGL::MeshGL(const MeshGL &mesh)
24 {
25         indices = mesh.indices;
26         vertices = mesh.vertices;
27         normals = mesh.normals;
28         tex_coords = mesh.tex_coords;
29
30         vbo_vertices = 0;
31         vbo_normals = 0;
32         vbo_tex_coords = 0;
33         ibo = 0;
34         vao = 0;
35
36         /* draw normals */
37         nvao = nvbo = 0;
38
39         /*
40          * if we set these to the actual
41          * vertices.size() and indices.size()
42          * update_vbo will have no effect
43          * */
44
45         num_vertices = 0;
46         num_indices = 0;
47 }
48
49 MeshGL &MeshGL::operator=(const MeshGL &mesh)
50 {
51         if(this == &mesh)
52                 return *this;
53
54         /* to avoid OpenGL leaks */
55         destroy_vbo();
56
57         /* what the copy constructor does */
58         indices = mesh.indices;
59         vertices = mesh.vertices;
60         normals = mesh.normals;
61         tex_coords = mesh.tex_coords;
62
63         return *this;
64 }
65
66 MeshGL::~MeshGL()
67 {
68         destroy_vbo();
69
70         vertices.clear();
71         normals.clear();
72         tex_coords.clear();
73         indices.clear();
74 }
75
76 void MeshGL::draw() const
77 {
78         if(!vdata_valid) {
79                 ((MeshGL *)this)->update_vertex_data();
80         }
81         glBindVertexArray(vao);
82
83         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
84         glDrawElements(GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, 0);
85
86         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
87         glBindVertexArray(0);
88 }
89
90 void MeshGL::draw_normals(float scale) const
91 {
92         if(!nvao) {
93                 glGenVertexArrays(1, &nvao);
94                 glBindVertexArray(nvao);
95
96                 glGenBuffers(1, &nvbo);
97                 glBindBuffer(GL_ARRAY_BUFFER, nvbo);
98
99                 glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(Vec3) * 2, 0, GL_STATIC_DRAW);
100                 Vec3 *data = (Vec3 *)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
101
102                 for(size_t i = 0; i < normals.size(); i++) {
103                         *data++ = vertices[i];
104                         *data++ = vertices[i] + normals[i] * scale;
105                 }
106                 glUnmapBuffer(GL_ARRAY_BUFFER);
107
108                 glVertexAttribPointer(MESH_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof(Vec3), 0);
109                 glEnableVertexAttribArray(MESH_VERTEX);
110                 glBindBuffer(GL_ARRAY_BUFFER, 0);
111         }
112         else {
113                 glBindVertexArray(nvao);
114         }
115
116         glDrawArrays(GL_LINES, 0, normals.size() * 2);
117         glBindVertexArray(0);
118 }
119
120 bool MeshGL::update_vertex_data()
121 {
122         update_vbo();
123         return true;
124 }
125
126 void MeshGL::update_vbo()
127 {
128         if(vertices.empty()) {
129                 printf("empty vertices\n");
130                 return;
131         }
132
133         /* vao */
134         if(!vao)
135                 glGenVertexArrays(1, &vao);
136         glBindVertexArray(vao);
137
138         /* vertices */
139
140         if(!vbo_vertices)
141                 glGenBuffers(1, &vbo_vertices);
142         glBindBuffer(GL_ARRAY_BUFFER, vbo_vertices);
143         if(num_vertices != (int)vertices.size())
144                 glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vec3),
145                              &vertices[0], GL_STATIC_DRAW);
146         else
147                 glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.size() * sizeof(Vec3),
148                                 &vertices[0]);
149         glVertexAttribPointer(MESH_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof(Vec3), 0);
150
151         /* normals */
152
153         if(!vbo_normals)
154                 glGenBuffers(1, &vbo_normals);
155         glBindBuffer(GL_ARRAY_BUFFER, vbo_normals);
156         if(num_vertices != (int)normals.size())
157                 glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(Vec3),
158                              &normals[0], GL_STATIC_DRAW);
159         else
160                 glBufferSubData(GL_ARRAY_BUFFER, 0, normals.size() * sizeof(Vec3),
161                                 &normals[0]);
162         glVertexAttribPointer(MESH_NORMAL, 3, GL_FLOAT, GL_FALSE, sizeof(Vec3), 0);
163
164         /* texture coordinates */
165
166         if(!vbo_tex_coords)
167                 glGenBuffers(1, &vbo_tex_coords);
168         glBindBuffer(GL_ARRAY_BUFFER, vbo_tex_coords);
169         if(num_vertices != (int)tex_coords.size())
170                 glBufferData(GL_ARRAY_BUFFER, tex_coords.size() * sizeof(Vec2), &tex_coords[0], GL_STATIC_DRAW);
171         else
172                 glBufferSubData(GL_ARRAY_BUFFER, 0, tex_coords.size() * sizeof(Vec2), &tex_coords[0]);
173         glVertexAttribPointer(MESH_TEXTURE, 2, GL_FLOAT, GL_FALSE, sizeof(Vec2), 0);
174
175         num_vertices = vertices.size();
176
177         /* indices */
178
179         if(!ibo)
180                 glGenBuffers(1, &ibo);
181         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
182         if(num_indices != (int)indices.size())
183                 glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * 2,
184                              &indices[0], GL_STATIC_DRAW);
185         else
186                 glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, indices.size() * 2,
187                                 &indices[0]);
188
189         num_indices = indices.size();
190
191         glEnableVertexAttribArray(MESH_VERTEX);
192         glEnableVertexAttribArray(MESH_NORMAL);
193         glEnableVertexAttribArray(MESH_TEXTURE);
194
195         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
196         glBindBuffer(GL_ARRAY_BUFFER, 0);
197         glBindVertexArray(0);
198 }
199
200 void MeshGL::destroy_vbo()
201 {
202         if(vbo_vertices)
203                 glDeleteBuffers(1, &vbo_vertices);
204         if(vbo_normals)
205                 glDeleteBuffers(1, &vbo_normals);
206         if(vbo_tex_coords)
207                 glDeleteBuffers(1, &vbo_tex_coords);
208         if(ibo)
209                 glDeleteBuffers(1, &ibo);
210         if(vao)
211                 glDeleteVertexArrays(1, &vao);
212
213         if(nvbo)
214                 glDeleteBuffers(1, &nvbo);
215         if(nvao)
216                 glDeleteVertexArrays(1, &nvao);
217 }