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