conworlds

annotate src/mesh.cc @ 13:283cdfa7dda2

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