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