diff options
Diffstat (limited to 'dep/src/g3dlite/Box.cpp')
-rw-r--r-- | dep/src/g3dlite/Box.cpp | 213 |
1 files changed, 136 insertions, 77 deletions
diff --git a/dep/src/g3dlite/Box.cpp b/dep/src/g3dlite/Box.cpp index 725a7e95c3a..f7c112ae3a5 100644 --- a/dep/src/g3dlite/Box.cpp +++ b/dep/src/g3dlite/Box.cpp @@ -2,7 +2,7 @@ @file Box.cpp Box class - @maintainer Morgan McGuire, matrix@graphics3d.com + @maintainer Morgan McGuire, http://graphics.cs.williams.edu @created 2001-06-02 @edited 2006-02-05 @@ -27,10 +27,56 @@ namespace G3D { Box::Box() { } + Box::Box(const AABox& b) { init(b.low(), b.high()); } +Box::Box(class BinaryInput& b) { + deserialize(b); +} + + +void Box::serialize(class BinaryOutput& b) const { + int i; + for (i = 0; i < 8; ++i) { + _corner[i].serialize(b); + } + + // Other state can be reconstructed +} + + +void Box::deserialize(class BinaryInput& b) { + int i; + + _center = Vector3::zero(); + for (i = 0; i < 8; ++i) { + _corner[i].deserialize(b); + _center += _corner[i]; + } + + _center = _center / 8; + + // Reconstruct other state from the corners + _axis[0] = _corner[5] - _corner[4]; + _axis[1] = _corner[7] - _corner[4]; + _axis[2] = _corner[0] - _corner[4]; + + for (i = 0; i < 3; ++i) { + _extent[i] = _axis[i].magnitude(); + _axis[i] /= _extent[i]; + } + + _volume = _extent.x * _extent.y * _extent.z; + + _area = 2 * + (_extent.x * _extent.y + + _extent.y * _extent.z + + _extent.z * _extent.x); +} + + Box::Box( const Vector3& min, const Vector3& max) { @@ -43,6 +89,11 @@ void Box::init( const Vector3& min, const Vector3& max) { + debugAssert( + (min.x <= max.x) && + (min.y <= max.y) && + (min.z <= max.z)); + setMany(0, 1, 2, 3, z, max); setMany(4, 5, 6, 7, z, min); @@ -58,23 +109,40 @@ void Box::init( _axis[1] = Vector3::unitY(); _axis[2] = Vector3::unitZ(); - _volume = _extent.x * _extent.y * _extent.z; - _area = 2 * + if (_extent.isFinite()) { + _volume = _extent.x * _extent.y * _extent.z; + } else { + _volume = G3D::finf(); + } + + debugAssert(! isNaN(_extent.x)); + + _area = 2 * (_extent.x * _extent.y + _extent.y * _extent.z + _extent.z * _extent.x); - _center = (max + min) / 2; + _center = (max + min) * 0.5f; + + // If the extent is infinite along an axis, make the center zero to avoid NaNs + for (int i = 0; i < 3; ++i) { + if (! G3D::isFinite(_extent[i])) { + _center[i] = 0.0f; + } + } } + float Box::volume() const { return _volume; } -float Box::surfaceArea() const { + +float Box::area() const { return _area; } + void Box::getLocalFrame(CoordinateFrame& frame) const { frame.rotation = Matrix3( @@ -85,12 +153,14 @@ void Box::getLocalFrame(CoordinateFrame& frame) const { frame.translation = _center; } + CoordinateFrame Box::localFrame() const { CoordinateFrame out; getLocalFrame(out); return out; } + void Box::getFaceCorners(int f, Vector3& v0, Vector3& v1, Vector3& v2, Vector3& v3) const { switch (f) { case 0: @@ -122,45 +192,29 @@ void Box::getFaceCorners(int f, Vector3& v0, Vector3& v1, Vector3& v2, Vector3& } } -bool Box::culledBy( - const Array<Plane>& plane, - int& cullingPlaneIndex, - const uint32 inMask, - uint32& outMask) const { - - return culledBy(plane.getCArray(), plane.size(), cullingPlaneIndex, inMask, outMask); -} - -bool Box::culledBy( - const Array<Plane>& plane, - int& cullingPlaneIndex, - const uint32 inMask) const { - return culledBy(plane.getCArray(), plane.size(), cullingPlaneIndex, inMask); -} -int32 Box::dummy = 0; +int Box::dummy = 0; bool Box::culledBy( - const class Plane* plane, - int numPlanes, + const Array<Plane>& plane, int& cullingPlane, const uint32 _inMask, uint32& childMask) const { uint32 inMask = _inMask; - assert(numPlanes < 31); + assert(plane.size() < 31); childMask = 0; // See if there is one plane for which all of the - // vertices are in the negative half space. - for (int p = 0; p < numPlanes; p++) { - - // Only test planes that are not masked - if ((inMask & 1) != 0) { + // vertices are in the negative half space. + for (int p = 0; p < plane.size(); ++p) { - Vector3 corner; + // Only test planes that are not masked + if ((inMask & 1) != 0) { + + Vector3 corner; int numContained = 0; int v = 0; @@ -168,83 +222,84 @@ bool Box::culledBy( // We can early-out only if we have found one point on each // side of the plane (i.e. if we are straddling). That // occurs when (numContained < v) && (numContained > 0) - for (v = 0; (v < 8) && ((numContained == v) || (numContained == 0)); ++v) { - if (plane[p].halfSpaceContains(getCorner(v))) { + for (v = 0; (v < 8) && ((numContained == v) || (numContained == 0)); ++v) { + if (plane[p].halfSpaceContains(_corner[v])) { ++numContained; } - } + } - if (numContained == 0) { - // Plane p culled the box - cullingPlane = p; + if (numContained == 0) { + // Plane p culled the box + cullingPlane = p; // The caller should not recurse into the children, // since the parent is culled. If they do recurse, // make them only test against this one plane, which // will immediately cull the volume. childMask = 1 << p; - return true; + return true; } else if (numContained < v) { // The bounding volume straddled the plane; we have // to keep testing against this plane childMask |= (1 << p); } - } + } // Move on to the next bit. - inMask = inMask >> 1; + inMask = inMask >> 1; } // None of the planes could cull this box - cullingPlane = -1; + cullingPlane = -1; return false; } + bool Box::culledBy( - const class Plane* plane, - int numPlanes, - int& cullingPlane, - const uint32 _inMask) const { + const Array<Plane>& plane, + int& cullingPlane, + const uint32 _inMask) const { - uint32 inMask = _inMask; - assert(numPlanes < 31); + uint32 inMask = _inMask; + assert(plane.size() < 31); // See if there is one plane for which all of the - // vertices are in the negative half space. - for (int p = 0; p < numPlanes; p++) { + // vertices are in the negative half space. + for (int p = 0; p < plane.size(); ++p) { - // Only test planes that are not masked - if ((inMask & 1) != 0) { - - bool culled = true; + // Only test planes that are not masked + if ((inMask & 1) != 0) { + + bool culled = true; int v; - // Assume this plane culls all points. See if there is a point - // not culled by the plane... early out when at least one point + // Assume this plane culls all points. See if there is a point + // not culled by the plane... early out when at least one point // is in the positive half space. - for (v = 0; (v < 8) && culled; ++v) { - culled = ! plane[p].halfSpaceContains(getCorner(v)); - } + for (v = 0; (v < 8) && culled; ++v) { + culled = ! plane[p].halfSpaceContains(corner(v)); + } - if (culled) { - // Plane p culled the box - cullingPlane = p; + if (culled) { + // Plane p culled the box + cullingPlane = p; - return true; + return true; } - } + } // Move on to the next bit. - inMask = inMask >> 1; + inMask = inMask >> 1; } // None of the planes could cull this box - cullingPlane = -1; + cullingPlane = -1; return false; } + bool Box::contains( const Vector3& point) const { @@ -264,7 +319,7 @@ bool Box::contains( Vector3 osPoint = M.inverse() * (point - _corner[0]); return - (osPoint.x >= 0) && + (osPoint.x >= 0) && (osPoint.y >= 0) && (osPoint.z >= 0) && (osPoint.x <= 1) && @@ -274,47 +329,51 @@ bool Box::contains( #undef setMany -#if 0 + void Box::getRandomSurfacePoint(Vector3& P, Vector3& N) const { float aXY = _extent.x * _extent.y; float aYZ = _extent.y * _extent.z; float aZX = _extent.z * _extent.x; - float r = (float)random(0, aXY + aYZ + aZX); + float r = (float)uniformRandom(0, aXY + aYZ + aZX); // Choose evenly between positive and negative face planes - float d = (random(0, 1) < 0.5f) ? -1.0f : 1.0f; + float d = (uniformRandom(0, 1) < 0.5f) ? -1.0f : 1.0f; // The probability of choosing a given face is proportional to // its area. if (r < aXY) { - P = _axis[0] * (float)random(-0.5, 0.5) * _extent.x + - _axis[1] * (float)random(-0.5, 0.5) * _extent.y + + P = _axis[0] * (float)uniformRandom(-0.5, 0.5) * _extent.x + + _axis[1] * (float)uniformRandom(-0.5, 0.5) * _extent.y + _center + _axis[2] * d * _extent.z * 0.5f; N = _axis[2] * d; } else if (r < aYZ) { - P = _axis[1] * (float)random(-0.5, 0.5) * _extent.y + - _axis[2] * (float)random(-0.5, 0.5) * _extent.z + + P = _axis[1] * (float)uniformRandom(-0.5, 0.5) * _extent.y + + _axis[2] * (float)uniformRandom(-0.5, 0.5) * _extent.z + _center + _axis[0] * d * _extent.x * 0.5f; N = _axis[0] * d; } else { - P = _axis[2] * (float)random(-0.5, 0.5) * _extent.z + - _axis[0] *(float) random(-0.5, 0.5) * _extent.x + + P = _axis[2] * (float)uniformRandom(-0.5, 0.5) * _extent.z + + _axis[0] *(float) uniformRandom(-0.5, 0.5) * _extent.x + _center + _axis[1] * d * _extent.y * 0.5f; N = _axis[1] * d; } } + Vector3 Box::randomInteriorPoint() const { Vector3 sum = _center; for (int a = 0; a < 3; ++a) { - sum += _axis[a] * (float)random(-0.5, 0.5) * _extent[a]; + sum += _axis[a] * (float)uniformRandom(-0.5, 0.5) * _extent[a]; } return sum; } -#endif + +Box Box::inf() { + return Box(-Vector3::inf(), Vector3::inf()); +} void Box::getBounds(class AABox& aabb) const { @@ -330,5 +389,5 @@ void Box::getBounds(class AABox& aabb) const { aabb = AABox(lo, hi); } -} // namespace +} // namespace |