#include "StdAfx.h" #include "Box.h" /// Collide a line against the box. /// /// Returns true on collision. bool CBox::CollideLine(const NiPoint3& start, const NiPoint3& end) const { float st,et; float fst = 0.f; float fet = 1.f; const float* bmin = &m_kMin.x; const float* bmax = &m_kMax.x; const float* si = &start.x; const float* ei = &end.x; for(int i = 0; i < 3; i++) { if(si[i] < ei[i]) { if (si[i] > bmax[i] || ei[i] < bmin[i]) return false; float di = ei[i] - si[i]; st = (si[i] < bmin[i]) ? (bmin[i] - si[i]) / di : 0.f; et = (ei[i] > bmax[i]) ? (bmax[i] - si[i]) / di : 1.f; } else { if (ei[i] > bmax[i] || si[i] < bmin[i]) return false; float di = ei[i] - si[i]; st = (si[i] > bmax[i]) ? (bmax[i] - si[i]) / di : 0.f; et = (ei[i] < bmin[i]) ? (bmin[i] - si[i]) / di : 1.f; } if (st > fst) { fst = st; } if (et < fet) fet = et; if (fet < fst) return false; } return true; } bool CBox::CollideBox(const NiPoint3& start, const NiPoint3& end, const NiPoint3& extent) const { float st,et; float fst = 0; float fet = 1; NiPoint3 newmin( m_kMin.x - extent.x, m_kMin.y - extent.y, m_kMin.z - extent.z ); NiPoint3 newmax( m_kMax.x + extent.x, m_kMax.y + extent.y, m_kMax.z + extent.z ); const float* bmin = &newmin.x; const float* bmax = &newmax.x; const float* si = &start.x; const float* ei = &end.x; for (int i = 0; i < 3; i++) { if (si[i] < ei[i]) { if (si[i] > bmax[i] || ei[i] < bmin[i]) return false; float di = ei[i] - si[i]; st = (si[i] < bmin[i]) ? (bmin[i] - si[i]) / di : 0; et = (ei[i] > bmax[i]) ? (bmax[i] - si[i]) / di : 1; } else { if (ei[i] > bmax[i] || si[i] < bmin[i]) return false; float di = ei[i] - si[i]; st = (si[i] > bmax[i]) ? (bmax[i] - si[i]) / di : 0; et = (ei[i] < bmin[i]) ? (bmin[i] - si[i]) / di : 1; } if (st > fst) { fst = st; } if (et < fet) fet = et; if (fet < fst) return false; } return true; } bool CBox::IsOverlapped(const CBox& box) const { if (box.m_kMin.x > m_kMax.x || box.m_kMin.y > m_kMax.y || box.m_kMin.z > m_kMax.z) return false; if (box.m_kMax.x < m_kMin.x || box.m_kMax.y < m_kMin.y || box.m_kMax.z < m_kMin.z) return false; return true; } bool CBox::IsContained(const NiPoint3& pos) const { if (pos.x > m_kMin.x && pos.y > m_kMin.y && pos.z > m_kMin.z && pos.x < m_kMax.x && pos.y < m_kMax.y && pos.z < m_kMax.z) return true; return false; } __forceinline float CalcPlaneDistance( const NiPoint3& Normal, float Constant, float x, float y, float z ) { return x * Normal.x + y * Normal.y + z * Normal.z - Constant; } int CBox::WhichSide(const NiPlane& kPlane) const { //NiPoint3 kPoint; unsigned int uiNegativeSide = 0; unsigned int uiPositiveSide = 0; if( CalcPlaneDistance( kPlane.m_kNormal, kPlane.m_fConstant, m_kMin.x, m_kMin.y, m_kMin.z ) >= 0 ) ++uiPositiveSide; else ++uiNegativeSide; if( CalcPlaneDistance( kPlane.m_kNormal, kPlane.m_fConstant, m_kMax.x, m_kMax.y, m_kMax.z ) >= 0 ) ++uiPositiveSide; else ++uiNegativeSide; if( uiPositiveSide && uiNegativeSide ) return NiPlane::NO_SIDE; if( CalcPlaneDistance( kPlane.m_kNormal, kPlane.m_fConstant, m_kMin.x, m_kMin.y, m_kMax.z ) >= 0 ) ++uiPositiveSide; else ++uiNegativeSide; if( CalcPlaneDistance( kPlane.m_kNormal, kPlane.m_fConstant, m_kMax.x, m_kMax.y, m_kMin.z ) >= 0 ) ++uiPositiveSide; else ++uiNegativeSide; if( uiPositiveSide && uiNegativeSide ) return NiPlane::NO_SIDE; if( CalcPlaneDistance( kPlane.m_kNormal, kPlane.m_fConstant, m_kMax.x, m_kMin.y, m_kMin.z ) >= 0 ) ++uiPositiveSide; else ++uiNegativeSide; if( CalcPlaneDistance( kPlane.m_kNormal, kPlane.m_fConstant, m_kMin.x, m_kMax.y, m_kMax.z ) >= 0 ) ++uiPositiveSide; else ++uiNegativeSide; if( uiPositiveSide && uiNegativeSide ) return NiPlane::NO_SIDE; if( CalcPlaneDistance( kPlane.m_kNormal, kPlane.m_fConstant, m_kMax.x, m_kMin.y, m_kMax.z ) >= 0 ) ++uiPositiveSide; else ++uiNegativeSide; if( CalcPlaneDistance( kPlane.m_kNormal, kPlane.m_fConstant, m_kMin.x, m_kMax.y, m_kMin.z ) >= 0 ) ++uiPositiveSide; else ++uiNegativeSide; if( uiPositiveSide && uiNegativeSide ) return NiPlane::NO_SIDE; if( uiPositiveSide ) return NiPlane::POSITIVE_SIDE; else return NiPlane::NEGATIVE_SIDE; } bool CBox::TestVisible(const NiFrustumPlanes& kPlanes) { unsigned int i; for (i = 0; i < NiFrustumPlanes::MAX_PLANES; i++) { int iSide = WhichSide(kPlanes.GetPlane(i)); if (iSide == NiPlane::NEGATIVE_SIDE) { // The object is not visible since it is on the negative // side of the plane. break; } } if(i == NiFrustumPlanes::MAX_PLANES) return true; return false; }