//----------------------------------------------------------------------------- // 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; }