tge/engine/util/frustrumCuller.cpp
2025-02-17 23:17:30 -06:00

166 lines
4.3 KiB
C++
Executable File

//-----------------------------------------------------------------------------
// Torque Shader Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "util/frustrumCuller.h"
#include "sceneGraph/sceneGraph.h"
#include "sceneGraph/sgUtil.h"
#include "terrain/sky.h"
#include "dgl/dgl.h"
SceneState *FrustrumCuller::smSceneState;
Point3F FrustrumCuller::smCamPos;
U32 FrustrumCuller::smNumClipPlanes;
F32 FrustrumCuller::smFarDistance;
PlaneF FrustrumCuller::smClipPlane[MaxClipPlanes];
void FrustrumCuller::init(SceneState *state)
{
if(Con::getBoolVariable("$lockFrustrum", false))
return;
// Set up some general info.
smSceneState = state;
smFarDistance = gClientSceneGraph->getCurrentSky()->getVisibleDistance();
// Now determine the frustrum.
F64 realfrustumParam[6];
dglGetFrustum(&realfrustumParam[0], &realfrustumParam[1],
&realfrustumParam[2], &realfrustumParam[3],
&realfrustumParam[4], &realfrustumParam[5]);
MatrixF camToObj;
dglGetModelview(&camToObj); // BUG? Test this.
camToObj.inverse();
camToObj.getColumn(3, &smCamPos);
Point3F osCamPoint(0,0,0);
camToObj.mulP(osCamPoint);
sgComputeOSFrustumPlanes(
realfrustumParam,
camToObj,
osCamPoint,
smClipPlane[4],
smClipPlane[0],
smClipPlane[1],
smClipPlane[2],
smClipPlane[3]);
smNumClipPlanes = 4;
if (state->mFlipCull)
{
smClipPlane[0].neg();
smClipPlane[1].neg();
smClipPlane[2].neg();
smClipPlane[3].neg();
smClipPlane[4].neg();
}
AssertFatal(smNumClipPlanes <= MaxClipPlanes, "FrustrumCuller::init - got too many clip planes!");
}
F32 FrustrumCuller::getBoxDistance(const Box3F &box)
{
Point3F vec;
const Point3F &minPoint = box.min;
const Point3F &maxPoint = box.max;
if(smCamPos.z < minPoint.z)
vec.z = minPoint.z - smCamPos.z;
else if(smCamPos.z > maxPoint.z)
vec.z = maxPoint.z - smCamPos.z;
else
vec.z = 0;
if(smCamPos.x < minPoint.x)
vec.x = minPoint.x - smCamPos.x;
else if(smCamPos.x > maxPoint.x)
vec.x = smCamPos.x - maxPoint.x;
else
vec.x = 0;
if(smCamPos.y < minPoint.y)
vec.y = minPoint.y - smCamPos.y;
else if(smCamPos.y > maxPoint.y)
vec.y = smCamPos.y - maxPoint.y;
else
vec.y = 0;
return vec.len();
}
S32 FrustrumCuller::testBoxVisibility(const Box3F &bounds, const S32 mask, const F32 expand)
{
S32 retMask = 0;
Point3F minPoint, maxPoint;
for(S32 i = 0; i < smNumClipPlanes; i++)
{
if(mask & (1 << i))
{
if(smClipPlane[i].x > 0)
{
maxPoint.x = bounds.max.x;
minPoint.x = bounds.min.x;
}
else
{
maxPoint.x = bounds.min.x;
minPoint.x = bounds.max.x;
}
if(smClipPlane[i].y > 0)
{
maxPoint.y = bounds.max.y;
minPoint.y = bounds.min.y;
}
else
{
maxPoint.y = bounds.min.y;
minPoint.y = bounds.max.y;
}
if(smClipPlane[i].z > 0)
{
maxPoint.z = bounds.max.z;
minPoint.z = bounds.min.z;
}
else
{
maxPoint.z = bounds.min.z;
minPoint.z = bounds.max.z;
}
F32 maxDot = mDot(maxPoint, smClipPlane[i]);
F32 minDot = mDot(minPoint, smClipPlane[i]);
F32 planeD = smClipPlane[i].d;
if(maxDot <= -(planeD + expand))
return -1;
if(minDot <= -planeD)
retMask |= (1 << i);
}
}
// Check the far distance as well.
if(mask & FarSphereMask)
{
F32 squareDistance = getBoxDistance(bounds);
// Reject stuff outside our visible range...
if(squareDistance >= smFarDistance)
return -1;
// See if the box potentially hits the far sphere. (Sort of assumes a square box!)
if(squareDistance + bounds.len_x() + bounds.len_z() > smFarDistance)
retMask |= FarSphereMask;
}
return retMask;
}