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