genesis-3d_engine/Engine/foundation/math/bbox.h
zhongdaohuan 6e8fbca745 genesis-3d engine version 1.3.
match the genesis editor version 1.3.0.653.
2014-05-05 14:50:33 +08:00

387 lines
11 KiB
Objective-C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/****************************************************************************
Copyright (c) 2004, Radon Labs GmbH
Copyright (c) 2011-2013,WebJet Business Division,CYOU
http://www.genesis-3d.com.cn
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#ifndef MATH_BBOX_H
#define MATH_BBOX_H
//------------------------------------------------------------------------------
/**
@class Math::bbox
Nebula's bounding box class.
@todo: UNTESTED!
*/
#include "math/point.h"
#include "math/vector.h"
#include "math/matrix44.h"
#include "math/line.h"
#include "math/plane.h"
#include "math/clipstatus.h"
#include "util/array.h"
//------------------------------------------------------------------------------
namespace Math
{
class bbox
{
public:
/// clip codes
enum
{
ClipLeft = (1<<0),
ClipRight = (1<<1),
ClipBottom = (1<<2),
ClipTop = (1<<3),
ClipNear = (1<<4),
ClipFar = (1<<5),
};
/// constructor 1
bbox();
/// constructor 3
explicit bbox(const point& center, const vector& extents);
/// constructor 3
explicit bbox(const point& min, const point& max);
/// construct bounding box from matrix44
bbox(const matrix44& m);
/// equality operator
bool operator==(const bbox& rhs) const;
/// inequality operator
bool operator!=(const bbox& rhs) const;
/// get center of box
point center() const;
/// get extents of box
vector extents() const;
/// get size of box
vector size() const;
/// get diagonal size of box
scalar diagonal_size() const;
/// set from matrix44
void set(const matrix44& m);
/// set from center point and extents
void set(const point& center, const vector& extents);
/// set pmin and pmax
void set(const point& min, const point& max);
/// begin extending the box
void begin_extend();
/// extend the box
void extend(const point& p);
/// extend the box
void extend(const bbox& box);
/// this resets the bounding box size to zero if no extend() method was called after begin_extend()
void end_extend();
/// transform bounding box
void transform(const matrix44& m);
/// check for intersection with axis aligned bounding box
bool intersects(const bbox& box) const;
/// check if this box completely contains the parameter box
bool contains(const bbox& box) const;
/// return true if this box contains the position
bool contains(const point& p) const;
/// check for intersection with other bounding box
ClipStatus::Type clipstatus(const bbox& other) const;
/// check for intersection with projection volume
ClipStatus::Type clipstatus(const matrix44& viewProjection) const;
/// create a matrix which transforms a unit cube to this bounding box
matrix44 to_matrix44() const;
/// return one of the 8 corner points
point corner_point(int index) const;
/// return side planes in clip space
void get_clipplanes(const matrix44& viewProjection, Util::Array<plane>& outPlanes) const;
/// <20><EFBFBD>е<EFBFBD><D0B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƽ<EFBFBD><C6BD>
scalar distancesq(const Math::vector &p) const;
/// convert to any type
template<typename T> T as() const;
static const bbox Zero;
point pmin;
point pmax;
};
//------------------------------------------------------------------------------
/**
*/
inline
bbox::bbox() :
pmin(-0.5f, -0.5f, -0.5f),
pmax(+0.5f, +0.5f, +0.5f)
{
// empty
}
//------------------------------------------------------------------------------
/**
*/
inline
bbox::bbox(const point& center, const vector& extents)
{
this->pmin = center - extents;
this->pmax = center + extents;
}
//------------------------------------------------------------------------------
/**
*/
inline
bbox::bbox(const point& min, const point& max)
{
this->pmin = min;
this->pmax = max;
}
//------------------------------------------------------------------------
/// equality operator
inline bool
bbox::operator==(const bbox& rhs) const
{
return (this->pmin == rhs.pmin) && (this->pmax == rhs.pmax);
}
/// inequality operator
inline bool
bbox::operator!=(const bbox& rhs) const
{
return (this->pmin != rhs.pmin) || (this->pmax != rhs.pmax);
}
//------------------------------------------------------------------------------
/**
Construct a bounding box around a 4x4 matrix. The translational part
defines the center point, and the x,y,z vectors of the matrix
define the extents.
*/
inline void
bbox::set(const matrix44& m)
{
// get extents
vector extents = ( m.get_xaxis().abs() + m.get_yaxis().abs() + m.get_zaxis().abs() ) * 0.5f;
point center = m.get_position();
this->pmin = center - extents;
this->pmax = center + extents;
}
//------------------------------------------------------------------------------
/**
*/
inline void
bbox::set(const point& min, const point& max)
{
this->pmin = min;
this->pmax = max;
}
//------------------------------------------------------------------------------
/**
*/
inline
bbox::bbox(const matrix44& m)
{
this->set(m);
}
//------------------------------------------------------------------------------
/**
*/
inline point
bbox::center() const
{
return this->pmin + ((this->pmax - this->pmin) * 0.5f);
}
//------------------------------------------------------------------------------
/**
*/
inline vector
bbox::extents() const
{
return (this->pmax - this->pmin) * 0.5f;
}
//------------------------------------------------------------------------------
/**
*/
inline vector
bbox::size() const
{
return this->pmax - this->pmin;
}
//------------------------------------------------------------------------------
/**
*/
inline void
bbox::set(const point& center, const vector& extents)
{
this->pmin = center - extents;
this->pmax = center + extents;
}
//------------------------------------------------------------------------------
/**
*/
inline void
bbox::begin_extend()
{
this->pmin.set(N_FLOAT32_MAX, N_FLOAT32_MAX, N_FLOAT32_MAX);
this->pmax.set(N_FLOAT32_MIN, N_FLOAT32_MIN, N_FLOAT32_MIN);
}
//------------------------------------------------------------------------------
/**
This just checks whether the extend() method has actually been called after
begin_extend() and just sets vmin and vmax to the null vector if it hasn't.
*/
inline
void
bbox::end_extend()
{
if ((this->pmin == point(N_FLOAT32_MAX, N_FLOAT32_MAX, N_FLOAT32_MAX)) &&
(this->pmax == point(N_FLOAT32_MIN, N_FLOAT32_MIN, N_FLOAT32_MIN)))
{
this->pmin.set(0.0f, 0.0f, 0.0f);
this->pmax.set(0.0f, 0.0f, 0.0f);
}
}
//------------------------------------------------------------------------------
/**
*/
inline void
bbox::extend(const point& p)
{
this->pmin = float4::minimize(this->pmin, p);
this->pmax = float4::maximize(this->pmax, p);
}
//------------------------------------------------------------------------------
/**
*/
inline
void
bbox::extend(const bbox& box)
{
this->pmin = float4::minimize(this->pmin, box.pmin);
this->pmax = float4::maximize(this->pmax, box.pmax);
}
//------------------------------------------------------------------------------
/**
Transforms this axis aligned bounding by the 4x4 matrix. This bounding
box must be axis aligned with the matrix, the resulting bounding
will be axis aligned in the matrix' "destination" space.
E.g. if you have a bounding box in model space 'modelBox', and a
'modelView' matrix, the operation
modelBox.transform(modelView)
would transform the bounding box into view space.
*/
inline void
bbox::transform(const matrix44& m)
{
Math::point temp;
Math::point minP(1000000, 1000000,1000000);
Math::point maxP(-1000000, -1000000, -1000000);
IndexT i;
for(i = 0; i < 8; ++i)
{
// Transform and check extents
temp = Math::matrix44::transform( m, corner_point(i));
if (temp.x() > maxP.x()) maxP.x() = temp.x();
if (temp.y() > maxP.y()) maxP.y() = temp.y();
if (temp.z() > maxP.z()) maxP.z() = temp.z();
if (temp.x() < minP.x()) minP.x() = temp.x();
if (temp.y() < minP.y()) minP.y() = temp.y();
if (temp.z() < minP.z()) minP.z() = temp.z();
}
this->pmin = minP;
this->pmax = maxP;
}
//------------------------------------------------------------------------------
/**
Check for intersection of 2 axis aligned bounding boxes. The
bounding boxes must live in the same coordinate space.
*/
inline bool
bbox::intersects(const bbox& box) const
{
bool lt = float4::less3_any(this->pmax, box.pmin);
bool gt = float4::greater3_any(this->pmin, box.pmax);
return !(lt || gt);
}
//------------------------------------------------------------------------------
/**
Check if the parameter bounding box is completely contained in this
bounding box.
*/
inline bool
bbox::contains(const bbox& box) const
{
bool lt = float4::less3_all(this->pmin, box.pmin);
bool ge = float4::greaterequal3_all(this->pmax, box.pmax);
return lt && ge;
}
//------------------------------------------------------------------------------
/**
Check if position is inside bounding box.
*/
inline bool
bbox::contains(const point& p) const
{
bool lt = float4::less3_all(this->pmin, p);
bool ge = float4::greaterequal3_all(this->pmax, p);
return lt && ge;
}
//------------------------------------------------------------------------------
/**
Create a transform matrix which would transform a unit cube to this
bounding box.
*/
inline matrix44
bbox::to_matrix44() const
{
matrix44 m = matrix44::scaling(this->size() * 0.5f);
float4 pos = this->center();
m.setrow3(pos);
return m;
}
//------------------------------------------------------------------------------
/**
*/
inline scalar
bbox::diagonal_size() const
{
return (this->pmax - this->pmin).length();
}
} // namespace Math
//------------------------------------------------------------------------------
#endif