goat3dgfx
view src/mesh.cc @ 21:7c593721547f
integrated support for the multiple animation system of libanim
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Fri, 27 Dec 2013 11:59:32 +0200 |
parents | 6f82b9b6d6c3 |
children |
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 "shader.h"
9 #include "logger.h"
11 using namespace goatgfx;
13 int Mesh::global_sdr_loc[NUM_MESH_ATTR] = { 0, 1, 2, 3, 4, 5 };
14 unsigned int Mesh::intersect_mode = ISECT_DEFAULT;
15 float Mesh::vertex_sel_dist = 0.01;
16 float Mesh::vis_vecsize = 1.0;
18 Mesh::Mesh()
19 {
20 clear();
22 glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects);
24 for(int i=0; i<NUM_MESH_ATTR; i++) {
25 vattr[i].vbo = buffer_objects[i];
26 }
27 ibo = buffer_objects[NUM_MESH_ATTR];
28 wire_ibo = 0;
29 }
31 Mesh::~Mesh()
32 {
33 glDeleteBuffers(NUM_MESH_ATTR + 1, buffer_objects);
35 if(wire_ibo) {
36 glDeleteBuffers(1, &wire_ibo);
37 }
38 }
40 void Mesh::set_name(const char *name)
41 {
42 this->name = name;
43 }
45 const char *Mesh::get_name() const
46 {
47 return name.c_str();
48 }
50 bool Mesh::has_attrib(int attr) const
51 {
52 if(attr < 0 || attr >= NUM_MESH_ATTR) {
53 return false;
54 }
56 // if neither of these is valid, then nobody has set this attribute
57 return vattr[attr].vbo_valid || vattr[attr].data_valid;
58 }
60 void Mesh::clear()
61 {
62 bones.clear();
64 for(int i=0; i<NUM_MESH_ATTR; i++) {
65 vattr[i].nelem = 0;
66 vattr[i].vbo_valid = false;
67 vattr[i].data_valid = false;
68 //vattr[i].sdr_loc = -1;
69 vattr[i].data.clear();
70 }
71 ibo_valid = idata_valid = false;
72 idata.clear();
74 wire_ibo_valid = false;
76 nverts = nfaces = 0;
78 bsph_valid = false;
79 aabb_valid = false;
80 }
82 float *Mesh::set_attrib_data(int attrib, int nelem, unsigned int num, const float *data)
83 {
84 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
85 error_log("%s: invalid attrib: %d\n", __FUNCTION__, attrib);
86 return 0;
87 }
89 if(nverts && num != nverts) {
90 error_log("%s: attribute count missmatch (%d instead of %d)\n", __FUNCTION__, num, nverts);
91 return 0;
92 }
93 nverts = num;
95 vattr[attrib].data.clear();
96 vattr[attrib].nelem = nelem;
97 vattr[attrib].data.resize(num * nelem);
99 if(data) {
100 memcpy(&vattr[attrib].data[0], data, num * nelem * sizeof *data);
101 }
103 vattr[attrib].data_valid = true;
104 vattr[attrib].vbo_valid = false;
105 return &vattr[attrib].data[0];
106 }
108 float *Mesh::get_attrib_data(int attrib)
109 {
110 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
111 error_log("%s: invalid attrib: %d\n", __FUNCTION__, attrib);
112 return 0;
113 }
115 vattr[attrib].vbo_valid = false;
116 return (float*)((const Mesh*)this)->get_attrib_data(attrib);
117 }
119 const float *Mesh::get_attrib_data(int attrib) const
120 {
121 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
122 error_log("%s: invalid attrib: %d\n", __FUNCTION__, attrib);
123 return 0;
124 }
126 if(!vattr[attrib].data_valid) {
127 #if GL_ES_VERSION_2_0
128 error_log("%s: can't read back attrib data on CrippledGL ES\n", __FUNCTION__);
129 return 0;
130 #else
131 if(!vattr[attrib].vbo_valid) {
132 error_log("%s: unavailable attrib: %d\n", __FUNCTION__, attrib);
133 return 0;
134 }
136 // local data copy is unavailable, grab the data from the vbo
137 Mesh *m = (Mesh*)this;
138 m->vattr[attrib].data.resize(nverts * vattr[attrib].nelem);
140 glBindBuffer(GL_ARRAY_BUFFER, vattr[attrib].vbo);
141 void *data = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
142 memcpy(&m->vattr[attrib].data[0], data, nverts * vattr[attrib].nelem * sizeof(float));
143 glUnmapBuffer(GL_ARRAY_BUFFER);
145 vattr[attrib].data_valid = true;
146 #endif
147 }
149 return &vattr[attrib].data[0];
150 }
152 void Mesh::set_attrib(int attrib, int idx, const Vector4 &v)
153 {
154 float *data = get_attrib_data(attrib);
155 if(data) {
156 data += idx * vattr[attrib].nelem;
157 for(int i=0; i<vattr[attrib].nelem; i++) {
158 data[i] = v[i];
159 }
160 }
161 }
163 Vector4 Mesh::get_attrib(int attrib, int idx) const
164 {
165 Vector4 v(0.0, 0.0, 0.0, 1.0);
166 const float *data = get_attrib_data(attrib);
167 if(data) {
168 data += idx * vattr[attrib].nelem;
169 for(int i=0; i<vattr[attrib].nelem; i++) {
170 v[i] = data[i];
171 }
172 }
173 return v;
174 }
176 unsigned int *Mesh::set_index_data(int num, const unsigned int *indices)
177 {
178 int nidx = nfaces * 3;
179 if(nidx && num != nidx) {
180 error_log("%s: index count missmatch (%d instead of %d)\n", __FUNCTION__, num, nidx);
181 return 0;
182 }
183 nfaces = num / 3;
185 idata.clear();
186 idata.resize(num);
188 if(indices) {
189 memcpy(&idata[0], indices, num * sizeof *indices);
190 }
192 idata_valid = true;
193 ibo_valid = false;
195 return &idata[0];
196 }
198 unsigned int *Mesh::get_index_data()
199 {
200 ibo_valid = false;
201 return (unsigned int*)((const Mesh*)this)->get_index_data();
202 }
204 const unsigned int *Mesh::get_index_data() const
205 {
206 if(!idata_valid) {
207 #if GL_ES_VERSION_2_0
208 error_log("%s: can't read back index data in CrippledGL ES\n", __FUNCTION__);
209 return 0;
210 #else
211 if(!ibo_valid) {
212 error_log("%s: indices unavailable\n", __FUNCTION__);
213 return 0;
214 }
216 // local data copy is unavailable, gram the data from the ibo
217 Mesh *m = (Mesh*)this;
218 int nidx = nfaces * 3;
219 m->idata.resize(nidx);
221 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
222 void *data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY);
223 memcpy(&m->idata[0], data, nidx * sizeof(unsigned int));
224 glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
226 idata_valid = true;
227 #endif
228 }
230 return &idata[0];
231 }
233 void Mesh::append(const Mesh &mesh)
234 {
235 unsigned int idxoffs = nverts;
237 nverts += mesh.nverts;
238 nfaces += mesh.nfaces;
240 for(int i=0; i<NUM_MESH_ATTR; i++) {
241 if(has_attrib(i) && mesh.has_attrib(i)) {
242 // force validating the data arrays
243 get_attrib_data(i);
244 mesh.get_attrib_data(i);
246 // append the mesh data
247 vattr[i].data.insert(vattr[i].data.end(), mesh.vattr[i].data.begin(), mesh.vattr[i].data.end());
248 }
249 }
251 if(ibo_valid || idata_valid) {
252 // make index arrays valid
253 get_index_data();
254 mesh.get_index_data();
256 size_t orig_sz = idata.size();
258 idata.insert(idata.end(), mesh.idata.begin(), mesh.idata.end());
260 // fixup all the new indices
261 for(size_t i=orig_sz; i<idata.size(); i++) {
262 idata[i] += idxoffs;
263 }
264 }
266 // fuck everything
267 wire_ibo_valid = false;
268 aabb_valid = false;
269 bsph_valid = false;
270 }
272 // assemble a complete vertex by adding all the useful attributes
273 void Mesh::vertex(float x, float y, float z)
274 {
275 cur_val[MESH_ATTR_VERTEX] = Vector4(x, y, z, 1.0f);
276 vattr[MESH_ATTR_VERTEX].data_valid = true;
277 vattr[MESH_ATTR_VERTEX].nelem = 3;
279 for(int i=0; i<NUM_MESH_ATTR; i++) {
280 if(vattr[i].data_valid) {
281 for(int j=0; j<vattr[MESH_ATTR_VERTEX].nelem; j++) {
282 vattr[i].data.push_back(cur_val[i][j]);
283 }
284 }
285 vattr[i].vbo_valid = false;
286 }
288 if(idata_valid) {
289 idata.clear();
290 }
291 ibo_valid = idata_valid = false;
292 }
294 void Mesh::normal(float nx, float ny, float nz)
295 {
296 cur_val[MESH_ATTR_NORMAL] = Vector4(nx, ny, nz, 1.0f);
297 vattr[MESH_ATTR_NORMAL].data_valid = true;
298 vattr[MESH_ATTR_NORMAL].nelem = 3;
299 }
301 void Mesh::tangent(float tx, float ty, float tz)
302 {
303 cur_val[MESH_ATTR_TANGENT] = Vector4(tx, ty, tz, 1.0f);
304 vattr[MESH_ATTR_TANGENT].data_valid = true;
305 vattr[MESH_ATTR_TANGENT].nelem = 3;
306 }
308 void Mesh::texcoord(float u, float v, float w)
309 {
310 cur_val[MESH_ATTR_TEXCOORD] = Vector4(u, v, w, 1.0f);
311 vattr[MESH_ATTR_TEXCOORD].data_valid = true;
312 vattr[MESH_ATTR_TEXCOORD].nelem = 3;
313 }
315 void Mesh::boneweights(float w1, float w2, float w3, float w4)
316 {
317 cur_val[MESH_ATTR_BONEWEIGHTS] = Vector4(w1, w2, w3, w4);
318 vattr[MESH_ATTR_BONEWEIGHTS].data_valid = true;
319 vattr[MESH_ATTR_BONEWEIGHTS].nelem = 4;
320 }
322 void Mesh::boneidx(int idx1, int idx2, int idx3, int idx4)
323 {
324 cur_val[MESH_ATTR_BONEIDX] = Vector4(idx1, idx2, idx3, idx4);
325 vattr[MESH_ATTR_BONEIDX].data_valid = true;
326 vattr[MESH_ATTR_BONEIDX].nelem = 4;
327 }
329 /// static function
330 void Mesh::set_attrib_location(int attr, int loc)
331 {
332 if(attr < 0 || attr >= NUM_MESH_ATTR) {
333 return;
334 }
335 Mesh::global_sdr_loc[attr] = loc;
336 }
338 /// static function
339 int Mesh::get_attrib_location(int attr)
340 {
341 if(attr < 0 || attr >= NUM_MESH_ATTR) {
342 return -1;
343 }
344 return Mesh::global_sdr_loc[attr];
345 }
347 /// static function
348 void Mesh::clear_attrib_locations()
349 {
350 for(int i=0; i<NUM_MESH_ATTR; i++) {
351 Mesh::global_sdr_loc[i] = -1;
352 }
353 }
355 /// static function
356 void Mesh::set_vis_vecsize(float sz)
357 {
358 Mesh::vis_vecsize = sz;
359 }
361 float Mesh::get_vis_vecsize()
362 {
363 return Mesh::vis_vecsize;
364 }
366 void Mesh::apply_xform(const Matrix4x4 &xform)
367 {
368 Matrix4x4 dir_xform = xform;
369 dir_xform[0][3] = dir_xform[1][3] = dir_xform[2][3] = 0.0f;
370 dir_xform[3][0] = dir_xform[3][1] = dir_xform[3][2] = 0.0f;
371 dir_xform[3][3] = 1.0f;
373 apply_xform(xform, dir_xform);
374 }
376 void Mesh::apply_xform(const Matrix4x4 &xform, const Matrix4x4 &dir_xform)
377 {
378 for(unsigned int i=0; i<nverts; i++) {
379 Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
380 set_attrib(MESH_ATTR_VERTEX, i, v.transformed(xform));
382 if(has_attrib(MESH_ATTR_NORMAL)) {
383 Vector3 n = get_attrib(MESH_ATTR_NORMAL, i);
384 set_attrib(MESH_ATTR_NORMAL, i, n.transformed(dir_xform));
385 }
386 if(has_attrib(MESH_ATTR_TANGENT)) {
387 Vector3 t = get_attrib(MESH_ATTR_TANGENT, i);
388 set_attrib(MESH_ATTR_TANGENT, i, t.transformed(dir_xform));
389 }
390 }
391 }
393 int Mesh::add_bone(XFormNode *bone)
394 {
395 int idx = bones.size();
396 bones.push_back(bone);
397 return idx;
398 }
400 const XFormNode *Mesh::get_bone(int idx) const
401 {
402 if(idx < 0 || idx >= (int)bones.size()) {
403 return 0;
404 }
405 return bones[idx];
406 }
408 int Mesh::get_bones_count() const
409 {
410 return (int)bones.size();
411 }
413 void Mesh::draw() const
414 {
415 const ShaderProg *cur_sdr = get_current_shader();
416 #ifdef GL_ES_VERSION_2_0
417 if(!cur_sdr) {
418 error_log("%s: CrippledGL ES can't draw without a shader\n", __FUNCTION__);
419 return;
420 }
421 #endif
423 ((Mesh*)this)->update_buffers();
425 if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
426 error_log("%s: invalid vertex buffer\n", __FUNCTION__);
427 return;
428 }
430 if(cur_sdr) {
431 // rendering with shaders
432 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
433 error_log("%s: shader attribute location for vertices unset\n", __FUNCTION__);
434 return;
435 }
437 for(int i=0; i<NUM_MESH_ATTR; i++) {
438 int loc = global_sdr_loc[i];
439 if(loc >= 0 && vattr[i].vbo_valid) {
440 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
441 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
442 glEnableVertexAttribArray(loc);
443 }
444 }
445 } else {
446 #ifndef GL_ES_VERSION_2_0
447 // rendering with fixed-function (not available in GLES2)
448 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_VERTEX].vbo);
449 glVertexPointer(vattr[MESH_ATTR_VERTEX].nelem, GL_FLOAT, 0, 0);
450 glEnableClientState(GL_VERTEX_ARRAY);
452 if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
453 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_NORMAL].vbo);
454 glNormalPointer(GL_FLOAT, 0, 0);
455 glEnableClientState(GL_NORMAL_ARRAY);
456 }
457 if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
458 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_TEXCOORD].vbo);
459 glTexCoordPointer(vattr[MESH_ATTR_TEXCOORD].nelem, GL_FLOAT, 0, 0);
460 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
461 }
462 if(vattr[MESH_ATTR_COLOR].vbo_valid) {
463 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_COLOR].vbo);
464 glColorPointer(vattr[MESH_ATTR_COLOR].nelem, GL_FLOAT, 0, 0);
465 glEnableClientState(GL_COLOR_ARRAY);
466 }
467 #endif
468 }
469 glBindBuffer(GL_ARRAY_BUFFER, 0);
471 if(ibo_valid) {
472 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
473 glDrawElements(GL_TRIANGLES, nfaces * 3, GL_UNSIGNED_INT, 0);
474 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
475 } else {
476 glDrawArrays(GL_TRIANGLES, 0, nverts);
477 }
479 if(cur_sdr) {
480 // rendered with shaders
481 for(int i=0; i<NUM_MESH_ATTR; i++) {
482 int loc = global_sdr_loc[i];
483 if(loc >= 0 && vattr[i].vbo_valid) {
484 glDisableVertexAttribArray(loc);
485 }
486 }
487 } else {
488 #ifndef GL_ES_VERSION_2_0
489 // rendered with fixed-function
490 glDisableClientState(GL_VERTEX_ARRAY);
491 if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
492 glDisableClientState(GL_NORMAL_ARRAY);
493 }
494 if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
495 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
496 }
497 if(vattr[MESH_ATTR_COLOR].vbo_valid) {
498 glDisableClientState(GL_COLOR_ARRAY);
499 }
500 #endif
501 }
502 }
504 void Mesh::draw_wire() const
505 {
506 ((Mesh*)this)->update_wire_ibo();
508 if(!vattr[MESH_ATTR_VERTEX].vbo_valid || !wire_ibo_valid) {
509 error_log("%s: invalid vertex buffer\n", __FUNCTION__);
510 return;
511 }
512 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
513 error_log("%s: shader attribute location for vertices unset\n", __FUNCTION__);
514 return;
515 }
517 for(int i=0; i<NUM_MESH_ATTR; i++) {
518 int loc = global_sdr_loc[i];
519 if(loc >= 0 && vattr[i].vbo_valid) {
520 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
521 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
522 glEnableVertexAttribArray(loc);
523 }
524 }
525 glBindBuffer(GL_ARRAY_BUFFER, 0);
527 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
528 glDrawElements(GL_LINES, nfaces * 6, GL_UNSIGNED_INT, 0);
529 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
531 for(int i=0; i<NUM_MESH_ATTR; i++) {
532 int loc = global_sdr_loc[i];
533 if(loc >= 0 && vattr[i].vbo_valid) {
534 glDisableVertexAttribArray(loc);
535 }
536 }
537 }
539 void Mesh::draw_vertices() const
540 {
541 ((Mesh*)this)->update_buffers();
543 if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
544 error_log("%s: invalid vertex buffer\n", __FUNCTION__);
545 return;
546 }
547 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
548 error_log("%s: shader attribute location for vertices unset\n", __FUNCTION__);
549 return;
550 }
552 for(int i=0; i<NUM_MESH_ATTR; i++) {
553 int loc = global_sdr_loc[i];
554 if(loc >= 0 && vattr[i].vbo_valid) {
555 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
556 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
557 glEnableVertexAttribArray(loc);
558 }
559 }
560 glBindBuffer(GL_ARRAY_BUFFER, 0);
562 glDrawArrays(GL_POINTS, 0, nverts);
564 for(int i=0; i<NUM_MESH_ATTR; i++) {
565 int loc = global_sdr_loc[i];
566 if(loc >= 0 && vattr[i].vbo_valid) {
567 glDisableVertexAttribArray(loc);
568 }
569 }
570 }
572 void Mesh::draw_normals() const
573 {
574 #ifdef USE_OLDGL
575 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
576 Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
577 Vector3 *norm = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
579 if(!varr || !norm || vert_loc < 0) {
580 return;
581 }
583 glBegin(GL_LINES);
584 for(size_t i=0; i<nverts; i++) {
585 glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
586 Vector3 end = varr[i] + norm[i] * vis_vecsize;
587 glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
588 }
589 glEnd();
591 #endif // USE_OLDGL
592 }
594 void Mesh::draw_tangents() const
595 {
596 #ifdef USE_OLDGL
597 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
598 Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
599 Vector3 *tang = (Vector3*)get_attrib_data(MESH_ATTR_TANGENT);
601 if(!varr || !tang || vert_loc < 0) {
602 return;
603 }
605 glBegin(GL_LINES);
606 for(size_t i=0; i<nverts; i++) {
607 glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
608 Vector3 end = varr[i] + tang[i] * vis_vecsize;
609 glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
610 }
611 glEnd();
613 #endif // USE_OLDGL
614 }
616 void Mesh::get_aabbox(Vector3 *vmin, Vector3 *vmax) const
617 {
618 if(!aabb_valid) {
619 ((Mesh*)this)->calc_aabb();
620 }
621 *vmin = aabb.min;
622 *vmax = aabb.max;
623 }
625 const AABox &Mesh::get_aabbox() const
626 {
627 if(!aabb_valid) {
628 ((Mesh*)this)->calc_aabb();
629 }
630 return aabb;
631 }
633 float Mesh::get_bsphere(Vector3 *center, float *rad) const
634 {
635 if(!bsph_valid) {
636 ((Mesh*)this)->calc_bsph();
637 }
638 *center = bsph.center;
639 *rad = bsph.radius;
640 return bsph.radius;
641 }
643 const Sphere &Mesh::get_bsphere() const
644 {
645 if(!bsph_valid) {
646 ((Mesh*)this)->calc_bsph();
647 }
648 return bsph;
649 }
651 /// static function
652 void Mesh::set_intersect_mode(unsigned int mode)
653 {
654 Mesh::intersect_mode = mode;
655 }
657 /// static function
658 unsigned int Mesh::get_intersect_mode()
659 {
660 return Mesh::intersect_mode;
661 }
663 /// static function
664 void Mesh::set_vertex_select_distance(float dist)
665 {
666 Mesh::vertex_sel_dist = dist;
667 }
669 /// static function
670 float Mesh::get_vertex_select_distance()
671 {
672 return Mesh::vertex_sel_dist;
673 }
675 bool Mesh::intersect(const Ray &ray, HitPoint *hit) const
676 {
677 assert((Mesh::intersect_mode & (ISECT_VERTICES | ISECT_FACE)) != (ISECT_VERTICES | ISECT_FACE));
679 const Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
680 const Vector3 *narr = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
681 if(!varr) {
682 return false;
683 }
684 const unsigned int *idxarr = get_index_data();
686 // first test with the bounding box
687 AABox box;
688 get_aabbox(&box.min, &box.max);
689 if(!box.intersect(ray)) {
690 return false;
691 }
693 HitPoint nearest_hit;
694 nearest_hit.dist = FLT_MAX;
695 nearest_hit.obj = 0;
697 if(Mesh::intersect_mode & ISECT_VERTICES) {
698 // we asked for "intersections" with the vertices of the mesh
699 long nearest_vidx = -1;
700 float thres_sq = Mesh::vertex_sel_dist * Mesh::vertex_sel_dist;
702 for(unsigned int i=0; i<nverts; i++) {
704 if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(narr[i], ray.dir) > 0) {
705 continue;
706 }
708 // project the vertex onto the ray line
709 float t = dot_product(varr[i] - ray.origin, ray.dir);
710 Vector3 vproj = ray.origin + ray.dir * t;
712 float dist_sq = (vproj - varr[i]).length_sq();
713 if(dist_sq < thres_sq) {
714 if(!hit) {
715 return true;
716 }
717 if(t < nearest_hit.dist) {
718 nearest_hit.dist = t;
719 nearest_vidx = i;
720 }
721 }
722 }
724 if(nearest_vidx != -1) {
725 hitvert = varr[nearest_vidx];
726 nearest_hit.obj = &hitvert;
727 }
729 } else {
730 // regular intersection test with polygons
732 for(unsigned int i=0; i<nfaces; i++) {
733 Triangle face(i, varr, idxarr);
735 // ignore back-facing polygons if the mode flags include ISECT_FRONT
736 if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(face.get_normal(), ray.dir) > 0) {
737 continue;
738 }
740 HitPoint fhit;
741 if(face.intersect(ray, hit ? &fhit : 0)) {
742 if(!hit) {
743 return true;
744 }
745 if(fhit.dist < nearest_hit.dist) {
746 nearest_hit = fhit;
747 hitface = face;
748 }
749 }
750 }
751 }
753 if(nearest_hit.obj) {
754 if(hit) {
755 *hit = nearest_hit;
757 // if we are interested in the mesh and not the faces set obj to this
758 if(Mesh::intersect_mode & ISECT_FACE) {
759 hit->obj = &hitface;
760 } else if(Mesh::intersect_mode & ISECT_VERTICES) {
761 hit->obj = &hitvert;
762 } else {
763 hit->obj = this;
764 }
765 }
766 return true;
767 }
768 return false;
769 }
772 // ------ private member functions ------
774 void Mesh::calc_aabb()
775 {
776 // the cast is to force calling the const version which doesn't invalidate
777 if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
778 return;
779 }
781 aabb.min = Vector3(FLT_MAX, FLT_MAX, FLT_MAX);
782 aabb.max = -aabb.min;
784 for(unsigned int i=0; i<nverts; i++) {
785 Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
786 for(int j=0; j<3; j++) {
787 if(v[j] < aabb.min[j]) {
788 aabb.min[j] = v[j];
789 }
790 if(v[j] > aabb.max[j]) {
791 aabb.max[j] = v[j];
792 }
793 }
794 }
795 aabb_valid = true;
796 }
798 void Mesh::calc_bsph()
799 {
800 // the cast is to force calling the const version which doesn't invalidate
801 if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
802 return;
803 }
805 Vector3 v;
806 bsph.center = Vector3(0, 0, 0);
808 // first find the center
809 for(unsigned int i=0; i<nverts; i++) {
810 v = get_attrib(MESH_ATTR_VERTEX, i);
811 bsph.center += v;
812 }
813 bsph.center /= (float)nverts;
815 bsph.radius = 0.0f;
816 for(unsigned int i=0; i<nverts; i++) {
817 v = get_attrib(MESH_ATTR_VERTEX, i);
818 float dist_sq = (v - bsph.center).length_sq();
819 if(dist_sq > bsph.radius) {
820 bsph.radius = dist_sq;
821 }
822 }
823 bsph.radius = sqrt(bsph.radius);
825 bsph_valid = true;
826 }
828 void Mesh::update_buffers()
829 {
830 for(int i=0; i<NUM_MESH_ATTR; i++) {
831 if(has_attrib(i) && !vattr[i].vbo_valid) {
832 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
833 glBufferData(GL_ARRAY_BUFFER, nverts * vattr[i].nelem * sizeof(float), &vattr[i].data[0], GL_STATIC_DRAW);
834 vattr[i].vbo_valid = true;
835 }
836 }
837 glBindBuffer(GL_ARRAY_BUFFER, 0);
839 if(idata_valid && !ibo_valid) {
840 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
841 glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 3 * sizeof(unsigned int), &idata[0], GL_STATIC_DRAW);
842 ibo_valid = true;
843 }
844 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
845 }
847 void Mesh::update_wire_ibo()
848 {
849 update_buffers();
851 if(wire_ibo_valid) {
852 return;
853 }
855 if(!wire_ibo) {
856 glGenBuffers(1, &wire_ibo);
857 }
859 unsigned int *wire_idxarr = new unsigned int[nfaces * 6];
860 unsigned int *dest = wire_idxarr;
862 if(ibo_valid) {
863 // we're dealing with an indexed mesh
864 const unsigned int *idxarr = ((const Mesh*)this)->get_index_data();
866 for(unsigned int i=0; i<nfaces; i++) {
867 *dest++ = idxarr[0];
868 *dest++ = idxarr[1];
869 *dest++ = idxarr[1];
870 *dest++ = idxarr[2];
871 *dest++ = idxarr[2];
872 *dest++ = idxarr[0];
873 idxarr += 3;
874 }
875 } else {
876 // not an indexed mesh ...
877 for(unsigned int i=0; i<nfaces; i++) {
878 int vidx = i * 3;
879 *dest++ = vidx;
880 *dest++ = vidx + 1;
881 *dest++ = vidx + 1;
882 *dest++ = vidx + 2;
883 *dest++ = vidx + 2;
884 *dest++ = vidx;
885 }
886 }
888 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
889 glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 6 * sizeof(unsigned int), wire_idxarr, GL_STATIC_DRAW);
890 delete [] wire_idxarr;
891 wire_ibo_valid = true;
892 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
893 }
896 // ------ class Triangle ------
897 Triangle::Triangle()
898 {
899 normal_valid = false;
900 id = -1;
901 }
903 Triangle::Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2)
904 {
905 v[0] = v0;
906 v[1] = v1;
907 v[2] = v2;
908 normal_valid = false;
909 id = -1;
910 }
912 Triangle::Triangle(int n, const Vector3 *varr, const unsigned int *idxarr)
913 {
914 if(idxarr) {
915 v[0] = varr[idxarr[n * 3]];
916 v[1] = varr[idxarr[n * 3 + 1]];
917 v[2] = varr[idxarr[n * 3 + 2]];
918 } else {
919 v[0] = varr[n * 3];
920 v[1] = varr[n * 3 + 1];
921 v[2] = varr[n * 3 + 2];
922 }
923 normal_valid = false;
924 id = n;
925 }
927 void Triangle::calc_normal()
928 {
929 normal = cross_product(v[1] - v[0], v[2] - v[0]).normalized();
930 normal_valid = true;
931 }
933 const Vector3 &Triangle::get_normal() const
934 {
935 if(!normal_valid) {
936 ((Triangle*)this)->calc_normal();
937 }
938 return normal;
939 }
941 void Triangle::transform(const Matrix4x4 &xform)
942 {
943 v[0].transform(xform);
944 v[1].transform(xform);
945 v[2].transform(xform);
946 normal_valid = false;
947 }
949 void Triangle::draw() const
950 {
951 Vector3 n[3];
952 n[0] = get_normal();
953 n[1] = get_normal();
954 n[2] = get_normal();
956 int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
957 int nloc = Mesh::get_attrib_location(MESH_ATTR_NORMAL);
959 glEnableVertexAttribArray(vloc);
960 glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
961 glVertexAttribPointer(nloc, 3, GL_FLOAT, GL_FALSE, 0, &n[0].x);
963 glDrawArrays(GL_TRIANGLES, 0, 3);
965 glDisableVertexAttribArray(vloc);
966 glDisableVertexAttribArray(nloc);
967 CHECKGLERR;
968 }
970 void Triangle::draw_wire() const
971 {
972 static const int idxarr[] = {0, 1, 1, 2, 2, 0};
973 int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
975 glEnableVertexAttribArray(vloc);
976 glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
978 glDrawElements(GL_LINES, 6, GL_UNSIGNED_INT, idxarr);
980 glDisableVertexAttribArray(vloc);
981 CHECKGLERR;
982 }
984 Vector3 Triangle::calc_barycentric(const Vector3 &pos) const
985 {
986 Vector3 norm = get_normal();
988 float area_sq = fabs(dot_product(cross_product(v[1] - v[0], v[2] - v[0]), norm));
989 if(area_sq < 1e-5) {
990 return Vector3(0, 0, 0);
991 }
993 float asq0 = fabs(dot_product(cross_product(v[1] - pos, v[2] - pos), norm));
994 float asq1 = fabs(dot_product(cross_product(v[2] - pos, v[0] - pos), norm));
995 float asq2 = fabs(dot_product(cross_product(v[0] - pos, v[1] - pos), norm));
997 return Vector3(asq0 / area_sq, asq1 / area_sq, asq2 / area_sq);
998 }
1000 bool Triangle::intersect(const Ray &ray, HitPoint *hit) const
1001 {
1002 Vector3 normal = get_normal();
1004 float ndotdir = dot_product(ray.dir, normal);
1005 if(fabs(ndotdir) < 1e-4) {
1006 return false;
1007 }
1009 Vector3 vertdir = v[0] - ray.origin;
1010 float t = dot_product(normal, vertdir) / ndotdir;
1012 Vector3 pos = ray.origin + ray.dir * t;
1013 Vector3 bary = calc_barycentric(pos);
1015 if(bary.x + bary.y + bary.z > 1.00001) {
1016 return false;
1017 }
1019 if(hit) {
1020 hit->dist = t;
1021 hit->pos = ray.origin + ray.dir * t;
1022 hit->normal = normal;
1023 hit->obj = this;
1024 }
1025 return true;
1026 }