goat3dgfx
view src/mesh.cc @ 10:b4c9a24c946e
wrote an awesome configure script
added "main" 3d engine source file with global init/cleanup
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sun, 24 Nov 2013 13:30:44 +0200 |
parents | |
children | 7d6b667821cf |
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 int Mesh::global_sdr_loc[NUM_MESH_ATTR] = { 0, 1, 2, 3, 4, 5 };
11 unsigned int Mesh::intersect_mode = ISECT_DEFAULT;
12 float Mesh::vertex_sel_dist = 0.01;
13 float Mesh::vis_vecsize = 1.0;
15 Mesh::Mesh()
16 {
17 clear();
19 glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects);
21 for(int i=0; i<NUM_MESH_ATTR; i++) {
22 vattr[i].vbo = buffer_objects[i];
23 }
24 ibo = buffer_objects[NUM_MESH_ATTR];
25 wire_ibo = 0;
26 }
28 Mesh::~Mesh()
29 {
30 glDeleteBuffers(NUM_MESH_ATTR + 1, buffer_objects);
32 if(wire_ibo) {
33 glDeleteBuffers(1, &wire_ibo);
34 }
35 }
37 void Mesh::set_name(const char *name)
38 {
39 this->name = name;
40 }
42 const char *Mesh::get_name() const
43 {
44 return name.c_str();
45 }
47 bool Mesh::has_attrib(int attr) const
48 {
49 if(attr < 0 || attr >= NUM_MESH_ATTR) {
50 return false;
51 }
53 // if neither of these is valid, then nobody has set this attribute
54 return vattr[attr].vbo_valid || vattr[attr].data_valid;
55 }
57 void Mesh::clear()
58 {
59 bones.clear();
61 for(int i=0; i<NUM_MESH_ATTR; i++) {
62 vattr[i].nelem = 0;
63 vattr[i].vbo_valid = false;
64 vattr[i].data_valid = false;
65 //vattr[i].sdr_loc = -1;
66 vattr[i].data.clear();
67 }
68 ibo_valid = false;
69 idata.clear();
71 wire_ibo_valid = false;
73 nverts = nfaces = 0;
75 bsph_valid = false;
76 aabb_valid = false;
77 }
79 float *Mesh::set_attrib_data(int attrib, int nelem, unsigned int num, const float *data)
80 {
81 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
82 error_log("%s: invalid attrib: %d\n", __FUNCTION__, attrib);
83 return 0;
84 }
86 if(nverts && num != nverts) {
87 error_log("%s: attribute count missmatch (%d instead of %d)\n", __FUNCTION__, num, nverts);
88 return 0;
89 }
90 nverts = num;
92 vattr[attrib].data.clear();
93 vattr[attrib].nelem = nelem;
94 vattr[attrib].data.resize(num * nelem);
96 if(data) {
97 memcpy(&vattr[attrib].data[0], data, num * nelem * sizeof *data);
98 }
100 vattr[attrib].data_valid = true;
101 vattr[attrib].vbo_valid = false;
102 return &vattr[attrib].data[0];
103 }
105 float *Mesh::get_attrib_data(int attrib)
106 {
107 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
108 error_log("%s: invalid attrib: %d\n", __FUNCTION__, attrib);
109 return 0;
110 }
112 vattr[attrib].vbo_valid = false;
113 return (float*)((const Mesh*)this)->get_attrib_data(attrib);
114 }
116 const float *Mesh::get_attrib_data(int attrib) const
117 {
118 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
119 error_log("%s: invalid attrib: %d\n", __FUNCTION__, attrib);
120 return 0;
121 }
123 if(!vattr[attrib].data_valid) {
124 #if GL_ES_VERSION_2_0
125 error_log("%s: can't read back attrib data on CrippledGL ES\n", __FUNCTION__);
126 return 0;
127 #else
128 if(!vattr[attrib].vbo_valid) {
129 error_log("%s: unavailable attrib: %d\n", __FUNCTION__, attrib);
130 return 0;
131 }
133 // local data copy is unavailable, grab the data from the vbo
134 Mesh *m = (Mesh*)this;
135 m->vattr[attrib].data.resize(nverts * vattr[attrib].nelem);
137 glBindBuffer(GL_ARRAY_BUFFER, vattr[attrib].vbo);
138 void *data = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
139 memcpy(&m->vattr[attrib].data[0], data, nverts * vattr[attrib].nelem * sizeof(float));
140 glUnmapBuffer(GL_ARRAY_BUFFER);
142 vattr[attrib].data_valid = true;
143 #endif
144 }
146 return &vattr[attrib].data[0];
147 }
149 void Mesh::set_attrib(int attrib, int idx, const Vector4 &v)
150 {
151 float *data = get_attrib_data(attrib);
152 if(data) {
153 data += idx * vattr[attrib].nelem;
154 for(int i=0; i<vattr[attrib].nelem; i++) {
155 data[i] = v[i];
156 }
157 }
158 }
160 Vector4 Mesh::get_attrib(int attrib, int idx) const
161 {
162 Vector4 v(0.0, 0.0, 0.0, 1.0);
163 const float *data = get_attrib_data(attrib);
164 if(data) {
165 data += idx * vattr[attrib].nelem;
166 for(int i=0; i<vattr[attrib].nelem; i++) {
167 v[i] = data[i];
168 }
169 }
170 return v;
171 }
173 unsigned int *Mesh::set_index_data(int num, const unsigned int *indices)
174 {
175 int nidx = nfaces * 3;
176 if(nidx && num != nidx) {
177 error_log("%s: index count missmatch (%d instead of %d)\n", __FUNCTION__, num, nidx);
178 return 0;
179 }
180 nfaces = num / 3;
182 idata.clear();
183 idata.resize(num);
185 if(indices) {
186 memcpy(&idata[0], indices, num * sizeof *indices);
187 }
189 idata_valid = true;
190 ibo_valid = false;
192 return &idata[0];
193 }
195 unsigned int *Mesh::get_index_data()
196 {
197 ibo_valid = false;
198 return (unsigned int*)((const Mesh*)this)->get_index_data();
199 }
201 const unsigned int *Mesh::get_index_data() const
202 {
203 if(!idata_valid) {
204 #if GL_ES_VERSION_2_0
205 error_log("%s: can't read back index data in CrippledGL ES\n", __FUNCTION__);
206 return 0;
207 #else
208 if(!ibo_valid) {
209 error_log("%s: indices unavailable\n", __FUNCTION__);
210 return 0;
211 }
213 // local data copy is unavailable, gram the data from the ibo
214 Mesh *m = (Mesh*)this;
215 int nidx = nfaces * 3;
216 m->idata.resize(nidx);
218 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
219 void *data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY);
220 memcpy(&m->idata[0], data, nidx * sizeof(unsigned int));
221 glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
223 idata_valid = true;
224 #endif
225 }
227 return &idata[0];
228 }
230 void Mesh::append(const Mesh &mesh)
231 {
232 unsigned int idxoffs = nverts;
234 nverts += mesh.nverts;
235 nfaces += mesh.nfaces;
237 for(int i=0; i<NUM_MESH_ATTR; i++) {
238 if(has_attrib(i) && mesh.has_attrib(i)) {
239 // force validating the data arrays
240 get_attrib_data(i);
241 mesh.get_attrib_data(i);
243 // append the mesh data
244 vattr[i].data.insert(vattr[i].data.end(), mesh.vattr[i].data.begin(), mesh.vattr[i].data.end());
245 }
246 }
248 if(ibo_valid || idata_valid) {
249 // make index arrays valid
250 get_index_data();
251 mesh.get_index_data();
253 size_t orig_sz = idata.size();
255 idata.insert(idata.end(), mesh.idata.begin(), mesh.idata.end());
257 // fixup all the new indices
258 for(size_t i=orig_sz; i<idata.size(); i++) {
259 idata[i] += idxoffs;
260 }
261 }
263 // fuck everything
264 wire_ibo_valid = false;
265 aabb_valid = false;
266 bsph_valid = false;
267 }
269 // assemble a complete vertex by adding all the useful attributes
270 void Mesh::vertex(float x, float y, float z)
271 {
272 cur_val[MESH_ATTR_VERTEX] = Vector4(x, y, z, 1.0f);
273 vattr[MESH_ATTR_VERTEX].data_valid = true;
274 vattr[MESH_ATTR_VERTEX].nelem = 3;
276 for(int i=0; i<NUM_MESH_ATTR; i++) {
277 if(vattr[i].data_valid) {
278 for(int j=0; j<vattr[MESH_ATTR_VERTEX].nelem; j++) {
279 vattr[i].data.push_back(cur_val[i][j]);
280 }
281 }
282 vattr[i].vbo_valid = false;
283 }
285 if(idata_valid) {
286 idata.clear();
287 }
288 ibo_valid = idata_valid = false;
289 }
291 void Mesh::normal(float nx, float ny, float nz)
292 {
293 cur_val[MESH_ATTR_NORMAL] = Vector4(nx, ny, nz, 1.0f);
294 vattr[MESH_ATTR_NORMAL].data_valid = true;
295 vattr[MESH_ATTR_NORMAL].nelem = 3;
296 }
298 void Mesh::tangent(float tx, float ty, float tz)
299 {
300 cur_val[MESH_ATTR_TANGENT] = Vector4(tx, ty, tz, 1.0f);
301 vattr[MESH_ATTR_TANGENT].data_valid = true;
302 vattr[MESH_ATTR_TANGENT].nelem = 3;
303 }
305 void Mesh::texcoord(float u, float v, float w)
306 {
307 cur_val[MESH_ATTR_TEXCOORD] = Vector4(u, v, w, 1.0f);
308 vattr[MESH_ATTR_TEXCOORD].data_valid = true;
309 vattr[MESH_ATTR_TEXCOORD].nelem = 3;
310 }
312 void Mesh::boneweights(float w1, float w2, float w3, float w4)
313 {
314 cur_val[MESH_ATTR_BONEWEIGHTS] = Vector4(w1, w2, w3, w4);
315 vattr[MESH_ATTR_BONEWEIGHTS].data_valid = true;
316 vattr[MESH_ATTR_BONEWEIGHTS].nelem = 4;
317 }
319 void Mesh::boneidx(int idx1, int idx2, int idx3, int idx4)
320 {
321 cur_val[MESH_ATTR_BONEIDX] = Vector4(idx1, idx2, idx3, idx4);
322 vattr[MESH_ATTR_BONEIDX].data_valid = true;
323 vattr[MESH_ATTR_BONEIDX].nelem = 4;
324 }
326 /// static function
327 void Mesh::set_attrib_location(int attr, int loc)
328 {
329 if(attr < 0 || attr >= NUM_MESH_ATTR) {
330 return;
331 }
332 Mesh::global_sdr_loc[attr] = loc;
333 }
335 /// static function
336 int Mesh::get_attrib_location(int attr)
337 {
338 if(attr < 0 || attr >= NUM_MESH_ATTR) {
339 return -1;
340 }
341 return Mesh::global_sdr_loc[attr];
342 }
344 /// static function
345 void Mesh::clear_attrib_locations()
346 {
347 for(int i=0; i<NUM_MESH_ATTR; i++) {
348 Mesh::global_sdr_loc[i] = -1;
349 }
350 }
352 /// static function
353 void Mesh::set_vis_vecsize(float sz)
354 {
355 Mesh::vis_vecsize = sz;
356 }
358 float Mesh::get_vis_vecsize()
359 {
360 return Mesh::vis_vecsize;
361 }
363 void Mesh::apply_xform(const Matrix4x4 &xform)
364 {
365 Matrix4x4 dir_xform = xform;
366 dir_xform[0][3] = dir_xform[1][3] = dir_xform[2][3] = 0.0f;
367 dir_xform[3][0] = dir_xform[3][1] = dir_xform[3][2] = 0.0f;
368 dir_xform[3][3] = 1.0f;
370 apply_xform(xform, dir_xform);
371 }
373 void Mesh::apply_xform(const Matrix4x4 &xform, const Matrix4x4 &dir_xform)
374 {
375 for(unsigned int i=0; i<nverts; i++) {
376 Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
377 set_attrib(MESH_ATTR_VERTEX, i, v.transformed(xform));
379 if(has_attrib(MESH_ATTR_NORMAL)) {
380 Vector3 n = get_attrib(MESH_ATTR_NORMAL, i);
381 set_attrib(MESH_ATTR_NORMAL, i, n.transformed(dir_xform));
382 }
383 if(has_attrib(MESH_ATTR_TANGENT)) {
384 Vector3 t = get_attrib(MESH_ATTR_TANGENT, i);
385 set_attrib(MESH_ATTR_TANGENT, i, t.transformed(dir_xform));
386 }
387 }
388 }
390 int Mesh::add_bone(XFormNode *bone)
391 {
392 int idx = bones.size();
393 bones.push_back(bone);
394 return idx;
395 }
397 const XFormNode *Mesh::get_bone(int idx) const
398 {
399 if(idx < 0 || idx >= (int)bones.size()) {
400 return 0;
401 }
402 return bones[idx];
403 }
405 int Mesh::get_bones_count() const
406 {
407 return (int)bones.size();
408 }
410 void Mesh::draw() const
411 {
412 ((Mesh*)this)->update_buffers();
414 if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
415 error_log("%s: invalid vertex buffer\n", __FUNCTION__);
416 return;
417 }
418 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
419 error_log("%s: shader attribute location for vertices unset\n", __FUNCTION__);
420 return;
421 }
423 for(int i=0; i<NUM_MESH_ATTR; i++) {
424 int loc = global_sdr_loc[i];
425 if(loc >= 0 && vattr[i].vbo_valid) {
426 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
427 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
428 glEnableVertexAttribArray(loc);
429 }
430 }
431 glBindBuffer(GL_ARRAY_BUFFER, 0);
433 if(ibo_valid) {
434 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
435 glDrawElements(GL_TRIANGLES, nfaces * 3, GL_UNSIGNED_INT, 0);
436 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
437 } else {
438 glDrawArrays(GL_TRIANGLES, 0, nverts);
439 }
441 for(int i=0; i<NUM_MESH_ATTR; i++) {
442 int loc = global_sdr_loc[i];
443 if(loc >= 0 && vattr[i].vbo_valid) {
444 glDisableVertexAttribArray(loc);
445 }
446 }
447 }
449 void Mesh::draw_wire() const
450 {
451 ((Mesh*)this)->update_wire_ibo();
453 if(!vattr[MESH_ATTR_VERTEX].vbo_valid || !wire_ibo_valid) {
454 error_log("%s: invalid vertex buffer\n", __FUNCTION__);
455 return;
456 }
457 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
458 error_log("%s: shader attribute location for vertices unset\n", __FUNCTION__);
459 return;
460 }
462 for(int i=0; i<NUM_MESH_ATTR; i++) {
463 int loc = global_sdr_loc[i];
464 if(loc >= 0 && vattr[i].vbo_valid) {
465 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
466 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
467 glEnableVertexAttribArray(loc);
468 }
469 }
470 glBindBuffer(GL_ARRAY_BUFFER, 0);
472 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
473 glDrawElements(GL_LINES, nfaces * 6, GL_UNSIGNED_INT, 0);
474 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
476 for(int i=0; i<NUM_MESH_ATTR; i++) {
477 int loc = global_sdr_loc[i];
478 if(loc >= 0 && vattr[i].vbo_valid) {
479 glDisableVertexAttribArray(loc);
480 }
481 }
482 }
484 void Mesh::draw_vertices() const
485 {
486 ((Mesh*)this)->update_buffers();
488 if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
489 error_log("%s: invalid vertex buffer\n", __FUNCTION__);
490 return;
491 }
492 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
493 error_log("%s: shader attribute location for vertices unset\n", __FUNCTION__);
494 return;
495 }
497 for(int i=0; i<NUM_MESH_ATTR; i++) {
498 int loc = global_sdr_loc[i];
499 if(loc >= 0 && vattr[i].vbo_valid) {
500 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
501 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
502 glEnableVertexAttribArray(loc);
503 }
504 }
505 glBindBuffer(GL_ARRAY_BUFFER, 0);
507 glDrawArrays(GL_POINTS, 0, nverts);
509 for(int i=0; i<NUM_MESH_ATTR; i++) {
510 int loc = global_sdr_loc[i];
511 if(loc >= 0 && vattr[i].vbo_valid) {
512 glDisableVertexAttribArray(loc);
513 }
514 }
515 }
517 void Mesh::draw_normals() const
518 {
519 #ifdef USE_OLDGL
520 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
521 Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
522 Vector3 *norm = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
524 if(!varr || !norm || vert_loc < 0) {
525 return;
526 }
528 glBegin(GL_LINES);
529 for(size_t i=0; i<nverts; i++) {
530 glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
531 Vector3 end = varr[i] + norm[i] * vis_vecsize;
532 glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
533 }
534 glEnd();
536 #endif // USE_OLDGL
537 }
539 void Mesh::draw_tangents() const
540 {
541 #ifdef USE_OLDGL
542 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
543 Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
544 Vector3 *tang = (Vector3*)get_attrib_data(MESH_ATTR_TANGENT);
546 if(!varr || !tang || vert_loc < 0) {
547 return;
548 }
550 glBegin(GL_LINES);
551 for(size_t i=0; i<nverts; i++) {
552 glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
553 Vector3 end = varr[i] + tang[i] * vis_vecsize;
554 glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
555 }
556 glEnd();
558 #endif // USE_OLDGL
559 }
561 void Mesh::get_aabbox(Vector3 *vmin, Vector3 *vmax) const
562 {
563 if(!aabb_valid) {
564 ((Mesh*)this)->calc_aabb();
565 }
566 *vmin = aabb.min;
567 *vmax = aabb.max;
568 }
570 const AABox &Mesh::get_aabbox() const
571 {
572 if(!aabb_valid) {
573 ((Mesh*)this)->calc_aabb();
574 }
575 return aabb;
576 }
578 float Mesh::get_bsphere(Vector3 *center, float *rad) const
579 {
580 if(!bsph_valid) {
581 ((Mesh*)this)->calc_bsph();
582 }
583 *center = bsph.center;
584 *rad = bsph.radius;
585 return bsph.radius;
586 }
588 const Sphere &Mesh::get_bsphere() const
589 {
590 if(!bsph_valid) {
591 ((Mesh*)this)->calc_bsph();
592 }
593 return bsph;
594 }
596 /// static function
597 void Mesh::set_intersect_mode(unsigned int mode)
598 {
599 Mesh::intersect_mode = mode;
600 }
602 /// static function
603 unsigned int Mesh::get_intersect_mode()
604 {
605 return Mesh::intersect_mode;
606 }
608 /// static function
609 void Mesh::set_vertex_select_distance(float dist)
610 {
611 Mesh::vertex_sel_dist = dist;
612 }
614 /// static function
615 float Mesh::get_vertex_select_distance()
616 {
617 return Mesh::vertex_sel_dist;
618 }
620 bool Mesh::intersect(const Ray &ray, HitPoint *hit) const
621 {
622 assert((Mesh::intersect_mode & (ISECT_VERTICES | ISECT_FACE)) != (ISECT_VERTICES | ISECT_FACE));
624 const Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
625 const Vector3 *narr = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
626 if(!varr) {
627 return false;
628 }
629 const unsigned int *idxarr = get_index_data();
631 // first test with the bounding box
632 AABox box;
633 get_aabbox(&box.min, &box.max);
634 if(!box.intersect(ray)) {
635 return false;
636 }
638 HitPoint nearest_hit;
639 nearest_hit.dist = FLT_MAX;
640 nearest_hit.obj = 0;
642 if(Mesh::intersect_mode & ISECT_VERTICES) {
643 // we asked for "intersections" with the vertices of the mesh
644 long nearest_vidx = -1;
645 float thres_sq = Mesh::vertex_sel_dist * Mesh::vertex_sel_dist;
647 for(unsigned int i=0; i<nverts; i++) {
649 if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(narr[i], ray.dir) > 0) {
650 continue;
651 }
653 // project the vertex onto the ray line
654 float t = dot_product(varr[i] - ray.origin, ray.dir);
655 Vector3 vproj = ray.origin + ray.dir * t;
657 float dist_sq = (vproj - varr[i]).length_sq();
658 if(dist_sq < thres_sq) {
659 if(!hit) {
660 return true;
661 }
662 if(t < nearest_hit.dist) {
663 nearest_hit.dist = t;
664 nearest_vidx = i;
665 }
666 }
667 }
669 if(nearest_vidx != -1) {
670 hitvert = varr[nearest_vidx];
671 nearest_hit.obj = &hitvert;
672 }
674 } else {
675 // regular intersection test with polygons
677 for(unsigned int i=0; i<nfaces; i++) {
678 Triangle face(i, varr, idxarr);
680 // ignore back-facing polygons if the mode flags include ISECT_FRONT
681 if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(face.get_normal(), ray.dir) > 0) {
682 continue;
683 }
685 HitPoint fhit;
686 if(face.intersect(ray, hit ? &fhit : 0)) {
687 if(!hit) {
688 return true;
689 }
690 if(fhit.dist < nearest_hit.dist) {
691 nearest_hit = fhit;
692 hitface = face;
693 }
694 }
695 }
696 }
698 if(nearest_hit.obj) {
699 if(hit) {
700 *hit = nearest_hit;
702 // if we are interested in the mesh and not the faces set obj to this
703 if(Mesh::intersect_mode & ISECT_FACE) {
704 hit->obj = &hitface;
705 } else if(Mesh::intersect_mode & ISECT_VERTICES) {
706 hit->obj = &hitvert;
707 } else {
708 hit->obj = this;
709 }
710 }
711 return true;
712 }
713 return false;
714 }
717 // ------ private member functions ------
719 void Mesh::calc_aabb()
720 {
721 // the cast is to force calling the const version which doesn't invalidate
722 if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
723 return;
724 }
726 aabb.min = Vector3(FLT_MAX, FLT_MAX, FLT_MAX);
727 aabb.max = -aabb.min;
729 for(unsigned int i=0; i<nverts; i++) {
730 Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
731 for(int j=0; j<3; j++) {
732 if(v[j] < aabb.min[j]) {
733 aabb.min[j] = v[j];
734 }
735 if(v[j] > aabb.max[j]) {
736 aabb.max[j] = v[j];
737 }
738 }
739 }
740 aabb_valid = true;
741 }
743 void Mesh::calc_bsph()
744 {
745 // the cast is to force calling the const version which doesn't invalidate
746 if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
747 return;
748 }
750 Vector3 v;
751 bsph.center = Vector3(0, 0, 0);
753 // first find the center
754 for(unsigned int i=0; i<nverts; i++) {
755 v = get_attrib(MESH_ATTR_VERTEX, i);
756 bsph.center += v;
757 }
758 bsph.center /= (float)nverts;
760 bsph.radius = 0.0f;
761 for(unsigned int i=0; i<nverts; i++) {
762 v = get_attrib(MESH_ATTR_VERTEX, i);
763 float dist_sq = (v - bsph.center).length_sq();
764 if(dist_sq > bsph.radius) {
765 bsph.radius = dist_sq;
766 }
767 }
768 bsph.radius = sqrt(bsph.radius);
770 bsph_valid = true;
771 }
773 void Mesh::update_buffers()
774 {
775 for(int i=0; i<NUM_MESH_ATTR; i++) {
776 if(has_attrib(i) && !vattr[i].vbo_valid) {
777 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
778 glBufferData(GL_ARRAY_BUFFER, nverts * vattr[i].nelem * sizeof(float), &vattr[i].data[0], GL_STATIC_DRAW);
779 vattr[i].vbo_valid = true;
780 }
781 }
782 glBindBuffer(GL_ARRAY_BUFFER, 0);
784 if(idata_valid && !ibo_valid) {
785 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
786 glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 3 * sizeof(unsigned int), &idata[0], GL_STATIC_DRAW);
787 ibo_valid = true;
788 }
789 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
790 }
792 void Mesh::update_wire_ibo()
793 {
794 update_buffers();
796 if(wire_ibo_valid) {
797 return;
798 }
800 if(!wire_ibo) {
801 glGenBuffers(1, &wire_ibo);
802 }
804 unsigned int *wire_idxarr = new unsigned int[nfaces * 6];
805 unsigned int *dest = wire_idxarr;
807 if(ibo_valid) {
808 // we're dealing with an indexed mesh
809 const unsigned int *idxarr = ((const Mesh*)this)->get_index_data();
811 for(unsigned int i=0; i<nfaces; i++) {
812 *dest++ = idxarr[0];
813 *dest++ = idxarr[1];
814 *dest++ = idxarr[1];
815 *dest++ = idxarr[2];
816 *dest++ = idxarr[2];
817 *dest++ = idxarr[0];
818 idxarr += 3;
819 }
820 } else {
821 // not an indexed mesh ...
822 for(unsigned int i=0; i<nfaces; i++) {
823 int vidx = i * 3;
824 *dest++ = vidx;
825 *dest++ = vidx + 1;
826 *dest++ = vidx + 1;
827 *dest++ = vidx + 2;
828 *dest++ = vidx + 2;
829 *dest++ = vidx;
830 }
831 }
833 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
834 glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 6 * sizeof(unsigned int), wire_idxarr, GL_STATIC_DRAW);
835 delete [] wire_idxarr;
836 wire_ibo_valid = true;
837 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
838 }
841 // ------ class Triangle ------
842 Triangle::Triangle()
843 {
844 normal_valid = false;
845 id = -1;
846 }
848 Triangle::Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2)
849 {
850 v[0] = v0;
851 v[1] = v1;
852 v[2] = v2;
853 normal_valid = false;
854 id = -1;
855 }
857 Triangle::Triangle(int n, const Vector3 *varr, const unsigned int *idxarr)
858 {
859 if(idxarr) {
860 v[0] = varr[idxarr[n * 3]];
861 v[1] = varr[idxarr[n * 3 + 1]];
862 v[2] = varr[idxarr[n * 3 + 2]];
863 } else {
864 v[0] = varr[n * 3];
865 v[1] = varr[n * 3 + 1];
866 v[2] = varr[n * 3 + 2];
867 }
868 normal_valid = false;
869 id = n;
870 }
872 void Triangle::calc_normal()
873 {
874 normal = cross_product(v[1] - v[0], v[2] - v[0]).normalized();
875 normal_valid = true;
876 }
878 const Vector3 &Triangle::get_normal() const
879 {
880 if(!normal_valid) {
881 ((Triangle*)this)->calc_normal();
882 }
883 return normal;
884 }
886 void Triangle::transform(const Matrix4x4 &xform)
887 {
888 v[0].transform(xform);
889 v[1].transform(xform);
890 v[2].transform(xform);
891 normal_valid = false;
892 }
894 void Triangle::draw() const
895 {
896 Vector3 n[3];
897 n[0] = get_normal();
898 n[1] = get_normal();
899 n[2] = get_normal();
901 int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
902 int nloc = Mesh::get_attrib_location(MESH_ATTR_NORMAL);
904 glEnableVertexAttribArray(vloc);
905 glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
906 glVertexAttribPointer(nloc, 3, GL_FLOAT, GL_FALSE, 0, &n[0].x);
908 glDrawArrays(GL_TRIANGLES, 0, 3);
910 glDisableVertexAttribArray(vloc);
911 glDisableVertexAttribArray(nloc);
912 CHECKGLERR;
913 }
915 void Triangle::draw_wire() const
916 {
917 static const int idxarr[] = {0, 1, 1, 2, 2, 0};
918 int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
920 glEnableVertexAttribArray(vloc);
921 glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
923 glDrawElements(GL_LINES, 6, GL_UNSIGNED_INT, idxarr);
925 glDisableVertexAttribArray(vloc);
926 CHECKGLERR;
927 }
929 Vector3 Triangle::calc_barycentric(const Vector3 &pos) const
930 {
931 Vector3 norm = get_normal();
933 float area_sq = fabs(dot_product(cross_product(v[1] - v[0], v[2] - v[0]), norm));
934 if(area_sq < 1e-5) {
935 return Vector3(0, 0, 0);
936 }
938 float asq0 = fabs(dot_product(cross_product(v[1] - pos, v[2] - pos), norm));
939 float asq1 = fabs(dot_product(cross_product(v[2] - pos, v[0] - pos), norm));
940 float asq2 = fabs(dot_product(cross_product(v[0] - pos, v[1] - pos), norm));
942 return Vector3(asq0 / area_sq, asq1 / area_sq, asq2 / area_sq);
943 }
945 bool Triangle::intersect(const Ray &ray, HitPoint *hit) const
946 {
947 Vector3 normal = get_normal();
949 float ndotdir = dot_product(ray.dir, normal);
950 if(fabs(ndotdir) < 1e-4) {
951 return false;
952 }
954 Vector3 vertdir = v[0] - ray.origin;
955 float t = dot_product(normal, vertdir) / ndotdir;
957 Vector3 pos = ray.origin + ray.dir * t;
958 Vector3 bary = calc_barycentric(pos);
960 if(bary.x + bary.y + bary.z > 1.00001) {
961 return false;
962 }
964 if(hit) {
965 hit->dist = t;
966 hit->pos = ray.origin + ray.dir * t;
967 hit->normal = normal;
968 hit->obj = this;
969 }
970 return true;
971 }