3dphotoshoot

annotate src/mesh.cc @ 25:ac80210d5fbe

preparing a pc version for easier development of non-android-specifics
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 18 Jun 2015 03:12:30 +0300
parents
children
rev   line source
nuclear@25 1 #include <stdio.h>
nuclear@25 2 #include <stdlib.h>
nuclear@25 3 #include <float.h>
nuclear@25 4 #include <assert.h>
nuclear@25 5 #include "opengl.h"
nuclear@25 6 #include "mesh.h"
nuclear@25 7 //#include "xform_node.h"
nuclear@25 8 #include "shader.h"
nuclear@25 9
nuclear@25 10 int Mesh::global_sdr_loc[NUM_MESH_ATTR] = {
nuclear@25 11 (int)SDR_ATTR_VERTEX,
nuclear@25 12 (int)SDR_ATTR_NORMAL,
nuclear@25 13 (int)SDR_ATTR_TANGENT,
nuclear@25 14 (int)SDR_ATTR_TEXCOORD,
nuclear@25 15 (int)SDR_ATTR_COLOR,
nuclear@25 16 -1, -1};
nuclear@25 17 unsigned int Mesh::intersect_mode = ISECT_DEFAULT;
nuclear@25 18 float Mesh::vertex_sel_dist = 0.01;
nuclear@25 19 float Mesh::vis_vecsize = 1.0;
nuclear@25 20
nuclear@25 21 Mesh::Mesh()
nuclear@25 22 {
nuclear@25 23 clear();
nuclear@25 24
nuclear@25 25 glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects);
nuclear@25 26
nuclear@25 27 for(int i=0; i<NUM_MESH_ATTR; i++) {
nuclear@25 28 vattr[i].vbo = buffer_objects[i];
nuclear@25 29 }
nuclear@25 30 ibo = buffer_objects[NUM_MESH_ATTR];
nuclear@25 31 wire_ibo = 0;
nuclear@25 32 }
nuclear@25 33
nuclear@25 34 Mesh::~Mesh()
nuclear@25 35 {
nuclear@25 36 glDeleteBuffers(NUM_MESH_ATTR + 1, buffer_objects);
nuclear@25 37
nuclear@25 38 if(wire_ibo) {
nuclear@25 39 glDeleteBuffers(1, &wire_ibo);
nuclear@25 40 }
nuclear@25 41 }
nuclear@25 42
nuclear@25 43 Mesh::Mesh(const Mesh &rhs)
nuclear@25 44 {
nuclear@25 45 clear();
nuclear@25 46
nuclear@25 47 glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects);
nuclear@25 48
nuclear@25 49 for(int i=0; i<NUM_MESH_ATTR; i++) {
nuclear@25 50 vattr[i].vbo = buffer_objects[i];
nuclear@25 51 }
nuclear@25 52 ibo = buffer_objects[NUM_MESH_ATTR];
nuclear@25 53 wire_ibo = 0;
nuclear@25 54
nuclear@25 55 clone(rhs);
nuclear@25 56 }
nuclear@25 57
nuclear@25 58 Mesh &Mesh::operator =(const Mesh &rhs)
nuclear@25 59 {
nuclear@25 60 if(&rhs != this) {
nuclear@25 61 clone(rhs);
nuclear@25 62 }
nuclear@25 63 return *this;
nuclear@25 64 }
nuclear@25 65
nuclear@25 66 bool Mesh::clone(const Mesh &m)
nuclear@25 67 {
nuclear@25 68 clear();
nuclear@25 69
nuclear@25 70 for(int i=0; i<NUM_MESH_ATTR; i++) {
nuclear@25 71 if(m.has_attrib(i)) {
nuclear@25 72 m.get_attrib_data(i); // force validation of the actual data on the source mesh
nuclear@25 73
nuclear@25 74 vattr[i].nelem = m.vattr[i].nelem;
nuclear@25 75 vattr[i].data = m.vattr[i].data; // copy the actual data
nuclear@25 76 vattr[i].data_valid = true;
nuclear@25 77 }
nuclear@25 78 }
nuclear@25 79
nuclear@25 80 if(m.is_indexed()) {
nuclear@25 81 m.get_index_data(); // again, force validation
nuclear@25 82
nuclear@25 83 // copy the index data
nuclear@25 84 idata = m.idata;
nuclear@25 85 idata_valid = true;
nuclear@25 86 }
nuclear@25 87
nuclear@25 88 name = m.name;
nuclear@25 89 nverts = m.nverts;
nuclear@25 90 nfaces = m.nfaces;
nuclear@25 91
nuclear@25 92 //bones = m.bones;
nuclear@25 93
nuclear@25 94 memcpy(cur_val, m.cur_val, sizeof cur_val);
nuclear@25 95
nuclear@25 96 aabb = m.aabb;
nuclear@25 97 aabb_valid = m.aabb_valid;
nuclear@25 98 bsph = m.bsph;
nuclear@25 99 bsph_valid = m.bsph_valid;
nuclear@25 100
nuclear@25 101 hitface = m.hitface;
nuclear@25 102 hitvert = m.hitvert;
nuclear@25 103
nuclear@25 104 intersect_mode = m.intersect_mode;
nuclear@25 105 vertex_sel_dist = m.vertex_sel_dist;
nuclear@25 106 vis_vecsize = m.vis_vecsize;
nuclear@25 107
nuclear@25 108 return true;
nuclear@25 109 }
nuclear@25 110
nuclear@25 111 void Mesh::set_name(const char *name)
nuclear@25 112 {
nuclear@25 113 this->name = name;
nuclear@25 114 }
nuclear@25 115
nuclear@25 116 const char *Mesh::get_name() const
nuclear@25 117 {
nuclear@25 118 return name.c_str();
nuclear@25 119 }
nuclear@25 120
nuclear@25 121 bool Mesh::has_attrib(int attr) const
nuclear@25 122 {
nuclear@25 123 if(attr < 0 || attr >= NUM_MESH_ATTR) {
nuclear@25 124 return false;
nuclear@25 125 }
nuclear@25 126
nuclear@25 127 // if neither of these is valid, then nobody has set this attribute
nuclear@25 128 return vattr[attr].vbo_valid || vattr[attr].data_valid;
nuclear@25 129 }
nuclear@25 130
nuclear@25 131 bool Mesh::is_indexed() const
nuclear@25 132 {
nuclear@25 133 return ibo_valid || idata_valid;
nuclear@25 134 }
nuclear@25 135
nuclear@25 136 void Mesh::clear()
nuclear@25 137 {
nuclear@25 138 //bones.clear();
nuclear@25 139
nuclear@25 140 for(int i=0; i<NUM_MESH_ATTR; i++) {
nuclear@25 141 vattr[i].nelem = 0;
nuclear@25 142 vattr[i].vbo_valid = false;
nuclear@25 143 vattr[i].data_valid = false;
nuclear@25 144 //vattr[i].sdr_loc = -1;
nuclear@25 145 vattr[i].data.clear();
nuclear@25 146 }
nuclear@25 147 ibo_valid = idata_valid = false;
nuclear@25 148 idata.clear();
nuclear@25 149
nuclear@25 150 wire_ibo_valid = false;
nuclear@25 151
nuclear@25 152 nverts = nfaces = 0;
nuclear@25 153
nuclear@25 154 bsph_valid = false;
nuclear@25 155 aabb_valid = false;
nuclear@25 156 }
nuclear@25 157
nuclear@25 158 float *Mesh::set_attrib_data(int attrib, int nelem, unsigned int num, const float *data)
nuclear@25 159 {
nuclear@25 160 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
nuclear@25 161 fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
nuclear@25 162 return 0;
nuclear@25 163 }
nuclear@25 164
nuclear@25 165 if(nverts && num != nverts) {
nuclear@25 166 fprintf(stderr, "%s: attribute count missmatch (%d instead of %d)\n", __FUNCTION__, num, nverts);
nuclear@25 167 return 0;
nuclear@25 168 }
nuclear@25 169 nverts = num;
nuclear@25 170
nuclear@25 171 vattr[attrib].data.clear();
nuclear@25 172 vattr[attrib].nelem = nelem;
nuclear@25 173 vattr[attrib].data.resize(num * nelem);
nuclear@25 174
nuclear@25 175 if(data) {
nuclear@25 176 memcpy(&vattr[attrib].data[0], data, num * nelem * sizeof *data);
nuclear@25 177 }
nuclear@25 178
nuclear@25 179 vattr[attrib].data_valid = true;
nuclear@25 180 vattr[attrib].vbo_valid = false;
nuclear@25 181 return &vattr[attrib].data[0];
nuclear@25 182 }
nuclear@25 183
nuclear@25 184 float *Mesh::get_attrib_data(int attrib)
nuclear@25 185 {
nuclear@25 186 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
nuclear@25 187 fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
nuclear@25 188 return 0;
nuclear@25 189 }
nuclear@25 190
nuclear@25 191 vattr[attrib].vbo_valid = false;
nuclear@25 192 return (float*)((const Mesh*)this)->get_attrib_data(attrib);
nuclear@25 193 }
nuclear@25 194
nuclear@25 195 const float *Mesh::get_attrib_data(int attrib) const
nuclear@25 196 {
nuclear@25 197 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
nuclear@25 198 fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
nuclear@25 199 return 0;
nuclear@25 200 }
nuclear@25 201
nuclear@25 202 if(!vattr[attrib].data_valid) {
nuclear@25 203 #if GL_ES_VERSION_2_0
nuclear@25 204 fprintf(stderr, "%s: can't read back attrib data on CrippledGL ES\n", __FUNCTION__);
nuclear@25 205 return 0;
nuclear@25 206 #else
nuclear@25 207 if(!vattr[attrib].vbo_valid) {
nuclear@25 208 fprintf(stderr, "%s: unavailable attrib: %d\n", __FUNCTION__, attrib);
nuclear@25 209 return 0;
nuclear@25 210 }
nuclear@25 211
nuclear@25 212 // local data copy is unavailable, grab the data from the vbo
nuclear@25 213 Mesh *m = (Mesh*)this;
nuclear@25 214 m->vattr[attrib].data.resize(nverts * vattr[attrib].nelem);
nuclear@25 215
nuclear@25 216 glBindBuffer(GL_ARRAY_BUFFER, vattr[attrib].vbo);
nuclear@25 217 void *data = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
nuclear@25 218 memcpy(&m->vattr[attrib].data[0], data, nverts * vattr[attrib].nelem * sizeof(float));
nuclear@25 219 glUnmapBuffer(GL_ARRAY_BUFFER);
nuclear@25 220
nuclear@25 221 vattr[attrib].data_valid = true;
nuclear@25 222 #endif
nuclear@25 223 }
nuclear@25 224
nuclear@25 225 return &vattr[attrib].data[0];
nuclear@25 226 }
nuclear@25 227
nuclear@25 228 void Mesh::set_attrib(int attrib, int idx, const Vector4 &v)
nuclear@25 229 {
nuclear@25 230 float *data = get_attrib_data(attrib);
nuclear@25 231 if(data) {
nuclear@25 232 data += idx * vattr[attrib].nelem;
nuclear@25 233 for(int i=0; i<vattr[attrib].nelem; i++) {
nuclear@25 234 data[i] = v[i];
nuclear@25 235 }
nuclear@25 236 }
nuclear@25 237 }
nuclear@25 238
nuclear@25 239 Vector4 Mesh::get_attrib(int attrib, int idx) const
nuclear@25 240 {
nuclear@25 241 Vector4 v(0.0, 0.0, 0.0, 1.0);
nuclear@25 242 const float *data = get_attrib_data(attrib);
nuclear@25 243 if(data) {
nuclear@25 244 data += idx * vattr[attrib].nelem;
nuclear@25 245 for(int i=0; i<vattr[attrib].nelem; i++) {
nuclear@25 246 v[i] = data[i];
nuclear@25 247 }
nuclear@25 248 }
nuclear@25 249 return v;
nuclear@25 250 }
nuclear@25 251
nuclear@25 252 int Mesh::get_attrib_count(int attrib) const
nuclear@25 253 {
nuclear@25 254 return has_attrib(attrib) ? nverts : 0;
nuclear@25 255 }
nuclear@25 256
nuclear@25 257
nuclear@25 258 unsigned int *Mesh::set_index_data(int num, const unsigned int *indices)
nuclear@25 259 {
nuclear@25 260 int nidx = nfaces * 3;
nuclear@25 261 if(nidx && num != nidx) {
nuclear@25 262 fprintf(stderr, "%s: index count missmatch (%d instead of %d)\n", __FUNCTION__, num, nidx);
nuclear@25 263 return 0;
nuclear@25 264 }
nuclear@25 265 nfaces = num / 3;
nuclear@25 266
nuclear@25 267 idata.clear();
nuclear@25 268 idata.resize(num);
nuclear@25 269
nuclear@25 270 if(indices) {
nuclear@25 271 memcpy(&idata[0], indices, num * sizeof *indices);
nuclear@25 272 }
nuclear@25 273
nuclear@25 274 idata_valid = true;
nuclear@25 275 ibo_valid = false;
nuclear@25 276
nuclear@25 277 return &idata[0];
nuclear@25 278 }
nuclear@25 279
nuclear@25 280 unsigned int *Mesh::get_index_data()
nuclear@25 281 {
nuclear@25 282 ibo_valid = false;
nuclear@25 283 return (unsigned int*)((const Mesh*)this)->get_index_data();
nuclear@25 284 }
nuclear@25 285
nuclear@25 286 const unsigned int *Mesh::get_index_data() const
nuclear@25 287 {
nuclear@25 288 if(!idata_valid) {
nuclear@25 289 #if GL_ES_VERSION_2_0
nuclear@25 290 fprintf(stderr, "%s: can't read back index data in CrippledGL ES\n", __FUNCTION__);
nuclear@25 291 return 0;
nuclear@25 292 #else
nuclear@25 293 if(!ibo_valid) {
nuclear@25 294 fprintf(stderr, "%s: indices unavailable\n", __FUNCTION__);
nuclear@25 295 return 0;
nuclear@25 296 }
nuclear@25 297
nuclear@25 298 // local data copy is unavailable, gram the data from the ibo
nuclear@25 299 Mesh *m = (Mesh*)this;
nuclear@25 300 int nidx = nfaces * 3;
nuclear@25 301 m->idata.resize(nidx);
nuclear@25 302
nuclear@25 303 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
nuclear@25 304 void *data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY);
nuclear@25 305 memcpy(&m->idata[0], data, nidx * sizeof(unsigned int));
nuclear@25 306 glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
nuclear@25 307
nuclear@25 308 idata_valid = true;
nuclear@25 309 #endif
nuclear@25 310 }
nuclear@25 311
nuclear@25 312 return &idata[0];
nuclear@25 313 }
nuclear@25 314
nuclear@25 315 int Mesh::get_index_count() const
nuclear@25 316 {
nuclear@25 317 return nfaces * 3;
nuclear@25 318 }
nuclear@25 319
nuclear@25 320 void Mesh::append(const Mesh &mesh)
nuclear@25 321 {
nuclear@25 322 unsigned int idxoffs = nverts;
nuclear@25 323
nuclear@25 324 nverts += mesh.nverts;
nuclear@25 325 nfaces += mesh.nfaces;
nuclear@25 326
nuclear@25 327 for(int i=0; i<NUM_MESH_ATTR; i++) {
nuclear@25 328 if(has_attrib(i) && mesh.has_attrib(i)) {
nuclear@25 329 // force validating the data arrays
nuclear@25 330 get_attrib_data(i);
nuclear@25 331 mesh.get_attrib_data(i);
nuclear@25 332
nuclear@25 333 // append the mesh data
nuclear@25 334 vattr[i].data.insert(vattr[i].data.end(), mesh.vattr[i].data.begin(), mesh.vattr[i].data.end());
nuclear@25 335 }
nuclear@25 336 }
nuclear@25 337
nuclear@25 338 if(ibo_valid || idata_valid) {
nuclear@25 339 // make index arrays valid
nuclear@25 340 get_index_data();
nuclear@25 341 mesh.get_index_data();
nuclear@25 342
nuclear@25 343 size_t orig_sz = idata.size();
nuclear@25 344
nuclear@25 345 idata.insert(idata.end(), mesh.idata.begin(), mesh.idata.end());
nuclear@25 346
nuclear@25 347 // fixup all the new indices
nuclear@25 348 for(size_t i=orig_sz; i<idata.size(); i++) {
nuclear@25 349 idata[i] += idxoffs;
nuclear@25 350 }
nuclear@25 351 }
nuclear@25 352
nuclear@25 353 // fuck everything
nuclear@25 354 wire_ibo_valid = false;
nuclear@25 355 aabb_valid = false;
nuclear@25 356 bsph_valid = false;
nuclear@25 357 }
nuclear@25 358
nuclear@25 359 // assemble a complete vertex by adding all the useful attributes
nuclear@25 360 void Mesh::vertex(float x, float y, float z)
nuclear@25 361 {
nuclear@25 362 cur_val[MESH_ATTR_VERTEX] = Vector4(x, y, z, 1.0f);
nuclear@25 363 vattr[MESH_ATTR_VERTEX].data_valid = true;
nuclear@25 364 vattr[MESH_ATTR_VERTEX].nelem = 3;
nuclear@25 365
nuclear@25 366 for(int i=0; i<NUM_MESH_ATTR; i++) {
nuclear@25 367 if(vattr[i].data_valid) {
nuclear@25 368 for(int j=0; j<vattr[MESH_ATTR_VERTEX].nelem; j++) {
nuclear@25 369 vattr[i].data.push_back(cur_val[i][j]);
nuclear@25 370 }
nuclear@25 371 }
nuclear@25 372 vattr[i].vbo_valid = false;
nuclear@25 373 }
nuclear@25 374
nuclear@25 375 if(idata_valid) {
nuclear@25 376 idata.clear();
nuclear@25 377 }
nuclear@25 378 ibo_valid = idata_valid = false;
nuclear@25 379 }
nuclear@25 380
nuclear@25 381 void Mesh::normal(float nx, float ny, float nz)
nuclear@25 382 {
nuclear@25 383 cur_val[MESH_ATTR_NORMAL] = Vector4(nx, ny, nz, 1.0f);
nuclear@25 384 vattr[MESH_ATTR_NORMAL].data_valid = true;
nuclear@25 385 vattr[MESH_ATTR_NORMAL].nelem = 3;
nuclear@25 386 }
nuclear@25 387
nuclear@25 388 void Mesh::tangent(float tx, float ty, float tz)
nuclear@25 389 {
nuclear@25 390 cur_val[MESH_ATTR_TANGENT] = Vector4(tx, ty, tz, 1.0f);
nuclear@25 391 vattr[MESH_ATTR_TANGENT].data_valid = true;
nuclear@25 392 vattr[MESH_ATTR_TANGENT].nelem = 3;
nuclear@25 393 }
nuclear@25 394
nuclear@25 395 void Mesh::texcoord(float u, float v, float w)
nuclear@25 396 {
nuclear@25 397 cur_val[MESH_ATTR_TEXCOORD] = Vector4(u, v, w, 1.0f);
nuclear@25 398 vattr[MESH_ATTR_TEXCOORD].data_valid = true;
nuclear@25 399 vattr[MESH_ATTR_TEXCOORD].nelem = 3;
nuclear@25 400 }
nuclear@25 401
nuclear@25 402 void Mesh::boneweights(float w1, float w2, float w3, float w4)
nuclear@25 403 {
nuclear@25 404 cur_val[MESH_ATTR_BONEWEIGHTS] = Vector4(w1, w2, w3, w4);
nuclear@25 405 vattr[MESH_ATTR_BONEWEIGHTS].data_valid = true;
nuclear@25 406 vattr[MESH_ATTR_BONEWEIGHTS].nelem = 4;
nuclear@25 407 }
nuclear@25 408
nuclear@25 409 void Mesh::boneidx(int idx1, int idx2, int idx3, int idx4)
nuclear@25 410 {
nuclear@25 411 cur_val[MESH_ATTR_BONEIDX] = Vector4(idx1, idx2, idx3, idx4);
nuclear@25 412 vattr[MESH_ATTR_BONEIDX].data_valid = true;
nuclear@25 413 vattr[MESH_ATTR_BONEIDX].nelem = 4;
nuclear@25 414 }
nuclear@25 415
nuclear@25 416 int Mesh::get_poly_count() const
nuclear@25 417 {
nuclear@25 418 if(nfaces) {
nuclear@25 419 return nfaces;
nuclear@25 420 }
nuclear@25 421 if(nverts) {
nuclear@25 422 return nverts / 3;
nuclear@25 423 }
nuclear@25 424 return 0;
nuclear@25 425 }
nuclear@25 426
nuclear@25 427 /// static function
nuclear@25 428 void Mesh::set_attrib_location(int attr, int loc)
nuclear@25 429 {
nuclear@25 430 if(attr < 0 || attr >= NUM_MESH_ATTR) {
nuclear@25 431 return;
nuclear@25 432 }
nuclear@25 433 Mesh::global_sdr_loc[attr] = loc;
nuclear@25 434 }
nuclear@25 435
nuclear@25 436 /// static function
nuclear@25 437 int Mesh::get_attrib_location(int attr)
nuclear@25 438 {
nuclear@25 439 if(attr < 0 || attr >= NUM_MESH_ATTR) {
nuclear@25 440 return -1;
nuclear@25 441 }
nuclear@25 442 return Mesh::global_sdr_loc[attr];
nuclear@25 443 }
nuclear@25 444
nuclear@25 445 /// static function
nuclear@25 446 void Mesh::clear_attrib_locations()
nuclear@25 447 {
nuclear@25 448 for(int i=0; i<NUM_MESH_ATTR; i++) {
nuclear@25 449 Mesh::global_sdr_loc[i] = -1;
nuclear@25 450 }
nuclear@25 451 }
nuclear@25 452
nuclear@25 453 /// static function
nuclear@25 454 void Mesh::set_vis_vecsize(float sz)
nuclear@25 455 {
nuclear@25 456 Mesh::vis_vecsize = sz;
nuclear@25 457 }
nuclear@25 458
nuclear@25 459 float Mesh::get_vis_vecsize()
nuclear@25 460 {
nuclear@25 461 return Mesh::vis_vecsize;
nuclear@25 462 }
nuclear@25 463
nuclear@25 464 void Mesh::apply_xform(const Matrix4x4 &xform)
nuclear@25 465 {
nuclear@25 466 Matrix4x4 dir_xform = xform;
nuclear@25 467 dir_xform[0][3] = dir_xform[1][3] = dir_xform[2][3] = 0.0f;
nuclear@25 468 dir_xform[3][0] = dir_xform[3][1] = dir_xform[3][2] = 0.0f;
nuclear@25 469 dir_xform[3][3] = 1.0f;
nuclear@25 470
nuclear@25 471 apply_xform(xform, dir_xform);
nuclear@25 472 }
nuclear@25 473
nuclear@25 474 void Mesh::apply_xform(const Matrix4x4 &xform, const Matrix4x4 &dir_xform)
nuclear@25 475 {
nuclear@25 476 for(unsigned int i=0; i<nverts; i++) {
nuclear@25 477 Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
nuclear@25 478 set_attrib(MESH_ATTR_VERTEX, i, v.transformed(xform));
nuclear@25 479
nuclear@25 480 if(has_attrib(MESH_ATTR_NORMAL)) {
nuclear@25 481 Vector3 n = get_attrib(MESH_ATTR_NORMAL, i);
nuclear@25 482 set_attrib(MESH_ATTR_NORMAL, i, n.transformed(dir_xform));
nuclear@25 483 }
nuclear@25 484 if(has_attrib(MESH_ATTR_TANGENT)) {
nuclear@25 485 Vector3 t = get_attrib(MESH_ATTR_TANGENT, i);
nuclear@25 486 set_attrib(MESH_ATTR_TANGENT, i, t.transformed(dir_xform));
nuclear@25 487 }
nuclear@25 488 }
nuclear@25 489 }
nuclear@25 490
nuclear@25 491 void Mesh::flip()
nuclear@25 492 {
nuclear@25 493 flip_faces();
nuclear@25 494 flip_normals();
nuclear@25 495 }
nuclear@25 496
nuclear@25 497 void Mesh::flip_faces()
nuclear@25 498 {
nuclear@25 499 if(is_indexed()) {
nuclear@25 500 unsigned int *indices = get_index_data();
nuclear@25 501 if(!indices) return;
nuclear@25 502
nuclear@25 503 int idxnum = get_index_count();
nuclear@25 504 for(int i=0; i<idxnum; i+=3) {
nuclear@25 505 unsigned int tmp = indices[i + 2];
nuclear@25 506 indices[i + 2] = indices[i + 1];
nuclear@25 507 indices[i + 1] = tmp;
nuclear@25 508 }
nuclear@25 509
nuclear@25 510 } else {
nuclear@25 511 Vector3 *verts = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
nuclear@25 512 if(!verts) return;
nuclear@25 513
nuclear@25 514 int vnum = get_attrib_count(MESH_ATTR_VERTEX);
nuclear@25 515 for(int i=0; i<vnum; i+=3) {
nuclear@25 516 Vector3 tmp = verts[i + 2];
nuclear@25 517 verts[i + 2] = verts[i + 1];
nuclear@25 518 verts[i + 1] = tmp;
nuclear@25 519 }
nuclear@25 520 }
nuclear@25 521 }
nuclear@25 522
nuclear@25 523 void Mesh::flip_normals()
nuclear@25 524 {
nuclear@25 525 Vector3 *normals = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
nuclear@25 526 if(!normals) return;
nuclear@25 527
nuclear@25 528 int num = get_attrib_count(MESH_ATTR_NORMAL);
nuclear@25 529 for(int i=0; i<num; i++) {
nuclear@25 530 normals[i] = -normals[i];
nuclear@25 531 }
nuclear@25 532 }
nuclear@25 533
nuclear@25 534 /*
nuclear@25 535 int Mesh::add_bone(XFormNode *bone)
nuclear@25 536 {
nuclear@25 537 int idx = bones.size();
nuclear@25 538 bones.push_back(bone);
nuclear@25 539 return idx;
nuclear@25 540 }
nuclear@25 541
nuclear@25 542 const XFormNode *Mesh::get_bone(int idx) const
nuclear@25 543 {
nuclear@25 544 if(idx < 0 || idx >= (int)bones.size()) {
nuclear@25 545 return 0;
nuclear@25 546 }
nuclear@25 547 return bones[idx];
nuclear@25 548 }
nuclear@25 549
nuclear@25 550 int Mesh::get_bones_count() const
nuclear@25 551 {
nuclear@25 552 return (int)bones.size();
nuclear@25 553 }
nuclear@25 554 */
nuclear@25 555
nuclear@25 556 void Mesh::draw() const
nuclear@25 557 {
nuclear@25 558 #ifdef GL_ES_VERSION_2_0
nuclear@25 559 if(!SdrProg::active) {
nuclear@25 560 fprintf(stderr, "%s: CrippledGL ES can't draw without a shader\n", __FUNCTION__);
nuclear@25 561 return;
nuclear@25 562 }
nuclear@25 563 #endif
nuclear@25 564
nuclear@25 565 ((Mesh*)this)->update_buffers();
nuclear@25 566
nuclear@25 567 if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
nuclear@25 568 fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
nuclear@25 569 return;
nuclear@25 570 }
nuclear@25 571
nuclear@25 572 if(SdrProg::active) {
nuclear@25 573 // rendering with shaders
nuclear@25 574 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
nuclear@25 575 fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__);
nuclear@25 576 return;
nuclear@25 577 }
nuclear@25 578
nuclear@25 579 for(int i=0; i<NUM_MESH_ATTR; i++) {
nuclear@25 580 int loc = global_sdr_loc[i];
nuclear@25 581 if(loc >= 0 && vattr[i].vbo_valid) {
nuclear@25 582 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
nuclear@25 583 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
nuclear@25 584 glEnableVertexAttribArray(loc);
nuclear@25 585 }
nuclear@25 586 }
nuclear@25 587 } else {
nuclear@25 588 #ifndef GL_ES_VERSION_2_0
nuclear@25 589 // rendering with fixed-function (not available in GLES2)
nuclear@25 590 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_VERTEX].vbo);
nuclear@25 591 glVertexPointer(vattr[MESH_ATTR_VERTEX].nelem, GL_FLOAT, 0, 0);
nuclear@25 592 glEnableClientState(GL_VERTEX_ARRAY);
nuclear@25 593
nuclear@25 594 if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
nuclear@25 595 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_NORMAL].vbo);
nuclear@25 596 glNormalPointer(GL_FLOAT, 0, 0);
nuclear@25 597 glEnableClientState(GL_NORMAL_ARRAY);
nuclear@25 598 }
nuclear@25 599 if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
nuclear@25 600 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_TEXCOORD].vbo);
nuclear@25 601 glTexCoordPointer(vattr[MESH_ATTR_TEXCOORD].nelem, GL_FLOAT, 0, 0);
nuclear@25 602 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
nuclear@25 603 }
nuclear@25 604 if(vattr[MESH_ATTR_COLOR].vbo_valid) {
nuclear@25 605 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_COLOR].vbo);
nuclear@25 606 glColorPointer(vattr[MESH_ATTR_COLOR].nelem, GL_FLOAT, 0, 0);
nuclear@25 607 glEnableClientState(GL_COLOR_ARRAY);
nuclear@25 608 }
nuclear@25 609 #endif
nuclear@25 610 }
nuclear@25 611 glBindBuffer(GL_ARRAY_BUFFER, 0);
nuclear@25 612
nuclear@25 613 if(ibo_valid) {
nuclear@25 614 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
nuclear@25 615 glDrawElements(GL_TRIANGLES, nfaces * 3, GL_UNSIGNED_INT, 0);
nuclear@25 616 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
nuclear@25 617 } else {
nuclear@25 618 glDrawArrays(GL_TRIANGLES, 0, nverts);
nuclear@25 619 }
nuclear@25 620
nuclear@25 621 if(SdrProg::active) {
nuclear@25 622 // rendered with shaders
nuclear@25 623 for(int i=0; i<NUM_MESH_ATTR; i++) {
nuclear@25 624 int loc = global_sdr_loc[i];
nuclear@25 625 if(loc >= 0 && vattr[i].vbo_valid) {
nuclear@25 626 glDisableVertexAttribArray(loc);
nuclear@25 627 }
nuclear@25 628 }
nuclear@25 629 } else {
nuclear@25 630 #ifndef GL_ES_VERSION_2_0
nuclear@25 631 // rendered with fixed-function
nuclear@25 632 glDisableClientState(GL_VERTEX_ARRAY);
nuclear@25 633 if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
nuclear@25 634 glDisableClientState(GL_NORMAL_ARRAY);
nuclear@25 635 }
nuclear@25 636 if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
nuclear@25 637 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
nuclear@25 638 }
nuclear@25 639 if(vattr[MESH_ATTR_COLOR].vbo_valid) {
nuclear@25 640 glDisableClientState(GL_COLOR_ARRAY);
nuclear@25 641 }
nuclear@25 642 #endif
nuclear@25 643 }
nuclear@25 644 }
nuclear@25 645
nuclear@25 646 void Mesh::draw_wire() const
nuclear@25 647 {
nuclear@25 648 ((Mesh*)this)->update_wire_ibo();
nuclear@25 649
nuclear@25 650 if(!vattr[MESH_ATTR_VERTEX].vbo_valid || !wire_ibo_valid) {
nuclear@25 651 fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
nuclear@25 652 return;
nuclear@25 653 }
nuclear@25 654 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
nuclear@25 655 fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__);
nuclear@25 656 return;
nuclear@25 657 }
nuclear@25 658
nuclear@25 659 for(int i=0; i<NUM_MESH_ATTR; i++) {
nuclear@25 660 int loc = global_sdr_loc[i];
nuclear@25 661 if(loc >= 0 && vattr[i].vbo_valid) {
nuclear@25 662 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
nuclear@25 663 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
nuclear@25 664 glEnableVertexAttribArray(loc);
nuclear@25 665 }
nuclear@25 666 }
nuclear@25 667 glBindBuffer(GL_ARRAY_BUFFER, 0);
nuclear@25 668
nuclear@25 669 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
nuclear@25 670 glDrawElements(GL_LINES, nfaces * 6, GL_UNSIGNED_INT, 0);
nuclear@25 671 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
nuclear@25 672
nuclear@25 673 for(int i=0; i<NUM_MESH_ATTR; i++) {
nuclear@25 674 int loc = global_sdr_loc[i];
nuclear@25 675 if(loc >= 0 && vattr[i].vbo_valid) {
nuclear@25 676 glDisableVertexAttribArray(loc);
nuclear@25 677 }
nuclear@25 678 }
nuclear@25 679 }
nuclear@25 680
nuclear@25 681 void Mesh::draw_vertices() const
nuclear@25 682 {
nuclear@25 683 ((Mesh*)this)->update_buffers();
nuclear@25 684
nuclear@25 685 if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
nuclear@25 686 fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
nuclear@25 687 return;
nuclear@25 688 }
nuclear@25 689 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
nuclear@25 690 fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__);
nuclear@25 691 return;
nuclear@25 692 }
nuclear@25 693
nuclear@25 694 for(int i=0; i<NUM_MESH_ATTR; i++) {
nuclear@25 695 int loc = global_sdr_loc[i];
nuclear@25 696 if(loc >= 0 && vattr[i].vbo_valid) {
nuclear@25 697 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
nuclear@25 698 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
nuclear@25 699 glEnableVertexAttribArray(loc);
nuclear@25 700 }
nuclear@25 701 }
nuclear@25 702 glBindBuffer(GL_ARRAY_BUFFER, 0);
nuclear@25 703
nuclear@25 704 glDrawArrays(GL_POINTS, 0, nverts);
nuclear@25 705
nuclear@25 706 for(int i=0; i<NUM_MESH_ATTR; i++) {
nuclear@25 707 int loc = global_sdr_loc[i];
nuclear@25 708 if(loc >= 0 && vattr[i].vbo_valid) {
nuclear@25 709 glDisableVertexAttribArray(loc);
nuclear@25 710 }
nuclear@25 711 }
nuclear@25 712 }
nuclear@25 713
nuclear@25 714 void Mesh::draw_normals() const
nuclear@25 715 {
nuclear@25 716 #ifdef USE_OLDGL
nuclear@25 717 Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
nuclear@25 718 Vector3 *norm = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
nuclear@25 719 if(!varr || !norm) {
nuclear@25 720 return;
nuclear@25 721 }
nuclear@25 722
nuclear@25 723 glBegin(GL_LINES);
nuclear@25 724 if(get_current_shader()) {
nuclear@25 725 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
nuclear@25 726 if(vert_loc < 0) {
nuclear@25 727 glEnd();
nuclear@25 728 return;
nuclear@25 729 }
nuclear@25 730
nuclear@25 731 for(size_t i=0; i<nverts; i++) {
nuclear@25 732 glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
nuclear@25 733 Vector3 end = varr[i] + norm[i] * vis_vecsize;
nuclear@25 734 glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
nuclear@25 735 }
nuclear@25 736 } else {
nuclear@25 737 for(size_t i=0; i<nverts; i++) {
nuclear@25 738 glVertex3f(varr[i].x, varr[i].y, varr[i].z);
nuclear@25 739 Vector3 end = varr[i] + norm[i] * vis_vecsize;
nuclear@25 740 glVertex3f(end.x, end.y, end.z);
nuclear@25 741 }
nuclear@25 742 }
nuclear@25 743 glEnd();
nuclear@25 744 #endif // USE_OLDGL
nuclear@25 745 }
nuclear@25 746
nuclear@25 747 void Mesh::draw_tangents() const
nuclear@25 748 {
nuclear@25 749 #ifdef USE_OLDGL
nuclear@25 750 Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
nuclear@25 751 Vector3 *tang = (Vector3*)get_attrib_data(MESH_ATTR_TANGENT);
nuclear@25 752 if(!varr || !tang) {
nuclear@25 753 return;
nuclear@25 754 }
nuclear@25 755
nuclear@25 756 glBegin(GL_LINES);
nuclear@25 757 if(get_current_shader()) {
nuclear@25 758 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
nuclear@25 759 if(vert_loc < 0) {
nuclear@25 760 glEnd();
nuclear@25 761 return;
nuclear@25 762 }
nuclear@25 763
nuclear@25 764 for(size_t i=0; i<nverts; i++) {
nuclear@25 765 glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
nuclear@25 766 Vector3 end = varr[i] + tang[i] * vis_vecsize;
nuclear@25 767 glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
nuclear@25 768 }
nuclear@25 769 } else {
nuclear@25 770 for(size_t i=0; i<nverts; i++) {
nuclear@25 771 glVertex3f(varr[i].x, varr[i].y, varr[i].z);
nuclear@25 772 Vector3 end = varr[i] + tang[i] * vis_vecsize;
nuclear@25 773 glVertex3f(end.x, end.y, end.z);
nuclear@25 774 }
nuclear@25 775 }
nuclear@25 776 glEnd();
nuclear@25 777 #endif // USE_OLDGL
nuclear@25 778 }
nuclear@25 779
nuclear@25 780 void Mesh::get_aabbox(Vector3 *vmin, Vector3 *vmax) const
nuclear@25 781 {
nuclear@25 782 if(!aabb_valid) {
nuclear@25 783 ((Mesh*)this)->calc_aabb();
nuclear@25 784 }
nuclear@25 785 *vmin = aabb.min;
nuclear@25 786 *vmax = aabb.max;
nuclear@25 787 }
nuclear@25 788
nuclear@25 789 const AABox &Mesh::get_aabbox() const
nuclear@25 790 {
nuclear@25 791 if(!aabb_valid) {
nuclear@25 792 ((Mesh*)this)->calc_aabb();
nuclear@25 793 }
nuclear@25 794 return aabb;
nuclear@25 795 }
nuclear@25 796
nuclear@25 797 float Mesh::get_bsphere(Vector3 *center, float *rad) const
nuclear@25 798 {
nuclear@25 799 if(!bsph_valid) {
nuclear@25 800 ((Mesh*)this)->calc_bsph();
nuclear@25 801 }
nuclear@25 802 *center = bsph.center;
nuclear@25 803 *rad = bsph.radius;
nuclear@25 804 return bsph.radius;
nuclear@25 805 }
nuclear@25 806
nuclear@25 807 const Sphere &Mesh::get_bsphere() const
nuclear@25 808 {
nuclear@25 809 if(!bsph_valid) {
nuclear@25 810 ((Mesh*)this)->calc_bsph();
nuclear@25 811 }
nuclear@25 812 return bsph;
nuclear@25 813 }
nuclear@25 814
nuclear@25 815 /// static function
nuclear@25 816 void Mesh::set_intersect_mode(unsigned int mode)
nuclear@25 817 {
nuclear@25 818 Mesh::intersect_mode = mode;
nuclear@25 819 }
nuclear@25 820
nuclear@25 821 /// static function
nuclear@25 822 unsigned int Mesh::get_intersect_mode()
nuclear@25 823 {
nuclear@25 824 return Mesh::intersect_mode;
nuclear@25 825 }
nuclear@25 826
nuclear@25 827 /// static function
nuclear@25 828 void Mesh::set_vertex_select_distance(float dist)
nuclear@25 829 {
nuclear@25 830 Mesh::vertex_sel_dist = dist;
nuclear@25 831 }
nuclear@25 832
nuclear@25 833 /// static function
nuclear@25 834 float Mesh::get_vertex_select_distance()
nuclear@25 835 {
nuclear@25 836 return Mesh::vertex_sel_dist;
nuclear@25 837 }
nuclear@25 838
nuclear@25 839 bool Mesh::intersect(const Ray &ray, HitPoint *hit) const
nuclear@25 840 {
nuclear@25 841 assert((Mesh::intersect_mode & (ISECT_VERTICES | ISECT_FACE)) != (ISECT_VERTICES | ISECT_FACE));
nuclear@25 842
nuclear@25 843 const Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
nuclear@25 844 const Vector3 *narr = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
nuclear@25 845 if(!varr) {
nuclear@25 846 return false;
nuclear@25 847 }
nuclear@25 848 const unsigned int *idxarr = get_index_data();
nuclear@25 849
nuclear@25 850 // first test with the bounding box
nuclear@25 851 AABox box;
nuclear@25 852 get_aabbox(&box.min, &box.max);
nuclear@25 853 if(!box.intersect(ray)) {
nuclear@25 854 return false;
nuclear@25 855 }
nuclear@25 856
nuclear@25 857 HitPoint nearest_hit;
nuclear@25 858 nearest_hit.dist = FLT_MAX;
nuclear@25 859 nearest_hit.obj = 0;
nuclear@25 860
nuclear@25 861 if(Mesh::intersect_mode & ISECT_VERTICES) {
nuclear@25 862 // we asked for "intersections" with the vertices of the mesh
nuclear@25 863 long nearest_vidx = -1;
nuclear@25 864 float thres_sq = Mesh::vertex_sel_dist * Mesh::vertex_sel_dist;
nuclear@25 865
nuclear@25 866 for(unsigned int i=0; i<nverts; i++) {
nuclear@25 867
nuclear@25 868 if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(narr[i], ray.dir) > 0) {
nuclear@25 869 continue;
nuclear@25 870 }
nuclear@25 871
nuclear@25 872 // project the vertex onto the ray line
nuclear@25 873 float t = dot_product(varr[i] - ray.origin, ray.dir);
nuclear@25 874 Vector3 vproj = ray.origin + ray.dir * t;
nuclear@25 875
nuclear@25 876 float dist_sq = (vproj - varr[i]).length_sq();
nuclear@25 877 if(dist_sq < thres_sq) {
nuclear@25 878 if(!hit) {
nuclear@25 879 return true;
nuclear@25 880 }
nuclear@25 881 if(t < nearest_hit.dist) {
nuclear@25 882 nearest_hit.dist = t;
nuclear@25 883 nearest_vidx = i;
nuclear@25 884 }
nuclear@25 885 }
nuclear@25 886 }
nuclear@25 887
nuclear@25 888 if(nearest_vidx != -1) {
nuclear@25 889 hitvert = varr[nearest_vidx];
nuclear@25 890 nearest_hit.obj = &hitvert;
nuclear@25 891 }
nuclear@25 892
nuclear@25 893 } else {
nuclear@25 894 // regular intersection test with polygons
nuclear@25 895
nuclear@25 896 for(unsigned int i=0; i<nfaces; i++) {
nuclear@25 897 Triangle face(i, varr, idxarr);
nuclear@25 898
nuclear@25 899 // ignore back-facing polygons if the mode flags include ISECT_FRONT
nuclear@25 900 if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(face.get_normal(), ray.dir) > 0) {
nuclear@25 901 continue;
nuclear@25 902 }
nuclear@25 903
nuclear@25 904 HitPoint fhit;
nuclear@25 905 if(face.intersect(ray, hit ? &fhit : 0)) {
nuclear@25 906 if(!hit) {
nuclear@25 907 return true;
nuclear@25 908 }
nuclear@25 909 if(fhit.dist < nearest_hit.dist) {
nuclear@25 910 nearest_hit = fhit;
nuclear@25 911 hitface = face;
nuclear@25 912 }
nuclear@25 913 }
nuclear@25 914 }
nuclear@25 915 }
nuclear@25 916
nuclear@25 917 if(nearest_hit.obj) {
nuclear@25 918 if(hit) {
nuclear@25 919 *hit = nearest_hit;
nuclear@25 920
nuclear@25 921 // if we are interested in the mesh and not the faces set obj to this
nuclear@25 922 if(Mesh::intersect_mode & ISECT_FACE) {
nuclear@25 923 hit->obj = &hitface;
nuclear@25 924 } else if(Mesh::intersect_mode & ISECT_VERTICES) {
nuclear@25 925 hit->obj = &hitvert;
nuclear@25 926 } else {
nuclear@25 927 hit->obj = this;
nuclear@25 928 }
nuclear@25 929 }
nuclear@25 930 return true;
nuclear@25 931 }
nuclear@25 932 return false;
nuclear@25 933 }
nuclear@25 934
nuclear@25 935
nuclear@25 936 // ------ private member functions ------
nuclear@25 937
nuclear@25 938 void Mesh::calc_aabb()
nuclear@25 939 {
nuclear@25 940 // the cast is to force calling the const version which doesn't invalidate
nuclear@25 941 if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
nuclear@25 942 return;
nuclear@25 943 }
nuclear@25 944
nuclear@25 945 aabb.min = Vector3(FLT_MAX, FLT_MAX, FLT_MAX);
nuclear@25 946 aabb.max = -aabb.min;
nuclear@25 947
nuclear@25 948 for(unsigned int i=0; i<nverts; i++) {
nuclear@25 949 Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
nuclear@25 950 for(int j=0; j<3; j++) {
nuclear@25 951 if(v[j] < aabb.min[j]) {
nuclear@25 952 aabb.min[j] = v[j];
nuclear@25 953 }
nuclear@25 954 if(v[j] > aabb.max[j]) {
nuclear@25 955 aabb.max[j] = v[j];
nuclear@25 956 }
nuclear@25 957 }
nuclear@25 958 }
nuclear@25 959 aabb_valid = true;
nuclear@25 960 }
nuclear@25 961
nuclear@25 962 void Mesh::calc_bsph()
nuclear@25 963 {
nuclear@25 964 // the cast is to force calling the const version which doesn't invalidate
nuclear@25 965 if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
nuclear@25 966 return;
nuclear@25 967 }
nuclear@25 968
nuclear@25 969 Vector3 v;
nuclear@25 970 bsph.center = Vector3(0, 0, 0);
nuclear@25 971
nuclear@25 972 // first find the center
nuclear@25 973 for(unsigned int i=0; i<nverts; i++) {
nuclear@25 974 v = get_attrib(MESH_ATTR_VERTEX, i);
nuclear@25 975 bsph.center += v;
nuclear@25 976 }
nuclear@25 977 bsph.center /= (float)nverts;
nuclear@25 978
nuclear@25 979 bsph.radius = 0.0f;
nuclear@25 980 for(unsigned int i=0; i<nverts; i++) {
nuclear@25 981 v = get_attrib(MESH_ATTR_VERTEX, i);
nuclear@25 982 float dist_sq = (v - bsph.center).length_sq();
nuclear@25 983 if(dist_sq > bsph.radius) {
nuclear@25 984 bsph.radius = dist_sq;
nuclear@25 985 }
nuclear@25 986 }
nuclear@25 987 bsph.radius = sqrt(bsph.radius);
nuclear@25 988
nuclear@25 989 bsph_valid = true;
nuclear@25 990 }
nuclear@25 991
nuclear@25 992 void Mesh::update_buffers()
nuclear@25 993 {
nuclear@25 994 for(int i=0; i<NUM_MESH_ATTR; i++) {
nuclear@25 995 if(has_attrib(i) && !vattr[i].vbo_valid) {
nuclear@25 996 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
nuclear@25 997 glBufferData(GL_ARRAY_BUFFER, nverts * vattr[i].nelem * sizeof(float), &vattr[i].data[0], GL_STATIC_DRAW);
nuclear@25 998 vattr[i].vbo_valid = true;
nuclear@25 999 }
nuclear@25 1000 }
nuclear@25 1001 glBindBuffer(GL_ARRAY_BUFFER, 0);
nuclear@25 1002
nuclear@25 1003 if(idata_valid && !ibo_valid) {
nuclear@25 1004 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
nuclear@25 1005 glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 3 * sizeof(unsigned int), &idata[0], GL_STATIC_DRAW);
nuclear@25 1006 ibo_valid = true;
nuclear@25 1007 }
nuclear@25 1008 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
nuclear@25 1009 }
nuclear@25 1010
nuclear@25 1011 void Mesh::update_wire_ibo()
nuclear@25 1012 {
nuclear@25 1013 update_buffers();
nuclear@25 1014
nuclear@25 1015 if(wire_ibo_valid) {
nuclear@25 1016 return;
nuclear@25 1017 }
nuclear@25 1018
nuclear@25 1019 if(!wire_ibo) {
nuclear@25 1020 glGenBuffers(1, &wire_ibo);
nuclear@25 1021 }
nuclear@25 1022
nuclear@25 1023 unsigned int *wire_idxarr = new unsigned int[nfaces * 6];
nuclear@25 1024 unsigned int *dest = wire_idxarr;
nuclear@25 1025
nuclear@25 1026 if(ibo_valid) {
nuclear@25 1027 // we're dealing with an indexed mesh
nuclear@25 1028 const unsigned int *idxarr = ((const Mesh*)this)->get_index_data();
nuclear@25 1029
nuclear@25 1030 for(unsigned int i=0; i<nfaces; i++) {
nuclear@25 1031 *dest++ = idxarr[0];
nuclear@25 1032 *dest++ = idxarr[1];
nuclear@25 1033 *dest++ = idxarr[1];
nuclear@25 1034 *dest++ = idxarr[2];
nuclear@25 1035 *dest++ = idxarr[2];
nuclear@25 1036 *dest++ = idxarr[0];
nuclear@25 1037 idxarr += 3;
nuclear@25 1038 }
nuclear@25 1039 } else {
nuclear@25 1040 // not an indexed mesh ...
nuclear@25 1041 for(unsigned int i=0; i<nfaces; i++) {
nuclear@25 1042 int vidx = i * 3;
nuclear@25 1043 *dest++ = vidx;
nuclear@25 1044 *dest++ = vidx + 1;
nuclear@25 1045 *dest++ = vidx + 1;
nuclear@25 1046 *dest++ = vidx + 2;
nuclear@25 1047 *dest++ = vidx + 2;
nuclear@25 1048 *dest++ = vidx;
nuclear@25 1049 }
nuclear@25 1050 }
nuclear@25 1051
nuclear@25 1052 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
nuclear@25 1053 glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 6 * sizeof(unsigned int), wire_idxarr, GL_STATIC_DRAW);
nuclear@25 1054 delete [] wire_idxarr;
nuclear@25 1055 wire_ibo_valid = true;
nuclear@25 1056 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
nuclear@25 1057 }
nuclear@25 1058
nuclear@25 1059
nuclear@25 1060 // ------ class Triangle ------
nuclear@25 1061 Triangle::Triangle()
nuclear@25 1062 {
nuclear@25 1063 normal_valid = false;
nuclear@25 1064 id = -1;
nuclear@25 1065 }
nuclear@25 1066
nuclear@25 1067 Triangle::Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2)
nuclear@25 1068 {
nuclear@25 1069 v[0] = v0;
nuclear@25 1070 v[1] = v1;
nuclear@25 1071 v[2] = v2;
nuclear@25 1072 normal_valid = false;
nuclear@25 1073 id = -1;
nuclear@25 1074 }
nuclear@25 1075
nuclear@25 1076 Triangle::Triangle(int n, const Vector3 *varr, const unsigned int *idxarr)
nuclear@25 1077 {
nuclear@25 1078 if(idxarr) {
nuclear@25 1079 v[0] = varr[idxarr[n * 3]];
nuclear@25 1080 v[1] = varr[idxarr[n * 3 + 1]];
nuclear@25 1081 v[2] = varr[idxarr[n * 3 + 2]];
nuclear@25 1082 } else {
nuclear@25 1083 v[0] = varr[n * 3];
nuclear@25 1084 v[1] = varr[n * 3 + 1];
nuclear@25 1085 v[2] = varr[n * 3 + 2];
nuclear@25 1086 }
nuclear@25 1087 normal_valid = false;
nuclear@25 1088 id = n;
nuclear@25 1089 }
nuclear@25 1090
nuclear@25 1091 void Triangle::calc_normal()
nuclear@25 1092 {
nuclear@25 1093 normal = cross_product(v[1] - v[0], v[2] - v[0]).normalized();
nuclear@25 1094 normal_valid = true;
nuclear@25 1095 }
nuclear@25 1096
nuclear@25 1097 const Vector3 &Triangle::get_normal() const
nuclear@25 1098 {
nuclear@25 1099 if(!normal_valid) {
nuclear@25 1100 ((Triangle*)this)->calc_normal();
nuclear@25 1101 }
nuclear@25 1102 return normal;
nuclear@25 1103 }
nuclear@25 1104
nuclear@25 1105 void Triangle::transform(const Matrix4x4 &xform)
nuclear@25 1106 {
nuclear@25 1107 v[0].transform(xform);
nuclear@25 1108 v[1].transform(xform);
nuclear@25 1109 v[2].transform(xform);
nuclear@25 1110 normal_valid = false;
nuclear@25 1111 }
nuclear@25 1112
nuclear@25 1113 void Triangle::draw() const
nuclear@25 1114 {
nuclear@25 1115 Vector3 n[3];
nuclear@25 1116 n[0] = get_normal();
nuclear@25 1117 n[1] = get_normal();
nuclear@25 1118 n[2] = get_normal();
nuclear@25 1119
nuclear@25 1120 int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
nuclear@25 1121 int nloc = Mesh::get_attrib_location(MESH_ATTR_NORMAL);
nuclear@25 1122
nuclear@25 1123 glEnableVertexAttribArray(vloc);
nuclear@25 1124 glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
nuclear@25 1125 glVertexAttribPointer(nloc, 3, GL_FLOAT, GL_FALSE, 0, &n[0].x);
nuclear@25 1126
nuclear@25 1127 glDrawArrays(GL_TRIANGLES, 0, 3);
nuclear@25 1128
nuclear@25 1129 glDisableVertexAttribArray(vloc);
nuclear@25 1130 glDisableVertexAttribArray(nloc);
nuclear@25 1131 CHECK_GLERROR;
nuclear@25 1132 }
nuclear@25 1133
nuclear@25 1134 void Triangle::draw_wire() const
nuclear@25 1135 {
nuclear@25 1136 static const int idxarr[] = {0, 1, 1, 2, 2, 0};
nuclear@25 1137 int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
nuclear@25 1138
nuclear@25 1139 glEnableVertexAttribArray(vloc);
nuclear@25 1140 glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
nuclear@25 1141
nuclear@25 1142 glDrawElements(GL_LINES, 6, GL_UNSIGNED_INT, idxarr);
nuclear@25 1143
nuclear@25 1144 glDisableVertexAttribArray(vloc);
nuclear@25 1145 CHECK_GLERROR;
nuclear@25 1146 }
nuclear@25 1147
nuclear@25 1148 Vector3 Triangle::calc_barycentric(const Vector3 &pos) const
nuclear@25 1149 {
nuclear@25 1150 Vector3 norm = get_normal();
nuclear@25 1151
nuclear@25 1152 float area_sq = fabs(dot_product(cross_product(v[1] - v[0], v[2] - v[0]), norm));
nuclear@25 1153 if(area_sq < 1e-5) {
nuclear@25 1154 return Vector3(0, 0, 0);
nuclear@25 1155 }
nuclear@25 1156
nuclear@25 1157 float asq0 = fabs(dot_product(cross_product(v[1] - pos, v[2] - pos), norm));
nuclear@25 1158 float asq1 = fabs(dot_product(cross_product(v[2] - pos, v[0] - pos), norm));
nuclear@25 1159 float asq2 = fabs(dot_product(cross_product(v[0] - pos, v[1] - pos), norm));
nuclear@25 1160
nuclear@25 1161 return Vector3(asq0 / area_sq, asq1 / area_sq, asq2 / area_sq);
nuclear@25 1162 }
nuclear@25 1163
nuclear@25 1164 bool Triangle::intersect(const Ray &ray, HitPoint *hit) const
nuclear@25 1165 {
nuclear@25 1166 Vector3 normal = get_normal();
nuclear@25 1167
nuclear@25 1168 float ndotdir = dot_product(ray.dir, normal);
nuclear@25 1169 if(fabs(ndotdir) < 1e-4) {
nuclear@25 1170 return false;
nuclear@25 1171 }
nuclear@25 1172
nuclear@25 1173 Vector3 vertdir = v[0] - ray.origin;
nuclear@25 1174 float t = dot_product(normal, vertdir) / ndotdir;
nuclear@25 1175
nuclear@25 1176 Vector3 pos = ray.origin + ray.dir * t;
nuclear@25 1177 Vector3 bary = calc_barycentric(pos);
nuclear@25 1178
nuclear@25 1179 if(bary.x + bary.y + bary.z > 1.00001) {
nuclear@25 1180 return false;
nuclear@25 1181 }
nuclear@25 1182
nuclear@25 1183 if(hit) {
nuclear@25 1184 hit->dist = t;
nuclear@25 1185 hit->pos = ray.origin + ray.dir * t;
nuclear@25 1186 hit->normal = normal;
nuclear@25 1187 hit->obj = this;
nuclear@25 1188 }
nuclear@25 1189 return true;
nuclear@25 1190 }