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