goat3dgfx

view src/mesh.cc @ 16:f61cc1df533c

added viewscn example (under dev)
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 30 Nov 2013 20:53:26 +0200
parents 1873dfd13f2d
children 6f82b9b6d6c3
line source
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 #include "logger.h"
10 using namespace goatgfx;
12 int Mesh::global_sdr_loc[NUM_MESH_ATTR] = { 0, 1, 2, 3, 4, 5 };
13 unsigned int Mesh::intersect_mode = ISECT_DEFAULT;
14 float Mesh::vertex_sel_dist = 0.01;
15 float Mesh::vis_vecsize = 1.0;
17 Mesh::Mesh()
18 {
19 clear();
21 glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects);
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 }
30 Mesh::~Mesh()
31 {
32 glDeleteBuffers(NUM_MESH_ATTR + 1, buffer_objects);
34 if(wire_ibo) {
35 glDeleteBuffers(1, &wire_ibo);
36 }
37 }
39 void Mesh::set_name(const char *name)
40 {
41 this->name = name;
42 }
44 const char *Mesh::get_name() const
45 {
46 return name.c_str();
47 }
49 bool Mesh::has_attrib(int attr) const
50 {
51 if(attr < 0 || attr >= NUM_MESH_ATTR) {
52 return false;
53 }
55 // if neither of these is valid, then nobody has set this attribute
56 return vattr[attr].vbo_valid || vattr[attr].data_valid;
57 }
59 void Mesh::clear()
60 {
61 bones.clear();
63 for(int i=0; i<NUM_MESH_ATTR; i++) {
64 vattr[i].nelem = 0;
65 vattr[i].vbo_valid = false;
66 vattr[i].data_valid = false;
67 //vattr[i].sdr_loc = -1;
68 vattr[i].data.clear();
69 }
70 ibo_valid = false;
71 idata.clear();
73 wire_ibo_valid = false;
75 nverts = nfaces = 0;
77 bsph_valid = false;
78 aabb_valid = false;
79 }
81 float *Mesh::set_attrib_data(int attrib, int nelem, unsigned int num, const float *data)
82 {
83 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
84 error_log("%s: invalid attrib: %d\n", __FUNCTION__, attrib);
85 return 0;
86 }
88 if(nverts && num != nverts) {
89 error_log("%s: attribute count missmatch (%d instead of %d)\n", __FUNCTION__, num, nverts);
90 return 0;
91 }
92 nverts = num;
94 vattr[attrib].data.clear();
95 vattr[attrib].nelem = nelem;
96 vattr[attrib].data.resize(num * nelem);
98 if(data) {
99 memcpy(&vattr[attrib].data[0], data, num * nelem * sizeof *data);
100 }
102 vattr[attrib].data_valid = true;
103 vattr[attrib].vbo_valid = false;
104 return &vattr[attrib].data[0];
105 }
107 float *Mesh::get_attrib_data(int attrib)
108 {
109 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
110 error_log("%s: invalid attrib: %d\n", __FUNCTION__, attrib);
111 return 0;
112 }
114 vattr[attrib].vbo_valid = false;
115 return (float*)((const Mesh*)this)->get_attrib_data(attrib);
116 }
118 const float *Mesh::get_attrib_data(int attrib) const
119 {
120 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
121 error_log("%s: invalid attrib: %d\n", __FUNCTION__, attrib);
122 return 0;
123 }
125 if(!vattr[attrib].data_valid) {
126 #if GL_ES_VERSION_2_0
127 error_log("%s: can't read back attrib data on CrippledGL ES\n", __FUNCTION__);
128 return 0;
129 #else
130 if(!vattr[attrib].vbo_valid) {
131 error_log("%s: unavailable attrib: %d\n", __FUNCTION__, attrib);
132 return 0;
133 }
135 // local data copy is unavailable, grab the data from the vbo
136 Mesh *m = (Mesh*)this;
137 m->vattr[attrib].data.resize(nverts * vattr[attrib].nelem);
139 glBindBuffer(GL_ARRAY_BUFFER, vattr[attrib].vbo);
140 void *data = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
141 memcpy(&m->vattr[attrib].data[0], data, nverts * vattr[attrib].nelem * sizeof(float));
142 glUnmapBuffer(GL_ARRAY_BUFFER);
144 vattr[attrib].data_valid = true;
145 #endif
146 }
148 return &vattr[attrib].data[0];
149 }
151 void Mesh::set_attrib(int attrib, int idx, const Vector4 &v)
152 {
153 float *data = get_attrib_data(attrib);
154 if(data) {
155 data += idx * vattr[attrib].nelem;
156 for(int i=0; i<vattr[attrib].nelem; i++) {
157 data[i] = v[i];
158 }
159 }
160 }
162 Vector4 Mesh::get_attrib(int attrib, int idx) const
163 {
164 Vector4 v(0.0, 0.0, 0.0, 1.0);
165 const float *data = get_attrib_data(attrib);
166 if(data) {
167 data += idx * vattr[attrib].nelem;
168 for(int i=0; i<vattr[attrib].nelem; i++) {
169 v[i] = data[i];
170 }
171 }
172 return v;
173 }
175 unsigned int *Mesh::set_index_data(int num, const unsigned int *indices)
176 {
177 int nidx = nfaces * 3;
178 if(nidx && num != nidx) {
179 error_log("%s: index count missmatch (%d instead of %d)\n", __FUNCTION__, num, nidx);
180 return 0;
181 }
182 nfaces = num / 3;
184 idata.clear();
185 idata.resize(num);
187 if(indices) {
188 memcpy(&idata[0], indices, num * sizeof *indices);
189 }
191 idata_valid = true;
192 ibo_valid = false;
194 return &idata[0];
195 }
197 unsigned int *Mesh::get_index_data()
198 {
199 ibo_valid = false;
200 return (unsigned int*)((const Mesh*)this)->get_index_data();
201 }
203 const unsigned int *Mesh::get_index_data() const
204 {
205 if(!idata_valid) {
206 #if GL_ES_VERSION_2_0
207 error_log("%s: can't read back index data in CrippledGL ES\n", __FUNCTION__);
208 return 0;
209 #else
210 if(!ibo_valid) {
211 error_log("%s: indices unavailable\n", __FUNCTION__);
212 return 0;
213 }
215 // local data copy is unavailable, gram the data from the ibo
216 Mesh *m = (Mesh*)this;
217 int nidx = nfaces * 3;
218 m->idata.resize(nidx);
220 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
221 void *data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY);
222 memcpy(&m->idata[0], data, nidx * sizeof(unsigned int));
223 glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
225 idata_valid = true;
226 #endif
227 }
229 return &idata[0];
230 }
232 void Mesh::append(const Mesh &mesh)
233 {
234 unsigned int idxoffs = nverts;
236 nverts += mesh.nverts;
237 nfaces += mesh.nfaces;
239 for(int i=0; i<NUM_MESH_ATTR; i++) {
240 if(has_attrib(i) && mesh.has_attrib(i)) {
241 // force validating the data arrays
242 get_attrib_data(i);
243 mesh.get_attrib_data(i);
245 // append the mesh data
246 vattr[i].data.insert(vattr[i].data.end(), mesh.vattr[i].data.begin(), mesh.vattr[i].data.end());
247 }
248 }
250 if(ibo_valid || idata_valid) {
251 // make index arrays valid
252 get_index_data();
253 mesh.get_index_data();
255 size_t orig_sz = idata.size();
257 idata.insert(idata.end(), mesh.idata.begin(), mesh.idata.end());
259 // fixup all the new indices
260 for(size_t i=orig_sz; i<idata.size(); i++) {
261 idata[i] += idxoffs;
262 }
263 }
265 // fuck everything
266 wire_ibo_valid = false;
267 aabb_valid = false;
268 bsph_valid = false;
269 }
271 // assemble a complete vertex by adding all the useful attributes
272 void Mesh::vertex(float x, float y, float z)
273 {
274 cur_val[MESH_ATTR_VERTEX] = Vector4(x, y, z, 1.0f);
275 vattr[MESH_ATTR_VERTEX].data_valid = true;
276 vattr[MESH_ATTR_VERTEX].nelem = 3;
278 for(int i=0; i<NUM_MESH_ATTR; i++) {
279 if(vattr[i].data_valid) {
280 for(int j=0; j<vattr[MESH_ATTR_VERTEX].nelem; j++) {
281 vattr[i].data.push_back(cur_val[i][j]);
282 }
283 }
284 vattr[i].vbo_valid = false;
285 }
287 if(idata_valid) {
288 idata.clear();
289 }
290 ibo_valid = idata_valid = false;
291 }
293 void Mesh::normal(float nx, float ny, float nz)
294 {
295 cur_val[MESH_ATTR_NORMAL] = Vector4(nx, ny, nz, 1.0f);
296 vattr[MESH_ATTR_NORMAL].data_valid = true;
297 vattr[MESH_ATTR_NORMAL].nelem = 3;
298 }
300 void Mesh::tangent(float tx, float ty, float tz)
301 {
302 cur_val[MESH_ATTR_TANGENT] = Vector4(tx, ty, tz, 1.0f);
303 vattr[MESH_ATTR_TANGENT].data_valid = true;
304 vattr[MESH_ATTR_TANGENT].nelem = 3;
305 }
307 void Mesh::texcoord(float u, float v, float w)
308 {
309 cur_val[MESH_ATTR_TEXCOORD] = Vector4(u, v, w, 1.0f);
310 vattr[MESH_ATTR_TEXCOORD].data_valid = true;
311 vattr[MESH_ATTR_TEXCOORD].nelem = 3;
312 }
314 void Mesh::boneweights(float w1, float w2, float w3, float w4)
315 {
316 cur_val[MESH_ATTR_BONEWEIGHTS] = Vector4(w1, w2, w3, w4);
317 vattr[MESH_ATTR_BONEWEIGHTS].data_valid = true;
318 vattr[MESH_ATTR_BONEWEIGHTS].nelem = 4;
319 }
321 void Mesh::boneidx(int idx1, int idx2, int idx3, int idx4)
322 {
323 cur_val[MESH_ATTR_BONEIDX] = Vector4(idx1, idx2, idx3, idx4);
324 vattr[MESH_ATTR_BONEIDX].data_valid = true;
325 vattr[MESH_ATTR_BONEIDX].nelem = 4;
326 }
328 /// static function
329 void Mesh::set_attrib_location(int attr, int loc)
330 {
331 if(attr < 0 || attr >= NUM_MESH_ATTR) {
332 return;
333 }
334 Mesh::global_sdr_loc[attr] = loc;
335 }
337 /// static function
338 int Mesh::get_attrib_location(int attr)
339 {
340 if(attr < 0 || attr >= NUM_MESH_ATTR) {
341 return -1;
342 }
343 return Mesh::global_sdr_loc[attr];
344 }
346 /// static function
347 void Mesh::clear_attrib_locations()
348 {
349 for(int i=0; i<NUM_MESH_ATTR; i++) {
350 Mesh::global_sdr_loc[i] = -1;
351 }
352 }
354 /// static function
355 void Mesh::set_vis_vecsize(float sz)
356 {
357 Mesh::vis_vecsize = sz;
358 }
360 float Mesh::get_vis_vecsize()
361 {
362 return Mesh::vis_vecsize;
363 }
365 void Mesh::apply_xform(const Matrix4x4 &xform)
366 {
367 Matrix4x4 dir_xform = xform;
368 dir_xform[0][3] = dir_xform[1][3] = dir_xform[2][3] = 0.0f;
369 dir_xform[3][0] = dir_xform[3][1] = dir_xform[3][2] = 0.0f;
370 dir_xform[3][3] = 1.0f;
372 apply_xform(xform, dir_xform);
373 }
375 void Mesh::apply_xform(const Matrix4x4 &xform, const Matrix4x4 &dir_xform)
376 {
377 for(unsigned int i=0; i<nverts; i++) {
378 Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
379 set_attrib(MESH_ATTR_VERTEX, i, v.transformed(xform));
381 if(has_attrib(MESH_ATTR_NORMAL)) {
382 Vector3 n = get_attrib(MESH_ATTR_NORMAL, i);
383 set_attrib(MESH_ATTR_NORMAL, i, n.transformed(dir_xform));
384 }
385 if(has_attrib(MESH_ATTR_TANGENT)) {
386 Vector3 t = get_attrib(MESH_ATTR_TANGENT, i);
387 set_attrib(MESH_ATTR_TANGENT, i, t.transformed(dir_xform));
388 }
389 }
390 }
392 int Mesh::add_bone(XFormNode *bone)
393 {
394 int idx = bones.size();
395 bones.push_back(bone);
396 return idx;
397 }
399 const XFormNode *Mesh::get_bone(int idx) const
400 {
401 if(idx < 0 || idx >= (int)bones.size()) {
402 return 0;
403 }
404 return bones[idx];
405 }
407 int Mesh::get_bones_count() const
408 {
409 return (int)bones.size();
410 }
412 void Mesh::draw() const
413 {
414 ((Mesh*)this)->update_buffers();
416 if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
417 error_log("%s: invalid vertex buffer\n", __FUNCTION__);
418 return;
419 }
420 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
421 error_log("%s: shader attribute location for vertices unset\n", __FUNCTION__);
422 return;
423 }
425 for(int i=0; i<NUM_MESH_ATTR; i++) {
426 int loc = global_sdr_loc[i];
427 if(loc >= 0 && vattr[i].vbo_valid) {
428 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
429 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
430 glEnableVertexAttribArray(loc);
431 }
432 }
433 glBindBuffer(GL_ARRAY_BUFFER, 0);
435 if(ibo_valid) {
436 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
437 glDrawElements(GL_TRIANGLES, nfaces * 3, GL_UNSIGNED_INT, 0);
438 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
439 } else {
440 glDrawArrays(GL_TRIANGLES, 0, nverts);
441 }
443 for(int i=0; i<NUM_MESH_ATTR; i++) {
444 int loc = global_sdr_loc[i];
445 if(loc >= 0 && vattr[i].vbo_valid) {
446 glDisableVertexAttribArray(loc);
447 }
448 }
449 }
451 void Mesh::draw_wire() const
452 {
453 ((Mesh*)this)->update_wire_ibo();
455 if(!vattr[MESH_ATTR_VERTEX].vbo_valid || !wire_ibo_valid) {
456 error_log("%s: invalid vertex buffer\n", __FUNCTION__);
457 return;
458 }
459 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
460 error_log("%s: shader attribute location for vertices unset\n", __FUNCTION__);
461 return;
462 }
464 for(int i=0; i<NUM_MESH_ATTR; i++) {
465 int loc = global_sdr_loc[i];
466 if(loc >= 0 && vattr[i].vbo_valid) {
467 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
468 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
469 glEnableVertexAttribArray(loc);
470 }
471 }
472 glBindBuffer(GL_ARRAY_BUFFER, 0);
474 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
475 glDrawElements(GL_LINES, nfaces * 6, GL_UNSIGNED_INT, 0);
476 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
478 for(int i=0; i<NUM_MESH_ATTR; i++) {
479 int loc = global_sdr_loc[i];
480 if(loc >= 0 && vattr[i].vbo_valid) {
481 glDisableVertexAttribArray(loc);
482 }
483 }
484 }
486 void Mesh::draw_vertices() const
487 {
488 ((Mesh*)this)->update_buffers();
490 if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
491 error_log("%s: invalid vertex buffer\n", __FUNCTION__);
492 return;
493 }
494 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
495 error_log("%s: shader attribute location for vertices unset\n", __FUNCTION__);
496 return;
497 }
499 for(int i=0; i<NUM_MESH_ATTR; i++) {
500 int loc = global_sdr_loc[i];
501 if(loc >= 0 && vattr[i].vbo_valid) {
502 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
503 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
504 glEnableVertexAttribArray(loc);
505 }
506 }
507 glBindBuffer(GL_ARRAY_BUFFER, 0);
509 glDrawArrays(GL_POINTS, 0, nverts);
511 for(int i=0; i<NUM_MESH_ATTR; i++) {
512 int loc = global_sdr_loc[i];
513 if(loc >= 0 && vattr[i].vbo_valid) {
514 glDisableVertexAttribArray(loc);
515 }
516 }
517 }
519 void Mesh::draw_normals() const
520 {
521 #ifdef USE_OLDGL
522 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
523 Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
524 Vector3 *norm = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
526 if(!varr || !norm || vert_loc < 0) {
527 return;
528 }
530 glBegin(GL_LINES);
531 for(size_t i=0; i<nverts; i++) {
532 glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
533 Vector3 end = varr[i] + norm[i] * vis_vecsize;
534 glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
535 }
536 glEnd();
538 #endif // USE_OLDGL
539 }
541 void Mesh::draw_tangents() const
542 {
543 #ifdef USE_OLDGL
544 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
545 Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
546 Vector3 *tang = (Vector3*)get_attrib_data(MESH_ATTR_TANGENT);
548 if(!varr || !tang || vert_loc < 0) {
549 return;
550 }
552 glBegin(GL_LINES);
553 for(size_t i=0; i<nverts; i++) {
554 glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
555 Vector3 end = varr[i] + tang[i] * vis_vecsize;
556 glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
557 }
558 glEnd();
560 #endif // USE_OLDGL
561 }
563 void Mesh::get_aabbox(Vector3 *vmin, Vector3 *vmax) const
564 {
565 if(!aabb_valid) {
566 ((Mesh*)this)->calc_aabb();
567 }
568 *vmin = aabb.min;
569 *vmax = aabb.max;
570 }
572 const AABox &Mesh::get_aabbox() const
573 {
574 if(!aabb_valid) {
575 ((Mesh*)this)->calc_aabb();
576 }
577 return aabb;
578 }
580 float Mesh::get_bsphere(Vector3 *center, float *rad) const
581 {
582 if(!bsph_valid) {
583 ((Mesh*)this)->calc_bsph();
584 }
585 *center = bsph.center;
586 *rad = bsph.radius;
587 return bsph.radius;
588 }
590 const Sphere &Mesh::get_bsphere() const
591 {
592 if(!bsph_valid) {
593 ((Mesh*)this)->calc_bsph();
594 }
595 return bsph;
596 }
598 /// static function
599 void Mesh::set_intersect_mode(unsigned int mode)
600 {
601 Mesh::intersect_mode = mode;
602 }
604 /// static function
605 unsigned int Mesh::get_intersect_mode()
606 {
607 return Mesh::intersect_mode;
608 }
610 /// static function
611 void Mesh::set_vertex_select_distance(float dist)
612 {
613 Mesh::vertex_sel_dist = dist;
614 }
616 /// static function
617 float Mesh::get_vertex_select_distance()
618 {
619 return Mesh::vertex_sel_dist;
620 }
622 bool Mesh::intersect(const Ray &ray, HitPoint *hit) const
623 {
624 assert((Mesh::intersect_mode & (ISECT_VERTICES | ISECT_FACE)) != (ISECT_VERTICES | ISECT_FACE));
626 const Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
627 const Vector3 *narr = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
628 if(!varr) {
629 return false;
630 }
631 const unsigned int *idxarr = get_index_data();
633 // first test with the bounding box
634 AABox box;
635 get_aabbox(&box.min, &box.max);
636 if(!box.intersect(ray)) {
637 return false;
638 }
640 HitPoint nearest_hit;
641 nearest_hit.dist = FLT_MAX;
642 nearest_hit.obj = 0;
644 if(Mesh::intersect_mode & ISECT_VERTICES) {
645 // we asked for "intersections" with the vertices of the mesh
646 long nearest_vidx = -1;
647 float thres_sq = Mesh::vertex_sel_dist * Mesh::vertex_sel_dist;
649 for(unsigned int i=0; i<nverts; i++) {
651 if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(narr[i], ray.dir) > 0) {
652 continue;
653 }
655 // project the vertex onto the ray line
656 float t = dot_product(varr[i] - ray.origin, ray.dir);
657 Vector3 vproj = ray.origin + ray.dir * t;
659 float dist_sq = (vproj - varr[i]).length_sq();
660 if(dist_sq < thres_sq) {
661 if(!hit) {
662 return true;
663 }
664 if(t < nearest_hit.dist) {
665 nearest_hit.dist = t;
666 nearest_vidx = i;
667 }
668 }
669 }
671 if(nearest_vidx != -1) {
672 hitvert = varr[nearest_vidx];
673 nearest_hit.obj = &hitvert;
674 }
676 } else {
677 // regular intersection test with polygons
679 for(unsigned int i=0; i<nfaces; i++) {
680 Triangle face(i, varr, idxarr);
682 // ignore back-facing polygons if the mode flags include ISECT_FRONT
683 if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(face.get_normal(), ray.dir) > 0) {
684 continue;
685 }
687 HitPoint fhit;
688 if(face.intersect(ray, hit ? &fhit : 0)) {
689 if(!hit) {
690 return true;
691 }
692 if(fhit.dist < nearest_hit.dist) {
693 nearest_hit = fhit;
694 hitface = face;
695 }
696 }
697 }
698 }
700 if(nearest_hit.obj) {
701 if(hit) {
702 *hit = nearest_hit;
704 // if we are interested in the mesh and not the faces set obj to this
705 if(Mesh::intersect_mode & ISECT_FACE) {
706 hit->obj = &hitface;
707 } else if(Mesh::intersect_mode & ISECT_VERTICES) {
708 hit->obj = &hitvert;
709 } else {
710 hit->obj = this;
711 }
712 }
713 return true;
714 }
715 return false;
716 }
719 // ------ private member functions ------
721 void Mesh::calc_aabb()
722 {
723 // the cast is to force calling the const version which doesn't invalidate
724 if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
725 return;
726 }
728 aabb.min = Vector3(FLT_MAX, FLT_MAX, FLT_MAX);
729 aabb.max = -aabb.min;
731 for(unsigned int i=0; i<nverts; i++) {
732 Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
733 for(int j=0; j<3; j++) {
734 if(v[j] < aabb.min[j]) {
735 aabb.min[j] = v[j];
736 }
737 if(v[j] > aabb.max[j]) {
738 aabb.max[j] = v[j];
739 }
740 }
741 }
742 aabb_valid = true;
743 }
745 void Mesh::calc_bsph()
746 {
747 // the cast is to force calling the const version which doesn't invalidate
748 if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
749 return;
750 }
752 Vector3 v;
753 bsph.center = Vector3(0, 0, 0);
755 // first find the center
756 for(unsigned int i=0; i<nverts; i++) {
757 v = get_attrib(MESH_ATTR_VERTEX, i);
758 bsph.center += v;
759 }
760 bsph.center /= (float)nverts;
762 bsph.radius = 0.0f;
763 for(unsigned int i=0; i<nverts; i++) {
764 v = get_attrib(MESH_ATTR_VERTEX, i);
765 float dist_sq = (v - bsph.center).length_sq();
766 if(dist_sq > bsph.radius) {
767 bsph.radius = dist_sq;
768 }
769 }
770 bsph.radius = sqrt(bsph.radius);
772 bsph_valid = true;
773 }
775 void Mesh::update_buffers()
776 {
777 for(int i=0; i<NUM_MESH_ATTR; i++) {
778 if(has_attrib(i) && !vattr[i].vbo_valid) {
779 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
780 glBufferData(GL_ARRAY_BUFFER, nverts * vattr[i].nelem * sizeof(float), &vattr[i].data[0], GL_STATIC_DRAW);
781 vattr[i].vbo_valid = true;
782 }
783 }
784 glBindBuffer(GL_ARRAY_BUFFER, 0);
786 if(idata_valid && !ibo_valid) {
787 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
788 glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 3 * sizeof(unsigned int), &idata[0], GL_STATIC_DRAW);
789 ibo_valid = true;
790 }
791 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
792 }
794 void Mesh::update_wire_ibo()
795 {
796 update_buffers();
798 if(wire_ibo_valid) {
799 return;
800 }
802 if(!wire_ibo) {
803 glGenBuffers(1, &wire_ibo);
804 }
806 unsigned int *wire_idxarr = new unsigned int[nfaces * 6];
807 unsigned int *dest = wire_idxarr;
809 if(ibo_valid) {
810 // we're dealing with an indexed mesh
811 const unsigned int *idxarr = ((const Mesh*)this)->get_index_data();
813 for(unsigned int i=0; i<nfaces; i++) {
814 *dest++ = idxarr[0];
815 *dest++ = idxarr[1];
816 *dest++ = idxarr[1];
817 *dest++ = idxarr[2];
818 *dest++ = idxarr[2];
819 *dest++ = idxarr[0];
820 idxarr += 3;
821 }
822 } else {
823 // not an indexed mesh ...
824 for(unsigned int i=0; i<nfaces; i++) {
825 int vidx = i * 3;
826 *dest++ = vidx;
827 *dest++ = vidx + 1;
828 *dest++ = vidx + 1;
829 *dest++ = vidx + 2;
830 *dest++ = vidx + 2;
831 *dest++ = vidx;
832 }
833 }
835 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
836 glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 6 * sizeof(unsigned int), wire_idxarr, GL_STATIC_DRAW);
837 delete [] wire_idxarr;
838 wire_ibo_valid = true;
839 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
840 }
843 // ------ class Triangle ------
844 Triangle::Triangle()
845 {
846 normal_valid = false;
847 id = -1;
848 }
850 Triangle::Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2)
851 {
852 v[0] = v0;
853 v[1] = v1;
854 v[2] = v2;
855 normal_valid = false;
856 id = -1;
857 }
859 Triangle::Triangle(int n, const Vector3 *varr, const unsigned int *idxarr)
860 {
861 if(idxarr) {
862 v[0] = varr[idxarr[n * 3]];
863 v[1] = varr[idxarr[n * 3 + 1]];
864 v[2] = varr[idxarr[n * 3 + 2]];
865 } else {
866 v[0] = varr[n * 3];
867 v[1] = varr[n * 3 + 1];
868 v[2] = varr[n * 3 + 2];
869 }
870 normal_valid = false;
871 id = n;
872 }
874 void Triangle::calc_normal()
875 {
876 normal = cross_product(v[1] - v[0], v[2] - v[0]).normalized();
877 normal_valid = true;
878 }
880 const Vector3 &Triangle::get_normal() const
881 {
882 if(!normal_valid) {
883 ((Triangle*)this)->calc_normal();
884 }
885 return normal;
886 }
888 void Triangle::transform(const Matrix4x4 &xform)
889 {
890 v[0].transform(xform);
891 v[1].transform(xform);
892 v[2].transform(xform);
893 normal_valid = false;
894 }
896 void Triangle::draw() const
897 {
898 Vector3 n[3];
899 n[0] = get_normal();
900 n[1] = get_normal();
901 n[2] = get_normal();
903 int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
904 int nloc = Mesh::get_attrib_location(MESH_ATTR_NORMAL);
906 glEnableVertexAttribArray(vloc);
907 glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
908 glVertexAttribPointer(nloc, 3, GL_FLOAT, GL_FALSE, 0, &n[0].x);
910 glDrawArrays(GL_TRIANGLES, 0, 3);
912 glDisableVertexAttribArray(vloc);
913 glDisableVertexAttribArray(nloc);
914 CHECKGLERR;
915 }
917 void Triangle::draw_wire() const
918 {
919 static const int idxarr[] = {0, 1, 1, 2, 2, 0};
920 int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
922 glEnableVertexAttribArray(vloc);
923 glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
925 glDrawElements(GL_LINES, 6, GL_UNSIGNED_INT, idxarr);
927 glDisableVertexAttribArray(vloc);
928 CHECKGLERR;
929 }
931 Vector3 Triangle::calc_barycentric(const Vector3 &pos) const
932 {
933 Vector3 norm = get_normal();
935 float area_sq = fabs(dot_product(cross_product(v[1] - v[0], v[2] - v[0]), norm));
936 if(area_sq < 1e-5) {
937 return Vector3(0, 0, 0);
938 }
940 float asq0 = fabs(dot_product(cross_product(v[1] - pos, v[2] - pos), norm));
941 float asq1 = fabs(dot_product(cross_product(v[2] - pos, v[0] - pos), norm));
942 float asq2 = fabs(dot_product(cross_product(v[0] - pos, v[1] - pos), norm));
944 return Vector3(asq0 / area_sq, asq1 / area_sq, asq2 / area_sq);
945 }
947 bool Triangle::intersect(const Ray &ray, HitPoint *hit) const
948 {
949 Vector3 normal = get_normal();
951 float ndotdir = dot_product(ray.dir, normal);
952 if(fabs(ndotdir) < 1e-4) {
953 return false;
954 }
956 Vector3 vertdir = v[0] - ray.origin;
957 float t = dot_product(normal, vertdir) / ndotdir;
959 Vector3 pos = ray.origin + ray.dir * t;
960 Vector3 bary = calc_barycentric(pos);
962 if(bary.x + bary.y + bary.z > 1.00001) {
963 return false;
964 }
966 if(hit) {
967 hit->dist = t;
968 hit->pos = ray.origin + ray.dir * t;
969 hit->normal = normal;
970 hit->obj = this;
971 }
972 return true;
973 }