tavli

view src/mesh.cc @ 12:ae1c60726c41

better pieces
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 27 Jun 2015 13:53:43 +0300
parents f1ecc2439802
children b1a195c3ee16
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"
9 #define USE_OLDGL
11 int Mesh::global_sdr_loc[NUM_MESH_ATTR] = { 0, 1, 2, 3, 4, 5, 6 };
12 /*
13 (int)SDR_ATTR_VERTEX,
14 (int)SDR_ATTR_NORMAL,
15 (int)SDR_ATTR_TANGENT,
16 (int)SDR_ATTR_TEXCOORD,
17 (int)SDR_ATTR_COLOR,
18 -1, -1};
19 */
20 unsigned int Mesh::intersect_mode = ISECT_DEFAULT;
21 float Mesh::vertex_sel_dist = 0.01;
22 float Mesh::vis_vecsize = 1.0;
24 Mesh::Mesh()
25 {
26 clear();
28 glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects);
30 for(int i=0; i<NUM_MESH_ATTR; i++) {
31 vattr[i].vbo = buffer_objects[i];
32 }
33 ibo = buffer_objects[NUM_MESH_ATTR];
34 wire_ibo = 0;
35 }
37 Mesh::~Mesh()
38 {
39 glDeleteBuffers(NUM_MESH_ATTR + 1, buffer_objects);
41 if(wire_ibo) {
42 glDeleteBuffers(1, &wire_ibo);
43 }
44 }
46 Mesh::Mesh(const Mesh &rhs)
47 {
48 clear();
50 glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects);
52 for(int i=0; i<NUM_MESH_ATTR; i++) {
53 vattr[i].vbo = buffer_objects[i];
54 }
55 ibo = buffer_objects[NUM_MESH_ATTR];
56 wire_ibo = 0;
58 clone(rhs);
59 }
61 Mesh &Mesh::operator =(const Mesh &rhs)
62 {
63 if(&rhs != this) {
64 clone(rhs);
65 }
66 return *this;
67 }
69 bool Mesh::clone(const Mesh &m)
70 {
71 clear();
73 for(int i=0; i<NUM_MESH_ATTR; i++) {
74 if(m.has_attrib(i)) {
75 m.get_attrib_data(i); // force validation of the actual data on the source mesh
77 vattr[i].nelem = m.vattr[i].nelem;
78 vattr[i].data = m.vattr[i].data; // copy the actual data
79 vattr[i].data_valid = true;
80 }
81 }
83 if(m.is_indexed()) {
84 m.get_index_data(); // again, force validation
86 // copy the index data
87 idata = m.idata;
88 idata_valid = true;
89 }
91 name = m.name;
92 nverts = m.nverts;
93 nfaces = m.nfaces;
95 //bones = m.bones;
97 memcpy(cur_val, m.cur_val, sizeof cur_val);
99 aabb = m.aabb;
100 aabb_valid = m.aabb_valid;
101 bsph = m.bsph;
102 bsph_valid = m.bsph_valid;
104 hitface = m.hitface;
105 hitvert = m.hitvert;
107 intersect_mode = m.intersect_mode;
108 vertex_sel_dist = m.vertex_sel_dist;
109 vis_vecsize = m.vis_vecsize;
111 return true;
112 }
114 void Mesh::set_name(const char *name)
115 {
116 this->name = name;
117 }
119 const char *Mesh::get_name() const
120 {
121 return name.c_str();
122 }
124 bool Mesh::has_attrib(int attr) const
125 {
126 if(attr < 0 || attr >= NUM_MESH_ATTR) {
127 return false;
128 }
130 // if neither of these is valid, then nobody has set this attribute
131 return vattr[attr].vbo_valid || vattr[attr].data_valid;
132 }
134 bool Mesh::is_indexed() const
135 {
136 return ibo_valid || idata_valid;
137 }
139 void Mesh::clear()
140 {
141 //bones.clear();
143 for(int i=0; i<NUM_MESH_ATTR; i++) {
144 vattr[i].nelem = 0;
145 vattr[i].vbo_valid = false;
146 vattr[i].data_valid = false;
147 //vattr[i].sdr_loc = -1;
148 vattr[i].data.clear();
149 }
150 ibo_valid = idata_valid = false;
151 idata.clear();
153 wire_ibo_valid = false;
155 nverts = nfaces = 0;
157 bsph_valid = false;
158 aabb_valid = false;
159 }
161 float *Mesh::set_attrib_data(int attrib, int nelem, unsigned int num, const float *data)
162 {
163 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
164 fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
165 return 0;
166 }
168 if(nverts && num != nverts) {
169 fprintf(stderr, "%s: attribute count missmatch (%d instead of %d)\n", __FUNCTION__, num, nverts);
170 return 0;
171 }
172 nverts = num;
174 vattr[attrib].data.clear();
175 vattr[attrib].nelem = nelem;
176 vattr[attrib].data.resize(num * nelem);
178 if(data) {
179 memcpy(&vattr[attrib].data[0], data, num * nelem * sizeof *data);
180 }
182 vattr[attrib].data_valid = true;
183 vattr[attrib].vbo_valid = false;
184 return &vattr[attrib].data[0];
185 }
187 float *Mesh::get_attrib_data(int attrib)
188 {
189 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
190 fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
191 return 0;
192 }
194 vattr[attrib].vbo_valid = false;
195 return (float*)((const Mesh*)this)->get_attrib_data(attrib);
196 }
198 const float *Mesh::get_attrib_data(int attrib) const
199 {
200 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
201 fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
202 return 0;
203 }
205 if(!vattr[attrib].data_valid) {
206 #if GL_ES_VERSION_2_0
207 fprintf(stderr, "%s: can't read back attrib data on CrippledGL ES\n", __FUNCTION__);
208 return 0;
209 #else
210 if(!vattr[attrib].vbo_valid) {
211 fprintf(stderr, "%s: unavailable attrib: %d\n", __FUNCTION__, attrib);
212 return 0;
213 }
215 // local data copy is unavailable, grab the data from the vbo
216 Mesh *m = (Mesh*)this;
217 m->vattr[attrib].data.resize(nverts * vattr[attrib].nelem);
219 glBindBuffer(GL_ARRAY_BUFFER, vattr[attrib].vbo);
220 void *data = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
221 memcpy(&m->vattr[attrib].data[0], data, nverts * vattr[attrib].nelem * sizeof(float));
222 glUnmapBuffer(GL_ARRAY_BUFFER);
224 vattr[attrib].data_valid = true;
225 #endif
226 }
228 return &vattr[attrib].data[0];
229 }
231 void Mesh::set_attrib(int attrib, int idx, const Vector4 &v)
232 {
233 float *data = get_attrib_data(attrib);
234 if(data) {
235 data += idx * vattr[attrib].nelem;
236 for(int i=0; i<vattr[attrib].nelem; i++) {
237 data[i] = v[i];
238 }
239 }
240 }
242 Vector4 Mesh::get_attrib(int attrib, int idx) const
243 {
244 Vector4 v(0.0, 0.0, 0.0, 1.0);
245 const float *data = get_attrib_data(attrib);
246 if(data) {
247 data += idx * vattr[attrib].nelem;
248 for(int i=0; i<vattr[attrib].nelem; i++) {
249 v[i] = data[i];
250 }
251 }
252 return v;
253 }
255 int Mesh::get_attrib_count(int attrib) const
256 {
257 return has_attrib(attrib) ? nverts : 0;
258 }
261 unsigned int *Mesh::set_index_data(int num, const unsigned int *indices)
262 {
263 int nidx = nfaces * 3;
264 if(nidx && num != nidx) {
265 fprintf(stderr, "%s: index count missmatch (%d instead of %d)\n", __FUNCTION__, num, nidx);
266 return 0;
267 }
268 nfaces = num / 3;
270 idata.clear();
271 idata.resize(num);
273 if(indices) {
274 memcpy(&idata[0], indices, num * sizeof *indices);
275 }
277 idata_valid = true;
278 ibo_valid = false;
280 return &idata[0];
281 }
283 unsigned int *Mesh::get_index_data()
284 {
285 ibo_valid = false;
286 return (unsigned int*)((const Mesh*)this)->get_index_data();
287 }
289 const unsigned int *Mesh::get_index_data() const
290 {
291 if(!idata_valid) {
292 #if GL_ES_VERSION_2_0
293 fprintf(stderr, "%s: can't read back index data in CrippledGL ES\n", __FUNCTION__);
294 return 0;
295 #else
296 if(!ibo_valid) {
297 fprintf(stderr, "%s: indices unavailable\n", __FUNCTION__);
298 return 0;
299 }
301 // local data copy is unavailable, gram the data from the ibo
302 Mesh *m = (Mesh*)this;
303 int nidx = nfaces * 3;
304 m->idata.resize(nidx);
306 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
307 void *data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY);
308 memcpy(&m->idata[0], data, nidx * sizeof(unsigned int));
309 glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
311 idata_valid = true;
312 #endif
313 }
315 return &idata[0];
316 }
318 int Mesh::get_index_count() const
319 {
320 return nfaces * 3;
321 }
323 void Mesh::append(const Mesh &mesh)
324 {
325 unsigned int idxoffs = nverts;
327 if(!nverts) {
328 clone(mesh);
329 return;
330 }
332 nverts += mesh.nverts;
333 nfaces += mesh.nfaces;
335 for(int i=0; i<NUM_MESH_ATTR; i++) {
336 if(has_attrib(i) && mesh.has_attrib(i)) {
337 // force validating the data arrays
338 get_attrib_data(i);
339 mesh.get_attrib_data(i);
341 // append the mesh data
342 vattr[i].data.insert(vattr[i].data.end(), mesh.vattr[i].data.begin(), mesh.vattr[i].data.end());
343 }
344 }
346 if(ibo_valid || idata_valid) {
347 // make index arrays valid
348 get_index_data();
349 mesh.get_index_data();
351 size_t orig_sz = idata.size();
353 idata.insert(idata.end(), mesh.idata.begin(), mesh.idata.end());
355 // fixup all the new indices
356 for(size_t i=orig_sz; i<idata.size(); i++) {
357 idata[i] += idxoffs;
358 }
359 }
361 // fuck everything
362 wire_ibo_valid = false;
363 aabb_valid = false;
364 bsph_valid = false;
365 }
367 // assemble a complete vertex by adding all the useful attributes
368 void Mesh::vertex(float x, float y, float z)
369 {
370 cur_val[MESH_ATTR_VERTEX] = Vector4(x, y, z, 1.0f);
371 vattr[MESH_ATTR_VERTEX].data_valid = true;
372 vattr[MESH_ATTR_VERTEX].nelem = 3;
374 for(int i=0; i<NUM_MESH_ATTR; i++) {
375 if(vattr[i].data_valid) {
376 for(int j=0; j<vattr[MESH_ATTR_VERTEX].nelem; j++) {
377 vattr[i].data.push_back(cur_val[i][j]);
378 }
379 }
380 vattr[i].vbo_valid = false;
381 }
383 if(idata_valid) {
384 idata.clear();
385 }
386 ibo_valid = idata_valid = false;
387 }
389 void Mesh::normal(float nx, float ny, float nz)
390 {
391 cur_val[MESH_ATTR_NORMAL] = Vector4(nx, ny, nz, 1.0f);
392 vattr[MESH_ATTR_NORMAL].data_valid = true;
393 vattr[MESH_ATTR_NORMAL].nelem = 3;
394 }
396 void Mesh::tangent(float tx, float ty, float tz)
397 {
398 cur_val[MESH_ATTR_TANGENT] = Vector4(tx, ty, tz, 1.0f);
399 vattr[MESH_ATTR_TANGENT].data_valid = true;
400 vattr[MESH_ATTR_TANGENT].nelem = 3;
401 }
403 void Mesh::texcoord(float u, float v, float w)
404 {
405 cur_val[MESH_ATTR_TEXCOORD] = Vector4(u, v, w, 1.0f);
406 vattr[MESH_ATTR_TEXCOORD].data_valid = true;
407 vattr[MESH_ATTR_TEXCOORD].nelem = 3;
408 }
410 void Mesh::boneweights(float w1, float w2, float w3, float w4)
411 {
412 cur_val[MESH_ATTR_BONEWEIGHTS] = Vector4(w1, w2, w3, w4);
413 vattr[MESH_ATTR_BONEWEIGHTS].data_valid = true;
414 vattr[MESH_ATTR_BONEWEIGHTS].nelem = 4;
415 }
417 void Mesh::boneidx(int idx1, int idx2, int idx3, int idx4)
418 {
419 cur_val[MESH_ATTR_BONEIDX] = Vector4(idx1, idx2, idx3, idx4);
420 vattr[MESH_ATTR_BONEIDX].data_valid = true;
421 vattr[MESH_ATTR_BONEIDX].nelem = 4;
422 }
424 int Mesh::get_poly_count() const
425 {
426 if(nfaces) {
427 return nfaces;
428 }
429 if(nverts) {
430 return nverts / 3;
431 }
432 return 0;
433 }
435 /// static function
436 void Mesh::set_attrib_location(int attr, int loc)
437 {
438 if(attr < 0 || attr >= NUM_MESH_ATTR) {
439 return;
440 }
441 Mesh::global_sdr_loc[attr] = loc;
442 }
444 /// static function
445 int Mesh::get_attrib_location(int attr)
446 {
447 if(attr < 0 || attr >= NUM_MESH_ATTR) {
448 return -1;
449 }
450 return Mesh::global_sdr_loc[attr];
451 }
453 /// static function
454 void Mesh::clear_attrib_locations()
455 {
456 for(int i=0; i<NUM_MESH_ATTR; i++) {
457 Mesh::global_sdr_loc[i] = -1;
458 }
459 }
461 /// static function
462 void Mesh::set_vis_vecsize(float sz)
463 {
464 Mesh::vis_vecsize = sz;
465 }
467 float Mesh::get_vis_vecsize()
468 {
469 return Mesh::vis_vecsize;
470 }
472 void Mesh::apply_xform(const Matrix4x4 &xform)
473 {
474 Matrix4x4 dir_xform = xform;
475 dir_xform[0][3] = dir_xform[1][3] = dir_xform[2][3] = 0.0f;
476 dir_xform[3][0] = dir_xform[3][1] = dir_xform[3][2] = 0.0f;
477 dir_xform[3][3] = 1.0f;
479 apply_xform(xform, dir_xform);
480 }
482 void Mesh::apply_xform(const Matrix4x4 &xform, const Matrix4x4 &dir_xform)
483 {
484 for(unsigned int i=0; i<nverts; i++) {
485 Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
486 set_attrib(MESH_ATTR_VERTEX, i, v.transformed(xform));
488 if(has_attrib(MESH_ATTR_NORMAL)) {
489 Vector3 n = get_attrib(MESH_ATTR_NORMAL, i);
490 set_attrib(MESH_ATTR_NORMAL, i, n.transformed(dir_xform));
491 }
492 if(has_attrib(MESH_ATTR_TANGENT)) {
493 Vector3 t = get_attrib(MESH_ATTR_TANGENT, i);
494 set_attrib(MESH_ATTR_TANGENT, i, t.transformed(dir_xform));
495 }
496 }
497 }
499 void Mesh::flip()
500 {
501 flip_faces();
502 flip_normals();
503 }
505 void Mesh::flip_faces()
506 {
507 if(is_indexed()) {
508 unsigned int *indices = get_index_data();
509 if(!indices) return;
511 int idxnum = get_index_count();
512 for(int i=0; i<idxnum; i+=3) {
513 unsigned int tmp = indices[i + 2];
514 indices[i + 2] = indices[i + 1];
515 indices[i + 1] = tmp;
516 }
518 } else {
519 Vector3 *verts = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
520 if(!verts) return;
522 int vnum = get_attrib_count(MESH_ATTR_VERTEX);
523 for(int i=0; i<vnum; i+=3) {
524 Vector3 tmp = verts[i + 2];
525 verts[i + 2] = verts[i + 1];
526 verts[i + 1] = tmp;
527 }
528 }
529 }
531 void Mesh::flip_normals()
532 {
533 Vector3 *normals = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
534 if(!normals) return;
536 int num = get_attrib_count(MESH_ATTR_NORMAL);
537 for(int i=0; i<num; i++) {
538 normals[i] = -normals[i];
539 }
540 }
542 /*
543 int Mesh::add_bone(XFormNode *bone)
544 {
545 int idx = bones.size();
546 bones.push_back(bone);
547 return idx;
548 }
550 const XFormNode *Mesh::get_bone(int idx) const
551 {
552 if(idx < 0 || idx >= (int)bones.size()) {
553 return 0;
554 }
555 return bones[idx];
556 }
558 int Mesh::get_bones_count() const
559 {
560 return (int)bones.size();
561 }
562 */
564 void Mesh::draw() const
565 {
566 int cur_sdr;
567 glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
570 ((Mesh*)this)->update_buffers();
572 if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
573 fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
574 return;
575 }
577 if(cur_sdr) {
578 // rendering with shaders
579 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
580 fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__);
581 return;
582 }
584 for(int i=0; i<NUM_MESH_ATTR; i++) {
585 int loc = global_sdr_loc[i];
586 if(loc >= 0 && vattr[i].vbo_valid) {
587 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
588 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
589 glEnableVertexAttribArray(loc);
590 }
591 }
592 } else {
593 #ifndef GL_ES_VERSION_2_0
594 // rendering with fixed-function (not available in GLES2)
595 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_VERTEX].vbo);
596 glVertexPointer(vattr[MESH_ATTR_VERTEX].nelem, GL_FLOAT, 0, 0);
597 glEnableClientState(GL_VERTEX_ARRAY);
599 if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
600 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_NORMAL].vbo);
601 glNormalPointer(GL_FLOAT, 0, 0);
602 glEnableClientState(GL_NORMAL_ARRAY);
603 }
604 if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
605 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_TEXCOORD].vbo);
606 glTexCoordPointer(vattr[MESH_ATTR_TEXCOORD].nelem, GL_FLOAT, 0, 0);
607 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
608 }
609 if(vattr[MESH_ATTR_COLOR].vbo_valid) {
610 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_COLOR].vbo);
611 glColorPointer(vattr[MESH_ATTR_COLOR].nelem, GL_FLOAT, 0, 0);
612 glEnableClientState(GL_COLOR_ARRAY);
613 }
614 #endif
615 }
616 glBindBuffer(GL_ARRAY_BUFFER, 0);
618 if(ibo_valid) {
619 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
620 glDrawElements(GL_TRIANGLES, nfaces * 3, GL_UNSIGNED_INT, 0);
621 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
622 } else {
623 glDrawArrays(GL_TRIANGLES, 0, nverts);
624 }
626 if(cur_sdr) {
627 // rendered with shaders
628 for(int i=0; i<NUM_MESH_ATTR; i++) {
629 int loc = global_sdr_loc[i];
630 if(loc >= 0 && vattr[i].vbo_valid) {
631 glDisableVertexAttribArray(loc);
632 }
633 }
634 } else {
635 #ifndef GL_ES_VERSION_2_0
636 // rendered with fixed-function
637 glDisableClientState(GL_VERTEX_ARRAY);
638 if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
639 glDisableClientState(GL_NORMAL_ARRAY);
640 }
641 if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
642 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
643 }
644 if(vattr[MESH_ATTR_COLOR].vbo_valid) {
645 glDisableClientState(GL_COLOR_ARRAY);
646 }
647 #endif
648 }
649 }
651 void Mesh::draw_wire() const
652 {
653 ((Mesh*)this)->update_wire_ibo();
655 if(!vattr[MESH_ATTR_VERTEX].vbo_valid || !wire_ibo_valid) {
656 fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
657 return;
658 }
659 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
660 fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__);
661 return;
662 }
664 for(int i=0; i<NUM_MESH_ATTR; i++) {
665 int loc = global_sdr_loc[i];
666 if(loc >= 0 && vattr[i].vbo_valid) {
667 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
668 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
669 glEnableVertexAttribArray(loc);
670 }
671 }
672 glBindBuffer(GL_ARRAY_BUFFER, 0);
674 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
675 glDrawElements(GL_LINES, nfaces * 6, GL_UNSIGNED_INT, 0);
676 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
678 for(int i=0; i<NUM_MESH_ATTR; i++) {
679 int loc = global_sdr_loc[i];
680 if(loc >= 0 && vattr[i].vbo_valid) {
681 glDisableVertexAttribArray(loc);
682 }
683 }
684 }
686 void Mesh::draw_vertices() const
687 {
688 ((Mesh*)this)->update_buffers();
690 if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
691 fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
692 return;
693 }
694 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
695 fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__);
696 return;
697 }
699 for(int i=0; i<NUM_MESH_ATTR; i++) {
700 int loc = global_sdr_loc[i];
701 if(loc >= 0 && vattr[i].vbo_valid) {
702 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
703 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
704 glEnableVertexAttribArray(loc);
705 }
706 }
707 glBindBuffer(GL_ARRAY_BUFFER, 0);
709 glDrawArrays(GL_POINTS, 0, nverts);
711 for(int i=0; i<NUM_MESH_ATTR; i++) {
712 int loc = global_sdr_loc[i];
713 if(loc >= 0 && vattr[i].vbo_valid) {
714 glDisableVertexAttribArray(loc);
715 }
716 }
717 }
719 void Mesh::draw_normals() const
720 {
721 #ifdef USE_OLDGL
722 int cur_sdr;
723 glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
725 Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
726 Vector3 *norm = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
727 if(!varr || !norm) {
728 return;
729 }
731 glBegin(GL_LINES);
732 if(cur_sdr) {
733 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
734 if(vert_loc < 0) {
735 glEnd();
736 return;
737 }
739 for(size_t i=0; i<nverts; i++) {
740 glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
741 Vector3 end = varr[i] + norm[i] * vis_vecsize;
742 glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
743 }
744 } else {
745 for(size_t i=0; i<nverts; i++) {
746 glVertex3f(varr[i].x, varr[i].y, varr[i].z);
747 Vector3 end = varr[i] + norm[i] * vis_vecsize;
748 glVertex3f(end.x, end.y, end.z);
749 }
750 }
751 glEnd();
752 #endif // USE_OLDGL
753 }
755 void Mesh::draw_tangents() const
756 {
757 #ifdef USE_OLDGL
758 int cur_sdr;
759 glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
761 Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
762 Vector3 *tang = (Vector3*)get_attrib_data(MESH_ATTR_TANGENT);
763 if(!varr || !tang) {
764 return;
765 }
767 glBegin(GL_LINES);
768 if(cur_sdr) {
769 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
770 if(vert_loc < 0) {
771 glEnd();
772 return;
773 }
775 for(size_t i=0; i<nverts; i++) {
776 glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
777 Vector3 end = varr[i] + tang[i] * vis_vecsize;
778 glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
779 }
780 } else {
781 for(size_t i=0; i<nverts; i++) {
782 glVertex3f(varr[i].x, varr[i].y, varr[i].z);
783 Vector3 end = varr[i] + tang[i] * vis_vecsize;
784 glVertex3f(end.x, end.y, end.z);
785 }
786 }
787 glEnd();
788 #endif // USE_OLDGL
789 }
791 void Mesh::get_aabbox(Vector3 *vmin, Vector3 *vmax) const
792 {
793 if(!aabb_valid) {
794 ((Mesh*)this)->calc_aabb();
795 }
796 *vmin = aabb.min;
797 *vmax = aabb.max;
798 }
800 const AABox &Mesh::get_aabbox() const
801 {
802 if(!aabb_valid) {
803 ((Mesh*)this)->calc_aabb();
804 }
805 return aabb;
806 }
808 float Mesh::get_bsphere(Vector3 *center, float *rad) const
809 {
810 if(!bsph_valid) {
811 ((Mesh*)this)->calc_bsph();
812 }
813 *center = bsph.center;
814 *rad = bsph.radius;
815 return bsph.radius;
816 }
818 const Sphere &Mesh::get_bsphere() const
819 {
820 if(!bsph_valid) {
821 ((Mesh*)this)->calc_bsph();
822 }
823 return bsph;
824 }
826 /// static function
827 void Mesh::set_intersect_mode(unsigned int mode)
828 {
829 Mesh::intersect_mode = mode;
830 }
832 /// static function
833 unsigned int Mesh::get_intersect_mode()
834 {
835 return Mesh::intersect_mode;
836 }
838 /// static function
839 void Mesh::set_vertex_select_distance(float dist)
840 {
841 Mesh::vertex_sel_dist = dist;
842 }
844 /// static function
845 float Mesh::get_vertex_select_distance()
846 {
847 return Mesh::vertex_sel_dist;
848 }
850 bool Mesh::intersect(const Ray &ray, HitPoint *hit) const
851 {
852 assert((Mesh::intersect_mode & (ISECT_VERTICES | ISECT_FACE)) != (ISECT_VERTICES | ISECT_FACE));
854 const Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
855 const Vector3 *narr = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
856 if(!varr) {
857 return false;
858 }
859 const unsigned int *idxarr = get_index_data();
861 // first test with the bounding box
862 AABox box;
863 get_aabbox(&box.min, &box.max);
864 if(!box.intersect(ray)) {
865 return false;
866 }
868 HitPoint nearest_hit;
869 nearest_hit.dist = FLT_MAX;
870 nearest_hit.obj = 0;
872 if(Mesh::intersect_mode & ISECT_VERTICES) {
873 // we asked for "intersections" with the vertices of the mesh
874 long nearest_vidx = -1;
875 float thres_sq = Mesh::vertex_sel_dist * Mesh::vertex_sel_dist;
877 for(unsigned int i=0; i<nverts; i++) {
879 if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(narr[i], ray.dir) > 0) {
880 continue;
881 }
883 // project the vertex onto the ray line
884 float t = dot_product(varr[i] - ray.origin, ray.dir);
885 Vector3 vproj = ray.origin + ray.dir * t;
887 float dist_sq = (vproj - varr[i]).length_sq();
888 if(dist_sq < thres_sq) {
889 if(!hit) {
890 return true;
891 }
892 if(t < nearest_hit.dist) {
893 nearest_hit.dist = t;
894 nearest_vidx = i;
895 }
896 }
897 }
899 if(nearest_vidx != -1) {
900 hitvert = varr[nearest_vidx];
901 nearest_hit.obj = &hitvert;
902 }
904 } else {
905 // regular intersection test with polygons
907 for(unsigned int i=0; i<nfaces; i++) {
908 Triangle face(i, varr, idxarr);
910 // ignore back-facing polygons if the mode flags include ISECT_FRONT
911 if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(face.get_normal(), ray.dir) > 0) {
912 continue;
913 }
915 HitPoint fhit;
916 if(face.intersect(ray, hit ? &fhit : 0)) {
917 if(!hit) {
918 return true;
919 }
920 if(fhit.dist < nearest_hit.dist) {
921 nearest_hit = fhit;
922 hitface = face;
923 }
924 }
925 }
926 }
928 if(nearest_hit.obj) {
929 if(hit) {
930 *hit = nearest_hit;
932 // if we are interested in the mesh and not the faces set obj to this
933 if(Mesh::intersect_mode & ISECT_FACE) {
934 hit->obj = &hitface;
935 } else if(Mesh::intersect_mode & ISECT_VERTICES) {
936 hit->obj = &hitvert;
937 } else {
938 hit->obj = this;
939 }
940 }
941 return true;
942 }
943 return false;
944 }
947 // texture coordinate manipulation
948 void Mesh::texcoord_apply_xform(const Matrix4x4 &xform)
949 {
950 if(!has_attrib(MESH_ATTR_TEXCOORD)) {
951 return;
952 }
954 for(unsigned int i=0; i<nverts; i++) {
955 Vector4 tc = get_attrib(MESH_ATTR_TEXCOORD, i);
956 set_attrib(MESH_ATTR_TEXCOORD, i, tc.transformed(xform));
957 }
958 }
960 void Mesh::texcoord_gen_plane(const Vector3 &norm, const Vector3 &tang)
961 {
962 if(!nverts) return;
964 if(!has_attrib(MESH_ATTR_TEXCOORD)) {
965 // allocate texture coordinate attribute array
966 set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts);
967 }
969 Vector3 n = norm.normalized();
970 Vector3 b = cross_product(n, tang).normalized();
971 Vector3 t = cross_product(b, n);
973 for(unsigned int i=0; i<nverts; i++) {
974 Vector3 pos = get_attrib(MESH_ATTR_VERTEX, i);
976 // distance along the tangent direction
977 float u = dot_product(pos, t);
978 // distance along the bitangent direction
979 float v = dot_product(pos, b);
981 set_attrib(MESH_ATTR_TEXCOORD, i, Vector4(u, v, 0, 1));
982 }
983 }
985 void Mesh::texcoord_gen_box()
986 {
987 if(!nverts || !has_attrib(MESH_ATTR_NORMAL)) return;
989 if(!has_attrib(MESH_ATTR_TEXCOORD)) {
990 // allocate texture coordinate attribute array
991 set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts);
992 }
994 for(unsigned int i=0; i<nverts; i++) {
995 Vector3 pos = Vector3(get_attrib(MESH_ATTR_VERTEX, i)) * 0.5 + Vector3(0.5, 0.5, 0.5);
996 Vector3 norm = get_attrib(MESH_ATTR_NORMAL, i);
998 float abs_nx = fabs(norm.x);
999 float abs_ny = fabs(norm.y);
1000 float abs_nz = fabs(norm.z);
1001 int dom = abs_nx > abs_ny && abs_nx > abs_nz ? 0 : (abs_ny > abs_nz ? 1 : 2);
1003 float uv[2], *uvptr = uv;
1004 for(int j=0; j<3; j++) {
1005 if(j == dom) continue; // skip dominant axis
1007 *uvptr++ = pos[j];
1009 set_attrib(MESH_ATTR_TEXCOORD, i, Vector4(uv[0], uv[1], 0, 1));
1013 // ------ private member functions ------
1015 void Mesh::calc_aabb()
1017 // the cast is to force calling the const version which doesn't invalidate
1018 if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
1019 return;
1022 aabb.min = Vector3(FLT_MAX, FLT_MAX, FLT_MAX);
1023 aabb.max = -aabb.min;
1025 for(unsigned int i=0; i<nverts; i++) {
1026 Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
1027 for(int j=0; j<3; j++) {
1028 if(v[j] < aabb.min[j]) {
1029 aabb.min[j] = v[j];
1031 if(v[j] > aabb.max[j]) {
1032 aabb.max[j] = v[j];
1036 aabb_valid = true;
1039 void Mesh::calc_bsph()
1041 // the cast is to force calling the const version which doesn't invalidate
1042 if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
1043 return;
1046 Vector3 v;
1047 bsph.center = Vector3(0, 0, 0);
1049 // first find the center
1050 for(unsigned int i=0; i<nverts; i++) {
1051 v = get_attrib(MESH_ATTR_VERTEX, i);
1052 bsph.center += v;
1054 bsph.center /= (float)nverts;
1056 bsph.radius = 0.0f;
1057 for(unsigned int i=0; i<nverts; i++) {
1058 v = get_attrib(MESH_ATTR_VERTEX, i);
1059 float dist_sq = (v - bsph.center).length_sq();
1060 if(dist_sq > bsph.radius) {
1061 bsph.radius = dist_sq;
1064 bsph.radius = sqrt(bsph.radius);
1066 bsph_valid = true;
1069 void Mesh::update_buffers()
1071 for(int i=0; i<NUM_MESH_ATTR; i++) {
1072 if(has_attrib(i) && !vattr[i].vbo_valid) {
1073 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
1074 glBufferData(GL_ARRAY_BUFFER, nverts * vattr[i].nelem * sizeof(float), &vattr[i].data[0], GL_STATIC_DRAW);
1075 vattr[i].vbo_valid = true;
1078 glBindBuffer(GL_ARRAY_BUFFER, 0);
1080 if(idata_valid && !ibo_valid) {
1081 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
1082 glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 3 * sizeof(unsigned int), &idata[0], GL_STATIC_DRAW);
1083 ibo_valid = true;
1085 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1088 void Mesh::update_wire_ibo()
1090 update_buffers();
1092 if(wire_ibo_valid) {
1093 return;
1096 if(!wire_ibo) {
1097 glGenBuffers(1, &wire_ibo);
1100 unsigned int *wire_idxarr = new unsigned int[nfaces * 6];
1101 unsigned int *dest = wire_idxarr;
1103 if(ibo_valid) {
1104 // we're dealing with an indexed mesh
1105 const unsigned int *idxarr = ((const Mesh*)this)->get_index_data();
1107 for(unsigned int i=0; i<nfaces; i++) {
1108 *dest++ = idxarr[0];
1109 *dest++ = idxarr[1];
1110 *dest++ = idxarr[1];
1111 *dest++ = idxarr[2];
1112 *dest++ = idxarr[2];
1113 *dest++ = idxarr[0];
1114 idxarr += 3;
1116 } else {
1117 // not an indexed mesh ...
1118 for(unsigned int i=0; i<nfaces; i++) {
1119 int vidx = i * 3;
1120 *dest++ = vidx;
1121 *dest++ = vidx + 1;
1122 *dest++ = vidx + 1;
1123 *dest++ = vidx + 2;
1124 *dest++ = vidx + 2;
1125 *dest++ = vidx;
1129 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
1130 glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 6 * sizeof(unsigned int), wire_idxarr, GL_STATIC_DRAW);
1131 delete [] wire_idxarr;
1132 wire_ibo_valid = true;
1133 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1137 // ------ class Triangle ------
1138 Triangle::Triangle()
1140 normal_valid = false;
1141 id = -1;
1144 Triangle::Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2)
1146 v[0] = v0;
1147 v[1] = v1;
1148 v[2] = v2;
1149 normal_valid = false;
1150 id = -1;
1153 Triangle::Triangle(int n, const Vector3 *varr, const unsigned int *idxarr)
1155 if(idxarr) {
1156 v[0] = varr[idxarr[n * 3]];
1157 v[1] = varr[idxarr[n * 3 + 1]];
1158 v[2] = varr[idxarr[n * 3 + 2]];
1159 } else {
1160 v[0] = varr[n * 3];
1161 v[1] = varr[n * 3 + 1];
1162 v[2] = varr[n * 3 + 2];
1164 normal_valid = false;
1165 id = n;
1168 void Triangle::calc_normal()
1170 normal = cross_product(v[1] - v[0], v[2] - v[0]).normalized();
1171 normal_valid = true;
1174 const Vector3 &Triangle::get_normal() const
1176 if(!normal_valid) {
1177 ((Triangle*)this)->calc_normal();
1179 return normal;
1182 void Triangle::transform(const Matrix4x4 &xform)
1184 v[0].transform(xform);
1185 v[1].transform(xform);
1186 v[2].transform(xform);
1187 normal_valid = false;
1190 void Triangle::draw() const
1192 Vector3 n[3];
1193 n[0] = get_normal();
1194 n[1] = get_normal();
1195 n[2] = get_normal();
1197 int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
1198 int nloc = Mesh::get_attrib_location(MESH_ATTR_NORMAL);
1200 glEnableVertexAttribArray(vloc);
1201 glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
1202 glVertexAttribPointer(nloc, 3, GL_FLOAT, GL_FALSE, 0, &n[0].x);
1204 glDrawArrays(GL_TRIANGLES, 0, 3);
1206 glDisableVertexAttribArray(vloc);
1207 glDisableVertexAttribArray(nloc);
1210 void Triangle::draw_wire() const
1212 static const int idxarr[] = {0, 1, 1, 2, 2, 0};
1213 int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
1215 glEnableVertexAttribArray(vloc);
1216 glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
1218 glDrawElements(GL_LINES, 6, GL_UNSIGNED_INT, idxarr);
1220 glDisableVertexAttribArray(vloc);
1223 Vector3 Triangle::calc_barycentric(const Vector3 &pos) const
1225 Vector3 norm = get_normal();
1227 float area_sq = fabs(dot_product(cross_product(v[1] - v[0], v[2] - v[0]), norm));
1228 if(area_sq < 1e-5) {
1229 return Vector3(0, 0, 0);
1232 float asq0 = fabs(dot_product(cross_product(v[1] - pos, v[2] - pos), norm));
1233 float asq1 = fabs(dot_product(cross_product(v[2] - pos, v[0] - pos), norm));
1234 float asq2 = fabs(dot_product(cross_product(v[0] - pos, v[1] - pos), norm));
1236 return Vector3(asq0 / area_sq, asq1 / area_sq, asq2 / area_sq);
1239 bool Triangle::intersect(const Ray &ray, HitPoint *hit) const
1241 Vector3 normal = get_normal();
1243 float ndotdir = dot_product(ray.dir, normal);
1244 if(fabs(ndotdir) < 1e-4) {
1245 return false;
1248 Vector3 vertdir = v[0] - ray.origin;
1249 float t = dot_product(normal, vertdir) / ndotdir;
1251 Vector3 pos = ray.origin + ray.dir * t;
1252 Vector3 bary = calc_barycentric(pos);
1254 if(bary.x + bary.y + bary.z > 1.00001) {
1255 return false;
1258 if(hit) {
1259 hit->dist = t;
1260 hit->pos = ray.origin + ray.dir * t;
1261 hit->normal = normal;
1262 hit->obj = this;
1264 return true;