vrshoot

annotate src/mesh.cc @ 0:b2f14e535253

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