#include "Framework.h"
using namespace fw;
AABB::AABB() :
m_minEdge(-1.0f, -1.0f, -1.0f),
m_maxEdge(1.0f, 1.0f, 1.0f)
{
}
AABB::AABB(const D3DXVECTOR3& min, const D3DXVECTOR3& max) :
m_minEdge(min),
m_maxEdge(max)
{
}
AABB::~AABB()
{
}
D3DXVECTOR3 AABB::GetCenter()
{
return (m_minEdge + m_maxEdge) / 2;
}
void AABB::AddInternalPoint(const D3DXVECTOR3& p)
{
AddInternalPoint(p.x, p.y, p.z);
}
void AABB::AddInternalPoint(float x, float y, float z)
{
if (x > m_maxEdge.x) m_maxEdge.x = x;
if (y > m_maxEdge.y) m_maxEdge.y = y;
if (z > m_maxEdge.z) m_maxEdge.z = z;
if (x < m_minEdge.x) m_minEdge.x = x;
if (y < m_minEdge.y) m_minEdge.y = y;
if (z < m_minEdge.z) m_minEdge.z = z;
}
void AABB::Reset(float x, float y, float z)
{
m_maxEdge = D3DXVECTOR3(x, y, z);
m_minEdge = m_maxEdge;
}
void AABB::Reset(const D3DXVECTOR3& initValue)
{
m_maxEdge = initValue;
m_minEdge = initValue;
}
void AABB::GetEdges(std::vector<D3DXVECTOR3>& edges)
{
const D3DXVECTOR3 middle = GetCenter();
const D3DXVECTOR3 diag = middle - m_maxEdge;
/*
Edges are stored in this way:
/3--------/7
/ | / |
/ | / |
1---------5 |
| /2- - -|- -6
| / | /
|/ | /
0---------4/
*/
edges.clear();
edges.push_back(D3DXVECTOR3(middle.x + diag.x, middle.y + diag.y, middle.z + diag.z));
edges.push_back(D3DXVECTOR3(middle.x + diag.x, middle.y - diag.y, middle.z + diag.z));
edges.push_back(D3DXVECTOR3(middle.x + diag.x, middle.y + diag.y, middle.z - diag.z));
edges.push_back(D3DXVECTOR3(middle.x + diag.x, middle.y - diag.y, middle.z - diag.z));
edges.push_back(D3DXVECTOR3(middle.x - diag.x, middle.y + diag.y, middle.z + diag.z));
edges.push_back(D3DXVECTOR3(middle.x - diag.x, middle.y - diag.y, middle.z + diag.z));
edges.push_back(D3DXVECTOR3(middle.x - diag.x, middle.y + diag.y, middle.z - diag.z));
edges.push_back(D3DXVECTOR3(middle.x - diag.x, middle.y - diag.y, middle.z - diag.z));
}
D3DXVECTOR3 AABB::GetExtent() const
{
return m_maxEdge - m_minEdge;
}
float AABB::GetVolume()
{
D3DXVECTOR3 e = GetExtent();
return e.x * e.y * e.z;
}
const D3DXVECTOR3& AABB::GetMin() const
{
return m_minEdge;
}
const D3DXVECTOR3& AABB::GetMax() const
{
return m_maxEdge;
}
void AABB::Translate(const D3DXVECTOR3& translate)
{
D3DXMATRIX transform;
D3DXMatrixTranslation(&transform, translate.x, translate.y, translate.z);
Transform(transform);
Repair();
}
void AABB::Scale(const D3DXVECTOR3& scale)
{
D3DXMATRIX transform;
D3DXMatrixScaling(&transform, scale.x, scale.y, scale.z);
Transform(transform);
Repair();
}
/* Utilise l'algortihme d'intersection Slab */
bool AABB::Intersects(const Ray& r)
{
double t1 = (m_minEdge.x - r.x0.x) * r.n_inv.x;
double t2 = (m_maxEdge.x - r.x0.x) * r.n_inv.x;
double tmin = min(t1, t2);
double tmax = max(t1, t2);
t1 = (m_minEdge.y - r.x0.y) * r.n_inv.y;
t2 = (m_maxEdge.y - r.x0.y) * r.n_inv.y;
tmin = max(tmin, min(t1, t2));
tmax = min(tmax, max(t1, t2));
t1 = (m_minEdge.z - r.x0.z) * r.n_inv.z;
t2 = (m_maxEdge.z - r.x0.z) * r.n_inv.z;
tmin = max(tmin, min(t1, t2));
tmax = min(tmax, max(t1, t2));
return tmax > max(tmin, 0.0);
}
void AABB::Repair()
{
float t;
if (m_minEdge.x > m_maxEdge.x)
{
t = m_minEdge.x; m_minEdge.x = m_maxEdge.x; m_maxEdge.x = t;
}
if (m_minEdge.y > m_maxEdge.y)
{
t = m_minEdge.y; m_minEdge.y = m_maxEdge.y; m_maxEdge.y = t;
}
if (m_minEdge.z > m_maxEdge.z)
{
t = m_minEdge.z; m_minEdge.z = m_maxEdge.z; m_maxEdge.z = t;
}
}
void AABB::Transform(const D3DXMATRIX& mat)
{
D3DXVECTOR3 oldMin, oldMax, currentCorner;
// Getting the old values so that we can use the existing merge method.
oldMin = m_minEdge;
oldMax = m_maxEdge;
// reset
Reset(0.0f, 0.0f, 0.0f);
// We sequentially compute the corners in the following order :
// 0, 6, 5, 1, 2, 4 ,7 , 3
// This sequence allows us to only change one member at a time to get at all corners.
// For each one, we transform it using the matrix
// Which gives the resulting point and AddInternalPoint the resulting point.
// First corner
// min min min
currentCorner = oldMin;
D3DXVECTOR3 tmpVec;
D3DXVec3TransformCoord(&tmpVec, ¤tCorner, &mat);
AddInternalPoint(tmpVec);
// min,min,max
currentCorner.z = oldMax.z;
D3DXVec3TransformCoord(&tmpVec, ¤tCorner, &mat);
AddInternalPoint(tmpVec);
// min max max
currentCorner.y = oldMax.y;
D3DXVec3TransformCoord(&tmpVec, ¤tCorner, &mat);
AddInternalPoint(tmpVec);
// min max min
currentCorner.z = oldMin.z;
D3DXVec3TransformCoord(&tmpVec, ¤tCorner, &mat);
AddInternalPoint(tmpVec);
// max max min
currentCorner.x = oldMax.x;
D3DXVec3TransformCoord(&tmpVec, ¤tCorner, &mat);
AddInternalPoint(tmpVec);
// max max max
currentCorner.z = oldMax.z;
D3DXVec3TransformCoord(&tmpVec, ¤tCorner, &mat);
AddInternalPoint(tmpVec);
// max min max
currentCorner.y = oldMin.y;
D3DXVec3TransformCoord(&tmpVec, ¤tCorner, &mat);
AddInternalPoint(tmpVec);
// max min min
currentCorner.z = oldMin.z;
D3DXVec3TransformCoord(&tmpVec, ¤tCorner, &mat);
AddInternalPoint(tmpVec);
}
bool AABB::Contains(const AABB& other)
{
return m_minEdge.x <= other.m_minEdge.x &&
m_minEdge.y <= other.m_minEdge.y &&
m_minEdge.z <= other.m_minEdge.z &&
other.m_maxEdge.x <= m_maxEdge.x &&
other.m_maxEdge.y <= m_maxEdge.y &&
other.m_maxEdge.z <= m_maxEdge.z;
}