added everything
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_
|
18
engine/util/safeDelete.h
Executable file
18
engine/util/safeDelete.h
Executable 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
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
|
254
engine/util/triRayCheck.cpp
Executable file
254
engine/util/triRayCheck.cpp
Executable 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
25
engine/util/triRayCheck.h
Executable 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_
|
Reference in New Issue
Block a user