initial commit, first gear
[antikythera] / 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 void Mesh::explode()
540 {
541         if(!is_indexed()) return;       // no vertex sharing is possible in unindexed meshes
542
543         unsigned int *indices = get_index_data();
544         assert(indices);
545
546         int idxnum = get_index_count();
547         int nnverts = idxnum;
548
549         nverts = nnverts;
550
551         for(int i=0; i<NUM_MESH_ATTR; i++) {
552                 if(!has_attrib(i)) continue;
553
554                 const float *srcbuf = get_attrib_data(i);
555
556                 float *tmpbuf = new float[nnverts * vattr[i].nelem];
557                 float *dstptr = tmpbuf;
558                 for(int j=0; j<idxnum; j++) {
559                         unsigned int idx = indices[j];
560                         const float *srcptr = srcbuf + idx * vattr[i].nelem;
561
562                         for(int k=0; k<vattr[i].nelem; k++) {
563                                 *dstptr++ = *srcptr++;
564                         }
565                 }
566                 set_attrib_data(i, vattr[i].nelem, nnverts, tmpbuf);
567                 delete [] tmpbuf;
568         }
569
570         ibo_valid = false;
571         idata_valid = false;
572         idata.clear();
573
574         nfaces = idxnum / 3;
575 }
576
577 void Mesh::calc_face_normals()
578 {
579         const Vec3 *varr = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX);
580         Vec3 *narr = (Vec3*)get_attrib_data(MESH_ATTR_NORMAL);
581         if(!varr) {
582                 return;
583         }
584
585         if(is_indexed()) {
586                 const unsigned int *idxarr = get_index_data();
587
588                 for(unsigned int i=0; i<nfaces; i++) {
589                         Triangle face(i, varr, idxarr);
590                         face.calc_normal();
591
592                         for(int j=0; j<3; j++) {
593                                 unsigned int idx = *idxarr++;
594                                 narr[idx] = face.normal;
595                         }
596                 }
597         } else {
598                 // non-indexed
599                 int nfaces = nverts / 3;
600
601                 for(int i=0; i<nfaces; i++) {
602                         Triangle face(varr[0], varr[1], varr[2]);
603                         face.calc_normal();
604
605                         narr[0] = narr[1] = narr[2] = face.normal;
606                         varr += vattr[MESH_ATTR_VERTEX].nelem;
607                         narr += vattr[MESH_ATTR_NORMAL].nelem;
608                 }
609         }
610 }
611
612 /*
613 int Mesh::add_bone(XFormNode *bone)
614 {
615         int idx = bones.size();
616         bones.push_back(bone);
617         return idx;
618 }
619
620 const XFormNode *Mesh::get_bone(int idx) const
621 {
622         if(idx < 0 || idx >= (int)bones.size()) {
623                 return 0;
624         }
625         return bones[idx];
626 }
627
628 int Mesh::get_bones_count() const
629 {
630         return (int)bones.size();
631 }
632 */
633
634 bool Mesh::pre_draw() const
635 {
636         cur_sdr = 0;
637         glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
638
639         ((Mesh*)this)->update_buffers();
640
641         if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
642                 fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
643                 return false;
644         }
645
646         if(cur_sdr && use_custom_sdr_attr) {
647                 // rendering with shaders
648                 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
649                         fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__);
650                         return false;
651                 }
652
653                 for(int i=0; i<NUM_MESH_ATTR; i++) {
654                         int loc = global_sdr_loc[i];
655                         if(loc >= 0 && vattr[i].vbo_valid) {
656                                 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
657                                 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
658                                 glEnableVertexAttribArray(loc);
659                         }
660                 }
661         } else {
662 #ifndef GL_ES_VERSION_2_0
663                 // rendering with fixed-function (not available in GLES2)
664                 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_VERTEX].vbo);
665                 glVertexPointer(vattr[MESH_ATTR_VERTEX].nelem, GL_FLOAT, 0, 0);
666                 glEnableClientState(GL_VERTEX_ARRAY);
667
668                 if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
669                         glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_NORMAL].vbo);
670                         glNormalPointer(GL_FLOAT, 0, 0);
671                         glEnableClientState(GL_NORMAL_ARRAY);
672                 }
673                 if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
674                         glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_TEXCOORD].vbo);
675                         glTexCoordPointer(vattr[MESH_ATTR_TEXCOORD].nelem, GL_FLOAT, 0, 0);
676                         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
677                 }
678                 if(vattr[MESH_ATTR_COLOR].vbo_valid) {
679                         glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_COLOR].vbo);
680                         glColorPointer(vattr[MESH_ATTR_COLOR].nelem, GL_FLOAT, 0, 0);
681                         glEnableClientState(GL_COLOR_ARRAY);
682                 }
683 #endif
684         }
685         glBindBuffer(GL_ARRAY_BUFFER, 0);
686
687         return true;
688 }
689
690 void Mesh::draw() const
691 {
692         if(!pre_draw()) return;
693
694         if(ibo_valid) {
695                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
696                 glDrawElements(GL_TRIANGLES, nfaces * 3, GL_UNSIGNED_INT, 0);
697                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
698         } else {
699                 glDrawArrays(GL_TRIANGLES, 0, nverts);
700         }
701
702         post_draw();
703 }
704
705 void Mesh::post_draw() const
706 {
707         if(cur_sdr && use_custom_sdr_attr) {
708                 // rendered with shaders
709                 for(int i=0; i<NUM_MESH_ATTR; i++) {
710                         int loc = global_sdr_loc[i];
711                         if(loc >= 0 && vattr[i].vbo_valid) {
712                                 glDisableVertexAttribArray(loc);
713                         }
714                 }
715         } else {
716 #ifndef GL_ES_VERSION_2_0
717                 // rendered with fixed-function
718                 glDisableClientState(GL_VERTEX_ARRAY);
719                 if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
720                         glDisableClientState(GL_NORMAL_ARRAY);
721                 }
722                 if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
723                         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
724                 }
725                 if(vattr[MESH_ATTR_COLOR].vbo_valid) {
726                         glDisableClientState(GL_COLOR_ARRAY);
727                 }
728 #endif
729         }
730 }
731
732 void Mesh::draw_wire() const
733 {
734         if(!pre_draw()) return;
735
736         ((Mesh*)this)->update_wire_ibo();
737
738         int num_faces = get_poly_count();
739         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
740         glDrawElements(GL_LINES, num_faces * 6, GL_UNSIGNED_INT, 0);
741         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
742
743         post_draw();
744 }
745
746 void Mesh::draw_vertices() const
747 {
748         if(!pre_draw()) return;
749
750         glDrawArrays(GL_POINTS, 0, nverts);
751
752         post_draw();
753 }
754
755 void Mesh::draw_normals() const
756 {
757 #ifdef USE_OLDGL
758         int cur_sdr = 0;
759         glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
760
761         Vec3 *varr = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX);
762         Vec3 *norm = (Vec3*)get_attrib_data(MESH_ATTR_NORMAL);
763         if(!varr || !norm) {
764                 return;
765         }
766
767         glBegin(GL_LINES);
768         if(cur_sdr && use_custom_sdr_attr) {
769                 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
770                 if(vert_loc < 0) {
771                         glEnd();
772                         return;
773                 }
774
775                 for(size_t i=0; i<nverts; i++) {
776                         glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
777                         Vec3 end = varr[i] + norm[i] * vis_vecsize;
778                         glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
779                 }
780         } else {
781                 for(size_t i=0; i<nverts; i++) {
782                         glVertex3f(varr[i].x, varr[i].y, varr[i].z);
783                         Vec3 end = varr[i] + norm[i] * vis_vecsize;
784                         glVertex3f(end.x, end.y, end.z);
785                 }
786         }
787         glEnd();
788 #endif  // USE_OLDGL
789 }
790
791 void Mesh::draw_tangents() const
792 {
793 #ifdef USE_OLDGL
794         int cur_sdr = 0;
795         glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
796
797         Vec3 *varr = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX);
798         Vec3 *tang = (Vec3*)get_attrib_data(MESH_ATTR_TANGENT);
799         if(!varr || !tang) {
800                 return;
801         }
802
803         glBegin(GL_LINES);
804         if(cur_sdr && use_custom_sdr_attr) {
805                 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
806                 if(vert_loc < 0) {
807                         glEnd();
808                         return;
809                 }
810
811                 for(size_t i=0; i<nverts; i++) {
812                         glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
813                         Vec3 end = varr[i] + tang[i] * vis_vecsize;
814                         glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
815                 }
816         } else {
817                 for(size_t i=0; i<nverts; i++) {
818                         glVertex3f(varr[i].x, varr[i].y, varr[i].z);
819                         Vec3 end = varr[i] + tang[i] * vis_vecsize;
820                         glVertex3f(end.x, end.y, end.z);
821                 }
822         }
823         glEnd();
824 #endif  // USE_OLDGL
825 }
826
827 void Mesh::get_aabbox(Vec3 *vmin, Vec3 *vmax) const
828 {
829         if(!aabb_valid) {
830                 ((Mesh*)this)->calc_aabb();
831         }
832         *vmin = aabb.min;
833         *vmax = aabb.max;
834 }
835
836 const AABox &Mesh::get_aabbox() const
837 {
838         if(!aabb_valid) {
839                 ((Mesh*)this)->calc_aabb();
840         }
841         return aabb;
842 }
843
844 float Mesh::get_bsphere(Vec3 *center, float *rad) const
845 {
846         if(!bsph_valid) {
847                 ((Mesh*)this)->calc_bsph();
848         }
849         *center = bsph.center;
850         *rad = bsph.radius;
851         return bsph.radius;
852 }
853
854 const Sphere &Mesh::get_bsphere() const
855 {
856         if(!bsph_valid) {
857                 ((Mesh*)this)->calc_bsph();
858         }
859         return bsph;
860 }
861
862 /// static function
863 void Mesh::set_intersect_mode(unsigned int mode)
864 {
865         Mesh::intersect_mode = mode;
866 }
867
868 /// static function
869 unsigned int Mesh::get_intersect_mode()
870 {
871         return Mesh::intersect_mode;
872 }
873
874 /// static function
875 void Mesh::set_vertex_select_distance(float dist)
876 {
877         Mesh::vertex_sel_dist = dist;
878 }
879
880 /// static function
881 float Mesh::get_vertex_select_distance()
882 {
883         return Mesh::vertex_sel_dist;
884 }
885
886 bool Mesh::intersect(const Ray &ray, HitPoint *hit) const
887 {
888         assert((Mesh::intersect_mode & (ISECT_VERTICES | ISECT_FACE)) != (ISECT_VERTICES | ISECT_FACE));
889
890         const Vec3 *varr = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX);
891         const Vec3 *narr = (Vec3*)get_attrib_data(MESH_ATTR_NORMAL);
892         if(!varr) {
893                 return false;
894         }
895         const unsigned int *idxarr = get_index_data();
896
897         // first test with the bounding box
898         AABox box;
899         get_aabbox(&box.min, &box.max);
900         if(!box.intersect(ray)) {
901                 return false;
902         }
903
904         HitPoint nearest_hit;
905         nearest_hit.dist = FLT_MAX;
906         nearest_hit.obj = 0;
907
908         if(Mesh::intersect_mode & ISECT_VERTICES) {
909                 // we asked for "intersections" with the vertices of the mesh
910                 long nearest_vidx = -1;
911                 float thres_sq = Mesh::vertex_sel_dist * Mesh::vertex_sel_dist;
912
913                 for(unsigned int i=0; i<nverts; i++) {
914
915                         if((Mesh::intersect_mode & ISECT_FRONT) && dot(narr[i], ray.dir) > 0) {
916                                 continue;
917                         }
918
919                         // project the vertex onto the ray line
920                         float t = dot(varr[i] - ray.origin, ray.dir);
921                         Vec3 vproj = ray.origin + ray.dir * t;
922
923                         float dist_sq = length_sq(vproj - varr[i]);
924                         if(dist_sq < thres_sq) {
925                                 if(!hit) {
926                                         return true;
927                                 }
928                                 if(t < nearest_hit.dist) {
929                                         nearest_hit.dist = t;
930                                         nearest_vidx = i;
931                                 }
932                         }
933                 }
934
935                 if(nearest_vidx != -1) {
936                         hitvert = varr[nearest_vidx];
937                         nearest_hit.obj = &hitvert;
938                 }
939
940         } else {
941                 // regular intersection test with polygons
942
943                 for(unsigned int i=0; i<nfaces; i++) {
944                         Triangle face(i, varr, idxarr);
945
946                         // ignore back-facing polygons if the mode flags include ISECT_FRONT
947                         if((Mesh::intersect_mode & ISECT_FRONT) && dot(face.get_normal(), ray.dir) > 0) {
948                                 continue;
949                         }
950
951                         HitPoint fhit;
952                         if(face.intersect(ray, hit ? &fhit : 0)) {
953                                 if(!hit) {
954                                         return true;
955                                 }
956                                 if(fhit.dist < nearest_hit.dist) {
957                                         nearest_hit = fhit;
958                                         hitface = face;
959                                 }
960                         }
961                 }
962         }
963
964         if(nearest_hit.obj) {
965                 if(hit) {
966                         *hit = nearest_hit;
967
968                         // if we are interested in the mesh and not the faces set obj to this
969                         if(Mesh::intersect_mode & ISECT_FACE) {
970                                 hit->obj = &hitface;
971                         } else if(Mesh::intersect_mode & ISECT_VERTICES) {
972                                 hit->obj = &hitvert;
973                         } else {
974                                 hit->obj = this;
975                         }
976                 }
977                 return true;
978         }
979         return false;
980 }
981
982
983 // texture coordinate manipulation
984 void Mesh::texcoord_apply_xform(const Mat4 &xform)
985 {
986         if(!has_attrib(MESH_ATTR_TEXCOORD)) {
987                 return;
988         }
989
990         for(unsigned int i=0; i<nverts; i++) {
991                 Vec4 tc = get_attrib(MESH_ATTR_TEXCOORD, i);
992                 set_attrib(MESH_ATTR_TEXCOORD, i, xform * tc);
993         }
994 }
995
996 void Mesh::texcoord_gen_plane(const Vec3 &norm, const Vec3 &tang)
997 {
998         if(!nverts) return;
999
1000         if(!has_attrib(MESH_ATTR_TEXCOORD)) {
1001                 // allocate texture coordinate attribute array
1002                 set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts);
1003         }
1004
1005         Vec3 n = normalize(norm);
1006         Vec3 b = normalize(cross(n, tang));
1007         Vec3 t = cross(b, n);
1008
1009         for(unsigned int i=0; i<nverts; i++) {
1010                 Vec3 pos = Vec3(get_attrib(MESH_ATTR_VERTEX, i));
1011
1012                 // distance along the tangent direction
1013                 float u = dot(pos, t);
1014                 // distance along the bitangent direction
1015                 float v = dot(pos, b);
1016
1017                 set_attrib(MESH_ATTR_TEXCOORD, i, Vec4(u, v, 0, 1));
1018         }
1019 }
1020
1021 void Mesh::texcoord_gen_box()
1022 {
1023         if(!nverts || !has_attrib(MESH_ATTR_NORMAL)) return;
1024
1025         if(!has_attrib(MESH_ATTR_TEXCOORD)) {
1026                 // allocate texture coordinate attribute array
1027                 set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts);
1028         }
1029
1030         for(unsigned int i=0; i<nverts; i++) {
1031                 Vec3 pos = Vec3(get_attrib(MESH_ATTR_VERTEX, i)) * 0.5 + Vec3(0.5, 0.5, 0.5);
1032                 Vec3 norm = Vec3(get_attrib(MESH_ATTR_NORMAL, i));
1033
1034                 float abs_nx = fabs(norm.x);
1035                 float abs_ny = fabs(norm.y);
1036                 float abs_nz = fabs(norm.z);
1037                 int dom = abs_nx > abs_ny && abs_nx > abs_nz ? 0 : (abs_ny > abs_nz ? 1 : 2);
1038
1039                 float uv[2], *uvptr = uv;
1040                 for(int j=0; j<3; j++) {
1041                         if(j == dom) continue;  // skip dominant axis
1042
1043                         *uvptr++ = pos[j];
1044                 }
1045                 set_attrib(MESH_ATTR_TEXCOORD, i, Vec4(uv[0], uv[1], 0, 1));
1046         }
1047 }
1048
1049 void Mesh::texcoord_gen_cylinder()
1050 {
1051         if(!nverts) return;
1052
1053         if(!has_attrib(MESH_ATTR_TEXCOORD)) {
1054                 // allocate texture coordinate attribute array
1055                 set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts);
1056         }
1057
1058         for(unsigned int i=0; i<nverts; i++) {
1059                 Vec3 pos = Vec3(get_attrib(MESH_ATTR_VERTEX, i));
1060
1061                 float rho = sqrt(pos.x * pos.x + pos.z * pos.z);
1062                 float theta = rho == 0.0 ? 0.0 : atan2(pos.z / rho, pos.x / rho);
1063
1064                 float u = theta / (2.0 * M_PI) + 0.5;
1065                 float v = pos.y;
1066
1067                 set_attrib(MESH_ATTR_TEXCOORD, i, Vec4(u, v, 0, 1));
1068         }
1069 }
1070
1071
1072 bool Mesh::dump(const char *fname) const
1073 {
1074         FILE *fp = fopen(fname, "wb");
1075         if(fp) {
1076                 bool res = dump(fp);
1077                 fclose(fp);
1078                 return res;
1079         }
1080         return false;
1081 }
1082
1083 bool Mesh::dump(FILE *fp) const
1084 {
1085         if(!has_attrib(MESH_ATTR_VERTEX)) {
1086                 return false;
1087         }
1088
1089         fprintf(fp, "VERTEX ATTRIBUTES\n");
1090         static const char *label[] = { "pos", "nor", "tan", "tex", "col", "bw", "bid" };
1091         static const char *elemfmt[] = { 0, " %s(%g)", " %s(%g, %g)", " %s(%g, %g, %g)", " %s(%g, %g, %g, %g)", 0 };
1092
1093         for(int i=0; i<(int)nverts; i++) {
1094                 fprintf(fp, "%5u:", i);
1095                 for(int j=0; j<NUM_MESH_ATTR; j++) {
1096                         if(has_attrib(j)) {
1097                                 Vec4 v = get_attrib(j, i);
1098                                 int nelem = vattr[j].nelem;
1099                                 fprintf(fp, elemfmt[nelem], label[j], v.x, v.y, v.z, v.w);
1100                         }
1101                 }
1102                 fputc('\n', fp);
1103         }
1104
1105         if(is_indexed()) {
1106                 const unsigned int *idx = get_index_data();
1107                 int numidx = get_index_count();
1108                 int numtri = numidx / 3;
1109                 assert(numidx % 3 == 0);
1110
1111                 fprintf(fp, "FACES\n");
1112
1113                 for(int i=0; i<numtri; i++) {
1114                         fprintf(fp, "%5d: %d %d %d\n", i, idx[0], idx[1], idx[2]);
1115                         idx += 3;
1116                 }
1117         }
1118         return true;
1119 }
1120
1121 bool Mesh::dump_obj(const char *fname) const
1122 {
1123         FILE *fp = fopen(fname, "wb");
1124         if(fp) {
1125                 bool res = dump_obj(fp);
1126                 fclose(fp);
1127                 return res;
1128         }
1129         return false;
1130 }
1131
1132 bool Mesh::dump_obj(FILE *fp) const
1133 {
1134         if(!has_attrib(MESH_ATTR_VERTEX)) {
1135                 return false;
1136         }
1137
1138         for(int i=0; i<(int)nverts; i++) {
1139                 Vec4 v = get_attrib(MESH_ATTR_VERTEX, i);
1140                 fprintf(fp, "v %g %g %g\n", v.x, v.y, v.z);
1141         }
1142
1143         if(has_attrib(MESH_ATTR_NORMAL)) {
1144                 for(int i=0; i<(int)nverts; i++) {
1145                         Vec4 v = get_attrib(MESH_ATTR_NORMAL, i);
1146                         fprintf(fp, "vn %g %g %g\n", v.x, v.y, v.z);
1147                 }
1148         }
1149
1150         if(has_attrib(MESH_ATTR_TEXCOORD)) {
1151                 for(int i=0; i<(int)nverts; i++) {
1152                         Vec4 v = get_attrib(MESH_ATTR_TEXCOORD, i);
1153                         fprintf(fp, "vt %g %g\n", v.x, v.y);
1154                 }
1155         }
1156
1157         if(is_indexed()) {
1158                 const unsigned int *idxptr = get_index_data();
1159                 int numidx = get_index_count();
1160                 int numtri = numidx / 3;
1161                 assert(numidx % 3 == 0);
1162
1163                 for(int i=0; i<numtri; i++) {
1164                         fputc('f', fp);
1165                         for(int j=0; j<3; j++) {
1166                                 unsigned int idx = *idxptr++ + 1;
1167                                 fprintf(fp, " %u/%u/%u", idx, idx, idx);
1168                         }
1169                         fputc('\n', fp);
1170                 }
1171         } else {
1172                 int numtri = nverts / 3;
1173                 unsigned int idx = 1;
1174                 for(int i=0; i<numtri; i++) {
1175                         fputc('f', fp);
1176                         for(int j=0; j<3; j++) {
1177                                 fprintf(fp, " %u/%u/%u", idx, idx, idx);
1178                                 ++idx;
1179                         }
1180                         fputc('\n', fp);
1181                 }
1182         }
1183         return true;
1184 }
1185
1186 // ------ private member functions ------
1187
1188 void Mesh::calc_aabb()
1189 {
1190         // the cast is to force calling the const version which doesn't invalidate
1191         if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
1192                 return;
1193         }
1194
1195         aabb.min = Vec3(FLT_MAX, FLT_MAX, FLT_MAX);
1196         aabb.max = -aabb.min;
1197
1198         for(unsigned int i=0; i<nverts; i++) {
1199                 Vec4 v = get_attrib(MESH_ATTR_VERTEX, i);
1200                 for(int j=0; j<3; j++) {
1201                         if(v[j] < aabb.min[j]) {
1202                                 aabb.min[j] = v[j];
1203                         }
1204                         if(v[j] > aabb.max[j]) {
1205                                 aabb.max[j] = v[j];
1206                         }
1207                 }
1208         }
1209         aabb_valid = true;
1210 }
1211
1212 void Mesh::calc_bsph()
1213 {
1214         // the cast is to force calling the const version which doesn't invalidate
1215         if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
1216                 return;
1217         }
1218
1219         Vec3 v;
1220         bsph.center = Vec3(0, 0, 0);
1221
1222         // first find the center
1223         for(unsigned int i=0; i<nverts; i++) {
1224                 v = Vec3(get_attrib(MESH_ATTR_VERTEX, i));
1225                 bsph.center += v;
1226         }
1227         bsph.center /= (float)nverts;
1228
1229         bsph.radius = 0.0f;
1230         for(unsigned int i=0; i<nverts; i++) {
1231                 v = Vec3(get_attrib(MESH_ATTR_VERTEX, i));
1232                 float dist_sq = length_sq(v - bsph.center);
1233                 if(dist_sq > bsph.radius) {
1234                         bsph.radius = dist_sq;
1235                 }
1236         }
1237         bsph.radius = sqrt(bsph.radius);
1238
1239         bsph_valid = true;
1240 }
1241
1242 void Mesh::update_buffers()
1243 {
1244         for(int i=0; i<NUM_MESH_ATTR; i++) {
1245                 if(has_attrib(i) && !vattr[i].vbo_valid) {
1246                         glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
1247                         glBufferData(GL_ARRAY_BUFFER, nverts * vattr[i].nelem * sizeof(float), &vattr[i].data[0], GL_STATIC_DRAW);
1248                         vattr[i].vbo_valid = true;
1249                 }
1250         }
1251         glBindBuffer(GL_ARRAY_BUFFER, 0);
1252
1253         if(idata_valid && !ibo_valid) {
1254                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
1255                 glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 3 * sizeof(unsigned int), &idata[0], GL_STATIC_DRAW);
1256                 ibo_valid = true;
1257         }
1258         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1259 }
1260
1261 void Mesh::update_wire_ibo()
1262 {
1263         update_buffers();
1264
1265         if(wire_ibo_valid) {
1266                 return;
1267         }
1268
1269         if(!wire_ibo) {
1270                 glGenBuffers(1, &wire_ibo);
1271         }
1272
1273         int num_faces = get_poly_count();
1274
1275         unsigned int *wire_idxarr = new unsigned int[num_faces * 6];
1276         unsigned int *dest = wire_idxarr;
1277
1278         if(ibo_valid) {
1279                 // we're dealing with an indexed mesh
1280                 const unsigned int *idxarr = ((const Mesh*)this)->get_index_data();
1281
1282                 for(int i=0; i<num_faces; i++) {
1283                         *dest++ = idxarr[0];
1284                         *dest++ = idxarr[1];
1285                         *dest++ = idxarr[1];
1286                         *dest++ = idxarr[2];
1287                         *dest++ = idxarr[2];
1288                         *dest++ = idxarr[0];
1289                         idxarr += 3;
1290                 }
1291         } else {
1292                 // not an indexed mesh ...
1293                 for(int i=0; i<num_faces; i++) {
1294                         int vidx = i * 3;
1295                         *dest++ = vidx;
1296                         *dest++ = vidx + 1;
1297                         *dest++ = vidx + 1;
1298                         *dest++ = vidx + 2;
1299                         *dest++ = vidx + 2;
1300                         *dest++ = vidx;
1301                 }
1302         }
1303
1304         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
1305         glBufferData(GL_ELEMENT_ARRAY_BUFFER, num_faces * 6 * sizeof(unsigned int), wire_idxarr, GL_STATIC_DRAW);
1306         delete [] wire_idxarr;
1307         wire_ibo_valid = true;
1308         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1309 }
1310
1311
1312 // ------ class Triangle ------
1313 Triangle::Triangle()
1314 {
1315         normal_valid = false;
1316         id = -1;
1317 }
1318
1319 Triangle::Triangle(const Vec3 &v0, const Vec3 &v1, const Vec3 &v2)
1320 {
1321         v[0] = v0;
1322         v[1] = v1;
1323         v[2] = v2;
1324         normal_valid = false;
1325         id = -1;
1326 }
1327
1328 Triangle::Triangle(int n, const Vec3 *varr, const unsigned int *idxarr)
1329 {
1330         if(idxarr) {
1331                 v[0] = varr[idxarr[n * 3]];
1332                 v[1] = varr[idxarr[n * 3 + 1]];
1333                 v[2] = varr[idxarr[n * 3 + 2]];
1334         } else {
1335                 v[0] = varr[n * 3];
1336                 v[1] = varr[n * 3 + 1];
1337                 v[2] = varr[n * 3 + 2];
1338         }
1339         normal_valid = false;
1340         id = n;
1341 }
1342
1343 void Triangle::calc_normal()
1344 {
1345         normal = normalize(cross(v[1] - v[0], v[2] - v[0]));
1346         normal_valid = true;
1347 }
1348
1349 const Vec3 &Triangle::get_normal() const
1350 {
1351         if(!normal_valid) {
1352                 ((Triangle*)this)->calc_normal();
1353         }
1354         return normal;
1355 }
1356
1357 void Triangle::transform(const Mat4 &xform)
1358 {
1359         v[0] = xform * v[0];
1360         v[1] = xform * v[1];
1361         v[2] = xform * v[2];
1362         normal_valid = false;
1363 }
1364
1365 void Triangle::draw() const
1366 {
1367         Vec3 n[3];
1368         n[0] = n[1] = n[2] = get_normal();
1369
1370         int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
1371         int nloc = Mesh::get_attrib_location(MESH_ATTR_NORMAL);
1372
1373         glEnableVertexAttribArray(vloc);
1374         glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
1375         glVertexAttribPointer(nloc, 3, GL_FLOAT, GL_FALSE, 0, &n[0].x);
1376
1377         glDrawArrays(GL_TRIANGLES, 0, 3);
1378
1379         glDisableVertexAttribArray(vloc);
1380         glDisableVertexAttribArray(nloc);
1381 }
1382
1383 void Triangle::draw_wire() const
1384 {
1385         static const int idxarr[] = {0, 1, 1, 2, 2, 0};
1386         int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
1387
1388         glEnableVertexAttribArray(vloc);
1389         glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
1390
1391         glDrawElements(GL_LINES, 6, GL_UNSIGNED_INT, idxarr);
1392
1393         glDisableVertexAttribArray(vloc);
1394 }
1395
1396 Vec3 Triangle::calc_barycentric(const Vec3 &pos) const
1397 {
1398         Vec3 norm = get_normal();
1399
1400         float area_sq = fabs(dot(cross(v[1] - v[0], v[2] - v[0]), norm));
1401         if(area_sq < 1e-5) {
1402                 return Vec3(0, 0, 0);
1403         }
1404
1405         float asq0 = fabs(dot(cross(v[1] - pos, v[2] - pos), norm));
1406         float asq1 = fabs(dot(cross(v[2] - pos, v[0] - pos), norm));
1407         float asq2 = fabs(dot(cross(v[0] - pos, v[1] - pos), norm));
1408
1409         return Vec3(asq0 / area_sq, asq1 / area_sq, asq2 / area_sq);
1410 }
1411
1412 bool Triangle::intersect(const Ray &ray, HitPoint *hit) const
1413 {
1414         Vec3 normal = get_normal();
1415
1416         float ndotdir = dot(ray.dir, normal);
1417         if(fabs(ndotdir) < 1e-4) {
1418                 return false;
1419         }
1420
1421         Vec3 vertdir = v[0] - ray.origin;
1422         float t = dot(normal, vertdir) / ndotdir;
1423
1424         Vec3 pos = ray.origin + ray.dir * t;
1425         Vec3 bary = calc_barycentric(pos);
1426
1427         if(bary.x + bary.y + bary.z > 1.00001) {
1428                 return false;
1429         }
1430
1431         if(hit) {
1432                 hit->dist = t;
1433                 hit->pos = ray.origin + ray.dir * t;
1434                 hit->normal = normal;
1435                 hit->obj = this;
1436         }
1437         return true;
1438 }