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, 7 };
13 unsigned int Mesh::intersect_mode = ISECT_DEFAULT;
14 float Mesh::vertex_sel_dist = 0.01;
15 float Mesh::vis_vecsize = 1.0;
21 glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects);
23 for(int i=0; i<NUM_MESH_ATTR; i++) {
24 vattr[i].vbo = buffer_objects[i];
26 ibo = buffer_objects[NUM_MESH_ATTR];
32 glDeleteBuffers(NUM_MESH_ATTR + 1, buffer_objects);
35 glDeleteBuffers(1, &wire_ibo);
39 Mesh::Mesh(const Mesh &rhs)
43 glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects);
45 for(int i=0; i<NUM_MESH_ATTR; i++) {
46 vattr[i].vbo = buffer_objects[i];
48 ibo = buffer_objects[NUM_MESH_ATTR];
54 Mesh &Mesh::operator =(const Mesh &rhs)
62 bool Mesh::clone(const Mesh &m)
66 for(int i=0; i<NUM_MESH_ATTR; i++) {
68 m.get_attrib_data(i); // force validation of the actual data on the source mesh
70 vattr[i].nelem = m.vattr[i].nelem;
71 vattr[i].data = m.vattr[i].data; // copy the actual data
72 vattr[i].data_valid = true;
77 m.get_index_data(); // again, force validation
79 // copy the index data
90 memcpy(cur_val, m.cur_val, sizeof cur_val);
93 aabb_valid = m.aabb_valid;
95 bsph_valid = m.bsph_valid;
100 intersect_mode = m.intersect_mode;
101 vertex_sel_dist = m.vertex_sel_dist;
102 vis_vecsize = m.vis_vecsize;
107 void Mesh::set_name(const char *name)
112 const char *Mesh::get_name() const
117 bool Mesh::has_attrib(int attr) const
119 if(attr < 0 || attr >= NUM_MESH_ATTR) {
123 // if neither of these is valid, then nobody has set this attribute
124 return vattr[attr].vbo_valid || vattr[attr].data_valid;
127 bool Mesh::is_indexed() const
129 return ibo_valid || idata_valid;
136 for(int i=0; i<NUM_MESH_ATTR; i++) {
138 vattr[i].vbo_valid = false;
139 vattr[i].data_valid = false;
140 //vattr[i].sdr_loc = -1;
141 vattr[i].data.clear();
143 ibo_valid = idata_valid = false;
146 wire_ibo_valid = false;
154 float *Mesh::set_attrib_data(int attrib, int nelem, unsigned int num, const float *data)
156 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
157 fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
161 if(nverts && num != nverts) {
162 fprintf(stderr, "%s: attribute count missmatch (%d instead of %d)\n", __FUNCTION__, num, nverts);
167 vattr[attrib].data.clear();
168 vattr[attrib].nelem = nelem;
169 vattr[attrib].data.resize(num * nelem);
172 memcpy(&vattr[attrib].data[0], data, num * nelem * sizeof *data);
175 vattr[attrib].data_valid = true;
176 vattr[attrib].vbo_valid = false;
177 return &vattr[attrib].data[0];
180 float *Mesh::get_attrib_data(int attrib)
182 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
183 fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
187 vattr[attrib].vbo_valid = false;
188 return (float*)((const Mesh*)this)->get_attrib_data(attrib);
191 const float *Mesh::get_attrib_data(int attrib) const
193 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
194 fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
198 if(!vattr[attrib].data_valid) {
199 #if GL_ES_VERSION_2_0
200 fprintf(stderr, "%s: can't read back attrib data on CrippledGL ES\n", __FUNCTION__);
203 if(!vattr[attrib].vbo_valid) {
204 fprintf(stderr, "%s: unavailable attrib: %d\n", __FUNCTION__, attrib);
208 // local data copy is unavailable, grab the data from the vbo
209 Mesh *m = (Mesh*)this;
210 m->vattr[attrib].data.resize(nverts * vattr[attrib].nelem);
212 glBindBuffer(GL_ARRAY_BUFFER, vattr[attrib].vbo);
213 void *data = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
214 memcpy(&m->vattr[attrib].data[0], data, nverts * vattr[attrib].nelem * sizeof(float));
215 glUnmapBuffer(GL_ARRAY_BUFFER);
217 vattr[attrib].data_valid = true;
221 return &vattr[attrib].data[0];
224 void Mesh::set_attrib(int attrib, int idx, const Vec4 &v)
226 float *data = get_attrib_data(attrib);
228 data += idx * vattr[attrib].nelem;
229 for(int i=0; i<vattr[attrib].nelem; i++) {
235 Vec4 Mesh::get_attrib(int attrib, int idx) const
237 Vec4 v(0.0, 0.0, 0.0, 1.0);
238 const float *data = get_attrib_data(attrib);
240 data += idx * vattr[attrib].nelem;
241 for(int i=0; i<vattr[attrib].nelem; i++) {
248 int Mesh::get_attrib_count(int attrib) const
250 return has_attrib(attrib) ? nverts : 0;
254 unsigned int *Mesh::set_index_data(int num, const unsigned int *indices)
256 int nidx = nfaces * 3;
257 if(nidx && num != nidx) {
258 fprintf(stderr, "%s: index count mismatch (%d instead of %d)\n", __FUNCTION__, num, nidx);
267 memcpy(&idata[0], indices, num * sizeof *indices);
276 unsigned int *Mesh::get_index_data()
279 return (unsigned int*)((const Mesh*)this)->get_index_data();
282 const unsigned int *Mesh::get_index_data() const
285 #if GL_ES_VERSION_2_0
286 fprintf(stderr, "%s: can't read back index data in CrippledGL ES\n", __FUNCTION__);
290 fprintf(stderr, "%s: indices unavailable\n", __FUNCTION__);
294 // local data copy is unavailable, gram the data from the ibo
295 Mesh *m = (Mesh*)this;
296 int nidx = nfaces * 3;
297 m->idata.resize(nidx);
299 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
300 void *data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY);
301 memcpy(&m->idata[0], data, nidx * sizeof(unsigned int));
302 glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
311 int Mesh::get_index_count() const
316 void Mesh::append(const Mesh &mesh)
318 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
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());
339 if(ibo_valid || idata_valid) {
340 // make index arrays valid
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++) {
355 wire_ibo_valid = false;
360 // assemble a complete vertex by adding all the useful attributes
361 void Mesh::vertex(float x, float y, float z)
363 cur_val[MESH_ATTR_VERTEX] = Vec4(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]);
373 vattr[i].vbo_valid = false;
379 ibo_valid = idata_valid = false;
382 void Mesh::normal(float nx, float ny, float nz)
384 cur_val[MESH_ATTR_NORMAL] = Vec4(nx, ny, nz, 1.0f);
385 vattr[MESH_ATTR_NORMAL].data_valid = true;
386 vattr[MESH_ATTR_NORMAL].nelem = 3;
389 void Mesh::tangent(float tx, float ty, float tz)
391 cur_val[MESH_ATTR_TANGENT] = Vec4(tx, ty, tz, 1.0f);
392 vattr[MESH_ATTR_TANGENT].data_valid = true;
393 vattr[MESH_ATTR_TANGENT].nelem = 3;
396 void Mesh::texcoord(float u, float v, float w)
398 cur_val[MESH_ATTR_TEXCOORD] = Vec4(u, v, w, 1.0f);
399 vattr[MESH_ATTR_TEXCOORD].data_valid = true;
400 vattr[MESH_ATTR_TEXCOORD].nelem = 3;
403 void Mesh::boneweights(float w1, float w2, float w3, float w4)
405 cur_val[MESH_ATTR_BONEWEIGHTS] = Vec4(w1, w2, w3, w4);
406 vattr[MESH_ATTR_BONEWEIGHTS].data_valid = true;
407 vattr[MESH_ATTR_BONEWEIGHTS].nelem = 4;
410 void Mesh::boneidx(int idx1, int idx2, int idx3, int idx4)
412 cur_val[MESH_ATTR_BONEIDX] = Vec4(idx1, idx2, idx3, idx4);
413 vattr[MESH_ATTR_BONEIDX].data_valid = true;
414 vattr[MESH_ATTR_BONEIDX].nelem = 4;
417 int Mesh::get_poly_count() const
429 void Mesh::set_attrib_location(int attr, int loc)
431 if(attr < 0 || attr >= NUM_MESH_ATTR) {
434 Mesh::global_sdr_loc[attr] = loc;
438 int Mesh::get_attrib_location(int attr)
440 if(attr < 0 || attr >= NUM_MESH_ATTR) {
443 return Mesh::global_sdr_loc[attr];
447 void Mesh::clear_attrib_locations()
449 for(int i=0; i<NUM_MESH_ATTR; i++) {
450 Mesh::global_sdr_loc[i] = -1;
455 void Mesh::set_vis_vecsize(float sz)
457 Mesh::vis_vecsize = sz;
460 float Mesh::get_vis_vecsize()
462 return Mesh::vis_vecsize;
465 void Mesh::apply_xform(const Mat4 &xform)
467 Mat4 dir_xform = xform.upper3x3();
468 apply_xform(xform, dir_xform);
471 void Mesh::apply_xform(const Mat4 &xform, const Mat4 &dir_xform)
473 for(unsigned int i=0; i<nverts; i++) {
474 Vec4 v = get_attrib(MESH_ATTR_VERTEX, i);
475 set_attrib(MESH_ATTR_VERTEX, i, xform * v);
477 if(has_attrib(MESH_ATTR_NORMAL)) {
478 Vec3 n = Vec3(get_attrib(MESH_ATTR_NORMAL, i));
479 set_attrib(MESH_ATTR_NORMAL, i, Vec4(dir_xform * n));
481 if(has_attrib(MESH_ATTR_TANGENT)) {
482 Vec3 t = Vec3(get_attrib(MESH_ATTR_TANGENT, i));
483 set_attrib(MESH_ATTR_TANGENT, i, Vec4(dir_xform * t));
494 void Mesh::flip_faces()
497 unsigned int *indices = get_index_data();
500 int idxnum = get_index_count();
501 for(int i=0; i<idxnum; i+=3) {
502 unsigned int tmp = indices[i + 2];
503 indices[i + 2] = indices[i + 1];
504 indices[i + 1] = tmp;
508 Vec3 *verts = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX);
511 int vnum = get_attrib_count(MESH_ATTR_VERTEX);
512 for(int i=0; i<vnum; i+=3) {
513 Vec3 tmp = verts[i + 2];
514 verts[i + 2] = verts[i + 1];
520 void Mesh::flip_normals()
522 Vec3 *normals = (Vec3*)get_attrib_data(MESH_ATTR_NORMAL);
525 int num = get_attrib_count(MESH_ATTR_NORMAL);
526 for(int i=0; i<num; i++) {
527 normals[i] = -normals[i];
533 if(!is_indexed()) return; // no vertex sharing is possible in unindexed meshes
535 unsigned int *indices = get_index_data();
538 int idxnum = get_index_count();
539 int nnverts = idxnum;
543 for(int i=0; i<NUM_MESH_ATTR; i++) {
544 if(!has_attrib(i)) continue;
546 const float *srcbuf = get_attrib_data(i);
548 float *tmpbuf = new float[nnverts * vattr[i].nelem];
549 float *dstptr = tmpbuf;
550 for(int j=0; j<idxnum; j++) {
551 unsigned int idx = indices[j];
552 const float *srcptr = srcbuf + idx * vattr[i].nelem;
554 for(int k=0; k<vattr[i].nelem; k++) {
555 *dstptr++ = *srcptr++;
558 set_attrib_data(i, vattr[i].nelem, nnverts, tmpbuf);
569 void Mesh::calc_face_normals()
571 const Vec3 *varr = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX);
572 Vec3 *narr = (Vec3*)get_attrib_data(MESH_ATTR_NORMAL);
578 const unsigned int *idxarr = get_index_data();
580 for(unsigned int i=0; i<nfaces; i++) {
581 Triangle face(i, varr, idxarr);
584 for(int j=0; j<3; j++) {
585 unsigned int idx = *idxarr++;
586 narr[idx] = face.normal;
591 int nfaces = nverts / 3;
593 for(int i=0; i<nfaces; i++) {
594 Triangle face(varr[0], varr[1], varr[2]);
597 narr[0] = narr[1] = narr[2] = face.normal;
598 varr += vattr[MESH_ATTR_VERTEX].nelem;
599 narr += vattr[MESH_ATTR_NORMAL].nelem;
605 int Mesh::add_bone(XFormNode *bone)
607 int idx = bones.size();
608 bones.push_back(bone);
612 const XFormNode *Mesh::get_bone(int idx) const
614 if(idx < 0 || idx >= (int)bones.size()) {
620 int Mesh::get_bones_count() const
622 return (int)bones.size();
626 bool Mesh::pre_draw() const
629 glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
631 ((Mesh*)this)->update_buffers();
633 if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
634 fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
638 if(cur_sdr && use_custom_sdr_attr) {
639 // rendering with shaders
640 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
641 fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__);
645 for(int i=0; i<NUM_MESH_ATTR; i++) {
646 int loc = global_sdr_loc[i];
647 if(loc >= 0 && vattr[i].vbo_valid) {
648 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
649 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
650 glEnableVertexAttribArray(loc);
654 #ifndef GL_ES_VERSION_2_0
655 // rendering with fixed-function (not available in GLES2)
656 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_VERTEX].vbo);
657 glVertexPointer(vattr[MESH_ATTR_VERTEX].nelem, GL_FLOAT, 0, 0);
658 glEnableClientState(GL_VERTEX_ARRAY);
660 if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
661 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_NORMAL].vbo);
662 glNormalPointer(GL_FLOAT, 0, 0);
663 glEnableClientState(GL_NORMAL_ARRAY);
665 if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
666 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_TEXCOORD].vbo);
667 glTexCoordPointer(vattr[MESH_ATTR_TEXCOORD].nelem, GL_FLOAT, 0, 0);
668 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
670 if(vattr[MESH_ATTR_COLOR].vbo_valid) {
671 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_COLOR].vbo);
672 glColorPointer(vattr[MESH_ATTR_COLOR].nelem, GL_FLOAT, 0, 0);
673 glEnableClientState(GL_COLOR_ARRAY);
675 if(vattr[MESH_ATTR_TEXCOORD2].vbo_valid) {
676 glClientActiveTexture(GL_TEXTURE1);
677 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_TEXCOORD2].vbo);
678 glTexCoordPointer(vattr[MESH_ATTR_TEXCOORD2].nelem, GL_FLOAT, 0, 0);
679 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
680 glClientActiveTexture(GL_TEXTURE0);
684 glBindBuffer(GL_ARRAY_BUFFER, 0);
689 void Mesh::draw() const
691 if(!pre_draw()) return;
694 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
695 glDrawElements(GL_TRIANGLES, nfaces * 3, GL_UNSIGNED_INT, 0);
696 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
698 glDrawArrays(GL_TRIANGLES, 0, nverts);
704 void Mesh::post_draw() const
706 if(cur_sdr && use_custom_sdr_attr) {
707 // rendered with shaders
708 for(int i=0; i<NUM_MESH_ATTR; i++) {
709 int loc = global_sdr_loc[i];
710 if(loc >= 0 && vattr[i].vbo_valid) {
711 glDisableVertexAttribArray(loc);
715 #ifndef GL_ES_VERSION_2_0
716 // rendered with fixed-function
717 glDisableClientState(GL_VERTEX_ARRAY);
718 if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
719 glDisableClientState(GL_NORMAL_ARRAY);
721 if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
722 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
724 if(vattr[MESH_ATTR_COLOR].vbo_valid) {
725 glDisableClientState(GL_COLOR_ARRAY);
727 if(vattr[MESH_ATTR_TEXCOORD2].vbo_valid) {
728 glClientActiveTexture(GL_TEXTURE1);
729 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
730 glClientActiveTexture(GL_TEXTURE0);
736 void Mesh::draw_wire() const
738 if(!pre_draw()) return;
740 ((Mesh*)this)->update_wire_ibo();
742 int num_faces = get_poly_count();
743 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
744 glDrawElements(GL_LINES, num_faces * 6, GL_UNSIGNED_INT, 0);
745 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
750 void Mesh::draw_vertices() const
752 if(!pre_draw()) return;
754 glDrawArrays(GL_POINTS, 0, nverts);
759 void Mesh::draw_normals() const
763 glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
765 Vec3 *varr = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX);
766 Vec3 *norm = (Vec3*)get_attrib_data(MESH_ATTR_NORMAL);
772 if(cur_sdr && use_custom_sdr_attr) {
773 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
779 for(size_t i=0; i<nverts; i++) {
780 glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
781 Vec3 end = varr[i] + norm[i] * vis_vecsize;
782 glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
785 for(size_t i=0; i<nverts; i++) {
786 glVertex3f(varr[i].x, varr[i].y, varr[i].z);
787 Vec3 end = varr[i] + norm[i] * vis_vecsize;
788 glVertex3f(end.x, end.y, end.z);
795 void Mesh::draw_tangents() const
799 glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
801 Vec3 *varr = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX);
802 Vec3 *tang = (Vec3*)get_attrib_data(MESH_ATTR_TANGENT);
808 if(cur_sdr && use_custom_sdr_attr) {
809 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
815 for(size_t i=0; i<nverts; i++) {
816 glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
817 Vec3 end = varr[i] + tang[i] * vis_vecsize;
818 glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
821 for(size_t i=0; i<nverts; i++) {
822 glVertex3f(varr[i].x, varr[i].y, varr[i].z);
823 Vec3 end = varr[i] + tang[i] * vis_vecsize;
824 glVertex3f(end.x, end.y, end.z);
831 void Mesh::get_aabbox(Vec3 *vmin, Vec3 *vmax) const
834 ((Mesh*)this)->calc_aabb();
840 const AABox &Mesh::get_aabbox() const
843 ((Mesh*)this)->calc_aabb();
848 float Mesh::get_bsphere(Vec3 *center, float *rad) const
851 ((Mesh*)this)->calc_bsph();
853 *center = bsph.center;
858 const Sphere &Mesh::get_bsphere() const
861 ((Mesh*)this)->calc_bsph();
867 void Mesh::set_intersect_mode(unsigned int mode)
869 Mesh::intersect_mode = mode;
873 unsigned int Mesh::get_intersect_mode()
875 return Mesh::intersect_mode;
879 void Mesh::set_vertex_select_distance(float dist)
881 Mesh::vertex_sel_dist = dist;
885 float Mesh::get_vertex_select_distance()
887 return Mesh::vertex_sel_dist;
890 bool Mesh::intersect(const Ray &ray, HitPoint *hit) const
892 assert((Mesh::intersect_mode & (ISECT_VERTICES | ISECT_FACE)) != (ISECT_VERTICES | ISECT_FACE));
894 const Vec3 *varr = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX);
895 const Vec3 *narr = (Vec3*)get_attrib_data(MESH_ATTR_NORMAL);
899 const unsigned int *idxarr = get_index_data();
901 // first test with the bounding box
903 get_aabbox(&box.min, &box.max);
904 if(!box.intersect(ray)) {
908 HitPoint nearest_hit;
909 nearest_hit.dist = FLT_MAX;
910 nearest_hit.data = 0;
912 if(Mesh::intersect_mode & ISECT_VERTICES) {
913 // we asked for "intersections" with the vertices of the mesh
914 long nearest_vidx = -1;
915 float thres_sq = Mesh::vertex_sel_dist * Mesh::vertex_sel_dist;
917 for(unsigned int i=0; i<nverts; i++) {
919 if((Mesh::intersect_mode & ISECT_FRONT) && dot(narr[i], ray.dir) > 0) {
923 // project the vertex onto the ray line
924 float t = dot(varr[i] - ray.origin, ray.dir);
925 Vec3 vproj = ray.origin + ray.dir * t;
927 float dist_sq = length_sq(vproj - varr[i]);
928 if(dist_sq < thres_sq) {
932 if(t < nearest_hit.dist) {
933 nearest_hit.dist = t;
939 if(nearest_vidx != -1) {
940 hitvert = varr[nearest_vidx];
941 nearest_hit.data = &hitvert;
945 // regular intersection test with polygons
947 for(unsigned int i=0; i<nfaces; i++) {
948 Triangle face(i, varr, idxarr);
950 // ignore back-facing polygons if the mode flags include ISECT_FRONT
951 if((Mesh::intersect_mode & ISECT_FRONT) && dot(face.get_normal(), ray.dir) > 0) {
956 if(face.intersect(ray, hit ? &fhit : 0)) {
960 if(fhit.dist < nearest_hit.dist) {
968 if(nearest_hit.data) {
972 // if we are interested in the mesh and not the faces set obj to this
973 if(Mesh::intersect_mode & ISECT_FACE) {
974 hit->data = &hitface;
975 } else if(Mesh::intersect_mode & ISECT_VERTICES) {
976 hit->data = &hitvert;
978 hit->data = (void*)this;
987 // texture coordinate manipulation
988 void Mesh::texcoord_apply_xform(const Mat4 &xform)
990 if(!has_attrib(MESH_ATTR_TEXCOORD)) {
994 for(unsigned int i=0; i<nverts; i++) {
995 Vec4 tc = get_attrib(MESH_ATTR_TEXCOORD, i);
996 set_attrib(MESH_ATTR_TEXCOORD, i, xform * tc);
1000 void Mesh::texcoord_gen_plane(const Vec3 &norm, const Vec3 &tang)
1004 if(!has_attrib(MESH_ATTR_TEXCOORD)) {
1005 // allocate texture coordinate attribute array
1006 set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts);
1009 Vec3 n = normalize(norm);
1010 Vec3 b = normalize(cross(n, tang));
1011 Vec3 t = cross(b, n);
1013 for(unsigned int i=0; i<nverts; i++) {
1014 Vec3 pos = Vec3(get_attrib(MESH_ATTR_VERTEX, i));
1016 // distance along the tangent direction
1017 float u = dot(pos, t);
1018 // distance along the bitangent direction
1019 float v = dot(pos, b);
1021 set_attrib(MESH_ATTR_TEXCOORD, i, Vec4(u, v, 0, 1));
1025 void Mesh::texcoord_gen_box()
1027 if(!nverts || !has_attrib(MESH_ATTR_NORMAL)) return;
1029 if(!has_attrib(MESH_ATTR_TEXCOORD)) {
1030 // allocate texture coordinate attribute array
1031 set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts);
1034 for(unsigned int i=0; i<nverts; i++) {
1035 Vec3 pos = Vec3(get_attrib(MESH_ATTR_VERTEX, i)) * 0.5 + Vec3(0.5, 0.5, 0.5);
1036 Vec3 norm = Vec3(get_attrib(MESH_ATTR_NORMAL, i));
1038 float abs_nx = fabs(norm.x);
1039 float abs_ny = fabs(norm.y);
1040 float abs_nz = fabs(norm.z);
1041 int dom = abs_nx > abs_ny && abs_nx > abs_nz ? 0 : (abs_ny > abs_nz ? 1 : 2);
1043 float uv[2], *uvptr = uv;
1044 for(int j=0; j<3; j++) {
1045 if(j == dom) continue; // skip dominant axis
1049 set_attrib(MESH_ATTR_TEXCOORD, i, Vec4(uv[0], uv[1], 0, 1));
1053 void Mesh::texcoord_gen_cylinder()
1057 if(!has_attrib(MESH_ATTR_TEXCOORD)) {
1058 // allocate texture coordinate attribute array
1059 set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts);
1062 for(unsigned int i=0; i<nverts; i++) {
1063 Vec3 pos = Vec3(get_attrib(MESH_ATTR_VERTEX, i));
1065 float rho = sqrt(pos.x * pos.x + pos.z * pos.z);
1066 float theta = rho == 0.0 ? 0.0 : atan2(pos.z / rho, pos.x / rho);
1068 float u = theta / (2.0 * M_PI) + 0.5;
1071 set_attrib(MESH_ATTR_TEXCOORD, i, Vec4(u, v, 0, 1));
1076 bool Mesh::dump(const char *fname) const
1078 FILE *fp = fopen(fname, "wb");
1080 bool res = dump(fp);
1087 bool Mesh::dump(FILE *fp) const
1089 if(!has_attrib(MESH_ATTR_VERTEX)) {
1093 fprintf(fp, "VERTEX ATTRIBUTES\n");
1094 static const char *label[] = { "pos", "nor", "tan", "tex", "col", "bw", "bid", "tex2" };
1095 static const char *elemfmt[] = { 0, " %s(%g)", " %s(%g, %g)", " %s(%g, %g, %g)", " %s(%g, %g, %g, %g)", 0 };
1097 for(int i=0; i<(int)nverts; i++) {
1098 fprintf(fp, "%5u:", i);
1099 for(int j=0; j<NUM_MESH_ATTR; j++) {
1101 Vec4 v = get_attrib(j, i);
1102 int nelem = vattr[j].nelem;
1103 fprintf(fp, elemfmt[nelem], label[j], v.x, v.y, v.z, v.w);
1110 const unsigned int *idx = get_index_data();
1111 int numidx = get_index_count();
1112 int numtri = numidx / 3;
1113 assert(numidx % 3 == 0);
1115 fprintf(fp, "FACES\n");
1117 for(int i=0; i<numtri; i++) {
1118 fprintf(fp, "%5d: %d %d %d\n", i, idx[0], idx[1], idx[2]);
1125 bool Mesh::dump_obj(const char *fname) const
1127 FILE *fp = fopen(fname, "wb");
1129 bool res = dump_obj(fp);
1136 bool Mesh::dump_obj(FILE *fp) const
1138 if(!has_attrib(MESH_ATTR_VERTEX)) {
1142 for(int i=0; i<(int)nverts; i++) {
1143 Vec4 v = get_attrib(MESH_ATTR_VERTEX, i);
1144 fprintf(fp, "v %g %g %g\n", v.x, v.y, v.z);
1147 if(has_attrib(MESH_ATTR_NORMAL)) {
1148 for(int i=0; i<(int)nverts; i++) {
1149 Vec4 v = get_attrib(MESH_ATTR_NORMAL, i);
1150 fprintf(fp, "vn %g %g %g\n", v.x, v.y, v.z);
1154 if(has_attrib(MESH_ATTR_TEXCOORD)) {
1155 for(int i=0; i<(int)nverts; i++) {
1156 Vec4 v = get_attrib(MESH_ATTR_TEXCOORD, i);
1157 fprintf(fp, "vt %g %g\n", v.x, v.y);
1162 const unsigned int *idxptr = get_index_data();
1163 int numidx = get_index_count();
1164 int numtri = numidx / 3;
1165 assert(numidx % 3 == 0);
1167 for(int i=0; i<numtri; i++) {
1169 for(int j=0; j<3; j++) {
1170 unsigned int idx = *idxptr++ + 1;
1171 fprintf(fp, " %u/%u/%u", idx, idx, idx);
1176 int numtri = nverts / 3;
1177 unsigned int idx = 1;
1178 for(int i=0; i<numtri; i++) {
1180 for(int j=0; j<3; j++) {
1181 fprintf(fp, " %u/%u/%u", idx, idx, idx);
1190 // ------ private member functions ------
1192 void Mesh::calc_aabb()
1194 // the cast is to force calling the const version which doesn't invalidate
1195 if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
1199 aabb.min = Vec3(FLT_MAX, FLT_MAX, FLT_MAX);
1200 aabb.max = -aabb.min;
1202 for(unsigned int i=0; i<nverts; i++) {
1203 Vec4 v = get_attrib(MESH_ATTR_VERTEX, i);
1204 for(int j=0; j<3; j++) {
1205 if(v[j] < aabb.min[j]) {
1208 if(v[j] > aabb.max[j]) {
1216 void Mesh::calc_bsph()
1218 // the cast is to force calling the const version which doesn't invalidate
1219 if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
1224 bsph.center = Vec3(0, 0, 0);
1226 // first find the center
1227 for(unsigned int i=0; i<nverts; i++) {
1228 v = Vec3(get_attrib(MESH_ATTR_VERTEX, i));
1231 bsph.center /= (float)nverts;
1234 for(unsigned int i=0; i<nverts; i++) {
1235 v = Vec3(get_attrib(MESH_ATTR_VERTEX, i));
1236 float dist_sq = length_sq(v - bsph.center);
1237 if(dist_sq > bsph.radius) {
1238 bsph.radius = dist_sq;
1241 bsph.radius = sqrt(bsph.radius);
1246 void Mesh::update_buffers()
1248 for(int i=0; i<NUM_MESH_ATTR; i++) {
1249 if(has_attrib(i) && !vattr[i].vbo_valid) {
1250 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
1251 glBufferData(GL_ARRAY_BUFFER, nverts * vattr[i].nelem * sizeof(float), &vattr[i].data[0], GL_STATIC_DRAW);
1252 vattr[i].vbo_valid = true;
1255 glBindBuffer(GL_ARRAY_BUFFER, 0);
1257 if(idata_valid && !ibo_valid) {
1258 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
1259 glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 3 * sizeof(unsigned int), &idata[0], GL_STATIC_DRAW);
1262 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1265 void Mesh::update_wire_ibo()
1269 if(wire_ibo_valid) {
1274 glGenBuffers(1, &wire_ibo);
1277 int num_faces = get_poly_count();
1279 unsigned int *wire_idxarr = new unsigned int[num_faces * 6];
1280 unsigned int *dest = wire_idxarr;
1283 // we're dealing with an indexed mesh
1284 const unsigned int *idxarr = ((const Mesh*)this)->get_index_data();
1286 for(int i=0; i<num_faces; i++) {
1287 *dest++ = idxarr[0];
1288 *dest++ = idxarr[1];
1289 *dest++ = idxarr[1];
1290 *dest++ = idxarr[2];
1291 *dest++ = idxarr[2];
1292 *dest++ = idxarr[0];
1296 // not an indexed mesh ...
1297 for(int i=0; i<num_faces; i++) {
1308 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
1309 glBufferData(GL_ELEMENT_ARRAY_BUFFER, num_faces * 6 * sizeof(unsigned int), wire_idxarr, GL_STATIC_DRAW);
1310 delete [] wire_idxarr;
1311 wire_ibo_valid = true;
1312 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1316 // ------ class Triangle ------
1317 Triangle::Triangle()
1319 normal_valid = false;
1323 Triangle::Triangle(const Vec3 &v0, const Vec3 &v1, const Vec3 &v2)
1328 normal_valid = false;
1332 Triangle::Triangle(int n, const Vec3 *varr, const unsigned int *idxarr)
1335 v[0] = varr[idxarr[n * 3]];
1336 v[1] = varr[idxarr[n * 3 + 1]];
1337 v[2] = varr[idxarr[n * 3 + 2]];
1340 v[1] = varr[n * 3 + 1];
1341 v[2] = varr[n * 3 + 2];
1343 normal_valid = false;
1347 void Triangle::calc_normal()
1349 normal = normalize(cross(v[1] - v[0], v[2] - v[0]));
1350 normal_valid = true;
1353 const Vec3 &Triangle::get_normal() const
1356 ((Triangle*)this)->calc_normal();
1361 void Triangle::transform(const Mat4 &xform)
1363 v[0] = xform * v[0];
1364 v[1] = xform * v[1];
1365 v[2] = xform * v[2];
1366 normal_valid = false;
1369 void Triangle::draw() const
1372 n[0] = n[1] = n[2] = get_normal();
1374 int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
1375 int nloc = Mesh::get_attrib_location(MESH_ATTR_NORMAL);
1377 glEnableVertexAttribArray(vloc);
1378 glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
1379 glVertexAttribPointer(nloc, 3, GL_FLOAT, GL_FALSE, 0, &n[0].x);
1381 glDrawArrays(GL_TRIANGLES, 0, 3);
1383 glDisableVertexAttribArray(vloc);
1384 glDisableVertexAttribArray(nloc);
1387 void Triangle::draw_wire() const
1389 static const int idxarr[] = {0, 1, 1, 2, 2, 0};
1390 int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
1392 glEnableVertexAttribArray(vloc);
1393 glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
1395 glDrawElements(GL_LINES, 6, GL_UNSIGNED_INT, idxarr);
1397 glDisableVertexAttribArray(vloc);
1400 Vec3 Triangle::calc_barycentric(const Vec3 &pos) const
1402 Vec3 norm = get_normal();
1404 float area_sq = fabs(dot(cross(v[1] - v[0], v[2] - v[0]), norm));
1405 if(area_sq < 1e-5) {
1406 return Vec3(0, 0, 0);
1409 float asq0 = fabs(dot(cross(v[1] - pos, v[2] - pos), norm));
1410 float asq1 = fabs(dot(cross(v[2] - pos, v[0] - pos), norm));
1411 float asq2 = fabs(dot(cross(v[0] - pos, v[1] - pos), norm));
1413 return Vec3(asq0 / area_sq, asq1 / area_sq, asq2 / area_sq);
1416 bool Triangle::intersect(const Ray &ray, HitPoint *hit) const
1418 Vec3 normal = get_normal();
1420 float ndotdir = dot(ray.dir, normal);
1421 if(fabs(ndotdir) < 1e-4) {
1425 Vec3 vertdir = v[0] - ray.origin;
1426 float t = dot(normal, vertdir) / ndotdir;
1428 Vec3 pos = ray.origin + ray.dir * t;
1429 Vec3 bary = calc_barycentric(pos);
1431 if(bary.x + bary.y + bary.z > 1.00001) {
1437 hit->pos = ray.origin + ray.dir * t;
1438 hit->normal = normal;
1439 hit->data = (void*)this;