tavli

view src/mesh.cc @ 6:a0d30f6f20d4

- texture coordinate generation in class Mesh - wood texture
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 26 Jun 2015 04:22:06 +0300
parents 3fcd7b4d631f
children f1ecc2439802
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 int Mesh::global_sdr_loc[NUM_MESH_ATTR] = { 0, 1, 2, 3, 4, 5, 6 };
10 /*
11 (int)SDR_ATTR_VERTEX,
12 (int)SDR_ATTR_NORMAL,
13 (int)SDR_ATTR_TANGENT,
14 (int)SDR_ATTR_TEXCOORD,
15 (int)SDR_ATTR_COLOR,
16 -1, -1};
17 */
18 unsigned int Mesh::intersect_mode = ISECT_DEFAULT;
19 float Mesh::vertex_sel_dist = 0.01;
20 float Mesh::vis_vecsize = 1.0;
22 Mesh::Mesh()
23 {
24 clear();
26 glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects);
28 for(int i=0; i<NUM_MESH_ATTR; i++) {
29 vattr[i].vbo = buffer_objects[i];
30 }
31 ibo = buffer_objects[NUM_MESH_ATTR];
32 wire_ibo = 0;
33 }
35 Mesh::~Mesh()
36 {
37 glDeleteBuffers(NUM_MESH_ATTR + 1, buffer_objects);
39 if(wire_ibo) {
40 glDeleteBuffers(1, &wire_ibo);
41 }
42 }
44 Mesh::Mesh(const Mesh &rhs)
45 {
46 clear();
48 glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects);
50 for(int i=0; i<NUM_MESH_ATTR; i++) {
51 vattr[i].vbo = buffer_objects[i];
52 }
53 ibo = buffer_objects[NUM_MESH_ATTR];
54 wire_ibo = 0;
56 clone(rhs);
57 }
59 Mesh &Mesh::operator =(const Mesh &rhs)
60 {
61 if(&rhs != this) {
62 clone(rhs);
63 }
64 return *this;
65 }
67 bool Mesh::clone(const Mesh &m)
68 {
69 clear();
71 for(int i=0; i<NUM_MESH_ATTR; i++) {
72 if(m.has_attrib(i)) {
73 m.get_attrib_data(i); // force validation of the actual data on the source mesh
75 vattr[i].nelem = m.vattr[i].nelem;
76 vattr[i].data = m.vattr[i].data; // copy the actual data
77 vattr[i].data_valid = true;
78 }
79 }
81 if(m.is_indexed()) {
82 m.get_index_data(); // again, force validation
84 // copy the index data
85 idata = m.idata;
86 idata_valid = true;
87 }
89 name = m.name;
90 nverts = m.nverts;
91 nfaces = m.nfaces;
93 //bones = m.bones;
95 memcpy(cur_val, m.cur_val, sizeof cur_val);
97 aabb = m.aabb;
98 aabb_valid = m.aabb_valid;
99 bsph = m.bsph;
100 bsph_valid = m.bsph_valid;
102 hitface = m.hitface;
103 hitvert = m.hitvert;
105 intersect_mode = m.intersect_mode;
106 vertex_sel_dist = m.vertex_sel_dist;
107 vis_vecsize = m.vis_vecsize;
109 return true;
110 }
112 void Mesh::set_name(const char *name)
113 {
114 this->name = name;
115 }
117 const char *Mesh::get_name() const
118 {
119 return name.c_str();
120 }
122 bool Mesh::has_attrib(int attr) const
123 {
124 if(attr < 0 || attr >= NUM_MESH_ATTR) {
125 return false;
126 }
128 // if neither of these is valid, then nobody has set this attribute
129 return vattr[attr].vbo_valid || vattr[attr].data_valid;
130 }
132 bool Mesh::is_indexed() const
133 {
134 return ibo_valid || idata_valid;
135 }
137 void Mesh::clear()
138 {
139 //bones.clear();
141 for(int i=0; i<NUM_MESH_ATTR; i++) {
142 vattr[i].nelem = 0;
143 vattr[i].vbo_valid = false;
144 vattr[i].data_valid = false;
145 //vattr[i].sdr_loc = -1;
146 vattr[i].data.clear();
147 }
148 ibo_valid = idata_valid = false;
149 idata.clear();
151 wire_ibo_valid = false;
153 nverts = nfaces = 0;
155 bsph_valid = false;
156 aabb_valid = false;
157 }
159 float *Mesh::set_attrib_data(int attrib, int nelem, unsigned int num, const float *data)
160 {
161 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
162 fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
163 return 0;
164 }
166 if(nverts && num != nverts) {
167 fprintf(stderr, "%s: attribute count missmatch (%d instead of %d)\n", __FUNCTION__, num, nverts);
168 return 0;
169 }
170 nverts = num;
172 vattr[attrib].data.clear();
173 vattr[attrib].nelem = nelem;
174 vattr[attrib].data.resize(num * nelem);
176 if(data) {
177 memcpy(&vattr[attrib].data[0], data, num * nelem * sizeof *data);
178 }
180 vattr[attrib].data_valid = true;
181 vattr[attrib].vbo_valid = false;
182 return &vattr[attrib].data[0];
183 }
185 float *Mesh::get_attrib_data(int attrib)
186 {
187 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
188 fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
189 return 0;
190 }
192 vattr[attrib].vbo_valid = false;
193 return (float*)((const Mesh*)this)->get_attrib_data(attrib);
194 }
196 const float *Mesh::get_attrib_data(int attrib) const
197 {
198 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
199 fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
200 return 0;
201 }
203 if(!vattr[attrib].data_valid) {
204 #if GL_ES_VERSION_2_0
205 fprintf(stderr, "%s: can't read back attrib data on CrippledGL ES\n", __FUNCTION__);
206 return 0;
207 #else
208 if(!vattr[attrib].vbo_valid) {
209 fprintf(stderr, "%s: unavailable attrib: %d\n", __FUNCTION__, attrib);
210 return 0;
211 }
213 // local data copy is unavailable, grab the data from the vbo
214 Mesh *m = (Mesh*)this;
215 m->vattr[attrib].data.resize(nverts * vattr[attrib].nelem);
217 glBindBuffer(GL_ARRAY_BUFFER, vattr[attrib].vbo);
218 void *data = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
219 memcpy(&m->vattr[attrib].data[0], data, nverts * vattr[attrib].nelem * sizeof(float));
220 glUnmapBuffer(GL_ARRAY_BUFFER);
222 vattr[attrib].data_valid = true;
223 #endif
224 }
226 return &vattr[attrib].data[0];
227 }
229 void Mesh::set_attrib(int attrib, int idx, const Vector4 &v)
230 {
231 float *data = get_attrib_data(attrib);
232 if(data) {
233 data += idx * vattr[attrib].nelem;
234 for(int i=0; i<vattr[attrib].nelem; i++) {
235 data[i] = v[i];
236 }
237 }
238 }
240 Vector4 Mesh::get_attrib(int attrib, int idx) const
241 {
242 Vector4 v(0.0, 0.0, 0.0, 1.0);
243 const float *data = get_attrib_data(attrib);
244 if(data) {
245 data += idx * vattr[attrib].nelem;
246 for(int i=0; i<vattr[attrib].nelem; i++) {
247 v[i] = data[i];
248 }
249 }
250 return v;
251 }
253 int Mesh::get_attrib_count(int attrib) const
254 {
255 return has_attrib(attrib) ? nverts : 0;
256 }
259 unsigned int *Mesh::set_index_data(int num, const unsigned int *indices)
260 {
261 int nidx = nfaces * 3;
262 if(nidx && num != nidx) {
263 fprintf(stderr, "%s: index count missmatch (%d instead of %d)\n", __FUNCTION__, num, nidx);
264 return 0;
265 }
266 nfaces = num / 3;
268 idata.clear();
269 idata.resize(num);
271 if(indices) {
272 memcpy(&idata[0], indices, num * sizeof *indices);
273 }
275 idata_valid = true;
276 ibo_valid = false;
278 return &idata[0];
279 }
281 unsigned int *Mesh::get_index_data()
282 {
283 ibo_valid = false;
284 return (unsigned int*)((const Mesh*)this)->get_index_data();
285 }
287 const unsigned int *Mesh::get_index_data() const
288 {
289 if(!idata_valid) {
290 #if GL_ES_VERSION_2_0
291 fprintf(stderr, "%s: can't read back index data in CrippledGL ES\n", __FUNCTION__);
292 return 0;
293 #else
294 if(!ibo_valid) {
295 fprintf(stderr, "%s: indices unavailable\n", __FUNCTION__);
296 return 0;
297 }
299 // local data copy is unavailable, gram the data from the ibo
300 Mesh *m = (Mesh*)this;
301 int nidx = nfaces * 3;
302 m->idata.resize(nidx);
304 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
305 void *data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY);
306 memcpy(&m->idata[0], data, nidx * sizeof(unsigned int));
307 glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
309 idata_valid = true;
310 #endif
311 }
313 return &idata[0];
314 }
316 int Mesh::get_index_count() const
317 {
318 return nfaces * 3;
319 }
321 void Mesh::append(const Mesh &mesh)
322 {
323 unsigned int idxoffs = nverts;
325 nverts += mesh.nverts;
326 nfaces += mesh.nfaces;
328 for(int i=0; i<NUM_MESH_ATTR; i++) {
329 if(has_attrib(i) && mesh.has_attrib(i)) {
330 // force validating the data arrays
331 get_attrib_data(i);
332 mesh.get_attrib_data(i);
334 // append the mesh data
335 vattr[i].data.insert(vattr[i].data.end(), mesh.vattr[i].data.begin(), mesh.vattr[i].data.end());
336 }
337 }
339 if(ibo_valid || idata_valid) {
340 // make index arrays valid
341 get_index_data();
342 mesh.get_index_data();
344 size_t orig_sz = idata.size();
346 idata.insert(idata.end(), mesh.idata.begin(), mesh.idata.end());
348 // fixup all the new indices
349 for(size_t i=orig_sz; i<idata.size(); i++) {
350 idata[i] += idxoffs;
351 }
352 }
354 // fuck everything
355 wire_ibo_valid = false;
356 aabb_valid = false;
357 bsph_valid = false;
358 }
360 // assemble a complete vertex by adding all the useful attributes
361 void Mesh::vertex(float x, float y, float z)
362 {
363 cur_val[MESH_ATTR_VERTEX] = Vector4(x, y, z, 1.0f);
364 vattr[MESH_ATTR_VERTEX].data_valid = true;
365 vattr[MESH_ATTR_VERTEX].nelem = 3;
367 for(int i=0; i<NUM_MESH_ATTR; i++) {
368 if(vattr[i].data_valid) {
369 for(int j=0; j<vattr[MESH_ATTR_VERTEX].nelem; j++) {
370 vattr[i].data.push_back(cur_val[i][j]);
371 }
372 }
373 vattr[i].vbo_valid = false;
374 }
376 if(idata_valid) {
377 idata.clear();
378 }
379 ibo_valid = idata_valid = false;
380 }
382 void Mesh::normal(float nx, float ny, float nz)
383 {
384 cur_val[MESH_ATTR_NORMAL] = Vector4(nx, ny, nz, 1.0f);
385 vattr[MESH_ATTR_NORMAL].data_valid = true;
386 vattr[MESH_ATTR_NORMAL].nelem = 3;
387 }
389 void Mesh::tangent(float tx, float ty, float tz)
390 {
391 cur_val[MESH_ATTR_TANGENT] = Vector4(tx, ty, tz, 1.0f);
392 vattr[MESH_ATTR_TANGENT].data_valid = true;
393 vattr[MESH_ATTR_TANGENT].nelem = 3;
394 }
396 void Mesh::texcoord(float u, float v, float w)
397 {
398 cur_val[MESH_ATTR_TEXCOORD] = Vector4(u, v, w, 1.0f);
399 vattr[MESH_ATTR_TEXCOORD].data_valid = true;
400 vattr[MESH_ATTR_TEXCOORD].nelem = 3;
401 }
403 void Mesh::boneweights(float w1, float w2, float w3, float w4)
404 {
405 cur_val[MESH_ATTR_BONEWEIGHTS] = Vector4(w1, w2, w3, w4);
406 vattr[MESH_ATTR_BONEWEIGHTS].data_valid = true;
407 vattr[MESH_ATTR_BONEWEIGHTS].nelem = 4;
408 }
410 void Mesh::boneidx(int idx1, int idx2, int idx3, int idx4)
411 {
412 cur_val[MESH_ATTR_BONEIDX] = Vector4(idx1, idx2, idx3, idx4);
413 vattr[MESH_ATTR_BONEIDX].data_valid = true;
414 vattr[MESH_ATTR_BONEIDX].nelem = 4;
415 }
417 int Mesh::get_poly_count() const
418 {
419 if(nfaces) {
420 return nfaces;
421 }
422 if(nverts) {
423 return nverts / 3;
424 }
425 return 0;
426 }
428 /// static function
429 void Mesh::set_attrib_location(int attr, int loc)
430 {
431 if(attr < 0 || attr >= NUM_MESH_ATTR) {
432 return;
433 }
434 Mesh::global_sdr_loc[attr] = loc;
435 }
437 /// static function
438 int Mesh::get_attrib_location(int attr)
439 {
440 if(attr < 0 || attr >= NUM_MESH_ATTR) {
441 return -1;
442 }
443 return Mesh::global_sdr_loc[attr];
444 }
446 /// static function
447 void Mesh::clear_attrib_locations()
448 {
449 for(int i=0; i<NUM_MESH_ATTR; i++) {
450 Mesh::global_sdr_loc[i] = -1;
451 }
452 }
454 /// static function
455 void Mesh::set_vis_vecsize(float sz)
456 {
457 Mesh::vis_vecsize = sz;
458 }
460 float Mesh::get_vis_vecsize()
461 {
462 return Mesh::vis_vecsize;
463 }
465 void Mesh::apply_xform(const Matrix4x4 &xform)
466 {
467 Matrix4x4 dir_xform = xform;
468 dir_xform[0][3] = dir_xform[1][3] = dir_xform[2][3] = 0.0f;
469 dir_xform[3][0] = dir_xform[3][1] = dir_xform[3][2] = 0.0f;
470 dir_xform[3][3] = 1.0f;
472 apply_xform(xform, dir_xform);
473 }
475 void Mesh::apply_xform(const Matrix4x4 &xform, const Matrix4x4 &dir_xform)
476 {
477 for(unsigned int i=0; i<nverts; i++) {
478 Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
479 set_attrib(MESH_ATTR_VERTEX, i, v.transformed(xform));
481 if(has_attrib(MESH_ATTR_NORMAL)) {
482 Vector3 n = get_attrib(MESH_ATTR_NORMAL, i);
483 set_attrib(MESH_ATTR_NORMAL, i, n.transformed(dir_xform));
484 }
485 if(has_attrib(MESH_ATTR_TANGENT)) {
486 Vector3 t = get_attrib(MESH_ATTR_TANGENT, i);
487 set_attrib(MESH_ATTR_TANGENT, i, t.transformed(dir_xform));
488 }
489 }
490 }
492 void Mesh::flip()
493 {
494 flip_faces();
495 flip_normals();
496 }
498 void Mesh::flip_faces()
499 {
500 if(is_indexed()) {
501 unsigned int *indices = get_index_data();
502 if(!indices) return;
504 int idxnum = get_index_count();
505 for(int i=0; i<idxnum; i+=3) {
506 unsigned int tmp = indices[i + 2];
507 indices[i + 2] = indices[i + 1];
508 indices[i + 1] = tmp;
509 }
511 } else {
512 Vector3 *verts = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
513 if(!verts) return;
515 int vnum = get_attrib_count(MESH_ATTR_VERTEX);
516 for(int i=0; i<vnum; i+=3) {
517 Vector3 tmp = verts[i + 2];
518 verts[i + 2] = verts[i + 1];
519 verts[i + 1] = tmp;
520 }
521 }
522 }
524 void Mesh::flip_normals()
525 {
526 Vector3 *normals = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
527 if(!normals) return;
529 int num = get_attrib_count(MESH_ATTR_NORMAL);
530 for(int i=0; i<num; i++) {
531 normals[i] = -normals[i];
532 }
533 }
535 /*
536 int Mesh::add_bone(XFormNode *bone)
537 {
538 int idx = bones.size();
539 bones.push_back(bone);
540 return idx;
541 }
543 const XFormNode *Mesh::get_bone(int idx) const
544 {
545 if(idx < 0 || idx >= (int)bones.size()) {
546 return 0;
547 }
548 return bones[idx];
549 }
551 int Mesh::get_bones_count() const
552 {
553 return (int)bones.size();
554 }
555 */
557 void Mesh::draw() const
558 {
559 int cur_sdr;
560 glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
563 ((Mesh*)this)->update_buffers();
565 if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
566 fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
567 return;
568 }
570 if(cur_sdr) {
571 // rendering with shaders
572 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
573 fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__);
574 return;
575 }
577 for(int i=0; i<NUM_MESH_ATTR; i++) {
578 int loc = global_sdr_loc[i];
579 if(loc >= 0 && vattr[i].vbo_valid) {
580 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
581 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
582 glEnableVertexAttribArray(loc);
583 }
584 }
585 } else {
586 #ifndef GL_ES_VERSION_2_0
587 // rendering with fixed-function (not available in GLES2)
588 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_VERTEX].vbo);
589 glVertexPointer(vattr[MESH_ATTR_VERTEX].nelem, GL_FLOAT, 0, 0);
590 glEnableClientState(GL_VERTEX_ARRAY);
592 if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
593 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_NORMAL].vbo);
594 glNormalPointer(GL_FLOAT, 0, 0);
595 glEnableClientState(GL_NORMAL_ARRAY);
596 }
597 if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
598 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_TEXCOORD].vbo);
599 glTexCoordPointer(vattr[MESH_ATTR_TEXCOORD].nelem, GL_FLOAT, 0, 0);
600 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
601 }
602 if(vattr[MESH_ATTR_COLOR].vbo_valid) {
603 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_COLOR].vbo);
604 glColorPointer(vattr[MESH_ATTR_COLOR].nelem, GL_FLOAT, 0, 0);
605 glEnableClientState(GL_COLOR_ARRAY);
606 }
607 #endif
608 }
609 glBindBuffer(GL_ARRAY_BUFFER, 0);
611 if(ibo_valid) {
612 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
613 glDrawElements(GL_TRIANGLES, nfaces * 3, GL_UNSIGNED_INT, 0);
614 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
615 } else {
616 glDrawArrays(GL_TRIANGLES, 0, nverts);
617 }
619 if(cur_sdr) {
620 // rendered with shaders
621 for(int i=0; i<NUM_MESH_ATTR; i++) {
622 int loc = global_sdr_loc[i];
623 if(loc >= 0 && vattr[i].vbo_valid) {
624 glDisableVertexAttribArray(loc);
625 }
626 }
627 } else {
628 #ifndef GL_ES_VERSION_2_0
629 // rendered with fixed-function
630 glDisableClientState(GL_VERTEX_ARRAY);
631 if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
632 glDisableClientState(GL_NORMAL_ARRAY);
633 }
634 if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
635 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
636 }
637 if(vattr[MESH_ATTR_COLOR].vbo_valid) {
638 glDisableClientState(GL_COLOR_ARRAY);
639 }
640 #endif
641 }
642 }
644 void Mesh::draw_wire() const
645 {
646 ((Mesh*)this)->update_wire_ibo();
648 if(!vattr[MESH_ATTR_VERTEX].vbo_valid || !wire_ibo_valid) {
649 fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
650 return;
651 }
652 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
653 fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__);
654 return;
655 }
657 for(int i=0; i<NUM_MESH_ATTR; i++) {
658 int loc = global_sdr_loc[i];
659 if(loc >= 0 && vattr[i].vbo_valid) {
660 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
661 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
662 glEnableVertexAttribArray(loc);
663 }
664 }
665 glBindBuffer(GL_ARRAY_BUFFER, 0);
667 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
668 glDrawElements(GL_LINES, nfaces * 6, GL_UNSIGNED_INT, 0);
669 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
671 for(int i=0; i<NUM_MESH_ATTR; i++) {
672 int loc = global_sdr_loc[i];
673 if(loc >= 0 && vattr[i].vbo_valid) {
674 glDisableVertexAttribArray(loc);
675 }
676 }
677 }
679 void Mesh::draw_vertices() const
680 {
681 ((Mesh*)this)->update_buffers();
683 if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
684 fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
685 return;
686 }
687 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
688 fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__);
689 return;
690 }
692 for(int i=0; i<NUM_MESH_ATTR; i++) {
693 int loc = global_sdr_loc[i];
694 if(loc >= 0 && vattr[i].vbo_valid) {
695 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
696 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
697 glEnableVertexAttribArray(loc);
698 }
699 }
700 glBindBuffer(GL_ARRAY_BUFFER, 0);
702 glDrawArrays(GL_POINTS, 0, nverts);
704 for(int i=0; i<NUM_MESH_ATTR; i++) {
705 int loc = global_sdr_loc[i];
706 if(loc >= 0 && vattr[i].vbo_valid) {
707 glDisableVertexAttribArray(loc);
708 }
709 }
710 }
712 void Mesh::draw_normals() const
713 {
714 #ifdef USE_OLDGL
715 Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
716 Vector3 *norm = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
717 if(!varr || !norm) {
718 return;
719 }
721 glBegin(GL_LINES);
722 if(get_current_shader()) {
723 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
724 if(vert_loc < 0) {
725 glEnd();
726 return;
727 }
729 for(size_t i=0; i<nverts; i++) {
730 glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
731 Vector3 end = varr[i] + norm[i] * vis_vecsize;
732 glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
733 }
734 } else {
735 for(size_t i=0; i<nverts; i++) {
736 glVertex3f(varr[i].x, varr[i].y, varr[i].z);
737 Vector3 end = varr[i] + norm[i] * vis_vecsize;
738 glVertex3f(end.x, end.y, end.z);
739 }
740 }
741 glEnd();
742 #endif // USE_OLDGL
743 }
745 void Mesh::draw_tangents() const
746 {
747 #ifdef USE_OLDGL
748 Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
749 Vector3 *tang = (Vector3*)get_attrib_data(MESH_ATTR_TANGENT);
750 if(!varr || !tang) {
751 return;
752 }
754 glBegin(GL_LINES);
755 if(get_current_shader()) {
756 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
757 if(vert_loc < 0) {
758 glEnd();
759 return;
760 }
762 for(size_t i=0; i<nverts; i++) {
763 glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
764 Vector3 end = varr[i] + tang[i] * vis_vecsize;
765 glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
766 }
767 } else {
768 for(size_t i=0; i<nverts; i++) {
769 glVertex3f(varr[i].x, varr[i].y, varr[i].z);
770 Vector3 end = varr[i] + tang[i] * vis_vecsize;
771 glVertex3f(end.x, end.y, end.z);
772 }
773 }
774 glEnd();
775 #endif // USE_OLDGL
776 }
778 void Mesh::get_aabbox(Vector3 *vmin, Vector3 *vmax) const
779 {
780 if(!aabb_valid) {
781 ((Mesh*)this)->calc_aabb();
782 }
783 *vmin = aabb.min;
784 *vmax = aabb.max;
785 }
787 const AABox &Mesh::get_aabbox() const
788 {
789 if(!aabb_valid) {
790 ((Mesh*)this)->calc_aabb();
791 }
792 return aabb;
793 }
795 float Mesh::get_bsphere(Vector3 *center, float *rad) const
796 {
797 if(!bsph_valid) {
798 ((Mesh*)this)->calc_bsph();
799 }
800 *center = bsph.center;
801 *rad = bsph.radius;
802 return bsph.radius;
803 }
805 const Sphere &Mesh::get_bsphere() const
806 {
807 if(!bsph_valid) {
808 ((Mesh*)this)->calc_bsph();
809 }
810 return bsph;
811 }
813 /// static function
814 void Mesh::set_intersect_mode(unsigned int mode)
815 {
816 Mesh::intersect_mode = mode;
817 }
819 /// static function
820 unsigned int Mesh::get_intersect_mode()
821 {
822 return Mesh::intersect_mode;
823 }
825 /// static function
826 void Mesh::set_vertex_select_distance(float dist)
827 {
828 Mesh::vertex_sel_dist = dist;
829 }
831 /// static function
832 float Mesh::get_vertex_select_distance()
833 {
834 return Mesh::vertex_sel_dist;
835 }
837 bool Mesh::intersect(const Ray &ray, HitPoint *hit) const
838 {
839 assert((Mesh::intersect_mode & (ISECT_VERTICES | ISECT_FACE)) != (ISECT_VERTICES | ISECT_FACE));
841 const Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
842 const Vector3 *narr = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
843 if(!varr) {
844 return false;
845 }
846 const unsigned int *idxarr = get_index_data();
848 // first test with the bounding box
849 AABox box;
850 get_aabbox(&box.min, &box.max);
851 if(!box.intersect(ray)) {
852 return false;
853 }
855 HitPoint nearest_hit;
856 nearest_hit.dist = FLT_MAX;
857 nearest_hit.obj = 0;
859 if(Mesh::intersect_mode & ISECT_VERTICES) {
860 // we asked for "intersections" with the vertices of the mesh
861 long nearest_vidx = -1;
862 float thres_sq = Mesh::vertex_sel_dist * Mesh::vertex_sel_dist;
864 for(unsigned int i=0; i<nverts; i++) {
866 if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(narr[i], ray.dir) > 0) {
867 continue;
868 }
870 // project the vertex onto the ray line
871 float t = dot_product(varr[i] - ray.origin, ray.dir);
872 Vector3 vproj = ray.origin + ray.dir * t;
874 float dist_sq = (vproj - varr[i]).length_sq();
875 if(dist_sq < thres_sq) {
876 if(!hit) {
877 return true;
878 }
879 if(t < nearest_hit.dist) {
880 nearest_hit.dist = t;
881 nearest_vidx = i;
882 }
883 }
884 }
886 if(nearest_vidx != -1) {
887 hitvert = varr[nearest_vidx];
888 nearest_hit.obj = &hitvert;
889 }
891 } else {
892 // regular intersection test with polygons
894 for(unsigned int i=0; i<nfaces; i++) {
895 Triangle face(i, varr, idxarr);
897 // ignore back-facing polygons if the mode flags include ISECT_FRONT
898 if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(face.get_normal(), ray.dir) > 0) {
899 continue;
900 }
902 HitPoint fhit;
903 if(face.intersect(ray, hit ? &fhit : 0)) {
904 if(!hit) {
905 return true;
906 }
907 if(fhit.dist < nearest_hit.dist) {
908 nearest_hit = fhit;
909 hitface = face;
910 }
911 }
912 }
913 }
915 if(nearest_hit.obj) {
916 if(hit) {
917 *hit = nearest_hit;
919 // if we are interested in the mesh and not the faces set obj to this
920 if(Mesh::intersect_mode & ISECT_FACE) {
921 hit->obj = &hitface;
922 } else if(Mesh::intersect_mode & ISECT_VERTICES) {
923 hit->obj = &hitvert;
924 } else {
925 hit->obj = this;
926 }
927 }
928 return true;
929 }
930 return false;
931 }
934 // texture coordinate manipulation
935 void Mesh::texcoord_apply_xform(const Matrix4x4 &xform)
936 {
937 if(!has_attrib(MESH_ATTR_TEXCOORD)) {
938 return;
939 }
941 for(unsigned int i=0; i<nverts; i++) {
942 Vector4 tc = get_attrib(MESH_ATTR_TEXCOORD, i);
943 set_attrib(MESH_ATTR_TEXCOORD, i, tc.transformed(xform));
944 }
945 }
947 void Mesh::texcoord_gen_plane(const Vector3 &norm, const Vector3 &tang)
948 {
949 if(!nverts) return;
951 if(!has_attrib(MESH_ATTR_TEXCOORD)) {
952 // allocate texture coordinate attribute array
953 set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts);
954 }
956 Vector3 n = norm.normalized();
957 Vector3 b = cross_product(n, tang).normalized();
958 Vector3 t = cross_product(b, n);
960 for(unsigned int i=0; i<nverts; i++) {
961 Vector3 pos = get_attrib(MESH_ATTR_VERTEX, i);
963 // distance along the tangent direction
964 float u = dot_product(pos, t);
965 // distance along the bitangent direction
966 float v = dot_product(pos, b);
968 set_attrib(MESH_ATTR_TEXCOORD, i, Vector4(u, v, 0, 1));
969 }
970 }
972 void Mesh::texcoord_gen_box()
973 {
974 if(!nverts || !has_attrib(MESH_ATTR_NORMAL)) return;
976 if(!has_attrib(MESH_ATTR_TEXCOORD)) {
977 // allocate texture coordinate attribute array
978 set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts);
979 }
981 for(unsigned int i=0; i<nverts; i++) {
982 Vector3 pos = Vector3(get_attrib(MESH_ATTR_VERTEX, i)) * 0.5 + Vector3(0.5, 0.5, 0.5);
983 Vector3 norm = get_attrib(MESH_ATTR_NORMAL, i);
985 float abs_nx = fabs(norm.x);
986 float abs_ny = fabs(norm.y);
987 float abs_nz = fabs(norm.z);
988 int dom = abs_nx > abs_ny && abs_nx > abs_nz ? 0 : (abs_ny > abs_nz ? 1 : 2);
990 float uv[2], *uvptr = uv;
991 for(int j=0; j<3; j++) {
992 if(j == dom) continue; // skip dominant axis
994 *uvptr++ = pos[j];
995 }
996 set_attrib(MESH_ATTR_TEXCOORD, i, Vector4(uv[0], uv[1], 0, 1));
997 }
998 }
1000 // ------ private member functions ------
1002 void Mesh::calc_aabb()
1004 // the cast is to force calling the const version which doesn't invalidate
1005 if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
1006 return;
1009 aabb.min = Vector3(FLT_MAX, FLT_MAX, FLT_MAX);
1010 aabb.max = -aabb.min;
1012 for(unsigned int i=0; i<nverts; i++) {
1013 Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
1014 for(int j=0; j<3; j++) {
1015 if(v[j] < aabb.min[j]) {
1016 aabb.min[j] = v[j];
1018 if(v[j] > aabb.max[j]) {
1019 aabb.max[j] = v[j];
1023 aabb_valid = true;
1026 void Mesh::calc_bsph()
1028 // the cast is to force calling the const version which doesn't invalidate
1029 if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
1030 return;
1033 Vector3 v;
1034 bsph.center = Vector3(0, 0, 0);
1036 // first find the center
1037 for(unsigned int i=0; i<nverts; i++) {
1038 v = get_attrib(MESH_ATTR_VERTEX, i);
1039 bsph.center += v;
1041 bsph.center /= (float)nverts;
1043 bsph.radius = 0.0f;
1044 for(unsigned int i=0; i<nverts; i++) {
1045 v = get_attrib(MESH_ATTR_VERTEX, i);
1046 float dist_sq = (v - bsph.center).length_sq();
1047 if(dist_sq > bsph.radius) {
1048 bsph.radius = dist_sq;
1051 bsph.radius = sqrt(bsph.radius);
1053 bsph_valid = true;
1056 void Mesh::update_buffers()
1058 for(int i=0; i<NUM_MESH_ATTR; i++) {
1059 if(has_attrib(i) && !vattr[i].vbo_valid) {
1060 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
1061 glBufferData(GL_ARRAY_BUFFER, nverts * vattr[i].nelem * sizeof(float), &vattr[i].data[0], GL_STATIC_DRAW);
1062 vattr[i].vbo_valid = true;
1065 glBindBuffer(GL_ARRAY_BUFFER, 0);
1067 if(idata_valid && !ibo_valid) {
1068 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
1069 glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 3 * sizeof(unsigned int), &idata[0], GL_STATIC_DRAW);
1070 ibo_valid = true;
1072 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1075 void Mesh::update_wire_ibo()
1077 update_buffers();
1079 if(wire_ibo_valid) {
1080 return;
1083 if(!wire_ibo) {
1084 glGenBuffers(1, &wire_ibo);
1087 unsigned int *wire_idxarr = new unsigned int[nfaces * 6];
1088 unsigned int *dest = wire_idxarr;
1090 if(ibo_valid) {
1091 // we're dealing with an indexed mesh
1092 const unsigned int *idxarr = ((const Mesh*)this)->get_index_data();
1094 for(unsigned int i=0; i<nfaces; i++) {
1095 *dest++ = idxarr[0];
1096 *dest++ = idxarr[1];
1097 *dest++ = idxarr[1];
1098 *dest++ = idxarr[2];
1099 *dest++ = idxarr[2];
1100 *dest++ = idxarr[0];
1101 idxarr += 3;
1103 } else {
1104 // not an indexed mesh ...
1105 for(unsigned int i=0; i<nfaces; i++) {
1106 int vidx = i * 3;
1107 *dest++ = vidx;
1108 *dest++ = vidx + 1;
1109 *dest++ = vidx + 1;
1110 *dest++ = vidx + 2;
1111 *dest++ = vidx + 2;
1112 *dest++ = vidx;
1116 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
1117 glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 6 * sizeof(unsigned int), wire_idxarr, GL_STATIC_DRAW);
1118 delete [] wire_idxarr;
1119 wire_ibo_valid = true;
1120 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1124 // ------ class Triangle ------
1125 Triangle::Triangle()
1127 normal_valid = false;
1128 id = -1;
1131 Triangle::Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2)
1133 v[0] = v0;
1134 v[1] = v1;
1135 v[2] = v2;
1136 normal_valid = false;
1137 id = -1;
1140 Triangle::Triangle(int n, const Vector3 *varr, const unsigned int *idxarr)
1142 if(idxarr) {
1143 v[0] = varr[idxarr[n * 3]];
1144 v[1] = varr[idxarr[n * 3 + 1]];
1145 v[2] = varr[idxarr[n * 3 + 2]];
1146 } else {
1147 v[0] = varr[n * 3];
1148 v[1] = varr[n * 3 + 1];
1149 v[2] = varr[n * 3 + 2];
1151 normal_valid = false;
1152 id = n;
1155 void Triangle::calc_normal()
1157 normal = cross_product(v[1] - v[0], v[2] - v[0]).normalized();
1158 normal_valid = true;
1161 const Vector3 &Triangle::get_normal() const
1163 if(!normal_valid) {
1164 ((Triangle*)this)->calc_normal();
1166 return normal;
1169 void Triangle::transform(const Matrix4x4 &xform)
1171 v[0].transform(xform);
1172 v[1].transform(xform);
1173 v[2].transform(xform);
1174 normal_valid = false;
1177 void Triangle::draw() const
1179 Vector3 n[3];
1180 n[0] = get_normal();
1181 n[1] = get_normal();
1182 n[2] = get_normal();
1184 int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
1185 int nloc = Mesh::get_attrib_location(MESH_ATTR_NORMAL);
1187 glEnableVertexAttribArray(vloc);
1188 glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
1189 glVertexAttribPointer(nloc, 3, GL_FLOAT, GL_FALSE, 0, &n[0].x);
1191 glDrawArrays(GL_TRIANGLES, 0, 3);
1193 glDisableVertexAttribArray(vloc);
1194 glDisableVertexAttribArray(nloc);
1197 void Triangle::draw_wire() const
1199 static const int idxarr[] = {0, 1, 1, 2, 2, 0};
1200 int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
1202 glEnableVertexAttribArray(vloc);
1203 glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
1205 glDrawElements(GL_LINES, 6, GL_UNSIGNED_INT, idxarr);
1207 glDisableVertexAttribArray(vloc);
1210 Vector3 Triangle::calc_barycentric(const Vector3 &pos) const
1212 Vector3 norm = get_normal();
1214 float area_sq = fabs(dot_product(cross_product(v[1] - v[0], v[2] - v[0]), norm));
1215 if(area_sq < 1e-5) {
1216 return Vector3(0, 0, 0);
1219 float asq0 = fabs(dot_product(cross_product(v[1] - pos, v[2] - pos), norm));
1220 float asq1 = fabs(dot_product(cross_product(v[2] - pos, v[0] - pos), norm));
1221 float asq2 = fabs(dot_product(cross_product(v[0] - pos, v[1] - pos), norm));
1223 return Vector3(asq0 / area_sq, asq1 / area_sq, asq2 / area_sq);
1226 bool Triangle::intersect(const Ray &ray, HitPoint *hit) const
1228 Vector3 normal = get_normal();
1230 float ndotdir = dot_product(ray.dir, normal);
1231 if(fabs(ndotdir) < 1e-4) {
1232 return false;
1235 Vector3 vertdir = v[0] - ray.origin;
1236 float t = dot_product(normal, vertdir) / ndotdir;
1238 Vector3 pos = ray.origin + ray.dir * t;
1239 Vector3 bary = calc_barycentric(pos);
1241 if(bary.x + bary.y + bary.z > 1.00001) {
1242 return false;
1245 if(hit) {
1246 hit->dist = t;
1247 hit->pos = ray.origin + ray.dir * t;
1248 hit->normal = normal;
1249 hit->obj = this;
1251 return true;