7 //#include "xform_node.h"
11 bool Mesh::use_custom_sdr_attr = true;
12 int Mesh::global_sdr_loc[NUM_MESH_ATTR] = { 0, 1, 2, 3, 4, 5, 6 };
16 (int)SDR_ATTR_TANGENT,
17 (int)SDR_ATTR_TEXCOORD,
21 unsigned int Mesh::intersect_mode = ISECT_DEFAULT;
22 float Mesh::vertex_sel_dist = 0.01;
23 float Mesh::vis_vecsize = 1.0;
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];
34 ibo = buffer_objects[NUM_MESH_ATTR];
40 glDeleteBuffers(NUM_MESH_ATTR + 1, buffer_objects);
43 glDeleteBuffers(1, &wire_ibo);
47 Mesh::Mesh(const Mesh &rhs)
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];
56 ibo = buffer_objects[NUM_MESH_ATTR];
62 Mesh &Mesh::operator =(const Mesh &rhs)
70 bool Mesh::clone(const Mesh &m)
74 for(int i=0; i<NUM_MESH_ATTR; 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;
85 m.get_index_data(); // again, force validation
87 // copy the index data
98 memcpy(cur_val, m.cur_val, sizeof cur_val);
101 aabb_valid = m.aabb_valid;
103 bsph_valid = m.bsph_valid;
108 intersect_mode = m.intersect_mode;
109 vertex_sel_dist = m.vertex_sel_dist;
110 vis_vecsize = m.vis_vecsize;
115 void Mesh::set_name(const char *name)
120 const char *Mesh::get_name() const
125 bool Mesh::has_attrib(int attr) const
127 if(attr < 0 || attr >= NUM_MESH_ATTR) {
131 // if neither of these is valid, then nobody has set this attribute
132 return vattr[attr].vbo_valid || vattr[attr].data_valid;
135 bool Mesh::is_indexed() const
137 return ibo_valid || idata_valid;
144 for(int i=0; i<NUM_MESH_ATTR; i++) {
146 vattr[i].vbo_valid = false;
147 vattr[i].data_valid = false;
148 //vattr[i].sdr_loc = -1;
149 vattr[i].data.clear();
151 ibo_valid = idata_valid = false;
154 wire_ibo_valid = false;
162 float *Mesh::set_attrib_data(int attrib, int nelem, unsigned int num, const float *data)
164 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
165 fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
169 if(nverts && num != nverts) {
170 fprintf(stderr, "%s: attribute count missmatch (%d instead of %d)\n", __FUNCTION__, num, nverts);
175 vattr[attrib].data.clear();
176 vattr[attrib].nelem = nelem;
177 vattr[attrib].data.resize(num * nelem);
180 memcpy(&vattr[attrib].data[0], data, num * nelem * sizeof *data);
183 vattr[attrib].data_valid = true;
184 vattr[attrib].vbo_valid = false;
185 return &vattr[attrib].data[0];
188 float *Mesh::get_attrib_data(int attrib)
190 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
191 fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
195 vattr[attrib].vbo_valid = false;
196 return (float*)((const Mesh*)this)->get_attrib_data(attrib);
199 const float *Mesh::get_attrib_data(int attrib) const
201 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
202 fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
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__);
211 if(!vattr[attrib].vbo_valid) {
212 fprintf(stderr, "%s: unavailable attrib: %d\n", __FUNCTION__, attrib);
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;
229 return &vattr[attrib].data[0];
232 void Mesh::set_attrib(int attrib, int idx, const Vec4 &v)
234 float *data = get_attrib_data(attrib);
236 data += idx * vattr[attrib].nelem;
237 for(int i=0; i<vattr[attrib].nelem; i++) {
243 Vec4 Mesh::get_attrib(int attrib, int idx) const
245 Vec4 v(0.0, 0.0, 0.0, 1.0);
246 const float *data = get_attrib_data(attrib);
248 data += idx * vattr[attrib].nelem;
249 for(int i=0; i<vattr[attrib].nelem; i++) {
256 int Mesh::get_attrib_count(int attrib) const
258 return has_attrib(attrib) ? nverts : 0;
262 unsigned int *Mesh::set_index_data(int num, const unsigned int *indices)
264 int nidx = nfaces * 3;
265 if(nidx && num != nidx) {
266 fprintf(stderr, "%s: index count mismatch (%d instead of %d)\n", __FUNCTION__, num, nidx);
275 memcpy(&idata[0], indices, num * sizeof *indices);
284 unsigned int *Mesh::get_index_data()
287 return (unsigned int*)((const Mesh*)this)->get_index_data();
290 const unsigned int *Mesh::get_index_data() const
293 #if GL_ES_VERSION_2_0
294 fprintf(stderr, "%s: can't read back index data in CrippledGL ES\n", __FUNCTION__);
298 fprintf(stderr, "%s: indices unavailable\n", __FUNCTION__);
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);
319 int Mesh::get_index_count() const
324 void Mesh::append(const Mesh &mesh)
326 unsigned int idxoffs = nverts;
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
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());
347 if(ibo_valid || idata_valid) {
348 // make index arrays valid
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++) {
363 wire_ibo_valid = false;
368 // assemble a complete vertex by adding all the useful attributes
369 void Mesh::vertex(float x, float y, float z)
371 cur_val[MESH_ATTR_VERTEX] = Vec4(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]);
381 vattr[i].vbo_valid = false;
387 ibo_valid = idata_valid = false;
390 void Mesh::normal(float nx, float ny, float nz)
392 cur_val[MESH_ATTR_NORMAL] = Vec4(nx, ny, nz, 1.0f);
393 vattr[MESH_ATTR_NORMAL].data_valid = true;
394 vattr[MESH_ATTR_NORMAL].nelem = 3;
397 void Mesh::tangent(float tx, float ty, float tz)
399 cur_val[MESH_ATTR_TANGENT] = Vec4(tx, ty, tz, 1.0f);
400 vattr[MESH_ATTR_TANGENT].data_valid = true;
401 vattr[MESH_ATTR_TANGENT].nelem = 3;
404 void Mesh::texcoord(float u, float v, float w)
406 cur_val[MESH_ATTR_TEXCOORD] = Vec4(u, v, w, 1.0f);
407 vattr[MESH_ATTR_TEXCOORD].data_valid = true;
408 vattr[MESH_ATTR_TEXCOORD].nelem = 3;
411 void Mesh::boneweights(float w1, float w2, float w3, float w4)
413 cur_val[MESH_ATTR_BONEWEIGHTS] = Vec4(w1, w2, w3, w4);
414 vattr[MESH_ATTR_BONEWEIGHTS].data_valid = true;
415 vattr[MESH_ATTR_BONEWEIGHTS].nelem = 4;
418 void Mesh::boneidx(int idx1, int idx2, int idx3, int idx4)
420 cur_val[MESH_ATTR_BONEIDX] = Vec4(idx1, idx2, idx3, idx4);
421 vattr[MESH_ATTR_BONEIDX].data_valid = true;
422 vattr[MESH_ATTR_BONEIDX].nelem = 4;
425 int Mesh::get_poly_count() const
437 void Mesh::set_attrib_location(int attr, int loc)
439 if(attr < 0 || attr >= NUM_MESH_ATTR) {
442 Mesh::global_sdr_loc[attr] = loc;
446 int Mesh::get_attrib_location(int attr)
448 if(attr < 0 || attr >= NUM_MESH_ATTR) {
451 return Mesh::global_sdr_loc[attr];
455 void Mesh::clear_attrib_locations()
457 for(int i=0; i<NUM_MESH_ATTR; i++) {
458 Mesh::global_sdr_loc[i] = -1;
463 void Mesh::set_vis_vecsize(float sz)
465 Mesh::vis_vecsize = sz;
468 float Mesh::get_vis_vecsize()
470 return Mesh::vis_vecsize;
473 void Mesh::apply_xform(const Mat4 &xform)
475 Mat4 dir_xform = xform.upper3x3();
476 apply_xform(xform, dir_xform);
479 void Mesh::apply_xform(const Mat4 &xform, const Mat4 &dir_xform)
481 for(unsigned int i=0; i<nverts; i++) {
482 Vec4 v = get_attrib(MESH_ATTR_VERTEX, i);
483 set_attrib(MESH_ATTR_VERTEX, i, xform * v);
485 if(has_attrib(MESH_ATTR_NORMAL)) {
486 Vec3 n = Vec3(get_attrib(MESH_ATTR_NORMAL, i));
487 set_attrib(MESH_ATTR_NORMAL, i, Vec4(dir_xform * n));
489 if(has_attrib(MESH_ATTR_TANGENT)) {
490 Vec3 t = Vec3(get_attrib(MESH_ATTR_TANGENT, i));
491 set_attrib(MESH_ATTR_TANGENT, i, Vec4(dir_xform * t));
502 void Mesh::flip_faces()
505 unsigned int *indices = get_index_data();
508 int idxnum = get_index_count();
509 for(int i=0; i<idxnum; i+=3) {
510 unsigned int tmp = indices[i + 2];
511 indices[i + 2] = indices[i + 1];
512 indices[i + 1] = tmp;
516 Vec3 *verts = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX);
519 int vnum = get_attrib_count(MESH_ATTR_VERTEX);
520 for(int i=0; i<vnum; i+=3) {
521 Vec3 tmp = verts[i + 2];
522 verts[i + 2] = verts[i + 1];
528 void Mesh::flip_normals()
530 Vec3 *normals = (Vec3*)get_attrib_data(MESH_ATTR_NORMAL);
533 int num = get_attrib_count(MESH_ATTR_NORMAL);
534 for(int i=0; i<num; i++) {
535 normals[i] = -normals[i];
541 if(!is_indexed()) return; // no vertex sharing is possible in unindexed meshes
543 unsigned int *indices = get_index_data();
546 int idxnum = get_index_count();
547 int nnverts = idxnum;
551 for(int i=0; i<NUM_MESH_ATTR; i++) {
552 if(!has_attrib(i)) continue;
554 const float *srcbuf = get_attrib_data(i);
556 float *tmpbuf = new float[nnverts * vattr[i].nelem];
557 float *dstptr = tmpbuf;
558 for(int j=0; j<idxnum; j++) {
559 unsigned int idx = indices[j];
560 const float *srcptr = srcbuf + idx * vattr[i].nelem;
562 for(int k=0; k<vattr[i].nelem; k++) {
563 *dstptr++ = *srcptr++;
566 set_attrib_data(i, vattr[i].nelem, nnverts, tmpbuf);
577 void Mesh::calc_face_normals()
579 const Vec3 *varr = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX);
580 Vec3 *narr = (Vec3*)get_attrib_data(MESH_ATTR_NORMAL);
586 const unsigned int *idxarr = get_index_data();
588 for(unsigned int i=0; i<nfaces; i++) {
589 Triangle face(i, varr, idxarr);
592 for(int j=0; j<3; j++) {
593 unsigned int idx = *idxarr++;
594 narr[idx] = face.normal;
599 int nfaces = nverts / 3;
601 for(int i=0; i<nfaces; i++) {
602 Triangle face(varr[0], varr[1], varr[2]);
605 narr[0] = narr[1] = narr[2] = face.normal;
606 varr += vattr[MESH_ATTR_VERTEX].nelem;
607 narr += vattr[MESH_ATTR_NORMAL].nelem;
613 int Mesh::add_bone(XFormNode *bone)
615 int idx = bones.size();
616 bones.push_back(bone);
620 const XFormNode *Mesh::get_bone(int idx) const
622 if(idx < 0 || idx >= (int)bones.size()) {
628 int Mesh::get_bones_count() const
630 return (int)bones.size();
634 bool Mesh::pre_draw() const
637 glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
639 ((Mesh*)this)->update_buffers();
641 if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
642 fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
646 if(cur_sdr && use_custom_sdr_attr) {
647 // rendering with shaders
648 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
649 fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__);
653 for(int i=0; i<NUM_MESH_ATTR; i++) {
654 int loc = global_sdr_loc[i];
655 if(loc >= 0 && vattr[i].vbo_valid) {
656 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
657 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
658 glEnableVertexAttribArray(loc);
662 #ifndef GL_ES_VERSION_2_0
663 // rendering with fixed-function (not available in GLES2)
664 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_VERTEX].vbo);
665 glVertexPointer(vattr[MESH_ATTR_VERTEX].nelem, GL_FLOAT, 0, 0);
666 glEnableClientState(GL_VERTEX_ARRAY);
668 if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
669 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_NORMAL].vbo);
670 glNormalPointer(GL_FLOAT, 0, 0);
671 glEnableClientState(GL_NORMAL_ARRAY);
673 if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
674 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_TEXCOORD].vbo);
675 glTexCoordPointer(vattr[MESH_ATTR_TEXCOORD].nelem, GL_FLOAT, 0, 0);
676 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
678 if(vattr[MESH_ATTR_COLOR].vbo_valid) {
679 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_COLOR].vbo);
680 glColorPointer(vattr[MESH_ATTR_COLOR].nelem, GL_FLOAT, 0, 0);
681 glEnableClientState(GL_COLOR_ARRAY);
685 glBindBuffer(GL_ARRAY_BUFFER, 0);
690 void Mesh::draw() const
692 if(!pre_draw()) return;
695 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
696 glDrawElements(GL_TRIANGLES, nfaces * 3, GL_UNSIGNED_INT, 0);
697 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
699 glDrawArrays(GL_TRIANGLES, 0, nverts);
705 void Mesh::post_draw() const
707 if(cur_sdr && use_custom_sdr_attr) {
708 // rendered with shaders
709 for(int i=0; i<NUM_MESH_ATTR; i++) {
710 int loc = global_sdr_loc[i];
711 if(loc >= 0 && vattr[i].vbo_valid) {
712 glDisableVertexAttribArray(loc);
716 #ifndef GL_ES_VERSION_2_0
717 // rendered with fixed-function
718 glDisableClientState(GL_VERTEX_ARRAY);
719 if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
720 glDisableClientState(GL_NORMAL_ARRAY);
722 if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
723 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
725 if(vattr[MESH_ATTR_COLOR].vbo_valid) {
726 glDisableClientState(GL_COLOR_ARRAY);
732 void Mesh::draw_wire() const
734 if(!pre_draw()) return;
736 ((Mesh*)this)->update_wire_ibo();
738 int num_faces = get_poly_count();
739 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
740 glDrawElements(GL_LINES, num_faces * 6, GL_UNSIGNED_INT, 0);
741 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
746 void Mesh::draw_vertices() const
748 if(!pre_draw()) return;
750 glDrawArrays(GL_POINTS, 0, nverts);
755 void Mesh::draw_normals() const
759 glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
761 Vec3 *varr = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX);
762 Vec3 *norm = (Vec3*)get_attrib_data(MESH_ATTR_NORMAL);
768 if(cur_sdr && use_custom_sdr_attr) {
769 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
775 for(size_t i=0; i<nverts; i++) {
776 glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
777 Vec3 end = varr[i] + norm[i] * vis_vecsize;
778 glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
781 for(size_t i=0; i<nverts; i++) {
782 glVertex3f(varr[i].x, varr[i].y, varr[i].z);
783 Vec3 end = varr[i] + norm[i] * vis_vecsize;
784 glVertex3f(end.x, end.y, end.z);
791 void Mesh::draw_tangents() const
795 glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
797 Vec3 *varr = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX);
798 Vec3 *tang = (Vec3*)get_attrib_data(MESH_ATTR_TANGENT);
804 if(cur_sdr && use_custom_sdr_attr) {
805 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
811 for(size_t i=0; i<nverts; i++) {
812 glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
813 Vec3 end = varr[i] + tang[i] * vis_vecsize;
814 glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
817 for(size_t i=0; i<nverts; i++) {
818 glVertex3f(varr[i].x, varr[i].y, varr[i].z);
819 Vec3 end = varr[i] + tang[i] * vis_vecsize;
820 glVertex3f(end.x, end.y, end.z);
827 void Mesh::get_aabbox(Vec3 *vmin, Vec3 *vmax) const
830 ((Mesh*)this)->calc_aabb();
836 const AABox &Mesh::get_aabbox() const
839 ((Mesh*)this)->calc_aabb();
844 float Mesh::get_bsphere(Vec3 *center, float *rad) const
847 ((Mesh*)this)->calc_bsph();
849 *center = bsph.center;
854 const Sphere &Mesh::get_bsphere() const
857 ((Mesh*)this)->calc_bsph();
863 void Mesh::set_intersect_mode(unsigned int mode)
865 Mesh::intersect_mode = mode;
869 unsigned int Mesh::get_intersect_mode()
871 return Mesh::intersect_mode;
875 void Mesh::set_vertex_select_distance(float dist)
877 Mesh::vertex_sel_dist = dist;
881 float Mesh::get_vertex_select_distance()
883 return Mesh::vertex_sel_dist;
886 bool Mesh::intersect(const Ray &ray, HitPoint *hit) const
888 assert((Mesh::intersect_mode & (ISECT_VERTICES | ISECT_FACE)) != (ISECT_VERTICES | ISECT_FACE));
890 const Vec3 *varr = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX);
891 const Vec3 *narr = (Vec3*)get_attrib_data(MESH_ATTR_NORMAL);
895 const unsigned int *idxarr = get_index_data();
897 // first test with the bounding box
899 get_aabbox(&box.min, &box.max);
900 if(!box.intersect(ray)) {
904 HitPoint nearest_hit;
905 nearest_hit.dist = FLT_MAX;
908 if(Mesh::intersect_mode & ISECT_VERTICES) {
909 // we asked for "intersections" with the vertices of the mesh
910 long nearest_vidx = -1;
911 float thres_sq = Mesh::vertex_sel_dist * Mesh::vertex_sel_dist;
913 for(unsigned int i=0; i<nverts; i++) {
915 if((Mesh::intersect_mode & ISECT_FRONT) && dot(narr[i], ray.dir) > 0) {
919 // project the vertex onto the ray line
920 float t = dot(varr[i] - ray.origin, ray.dir);
921 Vec3 vproj = ray.origin + ray.dir * t;
923 float dist_sq = length_sq(vproj - varr[i]);
924 if(dist_sq < thres_sq) {
928 if(t < nearest_hit.dist) {
929 nearest_hit.dist = t;
935 if(nearest_vidx != -1) {
936 hitvert = varr[nearest_vidx];
937 nearest_hit.obj = &hitvert;
941 // regular intersection test with polygons
943 for(unsigned int i=0; i<nfaces; i++) {
944 Triangle face(i, varr, idxarr);
946 // ignore back-facing polygons if the mode flags include ISECT_FRONT
947 if((Mesh::intersect_mode & ISECT_FRONT) && dot(face.get_normal(), ray.dir) > 0) {
952 if(face.intersect(ray, hit ? &fhit : 0)) {
956 if(fhit.dist < nearest_hit.dist) {
964 if(nearest_hit.obj) {
968 // if we are interested in the mesh and not the faces set obj to this
969 if(Mesh::intersect_mode & ISECT_FACE) {
971 } else if(Mesh::intersect_mode & ISECT_VERTICES) {
983 // texture coordinate manipulation
984 void Mesh::texcoord_apply_xform(const Mat4 &xform)
986 if(!has_attrib(MESH_ATTR_TEXCOORD)) {
990 for(unsigned int i=0; i<nverts; i++) {
991 Vec4 tc = get_attrib(MESH_ATTR_TEXCOORD, i);
992 set_attrib(MESH_ATTR_TEXCOORD, i, xform * tc);
996 void Mesh::texcoord_gen_plane(const Vec3 &norm, const Vec3 &tang)
1000 if(!has_attrib(MESH_ATTR_TEXCOORD)) {
1001 // allocate texture coordinate attribute array
1002 set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts);
1005 Vec3 n = normalize(norm);
1006 Vec3 b = normalize(cross(n, tang));
1007 Vec3 t = cross(b, n);
1009 for(unsigned int i=0; i<nverts; i++) {
1010 Vec3 pos = Vec3(get_attrib(MESH_ATTR_VERTEX, i));
1012 // distance along the tangent direction
1013 float u = dot(pos, t);
1014 // distance along the bitangent direction
1015 float v = dot(pos, b);
1017 set_attrib(MESH_ATTR_TEXCOORD, i, Vec4(u, v, 0, 1));
1021 void Mesh::texcoord_gen_box()
1023 if(!nverts || !has_attrib(MESH_ATTR_NORMAL)) return;
1025 if(!has_attrib(MESH_ATTR_TEXCOORD)) {
1026 // allocate texture coordinate attribute array
1027 set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts);
1030 for(unsigned int i=0; i<nverts; i++) {
1031 Vec3 pos = Vec3(get_attrib(MESH_ATTR_VERTEX, i)) * 0.5 + Vec3(0.5, 0.5, 0.5);
1032 Vec3 norm = Vec3(get_attrib(MESH_ATTR_NORMAL, i));
1034 float abs_nx = fabs(norm.x);
1035 float abs_ny = fabs(norm.y);
1036 float abs_nz = fabs(norm.z);
1037 int dom = abs_nx > abs_ny && abs_nx > abs_nz ? 0 : (abs_ny > abs_nz ? 1 : 2);
1039 float uv[2], *uvptr = uv;
1040 for(int j=0; j<3; j++) {
1041 if(j == dom) continue; // skip dominant axis
1045 set_attrib(MESH_ATTR_TEXCOORD, i, Vec4(uv[0], uv[1], 0, 1));
1049 void Mesh::texcoord_gen_cylinder()
1053 if(!has_attrib(MESH_ATTR_TEXCOORD)) {
1054 // allocate texture coordinate attribute array
1055 set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts);
1058 for(unsigned int i=0; i<nverts; i++) {
1059 Vec3 pos = Vec3(get_attrib(MESH_ATTR_VERTEX, i));
1061 float rho = sqrt(pos.x * pos.x + pos.z * pos.z);
1062 float theta = rho == 0.0 ? 0.0 : atan2(pos.z / rho, pos.x / rho);
1064 float u = theta / (2.0 * M_PI) + 0.5;
1067 set_attrib(MESH_ATTR_TEXCOORD, i, Vec4(u, v, 0, 1));
1072 bool Mesh::dump(const char *fname) const
1074 FILE *fp = fopen(fname, "wb");
1076 bool res = dump(fp);
1083 bool Mesh::dump(FILE *fp) const
1085 if(!has_attrib(MESH_ATTR_VERTEX)) {
1089 fprintf(fp, "VERTEX ATTRIBUTES\n");
1090 static const char *label[] = { "pos", "nor", "tan", "tex", "col", "bw", "bid" };
1091 static const char *elemfmt[] = { 0, " %s(%g)", " %s(%g, %g)", " %s(%g, %g, %g)", " %s(%g, %g, %g, %g)", 0 };
1093 for(int i=0; i<(int)nverts; i++) {
1094 fprintf(fp, "%5u:", i);
1095 for(int j=0; j<NUM_MESH_ATTR; j++) {
1097 Vec4 v = get_attrib(j, i);
1098 int nelem = vattr[j].nelem;
1099 fprintf(fp, elemfmt[nelem], label[j], v.x, v.y, v.z, v.w);
1106 const unsigned int *idx = get_index_data();
1107 int numidx = get_index_count();
1108 int numtri = numidx / 3;
1109 assert(numidx % 3 == 0);
1111 fprintf(fp, "FACES\n");
1113 for(int i=0; i<numtri; i++) {
1114 fprintf(fp, "%5d: %d %d %d\n", i, idx[0], idx[1], idx[2]);
1121 bool Mesh::dump_obj(const char *fname) const
1123 FILE *fp = fopen(fname, "wb");
1125 bool res = dump_obj(fp);
1132 bool Mesh::dump_obj(FILE *fp) const
1134 if(!has_attrib(MESH_ATTR_VERTEX)) {
1138 for(int i=0; i<(int)nverts; i++) {
1139 Vec4 v = get_attrib(MESH_ATTR_VERTEX, i);
1140 fprintf(fp, "v %g %g %g\n", v.x, v.y, v.z);
1143 if(has_attrib(MESH_ATTR_NORMAL)) {
1144 for(int i=0; i<(int)nverts; i++) {
1145 Vec4 v = get_attrib(MESH_ATTR_NORMAL, i);
1146 fprintf(fp, "vn %g %g %g\n", v.x, v.y, v.z);
1150 if(has_attrib(MESH_ATTR_TEXCOORD)) {
1151 for(int i=0; i<(int)nverts; i++) {
1152 Vec4 v = get_attrib(MESH_ATTR_TEXCOORD, i);
1153 fprintf(fp, "vt %g %g\n", v.x, v.y);
1158 const unsigned int *idxptr = get_index_data();
1159 int numidx = get_index_count();
1160 int numtri = numidx / 3;
1161 assert(numidx % 3 == 0);
1163 for(int i=0; i<numtri; i++) {
1165 for(int j=0; j<3; j++) {
1166 unsigned int idx = *idxptr++ + 1;
1167 fprintf(fp, " %u/%u/%u", idx, idx, idx);
1172 int numtri = nverts / 3;
1173 unsigned int idx = 1;
1174 for(int i=0; i<numtri; i++) {
1176 for(int j=0; j<3; j++) {
1177 fprintf(fp, " %u/%u/%u", idx, idx, idx);
1186 // ------ private member functions ------
1188 void Mesh::calc_aabb()
1190 // the cast is to force calling the const version which doesn't invalidate
1191 if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
1195 aabb.min = Vec3(FLT_MAX, FLT_MAX, FLT_MAX);
1196 aabb.max = -aabb.min;
1198 for(unsigned int i=0; i<nverts; i++) {
1199 Vec4 v = get_attrib(MESH_ATTR_VERTEX, i);
1200 for(int j=0; j<3; j++) {
1201 if(v[j] < aabb.min[j]) {
1204 if(v[j] > aabb.max[j]) {
1212 void Mesh::calc_bsph()
1214 // the cast is to force calling the const version which doesn't invalidate
1215 if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
1220 bsph.center = Vec3(0, 0, 0);
1222 // first find the center
1223 for(unsigned int i=0; i<nverts; i++) {
1224 v = Vec3(get_attrib(MESH_ATTR_VERTEX, i));
1227 bsph.center /= (float)nverts;
1230 for(unsigned int i=0; i<nverts; i++) {
1231 v = Vec3(get_attrib(MESH_ATTR_VERTEX, i));
1232 float dist_sq = length_sq(v - bsph.center);
1233 if(dist_sq > bsph.radius) {
1234 bsph.radius = dist_sq;
1237 bsph.radius = sqrt(bsph.radius);
1242 void Mesh::update_buffers()
1244 for(int i=0; i<NUM_MESH_ATTR; i++) {
1245 if(has_attrib(i) && !vattr[i].vbo_valid) {
1246 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
1247 glBufferData(GL_ARRAY_BUFFER, nverts * vattr[i].nelem * sizeof(float), &vattr[i].data[0], GL_STATIC_DRAW);
1248 vattr[i].vbo_valid = true;
1251 glBindBuffer(GL_ARRAY_BUFFER, 0);
1253 if(idata_valid && !ibo_valid) {
1254 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
1255 glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 3 * sizeof(unsigned int), &idata[0], GL_STATIC_DRAW);
1258 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1261 void Mesh::update_wire_ibo()
1265 if(wire_ibo_valid) {
1270 glGenBuffers(1, &wire_ibo);
1273 int num_faces = get_poly_count();
1275 unsigned int *wire_idxarr = new unsigned int[num_faces * 6];
1276 unsigned int *dest = wire_idxarr;
1279 // we're dealing with an indexed mesh
1280 const unsigned int *idxarr = ((const Mesh*)this)->get_index_data();
1282 for(int i=0; i<num_faces; i++) {
1283 *dest++ = idxarr[0];
1284 *dest++ = idxarr[1];
1285 *dest++ = idxarr[1];
1286 *dest++ = idxarr[2];
1287 *dest++ = idxarr[2];
1288 *dest++ = idxarr[0];
1292 // not an indexed mesh ...
1293 for(int i=0; i<num_faces; i++) {
1304 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
1305 glBufferData(GL_ELEMENT_ARRAY_BUFFER, num_faces * 6 * sizeof(unsigned int), wire_idxarr, GL_STATIC_DRAW);
1306 delete [] wire_idxarr;
1307 wire_ibo_valid = true;
1308 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1312 // ------ class Triangle ------
1313 Triangle::Triangle()
1315 normal_valid = false;
1319 Triangle::Triangle(const Vec3 &v0, const Vec3 &v1, const Vec3 &v2)
1324 normal_valid = false;
1328 Triangle::Triangle(int n, const Vec3 *varr, const unsigned int *idxarr)
1331 v[0] = varr[idxarr[n * 3]];
1332 v[1] = varr[idxarr[n * 3 + 1]];
1333 v[2] = varr[idxarr[n * 3 + 2]];
1336 v[1] = varr[n * 3 + 1];
1337 v[2] = varr[n * 3 + 2];
1339 normal_valid = false;
1343 void Triangle::calc_normal()
1345 normal = normalize(cross(v[1] - v[0], v[2] - v[0]));
1346 normal_valid = true;
1349 const Vec3 &Triangle::get_normal() const
1352 ((Triangle*)this)->calc_normal();
1357 void Triangle::transform(const Mat4 &xform)
1359 v[0] = xform * v[0];
1360 v[1] = xform * v[1];
1361 v[2] = xform * v[2];
1362 normal_valid = false;
1365 void Triangle::draw() const
1368 n[0] = n[1] = n[2] = get_normal();
1370 int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
1371 int nloc = Mesh::get_attrib_location(MESH_ATTR_NORMAL);
1373 glEnableVertexAttribArray(vloc);
1374 glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
1375 glVertexAttribPointer(nloc, 3, GL_FLOAT, GL_FALSE, 0, &n[0].x);
1377 glDrawArrays(GL_TRIANGLES, 0, 3);
1379 glDisableVertexAttribArray(vloc);
1380 glDisableVertexAttribArray(nloc);
1383 void Triangle::draw_wire() const
1385 static const int idxarr[] = {0, 1, 1, 2, 2, 0};
1386 int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
1388 glEnableVertexAttribArray(vloc);
1389 glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
1391 glDrawElements(GL_LINES, 6, GL_UNSIGNED_INT, idxarr);
1393 glDisableVertexAttribArray(vloc);
1396 Vec3 Triangle::calc_barycentric(const Vec3 &pos) const
1398 Vec3 norm = get_normal();
1400 float area_sq = fabs(dot(cross(v[1] - v[0], v[2] - v[0]), norm));
1401 if(area_sq < 1e-5) {
1402 return Vec3(0, 0, 0);
1405 float asq0 = fabs(dot(cross(v[1] - pos, v[2] - pos), norm));
1406 float asq1 = fabs(dot(cross(v[2] - pos, v[0] - pos), norm));
1407 float asq2 = fabs(dot(cross(v[0] - pos, v[1] - pos), norm));
1409 return Vec3(asq0 / area_sq, asq1 / area_sq, asq2 / area_sq);
1412 bool Triangle::intersect(const Ray &ray, HitPoint *hit) const
1414 Vec3 normal = get_normal();
1416 float ndotdir = dot(ray.dir, normal);
1417 if(fabs(ndotdir) < 1e-4) {
1421 Vec3 vertdir = v[0] - ray.origin;
1422 float t = dot(normal, vertdir) / ndotdir;
1424 Vec3 pos = ray.origin + ray.dir * t;
1425 Vec3 bary = calc_barycentric(pos);
1427 if(bary.x + bary.y + bary.z > 1.00001) {
1433 hit->pos = ray.origin + ray.dir * t;
1434 hit->normal = normal;