conworlds

view src/mesh.cc @ 15:9b0db7dbde6e

hmmm doesn't work properly yes
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 24 Aug 2014 14:36:00 +0300
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 unsigned int *Mesh::set_index_data(int num, const unsigned int *indices)
175 {
176 int nidx = nfaces * 3;
177 if(nidx && num != nidx) {
178 error_log("%s: index count missmatch (%d instead of %d)\n", __FUNCTION__, num, nidx);
179 return 0;
180 }
181 nfaces = num / 3;
183 idata.clear();
184 idata.resize(num);
186 if(indices) {
187 memcpy(&idata[0], indices, num * sizeof *indices);
188 }
190 idata_valid = true;
191 ibo_valid = false;
193 return &idata[0];
194 }
196 unsigned int *Mesh::get_index_data()
197 {
198 ibo_valid = false;
199 return (unsigned int*)((const Mesh*)this)->get_index_data();
200 }
202 const unsigned int *Mesh::get_index_data() const
203 {
204 if(!idata_valid) {
205 #if GL_ES_VERSION_2_0
206 error_log("%s: can't read back index data in CrippledGL ES\n", __FUNCTION__);
207 return 0;
208 #else
209 if(!ibo_valid) {
210 error_log("%s: indices unavailable\n", __FUNCTION__);
211 return 0;
212 }
214 // local data copy is unavailable, gram the data from the ibo
215 Mesh *m = (Mesh*)this;
216 int nidx = nfaces * 3;
217 m->idata.resize(nidx);
219 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
220 void *data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY);
221 memcpy(&m->idata[0], data, nidx * sizeof(unsigned int));
222 glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
224 idata_valid = true;
225 #endif
226 }
228 return &idata[0];
229 }
231 void Mesh::append(const Mesh &mesh)
232 {
233 unsigned int idxoffs = nverts;
235 nverts += mesh.nverts;
236 nfaces += mesh.nfaces;
238 for(int i=0; i<NUM_MESH_ATTR; i++) {
239 if(has_attrib(i) && mesh.has_attrib(i)) {
240 // force validating the data arrays
241 get_attrib_data(i);
242 mesh.get_attrib_data(i);
244 // append the mesh data
245 vattr[i].data.insert(vattr[i].data.end(), mesh.vattr[i].data.begin(), mesh.vattr[i].data.end());
246 }
247 }
249 if(ibo_valid || idata_valid) {
250 // make index arrays valid
251 get_index_data();
252 mesh.get_index_data();
254 size_t orig_sz = idata.size();
256 idata.insert(idata.end(), mesh.idata.begin(), mesh.idata.end());
258 // fixup all the new indices
259 for(size_t i=orig_sz; i<idata.size(); i++) {
260 idata[i] += idxoffs;
261 }
262 }
264 // fuck everything
265 wire_ibo_valid = false;
266 aabb_valid = false;
267 bsph_valid = false;
268 }
270 // assemble a complete vertex by adding all the useful attributes
271 void Mesh::vertex(float x, float y, float z)
272 {
273 cur_val[MESH_ATTR_VERTEX] = Vector4(x, y, z, 1.0f);
274 vattr[MESH_ATTR_VERTEX].data_valid = true;
275 vattr[MESH_ATTR_VERTEX].nelem = 3;
277 for(int i=0; i<NUM_MESH_ATTR; i++) {
278 if(vattr[i].data_valid) {
279 for(int j=0; j<vattr[MESH_ATTR_VERTEX].nelem; j++) {
280 vattr[i].data.push_back(cur_val[i][j]);
281 }
282 }
283 vattr[i].vbo_valid = false;
284 }
286 if(idata_valid) {
287 idata.clear();
288 }
289 ibo_valid = idata_valid = false;
290 }
292 void Mesh::normal(float nx, float ny, float nz)
293 {
294 cur_val[MESH_ATTR_NORMAL] = Vector4(nx, ny, nz, 1.0f);
295 vattr[MESH_ATTR_NORMAL].data_valid = true;
296 vattr[MESH_ATTR_NORMAL].nelem = 3;
297 }
299 void Mesh::tangent(float tx, float ty, float tz)
300 {
301 cur_val[MESH_ATTR_TANGENT] = Vector4(tx, ty, tz, 1.0f);
302 vattr[MESH_ATTR_TANGENT].data_valid = true;
303 vattr[MESH_ATTR_TANGENT].nelem = 3;
304 }
306 void Mesh::texcoord(float u, float v, float w)
307 {
308 cur_val[MESH_ATTR_TEXCOORD] = Vector4(u, v, w, 1.0f);
309 vattr[MESH_ATTR_TEXCOORD].data_valid = true;
310 vattr[MESH_ATTR_TEXCOORD].nelem = 3;
311 }
313 void Mesh::boneweights(float w1, float w2, float w3, float w4)
314 {
315 cur_val[MESH_ATTR_BONEWEIGHTS] = Vector4(w1, w2, w3, w4);
316 vattr[MESH_ATTR_BONEWEIGHTS].data_valid = true;
317 vattr[MESH_ATTR_BONEWEIGHTS].nelem = 4;
318 }
320 void Mesh::boneidx(int idx1, int idx2, int idx3, int idx4)
321 {
322 cur_val[MESH_ATTR_BONEIDX] = Vector4(idx1, idx2, idx3, idx4);
323 vattr[MESH_ATTR_BONEIDX].data_valid = true;
324 vattr[MESH_ATTR_BONEIDX].nelem = 4;
325 }
327 /// static function
328 void Mesh::set_attrib_location(int attr, int loc)
329 {
330 if(attr < 0 || attr >= NUM_MESH_ATTR) {
331 return;
332 }
333 Mesh::global_sdr_loc[attr] = loc;
334 }
336 /// static function
337 int Mesh::get_attrib_location(int attr)
338 {
339 if(attr < 0 || attr >= NUM_MESH_ATTR) {
340 return -1;
341 }
342 return Mesh::global_sdr_loc[attr];
343 }
345 /// static function
346 void Mesh::clear_attrib_locations()
347 {
348 for(int i=0; i<NUM_MESH_ATTR; i++) {
349 Mesh::global_sdr_loc[i] = -1;
350 }
351 }
353 /// static function
354 void Mesh::set_vis_vecsize(float sz)
355 {
356 Mesh::vis_vecsize = sz;
357 }
359 float Mesh::get_vis_vecsize()
360 {
361 return Mesh::vis_vecsize;
362 }
364 void Mesh::apply_xform(const Matrix4x4 &xform)
365 {
366 Matrix4x4 dir_xform = xform;
367 dir_xform[0][3] = dir_xform[1][3] = dir_xform[2][3] = 0.0f;
368 dir_xform[3][0] = dir_xform[3][1] = dir_xform[3][2] = 0.0f;
369 dir_xform[3][3] = 1.0f;
371 apply_xform(xform, dir_xform);
372 }
374 void Mesh::apply_xform(const Matrix4x4 &xform, const Matrix4x4 &dir_xform)
375 {
376 for(unsigned int i=0; i<nverts; i++) {
377 Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
378 set_attrib(MESH_ATTR_VERTEX, i, v.transformed(xform));
380 if(has_attrib(MESH_ATTR_NORMAL)) {
381 Vector3 n = get_attrib(MESH_ATTR_NORMAL, i);
382 set_attrib(MESH_ATTR_NORMAL, i, n.transformed(dir_xform));
383 }
384 if(has_attrib(MESH_ATTR_TANGENT)) {
385 Vector3 t = get_attrib(MESH_ATTR_TANGENT, i);
386 set_attrib(MESH_ATTR_TANGENT, i, t.transformed(dir_xform));
387 }
388 }
389 }
391 int Mesh::add_bone(XFormNode *bone)
392 {
393 int idx = bones.size();
394 bones.push_back(bone);
395 return idx;
396 }
398 const XFormNode *Mesh::get_bone(int idx) const
399 {
400 if(idx < 0 || idx >= (int)bones.size()) {
401 return 0;
402 }
403 return bones[idx];
404 }
406 int Mesh::get_bones_count() const
407 {
408 return (int)bones.size();
409 }
411 void Mesh::draw() const
412 {
413 const ShaderProg *cur_sdr = get_current_shader();
414 #ifdef GL_ES_VERSION_2_0
415 if(!cur_sdr) {
416 error_log("%s: CrippledGL ES can't draw without a shader\n", __FUNCTION__);
417 return;
418 }
419 #endif
421 ((Mesh*)this)->update_buffers();
423 if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
424 error_log("%s: invalid vertex buffer\n", __FUNCTION__);
425 return;
426 }
428 if(cur_sdr) {
429 // rendering with shaders
430 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
431 error_log("%s: shader attribute location for vertices unset\n", __FUNCTION__);
432 return;
433 }
435 for(int i=0; i<NUM_MESH_ATTR; i++) {
436 int loc = global_sdr_loc[i];
437 if(loc >= 0 && vattr[i].vbo_valid) {
438 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
439 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
440 glEnableVertexAttribArray(loc);
441 }
442 }
443 } else {
444 #ifndef GL_ES_VERSION_2_0
445 // rendering with fixed-function (not available in GLES2)
446 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_VERTEX].vbo);
447 glVertexPointer(vattr[MESH_ATTR_VERTEX].nelem, GL_FLOAT, 0, 0);
448 glEnableClientState(GL_VERTEX_ARRAY);
450 if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
451 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_NORMAL].vbo);
452 glNormalPointer(GL_FLOAT, 0, 0);
453 glEnableClientState(GL_NORMAL_ARRAY);
454 }
455 if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
456 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_TEXCOORD].vbo);
457 glTexCoordPointer(vattr[MESH_ATTR_TEXCOORD].nelem, GL_FLOAT, 0, 0);
458 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
459 }
460 if(vattr[MESH_ATTR_COLOR].vbo_valid) {
461 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_COLOR].vbo);
462 glColorPointer(vattr[MESH_ATTR_COLOR].nelem, GL_FLOAT, 0, 0);
463 glEnableClientState(GL_COLOR_ARRAY);
464 }
465 #endif
466 }
467 glBindBuffer(GL_ARRAY_BUFFER, 0);
469 if(ibo_valid) {
470 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
471 glDrawElements(GL_TRIANGLES, nfaces * 3, GL_UNSIGNED_INT, 0);
472 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
473 } else {
474 glDrawArrays(GL_TRIANGLES, 0, nverts);
475 }
477 if(cur_sdr) {
478 // rendered with shaders
479 for(int i=0; i<NUM_MESH_ATTR; i++) {
480 int loc = global_sdr_loc[i];
481 if(loc >= 0 && vattr[i].vbo_valid) {
482 glDisableVertexAttribArray(loc);
483 }
484 }
485 } else {
486 #ifndef GL_ES_VERSION_2_0
487 // rendered with fixed-function
488 glDisableClientState(GL_VERTEX_ARRAY);
489 if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
490 glDisableClientState(GL_NORMAL_ARRAY);
491 }
492 if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
493 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
494 }
495 if(vattr[MESH_ATTR_COLOR].vbo_valid) {
496 glDisableClientState(GL_COLOR_ARRAY);
497 }
498 #endif
499 }
500 }
502 void Mesh::draw_wire() const
503 {
504 ((Mesh*)this)->update_wire_ibo();
506 if(!vattr[MESH_ATTR_VERTEX].vbo_valid || !wire_ibo_valid) {
507 error_log("%s: invalid vertex buffer\n", __FUNCTION__);
508 return;
509 }
510 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
511 error_log("%s: shader attribute location for vertices unset\n", __FUNCTION__);
512 return;
513 }
515 for(int i=0; i<NUM_MESH_ATTR; i++) {
516 int loc = global_sdr_loc[i];
517 if(loc >= 0 && vattr[i].vbo_valid) {
518 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
519 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
520 glEnableVertexAttribArray(loc);
521 }
522 }
523 glBindBuffer(GL_ARRAY_BUFFER, 0);
525 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
526 glDrawElements(GL_LINES, nfaces * 6, GL_UNSIGNED_INT, 0);
527 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
529 for(int i=0; i<NUM_MESH_ATTR; i++) {
530 int loc = global_sdr_loc[i];
531 if(loc >= 0 && vattr[i].vbo_valid) {
532 glDisableVertexAttribArray(loc);
533 }
534 }
535 }
537 void Mesh::draw_vertices() const
538 {
539 ((Mesh*)this)->update_buffers();
541 if(!vattr[MESH_ATTR_VERTEX].vbo_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 glDrawArrays(GL_POINTS, 0, nverts);
562 for(int i=0; i<NUM_MESH_ATTR; i++) {
563 int loc = global_sdr_loc[i];
564 if(loc >= 0 && vattr[i].vbo_valid) {
565 glDisableVertexAttribArray(loc);
566 }
567 }
568 }
570 void Mesh::draw_normals() const
571 {
572 #ifdef USE_OLDGL
573 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
574 Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
575 Vector3 *norm = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
577 if(!varr || !norm || vert_loc < 0) {
578 return;
579 }
581 glBegin(GL_LINES);
582 for(size_t i=0; i<nverts; i++) {
583 glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
584 Vector3 end = varr[i] + norm[i] * vis_vecsize;
585 glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
586 }
587 glEnd();
589 #endif // USE_OLDGL
590 }
592 void Mesh::draw_tangents() const
593 {
594 #ifdef USE_OLDGL
595 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
596 Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
597 Vector3 *tang = (Vector3*)get_attrib_data(MESH_ATTR_TANGENT);
599 if(!varr || !tang || vert_loc < 0) {
600 return;
601 }
603 glBegin(GL_LINES);
604 for(size_t i=0; i<nverts; i++) {
605 glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
606 Vector3 end = varr[i] + tang[i] * vis_vecsize;
607 glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
608 }
609 glEnd();
611 #endif // USE_OLDGL
612 }
614 void Mesh::get_aabbox(Vector3 *vmin, Vector3 *vmax) const
615 {
616 if(!aabb_valid) {
617 ((Mesh*)this)->calc_aabb();
618 }
619 *vmin = aabb.min;
620 *vmax = aabb.max;
621 }
623 const AABox &Mesh::get_aabbox() const
624 {
625 if(!aabb_valid) {
626 ((Mesh*)this)->calc_aabb();
627 }
628 return aabb;
629 }
631 float Mesh::get_bsphere(Vector3 *center, float *rad) const
632 {
633 if(!bsph_valid) {
634 ((Mesh*)this)->calc_bsph();
635 }
636 *center = bsph.center;
637 *rad = bsph.radius;
638 return bsph.radius;
639 }
641 const Sphere &Mesh::get_bsphere() const
642 {
643 if(!bsph_valid) {
644 ((Mesh*)this)->calc_bsph();
645 }
646 return bsph;
647 }
649 /// static function
650 void Mesh::set_intersect_mode(unsigned int mode)
651 {
652 Mesh::intersect_mode = mode;
653 }
655 /// static function
656 unsigned int Mesh::get_intersect_mode()
657 {
658 return Mesh::intersect_mode;
659 }
661 /// static function
662 void Mesh::set_vertex_select_distance(float dist)
663 {
664 Mesh::vertex_sel_dist = dist;
665 }
667 /// static function
668 float Mesh::get_vertex_select_distance()
669 {
670 return Mesh::vertex_sel_dist;
671 }
673 bool Mesh::intersect(const Ray &ray, HitPoint *hit) const
674 {
675 assert((Mesh::intersect_mode & (ISECT_VERTICES | ISECT_FACE)) != (ISECT_VERTICES | ISECT_FACE));
677 const Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
678 const Vector3 *narr = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
679 if(!varr) {
680 return false;
681 }
682 const unsigned int *idxarr = get_index_data();
684 // first test with the bounding box
685 AABox box;
686 get_aabbox(&box.min, &box.max);
687 if(!box.intersect(ray)) {
688 return false;
689 }
691 HitPoint nearest_hit;
692 nearest_hit.dist = FLT_MAX;
693 nearest_hit.obj = 0;
695 if(Mesh::intersect_mode & ISECT_VERTICES) {
696 // we asked for "intersections" with the vertices of the mesh
697 long nearest_vidx = -1;
698 float thres_sq = Mesh::vertex_sel_dist * Mesh::vertex_sel_dist;
700 for(unsigned int i=0; i<nverts; i++) {
702 if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(narr[i], ray.dir) > 0) {
703 continue;
704 }
706 // project the vertex onto the ray line
707 float t = dot_product(varr[i] - ray.origin, ray.dir);
708 Vector3 vproj = ray.origin + ray.dir * t;
710 float dist_sq = (vproj - varr[i]).length_sq();
711 if(dist_sq < thres_sq) {
712 if(!hit) {
713 return true;
714 }
715 if(t < nearest_hit.dist) {
716 nearest_hit.dist = t;
717 nearest_vidx = i;
718 }
719 }
720 }
722 if(nearest_vidx != -1) {
723 hitvert = varr[nearest_vidx];
724 nearest_hit.obj = &hitvert;
725 }
727 } else {
728 // regular intersection test with polygons
730 for(unsigned int i=0; i<nfaces; i++) {
731 Triangle face(i, varr, idxarr);
733 // ignore back-facing polygons if the mode flags include ISECT_FRONT
734 if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(face.get_normal(), ray.dir) > 0) {
735 continue;
736 }
738 HitPoint fhit;
739 if(face.intersect(ray, hit ? &fhit : 0)) {
740 if(!hit) {
741 return true;
742 }
743 if(fhit.dist < nearest_hit.dist) {
744 nearest_hit = fhit;
745 hitface = face;
746 }
747 }
748 }
749 }
751 if(nearest_hit.obj) {
752 if(hit) {
753 *hit = nearest_hit;
755 // if we are interested in the mesh and not the faces set obj to this
756 if(Mesh::intersect_mode & ISECT_FACE) {
757 hit->obj = &hitface;
758 } else if(Mesh::intersect_mode & ISECT_VERTICES) {
759 hit->obj = &hitvert;
760 } else {
761 hit->obj = this;
762 }
763 }
764 return true;
765 }
766 return false;
767 }
770 // ------ private member functions ------
772 void Mesh::calc_aabb()
773 {
774 // the cast is to force calling the const version which doesn't invalidate
775 if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
776 return;
777 }
779 aabb.min = Vector3(FLT_MAX, FLT_MAX, FLT_MAX);
780 aabb.max = -aabb.min;
782 for(unsigned int i=0; i<nverts; i++) {
783 Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
784 for(int j=0; j<3; j++) {
785 if(v[j] < aabb.min[j]) {
786 aabb.min[j] = v[j];
787 }
788 if(v[j] > aabb.max[j]) {
789 aabb.max[j] = v[j];
790 }
791 }
792 }
793 aabb_valid = true;
794 }
796 void Mesh::calc_bsph()
797 {
798 // the cast is to force calling the const version which doesn't invalidate
799 if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
800 return;
801 }
803 Vector3 v;
804 bsph.center = Vector3(0, 0, 0);
806 // first find the center
807 for(unsigned int i=0; i<nverts; i++) {
808 v = get_attrib(MESH_ATTR_VERTEX, i);
809 bsph.center += v;
810 }
811 bsph.center /= (float)nverts;
813 bsph.radius = 0.0f;
814 for(unsigned int i=0; i<nverts; i++) {
815 v = get_attrib(MESH_ATTR_VERTEX, i);
816 float dist_sq = (v - bsph.center).length_sq();
817 if(dist_sq > bsph.radius) {
818 bsph.radius = dist_sq;
819 }
820 }
821 bsph.radius = sqrt(bsph.radius);
823 bsph_valid = true;
824 }
826 void Mesh::update_buffers()
827 {
828 for(int i=0; i<NUM_MESH_ATTR; i++) {
829 if(has_attrib(i) && !vattr[i].vbo_valid) {
830 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
831 glBufferData(GL_ARRAY_BUFFER, nverts * vattr[i].nelem * sizeof(float), &vattr[i].data[0], GL_STATIC_DRAW);
832 vattr[i].vbo_valid = true;
833 }
834 }
835 glBindBuffer(GL_ARRAY_BUFFER, 0);
837 if(idata_valid && !ibo_valid) {
838 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
839 glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 3 * sizeof(unsigned int), &idata[0], GL_STATIC_DRAW);
840 ibo_valid = true;
841 }
842 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
843 }
845 void Mesh::update_wire_ibo()
846 {
847 update_buffers();
849 if(wire_ibo_valid) {
850 return;
851 }
853 if(!wire_ibo) {
854 glGenBuffers(1, &wire_ibo);
855 }
857 unsigned int *wire_idxarr = new unsigned int[nfaces * 6];
858 unsigned int *dest = wire_idxarr;
860 if(ibo_valid) {
861 // we're dealing with an indexed mesh
862 const unsigned int *idxarr = ((const Mesh*)this)->get_index_data();
864 for(unsigned int i=0; i<nfaces; i++) {
865 *dest++ = idxarr[0];
866 *dest++ = idxarr[1];
867 *dest++ = idxarr[1];
868 *dest++ = idxarr[2];
869 *dest++ = idxarr[2];
870 *dest++ = idxarr[0];
871 idxarr += 3;
872 }
873 } else {
874 // not an indexed mesh ...
875 for(unsigned int i=0; i<nfaces; i++) {
876 int vidx = i * 3;
877 *dest++ = vidx;
878 *dest++ = vidx + 1;
879 *dest++ = vidx + 1;
880 *dest++ = vidx + 2;
881 *dest++ = vidx + 2;
882 *dest++ = vidx;
883 }
884 }
886 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
887 glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 6 * sizeof(unsigned int), wire_idxarr, GL_STATIC_DRAW);
888 delete [] wire_idxarr;
889 wire_ibo_valid = true;
890 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
891 }
894 // ------ class Triangle ------
895 Triangle::Triangle()
896 {
897 normal_valid = false;
898 id = -1;
899 }
901 Triangle::Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2)
902 {
903 v[0] = v0;
904 v[1] = v1;
905 v[2] = v2;
906 normal_valid = false;
907 id = -1;
908 }
910 Triangle::Triangle(int n, const Vector3 *varr, const unsigned int *idxarr)
911 {
912 if(idxarr) {
913 v[0] = varr[idxarr[n * 3]];
914 v[1] = varr[idxarr[n * 3 + 1]];
915 v[2] = varr[idxarr[n * 3 + 2]];
916 } else {
917 v[0] = varr[n * 3];
918 v[1] = varr[n * 3 + 1];
919 v[2] = varr[n * 3 + 2];
920 }
921 normal_valid = false;
922 id = n;
923 }
925 void Triangle::calc_normal()
926 {
927 normal = cross_product(v[1] - v[0], v[2] - v[0]).normalized();
928 normal_valid = true;
929 }
931 const Vector3 &Triangle::get_normal() const
932 {
933 if(!normal_valid) {
934 ((Triangle*)this)->calc_normal();
935 }
936 return normal;
937 }
939 void Triangle::transform(const Matrix4x4 &xform)
940 {
941 v[0].transform(xform);
942 v[1].transform(xform);
943 v[2].transform(xform);
944 normal_valid = false;
945 }
947 void Triangle::draw() const
948 {
949 Vector3 n[3];
950 n[0] = get_normal();
951 n[1] = get_normal();
952 n[2] = get_normal();
954 int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
955 int nloc = Mesh::get_attrib_location(MESH_ATTR_NORMAL);
957 glEnableVertexAttribArray(vloc);
958 glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
959 glVertexAttribPointer(nloc, 3, GL_FLOAT, GL_FALSE, 0, &n[0].x);
961 glDrawArrays(GL_TRIANGLES, 0, 3);
963 glDisableVertexAttribArray(vloc);
964 glDisableVertexAttribArray(nloc);
965 CHECKGLERR;
966 }
968 void Triangle::draw_wire() const
969 {
970 static const int idxarr[] = {0, 1, 1, 2, 2, 0};
971 int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
973 glEnableVertexAttribArray(vloc);
974 glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
976 glDrawElements(GL_LINES, 6, GL_UNSIGNED_INT, idxarr);
978 glDisableVertexAttribArray(vloc);
979 CHECKGLERR;
980 }
982 Vector3 Triangle::calc_barycentric(const Vector3 &pos) const
983 {
984 Vector3 norm = get_normal();
986 float area_sq = fabs(dot_product(cross_product(v[1] - v[0], v[2] - v[0]), norm));
987 if(area_sq < 1e-5) {
988 return Vector3(0, 0, 0);
989 }
991 float asq0 = fabs(dot_product(cross_product(v[1] - pos, v[2] - pos), norm));
992 float asq1 = fabs(dot_product(cross_product(v[2] - pos, v[0] - pos), norm));
993 float asq2 = fabs(dot_product(cross_product(v[0] - pos, v[1] - pos), norm));
995 return Vector3(asq0 / area_sq, asq1 / area_sq, asq2 / area_sq);
996 }
998 bool Triangle::intersect(const Ray &ray, HitPoint *hit) const
999 {
1000 Vector3 normal = get_normal();
1002 float ndotdir = dot_product(ray.dir, normal);
1003 if(fabs(ndotdir) < 1e-4) {
1004 return false;
1007 Vector3 vertdir = v[0] - ray.origin;
1008 float t = dot_product(normal, vertdir) / ndotdir;
1010 Vector3 pos = ray.origin + ray.dir * t;
1011 Vector3 bary = calc_barycentric(pos);
1013 if(bary.x + bary.y + bary.z > 1.00001) {
1014 return false;
1017 if(hit) {
1018 hit->dist = t;
1019 hit->pos = ray.origin + ray.dir * t;
1020 hit->normal = normal;
1021 hit->obj = this;
1023 return true;