cubemapper
diff src/mesh.cc @ 0:8fc9e1d3aad2
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 27 Jul 2017 20:36:12 +0300 |
parents | |
children | 2bfafdced01a |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/mesh.cc Thu Jul 27 20:36:12 2017 +0300 1.3 @@ -0,0 +1,1362 @@ 1.4 +#include <stdio.h> 1.5 +#include <stdlib.h> 1.6 +#include <float.h> 1.7 +#include <assert.h> 1.8 +#include "opengl.h" 1.9 +#include "mesh.h" 1.10 +//#include "xform_node.h" 1.11 + 1.12 +#define USE_OLDGL 1.13 + 1.14 +bool Mesh::use_custom_sdr_attr = true; 1.15 +int Mesh::global_sdr_loc[NUM_MESH_ATTR] = { 0, 1, 2, 3, 4, 5, 6 }; 1.16 +/* 1.17 + (int)SDR_ATTR_VERTEX, 1.18 + (int)SDR_ATTR_NORMAL, 1.19 + (int)SDR_ATTR_TANGENT, 1.20 + (int)SDR_ATTR_TEXCOORD, 1.21 + (int)SDR_ATTR_COLOR, 1.22 + -1, -1}; 1.23 +*/ 1.24 +unsigned int Mesh::intersect_mode = ISECT_DEFAULT; 1.25 +float Mesh::vertex_sel_dist = 0.01; 1.26 +float Mesh::vis_vecsize = 1.0; 1.27 + 1.28 +Mesh::Mesh() 1.29 +{ 1.30 + clear(); 1.31 + 1.32 + glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects); 1.33 + 1.34 + for(int i=0; i<NUM_MESH_ATTR; i++) { 1.35 + vattr[i].vbo = buffer_objects[i]; 1.36 + } 1.37 + ibo = buffer_objects[NUM_MESH_ATTR]; 1.38 + wire_ibo = 0; 1.39 +} 1.40 + 1.41 +Mesh::~Mesh() 1.42 +{ 1.43 + glDeleteBuffers(NUM_MESH_ATTR + 1, buffer_objects); 1.44 + 1.45 + if(wire_ibo) { 1.46 + glDeleteBuffers(1, &wire_ibo); 1.47 + } 1.48 +} 1.49 + 1.50 +Mesh::Mesh(const Mesh &rhs) 1.51 +{ 1.52 + clear(); 1.53 + 1.54 + glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects); 1.55 + 1.56 + for(int i=0; i<NUM_MESH_ATTR; i++) { 1.57 + vattr[i].vbo = buffer_objects[i]; 1.58 + } 1.59 + ibo = buffer_objects[NUM_MESH_ATTR]; 1.60 + wire_ibo = 0; 1.61 + 1.62 + clone(rhs); 1.63 +} 1.64 + 1.65 +Mesh &Mesh::operator =(const Mesh &rhs) 1.66 +{ 1.67 + if(&rhs != this) { 1.68 + clone(rhs); 1.69 + } 1.70 + return *this; 1.71 +} 1.72 + 1.73 +bool Mesh::clone(const Mesh &m) 1.74 +{ 1.75 + clear(); 1.76 + 1.77 + for(int i=0; i<NUM_MESH_ATTR; i++) { 1.78 + if(m.has_attrib(i)) { 1.79 + m.get_attrib_data(i); // force validation of the actual data on the source mesh 1.80 + 1.81 + vattr[i].nelem = m.vattr[i].nelem; 1.82 + vattr[i].data = m.vattr[i].data; // copy the actual data 1.83 + vattr[i].data_valid = true; 1.84 + } 1.85 + } 1.86 + 1.87 + if(m.is_indexed()) { 1.88 + m.get_index_data(); // again, force validation 1.89 + 1.90 + // copy the index data 1.91 + idata = m.idata; 1.92 + idata_valid = true; 1.93 + } 1.94 + 1.95 + name = m.name; 1.96 + nverts = m.nverts; 1.97 + nfaces = m.nfaces; 1.98 + 1.99 + //bones = m.bones; 1.100 + 1.101 + memcpy(cur_val, m.cur_val, sizeof cur_val); 1.102 + 1.103 + aabb = m.aabb; 1.104 + aabb_valid = m.aabb_valid; 1.105 + bsph = m.bsph; 1.106 + bsph_valid = m.bsph_valid; 1.107 + 1.108 + hitface = m.hitface; 1.109 + hitvert = m.hitvert; 1.110 + 1.111 + intersect_mode = m.intersect_mode; 1.112 + vertex_sel_dist = m.vertex_sel_dist; 1.113 + vis_vecsize = m.vis_vecsize; 1.114 + 1.115 + return true; 1.116 +} 1.117 + 1.118 +void Mesh::set_name(const char *name) 1.119 +{ 1.120 + this->name = name; 1.121 +} 1.122 + 1.123 +const char *Mesh::get_name() const 1.124 +{ 1.125 + return name.c_str(); 1.126 +} 1.127 + 1.128 +bool Mesh::has_attrib(int attr) const 1.129 +{ 1.130 + if(attr < 0 || attr >= NUM_MESH_ATTR) { 1.131 + return false; 1.132 + } 1.133 + 1.134 + // if neither of these is valid, then nobody has set this attribute 1.135 + return vattr[attr].vbo_valid || vattr[attr].data_valid; 1.136 +} 1.137 + 1.138 +bool Mesh::is_indexed() const 1.139 +{ 1.140 + return ibo_valid || idata_valid; 1.141 +} 1.142 + 1.143 +void Mesh::clear() 1.144 +{ 1.145 + //bones.clear(); 1.146 + 1.147 + for(int i=0; i<NUM_MESH_ATTR; i++) { 1.148 + vattr[i].nelem = 0; 1.149 + vattr[i].vbo_valid = false; 1.150 + vattr[i].data_valid = false; 1.151 + //vattr[i].sdr_loc = -1; 1.152 + vattr[i].data.clear(); 1.153 + } 1.154 + ibo_valid = idata_valid = false; 1.155 + idata.clear(); 1.156 + 1.157 + wire_ibo_valid = false; 1.158 + 1.159 + nverts = nfaces = 0; 1.160 + 1.161 + bsph_valid = false; 1.162 + aabb_valid = false; 1.163 +} 1.164 + 1.165 +float *Mesh::set_attrib_data(int attrib, int nelem, unsigned int num, const float *data) 1.166 +{ 1.167 + if(attrib < 0 || attrib >= NUM_MESH_ATTR) { 1.168 + fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib); 1.169 + return 0; 1.170 + } 1.171 + 1.172 + if(nverts && num != nverts) { 1.173 + fprintf(stderr, "%s: attribute count missmatch (%d instead of %d)\n", __FUNCTION__, num, nverts); 1.174 + return 0; 1.175 + } 1.176 + nverts = num; 1.177 + 1.178 + vattr[attrib].data.clear(); 1.179 + vattr[attrib].nelem = nelem; 1.180 + vattr[attrib].data.resize(num * nelem); 1.181 + 1.182 + if(data) { 1.183 + memcpy(&vattr[attrib].data[0], data, num * nelem * sizeof *data); 1.184 + } 1.185 + 1.186 + vattr[attrib].data_valid = true; 1.187 + vattr[attrib].vbo_valid = false; 1.188 + return &vattr[attrib].data[0]; 1.189 +} 1.190 + 1.191 +float *Mesh::get_attrib_data(int attrib) 1.192 +{ 1.193 + if(attrib < 0 || attrib >= NUM_MESH_ATTR) { 1.194 + fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib); 1.195 + return 0; 1.196 + } 1.197 + 1.198 + vattr[attrib].vbo_valid = false; 1.199 + return (float*)((const Mesh*)this)->get_attrib_data(attrib); 1.200 +} 1.201 + 1.202 +const float *Mesh::get_attrib_data(int attrib) const 1.203 +{ 1.204 + if(attrib < 0 || attrib >= NUM_MESH_ATTR) { 1.205 + fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib); 1.206 + return 0; 1.207 + } 1.208 + 1.209 + if(!vattr[attrib].data_valid) { 1.210 +#if GL_ES_VERSION_2_0 1.211 + fprintf(stderr, "%s: can't read back attrib data on CrippledGL ES\n", __FUNCTION__); 1.212 + return 0; 1.213 +#else 1.214 + if(!vattr[attrib].vbo_valid) { 1.215 + fprintf(stderr, "%s: unavailable attrib: %d\n", __FUNCTION__, attrib); 1.216 + return 0; 1.217 + } 1.218 + 1.219 + // local data copy is unavailable, grab the data from the vbo 1.220 + Mesh *m = (Mesh*)this; 1.221 + m->vattr[attrib].data.resize(nverts * vattr[attrib].nelem); 1.222 + 1.223 + glBindBuffer(GL_ARRAY_BUFFER, vattr[attrib].vbo); 1.224 + void *data = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY); 1.225 + memcpy(&m->vattr[attrib].data[0], data, nverts * vattr[attrib].nelem * sizeof(float)); 1.226 + glUnmapBuffer(GL_ARRAY_BUFFER); 1.227 + 1.228 + vattr[attrib].data_valid = true; 1.229 +#endif 1.230 + } 1.231 + 1.232 + return &vattr[attrib].data[0]; 1.233 +} 1.234 + 1.235 +void Mesh::set_attrib(int attrib, int idx, const Vec4 &v) 1.236 +{ 1.237 + float *data = get_attrib_data(attrib); 1.238 + if(data) { 1.239 + data += idx * vattr[attrib].nelem; 1.240 + for(int i=0; i<vattr[attrib].nelem; i++) { 1.241 + data[i] = v[i]; 1.242 + } 1.243 + } 1.244 +} 1.245 + 1.246 +Vec4 Mesh::get_attrib(int attrib, int idx) const 1.247 +{ 1.248 + Vec4 v(0.0, 0.0, 0.0, 1.0); 1.249 + const float *data = get_attrib_data(attrib); 1.250 + if(data) { 1.251 + data += idx * vattr[attrib].nelem; 1.252 + for(int i=0; i<vattr[attrib].nelem; i++) { 1.253 + v[i] = data[i]; 1.254 + } 1.255 + } 1.256 + return v; 1.257 +} 1.258 + 1.259 +int Mesh::get_attrib_count(int attrib) const 1.260 +{ 1.261 + return has_attrib(attrib) ? nverts : 0; 1.262 +} 1.263 + 1.264 + 1.265 +unsigned int *Mesh::set_index_data(int num, const unsigned int *indices) 1.266 +{ 1.267 + int nidx = nfaces * 3; 1.268 + if(nidx && num != nidx) { 1.269 + fprintf(stderr, "%s: index count missmatch (%d instead of %d)\n", __FUNCTION__, num, nidx); 1.270 + return 0; 1.271 + } 1.272 + nfaces = num / 3; 1.273 + 1.274 + idata.clear(); 1.275 + idata.resize(num); 1.276 + 1.277 + if(indices) { 1.278 + memcpy(&idata[0], indices, num * sizeof *indices); 1.279 + } 1.280 + 1.281 + idata_valid = true; 1.282 + ibo_valid = false; 1.283 + 1.284 + return &idata[0]; 1.285 +} 1.286 + 1.287 +unsigned int *Mesh::get_index_data() 1.288 +{ 1.289 + ibo_valid = false; 1.290 + return (unsigned int*)((const Mesh*)this)->get_index_data(); 1.291 +} 1.292 + 1.293 +const unsigned int *Mesh::get_index_data() const 1.294 +{ 1.295 + if(!idata_valid) { 1.296 +#if GL_ES_VERSION_2_0 1.297 + fprintf(stderr, "%s: can't read back index data in CrippledGL ES\n", __FUNCTION__); 1.298 + return 0; 1.299 +#else 1.300 + if(!ibo_valid) { 1.301 + fprintf(stderr, "%s: indices unavailable\n", __FUNCTION__); 1.302 + return 0; 1.303 + } 1.304 + 1.305 + // local data copy is unavailable, gram the data from the ibo 1.306 + Mesh *m = (Mesh*)this; 1.307 + int nidx = nfaces * 3; 1.308 + m->idata.resize(nidx); 1.309 + 1.310 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); 1.311 + void *data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY); 1.312 + memcpy(&m->idata[0], data, nidx * sizeof(unsigned int)); 1.313 + glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); 1.314 + 1.315 + idata_valid = true; 1.316 +#endif 1.317 + } 1.318 + 1.319 + return &idata[0]; 1.320 +} 1.321 + 1.322 +int Mesh::get_index_count() const 1.323 +{ 1.324 + return nfaces * 3; 1.325 +} 1.326 + 1.327 +void Mesh::append(const Mesh &mesh) 1.328 +{ 1.329 + unsigned int idxoffs = nverts; 1.330 + 1.331 + if(!nverts) { 1.332 + clone(mesh); 1.333 + return; 1.334 + } 1.335 + 1.336 + nverts += mesh.nverts; 1.337 + nfaces += mesh.nfaces; 1.338 + 1.339 + for(int i=0; i<NUM_MESH_ATTR; i++) { 1.340 + if(has_attrib(i) && mesh.has_attrib(i)) { 1.341 + // force validating the data arrays 1.342 + get_attrib_data(i); 1.343 + mesh.get_attrib_data(i); 1.344 + 1.345 + // append the mesh data 1.346 + vattr[i].data.insert(vattr[i].data.end(), mesh.vattr[i].data.begin(), mesh.vattr[i].data.end()); 1.347 + } 1.348 + } 1.349 + 1.350 + if(ibo_valid || idata_valid) { 1.351 + // make index arrays valid 1.352 + get_index_data(); 1.353 + mesh.get_index_data(); 1.354 + 1.355 + size_t orig_sz = idata.size(); 1.356 + 1.357 + idata.insert(idata.end(), mesh.idata.begin(), mesh.idata.end()); 1.358 + 1.359 + // fixup all the new indices 1.360 + for(size_t i=orig_sz; i<idata.size(); i++) { 1.361 + idata[i] += idxoffs; 1.362 + } 1.363 + } 1.364 + 1.365 + // fuck everything 1.366 + wire_ibo_valid = false; 1.367 + aabb_valid = false; 1.368 + bsph_valid = false; 1.369 +} 1.370 + 1.371 +// assemble a complete vertex by adding all the useful attributes 1.372 +void Mesh::vertex(float x, float y, float z) 1.373 +{ 1.374 + cur_val[MESH_ATTR_VERTEX] = Vec4(x, y, z, 1.0f); 1.375 + vattr[MESH_ATTR_VERTEX].data_valid = true; 1.376 + vattr[MESH_ATTR_VERTEX].nelem = 3; 1.377 + 1.378 + for(int i=0; i<NUM_MESH_ATTR; i++) { 1.379 + if(vattr[i].data_valid) { 1.380 + for(int j=0; j<vattr[MESH_ATTR_VERTEX].nelem; j++) { 1.381 + vattr[i].data.push_back(cur_val[i][j]); 1.382 + } 1.383 + } 1.384 + vattr[i].vbo_valid = false; 1.385 + } 1.386 + 1.387 + if(idata_valid) { 1.388 + idata.clear(); 1.389 + } 1.390 + ibo_valid = idata_valid = false; 1.391 +} 1.392 + 1.393 +void Mesh::normal(float nx, float ny, float nz) 1.394 +{ 1.395 + cur_val[MESH_ATTR_NORMAL] = Vec4(nx, ny, nz, 1.0f); 1.396 + vattr[MESH_ATTR_NORMAL].data_valid = true; 1.397 + vattr[MESH_ATTR_NORMAL].nelem = 3; 1.398 +} 1.399 + 1.400 +void Mesh::tangent(float tx, float ty, float tz) 1.401 +{ 1.402 + cur_val[MESH_ATTR_TANGENT] = Vec4(tx, ty, tz, 1.0f); 1.403 + vattr[MESH_ATTR_TANGENT].data_valid = true; 1.404 + vattr[MESH_ATTR_TANGENT].nelem = 3; 1.405 +} 1.406 + 1.407 +void Mesh::texcoord(float u, float v, float w) 1.408 +{ 1.409 + cur_val[MESH_ATTR_TEXCOORD] = Vec4(u, v, w, 1.0f); 1.410 + vattr[MESH_ATTR_TEXCOORD].data_valid = true; 1.411 + vattr[MESH_ATTR_TEXCOORD].nelem = 3; 1.412 +} 1.413 + 1.414 +void Mesh::boneweights(float w1, float w2, float w3, float w4) 1.415 +{ 1.416 + cur_val[MESH_ATTR_BONEWEIGHTS] = Vec4(w1, w2, w3, w4); 1.417 + vattr[MESH_ATTR_BONEWEIGHTS].data_valid = true; 1.418 + vattr[MESH_ATTR_BONEWEIGHTS].nelem = 4; 1.419 +} 1.420 + 1.421 +void Mesh::boneidx(int idx1, int idx2, int idx3, int idx4) 1.422 +{ 1.423 + cur_val[MESH_ATTR_BONEIDX] = Vec4(idx1, idx2, idx3, idx4); 1.424 + vattr[MESH_ATTR_BONEIDX].data_valid = true; 1.425 + vattr[MESH_ATTR_BONEIDX].nelem = 4; 1.426 +} 1.427 + 1.428 +int Mesh::get_poly_count() const 1.429 +{ 1.430 + if(nfaces) { 1.431 + return nfaces; 1.432 + } 1.433 + if(nverts) { 1.434 + return nverts / 3; 1.435 + } 1.436 + return 0; 1.437 +} 1.438 + 1.439 +/// static function 1.440 +void Mesh::set_attrib_location(int attr, int loc) 1.441 +{ 1.442 + if(attr < 0 || attr >= NUM_MESH_ATTR) { 1.443 + return; 1.444 + } 1.445 + Mesh::global_sdr_loc[attr] = loc; 1.446 +} 1.447 + 1.448 +/// static function 1.449 +int Mesh::get_attrib_location(int attr) 1.450 +{ 1.451 + if(attr < 0 || attr >= NUM_MESH_ATTR) { 1.452 + return -1; 1.453 + } 1.454 + return Mesh::global_sdr_loc[attr]; 1.455 +} 1.456 + 1.457 +/// static function 1.458 +void Mesh::clear_attrib_locations() 1.459 +{ 1.460 + for(int i=0; i<NUM_MESH_ATTR; i++) { 1.461 + Mesh::global_sdr_loc[i] = -1; 1.462 + } 1.463 +} 1.464 + 1.465 +/// static function 1.466 +void Mesh::set_vis_vecsize(float sz) 1.467 +{ 1.468 + Mesh::vis_vecsize = sz; 1.469 +} 1.470 + 1.471 +float Mesh::get_vis_vecsize() 1.472 +{ 1.473 + return Mesh::vis_vecsize; 1.474 +} 1.475 + 1.476 +void Mesh::apply_xform(const Mat4 &xform) 1.477 +{ 1.478 + Mat4 dir_xform = xform.upper3x3(); 1.479 + apply_xform(xform, dir_xform); 1.480 +} 1.481 + 1.482 +void Mesh::apply_xform(const Mat4 &xform, const Mat4 &dir_xform) 1.483 +{ 1.484 + for(unsigned int i=0; i<nverts; i++) { 1.485 + Vec4 v = get_attrib(MESH_ATTR_VERTEX, i); 1.486 + set_attrib(MESH_ATTR_VERTEX, i, xform * v); 1.487 + 1.488 + if(has_attrib(MESH_ATTR_NORMAL)) { 1.489 + Vec3 n = get_attrib(MESH_ATTR_NORMAL, i).xyz(); 1.490 + set_attrib(MESH_ATTR_NORMAL, i, Vec4(dir_xform * n)); 1.491 + } 1.492 + if(has_attrib(MESH_ATTR_TANGENT)) { 1.493 + Vec3 t = get_attrib(MESH_ATTR_TANGENT, i).xyz(); 1.494 + set_attrib(MESH_ATTR_TANGENT, i, Vec4(dir_xform * t)); 1.495 + } 1.496 + } 1.497 +} 1.498 + 1.499 +void Mesh::flip() 1.500 +{ 1.501 + flip_faces(); 1.502 + flip_normals(); 1.503 +} 1.504 + 1.505 +void Mesh::flip_faces() 1.506 +{ 1.507 + if(is_indexed()) { 1.508 + unsigned int *indices = get_index_data(); 1.509 + if(!indices) return; 1.510 + 1.511 + int idxnum = get_index_count(); 1.512 + for(int i=0; i<idxnum; i+=3) { 1.513 + unsigned int tmp = indices[i + 2]; 1.514 + indices[i + 2] = indices[i + 1]; 1.515 + indices[i + 1] = tmp; 1.516 + } 1.517 + 1.518 + } else { 1.519 + Vec3 *verts = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX); 1.520 + if(!verts) return; 1.521 + 1.522 + int vnum = get_attrib_count(MESH_ATTR_VERTEX); 1.523 + for(int i=0; i<vnum; i+=3) { 1.524 + Vec3 tmp = verts[i + 2]; 1.525 + verts[i + 2] = verts[i + 1]; 1.526 + verts[i + 1] = tmp; 1.527 + } 1.528 + } 1.529 +} 1.530 + 1.531 +void Mesh::flip_normals() 1.532 +{ 1.533 + Vec3 *normals = (Vec3*)get_attrib_data(MESH_ATTR_NORMAL); 1.534 + if(!normals) return; 1.535 + 1.536 + int num = get_attrib_count(MESH_ATTR_NORMAL); 1.537 + for(int i=0; i<num; i++) { 1.538 + normals[i] = -normals[i]; 1.539 + } 1.540 +} 1.541 + 1.542 +/* 1.543 +int Mesh::add_bone(XFormNode *bone) 1.544 +{ 1.545 + int idx = bones.size(); 1.546 + bones.push_back(bone); 1.547 + return idx; 1.548 +} 1.549 + 1.550 +const XFormNode *Mesh::get_bone(int idx) const 1.551 +{ 1.552 + if(idx < 0 || idx >= (int)bones.size()) { 1.553 + return 0; 1.554 + } 1.555 + return bones[idx]; 1.556 +} 1.557 + 1.558 +int Mesh::get_bones_count() const 1.559 +{ 1.560 + return (int)bones.size(); 1.561 +} 1.562 +*/ 1.563 + 1.564 +bool Mesh::pre_draw() const 1.565 +{ 1.566 + cur_sdr = 0; 1.567 + glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr); 1.568 + 1.569 + ((Mesh*)this)->update_buffers(); 1.570 + 1.571 + if(!vattr[MESH_ATTR_VERTEX].vbo_valid) { 1.572 + fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__); 1.573 + return false; 1.574 + } 1.575 + 1.576 + if(cur_sdr && use_custom_sdr_attr) { 1.577 + // rendering with shaders 1.578 + if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) { 1.579 + fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__); 1.580 + return false; 1.581 + } 1.582 + 1.583 + for(int i=0; i<NUM_MESH_ATTR; i++) { 1.584 + int loc = global_sdr_loc[i]; 1.585 + if(loc >= 0 && vattr[i].vbo_valid) { 1.586 + glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo); 1.587 + glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0); 1.588 + glEnableVertexAttribArray(loc); 1.589 + } 1.590 + } 1.591 + } else { 1.592 +#ifndef GL_ES_VERSION_2_0 1.593 + // rendering with fixed-function (not available in GLES2) 1.594 + glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_VERTEX].vbo); 1.595 + glVertexPointer(vattr[MESH_ATTR_VERTEX].nelem, GL_FLOAT, 0, 0); 1.596 + glEnableClientState(GL_VERTEX_ARRAY); 1.597 + 1.598 + if(vattr[MESH_ATTR_NORMAL].vbo_valid) { 1.599 + glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_NORMAL].vbo); 1.600 + glNormalPointer(GL_FLOAT, 0, 0); 1.601 + glEnableClientState(GL_NORMAL_ARRAY); 1.602 + } 1.603 + if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) { 1.604 + glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_TEXCOORD].vbo); 1.605 + glTexCoordPointer(vattr[MESH_ATTR_TEXCOORD].nelem, GL_FLOAT, 0, 0); 1.606 + glEnableClientState(GL_TEXTURE_COORD_ARRAY); 1.607 + } 1.608 + if(vattr[MESH_ATTR_COLOR].vbo_valid) { 1.609 + glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_COLOR].vbo); 1.610 + glColorPointer(vattr[MESH_ATTR_COLOR].nelem, GL_FLOAT, 0, 0); 1.611 + glEnableClientState(GL_COLOR_ARRAY); 1.612 + } 1.613 +#endif 1.614 + } 1.615 + glBindBuffer(GL_ARRAY_BUFFER, 0); 1.616 + 1.617 + return true; 1.618 +} 1.619 + 1.620 +void Mesh::draw() const 1.621 +{ 1.622 + if(!pre_draw()) return; 1.623 + 1.624 + if(ibo_valid) { 1.625 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); 1.626 + glDrawElements(GL_TRIANGLES, nfaces * 3, GL_UNSIGNED_INT, 0); 1.627 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 1.628 + } else { 1.629 + glDrawArrays(GL_TRIANGLES, 0, nverts); 1.630 + } 1.631 + 1.632 + post_draw(); 1.633 +} 1.634 + 1.635 +void Mesh::post_draw() const 1.636 +{ 1.637 + if(cur_sdr && use_custom_sdr_attr) { 1.638 + // rendered with shaders 1.639 + for(int i=0; i<NUM_MESH_ATTR; i++) { 1.640 + int loc = global_sdr_loc[i]; 1.641 + if(loc >= 0 && vattr[i].vbo_valid) { 1.642 + glDisableVertexAttribArray(loc); 1.643 + } 1.644 + } 1.645 + } else { 1.646 +#ifndef GL_ES_VERSION_2_0 1.647 + // rendered with fixed-function 1.648 + glDisableClientState(GL_VERTEX_ARRAY); 1.649 + if(vattr[MESH_ATTR_NORMAL].vbo_valid) { 1.650 + glDisableClientState(GL_NORMAL_ARRAY); 1.651 + } 1.652 + if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) { 1.653 + glDisableClientState(GL_TEXTURE_COORD_ARRAY); 1.654 + } 1.655 + if(vattr[MESH_ATTR_COLOR].vbo_valid) { 1.656 + glDisableClientState(GL_COLOR_ARRAY); 1.657 + } 1.658 +#endif 1.659 + } 1.660 +} 1.661 + 1.662 +void Mesh::draw_wire() const 1.663 +{ 1.664 + if(!pre_draw()) return; 1.665 + 1.666 + ((Mesh*)this)->update_wire_ibo(); 1.667 + 1.668 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo); 1.669 + glDrawElements(GL_LINES, nfaces * 6, GL_UNSIGNED_INT, 0); 1.670 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 1.671 + 1.672 + post_draw(); 1.673 +} 1.674 + 1.675 +void Mesh::draw_vertices() const 1.676 +{ 1.677 + if(!pre_draw()) return; 1.678 + 1.679 + glDrawArrays(GL_POINTS, 0, nverts); 1.680 + 1.681 + post_draw(); 1.682 +} 1.683 + 1.684 +void Mesh::draw_normals() const 1.685 +{ 1.686 +#ifdef USE_OLDGL 1.687 + int cur_sdr = 0; 1.688 + glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr); 1.689 + 1.690 + Vec3 *varr = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX); 1.691 + Vec3 *norm = (Vec3*)get_attrib_data(MESH_ATTR_NORMAL); 1.692 + if(!varr || !norm) { 1.693 + return; 1.694 + } 1.695 + 1.696 + glBegin(GL_LINES); 1.697 + if(cur_sdr && use_custom_sdr_attr) { 1.698 + int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX]; 1.699 + if(vert_loc < 0) { 1.700 + glEnd(); 1.701 + return; 1.702 + } 1.703 + 1.704 + for(size_t i=0; i<nverts; i++) { 1.705 + glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z); 1.706 + Vec3 end = varr[i] + norm[i] * vis_vecsize; 1.707 + glVertexAttrib3f(vert_loc, end.x, end.y, end.z); 1.708 + } 1.709 + } else { 1.710 + for(size_t i=0; i<nverts; i++) { 1.711 + glVertex3f(varr[i].x, varr[i].y, varr[i].z); 1.712 + Vec3 end = varr[i] + norm[i] * vis_vecsize; 1.713 + glVertex3f(end.x, end.y, end.z); 1.714 + } 1.715 + } 1.716 + glEnd(); 1.717 +#endif // USE_OLDGL 1.718 +} 1.719 + 1.720 +void Mesh::draw_tangents() const 1.721 +{ 1.722 +#ifdef USE_OLDGL 1.723 + int cur_sdr = 0; 1.724 + glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr); 1.725 + 1.726 + Vec3 *varr = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX); 1.727 + Vec3 *tang = (Vec3*)get_attrib_data(MESH_ATTR_TANGENT); 1.728 + if(!varr || !tang) { 1.729 + return; 1.730 + } 1.731 + 1.732 + glBegin(GL_LINES); 1.733 + if(cur_sdr && use_custom_sdr_attr) { 1.734 + int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX]; 1.735 + if(vert_loc < 0) { 1.736 + glEnd(); 1.737 + return; 1.738 + } 1.739 + 1.740 + for(size_t i=0; i<nverts; i++) { 1.741 + glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z); 1.742 + Vec3 end = varr[i] + tang[i] * vis_vecsize; 1.743 + glVertexAttrib3f(vert_loc, end.x, end.y, end.z); 1.744 + } 1.745 + } else { 1.746 + for(size_t i=0; i<nverts; i++) { 1.747 + glVertex3f(varr[i].x, varr[i].y, varr[i].z); 1.748 + Vec3 end = varr[i] + tang[i] * vis_vecsize; 1.749 + glVertex3f(end.x, end.y, end.z); 1.750 + } 1.751 + } 1.752 + glEnd(); 1.753 +#endif // USE_OLDGL 1.754 +} 1.755 + 1.756 +void Mesh::get_aabbox(Vec3 *vmin, Vec3 *vmax) const 1.757 +{ 1.758 + if(!aabb_valid) { 1.759 + ((Mesh*)this)->calc_aabb(); 1.760 + } 1.761 + *vmin = aabb.min; 1.762 + *vmax = aabb.max; 1.763 +} 1.764 + 1.765 +const AABox &Mesh::get_aabbox() const 1.766 +{ 1.767 + if(!aabb_valid) { 1.768 + ((Mesh*)this)->calc_aabb(); 1.769 + } 1.770 + return aabb; 1.771 +} 1.772 + 1.773 +float Mesh::get_bsphere(Vec3 *center, float *rad) const 1.774 +{ 1.775 + if(!bsph_valid) { 1.776 + ((Mesh*)this)->calc_bsph(); 1.777 + } 1.778 + *center = bsph.center; 1.779 + *rad = bsph.radius; 1.780 + return bsph.radius; 1.781 +} 1.782 + 1.783 +const Sphere &Mesh::get_bsphere() const 1.784 +{ 1.785 + if(!bsph_valid) { 1.786 + ((Mesh*)this)->calc_bsph(); 1.787 + } 1.788 + return bsph; 1.789 +} 1.790 + 1.791 +/// static function 1.792 +void Mesh::set_intersect_mode(unsigned int mode) 1.793 +{ 1.794 + Mesh::intersect_mode = mode; 1.795 +} 1.796 + 1.797 +/// static function 1.798 +unsigned int Mesh::get_intersect_mode() 1.799 +{ 1.800 + return Mesh::intersect_mode; 1.801 +} 1.802 + 1.803 +/// static function 1.804 +void Mesh::set_vertex_select_distance(float dist) 1.805 +{ 1.806 + Mesh::vertex_sel_dist = dist; 1.807 +} 1.808 + 1.809 +/// static function 1.810 +float Mesh::get_vertex_select_distance() 1.811 +{ 1.812 + return Mesh::vertex_sel_dist; 1.813 +} 1.814 + 1.815 +bool Mesh::intersect(const Ray &ray, HitPoint *hit) const 1.816 +{ 1.817 + assert((Mesh::intersect_mode & (ISECT_VERTICES | ISECT_FACE)) != (ISECT_VERTICES | ISECT_FACE)); 1.818 + 1.819 + const Vec3 *varr = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX); 1.820 + const Vec3 *narr = (Vec3*)get_attrib_data(MESH_ATTR_NORMAL); 1.821 + if(!varr) { 1.822 + return false; 1.823 + } 1.824 + const unsigned int *idxarr = get_index_data(); 1.825 + 1.826 + // first test with the bounding box 1.827 + AABox box; 1.828 + get_aabbox(&box.min, &box.max); 1.829 + if(!box.intersect(ray)) { 1.830 + return false; 1.831 + } 1.832 + 1.833 + HitPoint nearest_hit; 1.834 + nearest_hit.dist = FLT_MAX; 1.835 + nearest_hit.obj = 0; 1.836 + 1.837 + if(Mesh::intersect_mode & ISECT_VERTICES) { 1.838 + // we asked for "intersections" with the vertices of the mesh 1.839 + long nearest_vidx = -1; 1.840 + float thres_sq = Mesh::vertex_sel_dist * Mesh::vertex_sel_dist; 1.841 + 1.842 + for(unsigned int i=0; i<nverts; i++) { 1.843 + 1.844 + if((Mesh::intersect_mode & ISECT_FRONT) && dot(narr[i], ray.dir) > 0) { 1.845 + continue; 1.846 + } 1.847 + 1.848 + // project the vertex onto the ray line 1.849 + float t = dot(varr[i] - ray.origin, ray.dir); 1.850 + Vec3 vproj = ray.origin + ray.dir * t; 1.851 + 1.852 + float dist_sq = length_sq(vproj - varr[i]); 1.853 + if(dist_sq < thres_sq) { 1.854 + if(!hit) { 1.855 + return true; 1.856 + } 1.857 + if(t < nearest_hit.dist) { 1.858 + nearest_hit.dist = t; 1.859 + nearest_vidx = i; 1.860 + } 1.861 + } 1.862 + } 1.863 + 1.864 + if(nearest_vidx != -1) { 1.865 + hitvert = varr[nearest_vidx]; 1.866 + nearest_hit.obj = &hitvert; 1.867 + } 1.868 + 1.869 + } else { 1.870 + // regular intersection test with polygons 1.871 + 1.872 + for(unsigned int i=0; i<nfaces; i++) { 1.873 + Triangle face(i, varr, idxarr); 1.874 + 1.875 + // ignore back-facing polygons if the mode flags include ISECT_FRONT 1.876 + if((Mesh::intersect_mode & ISECT_FRONT) && dot(face.get_normal(), ray.dir) > 0) { 1.877 + continue; 1.878 + } 1.879 + 1.880 + HitPoint fhit; 1.881 + if(face.intersect(ray, hit ? &fhit : 0)) { 1.882 + if(!hit) { 1.883 + return true; 1.884 + } 1.885 + if(fhit.dist < nearest_hit.dist) { 1.886 + nearest_hit = fhit; 1.887 + hitface = face; 1.888 + } 1.889 + } 1.890 + } 1.891 + } 1.892 + 1.893 + if(nearest_hit.obj) { 1.894 + if(hit) { 1.895 + *hit = nearest_hit; 1.896 + 1.897 + // if we are interested in the mesh and not the faces set obj to this 1.898 + if(Mesh::intersect_mode & ISECT_FACE) { 1.899 + hit->obj = &hitface; 1.900 + } else if(Mesh::intersect_mode & ISECT_VERTICES) { 1.901 + hit->obj = &hitvert; 1.902 + } else { 1.903 + hit->obj = this; 1.904 + } 1.905 + } 1.906 + return true; 1.907 + } 1.908 + return false; 1.909 +} 1.910 + 1.911 + 1.912 +// texture coordinate manipulation 1.913 +void Mesh::texcoord_apply_xform(const Mat4 &xform) 1.914 +{ 1.915 + if(!has_attrib(MESH_ATTR_TEXCOORD)) { 1.916 + return; 1.917 + } 1.918 + 1.919 + for(unsigned int i=0; i<nverts; i++) { 1.920 + Vec4 tc = get_attrib(MESH_ATTR_TEXCOORD, i); 1.921 + set_attrib(MESH_ATTR_TEXCOORD, i, xform * tc); 1.922 + } 1.923 +} 1.924 + 1.925 +void Mesh::texcoord_gen_plane(const Vec3 &norm, const Vec3 &tang) 1.926 +{ 1.927 + if(!nverts) return; 1.928 + 1.929 + if(!has_attrib(MESH_ATTR_TEXCOORD)) { 1.930 + // allocate texture coordinate attribute array 1.931 + set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts); 1.932 + } 1.933 + 1.934 + Vec3 n = normalize(norm); 1.935 + Vec3 b = normalize(cross(n, tang)); 1.936 + Vec3 t = cross(b, n); 1.937 + 1.938 + for(unsigned int i=0; i<nverts; i++) { 1.939 + Vec3 pos = get_attrib(MESH_ATTR_VERTEX, i).xyz(); 1.940 + 1.941 + // distance along the tangent direction 1.942 + float u = dot(pos, t); 1.943 + // distance along the bitangent direction 1.944 + float v = dot(pos, b); 1.945 + 1.946 + set_attrib(MESH_ATTR_TEXCOORD, i, Vec4(u, v, 0, 1)); 1.947 + } 1.948 +} 1.949 + 1.950 +void Mesh::texcoord_gen_box() 1.951 +{ 1.952 + if(!nverts || !has_attrib(MESH_ATTR_NORMAL)) return; 1.953 + 1.954 + if(!has_attrib(MESH_ATTR_TEXCOORD)) { 1.955 + // allocate texture coordinate attribute array 1.956 + set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts); 1.957 + } 1.958 + 1.959 + for(unsigned int i=0; i<nverts; i++) { 1.960 + Vec3 pos = Vec3(get_attrib(MESH_ATTR_VERTEX, i)) * 0.5 + Vec3(0.5, 0.5, 0.5); 1.961 + Vec3 norm = get_attrib(MESH_ATTR_NORMAL, i).xyz(); 1.962 + 1.963 + float abs_nx = fabs(norm.x); 1.964 + float abs_ny = fabs(norm.y); 1.965 + float abs_nz = fabs(norm.z); 1.966 + int dom = abs_nx > abs_ny && abs_nx > abs_nz ? 0 : (abs_ny > abs_nz ? 1 : 2); 1.967 + 1.968 + float uv[2], *uvptr = uv; 1.969 + for(int j=0; j<3; j++) { 1.970 + if(j == dom) continue; // skip dominant axis 1.971 + 1.972 + *uvptr++ = pos[j]; 1.973 + } 1.974 + set_attrib(MESH_ATTR_TEXCOORD, i, Vec4(uv[0], uv[1], 0, 1)); 1.975 + } 1.976 +} 1.977 + 1.978 +void Mesh::texcoord_gen_cylinder() 1.979 +{ 1.980 + if(!nverts) return; 1.981 + 1.982 + if(!has_attrib(MESH_ATTR_TEXCOORD)) { 1.983 + // allocate texture coordinate attribute array 1.984 + set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts); 1.985 + } 1.986 + 1.987 + for(unsigned int i=0; i<nverts; i++) { 1.988 + Vec3 pos = get_attrib(MESH_ATTR_VERTEX, i).xyz(); 1.989 + 1.990 + float rho = sqrt(pos.x * pos.x + pos.z * pos.z); 1.991 + float theta = rho == 0.0 ? 0.0 : atan2(pos.z / rho, pos.x / rho); 1.992 + 1.993 + float u = theta / (2.0 * M_PI) + 0.5; 1.994 + float v = pos.y; 1.995 + 1.996 + set_attrib(MESH_ATTR_TEXCOORD, i, Vec4(u, v, 0, 1)); 1.997 + } 1.998 +} 1.999 + 1.1000 + 1.1001 +bool Mesh::dump(const char *fname) const 1.1002 +{ 1.1003 + FILE *fp = fopen(fname, "wb"); 1.1004 + if(fp) { 1.1005 + bool res = dump(fp); 1.1006 + fclose(fp); 1.1007 + return res; 1.1008 + } 1.1009 + return false; 1.1010 +} 1.1011 + 1.1012 +bool Mesh::dump(FILE *fp) const 1.1013 +{ 1.1014 + if(!has_attrib(MESH_ATTR_VERTEX)) { 1.1015 + return false; 1.1016 + } 1.1017 + 1.1018 + fprintf(fp, "VERTEX ATTRIBUTES\n"); 1.1019 + static const char *label[] = { "pos", "nor", "tan", "tex", "col", "bw", "bid" }; 1.1020 + static const char *elemfmt[] = { 0, " %s(%g)", " %s(%g, %g)", " %s(%g, %g, %g)", " %s(%g, %g, %g, %g)", 0 }; 1.1021 + 1.1022 + for(int i=0; i<(int)nverts; i++) { 1.1023 + fprintf(fp, "%5u:", i); 1.1024 + for(int j=0; j<NUM_MESH_ATTR; j++) { 1.1025 + if(has_attrib(j)) { 1.1026 + Vec4 v = get_attrib(j, i); 1.1027 + int nelem = vattr[j].nelem; 1.1028 + fprintf(fp, elemfmt[nelem], label[j], v.x, v.y, v.z, v.w); 1.1029 + } 1.1030 + } 1.1031 + fputc('\n', fp); 1.1032 + } 1.1033 + 1.1034 + if(is_indexed()) { 1.1035 + const unsigned int *idx = get_index_data(); 1.1036 + int numidx = get_index_count(); 1.1037 + int numtri = numidx / 3; 1.1038 + assert(numidx % 3 == 0); 1.1039 + 1.1040 + fprintf(fp, "FACES\n"); 1.1041 + 1.1042 + for(int i=0; i<numtri; i++) { 1.1043 + fprintf(fp, "%5d: %d %d %d\n", i, idx[0], idx[1], idx[2]); 1.1044 + idx += 3; 1.1045 + } 1.1046 + } 1.1047 + return true; 1.1048 +} 1.1049 + 1.1050 +bool Mesh::dump_obj(const char *fname) const 1.1051 +{ 1.1052 + FILE *fp = fopen(fname, "wb"); 1.1053 + if(fp) { 1.1054 + bool res = dump_obj(fp); 1.1055 + fclose(fp); 1.1056 + return res; 1.1057 + } 1.1058 + return false; 1.1059 +} 1.1060 + 1.1061 +bool Mesh::dump_obj(FILE *fp) const 1.1062 +{ 1.1063 + if(!has_attrib(MESH_ATTR_VERTEX)) { 1.1064 + return false; 1.1065 + } 1.1066 + 1.1067 + for(int i=0; i<(int)nverts; i++) { 1.1068 + Vec4 v = get_attrib(MESH_ATTR_VERTEX, i); 1.1069 + fprintf(fp, "v %g %g %g\n", v.x, v.y, v.z); 1.1070 + } 1.1071 + 1.1072 + if(has_attrib(MESH_ATTR_NORMAL)) { 1.1073 + for(int i=0; i<(int)nverts; i++) { 1.1074 + Vec4 v = get_attrib(MESH_ATTR_NORMAL, i); 1.1075 + fprintf(fp, "vn %g %g %g\n", v.x, v.y, v.z); 1.1076 + } 1.1077 + } 1.1078 + 1.1079 + if(has_attrib(MESH_ATTR_TEXCOORD)) { 1.1080 + for(int i=0; i<(int)nverts; i++) { 1.1081 + Vec4 v = get_attrib(MESH_ATTR_TEXCOORD, i); 1.1082 + fprintf(fp, "vt %g %g\n", v.x, v.y); 1.1083 + } 1.1084 + } 1.1085 + 1.1086 + if(is_indexed()) { 1.1087 + const unsigned int *idxptr = get_index_data(); 1.1088 + int numidx = get_index_count(); 1.1089 + int numtri = numidx / 3; 1.1090 + assert(numidx % 3 == 0); 1.1091 + 1.1092 + for(int i=0; i<numtri; i++) { 1.1093 + fputc('f', fp); 1.1094 + for(int j=0; j<3; j++) { 1.1095 + unsigned int idx = *idxptr++ + 1; 1.1096 + fprintf(fp, " %u/%u/%u", idx, idx, idx); 1.1097 + } 1.1098 + fputc('\n', fp); 1.1099 + } 1.1100 + } else { 1.1101 + int numtri = nverts / 3; 1.1102 + unsigned int idx = 1; 1.1103 + for(int i=0; i<numtri; i++) { 1.1104 + fputc('f', fp); 1.1105 + for(int j=0; j<3; j++) { 1.1106 + fprintf(fp, " %u/%u/%u", idx, idx, idx); 1.1107 + ++idx; 1.1108 + } 1.1109 + fputc('\n', fp); 1.1110 + } 1.1111 + } 1.1112 + return true; 1.1113 +} 1.1114 + 1.1115 +// ------ private member functions ------ 1.1116 + 1.1117 +void Mesh::calc_aabb() 1.1118 +{ 1.1119 + // the cast is to force calling the const version which doesn't invalidate 1.1120 + if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) { 1.1121 + return; 1.1122 + } 1.1123 + 1.1124 + aabb.min = Vec3(FLT_MAX, FLT_MAX, FLT_MAX); 1.1125 + aabb.max = -aabb.min; 1.1126 + 1.1127 + for(unsigned int i=0; i<nverts; i++) { 1.1128 + Vec4 v = get_attrib(MESH_ATTR_VERTEX, i); 1.1129 + for(int j=0; j<3; j++) { 1.1130 + if(v[j] < aabb.min[j]) { 1.1131 + aabb.min[j] = v[j]; 1.1132 + } 1.1133 + if(v[j] > aabb.max[j]) { 1.1134 + aabb.max[j] = v[j]; 1.1135 + } 1.1136 + } 1.1137 + } 1.1138 + aabb_valid = true; 1.1139 +} 1.1140 + 1.1141 +void Mesh::calc_bsph() 1.1142 +{ 1.1143 + // the cast is to force calling the const version which doesn't invalidate 1.1144 + if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) { 1.1145 + return; 1.1146 + } 1.1147 + 1.1148 + Vec3 v; 1.1149 + bsph.center = Vec3(0, 0, 0); 1.1150 + 1.1151 + // first find the center 1.1152 + for(unsigned int i=0; i<nverts; i++) { 1.1153 + v = get_attrib(MESH_ATTR_VERTEX, i).xyz(); 1.1154 + bsph.center += v; 1.1155 + } 1.1156 + bsph.center /= (float)nverts; 1.1157 + 1.1158 + bsph.radius = 0.0f; 1.1159 + for(unsigned int i=0; i<nverts; i++) { 1.1160 + v = get_attrib(MESH_ATTR_VERTEX, i).xyz(); 1.1161 + float dist_sq = length_sq(v - bsph.center); 1.1162 + if(dist_sq > bsph.radius) { 1.1163 + bsph.radius = dist_sq; 1.1164 + } 1.1165 + } 1.1166 + bsph.radius = sqrt(bsph.radius); 1.1167 + 1.1168 + bsph_valid = true; 1.1169 +} 1.1170 + 1.1171 +void Mesh::update_buffers() 1.1172 +{ 1.1173 + for(int i=0; i<NUM_MESH_ATTR; i++) { 1.1174 + if(has_attrib(i) && !vattr[i].vbo_valid) { 1.1175 + glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo); 1.1176 + glBufferData(GL_ARRAY_BUFFER, nverts * vattr[i].nelem * sizeof(float), &vattr[i].data[0], GL_STATIC_DRAW); 1.1177 + vattr[i].vbo_valid = true; 1.1178 + } 1.1179 + } 1.1180 + glBindBuffer(GL_ARRAY_BUFFER, 0); 1.1181 + 1.1182 + if(idata_valid && !ibo_valid) { 1.1183 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); 1.1184 + glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 3 * sizeof(unsigned int), &idata[0], GL_STATIC_DRAW); 1.1185 + ibo_valid = true; 1.1186 + } 1.1187 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 1.1188 +} 1.1189 + 1.1190 +void Mesh::update_wire_ibo() 1.1191 +{ 1.1192 + update_buffers(); 1.1193 + 1.1194 + if(wire_ibo_valid) { 1.1195 + return; 1.1196 + } 1.1197 + 1.1198 + if(!wire_ibo) { 1.1199 + glGenBuffers(1, &wire_ibo); 1.1200 + } 1.1201 + 1.1202 + unsigned int *wire_idxarr = new unsigned int[nfaces * 6]; 1.1203 + unsigned int *dest = wire_idxarr; 1.1204 + 1.1205 + if(ibo_valid) { 1.1206 + // we're dealing with an indexed mesh 1.1207 + const unsigned int *idxarr = ((const Mesh*)this)->get_index_data(); 1.1208 + 1.1209 + for(unsigned int i=0; i<nfaces; i++) { 1.1210 + *dest++ = idxarr[0]; 1.1211 + *dest++ = idxarr[1]; 1.1212 + *dest++ = idxarr[1]; 1.1213 + *dest++ = idxarr[2]; 1.1214 + *dest++ = idxarr[2]; 1.1215 + *dest++ = idxarr[0]; 1.1216 + idxarr += 3; 1.1217 + } 1.1218 + } else { 1.1219 + // not an indexed mesh ... 1.1220 + for(unsigned int i=0; i<nfaces; i++) { 1.1221 + int vidx = i * 3; 1.1222 + *dest++ = vidx; 1.1223 + *dest++ = vidx + 1; 1.1224 + *dest++ = vidx + 1; 1.1225 + *dest++ = vidx + 2; 1.1226 + *dest++ = vidx + 2; 1.1227 + *dest++ = vidx; 1.1228 + } 1.1229 + } 1.1230 + 1.1231 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo); 1.1232 + glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 6 * sizeof(unsigned int), wire_idxarr, GL_STATIC_DRAW); 1.1233 + delete [] wire_idxarr; 1.1234 + wire_ibo_valid = true; 1.1235 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 1.1236 +} 1.1237 + 1.1238 + 1.1239 +// ------ class Triangle ------ 1.1240 +Triangle::Triangle() 1.1241 +{ 1.1242 + normal_valid = false; 1.1243 + id = -1; 1.1244 +} 1.1245 + 1.1246 +Triangle::Triangle(const Vec3 &v0, const Vec3 &v1, const Vec3 &v2) 1.1247 +{ 1.1248 + v[0] = v0; 1.1249 + v[1] = v1; 1.1250 + v[2] = v2; 1.1251 + normal_valid = false; 1.1252 + id = -1; 1.1253 +} 1.1254 + 1.1255 +Triangle::Triangle(int n, const Vec3 *varr, const unsigned int *idxarr) 1.1256 +{ 1.1257 + if(idxarr) { 1.1258 + v[0] = varr[idxarr[n * 3]]; 1.1259 + v[1] = varr[idxarr[n * 3 + 1]]; 1.1260 + v[2] = varr[idxarr[n * 3 + 2]]; 1.1261 + } else { 1.1262 + v[0] = varr[n * 3]; 1.1263 + v[1] = varr[n * 3 + 1]; 1.1264 + v[2] = varr[n * 3 + 2]; 1.1265 + } 1.1266 + normal_valid = false; 1.1267 + id = n; 1.1268 +} 1.1269 + 1.1270 +void Triangle::calc_normal() 1.1271 +{ 1.1272 + normal = normalize(cross(v[1] - v[0], v[2] - v[0])); 1.1273 + normal_valid = true; 1.1274 +} 1.1275 + 1.1276 +const Vec3 &Triangle::get_normal() const 1.1277 +{ 1.1278 + if(!normal_valid) { 1.1279 + ((Triangle*)this)->calc_normal(); 1.1280 + } 1.1281 + return normal; 1.1282 +} 1.1283 + 1.1284 +void Triangle::transform(const Mat4 &xform) 1.1285 +{ 1.1286 + v[0] = xform * v[0]; 1.1287 + v[1] = xform * v[1]; 1.1288 + v[2] = xform * v[2]; 1.1289 + normal_valid = false; 1.1290 +} 1.1291 + 1.1292 +void Triangle::draw() const 1.1293 +{ 1.1294 + Vec3 n[3]; 1.1295 + n[0] = n[1] = n[2] = get_normal(); 1.1296 + 1.1297 + int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX); 1.1298 + int nloc = Mesh::get_attrib_location(MESH_ATTR_NORMAL); 1.1299 + 1.1300 + glEnableVertexAttribArray(vloc); 1.1301 + glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x); 1.1302 + glVertexAttribPointer(nloc, 3, GL_FLOAT, GL_FALSE, 0, &n[0].x); 1.1303 + 1.1304 + glDrawArrays(GL_TRIANGLES, 0, 3); 1.1305 + 1.1306 + glDisableVertexAttribArray(vloc); 1.1307 + glDisableVertexAttribArray(nloc); 1.1308 +} 1.1309 + 1.1310 +void Triangle::draw_wire() const 1.1311 +{ 1.1312 + static const int idxarr[] = {0, 1, 1, 2, 2, 0}; 1.1313 + int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX); 1.1314 + 1.1315 + glEnableVertexAttribArray(vloc); 1.1316 + glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x); 1.1317 + 1.1318 + glDrawElements(GL_LINES, 6, GL_UNSIGNED_INT, idxarr); 1.1319 + 1.1320 + glDisableVertexAttribArray(vloc); 1.1321 +} 1.1322 + 1.1323 +Vec3 Triangle::calc_barycentric(const Vec3 &pos) const 1.1324 +{ 1.1325 + Vec3 norm = get_normal(); 1.1326 + 1.1327 + float area_sq = fabs(dot(cross(v[1] - v[0], v[2] - v[0]), norm)); 1.1328 + if(area_sq < 1e-5) { 1.1329 + return Vec3(0, 0, 0); 1.1330 + } 1.1331 + 1.1332 + float asq0 = fabs(dot(cross(v[1] - pos, v[2] - pos), norm)); 1.1333 + float asq1 = fabs(dot(cross(v[2] - pos, v[0] - pos), norm)); 1.1334 + float asq2 = fabs(dot(cross(v[0] - pos, v[1] - pos), norm)); 1.1335 + 1.1336 + return Vec3(asq0 / area_sq, asq1 / area_sq, asq2 / area_sq); 1.1337 +} 1.1338 + 1.1339 +bool Triangle::intersect(const Ray &ray, HitPoint *hit) const 1.1340 +{ 1.1341 + Vec3 normal = get_normal(); 1.1342 + 1.1343 + float ndotdir = dot(ray.dir, normal); 1.1344 + if(fabs(ndotdir) < 1e-4) { 1.1345 + return false; 1.1346 + } 1.1347 + 1.1348 + Vec3 vertdir = v[0] - ray.origin; 1.1349 + float t = dot(normal, vertdir) / ndotdir; 1.1350 + 1.1351 + Vec3 pos = ray.origin + ray.dir * t; 1.1352 + Vec3 bary = calc_barycentric(pos); 1.1353 + 1.1354 + if(bary.x + bary.y + bary.z > 1.00001) { 1.1355 + return false; 1.1356 + } 1.1357 + 1.1358 + if(hit) { 1.1359 + hit->dist = t; 1.1360 + hit->pos = ray.origin + ray.dir * t; 1.1361 + hit->normal = normal; 1.1362 + hit->obj = this; 1.1363 + } 1.1364 + return true; 1.1365 +}