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];
540 int Mesh::add_bone(XFormNode *bone)
542 int idx = bones.size();
543 bones.push_back(bone);
547 const XFormNode *Mesh::get_bone(int idx) const
549 if(idx < 0 || idx >= (int)bones.size()) {
555 int Mesh::get_bones_count() const
557 return (int)bones.size();
561 bool Mesh::pre_draw() const
564 glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
566 ((Mesh*)this)->update_buffers();
568 if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
569 fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
573 if(cur_sdr && use_custom_sdr_attr) {
574 // rendering with shaders
575 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
576 fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__);
580 for(int i=0; i<NUM_MESH_ATTR; i++) {
581 int loc = global_sdr_loc[i];
582 if(loc >= 0 && vattr[i].vbo_valid) {
583 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
584 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
585 glEnableVertexAttribArray(loc);
589 #ifndef GL_ES_VERSION_2_0
590 // rendering with fixed-function (not available in GLES2)
591 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_VERTEX].vbo);
592 glVertexPointer(vattr[MESH_ATTR_VERTEX].nelem, GL_FLOAT, 0, 0);
593 glEnableClientState(GL_VERTEX_ARRAY);
595 if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
596 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_NORMAL].vbo);
597 glNormalPointer(GL_FLOAT, 0, 0);
598 glEnableClientState(GL_NORMAL_ARRAY);
600 if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
601 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_TEXCOORD].vbo);
602 glTexCoordPointer(vattr[MESH_ATTR_TEXCOORD].nelem, GL_FLOAT, 0, 0);
603 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
605 if(vattr[MESH_ATTR_COLOR].vbo_valid) {
606 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_COLOR].vbo);
607 glColorPointer(vattr[MESH_ATTR_COLOR].nelem, GL_FLOAT, 0, 0);
608 glEnableClientState(GL_COLOR_ARRAY);
612 glBindBuffer(GL_ARRAY_BUFFER, 0);
617 void Mesh::draw() const
619 if(!pre_draw()) return;
622 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
623 glDrawElements(GL_TRIANGLES, nfaces * 3, GL_UNSIGNED_INT, 0);
624 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
626 glDrawArrays(GL_TRIANGLES, 0, nverts);
632 void Mesh::post_draw() const
634 if(cur_sdr && use_custom_sdr_attr) {
635 // rendered with shaders
636 for(int i=0; i<NUM_MESH_ATTR; i++) {
637 int loc = global_sdr_loc[i];
638 if(loc >= 0 && vattr[i].vbo_valid) {
639 glDisableVertexAttribArray(loc);
643 #ifndef GL_ES_VERSION_2_0
644 // rendered with fixed-function
645 glDisableClientState(GL_VERTEX_ARRAY);
646 if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
647 glDisableClientState(GL_NORMAL_ARRAY);
649 if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
650 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
652 if(vattr[MESH_ATTR_COLOR].vbo_valid) {
653 glDisableClientState(GL_COLOR_ARRAY);
659 void Mesh::draw_wire() const
661 if(!pre_draw()) return;
663 ((Mesh*)this)->update_wire_ibo();
665 int num_faces = get_poly_count();
666 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
667 glDrawElements(GL_LINES, num_faces * 6, GL_UNSIGNED_INT, 0);
668 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
673 void Mesh::draw_vertices() const
675 if(!pre_draw()) return;
677 glDrawArrays(GL_POINTS, 0, nverts);
682 void Mesh::draw_normals() const
686 glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
688 Vec3 *varr = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX);
689 Vec3 *norm = (Vec3*)get_attrib_data(MESH_ATTR_NORMAL);
695 if(cur_sdr && use_custom_sdr_attr) {
696 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
702 for(size_t i=0; i<nverts; i++) {
703 glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
704 Vec3 end = varr[i] + norm[i] * vis_vecsize;
705 glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
708 for(size_t i=0; i<nverts; i++) {
709 glVertex3f(varr[i].x, varr[i].y, varr[i].z);
710 Vec3 end = varr[i] + norm[i] * vis_vecsize;
711 glVertex3f(end.x, end.y, end.z);
718 void Mesh::draw_tangents() const
722 glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
724 Vec3 *varr = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX);
725 Vec3 *tang = (Vec3*)get_attrib_data(MESH_ATTR_TANGENT);
731 if(cur_sdr && use_custom_sdr_attr) {
732 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
738 for(size_t i=0; i<nverts; i++) {
739 glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
740 Vec3 end = varr[i] + tang[i] * vis_vecsize;
741 glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
744 for(size_t i=0; i<nverts; i++) {
745 glVertex3f(varr[i].x, varr[i].y, varr[i].z);
746 Vec3 end = varr[i] + tang[i] * vis_vecsize;
747 glVertex3f(end.x, end.y, end.z);
754 void Mesh::get_aabbox(Vec3 *vmin, Vec3 *vmax) const
757 ((Mesh*)this)->calc_aabb();
763 const AABox &Mesh::get_aabbox() const
766 ((Mesh*)this)->calc_aabb();
771 float Mesh::get_bsphere(Vec3 *center, float *rad) const
774 ((Mesh*)this)->calc_bsph();
776 *center = bsph.center;
781 const Sphere &Mesh::get_bsphere() const
784 ((Mesh*)this)->calc_bsph();
790 void Mesh::set_intersect_mode(unsigned int mode)
792 Mesh::intersect_mode = mode;
796 unsigned int Mesh::get_intersect_mode()
798 return Mesh::intersect_mode;
802 void Mesh::set_vertex_select_distance(float dist)
804 Mesh::vertex_sel_dist = dist;
808 float Mesh::get_vertex_select_distance()
810 return Mesh::vertex_sel_dist;
813 bool Mesh::intersect(const Ray &ray, HitPoint *hit) const
815 assert((Mesh::intersect_mode & (ISECT_VERTICES | ISECT_FACE)) != (ISECT_VERTICES | ISECT_FACE));
817 const Vec3 *varr = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX);
818 const Vec3 *narr = (Vec3*)get_attrib_data(MESH_ATTR_NORMAL);
822 const unsigned int *idxarr = get_index_data();
824 // first test with the bounding box
826 get_aabbox(&box.min, &box.max);
827 if(!box.intersect(ray)) {
831 HitPoint nearest_hit;
832 nearest_hit.dist = FLT_MAX;
835 if(Mesh::intersect_mode & ISECT_VERTICES) {
836 // we asked for "intersections" with the vertices of the mesh
837 long nearest_vidx = -1;
838 float thres_sq = Mesh::vertex_sel_dist * Mesh::vertex_sel_dist;
840 for(unsigned int i=0; i<nverts; i++) {
842 if((Mesh::intersect_mode & ISECT_FRONT) && dot(narr[i], ray.dir) > 0) {
846 // project the vertex onto the ray line
847 float t = dot(varr[i] - ray.origin, ray.dir);
848 Vec3 vproj = ray.origin + ray.dir * t;
850 float dist_sq = length_sq(vproj - varr[i]);
851 if(dist_sq < thres_sq) {
855 if(t < nearest_hit.dist) {
856 nearest_hit.dist = t;
862 if(nearest_vidx != -1) {
863 hitvert = varr[nearest_vidx];
864 nearest_hit.obj = &hitvert;
868 // regular intersection test with polygons
870 for(unsigned int i=0; i<nfaces; i++) {
871 Triangle face(i, varr, idxarr);
873 // ignore back-facing polygons if the mode flags include ISECT_FRONT
874 if((Mesh::intersect_mode & ISECT_FRONT) && dot(face.get_normal(), ray.dir) > 0) {
879 if(face.intersect(ray, hit ? &fhit : 0)) {
883 if(fhit.dist < nearest_hit.dist) {
891 if(nearest_hit.obj) {
895 // if we are interested in the mesh and not the faces set obj to this
896 if(Mesh::intersect_mode & ISECT_FACE) {
898 } else if(Mesh::intersect_mode & ISECT_VERTICES) {
910 // texture coordinate manipulation
911 void Mesh::texcoord_apply_xform(const Mat4 &xform)
913 if(!has_attrib(MESH_ATTR_TEXCOORD)) {
917 for(unsigned int i=0; i<nverts; i++) {
918 Vec4 tc = get_attrib(MESH_ATTR_TEXCOORD, i);
919 set_attrib(MESH_ATTR_TEXCOORD, i, xform * tc);
923 void Mesh::texcoord_gen_plane(const Vec3 &norm, const Vec3 &tang)
927 if(!has_attrib(MESH_ATTR_TEXCOORD)) {
928 // allocate texture coordinate attribute array
929 set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts);
932 Vec3 n = normalize(norm);
933 Vec3 b = normalize(cross(n, tang));
934 Vec3 t = cross(b, n);
936 for(unsigned int i=0; i<nverts; i++) {
937 Vec3 pos = Vec3(get_attrib(MESH_ATTR_VERTEX, i));
939 // distance along the tangent direction
940 float u = dot(pos, t);
941 // distance along the bitangent direction
942 float v = dot(pos, b);
944 set_attrib(MESH_ATTR_TEXCOORD, i, Vec4(u, v, 0, 1));
948 void Mesh::texcoord_gen_box()
950 if(!nverts || !has_attrib(MESH_ATTR_NORMAL)) return;
952 if(!has_attrib(MESH_ATTR_TEXCOORD)) {
953 // allocate texture coordinate attribute array
954 set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts);
957 for(unsigned int i=0; i<nverts; i++) {
958 Vec3 pos = Vec3(get_attrib(MESH_ATTR_VERTEX, i)) * 0.5 + Vec3(0.5, 0.5, 0.5);
959 Vec3 norm = Vec3(get_attrib(MESH_ATTR_NORMAL, i));
961 float abs_nx = fabs(norm.x);
962 float abs_ny = fabs(norm.y);
963 float abs_nz = fabs(norm.z);
964 int dom = abs_nx > abs_ny && abs_nx > abs_nz ? 0 : (abs_ny > abs_nz ? 1 : 2);
966 float uv[2], *uvptr = uv;
967 for(int j=0; j<3; j++) {
968 if(j == dom) continue; // skip dominant axis
972 set_attrib(MESH_ATTR_TEXCOORD, i, Vec4(uv[0], uv[1], 0, 1));
976 void Mesh::texcoord_gen_cylinder()
980 if(!has_attrib(MESH_ATTR_TEXCOORD)) {
981 // allocate texture coordinate attribute array
982 set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts);
985 for(unsigned int i=0; i<nverts; i++) {
986 Vec3 pos = Vec3(get_attrib(MESH_ATTR_VERTEX, i));
988 float rho = sqrt(pos.x * pos.x + pos.z * pos.z);
989 float theta = rho == 0.0 ? 0.0 : atan2(pos.z / rho, pos.x / rho);
991 float u = theta / (2.0 * M_PI) + 0.5;
994 set_attrib(MESH_ATTR_TEXCOORD, i, Vec4(u, v, 0, 1));
999 bool Mesh::dump(const char *fname) const
1001 FILE *fp = fopen(fname, "wb");
1003 bool res = dump(fp);
1010 bool Mesh::dump(FILE *fp) const
1012 if(!has_attrib(MESH_ATTR_VERTEX)) {
1016 fprintf(fp, "VERTEX ATTRIBUTES\n");
1017 static const char *label[] = { "pos", "nor", "tan", "tex", "col", "bw", "bid" };
1018 static const char *elemfmt[] = { 0, " %s(%g)", " %s(%g, %g)", " %s(%g, %g, %g)", " %s(%g, %g, %g, %g)", 0 };
1020 for(int i=0; i<(int)nverts; i++) {
1021 fprintf(fp, "%5u:", i);
1022 for(int j=0; j<NUM_MESH_ATTR; j++) {
1024 Vec4 v = get_attrib(j, i);
1025 int nelem = vattr[j].nelem;
1026 fprintf(fp, elemfmt[nelem], label[j], v.x, v.y, v.z, v.w);
1033 const unsigned int *idx = get_index_data();
1034 int numidx = get_index_count();
1035 int numtri = numidx / 3;
1036 assert(numidx % 3 == 0);
1038 fprintf(fp, "FACES\n");
1040 for(int i=0; i<numtri; i++) {
1041 fprintf(fp, "%5d: %d %d %d\n", i, idx[0], idx[1], idx[2]);
1048 bool Mesh::dump_obj(const char *fname) const
1050 FILE *fp = fopen(fname, "wb");
1052 bool res = dump_obj(fp);
1059 bool Mesh::dump_obj(FILE *fp) const
1061 if(!has_attrib(MESH_ATTR_VERTEX)) {
1065 for(int i=0; i<(int)nverts; i++) {
1066 Vec4 v = get_attrib(MESH_ATTR_VERTEX, i);
1067 fprintf(fp, "v %g %g %g\n", v.x, v.y, v.z);
1070 if(has_attrib(MESH_ATTR_NORMAL)) {
1071 for(int i=0; i<(int)nverts; i++) {
1072 Vec4 v = get_attrib(MESH_ATTR_NORMAL, i);
1073 fprintf(fp, "vn %g %g %g\n", v.x, v.y, v.z);
1077 if(has_attrib(MESH_ATTR_TEXCOORD)) {
1078 for(int i=0; i<(int)nverts; i++) {
1079 Vec4 v = get_attrib(MESH_ATTR_TEXCOORD, i);
1080 fprintf(fp, "vt %g %g\n", v.x, v.y);
1085 const unsigned int *idxptr = get_index_data();
1086 int numidx = get_index_count();
1087 int numtri = numidx / 3;
1088 assert(numidx % 3 == 0);
1090 for(int i=0; i<numtri; i++) {
1092 for(int j=0; j<3; j++) {
1093 unsigned int idx = *idxptr++ + 1;
1094 fprintf(fp, " %u/%u/%u", idx, idx, idx);
1099 int numtri = nverts / 3;
1100 unsigned int idx = 1;
1101 for(int i=0; i<numtri; i++) {
1103 for(int j=0; j<3; j++) {
1104 fprintf(fp, " %u/%u/%u", idx, idx, idx);
1113 // ------ private member functions ------
1115 void Mesh::calc_aabb()
1117 // the cast is to force calling the const version which doesn't invalidate
1118 if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
1122 aabb.min = Vec3(FLT_MAX, FLT_MAX, FLT_MAX);
1123 aabb.max = -aabb.min;
1125 for(unsigned int i=0; i<nverts; i++) {
1126 Vec4 v = get_attrib(MESH_ATTR_VERTEX, i);
1127 for(int j=0; j<3; j++) {
1128 if(v[j] < aabb.min[j]) {
1131 if(v[j] > aabb.max[j]) {
1139 void Mesh::calc_bsph()
1141 // the cast is to force calling the const version which doesn't invalidate
1142 if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
1147 bsph.center = Vec3(0, 0, 0);
1149 // first find the center
1150 for(unsigned int i=0; i<nverts; i++) {
1151 v = Vec3(get_attrib(MESH_ATTR_VERTEX, i));
1154 bsph.center /= (float)nverts;
1157 for(unsigned int i=0; i<nverts; i++) {
1158 v = Vec3(get_attrib(MESH_ATTR_VERTEX, i));
1159 float dist_sq = length_sq(v - bsph.center);
1160 if(dist_sq > bsph.radius) {
1161 bsph.radius = dist_sq;
1164 bsph.radius = sqrt(bsph.radius);
1169 void Mesh::update_buffers()
1171 for(int i=0; i<NUM_MESH_ATTR; i++) {
1172 if(has_attrib(i) && !vattr[i].vbo_valid) {
1173 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
1174 glBufferData(GL_ARRAY_BUFFER, nverts * vattr[i].nelem * sizeof(float), &vattr[i].data[0], GL_STATIC_DRAW);
1175 vattr[i].vbo_valid = true;
1178 glBindBuffer(GL_ARRAY_BUFFER, 0);
1180 if(idata_valid && !ibo_valid) {
1181 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
1182 glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 3 * sizeof(unsigned int), &idata[0], GL_STATIC_DRAW);
1185 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1188 void Mesh::update_wire_ibo()
1192 if(wire_ibo_valid) {
1197 glGenBuffers(1, &wire_ibo);
1200 int num_faces = get_poly_count();
1202 unsigned int *wire_idxarr = new unsigned int[num_faces * 6];
1203 unsigned int *dest = wire_idxarr;
1206 // we're dealing with an indexed mesh
1207 const unsigned int *idxarr = ((const Mesh*)this)->get_index_data();
1209 for(int i=0; i<num_faces; i++) {
1210 *dest++ = idxarr[0];
1211 *dest++ = idxarr[1];
1212 *dest++ = idxarr[1];
1213 *dest++ = idxarr[2];
1214 *dest++ = idxarr[2];
1215 *dest++ = idxarr[0];
1219 // not an indexed mesh ...
1220 for(int i=0; i<num_faces; i++) {
1231 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
1232 glBufferData(GL_ELEMENT_ARRAY_BUFFER, num_faces * 6 * sizeof(unsigned int), wire_idxarr, GL_STATIC_DRAW);
1233 delete [] wire_idxarr;
1234 wire_ibo_valid = true;
1235 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1239 // ------ class Triangle ------
1240 Triangle::Triangle()
1242 normal_valid = false;
1246 Triangle::Triangle(const Vec3 &v0, const Vec3 &v1, const Vec3 &v2)
1251 normal_valid = false;
1255 Triangle::Triangle(int n, const Vec3 *varr, const unsigned int *idxarr)
1258 v[0] = varr[idxarr[n * 3]];
1259 v[1] = varr[idxarr[n * 3 + 1]];
1260 v[2] = varr[idxarr[n * 3 + 2]];
1263 v[1] = varr[n * 3 + 1];
1264 v[2] = varr[n * 3 + 2];
1266 normal_valid = false;
1270 void Triangle::calc_normal()
1272 normal = normalize(cross(v[1] - v[0], v[2] - v[0]));
1273 normal_valid = true;
1276 const Vec3 &Triangle::get_normal() const
1279 ((Triangle*)this)->calc_normal();
1284 void Triangle::transform(const Mat4 &xform)
1286 v[0] = xform * v[0];
1287 v[1] = xform * v[1];
1288 v[2] = xform * v[2];
1289 normal_valid = false;
1292 void Triangle::draw() const
1295 n[0] = n[1] = n[2] = get_normal();
1297 int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
1298 int nloc = Mesh::get_attrib_location(MESH_ATTR_NORMAL);
1300 glEnableVertexAttribArray(vloc);
1301 glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
1302 glVertexAttribPointer(nloc, 3, GL_FLOAT, GL_FALSE, 0, &n[0].x);
1304 glDrawArrays(GL_TRIANGLES, 0, 3);
1306 glDisableVertexAttribArray(vloc);
1307 glDisableVertexAttribArray(nloc);
1310 void Triangle::draw_wire() const
1312 static const int idxarr[] = {0, 1, 1, 2, 2, 0};
1313 int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
1315 glEnableVertexAttribArray(vloc);
1316 glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
1318 glDrawElements(GL_LINES, 6, GL_UNSIGNED_INT, idxarr);
1320 glDisableVertexAttribArray(vloc);
1323 Vec3 Triangle::calc_barycentric(const Vec3 &pos) const
1325 Vec3 norm = get_normal();
1327 float area_sq = fabs(dot(cross(v[1] - v[0], v[2] - v[0]), norm));
1328 if(area_sq < 1e-5) {
1329 return Vec3(0, 0, 0);
1332 float asq0 = fabs(dot(cross(v[1] - pos, v[2] - pos), norm));
1333 float asq1 = fabs(dot(cross(v[2] - pos, v[0] - pos), norm));
1334 float asq2 = fabs(dot(cross(v[0] - pos, v[1] - pos), norm));
1336 return Vec3(asq0 / area_sq, asq1 / area_sq, asq2 / area_sq);
1339 bool Triangle::intersect(const Ray &ray, HitPoint *hit) const
1341 Vec3 normal = get_normal();
1343 float ndotdir = dot(ray.dir, normal);
1344 if(fabs(ndotdir) < 1e-4) {
1348 Vec3 vertdir = v[0] - ray.origin;
1349 float t = dot(normal, vertdir) / ndotdir;
1351 Vec3 pos = ray.origin + ray.dir * t;
1352 Vec3 bary = calc_barycentric(pos);
1354 if(bary.x + bary.y + bary.z > 1.00001) {
1360 hit->pos = ray.origin + ray.dir * t;
1361 hit->normal = normal;