00001 #ifndef N_BBOX_H
00002 #define N_BBOX_H
00003
00012 #include "mathlib/vector.h"
00013 #include "mathlib/matrix.h"
00014 #include "mathlib/line.h"
00015 #include "mathlib/plane.h"
00016 #include "util/narray.h"
00017
00018
00019
00020
00021 class bbox3
00022 {
00023 public:
00025 enum
00026 {
00027 ClipLeft = (1<<0),
00028 ClipRight = (1<<1),
00029 ClipBottom = (1<<2),
00030 ClipTop = (1<<3),
00031 ClipNear = (1<<4),
00032 ClipFar = (1<<5),
00033 };
00035 enum ClipStatus
00036 {
00037 Outside,
00038 Inside,
00039 Clipped,
00040 };
00041
00042 enum {
00043 OUTSIDE = 0,
00044 ISEQUAL = (1<<0),
00045 ISCONTAINED = (1<<1),
00046 CONTAINS = (1<<2),
00047 CLIPS = (1<<3),
00048 };
00049
00051 bbox3();
00053 bbox3(const vector3& center, const vector3& extents);
00055 bbox3(const matrix44& m);
00057 vector3 center() const;
00059 vector3 extents() const;
00061 vector3 size() const;
00063 float diagonal_size() const;
00065 void set(const matrix44& m);
00067 void set(const vector3& center, const vector3& extents);
00069 void begin_extend();
00071 void extend(const vector3& v);
00073 void end_extend();
00075 void extend(float x, float y, float z);
00077 void extend(const bbox3& box);
00079 void transform(const matrix44& m);
00081 void transform_divw(const matrix44& m);
00083 bool intersects(const bbox3& box) const;
00085 bool contains(const bbox3& box) const;
00087 bool contains(const vector3& pos) const;
00089 ClipStatus clipstatus(const bbox3& other) const;
00091 ClipStatus clipstatus(const matrix44& viewProjection) const;
00093 matrix44 to_matrix44() const;
00095 vector3 corner_point(int index) const;
00097 void get_clipplanes(const matrix44& viewProjection, nArray<plane>& outPlanes) const;
00098
00099 int line_test(float v0, float v1, float w0, float w1);
00100 int intersect(const bbox3& box);
00101 bool intersect(const line3& line, vector3& ipos) const;
00102
00103
00104
00105 bool isect_const_x(const float x, const line3& l, vector3& out) const
00106 {
00107 if (l.m.x != 0.0f)
00108 {
00109 float t = (x - l.b.x) / l.m.x;
00110 if ((t >= 0.0f) && (t <= 1.0f))
00111 {
00112
00113 out = l.ipol(t);
00114 return true;
00115 }
00116 }
00117 return false;
00118 }
00119 bool isect_const_y(const float y, const line3& l, vector3& out) const
00120 {
00121 if (l.m.y != 0.0f)
00122 {
00123 float t = (y - l.b.y) / l.m.y;
00124 if ((t >= 0.0f) && (t <= 1.0f))
00125 {
00126
00127 out = l.ipol(t);
00128 return true;
00129 }
00130 }
00131 return false;
00132 }
00133 bool isect_const_z(const float z, const line3& l, vector3& out) const
00134 {
00135 if (l.m.z != 0.0f)
00136 {
00137 float t = (z - l.b.z) / l.m.z;
00138 if ((t >= 0.0f) && (t <= 1.0f))
00139 {
00140
00141 out = l.ipol(t);
00142 return true;
00143 }
00144 }
00145 return false;
00146 }
00147
00148
00149 bool pip_const_x(const vector3& p) const
00150 {
00151 if ((p.y >= vmin.y) && (p.y <= vmax.y) && (p.z >= vmin.z) && (p.z <= vmax.z)) return true;
00152 return false;
00153 }
00154 bool pip_const_y(const vector3& p) const
00155 {
00156 if ((p.x >= vmin.x) && (p.x <= vmax.x) && (p.z >= vmin.z) && (p.z <= vmax.z)) return true;
00157 return false;
00158 }
00159 bool pip_const_z(const vector3& p) const
00160 {
00161 if ((p.x >= vmin.x) && (p.x <= vmax.x) && (p.y >= vmin.y) && (p.y <= vmax.y)) return true;
00162 return false;
00163 }
00164
00165 vector3 vmin;
00166 vector3 vmax;
00167 };
00168
00169
00172 inline
00173 bbox3::bbox3()
00174 {
00175
00176 }
00177
00178
00181 inline
00182 bbox3::bbox3(const vector3& center, const vector3& extents)
00183 {
00184 vmin = center - extents;
00185 vmax = center + extents;
00186 }
00187
00188
00194 inline
00195 void
00196 bbox3::set(const matrix44& m)
00197 {
00198
00199 float xExtent = n_max(n_max(n_abs(m.M11), n_abs(m.M21)), n_abs(m.M31));
00200 float yExtent = n_max(n_max(n_abs(m.M12), n_abs(m.M22)), n_abs(m.M32));
00201 float zExtent = n_max(n_max(n_abs(m.M13), n_abs(m.M23)), n_abs(m.M33));
00202 vector3 extent(xExtent, yExtent, zExtent);
00203
00204 vector3 center = m.pos_component();
00205 this->vmin = center - extent;
00206 this->vmax = center + extent;
00207 }
00208
00209
00212 inline
00213 bbox3::bbox3(const matrix44& m)
00214 {
00215 this->set(m);
00216 }
00217
00218
00221 inline
00222 vector3
00223 bbox3::center() const
00224 {
00225 return vector3((vmin + vmax) * 0.5f);
00226 }
00227
00228
00231 inline
00232 vector3
00233 bbox3::extents() const
00234 {
00235 return vector3((vmax - vmin) * 0.5f);
00236 }
00237
00238
00241 inline
00242 vector3
00243 bbox3::size() const
00244 {
00245 return vector3(vmax - vmin);
00246 }
00247
00248
00251 inline
00252 void
00253 bbox3::set(const vector3& center, const vector3& extents)
00254 {
00255 vmin = center - extents;
00256 vmax = center + extents;
00257 }
00258
00259
00262 inline
00263 void
00264 bbox3::begin_extend()
00265 {
00266 vmin.set( 1000000.0f, 1000000.0f, 1000000.0f);
00267 vmax.set(-1000000.0f, -1000000.0f, -1000000.0f);
00268 }
00269
00270
00275 inline
00276 void
00277 bbox3::end_extend()
00278 {
00279 if (vmin.isequal(vector3( 1000000.0f, 1000000.0f, 1000000.0f), TINY) &&
00280 vmax.isequal(vector3(-1000000.0f, -1000000.0f, -1000000.0f), TINY))
00281 {
00282 vmin.set(0.0f, 0.0f, 0.0f);
00283 vmax.set(0.0f, 0.0f, 0.0f);
00284 }
00285 }
00286
00287
00290 inline
00291 void
00292 bbox3::extend(const vector3& v)
00293 {
00294 if (v.x < vmin.x) vmin.x = v.x;
00295 if (v.x > vmax.x) vmax.x = v.x;
00296 if (v.y < vmin.y) vmin.y = v.y;
00297 if (v.y > vmax.y) vmax.y = v.y;
00298 if (v.z < vmin.z) vmin.z = v.z;
00299 if (v.z > vmax.z) vmax.z = v.z;
00300 }
00301
00302
00305 inline
00306 void
00307 bbox3::extend(float x, float y, float z)
00308 {
00309 if (x < vmin.x) vmin.x = x;
00310 if (x > vmax.x) vmax.x = x;
00311 if (y < vmin.y) vmin.y = y;
00312 if (y > vmax.y) vmax.y = y;
00313 if (z < vmin.z) vmin.z = z;
00314 if (z > vmax.z) vmax.z = z;
00315 }
00316
00317
00320 inline
00321 void
00322 bbox3::extend(const bbox3& box)
00323 {
00324 if (box.vmin.x < vmin.x) vmin.x = box.vmin.x;
00325 if (box.vmin.y < vmin.y) vmin.y = box.vmin.y;
00326 if (box.vmin.z < vmin.z) vmin.z = box.vmin.z;
00327 if (box.vmax.x > vmax.x) vmax.x = box.vmax.x;
00328 if (box.vmax.y > vmax.y) vmax.y = box.vmax.y;
00329 if (box.vmax.z > vmax.z) vmax.z = box.vmax.z;
00330 }
00331
00332
00336 inline
00337 vector3
00338 bbox3::corner_point(int index) const
00339 {
00340 n_assert((index >= 0) && (index < 8));
00341 switch (index)
00342 {
00343 case 0: return this->vmin;
00344 case 1: return vector3(this->vmin.x, this->vmax.y, this->vmin.z);
00345 case 2: return vector3(this->vmax.x, this->vmax.y, this->vmin.z);
00346 case 3: return vector3(this->vmax.x, this->vmin.y, this->vmin.z);
00347 case 4: return this->vmax;
00348 case 5: return vector3(this->vmin.x, this->vmax.y, this->vmax.z);
00349 case 6: return vector3(this->vmin.x, this->vmin.y, this->vmax.z);
00350 default: return vector3(this->vmax.x, this->vmin.y, this->vmax.z);
00351 }
00352 }
00353
00354
00358 inline
00359 void
00360 bbox3::get_clipplanes(const matrix44& viewProj, nArray<plane>& outPlanes) const
00361 {
00362 matrix44 inv = viewProj;
00363 inv.invert();
00364 inv.transpose();
00365
00366 vector4 planes[6];
00367
00368 planes[0].set(-1, 0, 0, +this->vmax.x);
00369 planes[1].set(+1, 0, 0, -this->vmin.x);
00370 planes[2].set(0, -1, 0, +this->vmax.y);
00371 planes[3].set(0, +1, 0, -this->vmin.y);
00372 planes[4].set(0, 0, -1, +this->vmax.z);
00373 planes[5].set(0, 0, +1, -this->vmin.z);
00374
00375 for (int i = 0; i < 6; ++i)
00376 {
00377 vector4 v = inv * planes[i];
00378 outPlanes.Append(plane(v.x, v.y, v.z, v.w));
00379 }
00380 }
00381
00382
00395 inline
00396 void
00397 bbox3::transform(const matrix44& m)
00398 {
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415 vector3 temp, min, max, corners[8];
00416 bool first = true;
00417 int i;
00418
00419 corners[0] = this->vmin;
00420 corners[1].x = this->vmin.x; corners[1].y = this->vmax.y; corners[1].z = this->vmin.z;
00421 corners[2].x = this->vmax.x; corners[2].y = this->vmax.y; corners[2].z = this->vmin.z;
00422 corners[3].x = this->vmax.x; corners[3].y = this->vmin.y; corners[3].z = this->vmin.z;
00423 corners[4] = this->vmax;
00424 corners[5].x = this->vmin.x; corners[5].y = this->vmax.y; corners[5].z = this->vmax.z;
00425 corners[6].x = this->vmin.x; corners[6].y = this->vmin.y; corners[6].z = this->vmax.z;
00426 corners[7].x = this->vmax.x; corners[7].y = this->vmin.y; corners[7].z = this->vmax.z;
00427
00428 for (i = 0; i < 8; ++i)
00429 {
00430
00431 temp = m * corners[i];
00432 if (first || temp.x > max.x) max.x = temp.x;
00433 if (first || temp.y > max.y) max.y = temp.y;
00434 if (first || temp.z > max.z) max.z = temp.z;
00435 if (first || temp.x < min.x) min.x = temp.x;
00436 if (first || temp.y < min.y) min.y = temp.y;
00437 if (first || temp.z < min.z) min.z = temp.z;
00438 first = false;
00439 }
00440
00441 this->vmin = min;
00442 this->vmax = max;
00443 }
00444
00445
00450 inline
00451 void
00452 bbox3::transform_divw(const matrix44& m)
00453 {
00454 vector3 temp, min, max, corners[8];
00455 bool first = true;
00456 int i;
00457
00458 corners[0] = this->vmin;
00459 corners[1].x = this->vmin.x; corners[1].y = this->vmax.y; corners[1].z = this->vmin.z;
00460 corners[2].x = this->vmax.x; corners[2].y = this->vmax.y; corners[2].z = this->vmin.z;
00461 corners[3].x = this->vmax.x; corners[3].y = this->vmin.y; corners[3].z = this->vmin.z;
00462 corners[4] = this->vmax;
00463 corners[5].x = this->vmin.x; corners[5].y = this->vmax.y; corners[5].z = this->vmax.z;
00464 corners[6].x = this->vmin.x; corners[6].y = this->vmin.y; corners[6].z = this->vmax.z;
00465 corners[7].x = this->vmax.x; corners[7].y = this->vmin.y; corners[7].z = this->vmax.z;
00466
00467 for (i = 0; i < 8; ++i)
00468 {
00469
00470 temp = m.mult_divw(corners[i]);
00471 if (first || temp.x > max.x) max.x = temp.x;
00472 if (first || temp.y > max.y) max.y = temp.y;
00473 if (first || temp.z > max.z) max.z = temp.z;
00474 if (first || temp.x < min.x) min.x = temp.x;
00475 if (first || temp.y < min.y) min.y = temp.y;
00476 if (first || temp.z < min.z) min.z = temp.z;
00477 first = false;
00478 }
00479
00480 this->vmin = min;
00481 this->vmax = max;
00482 }
00483
00484
00489 inline
00490 bool
00491 bbox3::intersects(const bbox3& box) const
00492 {
00493 if ((this->vmax.x < box.vmin.x) || (this->vmin.x > box.vmax.x) ||
00494 (this->vmax.y < box.vmin.y) || (this->vmin.y > box.vmax.y) ||
00495 (this->vmax.z < box.vmin.z) || (this->vmin.z > box.vmax.z))
00496 {
00497 return false;
00498 }
00499 return true;
00500 }
00501
00502
00507 inline
00508 bool
00509 bbox3::contains(const bbox3& box) const
00510 {
00511 if ((this->vmin.x < box.vmin.x) && (this->vmax.x >= box.vmax.x) &&
00512 (this->vmin.y < box.vmin.y) && (this->vmax.y >= box.vmax.y) &&
00513 (this->vmin.z < box.vmin.z) && (this->vmax.z >= box.vmax.z))
00514 {
00515 return true;
00516 }
00517 return false;
00518 }
00519
00520
00524 inline
00525 bool
00526 bbox3::contains(const vector3& v) const
00527 {
00528 if ((this->vmin.x < v.x) && (this->vmax.x >= v.x) &&
00529 (this->vmin.y < v.y) && (this->vmax.y >= v.y) &&
00530 (this->vmin.z < v.z) && (this->vmax.z >= v.z))
00531 {
00532 return true;
00533 }
00534 return false;
00535 }
00536
00537
00541 inline
00542 bbox3::ClipStatus
00543 bbox3::clipstatus(const bbox3& other) const
00544 {
00545 if (this->contains(other))
00546 {
00547 return Inside;
00548 }
00549 if (this->intersects(other))
00550 {
00551 return Clipped;
00552 }
00553 return Outside;
00554 }
00555
00556
00561 inline
00562 bbox3::ClipStatus
00563 bbox3::clipstatus(const matrix44& viewProjection) const
00564 {
00565 int andFlags = 0xffff;
00566 int orFlags = 0;
00567 int i;
00568 static vector4 v0;
00569 static vector4 v1;
00570 for (i = 0; i < 8; i++)
00571 {
00572 int clip = 0;
00573 v0.w = 1.0f;
00574 if (i & 1) v0.x = this->vmin.x;
00575 else v0.x = this->vmax.x;
00576 if (i & 2) v0.y = this->vmin.y;
00577 else v0.y = this->vmax.y;
00578 if (i & 4) v0.z = this->vmin.z;
00579 else v0.z = this->vmax.z;
00580
00581 v1 = viewProjection * v0;
00582
00583 if (v1.x < -v1.w) clip |= ClipLeft;
00584 else if (v1.x > v1.w) clip |= ClipRight;
00585 if (v1.y < -v1.w) clip |= ClipBottom;
00586 else if (v1.y > v1.w) clip |= ClipTop;
00587 if (v1.z < -v1.w) clip |= ClipFar;
00588 else if (v1.z > v1.w) clip |= ClipNear;
00589 andFlags &= clip;
00590 orFlags |= clip;
00591 }
00592 if (0 == orFlags) return Inside;
00593 if (0 != andFlags) return Outside;
00594 return Clipped;
00595 }
00596
00597
00602 inline
00603 matrix44
00604 bbox3::to_matrix44() const
00605 {
00606 matrix44 m;
00607 m.scale(this->size());
00608 m.translate(this->center());
00609 return m;
00610 }
00611
00612
00620 inline bool bbox3::intersect(const line3& line, vector3& ipos) const
00621 {
00622
00623 if (line.b.x >= vmin.x && line.b.y >= vmin.y && line.b.z >= vmin.z &&
00624 line.b.x <= vmax.x && line.b.y <= vmax.y && line.b.z <= vmax.z)
00625 {
00626 ipos = line.b;
00627 return true;
00628 }
00629
00630
00631 int plane[3];
00632 if (line.m.x > 0) plane[0] = 0;
00633 else plane[0] = 1;
00634 if (line.m.y > 0) plane[1] = 2;
00635 else plane[1] = 3;
00636 if (line.m.z > 0) plane[2] = 4;
00637 else plane[2] = 5;
00638
00639 for (int i = 0; i < 3; ++i)
00640 {
00641 switch (plane[i])
00642 {
00643 case 0:
00644 if (isect_const_x(vmin.x,line,ipos) && pip_const_x(ipos)) return true;
00645 break;
00646 case 1:
00647 if (isect_const_x(vmax.x,line,ipos) && pip_const_x(ipos)) return true;
00648 break;
00649 case 2:
00650 if (isect_const_y(vmin.y,line,ipos) && pip_const_y(ipos)) return true;
00651 break;
00652 case 3:
00653 if (isect_const_y(vmax.y,line,ipos) && pip_const_y(ipos)) return true;
00654 break;
00655 case 4:
00656 if (isect_const_z(vmin.z,line,ipos) && pip_const_z(ipos)) return true;
00657 break;
00658 case 5:
00659 if (isect_const_z(vmax.z,line,ipos) && pip_const_z(ipos)) return true;
00660 break;
00661 }
00662 }
00663
00664 return false;
00665 }
00666
00667
00670 inline
00671 int bbox3::line_test(float v0, float v1, float w0, float w1)
00672 {
00673
00674 if ((v1 < w0) || (v0 > w1)) return OUTSIDE;
00675 if ((v0 == w0) && (v1 == w1)) return ISEQUAL;
00676 if ((v0 >= w0) && (v1 <= w1)) return ISCONTAINED;
00677 if ((v0 <= w0) && (v1 >= w1)) return CONTAINS;
00678 return CLIPS;
00679 }
00680
00681
00687 inline
00688 int bbox3::intersect(const bbox3& box)
00689 {
00690 int and_code = 0xffff;
00691 int or_code = 0;
00692 int cx = line_test(vmin.x, vmax.x, box.vmin.x, box.vmax.x);
00693 and_code &= cx;
00694 or_code |= cx;
00695 int cy = line_test(vmin.y, vmax.y, box.vmin.y, box.vmax.y);
00696 and_code &= cy;
00697 or_code |= cy;
00698 int cz = line_test(vmin.z, vmax.z, box.vmin.z, box.vmax.z);
00699 and_code &= cz;
00700 or_code |= cz;
00701 if (or_code == 0) return OUTSIDE;
00702 if (and_code != 0) return and_code;
00703
00704
00705 if (cx && cy && cz) return CLIPS;
00706 return OUTSIDE;
00707 }
00708
00709
00712 inline
00713 float
00714 bbox3::diagonal_size() const
00715 {
00716 return vector3::distance(this->vmin, this->vmax);
00717 }
00718
00719 #endif