Initial commit
This commit is contained in:
412
engines/hpl1/engine/math/Frustum.cpp
Normal file
412
engines/hpl1/engine/math/Frustum.cpp
Normal file
@@ -0,0 +1,412 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006-2010 - Frictional Games
|
||||
*
|
||||
* This file is part of HPL1 Engine.
|
||||
*/
|
||||
|
||||
#include "hpl1/engine/math/Frustum.h"
|
||||
|
||||
#include "hpl1/engine/graphics/LowLevelGraphics.h"
|
||||
#include "hpl1/engine/math/Math.h"
|
||||
#include "hpl1/engine/system/low_level_system.h"
|
||||
|
||||
namespace hpl {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// CONSTRUCTORS
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
cFrustum::cFrustum() {
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC METHODS
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void cFrustum::SetViewProjMatrix(const cMatrixf &a_mtxProj, const cMatrixf &a_mtxView,
|
||||
float afFarPlane, float afNearPlane, float afFOV, float afAspect,
|
||||
const cVector3f &avOrigin, bool abInfFarPlane) {
|
||||
m_mtxViewProj = cMath::MatrixMul(a_mtxProj, a_mtxView);
|
||||
m_mtxModelView = a_mtxView;
|
||||
|
||||
mfFarPlane = afFarPlane;
|
||||
mfNearPlane = afNearPlane;
|
||||
mfFOV = afFOV;
|
||||
mfAspect = afAspect;
|
||||
|
||||
mvOrigin = avOrigin;
|
||||
|
||||
mbInfFarPlane = abInfFarPlane;
|
||||
|
||||
// This could be made more accurate.
|
||||
mOriginBV.SetSize(afNearPlane * 2);
|
||||
mOriginBV.SetPosition(mvOrigin);
|
||||
|
||||
UpdatePlanes();
|
||||
UpdateSphere();
|
||||
UpdateEndPoints();
|
||||
UpdateBV();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
cPlanef cFrustum::GetPlane(eFrustumPlane aType) {
|
||||
return mPlane[aType];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
eFrustumCollision cFrustum::CollideBoundingVolume(cBoundingVolume *aBV) {
|
||||
// Check if the BV is in the Frustum sphere.
|
||||
if (CollideFustrumSphere(aBV) == eFrustumCollision_Outside) {
|
||||
return eFrustumCollision_Outside;
|
||||
}
|
||||
|
||||
// Do a simple sphere collide test
|
||||
eFrustumCollision ret = CollideBVSphere(aBV);
|
||||
|
||||
// If there was an intersection, collide with the AABB
|
||||
if (ret == eFrustumCollision_Intersect) {
|
||||
return CollideBVAABB(aBV);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
bool cFrustum::CheckLineIntersection(const cVector3f &avPoint1, const cVector3f &avPoint2) {
|
||||
return cMath::CheckFrustumLineIntersection(&mPlane[0], avPoint1, avPoint2, 3);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
bool cFrustum::CheckQuadMeshIntersection(tVector3fVec *apPoints) {
|
||||
return cMath::CheckFrustumQuadMeshIntersection(&mPlane[0], apPoints, 3);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
bool cFrustum::CheckVolumeIntersection(cShadowVolumeBV *apVolume) {
|
||||
if (CheckQuadMeshIntersection(&apVolume->mvPoints)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// The first shadow plane is the near plane which we can skip.
|
||||
int lPairNum = (apVolume->mlPlaneCount - 1) / 2;
|
||||
|
||||
// Check with volume planes.
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (cMath::CheckFrustumLineIntersection(&apVolume->mvPlanes[1], mvOrigin, mvEndPoints[i],
|
||||
lPairNum)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// PRIVATE METHODS
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
eFrustumCollision cFrustum::CollideFustrumSphere(cBoundingVolume *aBV) {
|
||||
float fRadiusSum = mBoundingSphere.r + aBV->GetRadius();
|
||||
cVector3f vSepAxis = mBoundingSphere.center - aBV->GetWorldCenter();
|
||||
if (vSepAxis.SqrLength() > (fRadiusSum * fRadiusSum)) {
|
||||
return eFrustumCollision_Outside;
|
||||
}
|
||||
|
||||
return eFrustumCollision_Intersect;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
eFrustumCollision cFrustum::CollideBVSphere(cBoundingVolume *aBV) {
|
||||
int lPlanes = 6;
|
||||
if (mbInfFarPlane)
|
||||
lPlanes = 5;
|
||||
|
||||
for (int i = 0; i < lPlanes; i++) {
|
||||
float fDist = cMath::PlaneToPointDist(mPlane[i], aBV->GetWorldCenter());
|
||||
|
||||
if (fDist < -aBV->GetRadius()) {
|
||||
return eFrustumCollision_Outside;
|
||||
}
|
||||
|
||||
if (ABS(fDist) < aBV->GetRadius()) {
|
||||
return eFrustumCollision_Intersect;
|
||||
}
|
||||
}
|
||||
|
||||
return eFrustumCollision_Inside;
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
eFrustumCollision cFrustum::CollideBVAABB(cBoundingVolume *aBV) {
|
||||
cVector3f vMax = aBV->GetMax();
|
||||
cVector3f vMin = aBV->GetMin();
|
||||
|
||||
// Get the corners from the AAB
|
||||
cVector3f vCorners[9] = {
|
||||
cVector3f(vMax.x, vMax.y, vMax.z),
|
||||
cVector3f(vMax.x, vMax.y, vMin.z),
|
||||
cVector3f(vMax.x, vMin.y, vMax.z),
|
||||
cVector3f(vMax.x, vMin.y, vMin.z),
|
||||
|
||||
cVector3f(vMin.x, vMax.y, vMax.z),
|
||||
cVector3f(vMin.x, vMax.y, vMin.z),
|
||||
cVector3f(vMin.x, vMin.y, vMax.z),
|
||||
cVector3f(vMin.x, vMin.y, vMin.z),
|
||||
|
||||
// The "fuling", add center as well...
|
||||
aBV->GetPosition()};
|
||||
|
||||
int lTotalIn = 0;
|
||||
|
||||
int lPlanes = 6;
|
||||
if (mbInfFarPlane)
|
||||
lPlanes = 5;
|
||||
|
||||
// Go through all the planes
|
||||
for (int i = 0; i < lPlanes; i++) {
|
||||
int lInCount = 9;
|
||||
bool bIsIn = true;
|
||||
|
||||
for (int j = 0; j < 9; j++) {
|
||||
float fDist = cMath::PlaneToPointDist(mPlane[i], vCorners[j]);
|
||||
if (fDist < 0) {
|
||||
lInCount--;
|
||||
bIsIn = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (lInCount == 0)
|
||||
return eFrustumCollision_Outside;
|
||||
if (bIsIn)
|
||||
lTotalIn++;
|
||||
}
|
||||
|
||||
if (lTotalIn == lPlanes)
|
||||
return eFrustumCollision_Inside;
|
||||
|
||||
return eFrustumCollision_Intersect;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void cFrustum::UpdateSphere() {
|
||||
// calculate the radius of the frustum sphere
|
||||
float fViewLen = mfFarPlane - mfNearPlane;
|
||||
|
||||
float fHeight = fViewLen * tan(mfFOV * 0.5f);
|
||||
float fWidth = fHeight * mfAspect;
|
||||
|
||||
// halfway point between near/far planes starting at the origin and extending along the z axis
|
||||
cVector3f P(0.0f, 0.0f, mfNearPlane + fViewLen * 0.5f);
|
||||
|
||||
// the calculate far corner of the frustum
|
||||
cVector3f Q(fWidth, fHeight, fViewLen);
|
||||
|
||||
// the vector between P and Q
|
||||
cVector3f vDiff = P - Q;
|
||||
|
||||
// the radius becomes the length of this vector
|
||||
float fRadius = vDiff.Length();
|
||||
|
||||
// get the look vector of the camera from the view matrix
|
||||
cVector3f vLookVector = m_mtxModelView.GetForward() * -1;
|
||||
|
||||
// calculate the center of the sphere
|
||||
cVector3f vCenter = (mvOrigin) + (vLookVector * (fViewLen * 0.5f + mfNearPlane));
|
||||
|
||||
mBoundingSphere = cSpheref(vCenter, fRadius);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void cFrustum::UpdatePlanes() {
|
||||
// Left
|
||||
mPlane[eFrustumPlane_Left] = cPlanef(m_mtxViewProj.m[3][0] + m_mtxViewProj.m[0][0],
|
||||
m_mtxViewProj.m[3][1] + m_mtxViewProj.m[0][1],
|
||||
m_mtxViewProj.m[3][2] + m_mtxViewProj.m[0][2],
|
||||
m_mtxViewProj.m[3][3] + m_mtxViewProj.m[0][3]);
|
||||
|
||||
// Right
|
||||
mPlane[eFrustumPlane_Right] = cPlanef(m_mtxViewProj.m[3][0] - m_mtxViewProj.m[0][0],
|
||||
m_mtxViewProj.m[3][1] - m_mtxViewProj.m[0][1],
|
||||
m_mtxViewProj.m[3][2] - m_mtxViewProj.m[0][2],
|
||||
m_mtxViewProj.m[3][3] - m_mtxViewProj.m[0][3]);
|
||||
|
||||
// Bottom
|
||||
mPlane[eFrustumPlane_Bottom] = cPlanef(m_mtxViewProj.m[3][0] + m_mtxViewProj.m[1][0],
|
||||
m_mtxViewProj.m[3][1] + m_mtxViewProj.m[1][1],
|
||||
m_mtxViewProj.m[3][2] + m_mtxViewProj.m[1][2],
|
||||
m_mtxViewProj.m[3][3] + m_mtxViewProj.m[1][3]);
|
||||
|
||||
// Top
|
||||
mPlane[eFrustumPlane_Top] = cPlanef(m_mtxViewProj.m[3][0] - m_mtxViewProj.m[1][0],
|
||||
m_mtxViewProj.m[3][1] - m_mtxViewProj.m[1][1],
|
||||
m_mtxViewProj.m[3][2] - m_mtxViewProj.m[1][2],
|
||||
m_mtxViewProj.m[3][3] - m_mtxViewProj.m[1][3]);
|
||||
|
||||
// Near
|
||||
mPlane[eFrustumPlane_Near] = cPlanef(m_mtxViewProj.m[3][0] + m_mtxViewProj.m[2][0],
|
||||
m_mtxViewProj.m[3][1] + m_mtxViewProj.m[2][1],
|
||||
m_mtxViewProj.m[3][2] + m_mtxViewProj.m[2][2],
|
||||
m_mtxViewProj.m[3][3] + m_mtxViewProj.m[2][3]);
|
||||
// Far
|
||||
mPlane[eFrustumPlane_Far] = cPlanef(m_mtxViewProj.m[3][0] - m_mtxViewProj.m[2][0],
|
||||
m_mtxViewProj.m[3][1] - m_mtxViewProj.m[2][1],
|
||||
m_mtxViewProj.m[3][2] - m_mtxViewProj.m[2][2],
|
||||
m_mtxViewProj.m[3][3] - m_mtxViewProj.m[2][3]);
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
mPlane[i].Normalise();
|
||||
mPlane[i].CalcNormal();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void cFrustum::UpdateEndPoints() {
|
||||
float fXAngle = mfFOV * 0.5f;
|
||||
float fYAngle = mfFOV * 0.5f * mfAspect;
|
||||
|
||||
cVector3f vForward = m_mtxModelView.GetForward();
|
||||
// cVector3f vUp = m_mtxModelView.GetUp();
|
||||
cVector3f vRight = m_mtxModelView.GetRight();
|
||||
|
||||
// Point the forward vec in different dirs.
|
||||
cVector3f vUpDir = cMath::MatrixMul(cMath::MatrixQuaternion(cQuaternion(fXAngle, vRight)), vForward);
|
||||
cVector3f vDownDir = cMath::MatrixMul(cMath::MatrixQuaternion(cQuaternion(-fXAngle, vRight)), vForward);
|
||||
|
||||
// cVector3f vRightDir = cMath::MatrixMul(cMath::MatrixQuaternion(cQuaternion(fYAngle,vUp)), vForward);
|
||||
// cVector3f vLeftDir = cMath::MatrixMul(cMath::MatrixQuaternion(cQuaternion(-fYAngle,vUp)), vForward);
|
||||
|
||||
vForward = vForward * -1;
|
||||
|
||||
float fRightAdd = sin(fYAngle);
|
||||
// float fUpAdd = sin(fXAngle);
|
||||
|
||||
cVector3f vVec0 = vUpDir + vRight * fRightAdd;
|
||||
cVector3f vVec2 = vDownDir + vRight * fRightAdd;
|
||||
cVector3f vVec3 = vDownDir + vRight * -fRightAdd;
|
||||
cVector3f vVec1 = vUpDir + vRight * -fRightAdd;
|
||||
|
||||
/*cVector3f vVec0 = vUpDir;//cMath::Vector3Normalize(vUpDir+vRightDir);
|
||||
cVector3f vVec1 = vRightDir;//cMath::Vector3Normalize(vUpDir+vLeftDir);
|
||||
cVector3f vVec2 = vDownDir;//cMath::Vector3Normalize(vDownDir+vLeftDir);
|
||||
cVector3f vVec3 = vLeftDir;//cMath::Vector3Normalize(vDownDir+vRightDir);*/
|
||||
|
||||
// angles between forward and the vectors
|
||||
float fAngle0 = cMath::Vector3Angle(vVec0, vForward);
|
||||
float fAngle1 = cMath::Vector3Angle(vVec1, vForward);
|
||||
float fAngle2 = cMath::Vector3Angle(vVec2, vForward);
|
||||
float fAngle3 = cMath::Vector3Angle(vVec3, vForward);
|
||||
|
||||
// create end points.
|
||||
mvEndPoints[0] = mvOrigin + vVec0 * (mfFarPlane / cos(fAngle0));
|
||||
mvEndPoints[1] = mvOrigin + vVec1 * (mfFarPlane / cos(fAngle1));
|
||||
mvEndPoints[2] = mvOrigin + vVec2 * (mfFarPlane / cos(fAngle2));
|
||||
mvEndPoints[3] = mvOrigin + vVec3 * (mfFarPlane / cos(fAngle3));
|
||||
|
||||
/*mvEndPoints[0] = mvOrigin + (vUpDir+vRightDir) * mfFarPlane *-1;
|
||||
mvEndPoints[1] = mvOrigin + (vUpDir+vLeftDir) * mfFarPlane*-1;
|
||||
mvEndPoints[2] = mvOrigin + (vDownDir+vRightDir)* mfFarPlane*-1;
|
||||
mvEndPoints[3] = mvOrigin + (vDownDir+vLeftDir) * mfFarPlane*-1;*/
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void cFrustum::UpdateBV() {
|
||||
cVector3f vMin = mvOrigin;
|
||||
cVector3f vMax = mvOrigin;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (vMax.x < mvEndPoints[i].x)
|
||||
vMax.x = mvEndPoints[i].x;
|
||||
else if (vMin.x > mvEndPoints[i].x)
|
||||
vMin.x = mvEndPoints[i].x;
|
||||
|
||||
if (vMax.y < mvEndPoints[i].y)
|
||||
vMax.y = mvEndPoints[i].y;
|
||||
else if (vMin.y > mvEndPoints[i].y)
|
||||
vMin.y = mvEndPoints[i].y;
|
||||
|
||||
if (vMax.z < mvEndPoints[i].z)
|
||||
vMax.z = mvEndPoints[i].z;
|
||||
else if (vMin.z > mvEndPoints[i].z)
|
||||
vMin.z = mvEndPoints[i].z;
|
||||
}
|
||||
|
||||
mBoundingVolume.SetLocalMinMax(vMin, vMax);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const cVector3f &cFrustum::GetOrigin() {
|
||||
return mvOrigin;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
cBoundingVolume *cFrustum::GetOriginBV() {
|
||||
return &mOriginBV;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
cVector3f cFrustum::GetForward() {
|
||||
return m_mtxModelView.GetForward();
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void cFrustum::Draw(iLowLevelGraphics *apLowLevelGraphics) {
|
||||
apLowLevelGraphics->DrawLine(mvOrigin, mvEndPoints[0], cColor(1, 1, 1, 1));
|
||||
apLowLevelGraphics->DrawLine(mvOrigin, mvEndPoints[1], cColor(1, 1, 1, 1));
|
||||
apLowLevelGraphics->DrawLine(mvOrigin, mvEndPoints[2], cColor(1, 1, 1, 1));
|
||||
apLowLevelGraphics->DrawLine(mvOrigin, mvEndPoints[3], cColor(1, 1, 1, 1));
|
||||
|
||||
apLowLevelGraphics->DrawLine(mvEndPoints[0], mvEndPoints[1], cColor(1, 1, 1, 1));
|
||||
apLowLevelGraphics->DrawLine(mvEndPoints[1], mvEndPoints[2], cColor(1, 1, 1, 1));
|
||||
apLowLevelGraphics->DrawLine(mvEndPoints[2], mvEndPoints[3], cColor(1, 1, 1, 1));
|
||||
apLowLevelGraphics->DrawLine(mvEndPoints[3], mvEndPoints[0], cColor(1, 1, 1, 1));
|
||||
|
||||
apLowLevelGraphics->DrawLine(mvEndPoints[0], mvEndPoints[2], cColor(1, 1, 1, 1));
|
||||
apLowLevelGraphics->DrawLine(mvEndPoints[1], mvEndPoints[3], cColor(1, 1, 1, 1));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
} // namespace hpl
|
||||
Reference in New Issue
Block a user