ld33_umonster

annotate src/mesh.cc @ 5:1e8d90aeae34

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