149fbe7a78565ea9bb490a38a54a889a87b1f29b
[vrlugburz] / src / mesh.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stddef.h>
4 #include <string.h>
5 #include <float.h>
6 #define GL_GLEXT_PROTOTYPES 1
7 #include <GL/gl.h>
8 #include <GL/glext.h>
9 #include "mesh.h"
10
11 static int update_mesh_vbo(struct mesh *m);
12 static int update_meshgroup_vbo(struct meshgroup *mg);
13
14 void init_mesh(struct mesh *m)
15 {
16         memset(m, 0, sizeof *m);
17 }
18
19 void destroy_mesh(struct mesh *m)
20 {
21         free(m->varr);
22         free(m->iarr);
23
24         if(m->vbo) {
25                 glDeleteBuffers(1, &m->vbo);
26         }
27         if(m->ibo) {
28                 glDeleteBuffers(1, &m->ibo);
29         }
30 }
31
32 void clear_mesh(struct mesh *m)
33 {
34         free(m->varr);
35         free(m->iarr);
36
37         m->varr = 0;
38         m->iarr = 0;
39         m->num_verts = m->max_verts = m->num_idx = m->max_idx = 0;
40         m->mtl = 0;
41         m->bbvalid = m->vbovalid = 0;
42 }
43
44 void init_meshgroup(struct meshgroup *mg)
45 {
46         memset(mg, 0, sizeof *mg);
47 }
48
49 void destroy_meshgroup(struct meshgroup *mg)
50 {
51         free(mg->meshes);
52
53         if(mg->vbo) {
54                 glDeleteBuffers(1, &mg->vbo);
55         }
56         if(mg->ibo) {
57                 glDeleteBuffers(1, &mg->ibo);
58         }
59 }
60
61 void clear_meshgroup(struct meshgroup *mg)
62 {
63         free(mg->meshes);
64
65         mg->meshes = 0;
66         mg->num_meshes = 0;
67         mg->num_verts = mg->num_idx = 0;
68
69         mg->bbvalid = mg->vbovalid = 0;
70 }
71
72 void calc_mesh_bounds(struct mesh *m)
73 {
74         int i;
75         struct vertex *vptr = m->varr;
76
77         m->bb.vmin.x = m->bb.vmin.y = m->bb.vmin.z = FLT_MAX;
78         m->bb.vmax.x = m->bb.vmax.y = m->bb.vmax.z = -FLT_MAX;
79
80         for(i=0; i<m->num_verts; i++) {
81                 if(vptr->pos.x < m->bb.vmin.x) m->bb.vmin.x = vptr->pos.x;
82                 if(vptr->pos.y < m->bb.vmin.y) m->bb.vmin.y = vptr->pos.y;
83                 if(vptr->pos.z < m->bb.vmin.z) m->bb.vmin.z = vptr->pos.z;
84                 if(vptr->pos.x > m->bb.vmax.x) m->bb.vmax.x = vptr->pos.x;
85                 if(vptr->pos.y > m->bb.vmax.y) m->bb.vmax.y = vptr->pos.y;
86                 if(vptr->pos.z > m->bb.vmax.z) m->bb.vmax.z = vptr->pos.z;
87                 vptr++;
88         }
89
90         m->bbvalid = 1;
91 }
92
93 void calc_meshgroup_bounds(struct meshgroup *mg)
94 {
95         int i;
96         struct mesh *m;
97
98         mg->bb.vmin.x = mg->bb.vmin.y = mg->bb.vmin.z = FLT_MAX;
99         mg->bb.vmax.x = mg->bb.vmax.y = mg->bb.vmax.z = -FLT_MAX;
100
101         for(i=0; i<mg->num_meshes; i++) {
102                 m = mg->meshes[i];
103                 if(!m->bbvalid) {
104                         calc_mesh_bounds(m);
105                 }
106
107                 if(m->bb.vmin.x < mg->bb.vmin.x) mg->bb.vmin.x = m->bb.vmin.x;
108                 if(m->bb.vmin.y < mg->bb.vmin.y) mg->bb.vmin.y = m->bb.vmin.y;
109                 if(m->bb.vmin.z < mg->bb.vmin.z) mg->bb.vmin.z = m->bb.vmin.z;
110                 if(m->bb.vmax.x > mg->bb.vmax.x) mg->bb.vmax.x = m->bb.vmax.x;
111                 if(m->bb.vmax.y > mg->bb.vmax.y) mg->bb.vmax.y = m->bb.vmax.y;
112                 if(m->bb.vmax.z > mg->bb.vmax.z) mg->bb.vmax.z = m->bb.vmax.z;
113         }
114
115         mg->bbvalid = 1;
116 }
117
118 int add_mesh_vertex(struct mesh *m, struct vertex *v)
119 {
120         void *tmp;
121         int newmax;
122
123         if(m->num_verts >= m->max_verts) {
124                 newmax = m->max_verts ? m->max_verts * 2 : 16;
125                 if(!(tmp = realloc(m->varr, newmax * sizeof *m->varr))) {
126                         return -1;
127                 }
128                 m->varr = tmp;
129                 m->max_verts = newmax;
130         }
131
132         m->varr[m->num_verts++] = *v;
133         return 0;
134 }
135
136 int add_mesh_index(struct mesh *m, int idx)
137 {
138         void *tmp;
139         int newmax;
140
141         if(m->num_idx >= m->max_idx) {
142                 newmax = m->max_idx ? m->max_idx * 2 : 16;
143                 if(!(tmp = realloc(m->iarr, newmax * sizeof *m->iarr))) {
144                         return -1;
145                 }
146                 m->iarr = tmp;
147                 m->max_idx = newmax;
148         }
149
150         m->iarr[m->num_idx++] = idx;
151         return 0;
152 }
153
154 int add_mesh_face(struct mesh *m, int va, int vb, int vc)
155 {
156         if(add_mesh_index(m, va) == -1) return -1;
157         if(add_mesh_index(m, vb) == -1) {
158                 m->num_idx--;
159                 return -1;
160         }
161         if(add_mesh_index(m, vc) == -1) {
162                 m->num_idx -= 2;
163                 return -1;
164         }
165         return 0;
166 }
167
168 int add_meshgroup_mesh(struct meshgroup *mg, struct mesh *m)
169 {
170         void *tmp;
171         int newmax;
172
173         if(mg->num_meshes >= mg->max_meshes) {
174                 newmax = mg->max_meshes ? mg->max_meshes * 2 : 16;
175                 if(!(tmp = realloc(mg->meshes, newmax * sizeof *mg->meshes))) {
176                         return -1;
177                 }
178                 mg->meshes = tmp;
179                 mg->max_meshes = newmax;
180         }
181
182         mg->meshes[mg->num_meshes++] = m;
183         return 0;
184 }
185
186 void draw_mesh(struct mesh *m)
187 {
188         if(!m->vbovalid) {
189                 if(update_mesh_vbo(m) == -1) {
190                         return;
191                 }
192         }
193
194         glEnableVertexAttribArray(MESH_ATTR_VERTEX);
195         glEnableVertexAttribArray(MESH_ATTR_NORMAL);
196         glEnableVertexAttribArray(MESH_ATTR_TANGENT);
197         glEnableVertexAttribArray(MESH_ATTR_TEXCOORD);
198
199         glBindBuffer(GL_ARRAY_BUFFER, m->vbo);
200         glVertexAttribPointer(MESH_ATTR_VERTEX, 3, GL_FLOAT, 0, sizeof *m->varr, 0);
201         glVertexAttribPointer(MESH_ATTR_NORMAL, 3, GL_FLOAT, 0, sizeof *m->varr, (void*)offsetof(struct vertex, norm));
202         glVertexAttribPointer(MESH_ATTR_TANGENT, 3, GL_FLOAT, 0, sizeof *m->varr, (void*)offsetof(struct vertex, tang));
203         glVertexAttribPointer(MESH_ATTR_TEXCOORD, 2, GL_FLOAT, 0, sizeof *m->varr, (void*)offsetof(struct vertex, tex));
204         glBindBuffer(GL_ARRAY_BUFFER, 0);
205
206         if(m->ibo) {
207                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m->ibo);
208                 glDrawElements(GL_TRIANGLES, m->num_idx, GL_UNSIGNED_INT, 0);
209                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
210         } else {
211                 glDrawArrays(GL_TRIANGLES, 0, m->num_verts);
212         }
213
214         glDisableVertexAttribArray(MESH_ATTR_VERTEX);
215         glDisableVertexAttribArray(MESH_ATTR_NORMAL);
216         glDisableVertexAttribArray(MESH_ATTR_TANGENT);
217         glDisableVertexAttribArray(MESH_ATTR_TEXCOORD);
218 }
219
220 void draw_meshgroup(struct meshgroup *mg)
221 {
222         if(!mg->vbovalid) {
223                 if(update_meshgroup_vbo(mg) == -1) {
224                         return;
225                 }
226         }
227
228         glEnableVertexAttribArray(MESH_ATTR_VERTEX);
229         glEnableVertexAttribArray(MESH_ATTR_NORMAL);
230         glEnableVertexAttribArray(MESH_ATTR_TANGENT);
231         glEnableVertexAttribArray(MESH_ATTR_TEXCOORD);
232
233         glBindBuffer(GL_ARRAY_BUFFER, mg->vbo);
234         glVertexAttribPointer(MESH_ATTR_VERTEX, 3, GL_FLOAT, 0, sizeof(struct vertex), 0);
235         glVertexAttribPointer(MESH_ATTR_NORMAL, 3, GL_FLOAT, 0, sizeof(struct vertex), (void*)offsetof(struct vertex, norm));
236         glVertexAttribPointer(MESH_ATTR_TANGENT, 3, GL_FLOAT, 0, sizeof(struct vertex), (void*)offsetof(struct vertex, tang));
237         glVertexAttribPointer(MESH_ATTR_TEXCOORD, 2, GL_FLOAT, 0, sizeof(struct vertex), (void*)offsetof(struct vertex, tex));
238         glBindBuffer(GL_ARRAY_BUFFER, 0);
239
240         if(mg->ibo) {
241                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mg->ibo);
242                 glDrawElements(GL_TRIANGLES, mg->num_idx, GL_UNSIGNED_INT, 0);
243                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
244         } else {
245                 glDrawArrays(GL_TRIANGLES, 0, mg->num_verts);
246         }
247
248         glDisableVertexAttribArray(MESH_ATTR_VERTEX);
249         glDisableVertexAttribArray(MESH_ATTR_NORMAL);
250         glDisableVertexAttribArray(MESH_ATTR_TANGENT);
251         glDisableVertexAttribArray(MESH_ATTR_TEXCOORD);
252 }
253
254 static int update_mesh_vbo(struct mesh *m)
255 {
256         if(m->num_verts <= 0) return -1;
257
258         if(!m->vbo) {
259                 glGenBuffers(1, &m->vbo);
260         }
261         glBindBuffer(GL_ARRAY_BUFFER, m->vbo);
262         glBufferData(GL_ARRAY_BUFFER, m->num_verts * sizeof *m->varr, m->varr, GL_STATIC_DRAW);
263         glBindBuffer(GL_ARRAY_BUFFER, 0);
264
265         if(m->num_idx > 0) {
266                 if(!m->ibo) {
267                         glGenBuffers(1, &m->ibo);
268                 }
269                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m->ibo);
270                 glBufferData(GL_ELEMENT_ARRAY_BUFFER, m->num_idx * sizeof *m->iarr,
271                                 m->iarr, GL_STATIC_DRAW);
272                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
273         }
274         return 0;
275 }
276
277 static int update_meshgroup_vbo(struct meshgroup *mg)
278 {
279         int i;
280         struct vertex *varr, *vptr;
281         unsigned int *iarr = 0, *iptr;
282         struct mesh *m;
283
284         mg->num_verts = mg->num_idx = 0;
285
286         for(i=0; i<mg->num_meshes; i++) {
287                 mg->num_verts += mg->meshes[i]->num_verts;
288                 mg->num_idx += mg->meshes[i]->num_idx;
289         }
290
291         if(mg->num_verts <= 0) return -1;
292
293         if(!(varr = malloc(mg->num_verts * sizeof *varr))) {
294                 fprintf(stderr, "update_meshgroup_vbo: failed to allocate vertex array with %d vertices\n", mg->num_verts);
295                 return -1;
296         }
297         if(mg->num_idx > 0) {
298                 if(!(iarr = malloc(mg->num_idx * sizeof *iarr))) {
299                         fprintf(stderr, "update_meshgroup_vbo: failed to allocate index array with %d indices\n", mg->num_idx);
300                         free(varr);
301                         return -1;
302                 }
303         }
304
305         vptr = varr;
306         iptr = iarr;
307
308         for(i=0; i<mg->num_meshes; i++) {
309                 m = mg->meshes[i];
310                 memcpy(vptr, m->varr, m->num_verts * sizeof *vptr);
311                 vptr += m->num_verts;
312
313                 if(iarr) {
314                         memcpy(iptr, m->iarr, m->num_idx * sizeof *iptr);
315                         iptr += m->num_idx;
316                 }
317         }
318
319         if(!mg->vbo) {
320                 glGenBuffers(1, &mg->vbo);
321         }
322         glBindBuffer(GL_ARRAY_BUFFER, mg->vbo);
323         glBufferData(GL_ARRAY_BUFFER, mg->num_verts * sizeof *varr, varr, GL_STATIC_DRAW);
324         glBindBuffer(GL_ARRAY_BUFFER, 0);
325         if(iarr) {
326                 if(!mg->ibo) {
327                         glGenBuffers(1, &mg->ibo);
328                 }
329                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mg->ibo);
330                 glBufferData(GL_ELEMENT_ARRAY_BUFFER, mg->num_idx * sizeof *iarr, iarr, GL_STATIC_DRAW);
331                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
332         }
333
334         free(varr);
335         free(iarr);
336         return 0;
337 }