tavli

view src/mesh.cc @ 15:b1a195c3ee16

added shaders
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 28 Jun 2015 08:34:24 +0300
parents a8e26f163f99
children d6209903454b
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 bool Mesh::use_custom_sdr_attr = true;
12 int Mesh::global_sdr_loc[NUM_MESH_ATTR] = { 0, 1, 2, 3, 4, 5, 6 };
13 /*
14 (int)SDR_ATTR_VERTEX,
15 (int)SDR_ATTR_NORMAL,
16 (int)SDR_ATTR_TANGENT,
17 (int)SDR_ATTR_TEXCOORD,
18 (int)SDR_ATTR_COLOR,
19 -1, -1};
20 */
21 unsigned int Mesh::intersect_mode = ISECT_DEFAULT;
22 float Mesh::vertex_sel_dist = 0.01;
23 float Mesh::vis_vecsize = 1.0;
25 Mesh::Mesh()
26 {
27 clear();
29 glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects);
31 for(int i=0; i<NUM_MESH_ATTR; i++) {
32 vattr[i].vbo = buffer_objects[i];
33 }
34 ibo = buffer_objects[NUM_MESH_ATTR];
35 wire_ibo = 0;
36 }
38 Mesh::~Mesh()
39 {
40 glDeleteBuffers(NUM_MESH_ATTR + 1, buffer_objects);
42 if(wire_ibo) {
43 glDeleteBuffers(1, &wire_ibo);
44 }
45 }
47 Mesh::Mesh(const Mesh &rhs)
48 {
49 clear();
51 glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects);
53 for(int i=0; i<NUM_MESH_ATTR; i++) {
54 vattr[i].vbo = buffer_objects[i];
55 }
56 ibo = buffer_objects[NUM_MESH_ATTR];
57 wire_ibo = 0;
59 clone(rhs);
60 }
62 Mesh &Mesh::operator =(const Mesh &rhs)
63 {
64 if(&rhs != this) {
65 clone(rhs);
66 }
67 return *this;
68 }
70 bool Mesh::clone(const Mesh &m)
71 {
72 clear();
74 for(int i=0; i<NUM_MESH_ATTR; i++) {
75 if(m.has_attrib(i)) {
76 m.get_attrib_data(i); // force validation of the actual data on the source mesh
78 vattr[i].nelem = m.vattr[i].nelem;
79 vattr[i].data = m.vattr[i].data; // copy the actual data
80 vattr[i].data_valid = true;
81 }
82 }
84 if(m.is_indexed()) {
85 m.get_index_data(); // again, force validation
87 // copy the index data
88 idata = m.idata;
89 idata_valid = true;
90 }
92 name = m.name;
93 nverts = m.nverts;
94 nfaces = m.nfaces;
96 //bones = m.bones;
98 memcpy(cur_val, m.cur_val, sizeof cur_val);
100 aabb = m.aabb;
101 aabb_valid = m.aabb_valid;
102 bsph = m.bsph;
103 bsph_valid = m.bsph_valid;
105 hitface = m.hitface;
106 hitvert = m.hitvert;
108 intersect_mode = m.intersect_mode;
109 vertex_sel_dist = m.vertex_sel_dist;
110 vis_vecsize = m.vis_vecsize;
112 return true;
113 }
115 void Mesh::set_name(const char *name)
116 {
117 this->name = name;
118 }
120 const char *Mesh::get_name() const
121 {
122 return name.c_str();
123 }
125 bool Mesh::has_attrib(int attr) const
126 {
127 if(attr < 0 || attr >= NUM_MESH_ATTR) {
128 return false;
129 }
131 // if neither of these is valid, then nobody has set this attribute
132 return vattr[attr].vbo_valid || vattr[attr].data_valid;
133 }
135 bool Mesh::is_indexed() const
136 {
137 return ibo_valid || idata_valid;
138 }
140 void Mesh::clear()
141 {
142 //bones.clear();
144 for(int i=0; i<NUM_MESH_ATTR; i++) {
145 vattr[i].nelem = 0;
146 vattr[i].vbo_valid = false;
147 vattr[i].data_valid = false;
148 //vattr[i].sdr_loc = -1;
149 vattr[i].data.clear();
150 }
151 ibo_valid = idata_valid = false;
152 idata.clear();
154 wire_ibo_valid = false;
156 nverts = nfaces = 0;
158 bsph_valid = false;
159 aabb_valid = false;
160 }
162 float *Mesh::set_attrib_data(int attrib, int nelem, unsigned int num, const float *data)
163 {
164 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
165 fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
166 return 0;
167 }
169 if(nverts && num != nverts) {
170 fprintf(stderr, "%s: attribute count missmatch (%d instead of %d)\n", __FUNCTION__, num, nverts);
171 return 0;
172 }
173 nverts = num;
175 vattr[attrib].data.clear();
176 vattr[attrib].nelem = nelem;
177 vattr[attrib].data.resize(num * nelem);
179 if(data) {
180 memcpy(&vattr[attrib].data[0], data, num * nelem * sizeof *data);
181 }
183 vattr[attrib].data_valid = true;
184 vattr[attrib].vbo_valid = false;
185 return &vattr[attrib].data[0];
186 }
188 float *Mesh::get_attrib_data(int attrib)
189 {
190 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
191 fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
192 return 0;
193 }
195 vattr[attrib].vbo_valid = false;
196 return (float*)((const Mesh*)this)->get_attrib_data(attrib);
197 }
199 const float *Mesh::get_attrib_data(int attrib) const
200 {
201 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
202 fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
203 return 0;
204 }
206 if(!vattr[attrib].data_valid) {
207 #if GL_ES_VERSION_2_0
208 fprintf(stderr, "%s: can't read back attrib data on CrippledGL ES\n", __FUNCTION__);
209 return 0;
210 #else
211 if(!vattr[attrib].vbo_valid) {
212 fprintf(stderr, "%s: unavailable attrib: %d\n", __FUNCTION__, attrib);
213 return 0;
214 }
216 // local data copy is unavailable, grab the data from the vbo
217 Mesh *m = (Mesh*)this;
218 m->vattr[attrib].data.resize(nverts * vattr[attrib].nelem);
220 glBindBuffer(GL_ARRAY_BUFFER, vattr[attrib].vbo);
221 void *data = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
222 memcpy(&m->vattr[attrib].data[0], data, nverts * vattr[attrib].nelem * sizeof(float));
223 glUnmapBuffer(GL_ARRAY_BUFFER);
225 vattr[attrib].data_valid = true;
226 #endif
227 }
229 return &vattr[attrib].data[0];
230 }
232 void Mesh::set_attrib(int attrib, int idx, const Vector4 &v)
233 {
234 float *data = get_attrib_data(attrib);
235 if(data) {
236 data += idx * vattr[attrib].nelem;
237 for(int i=0; i<vattr[attrib].nelem; i++) {
238 data[i] = v[i];
239 }
240 }
241 }
243 Vector4 Mesh::get_attrib(int attrib, int idx) const
244 {
245 Vector4 v(0.0, 0.0, 0.0, 1.0);
246 const float *data = get_attrib_data(attrib);
247 if(data) {
248 data += idx * vattr[attrib].nelem;
249 for(int i=0; i<vattr[attrib].nelem; i++) {
250 v[i] = data[i];
251 }
252 }
253 return v;
254 }
256 int Mesh::get_attrib_count(int attrib) const
257 {
258 return has_attrib(attrib) ? nverts : 0;
259 }
262 unsigned int *Mesh::set_index_data(int num, const unsigned int *indices)
263 {
264 int nidx = nfaces * 3;
265 if(nidx && num != nidx) {
266 fprintf(stderr, "%s: index count missmatch (%d instead of %d)\n", __FUNCTION__, num, nidx);
267 return 0;
268 }
269 nfaces = num / 3;
271 idata.clear();
272 idata.resize(num);
274 if(indices) {
275 memcpy(&idata[0], indices, num * sizeof *indices);
276 }
278 idata_valid = true;
279 ibo_valid = false;
281 return &idata[0];
282 }
284 unsigned int *Mesh::get_index_data()
285 {
286 ibo_valid = false;
287 return (unsigned int*)((const Mesh*)this)->get_index_data();
288 }
290 const unsigned int *Mesh::get_index_data() const
291 {
292 if(!idata_valid) {
293 #if GL_ES_VERSION_2_0
294 fprintf(stderr, "%s: can't read back index data in CrippledGL ES\n", __FUNCTION__);
295 return 0;
296 #else
297 if(!ibo_valid) {
298 fprintf(stderr, "%s: indices unavailable\n", __FUNCTION__);
299 return 0;
300 }
302 // local data copy is unavailable, gram the data from the ibo
303 Mesh *m = (Mesh*)this;
304 int nidx = nfaces * 3;
305 m->idata.resize(nidx);
307 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
308 void *data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY);
309 memcpy(&m->idata[0], data, nidx * sizeof(unsigned int));
310 glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
312 idata_valid = true;
313 #endif
314 }
316 return &idata[0];
317 }
319 int Mesh::get_index_count() const
320 {
321 return nfaces * 3;
322 }
324 void Mesh::append(const Mesh &mesh)
325 {
326 unsigned int idxoffs = nverts;
328 if(!nverts) {
329 clone(mesh);
330 return;
331 }
333 nverts += mesh.nverts;
334 nfaces += mesh.nfaces;
336 for(int i=0; i<NUM_MESH_ATTR; i++) {
337 if(has_attrib(i) && mesh.has_attrib(i)) {
338 // force validating the data arrays
339 get_attrib_data(i);
340 mesh.get_attrib_data(i);
342 // append the mesh data
343 vattr[i].data.insert(vattr[i].data.end(), mesh.vattr[i].data.begin(), mesh.vattr[i].data.end());
344 }
345 }
347 if(ibo_valid || idata_valid) {
348 // make index arrays valid
349 get_index_data();
350 mesh.get_index_data();
352 size_t orig_sz = idata.size();
354 idata.insert(idata.end(), mesh.idata.begin(), mesh.idata.end());
356 // fixup all the new indices
357 for(size_t i=orig_sz; i<idata.size(); i++) {
358 idata[i] += idxoffs;
359 }
360 }
362 // fuck everything
363 wire_ibo_valid = false;
364 aabb_valid = false;
365 bsph_valid = false;
366 }
368 // assemble a complete vertex by adding all the useful attributes
369 void Mesh::vertex(float x, float y, float z)
370 {
371 cur_val[MESH_ATTR_VERTEX] = Vector4(x, y, z, 1.0f);
372 vattr[MESH_ATTR_VERTEX].data_valid = true;
373 vattr[MESH_ATTR_VERTEX].nelem = 3;
375 for(int i=0; i<NUM_MESH_ATTR; i++) {
376 if(vattr[i].data_valid) {
377 for(int j=0; j<vattr[MESH_ATTR_VERTEX].nelem; j++) {
378 vattr[i].data.push_back(cur_val[i][j]);
379 }
380 }
381 vattr[i].vbo_valid = false;
382 }
384 if(idata_valid) {
385 idata.clear();
386 }
387 ibo_valid = idata_valid = false;
388 }
390 void Mesh::normal(float nx, float ny, float nz)
391 {
392 cur_val[MESH_ATTR_NORMAL] = Vector4(nx, ny, nz, 1.0f);
393 vattr[MESH_ATTR_NORMAL].data_valid = true;
394 vattr[MESH_ATTR_NORMAL].nelem = 3;
395 }
397 void Mesh::tangent(float tx, float ty, float tz)
398 {
399 cur_val[MESH_ATTR_TANGENT] = Vector4(tx, ty, tz, 1.0f);
400 vattr[MESH_ATTR_TANGENT].data_valid = true;
401 vattr[MESH_ATTR_TANGENT].nelem = 3;
402 }
404 void Mesh::texcoord(float u, float v, float w)
405 {
406 cur_val[MESH_ATTR_TEXCOORD] = Vector4(u, v, w, 1.0f);
407 vattr[MESH_ATTR_TEXCOORD].data_valid = true;
408 vattr[MESH_ATTR_TEXCOORD].nelem = 3;
409 }
411 void Mesh::boneweights(float w1, float w2, float w3, float w4)
412 {
413 cur_val[MESH_ATTR_BONEWEIGHTS] = Vector4(w1, w2, w3, w4);
414 vattr[MESH_ATTR_BONEWEIGHTS].data_valid = true;
415 vattr[MESH_ATTR_BONEWEIGHTS].nelem = 4;
416 }
418 void Mesh::boneidx(int idx1, int idx2, int idx3, int idx4)
419 {
420 cur_val[MESH_ATTR_BONEIDX] = Vector4(idx1, idx2, idx3, idx4);
421 vattr[MESH_ATTR_BONEIDX].data_valid = true;
422 vattr[MESH_ATTR_BONEIDX].nelem = 4;
423 }
425 int Mesh::get_poly_count() const
426 {
427 if(nfaces) {
428 return nfaces;
429 }
430 if(nverts) {
431 return nverts / 3;
432 }
433 return 0;
434 }
436 /// static function
437 void Mesh::set_attrib_location(int attr, int loc)
438 {
439 if(attr < 0 || attr >= NUM_MESH_ATTR) {
440 return;
441 }
442 Mesh::global_sdr_loc[attr] = loc;
443 }
445 /// static function
446 int Mesh::get_attrib_location(int attr)
447 {
448 if(attr < 0 || attr >= NUM_MESH_ATTR) {
449 return -1;
450 }
451 return Mesh::global_sdr_loc[attr];
452 }
454 /// static function
455 void Mesh::clear_attrib_locations()
456 {
457 for(int i=0; i<NUM_MESH_ATTR; i++) {
458 Mesh::global_sdr_loc[i] = -1;
459 }
460 }
462 /// static function
463 void Mesh::set_vis_vecsize(float sz)
464 {
465 Mesh::vis_vecsize = sz;
466 }
468 float Mesh::get_vis_vecsize()
469 {
470 return Mesh::vis_vecsize;
471 }
473 void Mesh::apply_xform(const Matrix4x4 &xform)
474 {
475 Matrix4x4 dir_xform = xform;
476 dir_xform[0][3] = dir_xform[1][3] = dir_xform[2][3] = 0.0f;
477 dir_xform[3][0] = dir_xform[3][1] = dir_xform[3][2] = 0.0f;
478 dir_xform[3][3] = 1.0f;
480 apply_xform(xform, dir_xform);
481 }
483 void Mesh::apply_xform(const Matrix4x4 &xform, const Matrix4x4 &dir_xform)
484 {
485 for(unsigned int i=0; i<nverts; i++) {
486 Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
487 set_attrib(MESH_ATTR_VERTEX, i, v.transformed(xform));
489 if(has_attrib(MESH_ATTR_NORMAL)) {
490 Vector3 n = get_attrib(MESH_ATTR_NORMAL, i);
491 set_attrib(MESH_ATTR_NORMAL, i, n.transformed(dir_xform));
492 }
493 if(has_attrib(MESH_ATTR_TANGENT)) {
494 Vector3 t = get_attrib(MESH_ATTR_TANGENT, i);
495 set_attrib(MESH_ATTR_TANGENT, i, t.transformed(dir_xform));
496 }
497 }
498 }
500 void Mesh::flip()
501 {
502 flip_faces();
503 flip_normals();
504 }
506 void Mesh::flip_faces()
507 {
508 if(is_indexed()) {
509 unsigned int *indices = get_index_data();
510 if(!indices) return;
512 int idxnum = get_index_count();
513 for(int i=0; i<idxnum; i+=3) {
514 unsigned int tmp = indices[i + 2];
515 indices[i + 2] = indices[i + 1];
516 indices[i + 1] = tmp;
517 }
519 } else {
520 Vector3 *verts = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
521 if(!verts) return;
523 int vnum = get_attrib_count(MESH_ATTR_VERTEX);
524 for(int i=0; i<vnum; i+=3) {
525 Vector3 tmp = verts[i + 2];
526 verts[i + 2] = verts[i + 1];
527 verts[i + 1] = tmp;
528 }
529 }
530 }
532 void Mesh::flip_normals()
533 {
534 Vector3 *normals = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
535 if(!normals) return;
537 int num = get_attrib_count(MESH_ATTR_NORMAL);
538 for(int i=0; i<num; i++) {
539 normals[i] = -normals[i];
540 }
541 }
543 /*
544 int Mesh::add_bone(XFormNode *bone)
545 {
546 int idx = bones.size();
547 bones.push_back(bone);
548 return idx;
549 }
551 const XFormNode *Mesh::get_bone(int idx) const
552 {
553 if(idx < 0 || idx >= (int)bones.size()) {
554 return 0;
555 }
556 return bones[idx];
557 }
559 int Mesh::get_bones_count() const
560 {
561 return (int)bones.size();
562 }
563 */
565 void Mesh::draw() const
566 {
567 int cur_sdr;
568 glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
571 ((Mesh*)this)->update_buffers();
573 if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
574 fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
575 return;
576 }
578 if(cur_sdr && use_custom_sdr_attr) {
579 // rendering with shaders
580 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
581 fprintf(stderr, "%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 } else {
594 #ifndef GL_ES_VERSION_2_0
595 // rendering with fixed-function (not available in GLES2)
596 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_VERTEX].vbo);
597 glVertexPointer(vattr[MESH_ATTR_VERTEX].nelem, GL_FLOAT, 0, 0);
598 glEnableClientState(GL_VERTEX_ARRAY);
600 if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
601 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_NORMAL].vbo);
602 glNormalPointer(GL_FLOAT, 0, 0);
603 glEnableClientState(GL_NORMAL_ARRAY);
604 }
605 if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
606 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_TEXCOORD].vbo);
607 glTexCoordPointer(vattr[MESH_ATTR_TEXCOORD].nelem, GL_FLOAT, 0, 0);
608 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
609 }
610 if(vattr[MESH_ATTR_COLOR].vbo_valid) {
611 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_COLOR].vbo);
612 glColorPointer(vattr[MESH_ATTR_COLOR].nelem, GL_FLOAT, 0, 0);
613 glEnableClientState(GL_COLOR_ARRAY);
614 }
615 #endif
616 }
617 glBindBuffer(GL_ARRAY_BUFFER, 0);
619 if(ibo_valid) {
620 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
621 glDrawElements(GL_TRIANGLES, nfaces * 3, GL_UNSIGNED_INT, 0);
622 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
623 } else {
624 glDrawArrays(GL_TRIANGLES, 0, nverts);
625 }
627 if(cur_sdr && use_custom_sdr_attr) {
628 // rendered with shaders
629 for(int i=0; i<NUM_MESH_ATTR; i++) {
630 int loc = global_sdr_loc[i];
631 if(loc >= 0 && vattr[i].vbo_valid) {
632 glDisableVertexAttribArray(loc);
633 }
634 }
635 } else {
636 #ifndef GL_ES_VERSION_2_0
637 // rendered with fixed-function
638 glDisableClientState(GL_VERTEX_ARRAY);
639 if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
640 glDisableClientState(GL_NORMAL_ARRAY);
641 }
642 if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
643 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
644 }
645 if(vattr[MESH_ATTR_COLOR].vbo_valid) {
646 glDisableClientState(GL_COLOR_ARRAY);
647 }
648 #endif
649 }
650 }
652 void Mesh::draw_wire() const
653 {
654 ((Mesh*)this)->update_wire_ibo();
656 if(!vattr[MESH_ATTR_VERTEX].vbo_valid || !wire_ibo_valid) {
657 fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
658 return;
659 }
660 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
661 fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__);
662 return;
663 }
665 for(int i=0; i<NUM_MESH_ATTR; i++) {
666 int loc = global_sdr_loc[i];
667 if(loc >= 0 && vattr[i].vbo_valid) {
668 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
669 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
670 glEnableVertexAttribArray(loc);
671 }
672 }
673 glBindBuffer(GL_ARRAY_BUFFER, 0);
675 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
676 glDrawElements(GL_LINES, nfaces * 6, GL_UNSIGNED_INT, 0);
677 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
679 for(int i=0; i<NUM_MESH_ATTR; i++) {
680 int loc = global_sdr_loc[i];
681 if(loc >= 0 && vattr[i].vbo_valid) {
682 glDisableVertexAttribArray(loc);
683 }
684 }
685 }
687 void Mesh::draw_vertices() const
688 {
689 ((Mesh*)this)->update_buffers();
691 if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
692 fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
693 return;
694 }
695 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
696 fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__);
697 return;
698 }
700 for(int i=0; i<NUM_MESH_ATTR; i++) {
701 int loc = global_sdr_loc[i];
702 if(loc >= 0 && vattr[i].vbo_valid) {
703 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
704 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
705 glEnableVertexAttribArray(loc);
706 }
707 }
708 glBindBuffer(GL_ARRAY_BUFFER, 0);
710 glDrawArrays(GL_POINTS, 0, nverts);
712 for(int i=0; i<NUM_MESH_ATTR; i++) {
713 int loc = global_sdr_loc[i];
714 if(loc >= 0 && vattr[i].vbo_valid) {
715 glDisableVertexAttribArray(loc);
716 }
717 }
718 }
720 void Mesh::draw_normals() const
721 {
722 #ifdef USE_OLDGL
723 int cur_sdr;
724 glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
726 Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
727 Vector3 *norm = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
728 if(!varr || !norm) {
729 return;
730 }
732 glBegin(GL_LINES);
733 if(cur_sdr && use_custom_sdr_attr) {
734 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
735 if(vert_loc < 0) {
736 glEnd();
737 return;
738 }
740 for(size_t i=0; i<nverts; i++) {
741 glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
742 Vector3 end = varr[i] + norm[i] * vis_vecsize;
743 glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
744 }
745 } else {
746 for(size_t i=0; i<nverts; i++) {
747 glVertex3f(varr[i].x, varr[i].y, varr[i].z);
748 Vector3 end = varr[i] + norm[i] * vis_vecsize;
749 glVertex3f(end.x, end.y, end.z);
750 }
751 }
752 glEnd();
753 #endif // USE_OLDGL
754 }
756 void Mesh::draw_tangents() const
757 {
758 #ifdef USE_OLDGL
759 int cur_sdr;
760 glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
762 Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
763 Vector3 *tang = (Vector3*)get_attrib_data(MESH_ATTR_TANGENT);
764 if(!varr || !tang) {
765 return;
766 }
768 glBegin(GL_LINES);
769 if(cur_sdr && use_custom_sdr_attr) {
770 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
771 if(vert_loc < 0) {
772 glEnd();
773 return;
774 }
776 for(size_t i=0; i<nverts; i++) {
777 glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
778 Vector3 end = varr[i] + tang[i] * vis_vecsize;
779 glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
780 }
781 } else {
782 for(size_t i=0; i<nverts; i++) {
783 glVertex3f(varr[i].x, varr[i].y, varr[i].z);
784 Vector3 end = varr[i] + tang[i] * vis_vecsize;
785 glVertex3f(end.x, end.y, end.z);
786 }
787 }
788 glEnd();
789 #endif // USE_OLDGL
790 }
792 void Mesh::get_aabbox(Vector3 *vmin, Vector3 *vmax) const
793 {
794 if(!aabb_valid) {
795 ((Mesh*)this)->calc_aabb();
796 }
797 *vmin = aabb.min;
798 *vmax = aabb.max;
799 }
801 const AABox &Mesh::get_aabbox() const
802 {
803 if(!aabb_valid) {
804 ((Mesh*)this)->calc_aabb();
805 }
806 return aabb;
807 }
809 float Mesh::get_bsphere(Vector3 *center, float *rad) const
810 {
811 if(!bsph_valid) {
812 ((Mesh*)this)->calc_bsph();
813 }
814 *center = bsph.center;
815 *rad = bsph.radius;
816 return bsph.radius;
817 }
819 const Sphere &Mesh::get_bsphere() const
820 {
821 if(!bsph_valid) {
822 ((Mesh*)this)->calc_bsph();
823 }
824 return bsph;
825 }
827 /// static function
828 void Mesh::set_intersect_mode(unsigned int mode)
829 {
830 Mesh::intersect_mode = mode;
831 }
833 /// static function
834 unsigned int Mesh::get_intersect_mode()
835 {
836 return Mesh::intersect_mode;
837 }
839 /// static function
840 void Mesh::set_vertex_select_distance(float dist)
841 {
842 Mesh::vertex_sel_dist = dist;
843 }
845 /// static function
846 float Mesh::get_vertex_select_distance()
847 {
848 return Mesh::vertex_sel_dist;
849 }
851 bool Mesh::intersect(const Ray &ray, HitPoint *hit) const
852 {
853 assert((Mesh::intersect_mode & (ISECT_VERTICES | ISECT_FACE)) != (ISECT_VERTICES | ISECT_FACE));
855 const Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
856 const Vector3 *narr = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
857 if(!varr) {
858 return false;
859 }
860 const unsigned int *idxarr = get_index_data();
862 // first test with the bounding box
863 AABox box;
864 get_aabbox(&box.min, &box.max);
865 if(!box.intersect(ray)) {
866 return false;
867 }
869 HitPoint nearest_hit;
870 nearest_hit.dist = FLT_MAX;
871 nearest_hit.obj = 0;
873 if(Mesh::intersect_mode & ISECT_VERTICES) {
874 // we asked for "intersections" with the vertices of the mesh
875 long nearest_vidx = -1;
876 float thres_sq = Mesh::vertex_sel_dist * Mesh::vertex_sel_dist;
878 for(unsigned int i=0; i<nverts; i++) {
880 if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(narr[i], ray.dir) > 0) {
881 continue;
882 }
884 // project the vertex onto the ray line
885 float t = dot_product(varr[i] - ray.origin, ray.dir);
886 Vector3 vproj = ray.origin + ray.dir * t;
888 float dist_sq = (vproj - varr[i]).length_sq();
889 if(dist_sq < thres_sq) {
890 if(!hit) {
891 return true;
892 }
893 if(t < nearest_hit.dist) {
894 nearest_hit.dist = t;
895 nearest_vidx = i;
896 }
897 }
898 }
900 if(nearest_vidx != -1) {
901 hitvert = varr[nearest_vidx];
902 nearest_hit.obj = &hitvert;
903 }
905 } else {
906 // regular intersection test with polygons
908 for(unsigned int i=0; i<nfaces; i++) {
909 Triangle face(i, varr, idxarr);
911 // ignore back-facing polygons if the mode flags include ISECT_FRONT
912 if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(face.get_normal(), ray.dir) > 0) {
913 continue;
914 }
916 HitPoint fhit;
917 if(face.intersect(ray, hit ? &fhit : 0)) {
918 if(!hit) {
919 return true;
920 }
921 if(fhit.dist < nearest_hit.dist) {
922 nearest_hit = fhit;
923 hitface = face;
924 }
925 }
926 }
927 }
929 if(nearest_hit.obj) {
930 if(hit) {
931 *hit = nearest_hit;
933 // if we are interested in the mesh and not the faces set obj to this
934 if(Mesh::intersect_mode & ISECT_FACE) {
935 hit->obj = &hitface;
936 } else if(Mesh::intersect_mode & ISECT_VERTICES) {
937 hit->obj = &hitvert;
938 } else {
939 hit->obj = this;
940 }
941 }
942 return true;
943 }
944 return false;
945 }
948 // texture coordinate manipulation
949 void Mesh::texcoord_apply_xform(const Matrix4x4 &xform)
950 {
951 if(!has_attrib(MESH_ATTR_TEXCOORD)) {
952 return;
953 }
955 for(unsigned int i=0; i<nverts; i++) {
956 Vector4 tc = get_attrib(MESH_ATTR_TEXCOORD, i);
957 set_attrib(MESH_ATTR_TEXCOORD, i, tc.transformed(xform));
958 }
959 }
961 void Mesh::texcoord_gen_plane(const Vector3 &norm, const Vector3 &tang)
962 {
963 if(!nverts) return;
965 if(!has_attrib(MESH_ATTR_TEXCOORD)) {
966 // allocate texture coordinate attribute array
967 set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts);
968 }
970 Vector3 n = norm.normalized();
971 Vector3 b = cross_product(n, tang).normalized();
972 Vector3 t = cross_product(b, n);
974 for(unsigned int i=0; i<nverts; i++) {
975 Vector3 pos = get_attrib(MESH_ATTR_VERTEX, i);
977 // distance along the tangent direction
978 float u = dot_product(pos, t);
979 // distance along the bitangent direction
980 float v = dot_product(pos, b);
982 set_attrib(MESH_ATTR_TEXCOORD, i, Vector4(u, v, 0, 1));
983 }
984 }
986 void Mesh::texcoord_gen_box()
987 {
988 if(!nverts || !has_attrib(MESH_ATTR_NORMAL)) return;
990 if(!has_attrib(MESH_ATTR_TEXCOORD)) {
991 // allocate texture coordinate attribute array
992 set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts);
993 }
995 for(unsigned int i=0; i<nverts; i++) {
996 Vector3 pos = Vector3(get_attrib(MESH_ATTR_VERTEX, i)) * 0.5 + Vector3(0.5, 0.5, 0.5);
997 Vector3 norm = get_attrib(MESH_ATTR_NORMAL, i);
999 float abs_nx = fabs(norm.x);
1000 float abs_ny = fabs(norm.y);
1001 float abs_nz = fabs(norm.z);
1002 int dom = abs_nx > abs_ny && abs_nx > abs_nz ? 0 : (abs_ny > abs_nz ? 1 : 2);
1004 float uv[2], *uvptr = uv;
1005 for(int j=0; j<3; j++) {
1006 if(j == dom) continue; // skip dominant axis
1008 *uvptr++ = pos[j];
1010 set_attrib(MESH_ATTR_TEXCOORD, i, Vector4(uv[0], uv[1], 0, 1));
1014 // ------ private member functions ------
1016 void Mesh::calc_aabb()
1018 // the cast is to force calling the const version which doesn't invalidate
1019 if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
1020 return;
1023 aabb.min = Vector3(FLT_MAX, FLT_MAX, FLT_MAX);
1024 aabb.max = -aabb.min;
1026 for(unsigned int i=0; i<nverts; i++) {
1027 Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
1028 for(int j=0; j<3; j++) {
1029 if(v[j] < aabb.min[j]) {
1030 aabb.min[j] = v[j];
1032 if(v[j] > aabb.max[j]) {
1033 aabb.max[j] = v[j];
1037 aabb_valid = true;
1040 void Mesh::calc_bsph()
1042 // the cast is to force calling the const version which doesn't invalidate
1043 if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
1044 return;
1047 Vector3 v;
1048 bsph.center = Vector3(0, 0, 0);
1050 // first find the center
1051 for(unsigned int i=0; i<nverts; i++) {
1052 v = get_attrib(MESH_ATTR_VERTEX, i);
1053 bsph.center += v;
1055 bsph.center /= (float)nverts;
1057 bsph.radius = 0.0f;
1058 for(unsigned int i=0; i<nverts; i++) {
1059 v = get_attrib(MESH_ATTR_VERTEX, i);
1060 float dist_sq = (v - bsph.center).length_sq();
1061 if(dist_sq > bsph.radius) {
1062 bsph.radius = dist_sq;
1065 bsph.radius = sqrt(bsph.radius);
1067 bsph_valid = true;
1070 void Mesh::update_buffers()
1072 for(int i=0; i<NUM_MESH_ATTR; i++) {
1073 if(has_attrib(i) && !vattr[i].vbo_valid) {
1074 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
1075 glBufferData(GL_ARRAY_BUFFER, nverts * vattr[i].nelem * sizeof(float), &vattr[i].data[0], GL_STATIC_DRAW);
1076 vattr[i].vbo_valid = true;
1079 glBindBuffer(GL_ARRAY_BUFFER, 0);
1081 if(idata_valid && !ibo_valid) {
1082 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
1083 glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 3 * sizeof(unsigned int), &idata[0], GL_STATIC_DRAW);
1084 ibo_valid = true;
1086 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1089 void Mesh::update_wire_ibo()
1091 update_buffers();
1093 if(wire_ibo_valid) {
1094 return;
1097 if(!wire_ibo) {
1098 glGenBuffers(1, &wire_ibo);
1101 unsigned int *wire_idxarr = new unsigned int[nfaces * 6];
1102 unsigned int *dest = wire_idxarr;
1104 if(ibo_valid) {
1105 // we're dealing with an indexed mesh
1106 const unsigned int *idxarr = ((const Mesh*)this)->get_index_data();
1108 for(unsigned int i=0; i<nfaces; i++) {
1109 *dest++ = idxarr[0];
1110 *dest++ = idxarr[1];
1111 *dest++ = idxarr[1];
1112 *dest++ = idxarr[2];
1113 *dest++ = idxarr[2];
1114 *dest++ = idxarr[0];
1115 idxarr += 3;
1117 } else {
1118 // not an indexed mesh ...
1119 for(unsigned int i=0; i<nfaces; i++) {
1120 int vidx = i * 3;
1121 *dest++ = vidx;
1122 *dest++ = vidx + 1;
1123 *dest++ = vidx + 1;
1124 *dest++ = vidx + 2;
1125 *dest++ = vidx + 2;
1126 *dest++ = vidx;
1130 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
1131 glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 6 * sizeof(unsigned int), wire_idxarr, GL_STATIC_DRAW);
1132 delete [] wire_idxarr;
1133 wire_ibo_valid = true;
1134 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1138 // ------ class Triangle ------
1139 Triangle::Triangle()
1141 normal_valid = false;
1142 id = -1;
1145 Triangle::Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2)
1147 v[0] = v0;
1148 v[1] = v1;
1149 v[2] = v2;
1150 normal_valid = false;
1151 id = -1;
1154 Triangle::Triangle(int n, const Vector3 *varr, const unsigned int *idxarr)
1156 if(idxarr) {
1157 v[0] = varr[idxarr[n * 3]];
1158 v[1] = varr[idxarr[n * 3 + 1]];
1159 v[2] = varr[idxarr[n * 3 + 2]];
1160 } else {
1161 v[0] = varr[n * 3];
1162 v[1] = varr[n * 3 + 1];
1163 v[2] = varr[n * 3 + 2];
1165 normal_valid = false;
1166 id = n;
1169 void Triangle::calc_normal()
1171 normal = cross_product(v[1] - v[0], v[2] - v[0]).normalized();
1172 normal_valid = true;
1175 const Vector3 &Triangle::get_normal() const
1177 if(!normal_valid) {
1178 ((Triangle*)this)->calc_normal();
1180 return normal;
1183 void Triangle::transform(const Matrix4x4 &xform)
1185 v[0].transform(xform);
1186 v[1].transform(xform);
1187 v[2].transform(xform);
1188 normal_valid = false;
1191 void Triangle::draw() const
1193 Vector3 n[3];
1194 n[0] = get_normal();
1195 n[1] = get_normal();
1196 n[2] = get_normal();
1198 int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
1199 int nloc = Mesh::get_attrib_location(MESH_ATTR_NORMAL);
1201 glEnableVertexAttribArray(vloc);
1202 glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
1203 glVertexAttribPointer(nloc, 3, GL_FLOAT, GL_FALSE, 0, &n[0].x);
1205 glDrawArrays(GL_TRIANGLES, 0, 3);
1207 glDisableVertexAttribArray(vloc);
1208 glDisableVertexAttribArray(nloc);
1211 void Triangle::draw_wire() const
1213 static const int idxarr[] = {0, 1, 1, 2, 2, 0};
1214 int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
1216 glEnableVertexAttribArray(vloc);
1217 glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
1219 glDrawElements(GL_LINES, 6, GL_UNSIGNED_INT, idxarr);
1221 glDisableVertexAttribArray(vloc);
1224 Vector3 Triangle::calc_barycentric(const Vector3 &pos) const
1226 Vector3 norm = get_normal();
1228 float area_sq = fabs(dot_product(cross_product(v[1] - v[0], v[2] - v[0]), norm));
1229 if(area_sq < 1e-5) {
1230 return Vector3(0, 0, 0);
1233 float asq0 = fabs(dot_product(cross_product(v[1] - pos, v[2] - pos), norm));
1234 float asq1 = fabs(dot_product(cross_product(v[2] - pos, v[0] - pos), norm));
1235 float asq2 = fabs(dot_product(cross_product(v[0] - pos, v[1] - pos), norm));
1237 return Vector3(asq0 / area_sq, asq1 / area_sq, asq2 / area_sq);
1240 bool Triangle::intersect(const Ray &ray, HitPoint *hit) const
1242 Vector3 normal = get_normal();
1244 float ndotdir = dot_product(ray.dir, normal);
1245 if(fabs(ndotdir) < 1e-4) {
1246 return false;
1249 Vector3 vertdir = v[0] - ray.origin;
1250 float t = dot_product(normal, vertdir) / ndotdir;
1252 Vector3 pos = ray.origin + ray.dir * t;
1253 Vector3 bary = calc_barycentric(pos);
1255 if(bary.x + bary.y + bary.z > 1.00001) {
1256 return false;
1259 if(hit) {
1260 hit->dist = t;
1261 hit->pos = ray.origin + ray.dir * t;
1262 hit->normal = normal;
1263 hit->obj = this;
1265 return true;