mirror of
https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git
synced 2025-07-18 11:19:10 +00:00
Initial Commit of CyanWorlds.com Engine Open Source Client/Plugin
This commit is contained in:
@ -0,0 +1,4 @@
|
||||
|
||||
Collection of geometry intersection routines between various primitives, e.g. TriList/Box, Box/Box, Box/Sphere, etc.
|
||||
|
||||
Mesh types will often convert themselves to appropriate type, and call from this lib when queried for intersection.
|
@ -0,0 +1,685 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#include "hsTypes.h"
|
||||
#include "hsGeometry3.h"
|
||||
#include "plClosest.h"
|
||||
#include "hsFastMath.h"
|
||||
|
||||
|
||||
static const hsScalar kRealSmall = 1.e-5f;
|
||||
|
||||
// Find the closest point on a line (or segment) to a point.
|
||||
UInt32 plClosest::PointOnLine(const hsPoint3& p0,
|
||||
const hsPoint3& p1, const hsVector3& v1,
|
||||
hsPoint3& cp,
|
||||
UInt32 clamp)
|
||||
{
|
||||
hsScalar invV1Sq = v1.MagnitudeSquared();
|
||||
// v1 is also zero length. The two input points are the only options for output.
|
||||
if( invV1Sq < kRealSmall )
|
||||
{
|
||||
cp = p1;
|
||||
return kClamp;
|
||||
}
|
||||
hsScalar t = v1.InnerProduct(p0 - p1) / invV1Sq;
|
||||
cp = p1;
|
||||
// clamp to the ends of segment v1.
|
||||
if( (clamp & kClampLower1) && (t < 0) )
|
||||
{
|
||||
return kClampLower1;
|
||||
}
|
||||
if( (clamp & kClampUpper1) && (t > 1.f) )
|
||||
{
|
||||
cp += v1;
|
||||
return kClampUpper1;
|
||||
}
|
||||
|
||||
cp += v1 * t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Find closest points to each other from two lines (or segments).
|
||||
UInt32 plClosest::PointsOnLines(const hsPoint3& p0, const hsVector3& v0,
|
||||
const hsPoint3& p1, const hsVector3& v1,
|
||||
hsPoint3& cp0, hsPoint3& cp1,
|
||||
UInt32 clamp)
|
||||
{
|
||||
hsScalar invV0Sq = v0.MagnitudeSquared();
|
||||
// First handle degenerate cases.
|
||||
// v0 is zero length. Resolves to finding closest point on p1+v1 to p0
|
||||
if( invV0Sq < kRealSmall )
|
||||
{
|
||||
cp0 = p0;
|
||||
return kClamp0 | PointOnLine(p0, p1, v1, cp1, clamp);
|
||||
}
|
||||
invV0Sq = 1.f / invV0Sq;
|
||||
|
||||
// The real thing here, two non-zero length segments. (v1 can
|
||||
// be zero length, it doesn't affect the math like |v0|=0 does,
|
||||
// so we don't even bother to check. Only means maybe doing extra
|
||||
// work, since we're using segment-segment math when all we really
|
||||
// need is point-segment.)
|
||||
|
||||
// The parameterized points for along each of the segments are
|
||||
// P(t0) = p0 + v0*t0
|
||||
// P(t1) = p1 + v1*t1
|
||||
//
|
||||
// The closest point on p0+v0 to P(t1) is:
|
||||
// cp0 = p0 + ((P(t1) - p0) dot v0) * v0 / ||v0|| ||x|| is mag squared here
|
||||
// cp0 = p0 + v0*t0 => t0 = ((P(t1) - p0) dot v0 ) / ||v0||
|
||||
// t0 = ((p1 + v1*t1 - p0) dot v0) / ||v0||
|
||||
//
|
||||
// The distance squared from P(t1) to cp0 is:
|
||||
// (cp0 - P(t1)) dot (cp0 - P(t1))
|
||||
//
|
||||
// This expands out to:
|
||||
//
|
||||
// CV0 dot CV0 + 2 CV0 dot DV0 * t1 + (DV0 dot DV0) * t1^2
|
||||
//
|
||||
// where
|
||||
//
|
||||
// CV0 = p0 - p1 + ((p1 - p0) dot v0) / ||v0||) * v0 == vector from p1 to closest point on p0+v0
|
||||
// and
|
||||
// DV0 = ((v1 dot v0) / ||v0||) * v0 - v1 == ortho divergence vector of v1 from v0 negated.
|
||||
//
|
||||
// Taking the first derivative to find the local minimum of the function gives
|
||||
//
|
||||
// t1 = - (CV0 dot DV0) / (DV0 dot DV0)
|
||||
// and
|
||||
// t0 = ((p1 - v1 * t1 - p0) dot v0) / ||v0||
|
||||
//
|
||||
// which seems kind of obvious in retrospect.
|
||||
|
||||
hsVector3 p0subp1(&p0, &p1);
|
||||
|
||||
hsVector3 CV0 = p0subp1;
|
||||
CV0 += v0 * p0subp1.InnerProduct(v0) * -invV0Sq;
|
||||
|
||||
hsVector3 DV0 = v0 * (v1.InnerProduct(v0) * invV0Sq) - v1;
|
||||
|
||||
// Check for the vectors v0 and v1 being parallel, in which case
|
||||
// following the lines won't get us to any closer point.
|
||||
hsScalar DV0dotDV0 = DV0.InnerProduct(DV0);
|
||||
if( DV0dotDV0 < kRealSmall )
|
||||
{
|
||||
// If neither is clamped, return any two corresponding points.
|
||||
// If one is clamped, return closest points in its clamp range.
|
||||
// If both are clamped, well, both are clamped. The distance between
|
||||
// points will no longer be the distance between lines.
|
||||
// In any case, the distance between the points should be correct.
|
||||
UInt32 clamp1 = PointOnLine(p0, p1, v1, cp1, clamp);
|
||||
UInt32 clamp0 = PointOnLine(cp1, p0, v0, cp0, clamp >> 1);
|
||||
return clamp1 | (clamp0 << 1);
|
||||
}
|
||||
|
||||
UInt32 retVal = 0;
|
||||
|
||||
hsScalar t1 = - (CV0.InnerProduct(DV0)) / DV0dotDV0;
|
||||
if( (clamp & kClampLower1) && (t1 <= 0) )
|
||||
{
|
||||
t1 = 0;
|
||||
retVal |= kClampLower1;
|
||||
}
|
||||
else if( (clamp & kClampUpper1) && (t1 >= 1.f) )
|
||||
{
|
||||
t1 = 1.f;
|
||||
retVal |= kClampUpper1;
|
||||
}
|
||||
|
||||
hsScalar t0 = v0.InnerProduct(p0subp1 - v1 * t1) * -invV0Sq;
|
||||
cp0 = p0;
|
||||
if( (clamp & kClampUpper0) && (t0 >= 1.f) )
|
||||
{
|
||||
cp0 += v0;
|
||||
retVal |= kClampUpper0;
|
||||
}
|
||||
else if( !(clamp & kClampLower0) || (t0 > 0) )
|
||||
{
|
||||
cp0 += v0 * t0;
|
||||
}
|
||||
else
|
||||
{
|
||||
retVal |= kClampLower0;
|
||||
}
|
||||
|
||||
// If we clamped t0, we need to recalc t1 because the original
|
||||
// calculation of t1 was based on an infinite p0+v0.
|
||||
if( retVal & kClamp0 )
|
||||
{
|
||||
t1 = v1.InnerProduct(cp0 - p1) / v1.MagnitudeSquared();
|
||||
retVal &= ~kClamp1;
|
||||
if( (clamp & kClampLower1) && (t1 <= 0) )
|
||||
{
|
||||
t1 = 0;
|
||||
retVal |= kClampLower1;
|
||||
}
|
||||
else if( (clamp & kClampUpper1) && (t1 >= 1.f) )
|
||||
{
|
||||
t1 = 1.f;
|
||||
retVal |= kClampUpper1;
|
||||
}
|
||||
}
|
||||
|
||||
cp1 = p1;
|
||||
cp1 += v1 * t1;
|
||||
|
||||
return retVal;;
|
||||
}
|
||||
|
||||
hsBool plClosest::PointOnSphere(const hsPoint3& p0,
|
||||
const hsPoint3& center, hsScalar rad,
|
||||
hsPoint3& cp)
|
||||
{
|
||||
hsVector3 del(&p0, ¢er);
|
||||
hsScalar dist = hsFastMath::InvSqrtAppr(del.MagnitudeSquared());
|
||||
dist *= rad;
|
||||
del *= dist;
|
||||
cp = center;
|
||||
cp += del;
|
||||
return dist <= 1.f;
|
||||
}
|
||||
|
||||
hsBool plClosest::PointOnBox(const hsPoint3& p0,
|
||||
const hsPoint3& corner,
|
||||
const hsVector3& axis0,
|
||||
const hsVector3& axis1,
|
||||
const hsVector3& axis2,
|
||||
hsPoint3& cp)
|
||||
{
|
||||
UInt32 clamps = 0;
|
||||
hsPoint3 currPt = corner;
|
||||
clamps |= PointOnLine(p0, currPt, axis0, cp, kClamp);
|
||||
currPt = cp;
|
||||
clamps |= PointOnLine(p0, currPt, axis1, cp, kClamp);
|
||||
currPt = cp;
|
||||
clamps |= PointOnLine(p0, currPt, axis2, cp, kClamp);
|
||||
|
||||
return !clamps;
|
||||
}
|
||||
|
||||
hsBool plClosest::PointOnSphere(const hsPoint3& p0, const hsVector3& v0,
|
||||
const hsPoint3& center, hsScalar rad,
|
||||
hsPoint3& cp,
|
||||
UInt32 clamp)
|
||||
{
|
||||
// Does the line hit the sphere? If it does, we return the entry point in cp,
|
||||
// otherwise we find the closest point on the sphere to the line.
|
||||
/*
|
||||
((p0 + v0*t) - center)^2 = rad
|
||||
v0*v0 * t*t + 2 * v0*t * (p0-c) + (p0-c)^2 - rad = 0
|
||||
|
||||
t = (-2 * v0*(p0-c) +- sqrt(4 * (v0*(p0-c))^2 - 4 * v0*v0 * ((p0-c)^2 - rad) / 2 * v0 * v0
|
||||
|
||||
t = (-v0*(p0-c) +- sqrt((v0*(p0-c))^2 - v0*v0 * ((p0-c)^2 - rad) / v0 * v0
|
||||
|
||||
So, line hits the sphere if
|
||||
(v0*(p0-c))^2 > v0*v0 * ((p0-c)^2 - rad)
|
||||
|
||||
If clamped, need additional checks on t before returning true
|
||||
|
||||
If line doesn't hit the sphere, we find the closest point on the line
|
||||
to the center of the sphere, and return the intersection of the segment
|
||||
connecting that point and the center with the sphere.
|
||||
*/
|
||||
hsScalar termA = v0.InnerProduct(v0);
|
||||
if( termA < kRealSmall )
|
||||
{
|
||||
return PointOnSphere(p0, center, rad, cp);
|
||||
}
|
||||
hsVector3 p0Subc(&p0, ¢er);
|
||||
hsScalar termB = v0.InnerProduct(p0Subc);
|
||||
hsScalar termC = p0Subc.InnerProduct(p0Subc) - rad;
|
||||
hsScalar disc = termB * termB - 4 * termA * termC;
|
||||
if( disc >= 0 )
|
||||
{
|
||||
disc = hsSquareRoot(disc);
|
||||
hsScalar t = (-termB - disc) / (2.f * termA);
|
||||
if( (t < 0) && (clamp & kClampLower0) )
|
||||
{
|
||||
hsScalar tOut = (-termB + disc) / (2.f * termA);
|
||||
if( tOut < 0 )
|
||||
{
|
||||
// Both isects are before beginning of clamped line.
|
||||
cp = p0;
|
||||
cp += v0 * tOut;
|
||||
return false;
|
||||
}
|
||||
if( (tOut > 1.f) && (clamp & kClampUpper0) )
|
||||
{
|
||||
// The segment is entirely within the sphere. Take the closer end.
|
||||
if( -t < tOut - 1.f )
|
||||
{
|
||||
cp = p0;
|
||||
cp += v0 * t;
|
||||
}
|
||||
else
|
||||
{
|
||||
cp = p0;
|
||||
cp += v0 * tOut;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// We pierce the sphere from inside.
|
||||
cp = p0;
|
||||
cp += v0 * tOut;
|
||||
return true;
|
||||
}
|
||||
cp = p0;
|
||||
cp += v0 * t;
|
||||
if( (t > 1.f) && (clamp & kClampUpper0) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Okay, missed the sphere, find closest point.
|
||||
hsPoint3 lp;
|
||||
PointOnLine(center, p0, v0, lp, clamp);
|
||||
PointOnSphere(lp, center, rad, cp);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
hsBool plClosest::PointOnBox(const hsPoint3& p0, const hsVector3& v0,
|
||||
const hsPoint3& corner,
|
||||
const hsVector3& axis0,
|
||||
const hsVector3& axis1,
|
||||
const hsVector3& axis2,
|
||||
hsPoint3& cp,
|
||||
UInt32 clamp)
|
||||
{
|
||||
UInt32 clampRes = 0;
|
||||
|
||||
hsPoint3 cp0, cp1;
|
||||
hsPoint3 currPt = corner;
|
||||
|
||||
clampRes |= PointsOnLines(p0, v0, currPt, axis0, cp0, cp1, clamp);
|
||||
currPt = cp1;
|
||||
|
||||
clampRes |= PointsOnLines(p0, v0, currPt, axis1, cp0, cp1, clamp);
|
||||
currPt = cp1;
|
||||
|
||||
clampRes |= PointsOnLines(p0, v0, currPt, axis2, cp0, cp1, clamp);
|
||||
currPt = cp1;
|
||||
|
||||
return !clampRes;
|
||||
}
|
||||
|
||||
hsBool plClosest::PointOnPlane(const hsPoint3& p0,
|
||||
const hsPoint3& pPln, const hsVector3& n,
|
||||
hsPoint3& cp)
|
||||
{
|
||||
/*
|
||||
p' = p - ((p-pPln)*n)/|n| * n/|n|
|
||||
p' = p + ((pPln-p)*n) * n / |n|^2
|
||||
*/
|
||||
hsScalar invNLen = hsFastMath::InvSqrt(n.MagnitudeSquared());
|
||||
|
||||
hsScalar nDotp = n.InnerProduct(pPln - p0);
|
||||
cp = p0 + n * (nDotp * invNLen);
|
||||
|
||||
return nDotp >= 0;
|
||||
}
|
||||
|
||||
hsBool plClosest::PointOnPlane(const hsPoint3& p0, const hsVector3& v0,
|
||||
const hsPoint3& pPln, const hsVector3& n,
|
||||
hsPoint3& cp,
|
||||
UInt32 clamp)
|
||||
{
|
||||
/*
|
||||
p0 + v0*t is on plane, i.e.
|
||||
(p0 + v0*t) * n = pPln * n
|
||||
|
||||
p0 * n + v0 * n * t = pPln * n
|
||||
v0 * n * t = (pPln - p0) * n
|
||||
t = (pPln - p0) * n / (v0 * n)
|
||||
|
||||
Then clamp appropriately, garnish, and serve with wild rice.
|
||||
*/
|
||||
hsBool retVal = true;
|
||||
hsScalar pDotn = n.InnerProduct(pPln - p0);
|
||||
hsScalar v0Dotn = n.InnerProduct(v0);
|
||||
if( (v0Dotn < -kRealSmall) || (v0Dotn > kRealSmall) )
|
||||
{
|
||||
hsScalar t = pDotn / v0Dotn;
|
||||
|
||||
if( (clamp & kClampLower) && (t < 0) )
|
||||
{
|
||||
t = 0;
|
||||
retVal = false;
|
||||
}
|
||||
else if( (clamp & kClampUpper) && (t > 1.f) )
|
||||
{
|
||||
t = 1.f;
|
||||
retVal = false;
|
||||
}
|
||||
cp = p0;
|
||||
cp += v0 * t;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
cp = p0 + v0 * 0.5f;
|
||||
retVal = (pDotn > -kRealSmall) && (pDotn < kRealSmall);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
hsBool plClosest::PointBetweenBoxes(const hsPoint3& aCorner,
|
||||
const hsVector3& aAxis0,
|
||||
const hsVector3& aAxis1,
|
||||
const hsVector3& aAxis2,
|
||||
const hsPoint3& bCorner,
|
||||
const hsVector3& bAxis0,
|
||||
const hsVector3& bAxis1,
|
||||
const hsVector3& bAxis2,
|
||||
hsPoint3& cp0, hsPoint3& cp1)
|
||||
{
|
||||
const hsVector3* aAxes[3] = { &aAxis0, &aAxis1, &aAxis2 };
|
||||
const hsVector3* bAxes[3] = { &bAxis0, &bAxis1, &bAxis2 };
|
||||
|
||||
return PointBetweenBoxes(aCorner, aAxes, bCorner, bAxes, cp0, cp1);
|
||||
}
|
||||
|
||||
#if 0 // TRASH THIS
|
||||
hsBool plClosest::PointBetweenBoxes(const hsPoint3& aCorner,
|
||||
const hsVector3* aAxes[3],
|
||||
const hsPoint3& bCorner,
|
||||
const hsVector3* bAxes[3],
|
||||
hsPoint3& cp0, hsPoint3& cp1)
|
||||
{
|
||||
hsPoint3 aCurrPt = aCorner;
|
||||
hsPoint3 bCurrPt = bCorner;
|
||||
|
||||
hsPoint3 bStartPt[3];
|
||||
bStartPt[0] = bStartPt[1] = bStartPt[2] = bCorner;
|
||||
|
||||
hsBool retVal = true;
|
||||
int i, j;
|
||||
for( i = 0; i < 3; i++ )
|
||||
{
|
||||
hsPoint3 aBestPt;
|
||||
hsPoint3 bBestPt;
|
||||
|
||||
hsScalar minDistSq = 1.e33f;
|
||||
for( j = 0; j < 3; j++ )
|
||||
{
|
||||
hsPoint3 aNextPt, bNextPt;
|
||||
PointsOnLines(aCurrPt, *aAxes[i],
|
||||
bStartPt[j], *bAxes[j],
|
||||
aNextPt, bNextPt,
|
||||
plClosest::kClamp);
|
||||
|
||||
hsScalar distSq = hsVector3(&aNextPt, &bNextPt).MagnitudeSquared();
|
||||
if( distSq < minDistSq )
|
||||
{
|
||||
aBestPt = aNextPt;
|
||||
bBestPt = bNextPt;
|
||||
|
||||
if( distSq < kRealSmall )
|
||||
retVal = true;
|
||||
|
||||
minDistSq = distSq;
|
||||
}
|
||||
hsVector3 bMove(&bNextPt, &bStartPt[j]);
|
||||
int k;
|
||||
for( k = 0; k < 3; k++ )
|
||||
{
|
||||
if( k != j )
|
||||
bStartPt[k] += bMove;
|
||||
}
|
||||
}
|
||||
aCurrPt = aBestPt;
|
||||
bCurrPt = bBestPt;
|
||||
}
|
||||
cp0 = aCurrPt;
|
||||
cp1 = bCurrPt;
|
||||
|
||||
return retVal;
|
||||
}
|
||||
#elif 0 // TRASH THIS
|
||||
|
||||
hsBool plClosest::PointBetweenBoxes(const hsPoint3& aCorner,
|
||||
const hsVector3* aAxes[3],
|
||||
const hsPoint3& bCorner,
|
||||
const hsVector3* bAxes[3],
|
||||
hsPoint3& cp0, hsPoint3& cp1)
|
||||
{
|
||||
/*
|
||||
Six combinations to try to go through every possible
|
||||
combination of axes from A and B
|
||||
|
||||
00 00 01 01 02 02
|
||||
11 12 12 10 10 11
|
||||
22 21 20 22 21 20
|
||||
*/
|
||||
|
||||
int bIdx0 = 0;
|
||||
int bIdx1 = 1;
|
||||
int bIdx2 = 2;
|
||||
|
||||
hsPoint3 aBestPt, bBestPt;
|
||||
hsScalar minDistSq = 1.e33f;
|
||||
|
||||
hsBool retVal = false;
|
||||
|
||||
int i;
|
||||
for( i = 0; i < 6; i++ )
|
||||
{
|
||||
hsPoint3 aCurrPt = aCorner;
|
||||
hsPoint3 bCurrPt = bCorner;
|
||||
|
||||
hsPoint3 aNextPt, bNextPt;
|
||||
PointsOnLines(aCurrPt, *aAxes[0],
|
||||
bCurrPt, *bAxes[bIdx0],
|
||||
aNextPt, bNextPt,
|
||||
plClosest::kClamp);
|
||||
|
||||
aCurrPt = aNextPt;
|
||||
bCurrPt = bNextPt;
|
||||
|
||||
PointsOnLines(aCurrPt, *aAxes[1],
|
||||
bCurrPt, *bAxes[bIdx1],
|
||||
aNextPt, bNextPt,
|
||||
plClosest::kClamp);
|
||||
|
||||
aCurrPt = aNextPt;
|
||||
bCurrPt = bNextPt;
|
||||
|
||||
PointsOnLines(aCurrPt, *aAxes[2],
|
||||
bCurrPt, *bAxes[bIdx2],
|
||||
aNextPt, bNextPt,
|
||||
plClosest::kClamp);
|
||||
|
||||
|
||||
hsScalar distSq = hsVector3(&aNextPt, &bNextPt).MagnitudeSquared();
|
||||
if( distSq < minDistSq )
|
||||
{
|
||||
aBestPt = aNextPt;
|
||||
bBestPt = bNextPt;
|
||||
|
||||
if( distSq < kRealSmall )
|
||||
retVal = true;
|
||||
|
||||
minDistSq = distSq;
|
||||
}
|
||||
|
||||
if( i & 0x1 )
|
||||
{
|
||||
bIdx0++;
|
||||
bIdx1 = bIdx0 < 2 ? bIdx0+1 : 0;
|
||||
bIdx2 = bIdx1 < 2 ? bIdx1+1 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int t = bIdx1;
|
||||
bIdx1 = bIdx2;
|
||||
bIdx2 = t;
|
||||
}
|
||||
}
|
||||
cp0 = aBestPt;
|
||||
cp1 = bBestPt;
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
#else // TRASH THIS
|
||||
|
||||
hsBool plClosest::PointBetweenBoxes(const hsPoint3& aCorner,
|
||||
const hsVector3* aAxes[3],
|
||||
const hsPoint3& bCorner,
|
||||
const hsVector3* bAxes[3],
|
||||
hsPoint3& cp0, hsPoint3& cp1)
|
||||
{
|
||||
/*
|
||||
Six combinations to try to go through every possible
|
||||
combination of axes from A and B
|
||||
|
||||
00 00 01 01 02 02
|
||||
11 12 12 10 10 11
|
||||
22 21 20 22 21 20
|
||||
*/
|
||||
|
||||
struct trial {
|
||||
int aIdx[3];
|
||||
int bIdx[3];
|
||||
} trials[36];
|
||||
|
||||
|
||||
int tNext = 0;
|
||||
int k,l;
|
||||
for( k = 0; k < 3; k++ )
|
||||
{
|
||||
for( l = 0; l < 3; l++ )
|
||||
{
|
||||
int kPlus = k < 2 ? k+1 : 0;
|
||||
int kPlusPlus = kPlus < 2 ? kPlus+1 : 0;
|
||||
|
||||
int lPlus = l < 2 ? l+1 : 0;
|
||||
int lPlusPlus = lPlus < 2 ? lPlus+1 : 0;
|
||||
|
||||
trials[tNext].aIdx[0] = k;
|
||||
trials[tNext].bIdx[0] = l;
|
||||
|
||||
trials[tNext].aIdx[1] = kPlus;
|
||||
trials[tNext].bIdx[1] = lPlus;
|
||||
|
||||
trials[tNext].aIdx[2] = kPlusPlus;
|
||||
trials[tNext].bIdx[2] = lPlusPlus;
|
||||
|
||||
tNext++;
|
||||
|
||||
trials[tNext].aIdx[0] = k;
|
||||
trials[tNext].bIdx[0] = l;
|
||||
|
||||
trials[tNext].aIdx[1] = kPlusPlus;
|
||||
trials[tNext].bIdx[1] = lPlusPlus;
|
||||
|
||||
trials[tNext].aIdx[2] = kPlus;
|
||||
trials[tNext].bIdx[2] = lPlus;
|
||||
|
||||
tNext++;
|
||||
|
||||
trials[tNext].aIdx[0] = k;
|
||||
trials[tNext].bIdx[0] = l;
|
||||
|
||||
trials[tNext].aIdx[1] = kPlus;
|
||||
trials[tNext].bIdx[1] = lPlusPlus;
|
||||
|
||||
trials[tNext].aIdx[2] = kPlusPlus;
|
||||
trials[tNext].bIdx[2] = lPlus;
|
||||
|
||||
tNext++;
|
||||
|
||||
trials[tNext].aIdx[0] = k;
|
||||
trials[tNext].bIdx[0] = l;
|
||||
|
||||
trials[tNext].aIdx[1] = kPlusPlus;
|
||||
trials[tNext].bIdx[1] = lPlus;
|
||||
|
||||
trials[tNext].aIdx[2] = kPlus;
|
||||
trials[tNext].bIdx[2] = lPlusPlus;
|
||||
|
||||
tNext++;
|
||||
}
|
||||
}
|
||||
|
||||
hsPoint3 aBestPt, bBestPt;
|
||||
hsScalar minDistSq = 1.e33f;
|
||||
|
||||
hsBool retVal = false;
|
||||
|
||||
int i;
|
||||
for( i = 0; i < 36; i++ )
|
||||
{
|
||||
hsPoint3 aCurrPt = aCorner;
|
||||
hsPoint3 bCurrPt = bCorner;
|
||||
|
||||
hsPoint3 aNextPt, bNextPt;
|
||||
PointsOnLines(aCurrPt, *aAxes[trials[i].aIdx[0]],
|
||||
bCurrPt, *bAxes[trials[i].bIdx[0]],
|
||||
aNextPt, bNextPt,
|
||||
plClosest::kClamp);
|
||||
|
||||
aCurrPt = aNextPt;
|
||||
bCurrPt = bNextPt;
|
||||
|
||||
PointsOnLines(aCurrPt, *aAxes[trials[i].aIdx[1]],
|
||||
bCurrPt, *bAxes[trials[i].bIdx[1]],
|
||||
aNextPt, bNextPt,
|
||||
plClosest::kClamp);
|
||||
|
||||
aCurrPt = aNextPt;
|
||||
bCurrPt = bNextPt;
|
||||
|
||||
PointsOnLines(aCurrPt, *aAxes[trials[i].aIdx[2]],
|
||||
bCurrPt, *bAxes[trials[i].bIdx[2]],
|
||||
aNextPt, bNextPt,
|
||||
plClosest::kClamp);
|
||||
|
||||
|
||||
hsScalar distSq = hsVector3(&aNextPt, &bNextPt).MagnitudeSquared();
|
||||
if( distSq < minDistSq )
|
||||
{
|
||||
aBestPt = aNextPt;
|
||||
bBestPt = bNextPt;
|
||||
|
||||
if( distSq < kRealSmall )
|
||||
retVal = true;
|
||||
|
||||
minDistSq = distSq;
|
||||
}
|
||||
|
||||
}
|
||||
cp0 = aBestPt;
|
||||
cp1 = bBestPt;
|
||||
|
||||
return retVal;
|
||||
}
|
||||
#endif // TRASH THIS
|
@ -0,0 +1,122 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#ifndef plIsect_inc
|
||||
#define plIsect_inc
|
||||
|
||||
struct hsPoint3;
|
||||
struct hsVector3;
|
||||
|
||||
|
||||
class plClosest
|
||||
{
|
||||
public:
|
||||
enum plClosestClampFlags
|
||||
{
|
||||
kClampLower0 = 0x1,
|
||||
kClampUpper0 = 0x2,
|
||||
kClamp0 = kClampLower0 | kClampUpper0,
|
||||
kClampLower1 = 0x4,
|
||||
kClampLower = kClampLower0 | kClampLower1,
|
||||
kClampUpper1 = 0x8,
|
||||
kClampUpper = kClampUpper0 | kClampUpper1,
|
||||
kClamp1 = kClampLower1 | kClampUpper1,
|
||||
kClamp = kClamp0 | kClamp1
|
||||
};
|
||||
|
||||
|
||||
// Return clamp flags for where clamped
|
||||
static UInt32 PointOnLine(const hsPoint3& p0, // Point
|
||||
const hsPoint3& p1, const hsVector3& v1, // Line
|
||||
hsPoint3& cp, // Output closest point on line to p0
|
||||
UInt32 clamp); // Clamp on ends of segment (use Lower1/Upper1)
|
||||
|
||||
// Return clamp flags for where clamped
|
||||
static UInt32 PointsOnLines(const hsPoint3& p0, const hsVector3& v0,// First line
|
||||
const hsPoint3& p1, const hsVector3& v1, // Second line
|
||||
hsPoint3& cp0, // Output closest on line0 to line1
|
||||
hsPoint3& cp1, // Output closest on line1 to line0
|
||||
UInt32 clamp); // Clamp on ends
|
||||
|
||||
// Return true if p0 is inside or on sphere.
|
||||
static hsBool PointOnSphere(const hsPoint3& p0, // Point
|
||||
const hsPoint3& center, hsScalar rad, // Sphere
|
||||
hsPoint3& cp); // Output closest on sphere to p0
|
||||
|
||||
// Return true if p0 is inside box.
|
||||
static hsBool PointOnBox(const hsPoint3& p0, // Point
|
||||
const hsPoint3& corner, // Box defined by corner point and 3 (presumably but
|
||||
const hsVector3& axis0, // not required) ortho axes.
|
||||
const hsVector3& axis1,
|
||||
const hsVector3& axis2,
|
||||
hsPoint3& cp);
|
||||
|
||||
// Return true if line intersects or is inside sphere.
|
||||
static hsBool PointOnSphere(const hsPoint3& p0, const hsVector3& v0, // Line
|
||||
const hsPoint3& center, hsScalar rad, // Sphere
|
||||
hsPoint3& cp, // Output closest on sphere to p0, or entry point if line hits sphere
|
||||
UInt32 clamp);
|
||||
|
||||
// Return true if line intersects or is inside box.
|
||||
static hsBool PointOnBox(const hsPoint3& p0, const hsVector3& v0, // Line
|
||||
const hsPoint3& corner, // Box defined by corner point and 3 (presumably but
|
||||
const hsVector3& axis0, // not required) ortho axes.
|
||||
const hsVector3& axis1,
|
||||
const hsVector3& axis2,
|
||||
hsPoint3& cp,
|
||||
UInt32 clamp);
|
||||
|
||||
// Return true if point inside (negative side) of plane
|
||||
static hsBool PointOnPlane(const hsPoint3& p0,
|
||||
const hsPoint3& pPln, const hsVector3& n,
|
||||
hsPoint3& cp);
|
||||
|
||||
// Return true if line passes through plane.
|
||||
static hsBool PointOnPlane(const hsPoint3& p0, const hsVector3& v0,
|
||||
const hsPoint3& pPln, const hsVector3& n,
|
||||
hsPoint3& cp,
|
||||
UInt32 clamp);
|
||||
|
||||
// Two identical functions, just different wrapping. First version repacks
|
||||
// parameters and calls second.
|
||||
static hsBool PointBetweenBoxes(const hsPoint3& aCorner,
|
||||
const hsVector3& aAxis0,
|
||||
const hsVector3& aAxis1,
|
||||
const hsVector3& aAxis2,
|
||||
const hsPoint3& bCorner,
|
||||
const hsVector3& bAxis0,
|
||||
const hsVector3& bAxis1,
|
||||
const hsVector3& bAxis2,
|
||||
hsPoint3& cp0, hsPoint3& cp1);
|
||||
|
||||
static hsBool PointBetweenBoxes(const hsPoint3& aCorner,
|
||||
const hsVector3* aAxes[3],
|
||||
const hsPoint3& bCorner,
|
||||
const hsVector3* bAxes[3],
|
||||
hsPoint3& cp0, hsPoint3& cp1);
|
||||
};
|
||||
|
||||
#endif // plVolume_inc
|
@ -0,0 +1,96 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#include "hsTypes.h"
|
||||
#include "hsStream.h"
|
||||
|
||||
#include "plHardRegion.h"
|
||||
|
||||
#include "plgDispatch.h"
|
||||
#include "../plMessage/plRenderMsg.h"
|
||||
#include "plPipeline.h"
|
||||
|
||||
plHardRegion::plHardRegion()
|
||||
: fState(kDirty)
|
||||
{
|
||||
}
|
||||
|
||||
plHardRegion::~plHardRegion()
|
||||
{
|
||||
}
|
||||
|
||||
void plHardRegion::SetKey(plKey k)
|
||||
{
|
||||
plRegionBase::SetKey(k);
|
||||
|
||||
#if 0 // The caching of this probably isn't worth it.
|
||||
// We'll try evaluation every time first, and try
|
||||
// this later as an optimization.
|
||||
if( k )
|
||||
{
|
||||
plgDispatch::Dispatch()->RegisterForExactType(plRenderMsg::Index(), GetKey());
|
||||
}
|
||||
#endif // Caching
|
||||
}
|
||||
|
||||
void plHardRegion::Read(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
plRegionBase::Read(s, mgr);
|
||||
|
||||
fState = kDirty;
|
||||
}
|
||||
|
||||
void plHardRegion::Write(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
plRegionBase::Write(s, mgr);
|
||||
}
|
||||
|
||||
hsBool plHardRegion::CameraInside() const
|
||||
{
|
||||
if( fState & kDirty )
|
||||
{
|
||||
if( ICameraInside() )
|
||||
fState |= kCamInside;
|
||||
else
|
||||
fState &= ~kCamInside;
|
||||
fState &= ~kDirty;
|
||||
}
|
||||
return 0 != (fState & kCamInside);
|
||||
}
|
||||
|
||||
hsBool plHardRegion::MsgReceive(plMessage* msg)
|
||||
{
|
||||
plRenderMsg* rend = plRenderMsg::ConvertNoRef(msg);
|
||||
if( rend )
|
||||
{
|
||||
fState |= kDirty;
|
||||
fCamPos = rend->Pipeline()->GetViewPositionWorld();
|
||||
return true;
|
||||
}
|
||||
|
||||
return plRegionBase::MsgReceive(msg);
|
||||
}
|
||||
|
@ -0,0 +1,80 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#ifndef plHardRegion_inc
|
||||
#define plHardRegion_inc
|
||||
|
||||
#include "plRegionBase.h"
|
||||
#include "hsGeometry3.h"
|
||||
|
||||
class hsStream;
|
||||
class hsResMgr;
|
||||
class plMessage;
|
||||
|
||||
class plHardRegion : public plRegionBase
|
||||
{
|
||||
public:
|
||||
enum RefTypes {
|
||||
kSubRegion
|
||||
};
|
||||
|
||||
protected:
|
||||
enum
|
||||
{
|
||||
kDirty,
|
||||
kCamInside
|
||||
};
|
||||
|
||||
mutable UInt32 fState;
|
||||
hsPoint3 fCamPos;
|
||||
|
||||
virtual void SetKey(plKey k);
|
||||
|
||||
public:
|
||||
plHardRegion();
|
||||
virtual ~plHardRegion();
|
||||
|
||||
CLASSNAME_REGISTER( plHardRegion );
|
||||
GETINTERFACE_ANY( plHardRegion, plRegionBase );
|
||||
|
||||
virtual hsBool IsInside(const hsPoint3& pos) const { return IIsInside(pos); }
|
||||
virtual hsBool CameraInside() const;
|
||||
|
||||
virtual void SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l) = 0;
|
||||
|
||||
virtual Int32 GetNumProperties() const { return 1; } // This is stupid.
|
||||
|
||||
|
||||
virtual hsBool MsgReceive(plMessage* msg);
|
||||
|
||||
virtual void Read(hsStream* stream, hsResMgr* mgr);
|
||||
virtual void Write(hsStream* stream, hsResMgr* mgr);
|
||||
|
||||
virtual hsBool IIsInside(const hsPoint3& pos) const = 0;
|
||||
virtual hsBool ICameraInside() const = 0;
|
||||
};
|
||||
|
||||
#endif // plHardRegion_inc
|
@ -0,0 +1,152 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#include "hsTypes.h"
|
||||
#include "plHardRegionPlanes.h"
|
||||
|
||||
#include "hsStream.h"
|
||||
#include "hsGeometry3.h"
|
||||
#include "hsFastMath.h"
|
||||
#include "hsMatrix44.h"
|
||||
|
||||
|
||||
plHardRegionPlanes::plHardRegionPlanes()
|
||||
{
|
||||
}
|
||||
|
||||
plHardRegionPlanes::~plHardRegionPlanes()
|
||||
{
|
||||
}
|
||||
|
||||
hsBool plHardRegionPlanes::IIsInside(const hsPoint3& pos) const
|
||||
{
|
||||
int i;
|
||||
for( i = 0; i < fPlanes.GetCount(); i++ )
|
||||
{
|
||||
if( fPlanes[i].fWorldNorm.InnerProduct(pos) > fPlanes[i].fWorldDist )
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
hsBool plHardRegionPlanes::ICameraInside() const
|
||||
{
|
||||
return IIsInside(fCamPos);
|
||||
}
|
||||
|
||||
void plHardRegionPlanes::SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l)
|
||||
{
|
||||
int i;
|
||||
for( i = 0; i < fPlanes.GetCount(); i++ )
|
||||
{
|
||||
fPlanes[i].fWorldPos = l2w * fPlanes[i].fPos;
|
||||
|
||||
// Normal gets transpose of inverse.
|
||||
fPlanes[i].fWorldNorm.fX = w2l.fMap[0][0] * fPlanes[i].fNorm.fX
|
||||
+ w2l.fMap[1][0] * fPlanes[i].fNorm.fY
|
||||
+ w2l.fMap[2][0] * fPlanes[i].fNorm.fZ;
|
||||
|
||||
fPlanes[i].fWorldNorm.fY = w2l.fMap[0][1] * fPlanes[i].fNorm.fX
|
||||
+ w2l.fMap[1][1] * fPlanes[i].fNorm.fY
|
||||
+ w2l.fMap[2][1] * fPlanes[i].fNorm.fZ;
|
||||
|
||||
fPlanes[i].fWorldNorm.fZ = w2l.fMap[0][2] * fPlanes[i].fNorm.fX
|
||||
+ w2l.fMap[1][2] * fPlanes[i].fNorm.fY
|
||||
+ w2l.fMap[2][2] * fPlanes[i].fNorm.fZ;
|
||||
|
||||
hsFastMath::NormalizeAppr(fPlanes[i].fWorldNorm);
|
||||
|
||||
fPlanes[i].fWorldDist = fPlanes[i].fWorldNorm.InnerProduct(fPlanes[i].fWorldPos);
|
||||
}
|
||||
}
|
||||
|
||||
void plHardRegionPlanes::Read(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
plHardRegion::Read(s, mgr);
|
||||
|
||||
int n = s->ReadSwap32();
|
||||
fPlanes.SetCount(n);
|
||||
|
||||
int i;
|
||||
for( i = 0; i < n; i++ )
|
||||
{
|
||||
fPlanes[i].fNorm.Read(s);
|
||||
fPlanes[i].fPos.Read(s);
|
||||
|
||||
fPlanes[i].fWorldNorm.Read(s);
|
||||
fPlanes[i].fWorldPos.Read(s);
|
||||
|
||||
fPlanes[i].fWorldDist = fPlanes[i].fWorldNorm.InnerProduct(fPlanes[i].fWorldPos);
|
||||
}
|
||||
}
|
||||
|
||||
void plHardRegionPlanes::Write(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
plHardRegion::Write(s, mgr);
|
||||
|
||||
s->WriteSwap32(fPlanes.GetCount());
|
||||
|
||||
int i;
|
||||
for( i = 0; i < fPlanes.GetCount(); i++ )
|
||||
{
|
||||
fPlanes[i].fNorm.Write(s);
|
||||
fPlanes[i].fPos.Write(s);
|
||||
|
||||
fPlanes[i].fWorldNorm.Write(s);
|
||||
fPlanes[i].fWorldPos.Write(s);
|
||||
}
|
||||
}
|
||||
|
||||
void plHardRegionPlanes::AddPlane(const hsVector3& n, const hsPoint3& p)
|
||||
{
|
||||
hsVector3 nNorm = n;
|
||||
hsFastMath::Normalize(nNorm);
|
||||
|
||||
// First, make sure some idiot isn't adding the same plane in twice.
|
||||
// Also, look for the degenerate case of two parallel planes. In that
|
||||
// case, take the outer.
|
||||
int i;
|
||||
for( i = 0; i < fPlanes.GetCount(); i++ )
|
||||
{
|
||||
const hsScalar kCloseToOne = 1.f - 1.e-4f;
|
||||
if( fPlanes[i].fNorm.InnerProduct(nNorm) >= kCloseToOne )
|
||||
{
|
||||
hsScalar newDist = nNorm.InnerProduct(p);
|
||||
hsScalar oldDist = fPlanes[i].fNorm.InnerProduct(fPlanes[i].fPos);
|
||||
if( newDist > oldDist )
|
||||
{
|
||||
fPlanes[i].fPos = p;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
HardPlane plane;
|
||||
plane.fWorldNorm = plane.fNorm = nNorm;
|
||||
plane.fWorldPos = plane.fPos = p;
|
||||
plane.fWorldDist = plane.fWorldNorm.InnerProduct(plane.fWorldPos);
|
||||
|
||||
fPlanes.Append(plane);
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#ifndef plHardRegionPlanes_inc
|
||||
#define plHardRegionPlanes_inc
|
||||
|
||||
#include "plHardRegion.h"
|
||||
|
||||
class plHardRegionPlanes : public plHardRegion
|
||||
{
|
||||
protected:
|
||||
class HardPlane
|
||||
{
|
||||
public:
|
||||
hsVector3 fNorm;
|
||||
hsPoint3 fPos;
|
||||
|
||||
hsVector3 fWorldNorm;
|
||||
hsPoint3 fWorldPos;
|
||||
hsScalar fWorldDist;
|
||||
};
|
||||
hsTArray<HardPlane> fPlanes;
|
||||
|
||||
protected:
|
||||
public:
|
||||
plHardRegionPlanes();
|
||||
virtual ~plHardRegionPlanes();
|
||||
|
||||
CLASSNAME_REGISTER( plHardRegionPlanes );
|
||||
GETINTERFACE_ANY( plHardRegionPlanes, plHardRegion );
|
||||
|
||||
virtual void SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l);
|
||||
|
||||
virtual void Read(hsStream* stream, hsResMgr* mgr);
|
||||
virtual void Write(hsStream* stream, hsResMgr* mgr);
|
||||
|
||||
// Now Planes specifics
|
||||
void AddPlane(const hsVector3& n, const hsPoint3& p);
|
||||
UInt32 GetNumPlanes() const { return fPlanes.GetCount(); }
|
||||
void GetPlane(int i, hsVector3& n, hsPoint3& p) const { n = fPlanes[i].fNorm; p = fPlanes[i].fPos; }
|
||||
void GetWorldPlane(int i, hsVector3& n, hsPoint3& p) const { n = fPlanes[i].fWorldNorm; p = fPlanes[i].fWorldPos; }
|
||||
|
||||
virtual hsBool IIsInside(const hsPoint3& pos) const;
|
||||
virtual hsBool ICameraInside() const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // plHardRegionPlanes_inc
|
||||
|
@ -0,0 +1,196 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#include "hsTypes.h"
|
||||
|
||||
#include "plHardRegionTypes.h"
|
||||
#include "hsStream.h"
|
||||
#include "hsResMgr.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Base hard and complex
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
plHardRegionComplex::plHardRegionComplex()
|
||||
{
|
||||
}
|
||||
|
||||
plHardRegionComplex::~plHardRegionComplex()
|
||||
{
|
||||
}
|
||||
|
||||
void plHardRegionComplex::Read(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
plHardRegion::Read(s, mgr);
|
||||
|
||||
int n = s->ReadSwap32();
|
||||
int i;
|
||||
for( i = 0; i < n; i++ )
|
||||
mgr->ReadKeyNotifyMe(s, TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, 0, kSubRegion), plRefFlags::kActiveRef);
|
||||
}
|
||||
|
||||
void plHardRegionComplex::Write(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
plHardRegion::Write(s, mgr);
|
||||
|
||||
s->WriteSwap32(fSubRegions.GetCount());
|
||||
int i;
|
||||
for( i = 0; i < fSubRegions.GetCount(); i++ )
|
||||
mgr->WriteKey(s, fSubRegions[i]);
|
||||
}
|
||||
|
||||
hsBool plHardRegionComplex::MsgReceive(plMessage* msg)
|
||||
{
|
||||
plGenRefMsg* refMsg = plGenRefMsg::ConvertNoRef(msg);
|
||||
if( refMsg )
|
||||
{
|
||||
if( refMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest) )
|
||||
{
|
||||
plHardRegion* sub = plHardRegion::ConvertNoRef(refMsg->GetRef());
|
||||
hsAssert(fSubRegions.kMissingIndex == fSubRegions.Find(sub), "Adding subRegion I already have");
|
||||
fSubRegions.Append(sub);
|
||||
}
|
||||
else if( refMsg->GetContext() & (plRefMsg::kOnDestroy|plRefMsg::kOnRemove) )
|
||||
{
|
||||
plHardRegion* sub = (plHardRegion*)refMsg->GetRef();
|
||||
int idx = fSubRegions.Find(sub);
|
||||
if( idx != fSubRegions.kMissingIndex )
|
||||
fSubRegions.Remove(idx);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return plHardRegion::MsgReceive(msg);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Booleans follow
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Union
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
plHardRegionUnion::plHardRegionUnion()
|
||||
{
|
||||
}
|
||||
|
||||
plHardRegionUnion::~plHardRegionUnion()
|
||||
{
|
||||
}
|
||||
|
||||
hsBool plHardRegionUnion::IIsInside(const hsPoint3& pos) const
|
||||
{
|
||||
int i;
|
||||
for( i = 0; i < fSubRegions.GetCount(); i++ )
|
||||
{
|
||||
if( fSubRegions[i]->IIsInside(pos) )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
hsBool plHardRegionUnion::ICameraInside() const
|
||||
{
|
||||
if( fState & kDirty )
|
||||
{
|
||||
fState &= ~(kCamInside | kDirty);
|
||||
int i;
|
||||
for( i = 0; i < fSubRegions.GetCount(); i++ )
|
||||
{
|
||||
if( fSubRegions[i]->ICameraInside() )
|
||||
{
|
||||
fState |= kCamInside;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Intersection
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
plHardRegionIntersect::plHardRegionIntersect()
|
||||
{
|
||||
}
|
||||
|
||||
plHardRegionIntersect::~plHardRegionIntersect()
|
||||
{
|
||||
}
|
||||
|
||||
hsBool plHardRegionIntersect::IIsInside(const hsPoint3& pos) const
|
||||
{
|
||||
int i;
|
||||
for( i = 0; i < fSubRegions.GetCount(); i++ )
|
||||
{
|
||||
if( !fSubRegions[i]->IIsInside(pos) )
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
hsBool plHardRegionIntersect::ICameraInside() const
|
||||
{
|
||||
if( fState & kDirty )
|
||||
{
|
||||
fState &= ~kDirty;
|
||||
fState |= kCamInside;
|
||||
int i;
|
||||
for( i = 0; i < fSubRegions.GetCount(); i++ )
|
||||
{
|
||||
if( !fSubRegions[i]->ICameraInside() )
|
||||
{
|
||||
fState &= ~kCamInside;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Invert
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
plHardRegionInvert::plHardRegionInvert()
|
||||
{
|
||||
}
|
||||
|
||||
plHardRegionInvert::~plHardRegionInvert()
|
||||
{
|
||||
}
|
||||
|
||||
hsBool plHardRegionInvert::IIsInside(const hsPoint3& pos) const
|
||||
{
|
||||
hsAssert(fSubRegions.GetCount() <= 1, "Too many subRegions on inverter");
|
||||
return !fSubRegions[0]->IIsInside(pos);
|
||||
}
|
||||
|
||||
hsBool plHardRegionInvert::ICameraInside() const
|
||||
{
|
||||
hsAssert(fSubRegions.GetCount() <= 1, "Too many subRegions on inverter");
|
||||
return !fSubRegions[0]->ICameraInside();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
@ -0,0 +1,104 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#ifndef plHardRegionTypes_inc
|
||||
#define plHardRegionTypes_inc
|
||||
|
||||
#include "plHardRegion.h"
|
||||
#include "hsTemplates.h"
|
||||
|
||||
class plHardRegionComplex : public plHardRegion
|
||||
{
|
||||
protected:
|
||||
hsTArray<plHardRegion*> fSubRegions;
|
||||
|
||||
public:
|
||||
plHardRegionComplex();
|
||||
virtual ~plHardRegionComplex();
|
||||
|
||||
CLASSNAME_REGISTER( plHardRegionComplex );
|
||||
GETINTERFACE_ANY( plHardRegionComplex, plHardRegion );
|
||||
|
||||
// Don't propagate the settransform to our children, they move independently
|
||||
virtual void SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l) {}
|
||||
|
||||
virtual void Read(hsStream* stream, hsResMgr* mgr);
|
||||
virtual void Write(hsStream* stream, hsResMgr* mgr);
|
||||
|
||||
// Now Complex specifics
|
||||
virtual hsBool MsgReceive(plMessage* msg);
|
||||
|
||||
UInt16 GetNumSubs() const { return fSubRegions.GetCount(); }
|
||||
const plHardRegion* GetSub(int i) const { return fSubRegions[i]; }
|
||||
};
|
||||
|
||||
class plHardRegionUnion : public plHardRegionComplex
|
||||
{
|
||||
protected:
|
||||
public:
|
||||
plHardRegionUnion();
|
||||
virtual ~plHardRegionUnion();
|
||||
|
||||
CLASSNAME_REGISTER( plHardRegionUnion );
|
||||
GETINTERFACE_ANY( plHardRegionUnion, plHardRegionComplex );
|
||||
|
||||
virtual hsBool IIsInside(const hsPoint3& pos) const;
|
||||
virtual hsBool ICameraInside() const;
|
||||
|
||||
};
|
||||
|
||||
class plHardRegionIntersect : public plHardRegionComplex
|
||||
{
|
||||
protected:
|
||||
public:
|
||||
plHardRegionIntersect();
|
||||
virtual ~plHardRegionIntersect();
|
||||
|
||||
CLASSNAME_REGISTER( plHardRegionIntersect );
|
||||
GETINTERFACE_ANY( plHardRegionIntersect, plHardRegionComplex );
|
||||
|
||||
virtual hsBool IIsInside(const hsPoint3& pos) const;
|
||||
virtual hsBool ICameraInside() const;
|
||||
|
||||
};
|
||||
|
||||
class plHardRegionInvert : public plHardRegionComplex
|
||||
{
|
||||
protected:
|
||||
public:
|
||||
plHardRegionInvert();
|
||||
virtual ~plHardRegionInvert();
|
||||
|
||||
CLASSNAME_REGISTER( plHardRegionInvert );
|
||||
GETINTERFACE_ANY( plHardRegionInvert, plHardRegionComplex );
|
||||
|
||||
virtual hsBool IIsInside(const hsPoint3& pos) const;
|
||||
virtual hsBool ICameraInside() const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // plHardRegionTypes_inc
|
@ -0,0 +1,83 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#ifndef plIntersectCreatable_inc
|
||||
#define plIntersectCreatable_inc
|
||||
|
||||
#include "../pnFactory/plCreator.h"
|
||||
|
||||
#include "plVolumeIsect.h"
|
||||
|
||||
REGISTER_NONCREATABLE( plVolumeIsect );
|
||||
|
||||
REGISTER_CREATABLE( plSphereIsect );
|
||||
REGISTER_CREATABLE( plConeIsect );
|
||||
REGISTER_CREATABLE( plCylinderIsect );
|
||||
REGISTER_CREATABLE( plParallelIsect );
|
||||
REGISTER_CREATABLE( plConvexIsect );
|
||||
|
||||
REGISTER_CREATABLE( plBoundsIsect );
|
||||
|
||||
REGISTER_NONCREATABLE( plComplexIsect );
|
||||
|
||||
REGISTER_CREATABLE( plUnionIsect );
|
||||
REGISTER_CREATABLE( plIntersectionIsect );
|
||||
|
||||
#include "plRegionBase.h"
|
||||
|
||||
REGISTER_NONCREATABLE( plRegionBase );
|
||||
|
||||
#include "plSoftVolume.h"
|
||||
|
||||
REGISTER_NONCREATABLE( plSoftVolume );
|
||||
|
||||
#include "plSoftVolumeTypes.h"
|
||||
|
||||
REGISTER_CREATABLE( plSoftVolumeSimple );
|
||||
|
||||
REGISTER_NONCREATABLE( plSoftVolumeComplex );
|
||||
|
||||
REGISTER_CREATABLE( plSoftVolumeUnion );
|
||||
REGISTER_CREATABLE( plSoftVolumeIntersect );
|
||||
REGISTER_CREATABLE( plSoftVolumeInvert );
|
||||
|
||||
#include "plHardRegion.h"
|
||||
|
||||
REGISTER_NONCREATABLE( plHardRegion );
|
||||
|
||||
#include "plHardRegionPlanes.h"
|
||||
|
||||
REGISTER_CREATABLE( plHardRegionPlanes );
|
||||
|
||||
#include "plHardRegionTypes.h"
|
||||
|
||||
REGISTER_NONCREATABLE( plHardRegionComplex );
|
||||
|
||||
REGISTER_CREATABLE( plHardRegionUnion );
|
||||
REGISTER_CREATABLE( plHardRegionIntersect );
|
||||
REGISTER_CREATABLE( plHardRegionInvert );
|
||||
|
||||
#endif // plIntersectCreatable_inc
|
@ -0,0 +1,46 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#ifndef plRegionBase_inc
|
||||
#define plRegionBase_inc
|
||||
|
||||
#include "../pnSceneObject/plObjInterface.h"
|
||||
|
||||
struct hsPoint3;
|
||||
|
||||
class plRegionBase : public plObjInterface
|
||||
{
|
||||
public:
|
||||
plRegionBase() {}
|
||||
virtual ~plRegionBase() {}
|
||||
|
||||
CLASSNAME_REGISTER( plRegionBase );
|
||||
GETINTERFACE_ANY( plRegionBase, plObjInterface );
|
||||
|
||||
virtual hsBool IsInside(const hsPoint3& pos) const = 0;
|
||||
};
|
||||
|
||||
#endif // plRegionBase_inc
|
@ -0,0 +1,143 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#include "hsTypes.h"
|
||||
#include "hsStream.h"
|
||||
|
||||
#include "plSoftVolume.h"
|
||||
|
||||
#include "plgDispatch.h"
|
||||
#include "../plMessage/plListenerMsg.h"
|
||||
|
||||
plSoftVolume::plSoftVolume()
|
||||
: fListenState(0),
|
||||
fListenStrength(0),
|
||||
fInsideStrength(1.f),
|
||||
fOutsideStrength(0)
|
||||
{
|
||||
fListenPos.Set(0,0,0);
|
||||
}
|
||||
|
||||
plSoftVolume::~plSoftVolume()
|
||||
{
|
||||
}
|
||||
|
||||
void plSoftVolume::Read(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
plRegionBase::Read(s, mgr);
|
||||
|
||||
fListenState = s->ReadSwap32();
|
||||
|
||||
SetCheckListener(0 != (fListenState & kListenCheck));
|
||||
|
||||
fInsideStrength = s->ReadSwapScalar();
|
||||
fOutsideStrength = s->ReadSwapScalar();
|
||||
}
|
||||
|
||||
void plSoftVolume::Write(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
plRegionBase::Write(s, mgr);
|
||||
|
||||
s->WriteSwap32(fListenState);
|
||||
|
||||
s->WriteSwapScalar(fInsideStrength);
|
||||
s->WriteSwapScalar(fOutsideStrength);
|
||||
}
|
||||
|
||||
hsScalar plSoftVolume::GetStrength(const hsPoint3& pos) const
|
||||
{
|
||||
return IRemapStrength(IGetStrength(pos));
|
||||
}
|
||||
|
||||
hsScalar plSoftVolume::GetListenerStrength() const
|
||||
{
|
||||
if( !(fListenState & kListenPosSet) )
|
||||
{
|
||||
// Some screw-up, haven't received a pos yet. Turn it off till we do.
|
||||
return fListenStrength = IRemapStrength(0);
|
||||
}
|
||||
if( fListenState & kListenDirty )
|
||||
{
|
||||
fListenStrength = IUpdateListenerStrength();
|
||||
fListenState &= ~kListenDirty;
|
||||
}
|
||||
return fListenStrength;
|
||||
}
|
||||
|
||||
void plSoftVolume::UpdateListenerPosition(const hsPoint3& pos)
|
||||
{
|
||||
fListenPos = pos;
|
||||
fListenState |= kListenDirty | kListenPosSet;
|
||||
}
|
||||
|
||||
void plSoftVolume::SetCheckListener(hsBool on)
|
||||
{
|
||||
if( on )
|
||||
{
|
||||
plgDispatch::Dispatch()->RegisterForExactType(plListenerMsg::Index(), GetKey());
|
||||
fListenState |= kListenCheck | kListenDirty | kListenRegistered;
|
||||
}
|
||||
else
|
||||
{
|
||||
plgDispatch::Dispatch()->UnRegisterForExactType(plListenerMsg::Index(), GetKey());
|
||||
fListenState &= ~(kListenCheck | kListenDirty | kListenRegistered);
|
||||
}
|
||||
}
|
||||
|
||||
hsBool plSoftVolume::MsgReceive(plMessage* msg)
|
||||
{
|
||||
plListenerMsg* list = plListenerMsg::ConvertNoRef(msg);
|
||||
if( list )
|
||||
{
|
||||
UpdateListenerPosition(list->GetPosition());
|
||||
return true;
|
||||
}
|
||||
|
||||
return plRegionBase::MsgReceive(msg);
|
||||
}
|
||||
|
||||
hsScalar plSoftVolume::IUpdateListenerStrength() const
|
||||
{
|
||||
return fListenStrength = GetStrength(fListenPos);
|
||||
}
|
||||
|
||||
void plSoftVolume::SetInsideStrength(hsScalar s)
|
||||
{
|
||||
if( s < 0 )
|
||||
s = 0;
|
||||
else if( s > 1.f )
|
||||
s = 1.f;
|
||||
fInsideStrength = s;
|
||||
}
|
||||
|
||||
void plSoftVolume::SetOutsideStrength(hsScalar s)
|
||||
{
|
||||
if( s < 0 )
|
||||
s = 0;
|
||||
else if( s > 1.f )
|
||||
s = 1.f;
|
||||
fOutsideStrength = s;
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#ifndef plSoftVolume_inc
|
||||
#define plSoftVolume_inc
|
||||
|
||||
#include "plRegionBase.h"
|
||||
#include "hsGeometry3.h"
|
||||
|
||||
class hsStream;
|
||||
class hsResMgr;
|
||||
class plMessage;
|
||||
|
||||
class plSoftVolume : public plRegionBase
|
||||
{
|
||||
public:
|
||||
enum RefTypes {
|
||||
kSubVolume
|
||||
};
|
||||
|
||||
protected:
|
||||
enum {
|
||||
kListenNone = 0x0,
|
||||
kListenCheck = 0x1,
|
||||
kListenPosSet = 0x2,
|
||||
kListenDirty = 0x4,
|
||||
kListenRegistered = 0x8
|
||||
};
|
||||
|
||||
hsPoint3 fListenPos;
|
||||
mutable hsScalar fListenStrength;
|
||||
mutable UInt32 fListenState;
|
||||
|
||||
hsScalar fInsideStrength;
|
||||
hsScalar fOutsideStrength;
|
||||
|
||||
virtual hsScalar IUpdateListenerStrength() const;
|
||||
|
||||
hsScalar IRemapStrength(hsScalar s) const { return fOutsideStrength + s * (fInsideStrength - fOutsideStrength); }
|
||||
|
||||
private:
|
||||
// Don't call this, use public GetStrength().
|
||||
virtual hsScalar IGetStrength(const hsPoint3& pos) const = 0;
|
||||
|
||||
public:
|
||||
plSoftVolume();
|
||||
virtual ~plSoftVolume();
|
||||
|
||||
CLASSNAME_REGISTER( plSoftVolume );
|
||||
GETINTERFACE_ANY( plSoftVolume, plRegionBase );
|
||||
|
||||
virtual hsScalar GetStrength(const hsPoint3& pos) const;
|
||||
virtual hsBool IsInside(const hsPoint3& pos) const { return GetStrength(pos) >= 1.f; }
|
||||
|
||||
virtual void SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l) = 0;
|
||||
|
||||
virtual Int32 GetNumProperties() const { return 1; } // This is stupid.
|
||||
|
||||
virtual hsScalar GetListenerStrength() const;
|
||||
virtual void UpdateListenerPosition(const hsPoint3& p);
|
||||
virtual void SetCheckListener(hsBool on=true);
|
||||
virtual hsBool GetCheckListener() const { return 0 != (fListenState & kListenCheck); }
|
||||
|
||||
virtual hsBool MsgReceive(plMessage* msg);
|
||||
|
||||
virtual void Read(hsStream* stream, hsResMgr* mgr);
|
||||
virtual void Write(hsStream* stream, hsResMgr* mgr);
|
||||
|
||||
void SetInsideStrength(hsScalar s);
|
||||
void SetOutsideStrength(hsScalar s);
|
||||
|
||||
hsScalar GetInsideStrength() const { return fInsideStrength; }
|
||||
hsScalar GetOutsideStrength() const { return fOutsideStrength; }
|
||||
};
|
||||
|
||||
#endif // plSoftVolume_inc
|
||||
|
@ -0,0 +1,279 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#include "hsTypes.h"
|
||||
#include "hsMatrix44.h"
|
||||
#include "hsGeometry3.h"
|
||||
#include "hsResMgr.h"
|
||||
#include "hsStream.h"
|
||||
|
||||
#include "plVolumeIsect.h"
|
||||
#include "plSoftVolumeTypes.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
plSoftVolumeSimple::plSoftVolumeSimple()
|
||||
: fVolume(nil),
|
||||
fSoftDist(0)
|
||||
{
|
||||
}
|
||||
|
||||
plSoftVolumeSimple::~plSoftVolumeSimple()
|
||||
{
|
||||
delete fVolume;
|
||||
}
|
||||
|
||||
hsScalar plSoftVolumeSimple::IGetStrength(const hsPoint3& pos) const
|
||||
{
|
||||
if( !fVolume || GetProperty(kDisable) )
|
||||
return 0;
|
||||
|
||||
hsScalar dist = fVolume->Test(pos);
|
||||
|
||||
if( dist <= 0 )
|
||||
return 1.f;
|
||||
|
||||
if( dist >= fSoftDist )
|
||||
return 0;
|
||||
|
||||
dist /= fSoftDist;
|
||||
|
||||
return 1.f - dist;
|
||||
}
|
||||
|
||||
void plSoftVolumeSimple::SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l)
|
||||
{
|
||||
if( fVolume )
|
||||
fVolume->SetTransform(l2w, w2l);
|
||||
}
|
||||
|
||||
void plSoftVolumeSimple::Read(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
plSoftVolume::Read(s, mgr);
|
||||
|
||||
fSoftDist = s->ReadSwapScalar();
|
||||
|
||||
fVolume = plVolumeIsect::ConvertNoRef(mgr->ReadCreatable(s));
|
||||
}
|
||||
|
||||
void plSoftVolumeSimple::Write(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
plSoftVolume::Write(s, mgr);
|
||||
|
||||
s->WriteSwapScalar(fSoftDist);
|
||||
|
||||
mgr->WriteCreatable(s, fVolume);
|
||||
}
|
||||
|
||||
void plSoftVolumeSimple::SetVolume(plVolumeIsect* v)
|
||||
{
|
||||
delete fVolume;
|
||||
fVolume = v;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
plSoftVolumeComplex::plSoftVolumeComplex()
|
||||
{
|
||||
}
|
||||
|
||||
plSoftVolumeComplex::~plSoftVolumeComplex()
|
||||
{
|
||||
}
|
||||
|
||||
void plSoftVolumeComplex::Read(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
plSoftVolume::Read(s, mgr);
|
||||
|
||||
int n = s->ReadSwap32();
|
||||
int i;
|
||||
for( i = 0; i < n; i++ )
|
||||
mgr->ReadKeyNotifyMe(s, TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, 0, kSubVolume), plRefFlags::kActiveRef);
|
||||
}
|
||||
|
||||
void plSoftVolumeComplex::Write(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
plSoftVolume::Write(s, mgr);
|
||||
|
||||
s->WriteSwap32(fSubVolumes.GetCount());
|
||||
int i;
|
||||
for( i = 0; i < fSubVolumes.GetCount(); i++ )
|
||||
mgr->WriteKey(s, fSubVolumes[i]);
|
||||
}
|
||||
|
||||
hsBool plSoftVolumeComplex::MsgReceive(plMessage* msg)
|
||||
{
|
||||
plGenRefMsg* refMsg = plGenRefMsg::ConvertNoRef(msg);
|
||||
if( refMsg )
|
||||
{
|
||||
if( refMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest) )
|
||||
{
|
||||
plSoftVolume* sub = plSoftVolume::ConvertNoRef(refMsg->GetRef());
|
||||
hsAssert(fSubVolumes.kMissingIndex == fSubVolumes.Find(sub), "Adding subvolume I already have");
|
||||
fSubVolumes.Append(sub);
|
||||
}
|
||||
else if( refMsg->GetContext() & (plRefMsg::kOnDestroy|plRefMsg::kOnRemove) )
|
||||
{
|
||||
plSoftVolume* sub = (plSoftVolume*)refMsg->GetRef();
|
||||
int idx = fSubVolumes.Find(sub);
|
||||
if( idx != fSubVolumes.kMissingIndex )
|
||||
fSubVolumes.Remove(idx);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return plSoftVolume::MsgReceive(msg);
|
||||
}
|
||||
|
||||
void plSoftVolumeComplex::UpdateListenerPosition(const hsPoint3& pos)
|
||||
{
|
||||
plSoftVolume::UpdateListenerPosition(pos);
|
||||
int i;
|
||||
for( i = 0; i < fSubVolumes.GetCount(); i++ )
|
||||
fSubVolumes[i]->UpdateListenerPosition(pos);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
plSoftVolumeUnion::plSoftVolumeUnion()
|
||||
{
|
||||
}
|
||||
|
||||
plSoftVolumeUnion::~plSoftVolumeUnion()
|
||||
{
|
||||
}
|
||||
|
||||
hsScalar plSoftVolumeUnion::IGetStrength(const hsPoint3& pos) const
|
||||
{
|
||||
hsScalar retVal = 0;
|
||||
int i;
|
||||
for( i = 0; i < fSubVolumes.GetCount(); i++ )
|
||||
{
|
||||
hsScalar subRet = fSubVolumes[i]->GetStrength(pos);
|
||||
if( subRet >= 1.f )
|
||||
return 1.f;
|
||||
if( subRet > retVal )
|
||||
retVal = subRet;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
hsScalar plSoftVolumeUnion::IUpdateListenerStrength() const
|
||||
{
|
||||
hsScalar retVal = 0;
|
||||
int i;
|
||||
for( i = 0; i < fSubVolumes.GetCount(); i++ )
|
||||
{
|
||||
hsScalar subRet = fSubVolumes[i]->GetListenerStrength();
|
||||
if( subRet >= 1.f )
|
||||
{
|
||||
retVal = 1.f;
|
||||
break;
|
||||
}
|
||||
if( subRet > retVal )
|
||||
retVal = subRet;
|
||||
}
|
||||
return fListenStrength = IRemapStrength(retVal);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
plSoftVolumeIntersect::plSoftVolumeIntersect()
|
||||
{
|
||||
}
|
||||
|
||||
plSoftVolumeIntersect::~plSoftVolumeIntersect()
|
||||
{
|
||||
}
|
||||
|
||||
hsScalar plSoftVolumeIntersect::IGetStrength(const hsPoint3& pos) const
|
||||
{
|
||||
hsScalar retVal = 1.f;
|
||||
int i;
|
||||
for( i = 0; i < fSubVolumes.GetCount(); i++ )
|
||||
{
|
||||
hsScalar subRet = fSubVolumes[i]->GetStrength(pos);
|
||||
if( subRet <= 0 )
|
||||
return 0;
|
||||
if( subRet < retVal )
|
||||
retVal = subRet;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
hsScalar plSoftVolumeIntersect::IUpdateListenerStrength() const
|
||||
{
|
||||
hsScalar retVal = 1.f;
|
||||
int i;
|
||||
for( i = 0; i < fSubVolumes.GetCount(); i++ )
|
||||
{
|
||||
hsScalar subRet = fSubVolumes[i]->GetListenerStrength();
|
||||
if( subRet <= 0 )
|
||||
{
|
||||
retVal = 0.f;
|
||||
break;
|
||||
}
|
||||
if( subRet < retVal )
|
||||
retVal = subRet;
|
||||
}
|
||||
return fListenStrength = IRemapStrength(retVal);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
plSoftVolumeInvert::plSoftVolumeInvert()
|
||||
{
|
||||
}
|
||||
|
||||
plSoftVolumeInvert::~plSoftVolumeInvert()
|
||||
{
|
||||
}
|
||||
|
||||
hsScalar plSoftVolumeInvert::IGetStrength(const hsPoint3& pos) const
|
||||
{
|
||||
hsAssert(fSubVolumes.GetCount() <= 1, "Too many subvolumes on inverter");
|
||||
if( fSubVolumes.GetCount() )
|
||||
return 1.f - fSubVolumes[0]->GetStrength(pos);
|
||||
|
||||
return 1.f;
|
||||
}
|
||||
|
||||
hsScalar plSoftVolumeInvert::IUpdateListenerStrength() const
|
||||
{
|
||||
hsAssert(fSubVolumes.GetCount() <= 1, "Too many subvolumes on inverter");
|
||||
hsScalar retVal = 1.f;
|
||||
if( fSubVolumes.GetCount() )
|
||||
retVal = (1.f - fSubVolumes[0]->GetListenerStrength());
|
||||
|
||||
return fListenStrength = IRemapStrength(retVal);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////
|
@ -0,0 +1,144 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#ifndef plSoftVolumeTypes_inc
|
||||
#define plSoftVolumeTypes_inc
|
||||
|
||||
#include "plSoftVolume.h"
|
||||
#include "hsTemplates.h"
|
||||
|
||||
class plVolumeIsect;
|
||||
|
||||
class plSoftVolumeSimple : public plSoftVolume
|
||||
{
|
||||
protected:
|
||||
plVolumeIsect* fVolume;
|
||||
hsScalar fSoftDist;
|
||||
|
||||
private:
|
||||
virtual hsScalar IGetStrength(const hsPoint3& pos) const;
|
||||
|
||||
public:
|
||||
plSoftVolumeSimple();
|
||||
virtual ~plSoftVolumeSimple();
|
||||
|
||||
CLASSNAME_REGISTER( plSoftVolumeSimple );
|
||||
GETINTERFACE_ANY( plSoftVolumeSimple, plSoftVolume );
|
||||
|
||||
virtual void SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l);
|
||||
|
||||
virtual void Read(hsStream* stream, hsResMgr* mgr);
|
||||
virtual void Write(hsStream* stream, hsResMgr* mgr);
|
||||
|
||||
// Now Simple specifics
|
||||
plVolumeIsect* GetVolume() const { return fVolume; }
|
||||
void SetVolume(plVolumeIsect* v); // Takes ownership, don't delete after giving to SoftVolume
|
||||
|
||||
hsScalar GetDistance() const { return fSoftDist; }
|
||||
void SetDistance(hsScalar d) { fSoftDist = d; }
|
||||
|
||||
};
|
||||
|
||||
class plSoftVolumeComplex : public plSoftVolume
|
||||
{
|
||||
protected:
|
||||
hsTArray<plSoftVolume*> fSubVolumes;
|
||||
|
||||
public:
|
||||
plSoftVolumeComplex();
|
||||
virtual ~plSoftVolumeComplex();
|
||||
|
||||
CLASSNAME_REGISTER( plSoftVolumeComplex );
|
||||
GETINTERFACE_ANY( plSoftVolumeComplex, plSoftVolume );
|
||||
|
||||
// Don't propagate the settransform to our children, they move independently
|
||||
virtual void SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l) {}
|
||||
|
||||
virtual void Read(hsStream* stream, hsResMgr* mgr);
|
||||
virtual void Write(hsStream* stream, hsResMgr* mgr);
|
||||
|
||||
virtual void UpdateListenerPosition(const hsPoint3& p);
|
||||
|
||||
// Now Complex specifics
|
||||
virtual hsBool MsgReceive(plMessage* msg);
|
||||
|
||||
UInt16 GetNumSubs() const { return fSubVolumes.GetCount(); }
|
||||
const plSoftVolume* GetSub(int i) const { return fSubVolumes[i]; }
|
||||
};
|
||||
|
||||
class plSoftVolumeUnion : public plSoftVolumeComplex
|
||||
{
|
||||
protected:
|
||||
virtual hsScalar IUpdateListenerStrength() const;
|
||||
|
||||
private:
|
||||
virtual hsScalar IGetStrength(const hsPoint3& pos) const;
|
||||
|
||||
public:
|
||||
plSoftVolumeUnion();
|
||||
virtual ~plSoftVolumeUnion();
|
||||
|
||||
CLASSNAME_REGISTER( plSoftVolumeUnion );
|
||||
GETINTERFACE_ANY( plSoftVolumeUnion, plSoftVolumeComplex );
|
||||
|
||||
};
|
||||
|
||||
class plSoftVolumeIntersect : public plSoftVolumeComplex
|
||||
{
|
||||
protected:
|
||||
virtual hsScalar IUpdateListenerStrength() const;
|
||||
|
||||
private:
|
||||
virtual hsScalar IGetStrength(const hsPoint3& pos) const;
|
||||
|
||||
public:
|
||||
plSoftVolumeIntersect();
|
||||
virtual ~plSoftVolumeIntersect();
|
||||
|
||||
CLASSNAME_REGISTER( plSoftVolumeIntersect );
|
||||
GETINTERFACE_ANY( plSoftVolumeIntersect, plSoftVolumeComplex );
|
||||
|
||||
};
|
||||
|
||||
class plSoftVolumeInvert : public plSoftVolumeComplex
|
||||
{
|
||||
protected:
|
||||
virtual hsScalar IUpdateListenerStrength() const;
|
||||
|
||||
private:
|
||||
virtual hsScalar IGetStrength(const hsPoint3& pos) const;
|
||||
|
||||
public:
|
||||
plSoftVolumeInvert();
|
||||
virtual ~plSoftVolumeInvert();
|
||||
|
||||
CLASSNAME_REGISTER( plSoftVolumeInvert );
|
||||
GETINTERFACE_ANY( plSoftVolumeInvert, plSoftVolumeComplex );
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // plSoftVolumeTypes_inc
|
@ -0,0 +1,989 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#include "hsTypes.h"
|
||||
#include "plVolumeIsect.h"
|
||||
#include "hsBounds.h"
|
||||
#include "hsFastMath.h"
|
||||
#include "hsStream.h"
|
||||
#include "hsResMgr.h"
|
||||
#include "../plIntersect/plClosest.h"
|
||||
|
||||
static const hsScalar kDefLength = 5.f;
|
||||
|
||||
plSphereIsect::plSphereIsect()
|
||||
: fRadius(1.f)
|
||||
{
|
||||
fCenter.Set(0,0,0);
|
||||
int i;
|
||||
for( i = 0; i < 3; i++ )
|
||||
{
|
||||
fMins[i] = -fRadius;
|
||||
fMaxs[i] = fRadius;
|
||||
}
|
||||
}
|
||||
|
||||
plSphereIsect::~plSphereIsect()
|
||||
{
|
||||
}
|
||||
|
||||
void plSphereIsect::SetCenter(const hsPoint3& c)
|
||||
{
|
||||
fWorldCenter = fCenter = c;
|
||||
int i;
|
||||
for( i = 0; i < 3; i++ )
|
||||
{
|
||||
fMins[i] += c[i];
|
||||
fMaxs[i] += c[i];
|
||||
}
|
||||
}
|
||||
|
||||
void plSphereIsect::SetRadius(hsScalar r)
|
||||
{
|
||||
hsScalar del = r - fRadius;
|
||||
int i;
|
||||
for( i = 0; i < 3; i++ )
|
||||
{
|
||||
fMins[i] -= del;
|
||||
fMaxs[i] += del;
|
||||
}
|
||||
fRadius = r;
|
||||
}
|
||||
|
||||
void plSphereIsect::SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l)
|
||||
{
|
||||
fWorldCenter = l2w * fCenter;
|
||||
fMaxs = fMins = fWorldCenter;
|
||||
int i;
|
||||
for( i = 0; i < 3; i++ )
|
||||
{
|
||||
fMins[i] -= fRadius;
|
||||
fMaxs[i] += fRadius;
|
||||
}
|
||||
}
|
||||
|
||||
// Could use ClosestPoint to find the closest point on the bounds
|
||||
// to our center, and do a distance test on that. Would be more
|
||||
// accurate than this box test approx, but whatever.
|
||||
plVolumeCullResult plSphereIsect::Test(const hsBounds3Ext& bnd) const
|
||||
{
|
||||
const hsPoint3& maxs = bnd.GetMaxs();
|
||||
const hsPoint3& mins = bnd.GetMins();
|
||||
|
||||
if( (maxs.fX < fMins.fX)
|
||||
||
|
||||
(maxs.fY < fMins.fY)
|
||||
||
|
||||
(maxs.fZ < fMins.fZ) )
|
||||
return kVolumeCulled;
|
||||
|
||||
if( (mins.fX > fMaxs.fX)
|
||||
||
|
||||
(mins.fY > fMaxs.fY)
|
||||
||
|
||||
(mins.fZ > fMaxs.fZ) )
|
||||
return kVolumeCulled;
|
||||
|
||||
if( (maxs.fX > fMaxs.fX)
|
||||
||
|
||||
(maxs.fY > fMaxs.fY)
|
||||
||
|
||||
(maxs.fZ > fMaxs.fZ) )
|
||||
return kVolumeSplit;
|
||||
|
||||
if( (mins.fX < fMins.fX)
|
||||
||
|
||||
(mins.fY < fMins.fY)
|
||||
||
|
||||
(mins.fZ < fMins.fZ) )
|
||||
return kVolumeSplit;
|
||||
|
||||
return kVolumeClear;
|
||||
}
|
||||
|
||||
hsScalar plSphereIsect::Test(const hsPoint3& pos) const
|
||||
{
|
||||
hsScalar dist = (pos - fWorldCenter).MagnitudeSquared();
|
||||
if( dist < fRadius*fRadius )
|
||||
return 0;
|
||||
dist = hsSquareRoot(dist);
|
||||
return dist - fRadius;
|
||||
}
|
||||
|
||||
void plSphereIsect::Read(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
fCenter.Read(s);
|
||||
fWorldCenter.Read(s);
|
||||
fRadius = s->ReadSwapScalar();
|
||||
fMins.Read(s);
|
||||
fMaxs.Read(s);
|
||||
}
|
||||
|
||||
void plSphereIsect::Write(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
fCenter.Write(s);
|
||||
fWorldCenter.Write(s);
|
||||
s->WriteSwapScalar(fRadius);
|
||||
fMins.Write(s);
|
||||
fMaxs.Write(s);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
plConeIsect::plConeIsect()
|
||||
: fLength(kDefLength), fRadAngle(hsScalarPI*0.25f), fCapped(false)
|
||||
{
|
||||
ISetup();
|
||||
}
|
||||
|
||||
plConeIsect::~plConeIsect()
|
||||
{
|
||||
}
|
||||
|
||||
void plConeIsect::SetAngle(hsScalar rads)
|
||||
{
|
||||
fRadAngle = rads;
|
||||
ISetup();
|
||||
}
|
||||
|
||||
void plConeIsect::ISetup()
|
||||
{
|
||||
hsScalar sinAng, cosAng;
|
||||
hsFastMath::SinCosInRangeAppr(fRadAngle, sinAng, cosAng);
|
||||
|
||||
const hsScalar kHither = 0.1f;
|
||||
fLightToNDC.Reset();
|
||||
fLightToNDC.fMap[0][0] = hsScalarDiv( cosAng, sinAng );
|
||||
fLightToNDC.fMap[1][1] = hsScalarDiv( cosAng, sinAng );
|
||||
fLightToNDC.fMap[2][2] = -hsScalarDiv( fLength, fLength - kHither );
|
||||
fLightToNDC.fMap[3][3] = hsIntToScalar( 0 );
|
||||
fLightToNDC.fMap[3][2] = hsIntToScalar( -1 );
|
||||
fLightToNDC.fMap[2][3] = -hsScalarMulDiv( fLength, kHither, fLength - kHither );
|
||||
fLightToNDC.NotIdentity();
|
||||
}
|
||||
|
||||
plVolumeCullResult plConeIsect::Test(const hsBounds3Ext& bnd) const
|
||||
{
|
||||
plVolumeCullResult retVal = kVolumeClear;
|
||||
|
||||
hsPoint2 depth;
|
||||
hsVector3 normDir = -fWorldNorm;
|
||||
bnd.TestPlane(normDir, depth);
|
||||
if( depth.fY < normDir.InnerProduct(fWorldTip) )
|
||||
return kVolumeCulled;
|
||||
|
||||
int last = fCapped ? 5 : 4;
|
||||
int i;
|
||||
for( i = 0; i < last; i++ )
|
||||
{
|
||||
bnd.TestPlane(fNorms[i], depth);
|
||||
if( depth.fY + fDists[i] <= 0 )
|
||||
return kVolumeCulled;
|
||||
if( depth.fX + fDists[i] <= 0 )
|
||||
retVal = kVolumeSplit;
|
||||
}
|
||||
if( retVal == kVolumeSplit )
|
||||
{
|
||||
hsVector3 axis = normDir % hsVector3(&bnd.GetCenter(), &fWorldTip);
|
||||
hsFastMath::NormalizeAppr(axis);
|
||||
|
||||
hsVector3 perp = axis % normDir;
|
||||
|
||||
hsScalar sinAng, cosAng;
|
||||
hsFastMath::SinCosInRangeAppr(fRadAngle, sinAng, cosAng);
|
||||
|
||||
hsVector3 tangent = normDir + sinAng * perp + (1-cosAng) * (axis % perp);
|
||||
|
||||
hsVector3 normIn = tangent % axis;
|
||||
|
||||
hsVector3 normIn2 = perp + sinAng * (perp % axis) + (1-cosAng) * (axis % (axis % perp));
|
||||
|
||||
bnd.TestPlane(normIn, depth);
|
||||
hsScalar normInDotTip = normIn.InnerProduct(fWorldTip);
|
||||
if( depth.fY < normInDotTip )
|
||||
return kVolumeCulled;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
hsScalar plConeIsect::Test(const hsPoint3& pos) const
|
||||
{
|
||||
UInt32 clampFlags = fCapped ? plClosest::kClamp : plClosest::kClampLower;
|
||||
hsPoint3 cp;
|
||||
|
||||
plClosest::PointOnLine(pos,
|
||||
fWorldTip, fWorldNorm,
|
||||
cp,
|
||||
clampFlags);
|
||||
|
||||
hsScalar radDist = (pos - cp).Magnitude();
|
||||
hsScalar axDist = fWorldNorm.InnerProduct(pos - fWorldTip) / fLength;
|
||||
if( axDist < 0 )
|
||||
{
|
||||
return radDist;
|
||||
}
|
||||
hsScalar sinAng, cosAng;
|
||||
|
||||
hsFastMath::SinCosInRangeAppr(fRadAngle, sinAng, cosAng);
|
||||
|
||||
hsScalar radius = axDist * sinAng / cosAng;
|
||||
|
||||
radDist -= radius;
|
||||
axDist -= fLength;
|
||||
|
||||
if( fCapped && (axDist > 0) )
|
||||
{
|
||||
return axDist > radDist ? axDist : radDist;
|
||||
}
|
||||
|
||||
return radDist > 0 ? radDist : 0;
|
||||
}
|
||||
|
||||
//#define MF_DEBUG_NORM
|
||||
#ifdef MF_DEBUG_NORM
|
||||
#define IDEBUG_NORMALIZE( a, b ) { hsScalar len = 1.f / a.Magnitude(); a *= len; b *= len; }
|
||||
#else // MF_DEBUG_NORM
|
||||
#define IDEBUG_NORMALIZE( a, b )
|
||||
#endif // MF_DEBUG_NORM
|
||||
|
||||
void plConeIsect::SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l)
|
||||
{
|
||||
fWorldTip = l2w.GetTranslate();
|
||||
fWorldNorm.Set(l2w.fMap[0][2], l2w.fMap[1][2], l2w.fMap[2][2]);
|
||||
|
||||
fWorldToNDC = fLightToNDC * w2l;
|
||||
int i;
|
||||
for( i = 0; i < 2; i++ )
|
||||
{
|
||||
fNorms[i].Set(fWorldToNDC.fMap[3][0] - fWorldToNDC.fMap[i][0], fWorldToNDC.fMap[3][1] - fWorldToNDC.fMap[i][1], fWorldToNDC.fMap[3][2] - fWorldToNDC.fMap[i][2]);
|
||||
fDists[i] = fWorldToNDC.fMap[3][3] - fWorldToNDC.fMap[i][3];
|
||||
|
||||
IDEBUG_NORMALIZE( fNorms[i], fDists[i] );
|
||||
|
||||
fNorms[i+2].Set(fWorldToNDC.fMap[3][0] + fWorldToNDC.fMap[i][0], fWorldToNDC.fMap[3][1] + fWorldToNDC.fMap[i][1], fWorldToNDC.fMap[3][2] + fWorldToNDC.fMap[i][2]);
|
||||
fDists[i+2] = fWorldToNDC.fMap[3][3] + fWorldToNDC.fMap[i][3];
|
||||
|
||||
IDEBUG_NORMALIZE( fNorms[i+2], fDists[i+2] );
|
||||
}
|
||||
|
||||
if( fCapped )
|
||||
{
|
||||
fNorms[4].Set(fWorldToNDC.fMap[3][0] - fWorldToNDC.fMap[2][0], fWorldToNDC.fMap[3][1] - fWorldToNDC.fMap[2][1], fWorldToNDC.fMap[3][2] - fWorldToNDC.fMap[2][2]);
|
||||
fDists[4] = fWorldToNDC.fMap[3][3] - fWorldToNDC.fMap[2][3];
|
||||
|
||||
IDEBUG_NORMALIZE( fNorms[4], fDists[4] );
|
||||
}
|
||||
}
|
||||
|
||||
void plConeIsect::SetLength(hsScalar d)
|
||||
{
|
||||
if( d > 0 )
|
||||
{
|
||||
fCapped = true;
|
||||
fLength = d;
|
||||
}
|
||||
else
|
||||
{
|
||||
fCapped = false;
|
||||
fLength = kDefLength;
|
||||
}
|
||||
ISetup();
|
||||
}
|
||||
|
||||
void plConeIsect::Read(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
fCapped = s->ReadSwap32();
|
||||
|
||||
fRadAngle = s->ReadSwapScalar();
|
||||
fLength = s->ReadSwapScalar();
|
||||
|
||||
fWorldTip.Read(s);
|
||||
fWorldNorm.Read(s);
|
||||
|
||||
fWorldToNDC.Read(s);
|
||||
fLightToNDC.Read(s);
|
||||
|
||||
int n = fCapped ? 5 : 4;
|
||||
int i;
|
||||
for(i = 0; i < n; i++ )
|
||||
{
|
||||
fNorms[i].Read(s);
|
||||
fDists[i] = s->ReadSwapScalar();
|
||||
}
|
||||
}
|
||||
|
||||
void plConeIsect::Write(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
s->WriteSwap32(fCapped);
|
||||
|
||||
s->WriteSwapScalar(fRadAngle);
|
||||
s->WriteSwapScalar(fLength);
|
||||
|
||||
fWorldTip.Write(s);
|
||||
fWorldNorm.Write(s);
|
||||
|
||||
fWorldToNDC.Write(s);
|
||||
fLightToNDC.Write(s);
|
||||
|
||||
int n = fCapped ? 5 : 4;
|
||||
int i;
|
||||
for(i = 0; i < n; i++ )
|
||||
{
|
||||
fNorms[i].Write(s);
|
||||
s->WriteSwapScalar(fDists[i]);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
plCylinderIsect::plCylinderIsect()
|
||||
{
|
||||
}
|
||||
|
||||
plCylinderIsect::~plCylinderIsect()
|
||||
{
|
||||
}
|
||||
|
||||
void plCylinderIsect::ISetupCyl(const hsPoint3& wTop, const hsPoint3& wBot, hsScalar radius)
|
||||
{
|
||||
fWorldNorm.Set(&wTop, &wBot);
|
||||
fLength = fWorldNorm.Magnitude();
|
||||
fMin = fWorldNorm.InnerProduct(wBot);
|
||||
fMax = fWorldNorm.InnerProduct(wTop);
|
||||
if( fMin > fMax )
|
||||
{
|
||||
hsScalar t = fMin;
|
||||
fMin = fMax;
|
||||
fMax = t;
|
||||
}
|
||||
fRadius = radius;
|
||||
}
|
||||
|
||||
void plCylinderIsect::SetCylinder(const hsPoint3& lTop, const hsPoint3& lBot, hsScalar radius)
|
||||
{
|
||||
fTop = lTop;
|
||||
fBot = lBot;
|
||||
fRadius = radius;
|
||||
|
||||
ISetupCyl(fTop, fBot, fRadius);
|
||||
}
|
||||
|
||||
void plCylinderIsect::SetCylinder(const hsPoint3& lBot, const hsVector3& axis, hsScalar radius)
|
||||
{
|
||||
fBot = lBot;
|
||||
fTop = fBot;
|
||||
fTop += axis;
|
||||
|
||||
ISetupCyl(fTop, fBot, radius);
|
||||
|
||||
}
|
||||
|
||||
void plCylinderIsect::SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l)
|
||||
{
|
||||
hsPoint3 wTop = l2w * fTop;
|
||||
hsPoint3 wBot = l2w * fBot;
|
||||
|
||||
ISetupCyl(wTop, wBot, fRadius);
|
||||
}
|
||||
|
||||
plVolumeCullResult plCylinderIsect::Test(const hsBounds3Ext& bnd) const
|
||||
{
|
||||
plVolumeCullResult radVal = kVolumeClear;
|
||||
|
||||
// Central axis test
|
||||
hsPoint2 depth;
|
||||
bnd.TestPlane(fWorldNorm, depth);
|
||||
if( depth.fX > fMax )
|
||||
return kVolumeCulled;
|
||||
if( depth.fY < fMin )
|
||||
return kVolumeCulled;
|
||||
|
||||
if( (depth.fX < fMin)
|
||||
||(depth.fY > fMax) )
|
||||
{
|
||||
radVal = kVolumeSplit;
|
||||
}
|
||||
|
||||
// Radial test
|
||||
plVolumeCullResult retVal = kVolumeCulled;
|
||||
|
||||
// Find the closest point on/in the bounds to our central axis.
|
||||
// If that closest point is inside the cylinder, we have a hit.
|
||||
hsPoint3 corner;
|
||||
bnd.GetCorner(&corner);
|
||||
hsVector3 axes[3];
|
||||
bnd.GetAxes(axes+0, axes+1, axes+2);
|
||||
hsPoint3 cp = corner;
|
||||
|
||||
hsScalar bndRadiusSq = bnd.GetRadius();
|
||||
bndRadiusSq *= bndRadiusSq;
|
||||
|
||||
hsScalar radiusSq = fRadius*fRadius;
|
||||
|
||||
hsScalar maxClearDistSq = fRadius - bnd.GetRadius();
|
||||
maxClearDistSq *= maxClearDistSq;
|
||||
|
||||
int i;
|
||||
for( i = 0; i < 3; i++ )
|
||||
{
|
||||
hsPoint3 cp0;
|
||||
hsPoint3 currPt;
|
||||
plClosest::PointsOnLines(fWorldBot, fWorldNorm,
|
||||
cp, axes[i],
|
||||
cp0, currPt,
|
||||
plClosest::kClamp);
|
||||
hsScalar distSq = (cp0 - currPt).MagnitudeSquared();
|
||||
if( distSq < radiusSq )
|
||||
{
|
||||
if( distSq < maxClearDistSq )
|
||||
{
|
||||
return kVolumeClear == radVal ? kVolumeClear : kVolumeSplit;
|
||||
}
|
||||
retVal = kVolumeSplit;
|
||||
}
|
||||
cp = currPt;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
hsScalar plCylinderIsect::Test(const hsPoint3& pos) const
|
||||
{
|
||||
hsPoint3 cp;
|
||||
|
||||
plClosest::PointOnLine(pos,
|
||||
fWorldBot, fWorldNorm,
|
||||
cp,
|
||||
plClosest::kClamp);
|
||||
|
||||
hsScalar radDist = (pos - cp).Magnitude() - fRadius;
|
||||
hsScalar axDist = fWorldNorm.InnerProduct(pos - fWorldBot) / fLength;
|
||||
|
||||
if( axDist < 0 )
|
||||
axDist = -axDist;
|
||||
else
|
||||
axDist -= fLength;
|
||||
|
||||
hsScalar dist = axDist > radDist ? axDist : radDist;
|
||||
|
||||
return dist > 0 ? dist : 0;
|
||||
}
|
||||
|
||||
void plCylinderIsect::Read(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
fTop.Read(s);
|
||||
fBot.Read(s);
|
||||
fRadius = s->ReadSwapScalar();
|
||||
|
||||
fWorldBot.Read(s);
|
||||
fWorldNorm.Read(s);
|
||||
fLength = s->ReadSwapScalar();
|
||||
fMin = s->ReadSwapScalar();
|
||||
fMax = s->ReadSwapScalar();
|
||||
}
|
||||
|
||||
void plCylinderIsect::Write(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
fTop.Write(s);
|
||||
fBot.Write(s);
|
||||
s->WriteSwapScalar(fRadius);
|
||||
|
||||
fWorldBot.Write(s);
|
||||
fWorldNorm.Write(s);
|
||||
s->WriteSwapScalar(fLength);
|
||||
s->WriteSwapScalar(fMin);
|
||||
s->WriteSwapScalar(fMax);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
plParallelIsect::plParallelIsect()
|
||||
{
|
||||
}
|
||||
|
||||
plParallelIsect::~plParallelIsect()
|
||||
{
|
||||
}
|
||||
|
||||
void plParallelIsect::SetNumPlanes(int n)
|
||||
{
|
||||
fPlanes.SetCount(n);
|
||||
}
|
||||
|
||||
void plParallelIsect::SetPlane(int which, const hsPoint3& locPosOne, const hsPoint3& locPosTwo)
|
||||
{
|
||||
fPlanes[which].fPosOne = locPosOne;
|
||||
fPlanes[which].fPosTwo = locPosTwo;
|
||||
}
|
||||
|
||||
void plParallelIsect::SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l)
|
||||
{
|
||||
int i;
|
||||
for( i = 0; i < fPlanes.GetCount(); i++ )
|
||||
{
|
||||
hsPoint3 wPosOne = l2w * fPlanes[i].fPosOne;
|
||||
hsPoint3 wPosTwo = l2w * fPlanes[i].fPosTwo;
|
||||
hsVector3 norm;
|
||||
norm.Set(&wPosOne, &wPosTwo);
|
||||
fPlanes[i].fNorm = norm;
|
||||
hsScalar t0 = norm.InnerProduct(wPosOne);
|
||||
hsScalar t1 = norm.InnerProduct(wPosTwo);
|
||||
|
||||
if( t0 > t1 )
|
||||
{
|
||||
fPlanes[i].fMin = t1;
|
||||
fPlanes[i].fMax = t0;
|
||||
}
|
||||
else
|
||||
{
|
||||
fPlanes[i].fMin = t0;
|
||||
fPlanes[i].fMax = t1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plVolumeCullResult plParallelIsect::Test(const hsBounds3Ext& bnd) const
|
||||
{
|
||||
plVolumeCullResult retVal = kVolumeClear;
|
||||
int i;
|
||||
for( i = 0; i < fPlanes.GetCount(); i++ )
|
||||
{
|
||||
hsPoint2 depth;
|
||||
bnd.TestPlane(fPlanes[i].fNorm, depth);
|
||||
if( depth.fY < fPlanes[i].fMin )
|
||||
return kVolumeCulled;
|
||||
if( depth.fX > fPlanes[i].fMax )
|
||||
return kVolumeCulled;
|
||||
if( depth.fX < fPlanes[i].fMin )
|
||||
retVal = kVolumeSplit;
|
||||
if( depth.fY > fPlanes[i].fMax )
|
||||
retVal = kVolumeSplit;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
hsScalar plParallelIsect::Test(const hsPoint3& pos) const
|
||||
{
|
||||
hsScalar maxDist = 0;
|
||||
int i;
|
||||
for( i = 0; i < fPlanes.GetCount(); i++ )
|
||||
{
|
||||
hsScalar dist = fPlanes[i].fNorm.InnerProduct(pos);
|
||||
|
||||
if( dist > fPlanes[i].fMax )
|
||||
{
|
||||
dist -= fPlanes[i].fMax;
|
||||
dist *= hsFastMath::InvSqrtAppr(fPlanes[i].fNorm.MagnitudeSquared());
|
||||
if( dist > maxDist )
|
||||
maxDist = dist;
|
||||
}
|
||||
else if( dist < fPlanes[i].fMin )
|
||||
{
|
||||
dist = fPlanes[i].fMin - dist;
|
||||
dist *= hsFastMath::InvSqrtAppr(fPlanes[i].fNorm.MagnitudeSquared());
|
||||
if( dist > maxDist )
|
||||
maxDist = dist;
|
||||
}
|
||||
|
||||
}
|
||||
return maxDist;
|
||||
}
|
||||
|
||||
void plParallelIsect::Read(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
int n = s->ReadSwap16();
|
||||
|
||||
fPlanes.SetCount(n);
|
||||
int i;
|
||||
for( i = 0; i < n; i++ )
|
||||
{
|
||||
fPlanes[i].fNorm.Read(s);
|
||||
fPlanes[i].fMin = s->ReadSwapScalar();
|
||||
fPlanes[i].fMax = s->ReadSwapScalar();
|
||||
|
||||
fPlanes[i].fPosOne.Read(s);
|
||||
fPlanes[i].fPosTwo.Read(s);
|
||||
}
|
||||
}
|
||||
|
||||
void plParallelIsect::Write(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
s->WriteSwap16(fPlanes.GetCount());
|
||||
|
||||
int i;
|
||||
for( i = 0; i < fPlanes.GetCount(); i++ )
|
||||
{
|
||||
fPlanes[i].fNorm.Write(s);
|
||||
s->WriteSwapScalar(fPlanes[i].fMin);
|
||||
s->WriteSwapScalar(fPlanes[i].fMax);
|
||||
|
||||
fPlanes[i].fPosOne.Write(s);
|
||||
fPlanes[i].fPosTwo.Write(s);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
plConvexIsect::plConvexIsect()
|
||||
{
|
||||
}
|
||||
|
||||
plConvexIsect::~plConvexIsect()
|
||||
{
|
||||
}
|
||||
|
||||
void plConvexIsect::AddPlaneUnchecked(const hsVector3& n, hsScalar dist)
|
||||
{
|
||||
SinglePlane plane;
|
||||
plane.fNorm = n;
|
||||
plane.fPos.Set(0,0,0);
|
||||
plane.fDist = dist;
|
||||
|
||||
fPlanes.Append(plane);
|
||||
}
|
||||
|
||||
void plConvexIsect::AddPlane(const hsVector3& n, const hsPoint3& p)
|
||||
{
|
||||
hsVector3 nNorm = n;
|
||||
hsFastMath::Normalize(nNorm);
|
||||
|
||||
// First, make sure some idiot isn't adding the same plane in twice.
|
||||
// Also, look for the degenerate case of two parallel planes. In that
|
||||
// case, take the outer.
|
||||
int i;
|
||||
for( i = 0; i < fPlanes.GetCount(); i++ )
|
||||
{
|
||||
const hsScalar kCloseToOne = 1.f - 1.e-4f;
|
||||
if( fPlanes[i].fNorm.InnerProduct(nNorm) >= kCloseToOne )
|
||||
{
|
||||
hsScalar dist = nNorm.InnerProduct(p);
|
||||
if( dist > fPlanes[i].fDist )
|
||||
{
|
||||
fPlanes[i].fDist = dist;
|
||||
fPlanes[i].fPos = p;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
SinglePlane plane;
|
||||
plane.fNorm = nNorm;
|
||||
plane.fPos = p;
|
||||
plane.fDist = nNorm.InnerProduct(p);
|
||||
|
||||
fPlanes.Append(plane);
|
||||
}
|
||||
|
||||
void plConvexIsect::SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l)
|
||||
{
|
||||
int i;
|
||||
for( i = 0; i < fPlanes.GetCount(); i++ )
|
||||
{
|
||||
hsPoint3 wPos = l2w * fPlanes[i].fPos;
|
||||
|
||||
// Normal gets transpose of inverse.
|
||||
fPlanes[i].fWorldNorm.fX = w2l.fMap[0][0] * fPlanes[i].fNorm.fX
|
||||
+ w2l.fMap[1][0] * fPlanes[i].fNorm.fY
|
||||
+ w2l.fMap[2][0] * fPlanes[i].fNorm.fZ;
|
||||
|
||||
fPlanes[i].fWorldNorm.fY = w2l.fMap[0][1] * fPlanes[i].fNorm.fX
|
||||
+ w2l.fMap[1][1] * fPlanes[i].fNorm.fY
|
||||
+ w2l.fMap[2][1] * fPlanes[i].fNorm.fZ;
|
||||
|
||||
fPlanes[i].fWorldNorm.fZ = w2l.fMap[0][2] * fPlanes[i].fNorm.fX
|
||||
+ w2l.fMap[1][2] * fPlanes[i].fNorm.fY
|
||||
+ w2l.fMap[2][2] * fPlanes[i].fNorm.fZ;
|
||||
|
||||
hsFastMath::NormalizeAppr(fPlanes[i].fWorldNorm);
|
||||
|
||||
fPlanes[i].fWorldDist = fPlanes[i].fWorldNorm.InnerProduct(wPos);
|
||||
}
|
||||
}
|
||||
|
||||
plVolumeCullResult plConvexIsect::Test(const hsBounds3Ext& bnd) const
|
||||
{
|
||||
plVolumeCullResult retVal = kVolumeClear;
|
||||
int i;
|
||||
for( i = 0; i < fPlanes.GetCount(); i++ )
|
||||
{
|
||||
hsPoint2 depth;
|
||||
bnd.TestPlane(fPlanes[i].fWorldNorm, depth);
|
||||
|
||||
if( depth.fX > fPlanes[i].fWorldDist )
|
||||
return kVolumeCulled;
|
||||
|
||||
if( depth.fY > fPlanes[i].fWorldDist )
|
||||
retVal = kVolumeSplit;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
hsScalar plConvexIsect::Test(const hsPoint3& pos) const
|
||||
{
|
||||
hsScalar maxDist = 0;
|
||||
int i;
|
||||
for( i = 0; i < fPlanes.GetCount(); i++ )
|
||||
{
|
||||
hsScalar dist = fPlanes[i].fWorldNorm.InnerProduct(pos) - fPlanes[i].fWorldDist;
|
||||
|
||||
if( dist > maxDist )
|
||||
maxDist = dist;
|
||||
}
|
||||
return maxDist;
|
||||
}
|
||||
|
||||
void plConvexIsect::Read(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
Int16 n = s->ReadSwap16();
|
||||
|
||||
fPlanes.SetCount(n);
|
||||
int i;
|
||||
for( i = 0; i < n; i++ )
|
||||
{
|
||||
fPlanes[i].fNorm.Read(s);
|
||||
fPlanes[i].fPos.Read(s);
|
||||
fPlanes[i].fDist = s->ReadSwapScalar();
|
||||
|
||||
fPlanes[i].fWorldNorm.Read(s);
|
||||
fPlanes[i].fWorldDist = s->ReadSwapScalar();
|
||||
}
|
||||
}
|
||||
|
||||
void plConvexIsect::Write(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
s->WriteSwap16(fPlanes.GetCount());
|
||||
|
||||
int i;
|
||||
for( i = 0; i < fPlanes.GetCount(); i++ )
|
||||
{
|
||||
fPlanes[i].fNorm.Write(s);
|
||||
fPlanes[i].fPos.Write(s);
|
||||
s->WriteSwapScalar(fPlanes[i].fDist);
|
||||
|
||||
fPlanes[i].fWorldNorm.Write(s);
|
||||
s->WriteSwapScalar(fPlanes[i].fWorldDist);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
plBoundsIsect::plBoundsIsect()
|
||||
{
|
||||
}
|
||||
|
||||
plBoundsIsect::~plBoundsIsect()
|
||||
{
|
||||
}
|
||||
|
||||
void plBoundsIsect::SetBounds(const hsBounds3Ext& bnd)
|
||||
{
|
||||
fLocalBounds = bnd;
|
||||
fWorldBounds = bnd;
|
||||
}
|
||||
|
||||
void plBoundsIsect::SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l)
|
||||
{
|
||||
fWorldBounds = fLocalBounds;
|
||||
fWorldBounds.Transform(&l2w);
|
||||
}
|
||||
|
||||
plVolumeCullResult plBoundsIsect::Test(const hsBounds3Ext& bnd) const
|
||||
{
|
||||
int retVal = fWorldBounds.TestBound(bnd);
|
||||
if( retVal < 0 )
|
||||
return kVolumeCulled;
|
||||
if( retVal > 0 )
|
||||
return kVolumeClear;
|
||||
|
||||
retVal = bnd.TestBound(fWorldBounds);
|
||||
|
||||
return retVal < 0 ? kVolumeCulled : kVolumeSplit;
|
||||
}
|
||||
|
||||
hsScalar plBoundsIsect::Test(const hsPoint3& pos) const
|
||||
{
|
||||
hsAssert(false, "Unimplemented");
|
||||
return 0.f;
|
||||
}
|
||||
|
||||
void plBoundsIsect::Read(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
fLocalBounds.Read(s);
|
||||
fWorldBounds.Read(s);
|
||||
}
|
||||
|
||||
void plBoundsIsect::Write(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
fLocalBounds.Write(s);
|
||||
fWorldBounds.Write(s);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
plComplexIsect::plComplexIsect()
|
||||
{
|
||||
}
|
||||
|
||||
plComplexIsect::~plComplexIsect()
|
||||
{
|
||||
int i;
|
||||
for( i = 0; i < fVolumes.GetCount(); i++ )
|
||||
delete fVolumes[i];
|
||||
}
|
||||
|
||||
void plComplexIsect::AddVolume(plVolumeIsect* v)
|
||||
{
|
||||
fVolumes.Append(v);
|
||||
}
|
||||
|
||||
void plComplexIsect::SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l)
|
||||
{
|
||||
int i;
|
||||
for( i = 0; i < fVolumes.GetCount(); i++ )
|
||||
fVolumes[i]->SetTransform(l2w, w2l);
|
||||
}
|
||||
|
||||
void plComplexIsect::Read(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
int n = s->ReadSwap16();
|
||||
fVolumes.SetCount(n);
|
||||
int i;
|
||||
for( i = 0; i < n; i++ )
|
||||
{
|
||||
fVolumes[i] = plVolumeIsect::ConvertNoRef(mgr->ReadCreatable(s));
|
||||
hsAssert(fVolumes[i], "Failure reading in a sub-volume");
|
||||
}
|
||||
}
|
||||
|
||||
void plComplexIsect::Write(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
s->WriteSwap16(fVolumes.GetCount());
|
||||
int i;
|
||||
for( i = 0; i < fVolumes.GetCount(); i++ )
|
||||
mgr->WriteCreatable(s, fVolumes[i]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
plUnionIsect::plUnionIsect()
|
||||
{
|
||||
}
|
||||
|
||||
plUnionIsect::~plUnionIsect()
|
||||
{
|
||||
}
|
||||
|
||||
plVolumeCullResult plUnionIsect::Test(const hsBounds3Ext& bnd) const
|
||||
{
|
||||
plVolumeCullResult retVal = kVolumeCulled;
|
||||
int i;
|
||||
for( i = 0; i < fVolumes.GetCount(); i++ )
|
||||
{
|
||||
plVolumeCullResult ret = fVolumes[i]->Test(bnd);
|
||||
|
||||
switch( ret )
|
||||
{
|
||||
case kVolumeCulled:
|
||||
break;
|
||||
case kVolumeClear:
|
||||
return kVolumeClear;
|
||||
case kVolumeSplit:
|
||||
retVal = kVolumeSplit;
|
||||
break;
|
||||
};
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
hsScalar plUnionIsect::Test(const hsPoint3& pos) const
|
||||
{
|
||||
hsScalar retVal = 1.e33f;
|
||||
int i;
|
||||
for( i = 0; i < fVolumes.GetCount(); i++ )
|
||||
{
|
||||
hsScalar ret = fVolumes[i]->Test(pos);
|
||||
if( ret <= 0 )
|
||||
return 0;
|
||||
if( ret < retVal )
|
||||
retVal = ret;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
plIntersectionIsect::plIntersectionIsect()
|
||||
{
|
||||
}
|
||||
|
||||
plIntersectionIsect::~plIntersectionIsect()
|
||||
{
|
||||
}
|
||||
|
||||
plVolumeCullResult plIntersectionIsect::Test(const hsBounds3Ext& bnd) const
|
||||
{
|
||||
plVolumeCullResult retVal = kVolumeClear;
|
||||
int i;
|
||||
for( i = 0; i < fVolumes.GetCount(); i++ )
|
||||
{
|
||||
plVolumeCullResult ret = fVolumes[i]->Test(bnd);
|
||||
|
||||
switch( ret )
|
||||
{
|
||||
case kVolumeCulled:
|
||||
return kVolumeCulled;
|
||||
case kVolumeClear:
|
||||
break;
|
||||
case kVolumeSplit:
|
||||
retVal = kVolumeSplit;
|
||||
break;
|
||||
};
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
hsScalar plIntersectionIsect::Test(const hsPoint3& pos) const
|
||||
{
|
||||
hsScalar retVal = -1.f;
|
||||
int i;
|
||||
for( i = 0; i < fVolumes.GetCount(); i++ )
|
||||
{
|
||||
hsScalar ret = fVolumes[i]->Test(pos);
|
||||
if( ret > retVal )
|
||||
retVal = ret;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
@ -0,0 +1,308 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#ifndef plVolumeIsect_inc
|
||||
#define plVolumeIsect_inc
|
||||
|
||||
#include "hsGeometry3.h"
|
||||
#include "hsMatrix44.h"
|
||||
#include "hsTemplates.h"
|
||||
#include "hsBounds.h"
|
||||
|
||||
#include "../pnFactory/plCreatable.h"
|
||||
|
||||
class hsBounds3Ext;
|
||||
|
||||
enum plVolumeCullResult
|
||||
{
|
||||
kVolumeClear = 0x0,
|
||||
kVolumeCulled = 0x1,
|
||||
kVolumeSplit = 0x2
|
||||
};
|
||||
|
||||
|
||||
class plVolumeIsect : public plCreatable
|
||||
{
|
||||
public:
|
||||
CLASSNAME_REGISTER( plVolumeIsect );
|
||||
GETINTERFACE_ANY( plVolumeIsect, plCreatable );
|
||||
|
||||
virtual void SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l) = 0;
|
||||
virtual plVolumeCullResult Test(const hsBounds3Ext& bnd) const = 0;
|
||||
virtual hsScalar Test(const hsPoint3& pos) const = 0;
|
||||
|
||||
virtual void Read(hsStream* s, hsResMgr* mgr) = 0;
|
||||
virtual void Write(hsStream* s, hsResMgr* mgr) = 0;
|
||||
};
|
||||
|
||||
class plSphereIsect : public plVolumeIsect
|
||||
{
|
||||
protected:
|
||||
hsPoint3 fCenter;
|
||||
hsPoint3 fWorldCenter;
|
||||
hsScalar fRadius;
|
||||
hsPoint3 fMins;
|
||||
hsPoint3 fMaxs;
|
||||
public:
|
||||
plSphereIsect();
|
||||
virtual ~plSphereIsect();
|
||||
|
||||
CLASSNAME_REGISTER( plSphereIsect );
|
||||
GETINTERFACE_ANY( plSphereIsect, plVolumeIsect );
|
||||
|
||||
void SetCenter(const hsPoint3& c);
|
||||
void SetRadius(hsScalar r);
|
||||
|
||||
hsScalar GetRadius() const { return fRadius; }
|
||||
|
||||
virtual void SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l);
|
||||
|
||||
virtual plVolumeCullResult Test(const hsBounds3Ext& bnd) const;
|
||||
virtual hsScalar Test(const hsPoint3& pos) const; // return 0 if point inside, else "distance" from pos to volume
|
||||
|
||||
virtual void Read(hsStream* s, hsResMgr* mgr);
|
||||
virtual void Write(hsStream* s, hsResMgr* mgr);
|
||||
};
|
||||
|
||||
class plConeIsect : public plVolumeIsect
|
||||
{
|
||||
protected:
|
||||
hsBool fCapped;
|
||||
|
||||
hsScalar fRadAngle;
|
||||
hsScalar fLength;
|
||||
|
||||
hsPoint3 fWorldTip;
|
||||
hsVector3 fWorldNorm;
|
||||
|
||||
hsMatrix44 fWorldToNDC;
|
||||
hsMatrix44 fLightToNDC;
|
||||
|
||||
hsVector3 fNorms[5];
|
||||
hsScalar fDists[5];
|
||||
|
||||
void ISetup();
|
||||
public:
|
||||
|
||||
plConeIsect();
|
||||
virtual ~plConeIsect();
|
||||
|
||||
CLASSNAME_REGISTER( plConeIsect );
|
||||
GETINTERFACE_ANY( plConeIsect, plVolumeIsect );
|
||||
|
||||
void SetAngle(hsScalar rads);
|
||||
void SetLength(hsScalar d);
|
||||
|
||||
hsScalar GetLength() const { return fCapped ? fLength : 0; }
|
||||
hsScalar GetAngle() const { return fRadAngle; }
|
||||
|
||||
virtual void SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l);
|
||||
|
||||
virtual plVolumeCullResult Test(const hsBounds3Ext& bnd) const;
|
||||
virtual hsScalar Test(const hsPoint3& pos) const;
|
||||
|
||||
virtual void Read(hsStream* s, hsResMgr* mgr);
|
||||
virtual void Write(hsStream* s, hsResMgr* mgr);
|
||||
};
|
||||
|
||||
class plCylinderIsect : public plVolumeIsect
|
||||
{
|
||||
protected:
|
||||
hsPoint3 fTop;
|
||||
hsPoint3 fBot;
|
||||
hsScalar fRadius;
|
||||
|
||||
hsPoint3 fWorldBot;
|
||||
hsVector3 fWorldNorm;
|
||||
hsScalar fLength;
|
||||
hsScalar fMin;
|
||||
hsScalar fMax;
|
||||
|
||||
void ISetupCyl(const hsPoint3& wTop, const hsPoint3& wBot, hsScalar radius);
|
||||
|
||||
public:
|
||||
plCylinderIsect();
|
||||
virtual ~plCylinderIsect();
|
||||
|
||||
CLASSNAME_REGISTER( plCylinderIsect );
|
||||
GETINTERFACE_ANY( plCylinderIsect, plVolumeIsect );
|
||||
|
||||
void SetCylinder(const hsPoint3& lTop, const hsPoint3& lBot, hsScalar radius);
|
||||
void SetCylinder(const hsPoint3& lBot, const hsVector3& axis, hsScalar radius);
|
||||
|
||||
virtual void SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l);
|
||||
|
||||
virtual plVolumeCullResult Test(const hsBounds3Ext& bnd) const;
|
||||
virtual hsScalar Test(const hsPoint3& pos) const;
|
||||
|
||||
virtual void Read(hsStream* s, hsResMgr* mgr);
|
||||
virtual void Write(hsStream* s, hsResMgr* mgr);
|
||||
};
|
||||
|
||||
class plParallelIsect : public plVolumeIsect
|
||||
{
|
||||
protected:
|
||||
class ParPlane
|
||||
{
|
||||
public:
|
||||
hsVector3 fNorm;
|
||||
hsScalar fMin;
|
||||
hsScalar fMax;
|
||||
|
||||
hsPoint3 fPosOne;
|
||||
hsPoint3 fPosTwo;
|
||||
};
|
||||
hsTArray<ParPlane> fPlanes;
|
||||
|
||||
public:
|
||||
plParallelIsect();
|
||||
virtual ~plParallelIsect();
|
||||
|
||||
CLASSNAME_REGISTER( plParallelIsect );
|
||||
GETINTERFACE_ANY( plParallelIsect, plVolumeIsect );
|
||||
|
||||
void SetNumPlanes(int n); // each plane is really two parallel planes
|
||||
UInt16 GetNumPlanes() const { return fPlanes.GetCount(); }
|
||||
|
||||
void SetPlane(int which, const hsPoint3& locPosOne, const hsPoint3& locPosTwo);
|
||||
|
||||
virtual void SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l);
|
||||
|
||||
virtual plVolumeCullResult Test(const hsBounds3Ext& bnd) const;
|
||||
virtual hsScalar Test(const hsPoint3& pos) const;
|
||||
|
||||
virtual void Read(hsStream* s, hsResMgr* mgr);
|
||||
virtual void Write(hsStream* s, hsResMgr* mgr);
|
||||
};
|
||||
|
||||
class plConvexIsect : public plVolumeIsect
|
||||
{
|
||||
protected:
|
||||
class SinglePlane
|
||||
{
|
||||
public:
|
||||
hsVector3 fNorm;
|
||||
hsScalar fDist;
|
||||
hsPoint3 fPos;
|
||||
|
||||
hsVector3 fWorldNorm;
|
||||
hsScalar fWorldDist;
|
||||
};
|
||||
|
||||
hsTArray<SinglePlane> fPlanes;
|
||||
|
||||
public:
|
||||
plConvexIsect();
|
||||
virtual ~plConvexIsect();
|
||||
|
||||
CLASSNAME_REGISTER( plConvexIsect );
|
||||
GETINTERFACE_ANY( plConvexIsect, plVolumeIsect );
|
||||
|
||||
void ClearPlanes() { fPlanes.SetCount(0); }
|
||||
void AddPlaneUnchecked(const hsVector3& n, hsScalar dist); // no validation here
|
||||
void AddPlane(const hsVector3& n, const hsPoint3& p);
|
||||
UInt16 GetNumPlanes() const { return fPlanes.GetCount(); }
|
||||
|
||||
virtual void SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l);
|
||||
|
||||
virtual plVolumeCullResult Test(const hsBounds3Ext& bnd) const;
|
||||
virtual hsScalar Test(const hsPoint3& pos) const;
|
||||
|
||||
virtual void Read(hsStream* s, hsResMgr* mgr);
|
||||
virtual void Write(hsStream* s, hsResMgr* mgr);
|
||||
};
|
||||
|
||||
class plBoundsIsect : public plVolumeIsect
|
||||
{
|
||||
protected:
|
||||
hsBounds3Ext fLocalBounds;
|
||||
hsBounds3Ext fWorldBounds;
|
||||
public:
|
||||
plBoundsIsect();
|
||||
virtual ~plBoundsIsect();
|
||||
|
||||
CLASSNAME_REGISTER( plBoundsIsect );
|
||||
GETINTERFACE_ANY( plBoundsIsect, plVolumeIsect );
|
||||
|
||||
void SetBounds(const hsBounds3Ext& bnd);
|
||||
|
||||
virtual void SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l);
|
||||
|
||||
virtual plVolumeCullResult Test(const hsBounds3Ext& bnd) const;
|
||||
virtual hsScalar Test(const hsPoint3& pos) const;
|
||||
|
||||
virtual void Read(hsStream* s, hsResMgr* mgr);
|
||||
virtual void Write(hsStream* s, hsResMgr* mgr);
|
||||
};
|
||||
|
||||
class plComplexIsect : public plVolumeIsect
|
||||
{
|
||||
protected:
|
||||
hsTArray<plVolumeIsect*> fVolumes;
|
||||
|
||||
public:
|
||||
plComplexIsect();
|
||||
virtual ~plComplexIsect();
|
||||
|
||||
CLASSNAME_REGISTER( plComplexIsect );
|
||||
GETINTERFACE_ANY( plComplexIsect, plVolumeIsect );
|
||||
|
||||
void AddVolume(plVolumeIsect* v); // Will capture pointer
|
||||
UInt16 GetNumVolumes() const { return fVolumes.GetCount(); }
|
||||
|
||||
virtual void SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l);
|
||||
|
||||
virtual void Read(hsStream* s, hsResMgr* mgr);
|
||||
virtual void Write(hsStream* s, hsResMgr* mgr);
|
||||
};
|
||||
|
||||
class plUnionIsect : public plComplexIsect
|
||||
{
|
||||
public:
|
||||
plUnionIsect();
|
||||
~plUnionIsect();
|
||||
|
||||
CLASSNAME_REGISTER( plUnionIsect );
|
||||
GETINTERFACE_ANY( plUnionIsect, plComplexIsect );
|
||||
|
||||
virtual plVolumeCullResult Test(const hsBounds3Ext& bnd) const;
|
||||
virtual hsScalar Test(const hsPoint3& pos) const;
|
||||
};
|
||||
|
||||
class plIntersectionIsect : public plComplexIsect
|
||||
{
|
||||
public:
|
||||
plIntersectionIsect();
|
||||
~plIntersectionIsect();
|
||||
|
||||
CLASSNAME_REGISTER( plIntersectionIsect );
|
||||
GETINTERFACE_ANY( plIntersectionIsect, plComplexIsect );
|
||||
|
||||
virtual plVolumeCullResult Test(const hsBounds3Ext& bnd) const;
|
||||
virtual hsScalar Test(const hsPoint3& pos) const;
|
||||
};
|
||||
|
||||
#endif // plVolumeIsect_inc
|
Reference in New Issue
Block a user