added everything

This commit is contained in:
Metario
2017-04-17 06:17:10 -06:00
commit 9c6ff74f19
6121 changed files with 1625704 additions and 0 deletions

5
engine/util/fourcc.h Executable file
View 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
View 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
View 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
View 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
View 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
View 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
View 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_

18
engine/util/safeDelete.h Executable file
View File

@ -0,0 +1,18 @@
//-----------------------------------------------------------------------------
// 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_DELETE_OBJECT
#define SAFE_DELETE_OBJECT(a) if( (a) != NULL ) (a)->deleteObject(); (a) = NULL;
#undef SAFE_FREE
#define SAFE_FREE(a) if( (a) != NULL ) dFree (a); (a) = NULL;

175
engine/util/triBoxCheck.cpp Executable file
View 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
View 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(&center);
Point3F verts[3] = {a,b,c};
return triBoxOverlap(center, halfSize, verts);
}
#endif

254
engine/util/triRayCheck.cpp Executable file
View File

@ -0,0 +1,254 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Ray to triangle intersection test code originally by Tomas Akenine-M<>ller
// and Ben Trumbore.
// http://www.cs.lth.se/home/Tomas_Akenine_Moller/code/
// Ported to TGE by DAW, 2005-7-15
//-----------------------------------------------------------------------------
#include "util/triRayCheck.h"
#include "math/mPlane.h"
#define EPSILON 0.000001
#define CROSS(dest,v1,v2) \
dest[0]=v1[1]*v2[2]-v1[2]*v2[1]; \
dest[1]=v1[2]*v2[0]-v1[0]*v2[2]; \
dest[2]=v1[0]*v2[1]-v1[1]*v2[0];
#define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2])
#define SUB(dest,v1,v2) \
dest[0]=v1[0]-v2[0]; \
dest[1]=v1[1]-v2[1]; \
dest[2]=v1[2]-v2[2];
bool intersect_triangle(Point3F orig, Point3F dir,
Point3F vert0, Point3F vert1, Point3F vert2,
F32& t, F32& u, F32& v)
{
Point3F edge1, edge2, tvec, pvec, qvec;
F32 det,inv_det;
/* find vectors for two edges sharing vert0 */
edge1.x = vert1.x - vert0.x;
edge1.y = vert1.y - vert0.y;
edge1.z = vert1.z - vert0.z;
edge2.x = vert2.x - vert0.x;
edge2.y = vert2.y - vert0.y;
edge2.z = vert2.z - vert0.z;
/* begin calculating determinant - also used to calculate U parameter */
//CROSS(pvec, dir, edge2);
mCross(dir, edge2, &pvec);
/* if determinant is near zero, ray lies in plane of triangle */
//det = DOT(edge1, pvec);
det = mDot(edge1, pvec);
#ifdef TEST_CULL /* define TEST_CULL if culling is desired */
if (det < EPSILON)
return 0;
/* calculate distance from vert0 to ray origin */
SUB(tvec, orig, vert0);
/* calculate U parameter and test bounds */
*u = DOT(tvec, pvec);
if (*u < 0.0 || *u > det)
return 0;
/* prepare to test V parameter */
CROSS(qvec, tvec, edge1);
/* calculate V parameter and test bounds */
*v = DOT(dir, qvec);
if (*v < 0.0 || *u + *v > det)
return 0;
/* calculate t, scale parameters, ray intersects triangle */
*t = DOT(edge2, qvec);
inv_det = 1.0 / det;
*t *= inv_det;
*u *= inv_det;
*v *= inv_det;
#else /* the non-culling branch */
if (det > -EPSILON && det < EPSILON)
return false;
inv_det = 1.0 / det;
/* calculate distance from vert0 to ray origin */
//SUB(tvec, orig, vert0);
tvec.x = orig.x - vert0.x;
tvec.y = orig.y - vert0.y;
tvec.z = orig.z - vert0.z;
/* calculate U parameter and test bounds */
// *u = DOT(tvec, pvec) * inv_det;
u = mDot(tvec, pvec) * inv_det;
if (u < 0.0 || u > 1.0)
return false;
/* prepare to test V parameter */
//CROSS(qvec, tvec, edge1);
mCross(tvec, edge1, &qvec);
/* calculate V parameter and test bounds */
// *v = DOT(dir, qvec) * inv_det;
v = mDot(dir, qvec) * inv_det;
if (v < 0.0 || u + v > 1.0)
return false;
/* calculate t, ray intersects triangle */
// *t = DOT(edge2, qvec) * inv_det;
t = mDot(edge2, qvec) * inv_det;
#endif
return true;
}
//*** Taken from TSE, and based on the above
bool castRayTriangle(Point3F orig, Point3F dir,
Point3F vert0, Point3F vert1, Point3F vert2,
F32 &t, Point2F &bary)
{
Point3F tvec, qvec;
// Find vectors for two edges sharing vert0
const Point3F edge1 = vert1 - vert0;
const Point3F edge2 = vert2 - vert0;
// Begin calculating determinant - also used to calculate U parameter.
const Point3F pvec = mCross(dir, edge2);
// If determinant is near zero, ray lies in plane of triangle.
const F32 det = mDot(edge1, pvec);
if (det > 0.00001)
{
// calculate distance from vert0 to ray origin
tvec = orig - vert0;
// calculate U parameter and test bounds
bary.x = mDot(tvec, pvec); // bary.x is really bary.u...
if (bary.x < 0.0 || bary.x > det)
return false;
// prepare to test V parameter
qvec = mCross(tvec, edge1);
// calculate V parameter and test bounds
bary.y = mDot(dir, qvec); // bary.y is really bary.v
if (bary.y < 0.0 || (bary.x + bary.y) > det)
return false;
}
else if(det < -0.00001)
{
// calculate distance from vert0 to ray origin
tvec = orig - vert0;
// calculate U parameter and test bounds
bary.x = mDot(tvec, pvec);
if (bary.x > 0.0 || bary.x < det)
return false;
// prepare to test V parameter
qvec = mCross(tvec, edge1);
// calculate V parameter and test bounds
bary.y = mDot(dir, qvec);
if (bary.y > 0.0 || (bary.x + bary.y) < det)
return false;
}
else
return false; // ray is parallel to the plane of the triangle.
const F32 inv_det = 1.0 / det;
// calculate t, ray intersects triangle
t = mDot(edge2, qvec) * inv_det;
bary *= inv_det;
//AssertFatal((t >= 0.f && t <=1.f), "AtlasGeomTracer::castRayTriangle - invalid t!");
// Hack, check the math here!
return (t >= 0.f && t <=1.f);
}
//--------------------------------------------------------
//--------------------------------------------------------
// JK: faster ray->convexHull test - taken from TSMesh...
//
// Used by lighting system...
//
bool castRayBrush(const Point3F &start, const Point3F &end,
PlaneF *planes, U32 planeCount)
{
// F32 startTime = -0.01f;
F32 startNum = -0.01f;
F32 startDen = 1.00f;
// F32 endTime = 1.01f;
F32 endNum = 1.01f;
F32 endDen = 1.00f;
S32 curPlane = 0;
U32 curMaterial = 0;
bool found = false;
bool tmpFound;
S32 tmpPlane;
F32 sgn = -1.0f;
F32 * pnum = &startNum;
F32 * pden = &startDen;
S32 * pplane = &curPlane;
bool * pfound = &found;
for (S32 i=0; i<planeCount; i++)
{
// if start & end outside, no collision
// if start & end inside, continue
// if start outside, end inside, or visa versa, find intersection of line with plane
// then update intersection of line with hull (using startTime and endTime)
F32 dot1 = mDot(planes[i],start) + planes[i].d;
F32 dot2 = mDot(planes[i],end) + planes[i].d;
if (dot1*dot2>0.0f)
{
// same side of the plane...which side -- dot==0 considered inside
if (dot1>0.0f)
// start and end outside of this plane, no collision
return false;
// start and end inside plane, continue
continue;
}
AssertFatal(dot1/(dot1-dot2)>=0.0f && dot1/(dot1-dot2)<=1.0f,"TSMesh::castRay (1)");
// find intersection (time) with this plane...
// F32 time = dot1 / (dot1-dot2);
F32 num = mFabs(dot1);
F32 den = mFabs(dot1-dot2);
if (sgn*dot1>=0)
{
sgn *= -1.0f;
pnum = (F32*) ((dsize_t)pnum ^ (dsize_t)&endNum ^ (dsize_t)&startNum);
pden = (F32*) ((dsize_t)pden ^ (dsize_t)&endDen ^ (dsize_t)&startDen);
pplane = (S32*) ((dsize_t)pplane ^ (dsize_t)&tmpPlane ^ (dsize_t)&curPlane);
pfound = (bool*) ((dsize_t)pfound ^ (dsize_t)&tmpFound ^ (dsize_t)&found);
}
bool noCollision = num*endDen*sgn<endNum*den*sgn && num*startDen*sgn<startNum*den*sgn;
if (num * *pden * sgn < *pnum * den * sgn && !noCollision)
{
*pnum = num;
*pden = den;
*pplane = i;
*pfound = true;
}
else if (noCollision)
return false;
}
return found;
}

25
engine/util/triRayCheck.h Executable file
View File

@ -0,0 +1,25 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Ray to triangle intersection test code originally by Tomas Akenine-M<>ller
// and Ben Trumbore.
// http://www.cs.lth.se/home/Tomas_Akenine_Moller/code/
// Ported to TGE by DAW, 2005-7-15
//-----------------------------------------------------------------------------
#ifndef _TRIRAYCHECK_H_
#define _TRIRAYCHECK_H_
#include "math/mPoint.h"
bool intersect_triangle(Point3F orig, Point3F dir,
Point3F vert0, Point3F vert1, Point3F vert2,
F32& t, F32& u, F32& v);
//*** Taken from TSE, but based on the above
bool castRayTriangle(Point3F orig, Point3F dir, Point3F vert0, Point3F vert1, Point3F vert2, F32 &t, Point2F &bary);
#endif // _TRIRAYCHECK_H_