234 lines
7.7 KiB
C++
234 lines
7.7 KiB
C++
|
/////////////////////////////////////////////////////////////////////
|
||
|
// Created by Dan Andersson 2013
|
||
|
/////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#include "Frustrum.h"
|
||
|
#include "Collision.h"
|
||
|
|
||
|
using namespace Oyster::Math;
|
||
|
using namespace Oyster::Collision;
|
||
|
|
||
|
namespace PrivateStatic
|
||
|
{
|
||
|
inline void vpToPlanes( Plane &lp, Plane &rp, Plane &bp, Plane &tp, Plane &np, Plane &fp, const Float4x4 &vp )
|
||
|
{
|
||
|
Float4x4 m = vp.getTranspose();
|
||
|
|
||
|
// left
|
||
|
lp.normal = m.v[3].xyz + m.v[0].xyz;
|
||
|
lp.phasing = lp.normal.length();
|
||
|
lp.normal /= lp.phasing;
|
||
|
lp.phasing = (m.v[3].w + m.v[0].w) / lp.phasing;
|
||
|
|
||
|
// right
|
||
|
rp.normal = m.v[3].xyz - m.v[0].xyz;
|
||
|
rp.phasing = rp.normal.length();
|
||
|
rp.normal /= rp.phasing;
|
||
|
rp.phasing = (m.v[3].w - m.v[0].w) / rp.phasing;
|
||
|
|
||
|
// bottom
|
||
|
bp.normal = m.v[3].xyz + m.v[1].xyz;
|
||
|
bp.phasing = bp.normal.length();
|
||
|
bp.normal /= bp.phasing;
|
||
|
bp.phasing = (m.v[3].w + m.v[1].w) / bp.phasing;
|
||
|
|
||
|
// top
|
||
|
tp.normal = m.v[3].xyz - m.v[1].xyz;
|
||
|
tp.phasing = tp.normal.length();
|
||
|
tp.normal /= tp.phasing;
|
||
|
tp.phasing = (m.v[3].w - m.v[1].w) / tp.phasing;
|
||
|
|
||
|
// near leftHanded DirectX
|
||
|
np.normal = m.v[2].xyz;
|
||
|
np.phasing = np.normal.length();
|
||
|
np.normal /= np.phasing;
|
||
|
np.phasing = m.v[2].w / np.phasing;
|
||
|
|
||
|
// far lefthanded
|
||
|
fp.normal = m.v[3].xyz - m.v[2].xyz;
|
||
|
fp.phasing = fp.normal.length();
|
||
|
fp.normal /= fp.phasing;
|
||
|
fp.phasing = (m.v[3].w - m.v[2].w) / fp.phasing;
|
||
|
|
||
|
/*/ near rightHanded openGL
|
||
|
np.normal = m.v[3].xyz + m.v[2].xyz;
|
||
|
np.phasing = np.normal.length();
|
||
|
np.normal /= np.phasing;
|
||
|
np.phasing = -(m.v[3].w + m.v[2].w) / np.phasing;
|
||
|
|
||
|
// far rightHanded
|
||
|
fp.normal = m.v[3].xyz - m.v[2].xyz;
|
||
|
fp.phasing = fp.normal.length();
|
||
|
fp.normal /= fp.phasing;
|
||
|
fp.phasing = -(m.v[3].w - m.v[2].w) / fp.phasing;*/
|
||
|
}
|
||
|
|
||
|
void interpolatePlanes( Plane &target, const Plane &planeA, const Plane &planeB, float interpolation )
|
||
|
{
|
||
|
float counterInterpol = 1.0f - interpolation;
|
||
|
target.normal = counterInterpol * planeA.normal;
|
||
|
target.normal += interpolation * planeB.normal;
|
||
|
target.phasing = counterInterpol * planeA.phasing;
|
||
|
target.phasing += interpolation * planeB.phasing;
|
||
|
target.normal.normalize();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Frustrum::Frustrum( ) : ICollideable(ICollideable::Frustrum),
|
||
|
leftPlane(Float3::standardUnitX, -0.5f), rightPlane(-Float3::standardUnitX, 0.5f),
|
||
|
bottomPlane(Float3::standardUnitY, -0.5f), topPlane(-Float3::standardUnitY, 0.5f),
|
||
|
nearPlane(Float3::standardUnitZ, -0.5f), farPlane(-Float3::standardUnitZ, 0.5f) {}
|
||
|
|
||
|
Frustrum::Frustrum( const Frustrum &frustrum ) : ICollideable(ICollideable::Frustrum),
|
||
|
leftPlane(frustrum.leftPlane), rightPlane(frustrum.rightPlane),
|
||
|
bottomPlane(frustrum.bottomPlane), topPlane(frustrum.topPlane),
|
||
|
nearPlane(frustrum.nearPlane), farPlane(frustrum.farPlane) {}
|
||
|
|
||
|
Frustrum::Frustrum( const Float4x4 &vp ) : ICollideable(ICollideable::Frustrum)
|
||
|
{ PrivateStatic::vpToPlanes( this->leftPlane, this->rightPlane, this->bottomPlane, this->topPlane, this->nearPlane, this->farPlane, vp ); }
|
||
|
|
||
|
Frustrum::~Frustrum( ) {}
|
||
|
|
||
|
Frustrum & Frustrum::operator = ( const Frustrum &frustrum )
|
||
|
{
|
||
|
this->leftPlane = frustrum.leftPlane;
|
||
|
this->rightPlane = frustrum.rightPlane;
|
||
|
this->bottomPlane = frustrum.bottomPlane;
|
||
|
this->topPlane = frustrum.topPlane;
|
||
|
this->nearPlane = frustrum.nearPlane;
|
||
|
this->farPlane = frustrum.farPlane;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
Frustrum & Frustrum::operator = ( const Float4x4 &vp )
|
||
|
{
|
||
|
PrivateStatic::vpToPlanes( this->leftPlane, this->rightPlane, this->bottomPlane, this->topPlane, this->nearPlane, this->farPlane, vp );
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
void Frustrum::split( Frustrum target[], unsigned int numX, unsigned int numY, unsigned int numZ ) const
|
||
|
{
|
||
|
float incrementX = 1.0f / numX,
|
||
|
incrementY = 1.0f / numY,
|
||
|
incrementZ = 1.0f / numZ,
|
||
|
interpolX = 0.0f,
|
||
|
interpolY = 0.0f,
|
||
|
interpolZ = 0.0f;
|
||
|
|
||
|
unsigned int i = 0U,
|
||
|
stepY = numX,
|
||
|
stepZ = numX * numY;
|
||
|
|
||
|
Collision::Plane invRight( -this->rightPlane.normal, -this->rightPlane.phasing ),
|
||
|
invBottom( -this->bottomPlane.normal, -this->bottomPlane.phasing ),
|
||
|
invFar( -this->farPlane.normal, -this->farPlane.phasing );
|
||
|
|
||
|
for( unsigned int iz = 0U; iz < numZ; ++iz )
|
||
|
{
|
||
|
interpolY = 0.0f;
|
||
|
for( unsigned int iy = 0U; iy < numY; ++iy )
|
||
|
{
|
||
|
interpolX = 0.0f;
|
||
|
for( unsigned int ix = 0U; ix < numX; ++ix )
|
||
|
{
|
||
|
if( ix == 0 )
|
||
|
target[i].leftPlane = this->leftPlane;
|
||
|
else
|
||
|
{
|
||
|
PrivateStatic::interpolatePlanes( target[i].leftPlane, this->leftPlane, invRight, interpolX );
|
||
|
|
||
|
unsigned int iLeft = i - 1;
|
||
|
target[iLeft].rightPlane.normal = -target[i].leftPlane.normal;
|
||
|
target[iLeft].rightPlane.phasing = -target[i].leftPlane.phasing;
|
||
|
}
|
||
|
if( ix == numX - 1 )
|
||
|
target[i].rightPlane = this->rightPlane;
|
||
|
|
||
|
if( iy == 0 )
|
||
|
target[i].topPlane = this->topPlane;
|
||
|
else
|
||
|
{
|
||
|
PrivateStatic::interpolatePlanes( target[i].topPlane, this->topPlane, invBottom, interpolY );
|
||
|
|
||
|
unsigned int iAbove = i - stepY;
|
||
|
target[iAbove].bottomPlane.normal = -target[i].topPlane.normal;
|
||
|
target[iAbove].bottomPlane.phasing = -target[i].topPlane.phasing;
|
||
|
}
|
||
|
if( iy == numY - 1 )
|
||
|
target[i].bottomPlane = this->bottomPlane;
|
||
|
|
||
|
if( iz == 0 )
|
||
|
target[i].nearPlane = this->nearPlane;
|
||
|
else
|
||
|
{
|
||
|
PrivateStatic::interpolatePlanes( target[i].nearPlane, this->nearPlane, invFar, interpolZ );
|
||
|
|
||
|
unsigned int iCloser = i - stepZ;
|
||
|
target[iCloser].farPlane.normal = -target[i].nearPlane.normal;
|
||
|
target[iCloser].farPlane.phasing = -target[i].nearPlane.phasing;
|
||
|
}
|
||
|
if( iz == numZ - 1 )
|
||
|
target[i].farPlane = this->farPlane;
|
||
|
|
||
|
++i;
|
||
|
interpolX += incrementX;
|
||
|
}
|
||
|
interpolY += incrementY;
|
||
|
}
|
||
|
interpolZ += incrementZ;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Frustrum::writeToByte( unsigned char targetMem[], unsigned int &nextIndex ) const
|
||
|
{
|
||
|
Float *fMem = (Float*)&targetMem[nextIndex];
|
||
|
for( int p = 0; p < 6; ++p )
|
||
|
{
|
||
|
fMem[0] = this->plane[p].element[0];
|
||
|
fMem[1] = this->plane[p].element[1];
|
||
|
fMem[2] = this->plane[p].element[2];
|
||
|
fMem[3] = this->plane[p].element[3];
|
||
|
fMem = &fMem[4];
|
||
|
}
|
||
|
nextIndex += 6 * ::Utility::StaticArray::numElementsOf( this->plane[0].byte );
|
||
|
}
|
||
|
|
||
|
ICollideable* Frustrum::clone( ) const
|
||
|
{ return new Frustrum(*this); }
|
||
|
|
||
|
bool Frustrum::Intersects( const ICollideable *target ) const
|
||
|
{
|
||
|
switch( target->type )
|
||
|
{
|
||
|
case ICollideable::Point: return Utility::intersect( *this, *(Collision::Point*)target );
|
||
|
case ICollideable::Ray: return Utility::intersect( *this, *(Collision::Ray*)target, ((Collision::Ray*)target)->collisionDistance );
|
||
|
case ICollideable::Sphere: return Utility::intersect( *this, *(Collision::Sphere*)target );
|
||
|
case ICollideable::Plane: return Utility::intersect( *this, *(Collision::Plane*)target );
|
||
|
case ICollideable::Triangle: return false; // TODO
|
||
|
case ICollideable::BoxAxisAligned: return Utility::intersect( *this, *(Collision::BoxAxisAligned*)target );
|
||
|
case ICollideable::Box: return Utility::intersect( *this, *(Collision::Box*)target );
|
||
|
case ICollideable::Frustrum: return Utility::intersect( *this, *(Collision::Frustrum*)target );
|
||
|
case ICollideable::Line: return false; // TODO
|
||
|
default: return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool Frustrum::Contains( const ICollideable *target ) const
|
||
|
{
|
||
|
switch( target->type )
|
||
|
{
|
||
|
case ICollideable::Point: return Utility::intersect( *this, *(Collision::Point*)target );
|
||
|
case ICollideable::Ray: return false; // TODO
|
||
|
case ICollideable::Sphere: return false; // TODO
|
||
|
case ICollideable::Plane: return false; // TODO
|
||
|
case ICollideable::Triangle: return false; // TODO
|
||
|
case ICollideable::BoxAxisAligned: return false; // TODO
|
||
|
case ICollideable::Box: return false; // TODO
|
||
|
case ICollideable::Frustrum: return false; // TODO
|
||
|
case ICollideable::Line: return false; // TODO
|
||
|
default: return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ICollideable::State Frustrum::Advanced( const ICollideable *target ) const
|
||
|
{ return ICollideable::Missed; } //Not supported returns 0
|