goat3d

view src/mesh.cc @ 3:31cf61bfd29d

added todo files for tools
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 19 Aug 2013 01:10:33 +0300
parents
children cd71f0b92f44
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 fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
83 return 0;
84 }
86 if(nverts && num != nverts) {
87 fprintf(stderr, "%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 fprintf(stderr, "%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 fprintf(stderr, "%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 fprintf(stderr, "%s: can't read back attrib data on CrippledGL ES\n", __FUNCTION__);
126 return 0;
127 #else
128 if(!vattr[attrib].vbo_valid) {
129 fprintf(stderr, "%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 fprintf(stderr, "%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 fprintf(stderr, "%s: can't read back index data in CrippledGL ES\n", __FUNCTION__);
206 return 0;
207 #else
208 if(!ibo_valid) {
209 fprintf(stderr, "%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 fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
416 return;
417 }
418 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
419 fprintf(stderr, "%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 fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
455 return;
456 }
457 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
458 fprintf(stderr, "%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 fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
490 return;
491 }
492 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
493 fprintf(stderr, "%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 #if 0
562 void Mesh::get_aabbox(Vector3 *vmin, Vector3 *vmax) const
563 {
564 if(!aabb_valid) {
565 ((Mesh*)this)->calc_aabb();
566 }
567 *vmin = aabb.min;
568 *vmax = aabb.max;
569 }
571 const AABox &Mesh::get_aabbox() const
572 {
573 if(!aabb_valid) {
574 ((Mesh*)this)->calc_aabb();
575 }
576 return aabb;
577 }
579 float Mesh::get_bsphere(Vector3 *center, float *rad) const
580 {
581 if(!bsph_valid) {
582 ((Mesh*)this)->calc_bsph();
583 }
584 *center = bsph.center;
585 *rad = bsph.radius;
586 return bsph.radius;
587 }
589 const Sphere &Mesh::get_bsphere() const
590 {
591 if(!bsph_valid) {
592 ((Mesh*)this)->calc_bsph();
593 }
594 return bsph;
595 }
597 /// static function
598 void Mesh::set_intersect_mode(unsigned int mode)
599 {
600 Mesh::intersect_mode = mode;
601 }
603 /// static function
604 unsigned int Mesh::get_intersect_mode()
605 {
606 return Mesh::intersect_mode;
607 }
609 /// static function
610 void Mesh::set_vertex_select_distance(float dist)
611 {
612 Mesh::vertex_sel_dist = dist;
613 }
615 /// static function
616 float Mesh::get_vertex_select_distance()
617 {
618 return Mesh::vertex_sel_dist;
619 }
621 /*bool Mesh::intersect(const Ray &ray, HitPoint *hit) const
622 {
623 assert((Mesh::intersect_mode & (ISECT_VERTICES | ISECT_FACE)) != (ISECT_VERTICES | ISECT_FACE));
625 const Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
626 const Vector3 *narr = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
627 if(!varr) {
628 return false;
629 }
630 const unsigned int *idxarr = get_index_data();
632 // first test with the bounding box
633 AABox box;
634 get_aabbox(&box.min, &box.max);
635 if(!box.intersect(ray)) {
636 return false;
637 }
639 HitPoint nearest_hit;
640 nearest_hit.dist = FLT_MAX;
641 nearest_hit.obj = 0;
643 if(Mesh::intersect_mode & ISECT_VERTICES) {
644 // we asked for "intersections" with the vertices of the mesh
645 long nearest_vidx = -1;
646 float thres_sq = Mesh::vertex_sel_dist * Mesh::vertex_sel_dist;
648 for(unsigned int i=0; i<nverts; i++) {
650 if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(narr[i], ray.dir) > 0) {
651 continue;
652 }
654 // project the vertex onto the ray line
655 float t = dot_product(varr[i] - ray.origin, ray.dir);
656 Vector3 vproj = ray.origin + ray.dir * t;
658 float dist_sq = (vproj - varr[i]).length_sq();
659 if(dist_sq < thres_sq) {
660 if(!hit) {
661 return true;
662 }
663 if(t < nearest_hit.dist) {
664 nearest_hit.dist = t;
665 nearest_vidx = i;
666 }
667 }
668 }
670 if(nearest_vidx != -1) {
671 hitvert = varr[nearest_vidx];
672 nearest_hit.obj = &hitvert;
673 }
675 } else {
676 // regular intersection test with polygons
678 for(unsigned int i=0; i<nfaces; i++) {
679 Triangle face(i, varr, idxarr);
681 // ignore back-facing polygons if the mode flags include ISECT_FRONT
682 if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(face.get_normal(), ray.dir) > 0) {
683 continue;
684 }
686 HitPoint fhit;
687 if(face.intersect(ray, hit ? &fhit : 0)) {
688 if(!hit) {
689 return true;
690 }
691 if(fhit.dist < nearest_hit.dist) {
692 nearest_hit = fhit;
693 hitface = face;
694 }
695 }
696 }
697 }
699 if(nearest_hit.obj) {
700 if(hit) {
701 *hit = nearest_hit;
703 // if we are interested in the mesh and not the faces set obj to this
704 if(Mesh::intersect_mode & ISECT_FACE) {
705 hit->obj = &hitface;
706 } else if(Mesh::intersect_mode & ISECT_VERTICES) {
707 hit->obj = &hitvert;
708 } else {
709 hit->obj = this;
710 }
711 }
712 return true;
713 }
714 return false;
715 }*/
718 // ------ private member functions ------
720 void Mesh::calc_aabb()
721 {
722 // the cast is to force calling the const version which doesn't invalidate
723 if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
724 return;
725 }
727 aabb.min = Vector3(FLT_MAX, FLT_MAX, FLT_MAX);
728 aabb.max = -aabb.min;
730 for(unsigned int i=0; i<nverts; i++) {
731 Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
732 for(int j=0; j<3; j++) {
733 if(v[j] < aabb.min[j]) {
734 aabb.min[j] = v[j];
735 }
736 if(v[j] > aabb.max[j]) {
737 aabb.max[j] = v[j];
738 }
739 }
740 }
741 aabb_valid = true;
742 }
744 void Mesh::calc_bsph()
745 {
746 // the cast is to force calling the const version which doesn't invalidate
747 if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
748 return;
749 }
751 Vector3 v;
752 bsph.center = Vector3(0, 0, 0);
754 // first find the center
755 for(unsigned int i=0; i<nverts; i++) {
756 v = get_attrib(MESH_ATTR_VERTEX, i);
757 bsph.center += v;
758 }
759 bsph.center /= (float)nverts;
761 bsph.radius = 0.0f;
762 for(unsigned int i=0; i<nverts; i++) {
763 v = get_attrib(MESH_ATTR_VERTEX, i);
764 float dist_sq = (v - bsph.center).length_sq();
765 if(dist_sq > bsph.radius) {
766 bsph.radius = dist_sq;
767 }
768 }
769 bsph.radius = sqrt(bsph.radius);
771 bsph_valid = true;
772 }
773 #endif
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 }*/