fixed Mesh wireframe rendering for non-indexed meshes
[vrfileman] / src / mesh.cc
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <float.h>
4 #include <assert.h>
5 #include "opengl.h"
6 #include "mesh.h"
7 //#include "xform_node.h"
8
9 #define USE_OLDGL
10
11 bool Mesh::use_custom_sdr_attr = true;
12 int Mesh::global_sdr_loc[NUM_MESH_ATTR] = { 0, 1, 2, 3, 4, 5, 6 };
13 /*
14         (int)SDR_ATTR_VERTEX,
15         (int)SDR_ATTR_NORMAL,
16         (int)SDR_ATTR_TANGENT,
17         (int)SDR_ATTR_TEXCOORD,
18         (int)SDR_ATTR_COLOR,
19         -1, -1};
20 */
21 unsigned int Mesh::intersect_mode = ISECT_DEFAULT;
22 float Mesh::vertex_sel_dist = 0.01;
23 float Mesh::vis_vecsize = 1.0;
24
25 Mesh::Mesh()
26 {
27         clear();
28
29         glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects);
30
31         for(int i=0; i<NUM_MESH_ATTR; i++) {
32                 vattr[i].vbo = buffer_objects[i];
33         }
34         ibo = buffer_objects[NUM_MESH_ATTR];
35         wire_ibo = 0;
36 }
37
38 Mesh::~Mesh()
39 {
40         glDeleteBuffers(NUM_MESH_ATTR + 1, buffer_objects);
41
42         if(wire_ibo) {
43                 glDeleteBuffers(1, &wire_ibo);
44         }
45 }
46
47 Mesh::Mesh(const Mesh &rhs)
48 {
49         clear();
50
51         glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects);
52
53         for(int i=0; i<NUM_MESH_ATTR; i++) {
54                 vattr[i].vbo = buffer_objects[i];
55         }
56         ibo = buffer_objects[NUM_MESH_ATTR];
57         wire_ibo = 0;
58
59         clone(rhs);
60 }
61
62 Mesh &Mesh::operator =(const Mesh &rhs)
63 {
64         if(&rhs != this) {
65                 clone(rhs);
66         }
67         return *this;
68 }
69
70 bool Mesh::clone(const Mesh &m)
71 {
72         clear();
73
74         for(int i=0; i<NUM_MESH_ATTR; i++) {
75                 if(m.has_attrib(i)) {
76                         m.get_attrib_data(i);   // force validation of the actual data on the source mesh
77
78                         vattr[i].nelem = m.vattr[i].nelem;
79                         vattr[i].data = m.vattr[i].data;        // copy the actual data
80                         vattr[i].data_valid = true;
81                 }
82         }
83
84         if(m.is_indexed()) {
85                 m.get_index_data();             // again, force validation
86
87                 // copy the index data
88                 idata = m.idata;
89                 idata_valid = true;
90         }
91
92         name = m.name;
93         nverts = m.nverts;
94         nfaces = m.nfaces;
95
96         //bones = m.bones;
97
98         memcpy(cur_val, m.cur_val, sizeof cur_val);
99
100         aabb = m.aabb;
101         aabb_valid = m.aabb_valid;
102         bsph = m.bsph;
103         bsph_valid = m.bsph_valid;
104
105         hitface = m.hitface;
106         hitvert = m.hitvert;
107
108         intersect_mode = m.intersect_mode;
109         vertex_sel_dist = m.vertex_sel_dist;
110         vis_vecsize = m.vis_vecsize;
111
112         return true;
113 }
114
115 void Mesh::set_name(const char *name)
116 {
117         this->name = name;
118 }
119
120 const char *Mesh::get_name() const
121 {
122         return name.c_str();
123 }
124
125 bool Mesh::has_attrib(int attr) const
126 {
127         if(attr < 0 || attr >= NUM_MESH_ATTR) {
128                 return false;
129         }
130
131         // if neither of these is valid, then nobody has set this attribute
132         return vattr[attr].vbo_valid || vattr[attr].data_valid;
133 }
134
135 bool Mesh::is_indexed() const
136 {
137         return ibo_valid || idata_valid;
138 }
139
140 void Mesh::clear()
141 {
142         //bones.clear();
143
144         for(int i=0; i<NUM_MESH_ATTR; i++) {
145                 vattr[i].nelem = 0;
146                 vattr[i].vbo_valid = false;
147                 vattr[i].data_valid = false;
148                 //vattr[i].sdr_loc = -1;
149                 vattr[i].data.clear();
150         }
151         ibo_valid = idata_valid = false;
152         idata.clear();
153
154         wire_ibo_valid = false;
155
156         nverts = nfaces = 0;
157
158         bsph_valid = false;
159         aabb_valid = false;
160 }
161
162 float *Mesh::set_attrib_data(int attrib, int nelem, unsigned int num, const float *data)
163 {
164         if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
165                 fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
166                 return 0;
167         }
168
169         if(nverts && num != nverts) {
170                 fprintf(stderr, "%s: attribute count missmatch (%d instead of %d)\n", __FUNCTION__, num, nverts);
171                 return 0;
172         }
173         nverts = num;
174
175         vattr[attrib].data.clear();
176         vattr[attrib].nelem = nelem;
177         vattr[attrib].data.resize(num * nelem);
178
179         if(data) {
180                 memcpy(&vattr[attrib].data[0], data, num * nelem * sizeof *data);
181         }
182
183         vattr[attrib].data_valid = true;
184         vattr[attrib].vbo_valid = false;
185         return &vattr[attrib].data[0];
186 }
187
188 float *Mesh::get_attrib_data(int attrib)
189 {
190         if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
191                 fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
192                 return 0;
193         }
194
195         vattr[attrib].vbo_valid = false;
196         return (float*)((const Mesh*)this)->get_attrib_data(attrib);
197 }
198
199 const float *Mesh::get_attrib_data(int attrib) const
200 {
201         if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
202                 fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
203                 return 0;
204         }
205
206         if(!vattr[attrib].data_valid) {
207 #if GL_ES_VERSION_2_0
208                 fprintf(stderr, "%s: can't read back attrib data on CrippledGL ES\n", __FUNCTION__);
209                 return 0;
210 #else
211                 if(!vattr[attrib].vbo_valid) {
212                         fprintf(stderr, "%s: unavailable attrib: %d\n", __FUNCTION__, attrib);
213                         return 0;
214                 }
215
216                 // local data copy is unavailable, grab the data from the vbo
217                 Mesh *m = (Mesh*)this;
218                 m->vattr[attrib].data.resize(nverts * vattr[attrib].nelem);
219
220                 glBindBuffer(GL_ARRAY_BUFFER, vattr[attrib].vbo);
221                 void *data = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
222                 memcpy(&m->vattr[attrib].data[0], data, nverts * vattr[attrib].nelem * sizeof(float));
223                 glUnmapBuffer(GL_ARRAY_BUFFER);
224
225                 vattr[attrib].data_valid = true;
226 #endif
227         }
228
229         return &vattr[attrib].data[0];
230 }
231
232 void Mesh::set_attrib(int attrib, int idx, const Vec4 &v)
233 {
234         float *data = get_attrib_data(attrib);
235         if(data) {
236                 data += idx * vattr[attrib].nelem;
237                 for(int i=0; i<vattr[attrib].nelem; i++) {
238                         data[i] = v[i];
239                 }
240         }
241 }
242
243 Vec4 Mesh::get_attrib(int attrib, int idx) const
244 {
245         Vec4 v(0.0, 0.0, 0.0, 1.0);
246         const float *data = get_attrib_data(attrib);
247         if(data) {
248                 data += idx * vattr[attrib].nelem;
249                 for(int i=0; i<vattr[attrib].nelem; i++) {
250                         v[i] = data[i];
251                 }
252         }
253         return v;
254 }
255
256 int Mesh::get_attrib_count(int attrib) const
257 {
258         return has_attrib(attrib) ? nverts : 0;
259 }
260
261
262 unsigned int *Mesh::set_index_data(int num, const unsigned int *indices)
263 {
264         int nidx = nfaces * 3;
265         if(nidx && num != nidx) {
266                 fprintf(stderr, "%s: index count mismatch (%d instead of %d)\n", __FUNCTION__, num, nidx);
267                 return 0;
268         }
269         nfaces = num / 3;
270
271         idata.clear();
272         idata.resize(num);
273
274         if(indices) {
275                 memcpy(&idata[0], indices, num * sizeof *indices);
276         }
277
278         idata_valid = true;
279         ibo_valid = false;
280
281         return &idata[0];
282 }
283
284 unsigned int *Mesh::get_index_data()
285 {
286         ibo_valid = false;
287         return (unsigned int*)((const Mesh*)this)->get_index_data();
288 }
289
290 const unsigned int *Mesh::get_index_data() const
291 {
292         if(!idata_valid) {
293 #if GL_ES_VERSION_2_0
294                 fprintf(stderr, "%s: can't read back index data in CrippledGL ES\n", __FUNCTION__);
295                 return 0;
296 #else
297                 if(!ibo_valid) {
298                         fprintf(stderr, "%s: indices unavailable\n", __FUNCTION__);
299                         return 0;
300                 }
301
302                 // local data copy is unavailable, gram the data from the ibo
303                 Mesh *m = (Mesh*)this;
304                 int nidx = nfaces * 3;
305                 m->idata.resize(nidx);
306
307                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
308                 void *data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY);
309                 memcpy(&m->idata[0], data, nidx * sizeof(unsigned int));
310                 glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
311
312                 idata_valid = true;
313 #endif
314         }
315
316         return &idata[0];
317 }
318
319 int Mesh::get_index_count() const
320 {
321         return nfaces * 3;
322 }
323
324 void Mesh::append(const Mesh &mesh)
325 {
326         unsigned int idxoffs = nverts;
327
328         if(!nverts) {
329                 clone(mesh);
330                 return;
331         }
332
333         nverts += mesh.nverts;
334         nfaces += mesh.nfaces;
335
336         for(int i=0; i<NUM_MESH_ATTR; i++) {
337                 if(has_attrib(i) && mesh.has_attrib(i)) {
338                         // force validating the data arrays
339                         get_attrib_data(i);
340                         mesh.get_attrib_data(i);
341
342                         // append the mesh data
343                         vattr[i].data.insert(vattr[i].data.end(), mesh.vattr[i].data.begin(), mesh.vattr[i].data.end());
344                 }
345         }
346
347         if(ibo_valid || idata_valid) {
348                 // make index arrays valid
349                 get_index_data();
350                 mesh.get_index_data();
351
352                 size_t orig_sz = idata.size();
353
354                 idata.insert(idata.end(), mesh.idata.begin(), mesh.idata.end());
355
356                 // fixup all the new indices
357                 for(size_t i=orig_sz; i<idata.size(); i++) {
358                         idata[i] += idxoffs;
359                 }
360         }
361
362         // fuck everything
363         wire_ibo_valid = false;
364         aabb_valid = false;
365         bsph_valid = false;
366 }
367
368 // assemble a complete vertex by adding all the useful attributes
369 void Mesh::vertex(float x, float y, float z)
370 {
371         cur_val[MESH_ATTR_VERTEX] = Vec4(x, y, z, 1.0f);
372         vattr[MESH_ATTR_VERTEX].data_valid = true;
373         vattr[MESH_ATTR_VERTEX].nelem = 3;
374
375         for(int i=0; i<NUM_MESH_ATTR; i++) {
376                 if(vattr[i].data_valid) {
377                         for(int j=0; j<vattr[MESH_ATTR_VERTEX].nelem; j++) {
378                                 vattr[i].data.push_back(cur_val[i][j]);
379                         }
380                 }
381                 vattr[i].vbo_valid = false;
382         }
383
384         if(idata_valid) {
385                 idata.clear();
386         }
387         ibo_valid = idata_valid = false;
388 }
389
390 void Mesh::normal(float nx, float ny, float nz)
391 {
392         cur_val[MESH_ATTR_NORMAL] = Vec4(nx, ny, nz, 1.0f);
393         vattr[MESH_ATTR_NORMAL].data_valid = true;
394         vattr[MESH_ATTR_NORMAL].nelem = 3;
395 }
396
397 void Mesh::tangent(float tx, float ty, float tz)
398 {
399         cur_val[MESH_ATTR_TANGENT] = Vec4(tx, ty, tz, 1.0f);
400         vattr[MESH_ATTR_TANGENT].data_valid = true;
401         vattr[MESH_ATTR_TANGENT].nelem = 3;
402 }
403
404 void Mesh::texcoord(float u, float v, float w)
405 {
406         cur_val[MESH_ATTR_TEXCOORD] = Vec4(u, v, w, 1.0f);
407         vattr[MESH_ATTR_TEXCOORD].data_valid = true;
408         vattr[MESH_ATTR_TEXCOORD].nelem = 3;
409 }
410
411 void Mesh::boneweights(float w1, float w2, float w3, float w4)
412 {
413         cur_val[MESH_ATTR_BONEWEIGHTS] = Vec4(w1, w2, w3, w4);
414         vattr[MESH_ATTR_BONEWEIGHTS].data_valid = true;
415         vattr[MESH_ATTR_BONEWEIGHTS].nelem = 4;
416 }
417
418 void Mesh::boneidx(int idx1, int idx2, int idx3, int idx4)
419 {
420         cur_val[MESH_ATTR_BONEIDX] = Vec4(idx1, idx2, idx3, idx4);
421         vattr[MESH_ATTR_BONEIDX].data_valid = true;
422         vattr[MESH_ATTR_BONEIDX].nelem = 4;
423 }
424
425 int Mesh::get_poly_count() const
426 {
427         if(nfaces) {
428                 return nfaces;
429         }
430         if(nverts) {
431                 return nverts / 3;
432         }
433         return 0;
434 }
435
436 /// static function
437 void Mesh::set_attrib_location(int attr, int loc)
438 {
439         if(attr < 0 || attr >= NUM_MESH_ATTR) {
440                 return;
441         }
442         Mesh::global_sdr_loc[attr] = loc;
443 }
444
445 /// static function
446 int Mesh::get_attrib_location(int attr)
447 {
448         if(attr < 0 || attr >= NUM_MESH_ATTR) {
449                 return -1;
450         }
451         return Mesh::global_sdr_loc[attr];
452 }
453
454 /// static function
455 void Mesh::clear_attrib_locations()
456 {
457         for(int i=0; i<NUM_MESH_ATTR; i++) {
458                 Mesh::global_sdr_loc[i] = -1;
459         }
460 }
461
462 /// static function
463 void Mesh::set_vis_vecsize(float sz)
464 {
465         Mesh::vis_vecsize = sz;
466 }
467
468 float Mesh::get_vis_vecsize()
469 {
470         return Mesh::vis_vecsize;
471 }
472
473 void Mesh::apply_xform(const Mat4 &xform)
474 {
475         Mat4 dir_xform = xform.upper3x3();
476         apply_xform(xform, dir_xform);
477 }
478
479 void Mesh::apply_xform(const Mat4 &xform, const Mat4 &dir_xform)
480 {
481         for(unsigned int i=0; i<nverts; i++) {
482                 Vec4 v = get_attrib(MESH_ATTR_VERTEX, i);
483                 set_attrib(MESH_ATTR_VERTEX, i, xform * v);
484
485                 if(has_attrib(MESH_ATTR_NORMAL)) {
486                         Vec3 n = Vec3(get_attrib(MESH_ATTR_NORMAL, i));
487                         set_attrib(MESH_ATTR_NORMAL, i, Vec4(dir_xform * n));
488                 }
489                 if(has_attrib(MESH_ATTR_TANGENT)) {
490                         Vec3 t = Vec3(get_attrib(MESH_ATTR_TANGENT, i));
491                         set_attrib(MESH_ATTR_TANGENT, i, Vec4(dir_xform * t));
492                 }
493         }
494 }
495
496 void Mesh::flip()
497 {
498         flip_faces();
499         flip_normals();
500 }
501
502 void Mesh::flip_faces()
503 {
504         if(is_indexed()) {
505                 unsigned int *indices = get_index_data();
506                 if(!indices) return;
507
508                 int idxnum = get_index_count();
509                 for(int i=0; i<idxnum; i+=3) {
510                         unsigned int tmp = indices[i + 2];
511                         indices[i + 2] = indices[i + 1];
512                         indices[i + 1] = tmp;
513                 }
514
515         } else {
516                 Vec3 *verts = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX);
517                 if(!verts) return;
518
519                 int vnum = get_attrib_count(MESH_ATTR_VERTEX);
520                 for(int i=0; i<vnum; i+=3) {
521                         Vec3 tmp = verts[i + 2];
522                         verts[i + 2] = verts[i + 1];
523                         verts[i + 1] = tmp;
524                 }
525         }
526 }
527
528 void Mesh::flip_normals()
529 {
530         Vec3 *normals = (Vec3*)get_attrib_data(MESH_ATTR_NORMAL);
531         if(!normals) return;
532
533         int num = get_attrib_count(MESH_ATTR_NORMAL);
534         for(int i=0; i<num; i++) {
535                 normals[i] = -normals[i];
536         }
537 }
538
539 /*
540 int Mesh::add_bone(XFormNode *bone)
541 {
542         int idx = bones.size();
543         bones.push_back(bone);
544         return idx;
545 }
546
547 const XFormNode *Mesh::get_bone(int idx) const
548 {
549         if(idx < 0 || idx >= (int)bones.size()) {
550                 return 0;
551         }
552         return bones[idx];
553 }
554
555 int Mesh::get_bones_count() const
556 {
557         return (int)bones.size();
558 }
559 */
560
561 bool Mesh::pre_draw() const
562 {
563         cur_sdr = 0;
564         glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
565
566         ((Mesh*)this)->update_buffers();
567
568         if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
569                 fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
570                 return false;
571         }
572
573         if(cur_sdr && use_custom_sdr_attr) {
574                 // rendering with shaders
575                 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
576                         fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__);
577                         return false;
578                 }
579
580                 for(int i=0; i<NUM_MESH_ATTR; i++) {
581                         int loc = global_sdr_loc[i];
582                         if(loc >= 0 && vattr[i].vbo_valid) {
583                                 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
584                                 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
585                                 glEnableVertexAttribArray(loc);
586                         }
587                 }
588         } else {
589 #ifndef GL_ES_VERSION_2_0
590                 // rendering with fixed-function (not available in GLES2)
591                 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_VERTEX].vbo);
592                 glVertexPointer(vattr[MESH_ATTR_VERTEX].nelem, GL_FLOAT, 0, 0);
593                 glEnableClientState(GL_VERTEX_ARRAY);
594
595                 if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
596                         glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_NORMAL].vbo);
597                         glNormalPointer(GL_FLOAT, 0, 0);
598                         glEnableClientState(GL_NORMAL_ARRAY);
599                 }
600                 if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
601                         glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_TEXCOORD].vbo);
602                         glTexCoordPointer(vattr[MESH_ATTR_TEXCOORD].nelem, GL_FLOAT, 0, 0);
603                         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
604                 }
605                 if(vattr[MESH_ATTR_COLOR].vbo_valid) {
606                         glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_COLOR].vbo);
607                         glColorPointer(vattr[MESH_ATTR_COLOR].nelem, GL_FLOAT, 0, 0);
608                         glEnableClientState(GL_COLOR_ARRAY);
609                 }
610 #endif
611         }
612         glBindBuffer(GL_ARRAY_BUFFER, 0);
613
614         return true;
615 }
616
617 void Mesh::draw() const
618 {
619         if(!pre_draw()) return;
620
621         if(ibo_valid) {
622                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
623                 glDrawElements(GL_TRIANGLES, nfaces * 3, GL_UNSIGNED_INT, 0);
624                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
625         } else {
626                 glDrawArrays(GL_TRIANGLES, 0, nverts);
627         }
628
629         post_draw();
630 }
631
632 void Mesh::post_draw() const
633 {
634         if(cur_sdr && use_custom_sdr_attr) {
635                 // rendered with shaders
636                 for(int i=0; i<NUM_MESH_ATTR; i++) {
637                         int loc = global_sdr_loc[i];
638                         if(loc >= 0 && vattr[i].vbo_valid) {
639                                 glDisableVertexAttribArray(loc);
640                         }
641                 }
642         } else {
643 #ifndef GL_ES_VERSION_2_0
644                 // rendered with fixed-function
645                 glDisableClientState(GL_VERTEX_ARRAY);
646                 if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
647                         glDisableClientState(GL_NORMAL_ARRAY);
648                 }
649                 if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
650                         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
651                 }
652                 if(vattr[MESH_ATTR_COLOR].vbo_valid) {
653                         glDisableClientState(GL_COLOR_ARRAY);
654                 }
655 #endif
656         }
657 }
658
659 void Mesh::draw_wire() const
660 {
661         if(!pre_draw()) return;
662
663         ((Mesh*)this)->update_wire_ibo();
664
665         int num_faces = get_poly_count();
666         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
667         glDrawElements(GL_LINES, num_faces * 6, GL_UNSIGNED_INT, 0);
668         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
669
670         post_draw();
671 }
672
673 void Mesh::draw_vertices() const
674 {
675         if(!pre_draw()) return;
676
677         glDrawArrays(GL_POINTS, 0, nverts);
678
679         post_draw();
680 }
681
682 void Mesh::draw_normals() const
683 {
684 #ifdef USE_OLDGL
685         int cur_sdr = 0;
686         glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
687
688         Vec3 *varr = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX);
689         Vec3 *norm = (Vec3*)get_attrib_data(MESH_ATTR_NORMAL);
690         if(!varr || !norm) {
691                 return;
692         }
693
694         glBegin(GL_LINES);
695         if(cur_sdr && use_custom_sdr_attr) {
696                 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
697                 if(vert_loc < 0) {
698                         glEnd();
699                         return;
700                 }
701
702                 for(size_t i=0; i<nverts; i++) {
703                         glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
704                         Vec3 end = varr[i] + norm[i] * vis_vecsize;
705                         glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
706                 }
707         } else {
708                 for(size_t i=0; i<nverts; i++) {
709                         glVertex3f(varr[i].x, varr[i].y, varr[i].z);
710                         Vec3 end = varr[i] + norm[i] * vis_vecsize;
711                         glVertex3f(end.x, end.y, end.z);
712                 }
713         }
714         glEnd();
715 #endif  // USE_OLDGL
716 }
717
718 void Mesh::draw_tangents() const
719 {
720 #ifdef USE_OLDGL
721         int cur_sdr = 0;
722         glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
723
724         Vec3 *varr = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX);
725         Vec3 *tang = (Vec3*)get_attrib_data(MESH_ATTR_TANGENT);
726         if(!varr || !tang) {
727                 return;
728         }
729
730         glBegin(GL_LINES);
731         if(cur_sdr && use_custom_sdr_attr) {
732                 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
733                 if(vert_loc < 0) {
734                         glEnd();
735                         return;
736                 }
737
738                 for(size_t i=0; i<nverts; i++) {
739                         glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
740                         Vec3 end = varr[i] + tang[i] * vis_vecsize;
741                         glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
742                 }
743         } else {
744                 for(size_t i=0; i<nverts; i++) {
745                         glVertex3f(varr[i].x, varr[i].y, varr[i].z);
746                         Vec3 end = varr[i] + tang[i] * vis_vecsize;
747                         glVertex3f(end.x, end.y, end.z);
748                 }
749         }
750         glEnd();
751 #endif  // USE_OLDGL
752 }
753
754 void Mesh::get_aabbox(Vec3 *vmin, Vec3 *vmax) const
755 {
756         if(!aabb_valid) {
757                 ((Mesh*)this)->calc_aabb();
758         }
759         *vmin = aabb.min;
760         *vmax = aabb.max;
761 }
762
763 const AABox &Mesh::get_aabbox() const
764 {
765         if(!aabb_valid) {
766                 ((Mesh*)this)->calc_aabb();
767         }
768         return aabb;
769 }
770
771 float Mesh::get_bsphere(Vec3 *center, float *rad) const
772 {
773         if(!bsph_valid) {
774                 ((Mesh*)this)->calc_bsph();
775         }
776         *center = bsph.center;
777         *rad = bsph.radius;
778         return bsph.radius;
779 }
780
781 const Sphere &Mesh::get_bsphere() const
782 {
783         if(!bsph_valid) {
784                 ((Mesh*)this)->calc_bsph();
785         }
786         return bsph;
787 }
788
789 /// static function
790 void Mesh::set_intersect_mode(unsigned int mode)
791 {
792         Mesh::intersect_mode = mode;
793 }
794
795 /// static function
796 unsigned int Mesh::get_intersect_mode()
797 {
798         return Mesh::intersect_mode;
799 }
800
801 /// static function
802 void Mesh::set_vertex_select_distance(float dist)
803 {
804         Mesh::vertex_sel_dist = dist;
805 }
806
807 /// static function
808 float Mesh::get_vertex_select_distance()
809 {
810         return Mesh::vertex_sel_dist;
811 }
812
813 bool Mesh::intersect(const Ray &ray, HitPoint *hit) const
814 {
815         assert((Mesh::intersect_mode & (ISECT_VERTICES | ISECT_FACE)) != (ISECT_VERTICES | ISECT_FACE));
816
817         const Vec3 *varr = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX);
818         const Vec3 *narr = (Vec3*)get_attrib_data(MESH_ATTR_NORMAL);
819         if(!varr) {
820                 return false;
821         }
822         const unsigned int *idxarr = get_index_data();
823
824         // first test with the bounding box
825         AABox box;
826         get_aabbox(&box.min, &box.max);
827         if(!box.intersect(ray)) {
828                 return false;
829         }
830
831         HitPoint nearest_hit;
832         nearest_hit.dist = FLT_MAX;
833         nearest_hit.obj = 0;
834
835         if(Mesh::intersect_mode & ISECT_VERTICES) {
836                 // we asked for "intersections" with the vertices of the mesh
837                 long nearest_vidx = -1;
838                 float thres_sq = Mesh::vertex_sel_dist * Mesh::vertex_sel_dist;
839
840                 for(unsigned int i=0; i<nverts; i++) {
841
842                         if((Mesh::intersect_mode & ISECT_FRONT) && dot(narr[i], ray.dir) > 0) {
843                                 continue;
844                         }
845
846                         // project the vertex onto the ray line
847                         float t = dot(varr[i] - ray.origin, ray.dir);
848                         Vec3 vproj = ray.origin + ray.dir * t;
849
850                         float dist_sq = length_sq(vproj - varr[i]);
851                         if(dist_sq < thres_sq) {
852                                 if(!hit) {
853                                         return true;
854                                 }
855                                 if(t < nearest_hit.dist) {
856                                         nearest_hit.dist = t;
857                                         nearest_vidx = i;
858                                 }
859                         }
860                 }
861
862                 if(nearest_vidx != -1) {
863                         hitvert = varr[nearest_vidx];
864                         nearest_hit.obj = &hitvert;
865                 }
866
867         } else {
868                 // regular intersection test with polygons
869
870                 for(unsigned int i=0; i<nfaces; i++) {
871                         Triangle face(i, varr, idxarr);
872
873                         // ignore back-facing polygons if the mode flags include ISECT_FRONT
874                         if((Mesh::intersect_mode & ISECT_FRONT) && dot(face.get_normal(), ray.dir) > 0) {
875                                 continue;
876                         }
877
878                         HitPoint fhit;
879                         if(face.intersect(ray, hit ? &fhit : 0)) {
880                                 if(!hit) {
881                                         return true;
882                                 }
883                                 if(fhit.dist < nearest_hit.dist) {
884                                         nearest_hit = fhit;
885                                         hitface = face;
886                                 }
887                         }
888                 }
889         }
890
891         if(nearest_hit.obj) {
892                 if(hit) {
893                         *hit = nearest_hit;
894
895                         // if we are interested in the mesh and not the faces set obj to this
896                         if(Mesh::intersect_mode & ISECT_FACE) {
897                                 hit->obj = &hitface;
898                         } else if(Mesh::intersect_mode & ISECT_VERTICES) {
899                                 hit->obj = &hitvert;
900                         } else {
901                                 hit->obj = this;
902                         }
903                 }
904                 return true;
905         }
906         return false;
907 }
908
909
910 // texture coordinate manipulation
911 void Mesh::texcoord_apply_xform(const Mat4 &xform)
912 {
913         if(!has_attrib(MESH_ATTR_TEXCOORD)) {
914                 return;
915         }
916
917         for(unsigned int i=0; i<nverts; i++) {
918                 Vec4 tc = get_attrib(MESH_ATTR_TEXCOORD, i);
919                 set_attrib(MESH_ATTR_TEXCOORD, i, xform * tc);
920         }
921 }
922
923 void Mesh::texcoord_gen_plane(const Vec3 &norm, const Vec3 &tang)
924 {
925         if(!nverts) return;
926
927         if(!has_attrib(MESH_ATTR_TEXCOORD)) {
928                 // allocate texture coordinate attribute array
929                 set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts);
930         }
931
932         Vec3 n = normalize(norm);
933         Vec3 b = normalize(cross(n, tang));
934         Vec3 t = cross(b, n);
935
936         for(unsigned int i=0; i<nverts; i++) {
937                 Vec3 pos = Vec3(get_attrib(MESH_ATTR_VERTEX, i));
938
939                 // distance along the tangent direction
940                 float u = dot(pos, t);
941                 // distance along the bitangent direction
942                 float v = dot(pos, b);
943
944                 set_attrib(MESH_ATTR_TEXCOORD, i, Vec4(u, v, 0, 1));
945         }
946 }
947
948 void Mesh::texcoord_gen_box()
949 {
950         if(!nverts || !has_attrib(MESH_ATTR_NORMAL)) return;
951
952         if(!has_attrib(MESH_ATTR_TEXCOORD)) {
953                 // allocate texture coordinate attribute array
954                 set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts);
955         }
956
957         for(unsigned int i=0; i<nverts; i++) {
958                 Vec3 pos = Vec3(get_attrib(MESH_ATTR_VERTEX, i)) * 0.5 + Vec3(0.5, 0.5, 0.5);
959                 Vec3 norm = Vec3(get_attrib(MESH_ATTR_NORMAL, i));
960
961                 float abs_nx = fabs(norm.x);
962                 float abs_ny = fabs(norm.y);
963                 float abs_nz = fabs(norm.z);
964                 int dom = abs_nx > abs_ny && abs_nx > abs_nz ? 0 : (abs_ny > abs_nz ? 1 : 2);
965
966                 float uv[2], *uvptr = uv;
967                 for(int j=0; j<3; j++) {
968                         if(j == dom) continue;  // skip dominant axis
969
970                         *uvptr++ = pos[j];
971                 }
972                 set_attrib(MESH_ATTR_TEXCOORD, i, Vec4(uv[0], uv[1], 0, 1));
973         }
974 }
975
976 void Mesh::texcoord_gen_cylinder()
977 {
978         if(!nverts) return;
979
980         if(!has_attrib(MESH_ATTR_TEXCOORD)) {
981                 // allocate texture coordinate attribute array
982                 set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts);
983         }
984
985         for(unsigned int i=0; i<nverts; i++) {
986                 Vec3 pos = Vec3(get_attrib(MESH_ATTR_VERTEX, i));
987
988                 float rho = sqrt(pos.x * pos.x + pos.z * pos.z);
989                 float theta = rho == 0.0 ? 0.0 : atan2(pos.z / rho, pos.x / rho);
990
991                 float u = theta / (2.0 * M_PI) + 0.5;
992                 float v = pos.y;
993
994                 set_attrib(MESH_ATTR_TEXCOORD, i, Vec4(u, v, 0, 1));
995         }
996 }
997
998
999 bool Mesh::dump(const char *fname) const
1000 {
1001         FILE *fp = fopen(fname, "wb");
1002         if(fp) {
1003                 bool res = dump(fp);
1004                 fclose(fp);
1005                 return res;
1006         }
1007         return false;
1008 }
1009
1010 bool Mesh::dump(FILE *fp) const
1011 {
1012         if(!has_attrib(MESH_ATTR_VERTEX)) {
1013                 return false;
1014         }
1015
1016         fprintf(fp, "VERTEX ATTRIBUTES\n");
1017         static const char *label[] = { "pos", "nor", "tan", "tex", "col", "bw", "bid" };
1018         static const char *elemfmt[] = { 0, " %s(%g)", " %s(%g, %g)", " %s(%g, %g, %g)", " %s(%g, %g, %g, %g)", 0 };
1019
1020         for(int i=0; i<(int)nverts; i++) {
1021                 fprintf(fp, "%5u:", i);
1022                 for(int j=0; j<NUM_MESH_ATTR; j++) {
1023                         if(has_attrib(j)) {
1024                                 Vec4 v = get_attrib(j, i);
1025                                 int nelem = vattr[j].nelem;
1026                                 fprintf(fp, elemfmt[nelem], label[j], v.x, v.y, v.z, v.w);
1027                         }
1028                 }
1029                 fputc('\n', fp);
1030         }
1031
1032         if(is_indexed()) {
1033                 const unsigned int *idx = get_index_data();
1034                 int numidx = get_index_count();
1035                 int numtri = numidx / 3;
1036                 assert(numidx % 3 == 0);
1037
1038                 fprintf(fp, "FACES\n");
1039
1040                 for(int i=0; i<numtri; i++) {
1041                         fprintf(fp, "%5d: %d %d %d\n", i, idx[0], idx[1], idx[2]);
1042                         idx += 3;
1043                 }
1044         }
1045         return true;
1046 }
1047
1048 bool Mesh::dump_obj(const char *fname) const
1049 {
1050         FILE *fp = fopen(fname, "wb");
1051         if(fp) {
1052                 bool res = dump_obj(fp);
1053                 fclose(fp);
1054                 return res;
1055         }
1056         return false;
1057 }
1058
1059 bool Mesh::dump_obj(FILE *fp) const
1060 {
1061         if(!has_attrib(MESH_ATTR_VERTEX)) {
1062                 return false;
1063         }
1064
1065         for(int i=0; i<(int)nverts; i++) {
1066                 Vec4 v = get_attrib(MESH_ATTR_VERTEX, i);
1067                 fprintf(fp, "v %g %g %g\n", v.x, v.y, v.z);
1068         }
1069
1070         if(has_attrib(MESH_ATTR_NORMAL)) {
1071                 for(int i=0; i<(int)nverts; i++) {
1072                         Vec4 v = get_attrib(MESH_ATTR_NORMAL, i);
1073                         fprintf(fp, "vn %g %g %g\n", v.x, v.y, v.z);
1074                 }
1075         }
1076
1077         if(has_attrib(MESH_ATTR_TEXCOORD)) {
1078                 for(int i=0; i<(int)nverts; i++) {
1079                         Vec4 v = get_attrib(MESH_ATTR_TEXCOORD, i);
1080                         fprintf(fp, "vt %g %g\n", v.x, v.y);
1081                 }
1082         }
1083
1084         if(is_indexed()) {
1085                 const unsigned int *idxptr = get_index_data();
1086                 int numidx = get_index_count();
1087                 int numtri = numidx / 3;
1088                 assert(numidx % 3 == 0);
1089
1090                 for(int i=0; i<numtri; i++) {
1091                         fputc('f', fp);
1092                         for(int j=0; j<3; j++) {
1093                                 unsigned int idx = *idxptr++ + 1;
1094                                 fprintf(fp, " %u/%u/%u", idx, idx, idx);
1095                         }
1096                         fputc('\n', fp);
1097                 }
1098         } else {
1099                 int numtri = nverts / 3;
1100                 unsigned int idx = 1;
1101                 for(int i=0; i<numtri; i++) {
1102                         fputc('f', fp);
1103                         for(int j=0; j<3; j++) {
1104                                 fprintf(fp, " %u/%u/%u", idx, idx, idx);
1105                                 ++idx;
1106                         }
1107                         fputc('\n', fp);
1108                 }
1109         }
1110         return true;
1111 }
1112
1113 // ------ private member functions ------
1114
1115 void Mesh::calc_aabb()
1116 {
1117         // the cast is to force calling the const version which doesn't invalidate
1118         if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
1119                 return;
1120         }
1121
1122         aabb.min = Vec3(FLT_MAX, FLT_MAX, FLT_MAX);
1123         aabb.max = -aabb.min;
1124
1125         for(unsigned int i=0; i<nverts; i++) {
1126                 Vec4 v = get_attrib(MESH_ATTR_VERTEX, i);
1127                 for(int j=0; j<3; j++) {
1128                         if(v[j] < aabb.min[j]) {
1129                                 aabb.min[j] = v[j];
1130                         }
1131                         if(v[j] > aabb.max[j]) {
1132                                 aabb.max[j] = v[j];
1133                         }
1134                 }
1135         }
1136         aabb_valid = true;
1137 }
1138
1139 void Mesh::calc_bsph()
1140 {
1141         // the cast is to force calling the const version which doesn't invalidate
1142         if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
1143                 return;
1144         }
1145
1146         Vec3 v;
1147         bsph.center = Vec3(0, 0, 0);
1148
1149         // first find the center
1150         for(unsigned int i=0; i<nverts; i++) {
1151                 v = Vec3(get_attrib(MESH_ATTR_VERTEX, i));
1152                 bsph.center += v;
1153         }
1154         bsph.center /= (float)nverts;
1155
1156         bsph.radius = 0.0f;
1157         for(unsigned int i=0; i<nverts; i++) {
1158                 v = Vec3(get_attrib(MESH_ATTR_VERTEX, i));
1159                 float dist_sq = length_sq(v - bsph.center);
1160                 if(dist_sq > bsph.radius) {
1161                         bsph.radius = dist_sq;
1162                 }
1163         }
1164         bsph.radius = sqrt(bsph.radius);
1165
1166         bsph_valid = true;
1167 }
1168
1169 void Mesh::update_buffers()
1170 {
1171         for(int i=0; i<NUM_MESH_ATTR; i++) {
1172                 if(has_attrib(i) && !vattr[i].vbo_valid) {
1173                         glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
1174                         glBufferData(GL_ARRAY_BUFFER, nverts * vattr[i].nelem * sizeof(float), &vattr[i].data[0], GL_STATIC_DRAW);
1175                         vattr[i].vbo_valid = true;
1176                 }
1177         }
1178         glBindBuffer(GL_ARRAY_BUFFER, 0);
1179
1180         if(idata_valid && !ibo_valid) {
1181                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
1182                 glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 3 * sizeof(unsigned int), &idata[0], GL_STATIC_DRAW);
1183                 ibo_valid = true;
1184         }
1185         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1186 }
1187
1188 void Mesh::update_wire_ibo()
1189 {
1190         update_buffers();
1191
1192         if(wire_ibo_valid) {
1193                 return;
1194         }
1195
1196         if(!wire_ibo) {
1197                 glGenBuffers(1, &wire_ibo);
1198         }
1199
1200         int num_faces = get_poly_count();
1201
1202         unsigned int *wire_idxarr = new unsigned int[num_faces * 6];
1203         unsigned int *dest = wire_idxarr;
1204
1205         if(ibo_valid) {
1206                 // we're dealing with an indexed mesh
1207                 const unsigned int *idxarr = ((const Mesh*)this)->get_index_data();
1208
1209                 for(int i=0; i<num_faces; i++) {
1210                         *dest++ = idxarr[0];
1211                         *dest++ = idxarr[1];
1212                         *dest++ = idxarr[1];
1213                         *dest++ = idxarr[2];
1214                         *dest++ = idxarr[2];
1215                         *dest++ = idxarr[0];
1216                         idxarr += 3;
1217                 }
1218         } else {
1219                 // not an indexed mesh ...
1220                 for(int i=0; i<num_faces; i++) {
1221                         int vidx = i * 3;
1222                         *dest++ = vidx;
1223                         *dest++ = vidx + 1;
1224                         *dest++ = vidx + 1;
1225                         *dest++ = vidx + 2;
1226                         *dest++ = vidx + 2;
1227                         *dest++ = vidx;
1228                 }
1229         }
1230
1231         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
1232         glBufferData(GL_ELEMENT_ARRAY_BUFFER, num_faces * 6 * sizeof(unsigned int), wire_idxarr, GL_STATIC_DRAW);
1233         delete [] wire_idxarr;
1234         wire_ibo_valid = true;
1235         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1236 }
1237
1238
1239 // ------ class Triangle ------
1240 Triangle::Triangle()
1241 {
1242         normal_valid = false;
1243         id = -1;
1244 }
1245
1246 Triangle::Triangle(const Vec3 &v0, const Vec3 &v1, const Vec3 &v2)
1247 {
1248         v[0] = v0;
1249         v[1] = v1;
1250         v[2] = v2;
1251         normal_valid = false;
1252         id = -1;
1253 }
1254
1255 Triangle::Triangle(int n, const Vec3 *varr, const unsigned int *idxarr)
1256 {
1257         if(idxarr) {
1258                 v[0] = varr[idxarr[n * 3]];
1259                 v[1] = varr[idxarr[n * 3 + 1]];
1260                 v[2] = varr[idxarr[n * 3 + 2]];
1261         } else {
1262                 v[0] = varr[n * 3];
1263                 v[1] = varr[n * 3 + 1];
1264                 v[2] = varr[n * 3 + 2];
1265         }
1266         normal_valid = false;
1267         id = n;
1268 }
1269
1270 void Triangle::calc_normal()
1271 {
1272         normal = normalize(cross(v[1] - v[0], v[2] - v[0]));
1273         normal_valid = true;
1274 }
1275
1276 const Vec3 &Triangle::get_normal() const
1277 {
1278         if(!normal_valid) {
1279                 ((Triangle*)this)->calc_normal();
1280         }
1281         return normal;
1282 }
1283
1284 void Triangle::transform(const Mat4 &xform)
1285 {
1286         v[0] = xform * v[0];
1287         v[1] = xform * v[1];
1288         v[2] = xform * v[2];
1289         normal_valid = false;
1290 }
1291
1292 void Triangle::draw() const
1293 {
1294         Vec3 n[3];
1295         n[0] = n[1] = n[2] = get_normal();
1296
1297         int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
1298         int nloc = Mesh::get_attrib_location(MESH_ATTR_NORMAL);
1299
1300         glEnableVertexAttribArray(vloc);
1301         glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
1302         glVertexAttribPointer(nloc, 3, GL_FLOAT, GL_FALSE, 0, &n[0].x);
1303
1304         glDrawArrays(GL_TRIANGLES, 0, 3);
1305
1306         glDisableVertexAttribArray(vloc);
1307         glDisableVertexAttribArray(nloc);
1308 }
1309
1310 void Triangle::draw_wire() const
1311 {
1312         static const int idxarr[] = {0, 1, 1, 2, 2, 0};
1313         int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
1314
1315         glEnableVertexAttribArray(vloc);
1316         glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
1317
1318         glDrawElements(GL_LINES, 6, GL_UNSIGNED_INT, idxarr);
1319
1320         glDisableVertexAttribArray(vloc);
1321 }
1322
1323 Vec3 Triangle::calc_barycentric(const Vec3 &pos) const
1324 {
1325         Vec3 norm = get_normal();
1326
1327         float area_sq = fabs(dot(cross(v[1] - v[0], v[2] - v[0]), norm));
1328         if(area_sq < 1e-5) {
1329                 return Vec3(0, 0, 0);
1330         }
1331
1332         float asq0 = fabs(dot(cross(v[1] - pos, v[2] - pos), norm));
1333         float asq1 = fabs(dot(cross(v[2] - pos, v[0] - pos), norm));
1334         float asq2 = fabs(dot(cross(v[0] - pos, v[1] - pos), norm));
1335
1336         return Vec3(asq0 / area_sq, asq1 / area_sq, asq2 / area_sq);
1337 }
1338
1339 bool Triangle::intersect(const Ray &ray, HitPoint *hit) const
1340 {
1341         Vec3 normal = get_normal();
1342
1343         float ndotdir = dot(ray.dir, normal);
1344         if(fabs(ndotdir) < 1e-4) {
1345                 return false;
1346         }
1347
1348         Vec3 vertdir = v[0] - ray.origin;
1349         float t = dot(normal, vertdir) / ndotdir;
1350
1351         Vec3 pos = ray.origin + ray.dir * t;
1352         Vec3 bary = calc_barycentric(pos);
1353
1354         if(bary.x + bary.y + bary.z > 1.00001) {
1355                 return false;
1356         }
1357
1358         if(hit) {
1359                 hit->dist = t;
1360                 hit->pos = ray.origin + ray.dir * t;
1361                 hit->normal = normal;
1362                 hit->obj = this;
1363         }
1364         return true;
1365 }