vrshoot

view src/mesh.cc @ 0:b2f14e535253

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 01 Feb 2014 19:58:19 +0200
parents
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 int Mesh::global_sdr_loc[NUM_MESH_ATTR] = { 0, 1, 2, 3, 4, 5 };
12 unsigned int Mesh::intersect_mode = ISECT_DEFAULT;
13 float Mesh::vertex_sel_dist = 0.01;
14 float Mesh::vis_vecsize = 1.0;
16 Mesh::Mesh()
17 {
18 clear();
20 glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects);
22 for(int i=0; i<NUM_MESH_ATTR; i++) {
23 vattr[i].vbo = buffer_objects[i];
24 }
25 ibo = buffer_objects[NUM_MESH_ATTR];
26 wire_ibo = 0;
27 }
29 Mesh::~Mesh()
30 {
31 glDeleteBuffers(NUM_MESH_ATTR + 1, buffer_objects);
33 if(wire_ibo) {
34 glDeleteBuffers(1, &wire_ibo);
35 }
36 }
38 void Mesh::set_name(const char *name)
39 {
40 this->name = name;
41 }
43 const char *Mesh::get_name() const
44 {
45 return name.c_str();
46 }
48 bool Mesh::has_attrib(int attr) const
49 {
50 if(attr < 0 || attr >= NUM_MESH_ATTR) {
51 return false;
52 }
54 // if neither of these is valid, then nobody has set this attribute
55 return vattr[attr].vbo_valid || vattr[attr].data_valid;
56 }
58 void Mesh::clear()
59 {
60 bones.clear();
62 for(int i=0; i<NUM_MESH_ATTR; i++) {
63 vattr[i].nelem = 0;
64 vattr[i].vbo_valid = false;
65 vattr[i].data_valid = false;
66 //vattr[i].sdr_loc = -1;
67 vattr[i].data.clear();
68 }
69 ibo_valid = idata_valid = false;
70 idata.clear();
72 wire_ibo_valid = false;
74 nverts = nfaces = 0;
76 bsph_valid = false;
77 aabb_valid = false;
78 }
80 float *Mesh::set_attrib_data(int attrib, int nelem, unsigned int num, const float *data)
81 {
82 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
83 error_log("%s: invalid attrib: %d\n", __FUNCTION__, attrib);
84 return 0;
85 }
87 if(nverts && num != nverts) {
88 error_log("%s: attribute count missmatch (%d instead of %d)\n", __FUNCTION__, num, nverts);
89 return 0;
90 }
91 nverts = num;
93 vattr[attrib].data.clear();
94 vattr[attrib].nelem = nelem;
95 vattr[attrib].data.resize(num * nelem);
97 if(data) {
98 memcpy(&vattr[attrib].data[0], data, num * nelem * sizeof *data);
99 }
101 vattr[attrib].data_valid = true;
102 vattr[attrib].vbo_valid = false;
103 return &vattr[attrib].data[0];
104 }
106 float *Mesh::get_attrib_data(int attrib)
107 {
108 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
109 error_log("%s: invalid attrib: %d\n", __FUNCTION__, attrib);
110 return 0;
111 }
113 vattr[attrib].vbo_valid = false;
114 return (float*)((const Mesh*)this)->get_attrib_data(attrib);
115 }
117 const float *Mesh::get_attrib_data(int attrib) const
118 {
119 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
120 error_log("%s: invalid attrib: %d\n", __FUNCTION__, attrib);
121 return 0;
122 }
124 if(!vattr[attrib].data_valid) {
125 #if GL_ES_VERSION_2_0
126 error_log("%s: can't read back attrib data on CrippledGL ES\n", __FUNCTION__);
127 return 0;
128 #else
129 if(!vattr[attrib].vbo_valid) {
130 error_log("%s: unavailable attrib: %d\n", __FUNCTION__, attrib);
131 return 0;
132 }
134 // local data copy is unavailable, grab the data from the vbo
135 Mesh *m = (Mesh*)this;
136 m->vattr[attrib].data.resize(nverts * vattr[attrib].nelem);
138 glBindBuffer(GL_ARRAY_BUFFER, vattr[attrib].vbo);
139 void *data = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
140 memcpy(&m->vattr[attrib].data[0], data, nverts * vattr[attrib].nelem * sizeof(float));
141 glUnmapBuffer(GL_ARRAY_BUFFER);
143 vattr[attrib].data_valid = true;
144 #endif
145 }
147 return &vattr[attrib].data[0];
148 }
150 void Mesh::set_attrib(int attrib, int idx, const Vector4 &v)
151 {
152 float *data = get_attrib_data(attrib);
153 if(data) {
154 data += idx * vattr[attrib].nelem;
155 for(int i=0; i<vattr[attrib].nelem; i++) {
156 data[i] = v[i];
157 }
158 }
159 }
161 Vector4 Mesh::get_attrib(int attrib, int idx) const
162 {
163 Vector4 v(0.0, 0.0, 0.0, 1.0);
164 const float *data = get_attrib_data(attrib);
165 if(data) {
166 data += idx * vattr[attrib].nelem;
167 for(int i=0; i<vattr[attrib].nelem; i++) {
168 v[i] = data[i];
169 }
170 }
171 return v;
172 }
174 int Mesh::get_attrib_count(int attrib) const
175 {
176 return has_attrib(attrib) ? nverts : 0;
177 }
180 unsigned int *Mesh::set_index_data(int num, const unsigned int *indices)
181 {
182 int nidx = nfaces * 3;
183 if(nidx && num != nidx) {
184 error_log("%s: index count missmatch (%d instead of %d)\n", __FUNCTION__, num, nidx);
185 return 0;
186 }
187 nfaces = num / 3;
189 idata.clear();
190 idata.resize(num);
192 if(indices) {
193 memcpy(&idata[0], indices, num * sizeof *indices);
194 }
196 idata_valid = true;
197 ibo_valid = false;
199 return &idata[0];
200 }
202 unsigned int *Mesh::get_index_data()
203 {
204 ibo_valid = false;
205 return (unsigned int*)((const Mesh*)this)->get_index_data();
206 }
208 const unsigned int *Mesh::get_index_data() const
209 {
210 if(!idata_valid) {
211 #if GL_ES_VERSION_2_0
212 error_log("%s: can't read back index data in CrippledGL ES\n", __FUNCTION__);
213 return 0;
214 #else
215 if(!ibo_valid) {
216 error_log("%s: indices unavailable\n", __FUNCTION__);
217 return 0;
218 }
220 // local data copy is unavailable, gram the data from the ibo
221 Mesh *m = (Mesh*)this;
222 int nidx = nfaces * 3;
223 m->idata.resize(nidx);
225 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
226 void *data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY);
227 memcpy(&m->idata[0], data, nidx * sizeof(unsigned int));
228 glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
230 idata_valid = true;
231 #endif
232 }
234 return &idata[0];
235 }
237 int Mesh::get_index_count() const
238 {
239 return nfaces * 3;
240 }
242 void Mesh::append(const Mesh &mesh)
243 {
244 unsigned int idxoffs = nverts;
246 nverts += mesh.nverts;
247 nfaces += mesh.nfaces;
249 for(int i=0; i<NUM_MESH_ATTR; i++) {
250 if(has_attrib(i) && mesh.has_attrib(i)) {
251 // force validating the data arrays
252 get_attrib_data(i);
253 mesh.get_attrib_data(i);
255 // append the mesh data
256 vattr[i].data.insert(vattr[i].data.end(), mesh.vattr[i].data.begin(), mesh.vattr[i].data.end());
257 }
258 }
260 if(ibo_valid || idata_valid) {
261 // make index arrays valid
262 get_index_data();
263 mesh.get_index_data();
265 size_t orig_sz = idata.size();
267 idata.insert(idata.end(), mesh.idata.begin(), mesh.idata.end());
269 // fixup all the new indices
270 for(size_t i=orig_sz; i<idata.size(); i++) {
271 idata[i] += idxoffs;
272 }
273 }
275 // fuck everything
276 wire_ibo_valid = false;
277 aabb_valid = false;
278 bsph_valid = false;
279 }
281 // assemble a complete vertex by adding all the useful attributes
282 void Mesh::vertex(float x, float y, float z)
283 {
284 cur_val[MESH_ATTR_VERTEX] = Vector4(x, y, z, 1.0f);
285 vattr[MESH_ATTR_VERTEX].data_valid = true;
286 vattr[MESH_ATTR_VERTEX].nelem = 3;
288 for(int i=0; i<NUM_MESH_ATTR; i++) {
289 if(vattr[i].data_valid) {
290 for(int j=0; j<vattr[MESH_ATTR_VERTEX].nelem; j++) {
291 vattr[i].data.push_back(cur_val[i][j]);
292 }
293 }
294 vattr[i].vbo_valid = false;
295 }
296 nverts++;
298 /*if(idata_valid) {
299 idata.clear();
300 }
301 ibo_valid = idata_valid = false;*/
302 }
304 void Mesh::normal(float nx, float ny, float nz)
305 {
306 cur_val[MESH_ATTR_NORMAL] = Vector4(nx, ny, nz, 1.0f);
307 vattr[MESH_ATTR_NORMAL].data_valid = true;
308 vattr[MESH_ATTR_NORMAL].nelem = 3;
309 }
311 void Mesh::tangent(float tx, float ty, float tz)
312 {
313 cur_val[MESH_ATTR_TANGENT] = Vector4(tx, ty, tz, 1.0f);
314 vattr[MESH_ATTR_TANGENT].data_valid = true;
315 vattr[MESH_ATTR_TANGENT].nelem = 3;
316 }
318 void Mesh::texcoord(float u, float v, float w)
319 {
320 cur_val[MESH_ATTR_TEXCOORD] = Vector4(u, v, w, 1.0f);
321 vattr[MESH_ATTR_TEXCOORD].data_valid = true;
322 vattr[MESH_ATTR_TEXCOORD].nelem = 3;
323 }
325 void Mesh::boneweights(float w1, float w2, float w3, float w4)
326 {
327 cur_val[MESH_ATTR_BONEWEIGHTS] = Vector4(w1, w2, w3, w4);
328 vattr[MESH_ATTR_BONEWEIGHTS].data_valid = true;
329 vattr[MESH_ATTR_BONEWEIGHTS].nelem = 4;
330 }
332 void Mesh::boneidx(int idx1, int idx2, int idx3, int idx4)
333 {
334 cur_val[MESH_ATTR_BONEIDX] = Vector4(idx1, idx2, idx3, idx4);
335 vattr[MESH_ATTR_BONEIDX].data_valid = true;
336 vattr[MESH_ATTR_BONEIDX].nelem = 4;
337 }
339 void Mesh::face(unsigned int v0, unsigned int v1, unsigned int v2)
340 {
341 idata.push_back(v0);
342 idata.push_back(v1);
343 idata.push_back(v2);
345 idata_valid = true;
346 ibo_valid = false;
348 nfaces++;
349 }
351 int Mesh::get_poly_count() const
352 {
353 if(nfaces) {
354 return nfaces;
355 }
356 if(nverts) {
357 return nverts / 3;
358 }
359 return 0;
360 }
362 /// static function
363 void Mesh::set_attrib_location(int attr, int loc)
364 {
365 if(attr < 0 || attr >= NUM_MESH_ATTR) {
366 return;
367 }
368 Mesh::global_sdr_loc[attr] = loc;
369 }
371 /// static function
372 int Mesh::get_attrib_location(int attr)
373 {
374 if(attr < 0 || attr >= NUM_MESH_ATTR) {
375 return -1;
376 }
377 return Mesh::global_sdr_loc[attr];
378 }
380 /// static function
381 void Mesh::clear_attrib_locations()
382 {
383 for(int i=0; i<NUM_MESH_ATTR; i++) {
384 Mesh::global_sdr_loc[i] = -1;
385 }
386 }
388 /// static function
389 void Mesh::set_vis_vecsize(float sz)
390 {
391 Mesh::vis_vecsize = sz;
392 }
394 float Mesh::get_vis_vecsize()
395 {
396 return Mesh::vis_vecsize;
397 }
399 void Mesh::apply_xform(const Matrix4x4 &xform)
400 {
401 Matrix4x4 dir_xform = xform;
402 dir_xform[0][3] = dir_xform[1][3] = dir_xform[2][3] = 0.0f;
403 dir_xform[3][0] = dir_xform[3][1] = dir_xform[3][2] = 0.0f;
404 dir_xform[3][3] = 1.0f;
406 apply_xform(xform, dir_xform);
407 }
409 void Mesh::apply_xform(const Matrix4x4 &xform, const Matrix4x4 &dir_xform)
410 {
411 for(unsigned int i=0; i<nverts; i++) {
412 Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
413 set_attrib(MESH_ATTR_VERTEX, i, v.transformed(xform));
415 if(has_attrib(MESH_ATTR_NORMAL)) {
416 Vector3 n = get_attrib(MESH_ATTR_NORMAL, i);
417 set_attrib(MESH_ATTR_NORMAL, i, n.transformed(dir_xform));
418 }
419 if(has_attrib(MESH_ATTR_TANGENT)) {
420 Vector3 t = get_attrib(MESH_ATTR_TANGENT, i);
421 set_attrib(MESH_ATTR_TANGENT, i, t.transformed(dir_xform));
422 }
423 }
424 }
426 int Mesh::add_bone(XFormNode *bone)
427 {
428 int idx = bones.size();
429 bones.push_back(bone);
430 return idx;
431 }
433 const XFormNode *Mesh::get_bone(int idx) const
434 {
435 if(idx < 0 || idx >= (int)bones.size()) {
436 return 0;
437 }
438 return bones[idx];
439 }
441 int Mesh::get_bones_count() const
442 {
443 return (int)bones.size();
444 }
446 void Mesh::draw() const
447 {
448 const ShaderProg *cur_sdr = get_current_shader();
449 #ifdef GL_ES_VERSION_2_0
450 if(!cur_sdr) {
451 error_log("%s: CrippledGL ES can't draw without a shader\n", __FUNCTION__);
452 return;
453 }
454 #endif
456 ((Mesh*)this)->update_buffers();
458 if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
459 error_log("%s: invalid vertex buffer\n", __FUNCTION__);
460 return;
461 }
463 if(cur_sdr) {
464 // rendering with shaders
465 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
466 error_log("%s: shader attribute location for vertices unset\n", __FUNCTION__);
467 return;
468 }
470 for(int i=0; i<NUM_MESH_ATTR; i++) {
471 int loc = global_sdr_loc[i];
472 if(loc >= 0 && vattr[i].vbo_valid) {
473 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
474 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
475 glEnableVertexAttribArray(loc);
476 }
477 }
478 } else {
479 #ifndef GL_ES_VERSION_2_0
480 // rendering with fixed-function (not available in GLES2)
481 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_VERTEX].vbo);
482 glVertexPointer(vattr[MESH_ATTR_VERTEX].nelem, GL_FLOAT, 0, 0);
483 glEnableClientState(GL_VERTEX_ARRAY);
485 if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
486 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_NORMAL].vbo);
487 glNormalPointer(GL_FLOAT, 0, 0);
488 glEnableClientState(GL_NORMAL_ARRAY);
489 }
490 if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
491 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_TEXCOORD].vbo);
492 glTexCoordPointer(vattr[MESH_ATTR_TEXCOORD].nelem, GL_FLOAT, 0, 0);
493 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
494 }
495 if(vattr[MESH_ATTR_COLOR].vbo_valid) {
496 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_COLOR].vbo);
497 glColorPointer(vattr[MESH_ATTR_COLOR].nelem, GL_FLOAT, 0, 0);
498 glEnableClientState(GL_COLOR_ARRAY);
499 }
500 #endif
501 }
502 glBindBuffer(GL_ARRAY_BUFFER, 0);
504 if(ibo_valid) {
505 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
506 glDrawElements(GL_TRIANGLES, nfaces * 3, GL_UNSIGNED_INT, 0);
507 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
508 } else {
509 glDrawArrays(GL_TRIANGLES, 0, nverts);
510 }
512 if(cur_sdr) {
513 // rendered with shaders
514 for(int i=0; i<NUM_MESH_ATTR; i++) {
515 int loc = global_sdr_loc[i];
516 if(loc >= 0 && vattr[i].vbo_valid) {
517 glDisableVertexAttribArray(loc);
518 }
519 }
520 } else {
521 #ifndef GL_ES_VERSION_2_0
522 // rendered with fixed-function
523 glDisableClientState(GL_VERTEX_ARRAY);
524 if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
525 glDisableClientState(GL_NORMAL_ARRAY);
526 }
527 if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
528 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
529 }
530 if(vattr[MESH_ATTR_COLOR].vbo_valid) {
531 glDisableClientState(GL_COLOR_ARRAY);
532 }
533 #endif
534 }
535 }
537 void Mesh::draw_wire() const
538 {
539 ((Mesh*)this)->update_wire_ibo();
541 if(!vattr[MESH_ATTR_VERTEX].vbo_valid || !wire_ibo_valid) {
542 error_log("%s: invalid vertex buffer\n", __FUNCTION__);
543 return;
544 }
545 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
546 error_log("%s: shader attribute location for vertices unset\n", __FUNCTION__);
547 return;
548 }
550 for(int i=0; i<NUM_MESH_ATTR; i++) {
551 int loc = global_sdr_loc[i];
552 if(loc >= 0 && vattr[i].vbo_valid) {
553 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
554 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
555 glEnableVertexAttribArray(loc);
556 }
557 }
558 glBindBuffer(GL_ARRAY_BUFFER, 0);
560 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
561 glDrawElements(GL_LINES, nfaces * 6, GL_UNSIGNED_INT, 0);
562 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
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_vertices() const
573 {
574 ((Mesh*)this)->update_buffers();
576 if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
577 error_log("%s: invalid vertex buffer\n", __FUNCTION__);
578 return;
579 }
580 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
581 error_log("%s: shader attribute location for vertices unset\n", __FUNCTION__);
582 return;
583 }
585 for(int i=0; i<NUM_MESH_ATTR; i++) {
586 int loc = global_sdr_loc[i];
587 if(loc >= 0 && vattr[i].vbo_valid) {
588 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
589 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
590 glEnableVertexAttribArray(loc);
591 }
592 }
593 glBindBuffer(GL_ARRAY_BUFFER, 0);
595 glDrawArrays(GL_POINTS, 0, nverts);
597 for(int i=0; i<NUM_MESH_ATTR; i++) {
598 int loc = global_sdr_loc[i];
599 if(loc >= 0 && vattr[i].vbo_valid) {
600 glDisableVertexAttribArray(loc);
601 }
602 }
603 }
605 void Mesh::draw_normals() const
606 {
607 #ifdef USE_OLDGL
608 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
609 Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
610 Vector3 *norm = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
612 if(!varr || !norm || vert_loc < 0) {
613 return;
614 }
616 glBegin(GL_LINES);
617 for(size_t i=0; i<nverts; i++) {
618 glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
619 Vector3 end = varr[i] + norm[i] * vis_vecsize;
620 glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
621 }
622 glEnd();
624 #endif // USE_OLDGL
625 }
627 void Mesh::draw_tangents() const
628 {
629 #ifdef USE_OLDGL
630 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
631 Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
632 Vector3 *tang = (Vector3*)get_attrib_data(MESH_ATTR_TANGENT);
634 if(!varr || !tang || vert_loc < 0) {
635 return;
636 }
638 glBegin(GL_LINES);
639 for(size_t i=0; i<nverts; i++) {
640 glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
641 Vector3 end = varr[i] + tang[i] * vis_vecsize;
642 glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
643 }
644 glEnd();
646 #endif // USE_OLDGL
647 }
649 void Mesh::get_aabbox(Vector3 *vmin, Vector3 *vmax) const
650 {
651 if(!aabb_valid) {
652 ((Mesh*)this)->calc_aabb();
653 }
654 *vmin = aabb.min;
655 *vmax = aabb.max;
656 }
658 const AABox &Mesh::get_aabbox() const
659 {
660 if(!aabb_valid) {
661 ((Mesh*)this)->calc_aabb();
662 }
663 return aabb;
664 }
666 float Mesh::get_bsphere(Vector3 *center, float *rad) const
667 {
668 if(!bsph_valid) {
669 ((Mesh*)this)->calc_bsph();
670 }
671 *center = bsph.center;
672 *rad = bsph.radius;
673 return bsph.radius;
674 }
676 const Sphere &Mesh::get_bsphere() const
677 {
678 if(!bsph_valid) {
679 ((Mesh*)this)->calc_bsph();
680 }
681 return bsph;
682 }
684 /// static function
685 void Mesh::set_intersect_mode(unsigned int mode)
686 {
687 Mesh::intersect_mode = mode;
688 }
690 /// static function
691 unsigned int Mesh::get_intersect_mode()
692 {
693 return Mesh::intersect_mode;
694 }
696 /// static function
697 void Mesh::set_vertex_select_distance(float dist)
698 {
699 Mesh::vertex_sel_dist = dist;
700 }
702 /// static function
703 float Mesh::get_vertex_select_distance()
704 {
705 return Mesh::vertex_sel_dist;
706 }
708 bool Mesh::intersect(const Ray &ray, HitPoint *hit) const
709 {
710 assert((Mesh::intersect_mode & (ISECT_VERTICES | ISECT_FACE)) != (ISECT_VERTICES | ISECT_FACE));
712 const Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
713 const Vector3 *narr = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
714 if(!varr) {
715 return false;
716 }
717 const unsigned int *idxarr = get_index_data();
719 // first test with the bounding box
720 AABox box;
721 get_aabbox(&box.min, &box.max);
722 if(!box.intersect(ray)) {
723 return false;
724 }
726 HitPoint nearest_hit;
727 nearest_hit.dist = FLT_MAX;
728 nearest_hit.obj = 0;
730 if(Mesh::intersect_mode & ISECT_VERTICES) {
731 // we asked for "intersections" with the vertices of the mesh
732 long nearest_vidx = -1;
733 float thres_sq = Mesh::vertex_sel_dist * Mesh::vertex_sel_dist;
735 for(unsigned int i=0; i<nverts; i++) {
737 if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(narr[i], ray.dir) > 0) {
738 continue;
739 }
741 // project the vertex onto the ray line
742 float t = dot_product(varr[i] - ray.origin, ray.dir);
743 Vector3 vproj = ray.origin + ray.dir * t;
745 float dist_sq = (vproj - varr[i]).length_sq();
746 if(dist_sq < thres_sq) {
747 if(!hit) {
748 return true;
749 }
750 if(t < nearest_hit.dist) {
751 nearest_hit.dist = t;
752 nearest_vidx = i;
753 }
754 }
755 }
757 if(nearest_vidx != -1) {
758 hitvert = varr[nearest_vidx];
759 nearest_hit.obj = &hitvert;
760 }
762 } else {
763 // regular intersection test with polygons
765 for(unsigned int i=0; i<nfaces; i++) {
766 Triangle face(i, varr, idxarr);
768 // ignore back-facing polygons if the mode flags include ISECT_FRONT
769 if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(face.get_normal(), ray.dir) > 0) {
770 continue;
771 }
773 HitPoint fhit;
774 if(face.intersect(ray, hit ? &fhit : 0)) {
775 if(!hit) {
776 return true;
777 }
778 if(fhit.dist < nearest_hit.dist) {
779 nearest_hit = fhit;
780 hitface = face;
781 }
782 }
783 }
784 }
786 if(nearest_hit.obj) {
787 if(hit) {
788 *hit = nearest_hit;
790 // if we are interested in the mesh and not the faces set obj to this
791 if(Mesh::intersect_mode & ISECT_FACE) {
792 hit->obj = &hitface;
793 } else if(Mesh::intersect_mode & ISECT_VERTICES) {
794 hit->obj = &hitvert;
795 } else {
796 hit->obj = this;
797 }
798 }
799 return true;
800 }
801 return false;
802 }
805 // ------ private member functions ------
807 void Mesh::calc_aabb()
808 {
809 // the cast is to force calling the const version which doesn't invalidate
810 if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
811 return;
812 }
814 aabb.min = Vector3(FLT_MAX, FLT_MAX, FLT_MAX);
815 aabb.max = -aabb.min;
817 for(unsigned int i=0; i<nverts; i++) {
818 Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
819 for(int j=0; j<3; j++) {
820 if(v[j] < aabb.min[j]) {
821 aabb.min[j] = v[j];
822 }
823 if(v[j] > aabb.max[j]) {
824 aabb.max[j] = v[j];
825 }
826 }
827 }
828 aabb_valid = true;
829 }
831 void Mesh::calc_bsph()
832 {
833 // the cast is to force calling the const version which doesn't invalidate
834 if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
835 return;
836 }
838 Vector3 v;
839 bsph.center = Vector3(0, 0, 0);
841 // first find the center
842 for(unsigned int i=0; i<nverts; i++) {
843 v = get_attrib(MESH_ATTR_VERTEX, i);
844 bsph.center += v;
845 }
846 bsph.center /= (float)nverts;
848 bsph.radius = 0.0f;
849 for(unsigned int i=0; i<nverts; i++) {
850 v = get_attrib(MESH_ATTR_VERTEX, i);
851 float dist_sq = (v - bsph.center).length_sq();
852 if(dist_sq > bsph.radius) {
853 bsph.radius = dist_sq;
854 }
855 }
856 bsph.radius = sqrt(bsph.radius);
858 bsph_valid = true;
859 }
861 void Mesh::update_buffers()
862 {
863 for(int i=0; i<NUM_MESH_ATTR; i++) {
864 if(has_attrib(i) && !vattr[i].vbo_valid) {
865 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
866 glBufferData(GL_ARRAY_BUFFER, nverts * vattr[i].nelem * sizeof(float), &vattr[i].data[0], GL_STATIC_DRAW);
867 vattr[i].vbo_valid = true;
868 }
869 }
870 glBindBuffer(GL_ARRAY_BUFFER, 0);
872 if(idata_valid && !ibo_valid) {
873 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
874 glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 3 * sizeof(unsigned int), &idata[0], GL_STATIC_DRAW);
875 ibo_valid = true;
876 }
877 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
878 }
880 void Mesh::update_wire_ibo()
881 {
882 update_buffers();
884 if(wire_ibo_valid) {
885 return;
886 }
888 if(!wire_ibo) {
889 glGenBuffers(1, &wire_ibo);
890 }
892 unsigned int *wire_idxarr = new unsigned int[nfaces * 6];
893 unsigned int *dest = wire_idxarr;
895 if(ibo_valid) {
896 // we're dealing with an indexed mesh
897 const unsigned int *idxarr = ((const Mesh*)this)->get_index_data();
899 for(unsigned int i=0; i<nfaces; i++) {
900 *dest++ = idxarr[0];
901 *dest++ = idxarr[1];
902 *dest++ = idxarr[1];
903 *dest++ = idxarr[2];
904 *dest++ = idxarr[2];
905 *dest++ = idxarr[0];
906 idxarr += 3;
907 }
908 } else {
909 // not an indexed mesh ...
910 for(unsigned int i=0; i<nfaces; i++) {
911 int vidx = i * 3;
912 *dest++ = vidx;
913 *dest++ = vidx + 1;
914 *dest++ = vidx + 1;
915 *dest++ = vidx + 2;
916 *dest++ = vidx + 2;
917 *dest++ = vidx;
918 }
919 }
921 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
922 glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 6 * sizeof(unsigned int), wire_idxarr, GL_STATIC_DRAW);
923 delete [] wire_idxarr;
924 wire_ibo_valid = true;
925 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
926 }
929 // ------ class Triangle ------
930 Triangle::Triangle()
931 {
932 normal_valid = false;
933 id = -1;
934 }
936 Triangle::Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2)
937 {
938 v[0] = v0;
939 v[1] = v1;
940 v[2] = v2;
941 normal_valid = false;
942 id = -1;
943 }
945 Triangle::Triangle(int n, const Vector3 *varr, const unsigned int *idxarr)
946 {
947 if(idxarr) {
948 v[0] = varr[idxarr[n * 3]];
949 v[1] = varr[idxarr[n * 3 + 1]];
950 v[2] = varr[idxarr[n * 3 + 2]];
951 } else {
952 v[0] = varr[n * 3];
953 v[1] = varr[n * 3 + 1];
954 v[2] = varr[n * 3 + 2];
955 }
956 normal_valid = false;
957 id = n;
958 }
960 void Triangle::calc_normal()
961 {
962 normal = cross_product(v[1] - v[0], v[2] - v[0]).normalized();
963 normal_valid = true;
964 }
966 const Vector3 &Triangle::get_normal() const
967 {
968 if(!normal_valid) {
969 ((Triangle*)this)->calc_normal();
970 }
971 return normal;
972 }
974 void Triangle::transform(const Matrix4x4 &xform)
975 {
976 v[0].transform(xform);
977 v[1].transform(xform);
978 v[2].transform(xform);
979 normal_valid = false;
980 }
982 void Triangle::draw() const
983 {
984 Vector3 n[3];
985 n[0] = get_normal();
986 n[1] = get_normal();
987 n[2] = get_normal();
989 int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
990 int nloc = Mesh::get_attrib_location(MESH_ATTR_NORMAL);
992 glEnableVertexAttribArray(vloc);
993 glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
994 glVertexAttribPointer(nloc, 3, GL_FLOAT, GL_FALSE, 0, &n[0].x);
996 glDrawArrays(GL_TRIANGLES, 0, 3);
998 glDisableVertexAttribArray(vloc);
999 glDisableVertexAttribArray(nloc);
1000 CHECKGLERR;
1003 void Triangle::draw_wire() const
1005 static const int idxarr[] = {0, 1, 1, 2, 2, 0};
1006 int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
1008 glEnableVertexAttribArray(vloc);
1009 glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
1011 glDrawElements(GL_LINES, 6, GL_UNSIGNED_INT, idxarr);
1013 glDisableVertexAttribArray(vloc);
1014 CHECKGLERR;
1017 Vector3 Triangle::calc_barycentric(const Vector3 &pos) const
1019 Vector3 norm = get_normal();
1021 float area_sq = fabs(dot_product(cross_product(v[1] - v[0], v[2] - v[0]), norm));
1022 if(area_sq < 1e-5) {
1023 return Vector3(0, 0, 0);
1026 float asq0 = fabs(dot_product(cross_product(v[1] - pos, v[2] - pos), norm));
1027 float asq1 = fabs(dot_product(cross_product(v[2] - pos, v[0] - pos), norm));
1028 float asq2 = fabs(dot_product(cross_product(v[0] - pos, v[1] - pos), norm));
1030 return Vector3(asq0 / area_sq, asq1 / area_sq, asq2 / area_sq);
1033 bool Triangle::intersect(const Ray &ray, HitPoint *hit) const
1035 Vector3 normal = get_normal();
1037 float ndotdir = dot_product(ray.dir, normal);
1038 if(fabs(ndotdir) < 1e-4) {
1039 return false;
1042 Vector3 vertdir = v[0] - ray.origin;
1043 float t = dot_product(normal, vertdir) / ndotdir;
1045 Vector3 pos = ray.origin + ray.dir * t;
1046 Vector3 bary = calc_barycentric(pos);
1048 if(bary.x + bary.y + bary.z > 1.00001) {
1049 return false;
1052 if(hit) {
1053 hit->dist = t;
1054 hit->pos = ray.origin + ray.dir * t;
1055 hit->normal = normal;
1056 hit->obj = this;
1058 return true;