Initial commit
This commit is contained in:
5
engine/util/fourcc.h
Executable file
5
engine/util/fourcc.h
Executable file
@ -0,0 +1,5 @@
|
||||
#ifndef MAKEFOURCC
|
||||
#define MAKEFOURCC(ch0, ch1, ch2, ch3) \
|
||||
((U32)(U8)(ch0) | ((U32)(U8)(ch1) << 8) | \
|
||||
((U32)(U8)(ch2) << 16) | ((U32)(U8)(ch3) << 24 ))
|
||||
#endif //defined(MAKEFOURCC)
|
166
engine/util/frustrumCuller.cpp
Executable file
166
engine/util/frustrumCuller.cpp
Executable file
@ -0,0 +1,166 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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;
|
||||
}
|
39
engine/util/frustrumCuller.h
Executable file
39
engine/util/frustrumCuller.h
Executable file
@ -0,0 +1,39 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Shader Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _FRUSTRUMCULLER_H_
|
||||
#define _FRUSTRUMCULLER_H_
|
||||
|
||||
#include "math/mBox.h"
|
||||
#include "sceneGraph/sceneState.h"
|
||||
|
||||
namespace FrustrumCuller
|
||||
{
|
||||
enum
|
||||
{
|
||||
/// We need to store at least 4 clip planes (sides of view frustrum).
|
||||
MaxClipPlanes = 5,
|
||||
|
||||
// Clipping related flags...
|
||||
ClipPlaneMask = BIT(MaxClipPlanes) - 1,
|
||||
FarSphereMask = BIT(MaxClipPlanes + 1),
|
||||
FogPlaneBoxMask = BIT(MaxClipPlanes + 2),
|
||||
|
||||
AllClipPlanes = ClipPlaneMask | FarSphereMask,
|
||||
|
||||
};
|
||||
|
||||
extern SceneState *smSceneState;
|
||||
extern Point3F smCamPos;
|
||||
extern F32 smFarDistance;
|
||||
extern U32 smNumClipPlanes;
|
||||
extern PlaneF smClipPlane[MaxClipPlanes];
|
||||
|
||||
void init(SceneState *state);
|
||||
S32 testBoxVisibility(const Box3F &bounds, const S32 mask, const F32 expand);
|
||||
F32 getBoxDistance(const Box3F &box);
|
||||
};
|
||||
|
||||
#endif
|
229
engine/util/quadTreeTracer.cpp
Executable file
229
engine/util/quadTreeTracer.cpp
Executable file
@ -0,0 +1,229 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Shader Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "util/quadTreeTracer.h"
|
||||
#include "platform/profiler.h"
|
||||
#include "core/frameAllocator.h"
|
||||
|
||||
static F32 calcInterceptV(F32 vStart, F32 invDeltaV, F32 intercept)
|
||||
{
|
||||
return (intercept - vStart) * invDeltaV;
|
||||
}
|
||||
|
||||
static F32 calcInterceptNone(F32, F32, F32)
|
||||
{
|
||||
return F32_MAX;
|
||||
}
|
||||
|
||||
static F32 (*calcInterceptX)(F32, F32, F32);
|
||||
static F32 (*calcInterceptY)(F32, F32, F32);
|
||||
|
||||
bool QuadTreeTracer::castRay(const Point3F &start, const Point3F &end, RayInfo *info)
|
||||
{
|
||||
PROFILE_START(QuadTreeTracer_castRay);
|
||||
|
||||
// Do some precalculations we'll use for the rest of this routine.
|
||||
// Set up our intercept calculation methods.
|
||||
F32 invDeltaX;
|
||||
if(end.x == start.x)
|
||||
{
|
||||
calcInterceptX = calcInterceptNone;
|
||||
invDeltaX = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
invDeltaX = 1.f / (end.x - start.x);
|
||||
calcInterceptX = calcInterceptV;
|
||||
}
|
||||
|
||||
F32 invDeltaY;
|
||||
if(end.y == start.y)
|
||||
{
|
||||
calcInterceptY = calcInterceptNone;
|
||||
invDeltaY = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
invDeltaY = 1.f / (end.y - start.y);
|
||||
calcInterceptY = calcInterceptV;
|
||||
}
|
||||
|
||||
// Subdivide our space based on the size of the lowest level of the tree...
|
||||
const F32 invSize = 1.f / F32(BIT(mTreeDepth-1));
|
||||
|
||||
// Grab this off the frame allocator, we don't want to do a proper alloc
|
||||
// on every ray!
|
||||
FrameAllocatorMarker stackAlloc;
|
||||
RayStackNode *stack = (RayStackNode*)stackAlloc.alloc(sizeof(RayStackNode) * (mTreeDepth * 3 + 1));
|
||||
|
||||
U32 stackSize = 1;
|
||||
|
||||
// Kick off the stack with the root node.
|
||||
stack[0].startT = 0;
|
||||
stack[0].endT = 1;
|
||||
stack[0].squarePos.set(0,0);
|
||||
stack[0].level = mTreeDepth - 1;
|
||||
|
||||
//Con::printf("QuadTreeTracer::castRay(%x)", this);
|
||||
|
||||
// Aright, now let's do some raycasting!
|
||||
while(stackSize--)
|
||||
{
|
||||
// Get the current node for easy access...
|
||||
RayStackNode *sn = stack + stackSize;
|
||||
|
||||
const U32 level = sn->level;
|
||||
const F32 startT = sn->startT;
|
||||
const F32 endT = sn->endT;
|
||||
const Point2I squarePos = sn->squarePos;
|
||||
|
||||
AssertFatal((startT >= 0.f) && (startT <= 1.f), "QuadTreeTracer::castRay - out of range startT on stack!");
|
||||
AssertFatal((endT >= 0.f) && (endT <= 1.f), "QuadTreeTracer::castRay - out of range endT on stack!");
|
||||
|
||||
//Con::printf(" -- node(%d, %d @ %d), sT=%g, eT=%g", squarePos.x, squarePos.y, level, startT, endT);
|
||||
|
||||
// Figure our start and end Z.
|
||||
const F32 startZ = startT * (end.z - start.z) + start.z;
|
||||
const F32 endZ = endT * (end.z - start.z) + start.z;
|
||||
|
||||
// Ok, now let's see if we hit the lower bound
|
||||
const F32 squareMin = getSquareMin(level, squarePos);
|
||||
|
||||
if(startZ < squareMin && endZ < squareMin)
|
||||
continue; //Nope, skip out.
|
||||
|
||||
// Hmm, let's check the upper bound.
|
||||
const F32 squareMax = getSquareMax(level, squarePos);
|
||||
|
||||
if(startZ > squareMax && endZ > squareMax)
|
||||
continue; //Nope, skip out.
|
||||
|
||||
// We might be intersecting something... If we've hit
|
||||
// the tree depth let's deal with the leaf intersection.
|
||||
if(level == 0)
|
||||
{
|
||||
//Con::printf(" ++ check node(%d, %d @ %d), sT=%g, eT=%g", squarePos.x, squarePos.y, level, startT, endT);
|
||||
|
||||
if(castLeafRay(squarePos, start, end, startT, endT, info))
|
||||
{
|
||||
PROFILE_END();
|
||||
return true; // We hit, tell 'em so!
|
||||
}
|
||||
continue; // Otherwise, keep looking.
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ok, we have to push our children as we're an inner node.
|
||||
|
||||
// First, figure out some widths...
|
||||
U32 squareSize = BIT(level);
|
||||
U32 subSqSize = BIT(level - 1);
|
||||
|
||||
// Now, calculate intercepts so we know how to deal with this
|
||||
// situation... (intercept = position, int = t value for that pos)
|
||||
|
||||
const F32 xIntercept = (squarePos.x + subSqSize) * invSize;
|
||||
F32 xInt = calcInterceptX(start.x, invDeltaX, xIntercept);
|
||||
|
||||
const F32 yIntercept = (squarePos.y + subSqSize) * invSize;
|
||||
F32 yInt = calcInterceptY(start.y, invDeltaY, yIntercept);
|
||||
|
||||
// Our starting position for this subray...
|
||||
const F32 startX = startT * (end.x - start.x) + start.x;
|
||||
const F32 startY = startT * (end.y - start.y) + start.y;
|
||||
|
||||
// Deal with squares that might be "behind" the ray.
|
||||
if(xInt < startT) xInt = F32_MAX;
|
||||
if(yInt < startT) yInt = F32_MAX;
|
||||
|
||||
// Do a little magic to calculate our next checks...
|
||||
const U32 x0 = (startX > xIntercept) * subSqSize;
|
||||
const U32 y0 = (startY > yIntercept) * subSqSize;
|
||||
|
||||
const U32 x1 = subSqSize - x0;
|
||||
const U32 y1 = subSqSize - y0;
|
||||
|
||||
//AssertFatal(x1 < 1000, "QuadTreeTracer::castRay - possible overflow in x1!");
|
||||
//AssertFatal(y1 < 1000, "QuadTreeTracer::castRay - possible overflow in y1!");
|
||||
|
||||
const U32 nextLevel = level - 1;
|
||||
|
||||
// Ok, now let's figure out what nodes, in what order, need to go
|
||||
// on the stack. We push things on in reverse order of processing.
|
||||
if(xInt > endT && yInt > endT)
|
||||
{
|
||||
stack[stackSize].squarePos.set(squarePos.x + x0, squarePos.y + y0);
|
||||
stack[stackSize].level = nextLevel;
|
||||
stackSize++;
|
||||
}
|
||||
else if(xInt < yInt)
|
||||
{
|
||||
F32 nextIntersect = endT;
|
||||
|
||||
if(yInt <= endT)
|
||||
{
|
||||
stack[stackSize].squarePos.set(squarePos.x + x1, squarePos.y + y1);
|
||||
stack[stackSize].startT = yInt;
|
||||
stack[stackSize].endT = endT;
|
||||
stack[stackSize].level = nextLevel;
|
||||
nextIntersect = yInt;
|
||||
stackSize++;
|
||||
}
|
||||
|
||||
// Do middle two, order doesn't matter.
|
||||
stack[stackSize].squarePos.set(squarePos.x + x1, squarePos.y + y0);
|
||||
stack[stackSize].startT = xInt;
|
||||
stack[stackSize].endT = nextIntersect;
|
||||
stack[stackSize].level = nextLevel;
|
||||
|
||||
stack[stackSize+1].squarePos.set(squarePos.x + x0, squarePos.y + y0);
|
||||
stack[stackSize+1].startT = startT;
|
||||
stack[stackSize+1].endT = xInt;
|
||||
stack[stackSize+1].level = nextLevel;
|
||||
stackSize += 2;
|
||||
}
|
||||
else if(yInt < xInt)
|
||||
{
|
||||
F32 nextIntersect = endT;
|
||||
if(xInt <= endT)
|
||||
{
|
||||
stack[stackSize].squarePos.set(squarePos.x + x1, squarePos.y + y1);
|
||||
stack[stackSize].startT = xInt;
|
||||
stack[stackSize].endT = endT;
|
||||
stack[stackSize].level = nextLevel;
|
||||
nextIntersect = xInt;
|
||||
stackSize++;
|
||||
}
|
||||
stack[stackSize].squarePos.set(squarePos.x + x0, squarePos.y + y1);
|
||||
stack[stackSize].startT = yInt;
|
||||
stack[stackSize].endT = nextIntersect;
|
||||
stack[stackSize].level = nextLevel;
|
||||
|
||||
stack[stackSize+1].squarePos.set(squarePos.x + x0, squarePos.y + y0);
|
||||
stack[stackSize+1].startT = startT;
|
||||
stack[stackSize+1].endT = yInt;
|
||||
stack[stackSize+1].level = nextLevel;
|
||||
stackSize += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
stack[stackSize].squarePos.set(squarePos.x + x1, squarePos.y + y1);
|
||||
stack[stackSize].startT = xInt;
|
||||
stack[stackSize].endT = endT;
|
||||
stack[stackSize].level = nextLevel;
|
||||
|
||||
stack[stackSize+1].squarePos.set(squarePos.x + x0, squarePos.y + y0);
|
||||
stack[stackSize+1].startT = startT;
|
||||
stack[stackSize+1].endT = xInt;
|
||||
stack[stackSize+1].level = nextLevel;
|
||||
stackSize += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing found, so give up.
|
||||
PROFILE_END();
|
||||
return false;
|
||||
}
|
87
engine/util/quadTreeTracer.h
Executable file
87
engine/util/quadTreeTracer.h
Executable file
@ -0,0 +1,87 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Shader Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _QUADTREETRACER_H_
|
||||
#define _QUADTREETRACER_H_
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "math/mPoint.h"
|
||||
#include "sim/sceneObject.h"
|
||||
|
||||
/// Helper class to perform a fast, recursive ray cast against a set of
|
||||
/// hierarchical bounding boxes.
|
||||
///
|
||||
/// This class assumes that it is working on a unit quadtree (ie, one that
|
||||
/// extends from 0..1 in the XY dimensions. Z scale is unaffected).
|
||||
///
|
||||
/// Node indexing is done TGE Terrain style - 0 is the largest level of the
|
||||
/// quadtree, while coordinates are always in the full range of the quadtree
|
||||
/// (in a 6 deep tree, 0..63, for instance). This allows the quadtree descent
|
||||
/// to be very fast!
|
||||
class QuadTreeTracer
|
||||
{
|
||||
protected:
|
||||
|
||||
struct StackNode
|
||||
{
|
||||
Point2I squarePos;
|
||||
U32 level;
|
||||
};
|
||||
|
||||
struct RayStackNode : StackNode
|
||||
{
|
||||
F32 startT;
|
||||
F32 endT;
|
||||
};
|
||||
|
||||
U32 mTreeDepth;
|
||||
|
||||
QuadTreeTracer(U32 treeDepth)
|
||||
: mTreeDepth(treeDepth)
|
||||
{
|
||||
}
|
||||
|
||||
/// Children better implement these! They return min/max height bounds
|
||||
/// of the specified square.
|
||||
virtual const F32 getSquareMin(const U32 &level, const Point2I &pos) const = 0;
|
||||
virtual const F32 getSquareMax(const U32 &level, const Point2I &pos) const = 0;
|
||||
|
||||
/// And this does checks on leaf nodes.
|
||||
virtual bool castLeafRay(const Point2I pos, const Point3F &start, const Point3F &end, const F32 &startT, const F32 &endT, RayInfo *info) = 0;
|
||||
|
||||
/// Helper function to calculate intercepts.
|
||||
inline const F32 calcIntercept(const F32 vStart, const F32 invDeltaV, const F32 intercept) const
|
||||
{
|
||||
return (intercept - vStart) * invDeltaV;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// Size of a quadtree of depth.
|
||||
static inline const U32 getNodeCount(const U32 depth)
|
||||
{
|
||||
return 0x55555555 & ((1 << depth*2) - 1);
|
||||
}
|
||||
|
||||
/// Index of a node at given position in a quadtree.
|
||||
static inline const U32 getNodeIndex(const U32 level, const Point2I pos)
|
||||
{
|
||||
//AssertFatal(level < mTreeDepth, "QuadTreeTracer::getNodeIndex - out of range level!)
|
||||
AssertFatal(pos.x < BIT(level) && pos.x >= 0 , "QuadTreeTracer::getNodeIndex - out of range x for level!");
|
||||
AssertFatal(pos.y < BIT(level) && pos.y >= 0 , "QuadTreeTracer::getNodeIndex - out of range y for level!");
|
||||
|
||||
const U32 base = getNodeCount(level);
|
||||
return base + (pos.x << level) + pos.y;
|
||||
}
|
||||
|
||||
/// Cast a ray against a quadtree of hierarchical bounding boxes.
|
||||
///
|
||||
/// This method assumes the quadtree extends from (0..1) along the
|
||||
/// X and Y axes. Z is unscaled. You may need to adjust the points
|
||||
/// you pass into this method to get the proper results.
|
||||
bool castRay(const Point3F &start, const Point3F &end, RayInfo *info);
|
||||
};
|
||||
|
||||
#endif
|
150
engine/util/rectClipper.cpp
Executable file
150
engine/util/rectClipper.cpp
Executable file
@ -0,0 +1,150 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Shader Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "util/rectClipper.h"
|
||||
|
||||
namespace {
|
||||
|
||||
inline void
|
||||
swap(F32& in_one, F32& in_two)
|
||||
{
|
||||
F32 temp = in_one;
|
||||
in_one = in_two;
|
||||
in_two = temp;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool
|
||||
RectClipper::clipLine(const Point2I& in_rStart,
|
||||
const Point2I& in_rEnd,
|
||||
Point2I& out_rStart,
|
||||
Point2I& out_rEnd) const
|
||||
{
|
||||
// Check for trivial rejection
|
||||
if ((in_rStart.x < m_clipRect.point.x && in_rEnd.x < m_clipRect.point.x) ||
|
||||
(in_rStart.x >= m_clipRect.point.x + m_clipRect.extent.x &&
|
||||
in_rEnd.x >= m_clipRect.point.x + m_clipRect.extent.x))
|
||||
return false;
|
||||
if ((in_rStart.y < m_clipRect.point.y && in_rEnd.y < m_clipRect.point.y) ||
|
||||
(in_rStart.y >= m_clipRect.point.y + m_clipRect.extent.y &&
|
||||
in_rEnd.y >= m_clipRect.point.y + m_clipRect.extent.y))
|
||||
return false;
|
||||
|
||||
F32 x1 = F32(in_rStart.x);
|
||||
F32 y1 = F32(in_rStart.y);
|
||||
F32 x2 = F32(in_rEnd.x);
|
||||
F32 y2 = F32(in_rEnd.y);
|
||||
|
||||
// I'm using essentially what's in the Phoenix libs, Liang-Biarsky based, but
|
||||
// converted to FP math for greater precision on the back end...
|
||||
//
|
||||
bool flipped = false;
|
||||
if (x1 > x2)
|
||||
{
|
||||
swap(x1, x2);
|
||||
swap(y1, y2);
|
||||
flipped = !flipped;
|
||||
}
|
||||
|
||||
F32 dx = x2 - x1;
|
||||
F32 dy = y2 - y1;
|
||||
|
||||
// Clip x coord
|
||||
F32 t;
|
||||
if (x1 < F32(m_clipRect.point.x))
|
||||
{
|
||||
t = (F32(m_clipRect.point.x) - x1) / F32(dx);
|
||||
x1 = F32(m_clipRect.point.x);
|
||||
y1 += t * dy;
|
||||
dx = x2 - x1;
|
||||
dy = y2 - y1;
|
||||
}
|
||||
if (x2 >= F32(m_clipRect.point.x + m_clipRect.extent.x))
|
||||
{
|
||||
t = (F32(m_clipRect.point.x + m_clipRect.extent.x - 1) - x1) / F32(dx);
|
||||
x2 = F32(m_clipRect.point.x + m_clipRect.extent.x - 1);
|
||||
y2 = y1 + (t * dy);
|
||||
dx = x2 - x1;
|
||||
dy = y2 - y1;
|
||||
}
|
||||
|
||||
// Recheck trivial rejection condition...
|
||||
if((y1 > F32(m_clipRect.point.y + m_clipRect.extent.y - 1) &&
|
||||
y2 > F32(m_clipRect.point.y + m_clipRect.extent.y - 1)) ||
|
||||
(y1 < F32(m_clipRect.point.y) && y2 < F32(m_clipRect.point.y)))
|
||||
return false;
|
||||
|
||||
if (y1 > y2)
|
||||
{
|
||||
swap(x1, x2);
|
||||
swap(y1, y2);
|
||||
flipped = !flipped;
|
||||
}
|
||||
|
||||
if (y1 < F32(m_clipRect.point.y))
|
||||
{
|
||||
t = (F32(m_clipRect.point.y) - y1) / F32(dy);
|
||||
y1 = F32(m_clipRect.point.y);
|
||||
x1 += t * dx;
|
||||
dx = x2 - x1;
|
||||
dy = y2 - y1;
|
||||
}
|
||||
if (y2 > F32(m_clipRect.point.y + m_clipRect.extent.y - 1))
|
||||
{
|
||||
t = (F32(m_clipRect.point.y + m_clipRect.extent.y - 1) - y1) / F32(dy);
|
||||
y2 = F32(m_clipRect.point.y + m_clipRect.extent.y - 1);
|
||||
x2 = x1 + (t * dx);
|
||||
}
|
||||
|
||||
if (flipped == true)
|
||||
{
|
||||
out_rEnd.x = S32(x1 + 0.5f);
|
||||
out_rEnd.y = S32(y1 + 0.5f);
|
||||
out_rStart.x = S32(x2 + 0.5f);
|
||||
out_rStart.y = S32(y2 + 0.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
out_rStart.x = S32(x1 + 0.5f);
|
||||
out_rStart.y = S32(y1 + 0.5f);
|
||||
out_rEnd.x = S32(x2 + 0.5f);
|
||||
out_rEnd.y = S32(y2 + 0.5f);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
RectClipper::clipRect(const RectI& in_rRect,
|
||||
RectI& out_rRect) const
|
||||
{
|
||||
AssertFatal(in_rRect.isValidRect(), "Inappropriate min/max coords for rectangle");
|
||||
|
||||
if (in_rRect.point.x + in_rRect.extent.x - 1 < m_clipRect.point.x ||
|
||||
in_rRect.point.x > m_clipRect.point.x + m_clipRect.extent.x - 1)
|
||||
return false;
|
||||
if (in_rRect.point.y + in_rRect.extent.y - 1 < m_clipRect.point.y ||
|
||||
in_rRect.point.y > m_clipRect.point.y + m_clipRect.extent.y - 1)
|
||||
return false;
|
||||
|
||||
if (in_rRect.point.x < m_clipRect.point.x) out_rRect.point.x = m_clipRect.point.x;
|
||||
else out_rRect.point.x = in_rRect.point.x;
|
||||
|
||||
if (in_rRect.point.y < m_clipRect.point.y) out_rRect.point.y = m_clipRect.point.y;
|
||||
else out_rRect.point.y = in_rRect.point.y;
|
||||
|
||||
Point2I bottomR;
|
||||
bottomR.x = getMin(in_rRect.point.x + in_rRect.extent.x - 1,
|
||||
m_clipRect.point.x + m_clipRect.extent.x - 1);
|
||||
bottomR.y = getMin(in_rRect.point.y + in_rRect.extent.y - 1,
|
||||
m_clipRect.point.y + m_clipRect.extent.y - 1);
|
||||
|
||||
out_rRect.extent.x = bottomR.x - out_rRect.point.x + 1;
|
||||
out_rRect.extent.x = bottomR.y - out_rRect.point.y + 1;
|
||||
|
||||
return true;
|
||||
}
|
55
engine/util/rectClipper.h
Executable file
55
engine/util/rectClipper.h
Executable file
@ -0,0 +1,55 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Shader Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _RECTCLIPPER_H_
|
||||
#define _RECTCLIPPER_H_
|
||||
|
||||
//Includes
|
||||
#ifndef _PLATFORM_H_
|
||||
#include "platform/platform.h"
|
||||
#endif
|
||||
#ifndef _MRECT_H_
|
||||
#include "math/mRect.h"
|
||||
#endif
|
||||
|
||||
|
||||
class RectClipper
|
||||
{
|
||||
RectI m_clipRect;
|
||||
|
||||
public:
|
||||
RectClipper(const RectI& in_rRect);
|
||||
|
||||
bool clipPoint(const Point2I& in_rPoint) const;
|
||||
bool clipLine(const Point2I& in_rStart,
|
||||
const Point2I& in_rEnd,
|
||||
Point2I& out_rStart,
|
||||
Point2I& out_rEnd) const;
|
||||
bool clipRect(const RectI& in_rRect,
|
||||
RectI& out_rRect) const;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//-------------------------------------- INLINES
|
||||
//
|
||||
inline
|
||||
RectClipper::RectClipper(const RectI& in_rRect)
|
||||
: m_clipRect(in_rRect)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
inline bool
|
||||
RectClipper::clipPoint(const Point2I& in_rPoint) const
|
||||
{
|
||||
if ((in_rPoint.x < m_clipRect.point.x) ||
|
||||
(in_rPoint.y < m_clipRect.point.y) ||
|
||||
(in_rPoint.x >= m_clipRect.point.x + m_clipRect.extent.x) ||
|
||||
(in_rPoint.y >= m_clipRect.point.y + m_clipRect.extent.y))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif //_RECTCLIPPER_H_
|
15
engine/util/safeDelete.h
Executable file
15
engine/util/safeDelete.h
Executable file
@ -0,0 +1,15 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Shader Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Utility macros. We clobber to enforce our semantics!
|
||||
|
||||
#undef SAFE_DELETE
|
||||
#define SAFE_DELETE(a) if( (a) != NULL ) delete (a); (a) = NULL;
|
||||
|
||||
#undef SAFE_DELETE_ARRAY
|
||||
#define SAFE_DELETE_ARRAY(a) if( (a) != NULL ) delete [] (a); (a) = NULL;
|
||||
|
||||
#undef SAFE_FREE
|
||||
#define SAFE_FREE(a) if( (a) != NULL ) dFree (a); (a) = NULL;
|
175
engine/util/triBoxCheck.cpp
Executable file
175
engine/util/triBoxCheck.cpp
Executable file
@ -0,0 +1,175 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Shader Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// AABB-triangle overlap test code originally by Tomas Akenine-M<>ller
|
||||
// Assisted by Pierre Terdiman and David Hunt
|
||||
// http://www.cs.lth.se/home/Tomas_Akenine_Moller/code/
|
||||
// Ported to TSE by BJG, 2005-4-14
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "util/triBoxCheck.h"
|
||||
|
||||
#define FINDMINMAX(x0,x1,x2,min,max) \
|
||||
min = max = x0; \
|
||||
if(x1<min) min=x1;\
|
||||
if(x1>max) max=x1;\
|
||||
if(x2<min) min=x2;\
|
||||
if(x2>max) max=x2;
|
||||
|
||||
bool planeBoxOverlap(Point3F normal, Point3F vert, Point3F maxbox)
|
||||
{
|
||||
S32 q;
|
||||
F32 v;
|
||||
Point3F vmin, vmax;
|
||||
|
||||
for(q=0;q<=2;q++)
|
||||
{
|
||||
v=vert[q];
|
||||
if(normal[q]>0.0f)
|
||||
{
|
||||
vmin[q]=-maxbox[q] - v;
|
||||
vmax[q]= maxbox[q] - v;
|
||||
}
|
||||
else
|
||||
{
|
||||
vmin[q]= maxbox[q] - v;
|
||||
vmax[q]=-maxbox[q] - v;
|
||||
}
|
||||
}
|
||||
|
||||
if(mDot(normal, vmin) > 0.f)
|
||||
return false;
|
||||
|
||||
if(mDot(normal, vmax) >= 0.f)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*======================== X-tests ========================*/
|
||||
#define AXISTEST_X01(a, b, fa, fb) \
|
||||
p0 = a*v0.y - b*v0.z; \
|
||||
p2 = a*v2.y - b*v2.z; \
|
||||
if(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;} \
|
||||
rad = fa * boxhalfsize.y + fb * boxhalfsize.z; \
|
||||
if(min>rad || max<-rad) return false;
|
||||
|
||||
#define AXISTEST_X2(a, b, fa, fb) \
|
||||
p0 = a*v0.y - b*v0.z; \
|
||||
p1 = a*v1.y - b*v1.z; \
|
||||
if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
|
||||
rad = fa * boxhalfsize.y + fb * boxhalfsize.z; \
|
||||
if(min>rad || max<-rad) return false;
|
||||
|
||||
/*======================== Y-tests ========================*/
|
||||
#define AXISTEST_Y02(a, b, fa, fb) \
|
||||
p0 = -a*v0.x + b*v0.z; \
|
||||
p2 = -a*v2.x + b*v2.z; \
|
||||
if(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;} \
|
||||
rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \
|
||||
if(min>rad || max<-rad) return false;
|
||||
|
||||
#define AXISTEST_Y1(a, b, fa, fb) \
|
||||
p0 = -a*v0.x + b*v0.z; \
|
||||
p1 = -a*v1.x + b*v1.z; \
|
||||
if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
|
||||
rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \
|
||||
if(min>rad || max<-rad) return false;
|
||||
|
||||
/*======================== Z-tests ========================*/
|
||||
|
||||
#define AXISTEST_Z12(a, b, fa, fb) \
|
||||
p1 = a*v1.x - b*v1.y; \
|
||||
p2 = a*v2.x - b*v2.y; \
|
||||
if(p2<p1) {min=p2; max=p1;} else {min=p1; max=p2;} \
|
||||
rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \
|
||||
if(min>rad || max<-rad) return false;
|
||||
|
||||
#define AXISTEST_Z0(a, b, fa, fb) \
|
||||
p0 = a*v0.x - b*v0.y; \
|
||||
p1 = a*v1.x - b*v1.y; \
|
||||
if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
|
||||
rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \
|
||||
if(min>rad || max<-rad) return false;
|
||||
|
||||
bool triBoxOverlap(Point3F boxcenter, Point3F boxhalfsize, Point3F triverts[3])
|
||||
{
|
||||
/* use separating axis theorem to test overlap between triangle and box */
|
||||
/* need to test for overlap in these directions: */
|
||||
/* 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */
|
||||
/* we do not even need to test these) */
|
||||
/* 2) normal of the triangle */
|
||||
/* 3) crossproduct(edge from tri, {x,y,z}-directin) */
|
||||
/* this gives 3x3=9 more tests */
|
||||
|
||||
Point3F v0,v1,v2;
|
||||
|
||||
F32 min,max,p0,p1,p2,rad,fex,fey,fez; // -NJMP- "d" local variable removed
|
||||
Point3F normal,e0,e1,e2;
|
||||
|
||||
/* This is the fastest branch on Sun */
|
||||
/* move everything so that the boxcenter is in (0,0,0) */
|
||||
v0 = triverts[0] - boxcenter;
|
||||
v1 = triverts[1] - boxcenter;
|
||||
v2 = triverts[2] - boxcenter;
|
||||
|
||||
/* compute triangle edges */
|
||||
e0 = v1 - v0; /* tri edge 0 */
|
||||
e1 = v2 - v1; /* tri edge 1 */
|
||||
e2 = v0 - v2; /* tri edge 2 */
|
||||
|
||||
/* Bullet 3: */
|
||||
/* test the 9 tests first (this was faster) */
|
||||
fex = mFabs(e0.x);
|
||||
fey = mFabs(e0.y);
|
||||
fez = mFabs(e0.z);
|
||||
AXISTEST_X01(e0.z, e0.y, fez, fey);
|
||||
AXISTEST_Y02(e0.z, e0.x, fez, fex);
|
||||
AXISTEST_Z12(e0.y, e0.x, fey, fex);
|
||||
|
||||
fex = mFabs(e1.x);
|
||||
fey = mFabs(e1.y);
|
||||
fez = mFabs(e1.z);
|
||||
AXISTEST_X01(e1.z, e1.y, fez, fey);
|
||||
AXISTEST_Y02(e1.z, e1.x, fez, fex);
|
||||
AXISTEST_Z0(e1.y, e1.x, fey, fex);
|
||||
|
||||
fex = mFabs(e2.x);
|
||||
fey = mFabs(e2.y);
|
||||
fez = mFabs(e2.z);
|
||||
AXISTEST_X2(e2.z, e2.y, fez, fey);
|
||||
AXISTEST_Y1(e2.z, e2.x, fez, fex);
|
||||
AXISTEST_Z12(e2.y, e2.x, fey, fex);
|
||||
|
||||
/* Bullet 1: */
|
||||
/* first test overlap in the {x,y,z}-directions */
|
||||
/* find min, max of the triangle each direction, and test for overlap in */
|
||||
/* that direction -- this is equivalent to testing a minimal AABB around */
|
||||
/* the triangle against the AABB */
|
||||
|
||||
/* test in X-direction */
|
||||
FINDMINMAX(v0.x,v1.x,v2.x,min,max);
|
||||
if(min>boxhalfsize.x || max<-boxhalfsize.x) return false;
|
||||
|
||||
/* test in Y-direction */
|
||||
FINDMINMAX(v0.y,v1.y,v2.y,min,max);
|
||||
if(min>boxhalfsize.y || max<-boxhalfsize.y) return false;
|
||||
|
||||
/* test in Z-direction */
|
||||
FINDMINMAX(v0.z,v1.z,v2.z,min,max);
|
||||
if(min>boxhalfsize.z || max<-boxhalfsize.z) return false;
|
||||
|
||||
/* Bullet 2: */
|
||||
/* test if the box intersects the plane of the triangle */
|
||||
/* compute plane equation of triangle: normal*x+d=0 */
|
||||
normal = mCross(e0, e1);
|
||||
|
||||
if(!planeBoxOverlap(normal,v0,boxhalfsize)) return false;
|
||||
|
||||
return true; /* box and triangle overlaps */
|
||||
}
|
||||
|
35
engine/util/triBoxCheck.h
Executable file
35
engine/util/triBoxCheck.h
Executable file
@ -0,0 +1,35 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Shader Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// AABB-triangle overlap test code originally by Tomas Akenine-M<>ller
|
||||
// Assisted by Pierre Terdiman and David Hunt
|
||||
// http://www.cs.lth.se/home/Tomas_Akenine_Moller/code/
|
||||
// Ported to TSE by BJG, 2005-4-14
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _TRIBOXCHECK_H_
|
||||
#define _TRIBOXCHECK_H_
|
||||
|
||||
#include "math/mPoint.h"
|
||||
#include "math/mBox.h"
|
||||
|
||||
bool triBoxOverlap(Point3F boxcenter, Point3F boxhalfsize, Point3F triverts[3]);
|
||||
|
||||
/// Massage stuff into right format for triBoxOverlap test. This is really
|
||||
/// just a helper function - use the other version if you want to be fast!
|
||||
inline bool triBoxOverlap(Box3F box, Point3F a, Point3F b, Point3F c)
|
||||
{
|
||||
Point3F halfSize(box.len_x() / 2.f, box.len_y() / 2.f, box.len_z() / 2.f);
|
||||
|
||||
Point3F center;
|
||||
box.getCenter(¢er);
|
||||
|
||||
Point3F verts[3] = {a,b,c};
|
||||
|
||||
return triBoxOverlap(center, halfSize, verts);
|
||||
}
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user