coeng

annotate src/mesh.cc @ 8:8cce82794f90

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