mirror of
https://github.com/EQEmu/Server.git
synced 2026-02-18 06:32:25 +00:00
RaycastMesh work der started I'm going to pick up...
This commit is contained in:
parent
14649ce611
commit
eabea6ea16
@ -95,6 +95,7 @@ SET(zone_sources
|
||||
questmgr.cpp
|
||||
QuestParserCollection.cpp
|
||||
raids.cpp
|
||||
RaycastMesh.cpp
|
||||
spawn2.cpp
|
||||
spawn2.h
|
||||
spawngroup.cpp
|
||||
@ -183,6 +184,7 @@ SET(zone_headers
|
||||
QuestParserCollection.h
|
||||
raid.h
|
||||
raids.h
|
||||
RaycastMesh.h
|
||||
skills.h
|
||||
spawn2.cpp
|
||||
spawn2.h
|
||||
|
||||
1025
zone/Map.cpp
1025
zone/Map.cpp
File diff suppressed because it is too large
Load Diff
938
zone/RaycastMesh.cpp
Normal file
938
zone/RaycastMesh.cpp
Normal file
@ -0,0 +1,938 @@
|
||||
#include "RaycastMesh.h"
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <vector>
|
||||
|
||||
// This code snippet allows you to create an axis aligned bounding volume tree for a triangle mesh so that you can do
|
||||
// high-speed raycasting.
|
||||
//
|
||||
// There are much better implementations of this available on the internet. In particular I recommend that you use
|
||||
// OPCODE written by Pierre Terdiman.
|
||||
// @see: http://www.codercorner.com/Opcode.htm
|
||||
//
|
||||
// OPCODE does a whole lot more than just raycasting, and is a rather significant amount of source code.
|
||||
//
|
||||
// I am providing this code snippet for the use case where you *only* want to do quick and dirty optimized raycasting.
|
||||
// I have not done performance testing between this version and OPCODE; so I don't know how much slower it is. However,
|
||||
// anytime you switch to using a spatial data structure for raycasting, you increase your performance by orders and orders
|
||||
// of magnitude; so this implementation should work fine for simple tools and utilities.
|
||||
//
|
||||
// It also serves as a nice sample for people who are trying to learn the algorithm of how to implement AABB trees.
|
||||
// AABB = Axis Aligned Bounding Volume trees.
|
||||
//
|
||||
// http://www.cgal.org/Manual/3.5/doc_html/cgal_manual/AABB_tree/Chapter_main.html
|
||||
//
|
||||
//
|
||||
// This code snippet was written by John W. Ratcliff on August 18, 2011 and released under the MIT. license.
|
||||
//
|
||||
// mailto:jratcliffscarab@gmail.com
|
||||
//
|
||||
// The official source can be found at: http://code.google.com/p/raycastmesh/
|
||||
//
|
||||
//
|
||||
|
||||
#pragma warning(disable:4100)
|
||||
|
||||
namespace RAYCAST_MESH
|
||||
{
|
||||
|
||||
typedef std::vector< RmUint32 > TriVector;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* A method to compute a ray-AABB intersection.
|
||||
* Original code by Andrew Woo, from "Graphics Gems", Academic Press, 1990
|
||||
* Optimized code by Pierre Terdiman, 2000 (~20-30% faster on my Celeron 500)
|
||||
* Epsilon value added by Klaus Hartmann. (discarding it saves a few cycles only)
|
||||
*
|
||||
* Hence this version is faster as well as more robust than the original one.
|
||||
*
|
||||
* Should work provided:
|
||||
* 1) the integer representation of 0.0f is 0x00000000
|
||||
* 2) the sign bit of the RmReal is the most significant one
|
||||
*
|
||||
* Report bugs: p.terdiman@codercorner.com
|
||||
*
|
||||
* \param aabb [in] the axis-aligned bounding box
|
||||
* \param origin [in] ray origin
|
||||
* \param dir [in] ray direction
|
||||
* \param coord [out] impact coordinates
|
||||
* \return true if ray intersects AABB
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#define RAYAABB_EPSILON 0.00001f
|
||||
//! Integer representation of a RmRealing-point value.
|
||||
#define IR(x) ((RmUint32&)x)
|
||||
|
||||
bool intersectRayAABB(const RmReal MinB[3],const RmReal MaxB[3],const RmReal origin[3],const RmReal dir[3],RmReal coord[3])
|
||||
{
|
||||
bool Inside = true;
|
||||
RmReal MaxT[3];
|
||||
MaxT[0]=MaxT[1]=MaxT[2]=-1.0f;
|
||||
|
||||
// Find candidate planes.
|
||||
for(RmUint32 i=0;i<3;i++)
|
||||
{
|
||||
if(origin[i] < MinB[i])
|
||||
{
|
||||
coord[i] = MinB[i];
|
||||
Inside = false;
|
||||
|
||||
// Calculate T distances to candidate planes
|
||||
if(IR(dir[i])) MaxT[i] = (MinB[i] - origin[i]) / dir[i];
|
||||
}
|
||||
else if(origin[i] > MaxB[i])
|
||||
{
|
||||
coord[i] = MaxB[i];
|
||||
Inside = false;
|
||||
|
||||
// Calculate T distances to candidate planes
|
||||
if(IR(dir[i])) MaxT[i] = (MaxB[i] - origin[i]) / dir[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Ray origin inside bounding box
|
||||
if(Inside)
|
||||
{
|
||||
coord[0] = origin[0];
|
||||
coord[1] = origin[1];
|
||||
coord[2] = origin[2];
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get largest of the maxT's for final choice of intersection
|
||||
RmUint32 WhichPlane = 0;
|
||||
if(MaxT[1] > MaxT[WhichPlane]) WhichPlane = 1;
|
||||
if(MaxT[2] > MaxT[WhichPlane]) WhichPlane = 2;
|
||||
|
||||
// Check final candidate actually inside box
|
||||
if(IR(MaxT[WhichPlane])&0x80000000) return false;
|
||||
|
||||
for(RmUint32 i=0;i<3;i++)
|
||||
{
|
||||
if(i!=WhichPlane)
|
||||
{
|
||||
coord[i] = origin[i] + MaxT[WhichPlane] * dir[i];
|
||||
#ifdef RAYAABB_EPSILON
|
||||
if(coord[i] < MinB[i] - RAYAABB_EPSILON || coord[i] > MaxB[i] + RAYAABB_EPSILON) return false;
|
||||
#else
|
||||
if(coord[i] < MinB[i] || coord[i] > MaxB[i]) return false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return true; // ray hits box
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool intersectLineSegmentAABB(const RmReal bmin[3],const RmReal bmax[3],const RmReal p1[3],const RmReal dir[3],RmReal &dist,RmReal intersect[3])
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if ( dist > RAYAABB_EPSILON )
|
||||
{
|
||||
ret = intersectRayAABB(bmin,bmax,p1,dir,intersect);
|
||||
if ( ret )
|
||||
{
|
||||
RmReal dx = p1[0]-intersect[0];
|
||||
RmReal dy = p1[1]-intersect[1];
|
||||
RmReal dz = p1[2]-intersect[2];
|
||||
RmReal d = dx*dx+dy*dy+dz*dz;
|
||||
if ( d < dist*dist )
|
||||
{
|
||||
dist = sqrtf(d);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* a = b - c */
|
||||
#define vector(a,b,c) \
|
||||
(a)[0] = (b)[0] - (c)[0]; \
|
||||
(a)[1] = (b)[1] - (c)[1]; \
|
||||
(a)[2] = (b)[2] - (c)[2];
|
||||
|
||||
#define innerProduct(v,q) \
|
||||
((v)[0] * (q)[0] + \
|
||||
(v)[1] * (q)[1] + \
|
||||
(v)[2] * (q)[2])
|
||||
|
||||
#define crossProduct(a,b,c) \
|
||||
(a)[0] = (b)[1] * (c)[2] - (c)[1] * (b)[2]; \
|
||||
(a)[1] = (b)[2] * (c)[0] - (c)[2] * (b)[0]; \
|
||||
(a)[2] = (b)[0] * (c)[1] - (c)[0] * (b)[1];
|
||||
|
||||
|
||||
static inline bool rayIntersectsTriangle(const RmReal *p,const RmReal *d,const RmReal *v0,const RmReal *v1,const RmReal *v2,RmReal &t)
|
||||
{
|
||||
RmReal e1[3],e2[3],h[3],s[3],q[3];
|
||||
RmReal a,f,u,v;
|
||||
|
||||
vector(e1,v1,v0);
|
||||
vector(e2,v2,v0);
|
||||
crossProduct(h,d,e2);
|
||||
a = innerProduct(e1,h);
|
||||
|
||||
if (a > -0.00001 && a < 0.00001)
|
||||
return(false);
|
||||
|
||||
f = 1/a;
|
||||
vector(s,p,v0);
|
||||
u = f * (innerProduct(s,h));
|
||||
|
||||
if (u < 0.0 || u > 1.0)
|
||||
return(false);
|
||||
|
||||
crossProduct(q,s,e1);
|
||||
v = f * innerProduct(d,q);
|
||||
if (v < 0.0 || u + v > 1.0)
|
||||
return(false);
|
||||
// at this stage we can compute t to find out where
|
||||
// the intersection point is on the line
|
||||
t = f * innerProduct(e2,q);
|
||||
if (t > 0) // ray intersection
|
||||
return(true);
|
||||
else // this means that there is a line intersection
|
||||
// but not a ray intersection
|
||||
return (false);
|
||||
}
|
||||
|
||||
static RmReal computePlane(const RmReal *A,const RmReal *B,const RmReal *C,RmReal *n) // returns D
|
||||
{
|
||||
RmReal vx = (B[0] - C[0]);
|
||||
RmReal vy = (B[1] - C[1]);
|
||||
RmReal vz = (B[2] - C[2]);
|
||||
|
||||
RmReal wx = (A[0] - B[0]);
|
||||
RmReal wy = (A[1] - B[1]);
|
||||
RmReal wz = (A[2] - B[2]);
|
||||
|
||||
RmReal vw_x = vy * wz - vz * wy;
|
||||
RmReal vw_y = vz * wx - vx * wz;
|
||||
RmReal vw_z = vx * wy - vy * wx;
|
||||
|
||||
RmReal mag = sqrt((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z));
|
||||
|
||||
if ( mag < 0.000001f )
|
||||
{
|
||||
mag = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
mag = 1.0f/mag;
|
||||
}
|
||||
|
||||
RmReal x = vw_x * mag;
|
||||
RmReal y = vw_y * mag;
|
||||
RmReal z = vw_z * mag;
|
||||
|
||||
|
||||
RmReal D = 0.0f - ((x*A[0])+(y*A[1])+(z*A[2]));
|
||||
|
||||
n[0] = x;
|
||||
n[1] = y;
|
||||
n[2] = z;
|
||||
|
||||
return D;
|
||||
}
|
||||
|
||||
|
||||
#define TRI_EOF 0xFFFFFFFF
|
||||
|
||||
enum AxisAABB
|
||||
{
|
||||
AABB_XAXIS,
|
||||
AABB_YAXIS,
|
||||
AABB_ZAXIS
|
||||
};
|
||||
|
||||
enum ClipCode
|
||||
{
|
||||
CC_MINX = (1<<0),
|
||||
CC_MAXX = (1<<1),
|
||||
CC_MINY = (1<<2),
|
||||
CC_MAXY = (1<<3),
|
||||
CC_MINZ = (1<<4),
|
||||
CC_MAXZ = (1<<5),
|
||||
};
|
||||
|
||||
|
||||
class BoundsAABB
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
void setMin(const RmReal *v)
|
||||
{
|
||||
mMin[0] = v[0];
|
||||
mMin[1] = v[1];
|
||||
mMin[2] = v[2];
|
||||
}
|
||||
|
||||
void setMax(const RmReal *v)
|
||||
{
|
||||
mMax[0] = v[0];
|
||||
mMax[1] = v[1];
|
||||
mMax[2] = v[2];
|
||||
}
|
||||
|
||||
void setMin(RmReal x,RmReal y,RmReal z)
|
||||
{
|
||||
mMin[0] = x;
|
||||
mMin[1] = y;
|
||||
mMin[2] = z;
|
||||
}
|
||||
|
||||
void setMax(RmReal x,RmReal y,RmReal z)
|
||||
{
|
||||
mMax[0] = x;
|
||||
mMax[1] = y;
|
||||
mMax[2] = z;
|
||||
}
|
||||
|
||||
void include(const RmReal *v)
|
||||
{
|
||||
if ( v[0] < mMin[0] ) mMin[0] = v[0];
|
||||
if ( v[1] < mMin[1] ) mMin[1] = v[1];
|
||||
if ( v[2] < mMin[2] ) mMin[2] = v[2];
|
||||
|
||||
if ( v[0] > mMax[0] ) mMax[0] = v[0];
|
||||
if ( v[1] > mMax[1] ) mMax[1] = v[1];
|
||||
if ( v[2] > mMax[2] ) mMax[2] = v[2];
|
||||
}
|
||||
|
||||
void getCenter(RmReal *center) const
|
||||
{
|
||||
center[0] = (mMin[0]+mMax[0])*0.5f;
|
||||
center[1] = (mMin[1]+mMax[1])*0.5f;
|
||||
center[2] = (mMin[2]+mMax[2])*0.5f;
|
||||
}
|
||||
|
||||
bool intersects(const BoundsAABB &b) const
|
||||
{
|
||||
if ((mMin[0] > b.mMax[0]) || (b.mMin[0] > mMax[0])) return false;
|
||||
if ((mMin[1] > b.mMax[1]) || (b.mMin[1] > mMax[1])) return false;
|
||||
if ((mMin[2] > b.mMax[2]) || (b.mMin[2] > mMax[2])) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool containsTriangle(const RmReal *p1,const RmReal *p2,const RmReal *p3) const
|
||||
{
|
||||
BoundsAABB b;
|
||||
b.setMin(p1);
|
||||
b.setMax(p1);
|
||||
b.include(p2);
|
||||
b.include(p3);
|
||||
return intersects(b);
|
||||
}
|
||||
|
||||
bool containsTriangleExact(const RmReal *p1,const RmReal *p2,const RmReal *p3,RmUint32 &orCode) const
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
RmUint32 andCode;
|
||||
orCode = getClipCode(p1,p2,p3,andCode);
|
||||
if ( andCode == 0 )
|
||||
{
|
||||
ret = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline RmUint32 getClipCode(const RmReal *p1,const RmReal *p2,const RmReal *p3,RmUint32 &andCode) const
|
||||
{
|
||||
andCode = 0xFFFFFFFF;
|
||||
RmUint32 c1 = getClipCode(p1);
|
||||
RmUint32 c2 = getClipCode(p2);
|
||||
RmUint32 c3 = getClipCode(p3);
|
||||
andCode&=c1;
|
||||
andCode&=c2;
|
||||
andCode&=c3;
|
||||
return c1|c2|c3;
|
||||
}
|
||||
|
||||
inline RmUint32 getClipCode(const RmReal *p) const
|
||||
{
|
||||
RmUint32 ret = 0;
|
||||
|
||||
if ( p[0] < mMin[0] )
|
||||
{
|
||||
ret|=CC_MINX;
|
||||
}
|
||||
else if ( p[0] > mMax[0] )
|
||||
{
|
||||
ret|=CC_MAXX;
|
||||
}
|
||||
|
||||
if ( p[1] < mMin[1] )
|
||||
{
|
||||
ret|=CC_MINY;
|
||||
}
|
||||
else if ( p[1] > mMax[1] )
|
||||
{
|
||||
ret|=CC_MAXY;
|
||||
}
|
||||
|
||||
if ( p[2] < mMin[2] )
|
||||
{
|
||||
ret|=CC_MINZ;
|
||||
}
|
||||
else if ( p[2] > mMax[2] )
|
||||
{
|
||||
ret|=CC_MAXZ;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline void clamp(const BoundsAABB &aabb)
|
||||
{
|
||||
if ( mMin[0] < aabb.mMin[0] ) mMin[0] = aabb.mMin[0];
|
||||
if ( mMin[1] < aabb.mMin[1] ) mMin[1] = aabb.mMin[1];
|
||||
if ( mMin[2] < aabb.mMin[2] ) mMin[2] = aabb.mMin[2];
|
||||
if ( mMax[0] > aabb.mMax[0] ) mMax[0] = aabb.mMax[0];
|
||||
if ( mMax[1] > aabb.mMax[1] ) mMax[1] = aabb.mMax[1];
|
||||
if ( mMax[2] > aabb.mMax[2] ) mMax[2] = aabb.mMax[2];
|
||||
}
|
||||
|
||||
RmReal mMin[3];
|
||||
RmReal mMax[3];
|
||||
};
|
||||
|
||||
|
||||
class NodeAABB;
|
||||
|
||||
class NodeInterface
|
||||
{
|
||||
public:
|
||||
virtual NodeAABB * getNode(void) = 0;
|
||||
virtual void getFaceNormal(RmUint32 tri,RmReal *faceNormal) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class NodeAABB
|
||||
{
|
||||
public:
|
||||
NodeAABB(void)
|
||||
{
|
||||
mLeft = NULL;
|
||||
mRight = NULL;
|
||||
mLeafTriangleIndex= TRI_EOF;
|
||||
}
|
||||
|
||||
NodeAABB(RmUint32 vcount,const RmReal *vertices,RmUint32 tcount,RmUint32 *indices,
|
||||
RmUint32 maxDepth, // Maximum recursion depth for the triangle mesh.
|
||||
RmUint32 minLeafSize, // minimum triangles to treat as a 'leaf' node.
|
||||
RmReal minAxisSize,
|
||||
NodeInterface *callback,
|
||||
TriVector &leafTriangles) // once a particular axis is less than this size, stop sub-dividing.
|
||||
|
||||
{
|
||||
mLeft = NULL;
|
||||
mRight = NULL;
|
||||
mLeafTriangleIndex = TRI_EOF;
|
||||
TriVector triangles;
|
||||
triangles.reserve(tcount);
|
||||
for (RmUint32 i=0; i<tcount; i++)
|
||||
{
|
||||
triangles.push_back(i);
|
||||
}
|
||||
mBounds.setMin( vertices );
|
||||
mBounds.setMax( vertices );
|
||||
const RmReal *vtx = vertices+3;
|
||||
for (RmUint32 i=1; i<vcount; i++)
|
||||
{
|
||||
mBounds.include( vtx );
|
||||
vtx+=3;
|
||||
}
|
||||
split(triangles,vcount,vertices,tcount,indices,0,maxDepth,minLeafSize,minAxisSize,callback,leafTriangles);
|
||||
}
|
||||
|
||||
NodeAABB(const BoundsAABB &aabb)
|
||||
{
|
||||
mBounds = aabb;
|
||||
mLeft = NULL;
|
||||
mRight = NULL;
|
||||
mLeafTriangleIndex = TRI_EOF;
|
||||
}
|
||||
|
||||
~NodeAABB(void)
|
||||
{
|
||||
}
|
||||
|
||||
// here is where we split the mesh..
|
||||
void split(const TriVector &triangles,
|
||||
RmUint32 vcount,
|
||||
const RmReal *vertices,
|
||||
RmUint32 tcount,
|
||||
const RmUint32 *indices,
|
||||
RmUint32 depth,
|
||||
RmUint32 maxDepth, // Maximum recursion depth for the triangle mesh.
|
||||
RmUint32 minLeafSize, // minimum triangles to treat as a 'leaf' node.
|
||||
RmReal minAxisSize,
|
||||
NodeInterface *callback,
|
||||
TriVector &leafTriangles) // once a particular axis is less than this size, stop sub-dividing.
|
||||
|
||||
{
|
||||
// Find the longest axis of the bounding volume of this node
|
||||
RmReal dx = mBounds.mMax[0] - mBounds.mMin[0];
|
||||
RmReal dy = mBounds.mMax[1] - mBounds.mMin[1];
|
||||
RmReal dz = mBounds.mMax[2] - mBounds.mMin[2];
|
||||
|
||||
AxisAABB axis = AABB_XAXIS;
|
||||
RmReal laxis = dx;
|
||||
|
||||
if ( dy > dx )
|
||||
{
|
||||
axis = AABB_YAXIS;
|
||||
laxis = dy;
|
||||
}
|
||||
|
||||
if ( dz > dx && dz > dy )
|
||||
{
|
||||
axis = AABB_ZAXIS;
|
||||
laxis = dz;
|
||||
}
|
||||
|
||||
RmUint32 count = triangles.size();
|
||||
|
||||
// if the number of triangles is less than the minimum allowed for a leaf node or...
|
||||
// we have reached the maximum recursion depth or..
|
||||
// the width of the longest axis is less than the minimum axis size then...
|
||||
// we create the leaf node and copy the triangles into the leaf node triangle array.
|
||||
if ( count < minLeafSize || depth >= maxDepth || laxis < minAxisSize )
|
||||
{
|
||||
// Copy the triangle indices into the leaf triangles array
|
||||
mLeafTriangleIndex = leafTriangles.size(); // assign the array start location for these leaf triangles.
|
||||
leafTriangles.push_back(count);
|
||||
for (TriVector::const_iterator i=triangles.begin(); i!=triangles.end(); ++i)
|
||||
{
|
||||
RmUint32 tri = *i;
|
||||
leafTriangles.push_back(tri);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RmReal center[3];
|
||||
mBounds.getCenter(center);
|
||||
BoundsAABB b1,b2;
|
||||
splitRect(axis,mBounds,b1,b2,center);
|
||||
|
||||
// Compute two bounding boxes based upon the split of the longest axis
|
||||
|
||||
BoundsAABB leftBounds,rightBounds;
|
||||
|
||||
TriVector leftTriangles;
|
||||
TriVector rightTriangles;
|
||||
|
||||
|
||||
// Create two arrays; one of all triangles which intersect the 'left' half of the bounding volume node
|
||||
// and another array that includes all triangles which intersect the 'right' half of the bounding volume node.
|
||||
for (TriVector::const_iterator i=triangles.begin(); i!=triangles.end(); ++i)
|
||||
{
|
||||
|
||||
RmUint32 tri = (*i);
|
||||
|
||||
{
|
||||
RmUint32 i1 = indices[tri*3+0];
|
||||
RmUint32 i2 = indices[tri*3+1];
|
||||
RmUint32 i3 = indices[tri*3+2];
|
||||
|
||||
const RmReal *p1 = &vertices[i1*3];
|
||||
const RmReal *p2 = &vertices[i2*3];
|
||||
const RmReal *p3 = &vertices[i3*3];
|
||||
|
||||
RmUint32 addCount = 0;
|
||||
RmUint32 orCode=0xFFFFFFFF;
|
||||
if ( b1.containsTriangleExact(p1,p2,p3,orCode))
|
||||
{
|
||||
addCount++;
|
||||
if ( leftTriangles.empty() )
|
||||
{
|
||||
leftBounds.setMin(p1);
|
||||
leftBounds.setMax(p1);
|
||||
}
|
||||
leftBounds.include(p1);
|
||||
leftBounds.include(p2);
|
||||
leftBounds.include(p3);
|
||||
leftTriangles.push_back(tri); // Add this triangle to the 'left triangles' array and revise the left triangles bounding volume
|
||||
}
|
||||
// if the orCode is zero; meaning the triangle was fully self-contiained int he left bounding box; then we don't need to test against the right
|
||||
if ( orCode && b2.containsTriangleExact(p1,p2,p3,orCode))
|
||||
{
|
||||
addCount++;
|
||||
if ( rightTriangles.empty() )
|
||||
{
|
||||
rightBounds.setMin(p1);
|
||||
rightBounds.setMax(p1);
|
||||
}
|
||||
rightBounds.include(p1);
|
||||
rightBounds.include(p2);
|
||||
rightBounds.include(p3);
|
||||
rightTriangles.push_back(tri); // Add this triangle to the 'right triangles' array and revise the right triangles bounding volume.
|
||||
}
|
||||
assert( addCount );
|
||||
}
|
||||
}
|
||||
|
||||
if ( !leftTriangles.empty() ) // If there are triangles in the left half then...
|
||||
{
|
||||
leftBounds.clamp(b1); // we have to clamp the bounding volume so it stays inside the parent volume.
|
||||
mLeft = callback->getNode(); // get a new AABB node
|
||||
new ( mLeft ) NodeAABB(leftBounds); // initialize it to default constructor values.
|
||||
// Then recursively split this node.
|
||||
mLeft->split(leftTriangles,vcount,vertices,tcount,indices,depth+1,maxDepth,minLeafSize,minAxisSize,callback,leafTriangles);
|
||||
}
|
||||
|
||||
if ( !rightTriangles.empty() ) // If there are triangles in the right half then..
|
||||
{
|
||||
rightBounds.clamp(b2); // clamps the bounding volume so it stays restricted to the size of the parent volume.
|
||||
mRight = callback->getNode(); // allocate and default initialize a new node
|
||||
new ( mRight ) NodeAABB(rightBounds);
|
||||
// Recursively split this node.
|
||||
mRight->split(rightTriangles,vcount,vertices,tcount,indices,depth+1,maxDepth,minLeafSize,minAxisSize,callback,leafTriangles);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void splitRect(AxisAABB axis,const BoundsAABB &source,BoundsAABB &b1,BoundsAABB &b2,const RmReal *midpoint)
|
||||
{
|
||||
switch ( axis )
|
||||
{
|
||||
case AABB_XAXIS:
|
||||
{
|
||||
b1.setMin( source.mMin );
|
||||
b1.setMax( midpoint[0], source.mMax[1], source.mMax[2] );
|
||||
|
||||
b2.setMin( midpoint[0], source.mMin[1], source.mMin[2] );
|
||||
b2.setMax(source.mMax);
|
||||
}
|
||||
break;
|
||||
case AABB_YAXIS:
|
||||
{
|
||||
b1.setMin(source.mMin);
|
||||
b1.setMax(source.mMax[0], midpoint[1], source.mMax[2]);
|
||||
|
||||
b2.setMin(source.mMin[0], midpoint[1], source.mMin[2]);
|
||||
b2.setMax(source.mMax);
|
||||
}
|
||||
break;
|
||||
case AABB_ZAXIS:
|
||||
{
|
||||
b1.setMin(source.mMin);
|
||||
b1.setMax(source.mMax[0], source.mMax[1], midpoint[2]);
|
||||
|
||||
b2.setMin(source.mMin[0], source.mMin[1], midpoint[2]);
|
||||
b2.setMax(source.mMax);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
virtual void raycast(bool &hit,
|
||||
const RmReal *from,
|
||||
const RmReal *to,
|
||||
const RmReal *dir,
|
||||
RmReal *hitLocation,
|
||||
RmReal *hitNormal,
|
||||
RmReal *hitDistance,
|
||||
const RmReal *vertices,
|
||||
const RmUint32 *indices,
|
||||
RmReal &nearestDistance,
|
||||
NodeInterface *callback,
|
||||
RmUint32 *raycastTriangles,
|
||||
RmUint32 raycastFrame,
|
||||
const TriVector &leafTriangles,
|
||||
RmUint32 &nearestTriIndex)
|
||||
{
|
||||
RmReal sect[3];
|
||||
RmReal nd = nearestDistance;
|
||||
if ( !intersectLineSegmentAABB(mBounds.mMin,mBounds.mMax,from,dir,nd,sect) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
if ( mLeafTriangleIndex != TRI_EOF )
|
||||
{
|
||||
const RmUint32 *scan = &leafTriangles[mLeafTriangleIndex];
|
||||
RmUint32 count = *scan++;
|
||||
for (RmUint32 i=0; i<count; i++)
|
||||
{
|
||||
RmUint32 tri = *scan++;
|
||||
if ( raycastTriangles[tri] != raycastFrame )
|
||||
{
|
||||
raycastTriangles[tri] = raycastFrame;
|
||||
RmUint32 i1 = indices[tri*3+0];
|
||||
RmUint32 i2 = indices[tri*3+1];
|
||||
RmUint32 i3 = indices[tri*3+2];
|
||||
|
||||
const RmReal *p1 = &vertices[i1*3];
|
||||
const RmReal *p2 = &vertices[i2*3];
|
||||
const RmReal *p3 = &vertices[i3*3];
|
||||
|
||||
RmReal t;
|
||||
if ( rayIntersectsTriangle(from,dir,p1,p2,p3,t))
|
||||
{
|
||||
bool accept = false;
|
||||
if ( t == nearestDistance && tri < nearestTriIndex )
|
||||
{
|
||||
accept = true;
|
||||
}
|
||||
if ( t < nearestDistance || accept )
|
||||
{
|
||||
nearestDistance = t;
|
||||
if ( hitLocation )
|
||||
{
|
||||
hitLocation[0] = from[0]+dir[0]*t;
|
||||
hitLocation[1] = from[1]+dir[1]*t;
|
||||
hitLocation[2] = from[2]+dir[2]*t;
|
||||
}
|
||||
if ( hitNormal )
|
||||
{
|
||||
callback->getFaceNormal(tri,hitNormal);
|
||||
}
|
||||
if ( hitDistance )
|
||||
{
|
||||
*hitDistance = t;
|
||||
}
|
||||
nearestTriIndex = tri;
|
||||
hit = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( mLeft )
|
||||
{
|
||||
mLeft->raycast(hit,from,to,dir,hitLocation,hitNormal,hitDistance,vertices,indices,nearestDistance,callback,raycastTriangles,raycastFrame,leafTriangles,nearestTriIndex);
|
||||
}
|
||||
if ( mRight )
|
||||
{
|
||||
mRight->raycast(hit,from,to,dir,hitLocation,hitNormal,hitDistance,vertices,indices,nearestDistance,callback,raycastTriangles,raycastFrame,leafTriangles,nearestTriIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NodeAABB *mLeft; // left node
|
||||
NodeAABB *mRight; // right node
|
||||
BoundsAABB mBounds; // bounding volume of node
|
||||
RmUint32 mLeafTriangleIndex; // if it is a leaf node; then these are the triangle indices.
|
||||
};
|
||||
|
||||
class MyRaycastMesh : public RaycastMesh, public NodeInterface
|
||||
{
|
||||
public:
|
||||
|
||||
MyRaycastMesh(RmUint32 vcount,const RmReal *vertices,RmUint32 tcount,const RmUint32 *indices,RmUint32 maxDepth,RmUint32 minLeafSize,RmReal minAxisSize)
|
||||
{
|
||||
mRaycastFrame = 0;
|
||||
if ( maxDepth < 2 )
|
||||
{
|
||||
maxDepth = 2;
|
||||
}
|
||||
if ( maxDepth > 15 )
|
||||
{
|
||||
maxDepth = 15;
|
||||
}
|
||||
RmUint32 pow2Table[16] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 65536 };
|
||||
mMaxNodeCount = 0;
|
||||
for (RmUint32 i=0; i<=maxDepth; i++)
|
||||
{
|
||||
mMaxNodeCount+=pow2Table[i];
|
||||
}
|
||||
mNodes = new NodeAABB[mMaxNodeCount];
|
||||
mNodeCount = 0;
|
||||
mVcount = vcount;
|
||||
mVertices = (RmReal *)::malloc(sizeof(RmReal)*3*vcount);
|
||||
memcpy(mVertices,vertices,sizeof(RmReal)*3*vcount);
|
||||
mTcount = tcount;
|
||||
mIndices = (RmUint32 *)::malloc(sizeof(RmUint32)*tcount*3);
|
||||
memcpy(mIndices,indices,sizeof(RmUint32)*tcount*3);
|
||||
mRaycastTriangles = (RmUint32 *)::malloc(tcount*sizeof(RmUint32));
|
||||
memset(mRaycastTriangles,0,tcount*sizeof(RmUint32));
|
||||
mRoot = getNode();
|
||||
mFaceNormals = NULL;
|
||||
new ( mRoot ) NodeAABB(mVcount,mVertices,mTcount,mIndices,maxDepth,minLeafSize,minAxisSize,this,mLeafTriangles);
|
||||
}
|
||||
|
||||
~MyRaycastMesh(void)
|
||||
{
|
||||
delete []mNodes;
|
||||
::free(mVertices);
|
||||
::free(mIndices);
|
||||
::free(mFaceNormals);
|
||||
::free(mRaycastTriangles);
|
||||
}
|
||||
|
||||
virtual bool raycast(const RmReal *from,const RmReal *to,RmReal *hitLocation,RmReal *hitNormal,RmReal *hitDistance)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
RmReal dir[3];
|
||||
dir[0] = to[0] - from[0];
|
||||
dir[1] = to[1] - from[1];
|
||||
dir[2] = to[2] - from[2];
|
||||
RmReal distance = sqrtf( dir[0]*dir[0] + dir[1]*dir[1]+dir[2]*dir[2] );
|
||||
if ( distance < 0.0000000001f ) return false;
|
||||
RmReal recipDistance = 1.0f / distance;
|
||||
dir[0]*=recipDistance;
|
||||
dir[1]*=recipDistance;
|
||||
dir[2]*=recipDistance;
|
||||
mRaycastFrame++;
|
||||
RmUint32 nearestTriIndex=TRI_EOF;
|
||||
mRoot->raycast(ret,from,to,dir,hitLocation,hitNormal,hitDistance,mVertices,mIndices,distance,this,mRaycastTriangles,mRaycastFrame,mLeafTriangles,nearestTriIndex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
virtual void release(void)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
virtual const RmReal * getBoundMin(void) const // return the minimum bounding box
|
||||
{
|
||||
return mRoot->mBounds.mMin;
|
||||
}
|
||||
virtual const RmReal * getBoundMax(void) const // return the maximum bounding box.
|
||||
{
|
||||
return mRoot->mBounds.mMax;
|
||||
}
|
||||
|
||||
virtual NodeAABB * getNode(void)
|
||||
{
|
||||
assert( mNodeCount < mMaxNodeCount );
|
||||
NodeAABB *ret = &mNodes[mNodeCount];
|
||||
mNodeCount++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
virtual void getFaceNormal(RmUint32 tri,RmReal *faceNormal)
|
||||
{
|
||||
if ( mFaceNormals == NULL )
|
||||
{
|
||||
mFaceNormals = (RmReal *)::malloc(sizeof(RmReal)*3*mTcount);
|
||||
for (RmUint32 i=0; i<mTcount; i++)
|
||||
{
|
||||
RmUint32 i1 = mIndices[i*3+0];
|
||||
RmUint32 i2 = mIndices[i*3+1];
|
||||
RmUint32 i3 = mIndices[i*3+2];
|
||||
const RmReal*p1 = &mVertices[i1*3];
|
||||
const RmReal*p2 = &mVertices[i2*3];
|
||||
const RmReal*p3 = &mVertices[i3*3];
|
||||
RmReal *dest = &mFaceNormals[i*3];
|
||||
computePlane(p3,p2,p1,dest);
|
||||
}
|
||||
}
|
||||
const RmReal *src = &mFaceNormals[tri*3];
|
||||
faceNormal[0] = src[0];
|
||||
faceNormal[1] = src[1];
|
||||
faceNormal[2] = src[2];
|
||||
}
|
||||
|
||||
virtual bool bruteForceRaycast(const RmReal *from,const RmReal *to,RmReal *hitLocation,RmReal *hitNormal,RmReal *hitDistance)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
RmReal dir[3];
|
||||
|
||||
dir[0] = to[0] - from[0];
|
||||
dir[1] = to[1] - from[1];
|
||||
dir[2] = to[2] - from[2];
|
||||
|
||||
RmReal distance = sqrtf( dir[0]*dir[0] + dir[1]*dir[1]+dir[2]*dir[2] );
|
||||
if ( distance < 0.0000000001f ) return false;
|
||||
RmReal recipDistance = 1.0f / distance;
|
||||
dir[0]*=recipDistance;
|
||||
dir[1]*=recipDistance;
|
||||
dir[2]*=recipDistance;
|
||||
const RmUint32 *indices = mIndices;
|
||||
const RmReal *vertices = mVertices;
|
||||
RmReal nearestDistance = distance;
|
||||
|
||||
for (RmUint32 tri=0; tri<mTcount; tri++)
|
||||
{
|
||||
RmUint32 i1 = indices[tri*3+0];
|
||||
RmUint32 i2 = indices[tri*3+1];
|
||||
RmUint32 i3 = indices[tri*3+2];
|
||||
|
||||
const RmReal *p1 = &vertices[i1*3];
|
||||
const RmReal *p2 = &vertices[i2*3];
|
||||
const RmReal *p3 = &vertices[i3*3];
|
||||
|
||||
RmReal t;
|
||||
if ( rayIntersectsTriangle(from,dir,p1,p2,p3,t))
|
||||
{
|
||||
if ( t < nearestDistance )
|
||||
{
|
||||
nearestDistance = t;
|
||||
if ( hitLocation )
|
||||
{
|
||||
hitLocation[0] = from[0]+dir[0]*t;
|
||||
hitLocation[1] = from[1]+dir[1]*t;
|
||||
hitLocation[2] = from[2]+dir[2]*t;
|
||||
}
|
||||
|
||||
if ( hitNormal )
|
||||
{
|
||||
getFaceNormal(tri,hitNormal);
|
||||
}
|
||||
|
||||
if ( hitDistance )
|
||||
{
|
||||
*hitDistance = t;
|
||||
}
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
RmUint32 mRaycastFrame;
|
||||
RmUint32 *mRaycastTriangles;
|
||||
RmUint32 mVcount;
|
||||
RmReal *mVertices;
|
||||
RmReal *mFaceNormals;
|
||||
RmUint32 mTcount;
|
||||
RmUint32 *mIndices;
|
||||
NodeAABB *mRoot;
|
||||
RmUint32 mNodeCount;
|
||||
RmUint32 mMaxNodeCount;
|
||||
NodeAABB *mNodes;
|
||||
TriVector mLeafTriangles;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
using namespace RAYCAST_MESH;
|
||||
|
||||
|
||||
RaycastMesh * createRaycastMesh(RmUint32 vcount, // The number of vertices in the source triangle mesh
|
||||
const RmReal *vertices, // The array of vertex positions in the format x1,y1,z1..x2,y2,z2.. etc.
|
||||
RmUint32 tcount, // The number of triangles in the source triangle mesh
|
||||
const RmUint32 *indices, // The triangle indices in the format of i1,i2,i3 ... i4,i5,i6, ...
|
||||
RmUint32 maxDepth, // Maximum recursion depth for the triangle mesh.
|
||||
RmUint32 minLeafSize, // minimum triangles to treat as a 'leaf' node.
|
||||
RmReal minAxisSize // once a particular axis is less than this size, stop sub-dividing.
|
||||
)
|
||||
{
|
||||
MyRaycastMesh *m = new MyRaycastMesh(vcount,vertices,tcount,indices,maxDepth,minLeafSize,minAxisSize);
|
||||
return static_cast< RaycastMesh * >(m);
|
||||
}
|
||||
|
||||
|
||||
60
zone/RaycastMesh.h
Normal file
60
zone/RaycastMesh.h
Normal file
@ -0,0 +1,60 @@
|
||||
#ifndef RAYCAST_MESH_H
|
||||
|
||||
#define RAYCAST_MESH_H
|
||||
|
||||
// This code snippet allows you to create an axis aligned bounding volume tree for a triangle mesh so that you can do
|
||||
// high-speed raycasting.
|
||||
//
|
||||
// There are much better implementations of this available on the internet. In particular I recommend that you use
|
||||
// OPCODE written by Pierre Terdiman.
|
||||
// @see: http://www.codercorner.com/Opcode.htm
|
||||
//
|
||||
// OPCODE does a whole lot more than just raycasting, and is a rather significant amount of source code.
|
||||
//
|
||||
// I am providing this code snippet for the use case where you *only* want to do quick and dirty optimized raycasting.
|
||||
// I have not done performance testing between this version and OPCODE; so I don't know how much slower it is. However,
|
||||
// anytime you switch to using a spatial data structure for raycasting, you increase your performance by orders and orders
|
||||
// of magnitude; so this implementation should work fine for simple tools and utilities.
|
||||
//
|
||||
// It also serves as a nice sample for people who are trying to learn the algorithm of how to implement AABB trees.
|
||||
// AABB = Axis Aligned Bounding Volume trees.
|
||||
//
|
||||
// http://www.cgal.org/Manual/3.5/doc_html/cgal_manual/AABB_tree/Chapter_main.html
|
||||
//
|
||||
//
|
||||
// This code snippet was written by John W. Ratcliff on August 18, 2011 and released under the MIT. license.
|
||||
//
|
||||
// mailto:jratcliffscarab@gmail.com
|
||||
//
|
||||
// The official source can be found at: http://code.google.com/p/raycastmesh/
|
||||
//
|
||||
//
|
||||
|
||||
typedef float RmReal;
|
||||
typedef unsigned int RmUint32;
|
||||
|
||||
class RaycastMesh
|
||||
{
|
||||
public:
|
||||
virtual bool raycast(const RmReal *from,const RmReal *to,RmReal *hitLocation,RmReal *hitNormal,RmReal *hitDistance) = 0;
|
||||
virtual bool bruteForceRaycast(const RmReal *from,const RmReal *to,RmReal *hitLocation,RmReal *hitNormal,RmReal *hitDistance) = 0;
|
||||
|
||||
virtual const RmReal * getBoundMin(void) const = 0; // return the minimum bounding box
|
||||
virtual const RmReal * getBoundMax(void) const = 0; // return the maximum bounding box.
|
||||
virtual void release(void) = 0;
|
||||
protected:
|
||||
virtual ~RaycastMesh(void) { };
|
||||
};
|
||||
|
||||
|
||||
RaycastMesh * createRaycastMesh(RmUint32 vcount, // The number of vertices in the source triangle mesh
|
||||
const RmReal *vertices, // The array of vertex positions in the format x1,y1,z1..x2,y2,z2.. etc.
|
||||
RmUint32 tcount, // The number of triangles in the source triangle mesh
|
||||
const RmUint32 *indices, // The triangle indices in the format of i1,i2,i3 ... i4,i5,i6, ...
|
||||
RmUint32 maxDepth=15, // Maximum recursion depth for the triangle mesh.
|
||||
RmUint32 minLeafSize=4, // minimum triangles to treat as a 'leaf' node.
|
||||
RmReal minAxisSize=0.01f // once a particular axis is less than this size, stop sub-dividing.
|
||||
);
|
||||
|
||||
|
||||
#endif
|
||||
190
zone/map.h
190
zone/map.h
@ -1,190 +0,0 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
|
||||
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; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
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, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef MAP_H
|
||||
#define MAP_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
//this is the current version number to expect from the map header
|
||||
#define MAP_VERSION 0x01000000
|
||||
|
||||
#define BEST_Z_INVALID -999999
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
typedef struct _vertex{
|
||||
// unsigned long order;
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
|
||||
_vertex()
|
||||
{
|
||||
x = y = z = 0.0f;
|
||||
};
|
||||
|
||||
_vertex(float ix, float iy, float iz)
|
||||
{
|
||||
x = ix;
|
||||
y = iy;
|
||||
z = iz;
|
||||
}
|
||||
bool operator==(const _vertex &v1) const
|
||||
{
|
||||
return((v1.x == x) && (v1.y == y) && (v1.z ==z));
|
||||
}
|
||||
|
||||
}VERTEX, *PVERTEX;
|
||||
|
||||
typedef struct _face{
|
||||
// unsigned long a, b, c; //vertexs
|
||||
VERTEX a;
|
||||
VERTEX b;
|
||||
VERTEX c;
|
||||
float nx, ny, nz, nd;
|
||||
}FACE, *PFACE;
|
||||
|
||||
typedef struct _mapHeader {
|
||||
uint32 version;
|
||||
uint32 face_count;
|
||||
uint16 node_count;
|
||||
uint32 facelist_count;
|
||||
} mapHeader;
|
||||
|
||||
/*
|
||||
This is used for the recursive node structure
|
||||
unsigned shorts are adequate because, worst case
|
||||
even in a zone that is 6000x6000 with a small node
|
||||
size of 30x30, there are only 40000 nodes.
|
||||
|
||||
quadrent definitions:
|
||||
quad 1 (nodes[0]):
|
||||
x>=0, y>=0
|
||||
quad 2 (nodes[1]):
|
||||
x<0, y>=0
|
||||
quad 3 (nodes[2]):
|
||||
x<0, y<0
|
||||
quad 4 (nodes[3]):
|
||||
x>=0, y<0
|
||||
|
||||
*/
|
||||
enum { //node flags
|
||||
nodeFinal = 0x01
|
||||
//7 more bits if theres something to use them for...
|
||||
};
|
||||
typedef struct _nodeHeader {
|
||||
//bounding box of this node
|
||||
//there is no reason that these could not be unsigned
|
||||
//shorts other than we have to compare them to floats
|
||||
//all over the place, so they stay floats for now.
|
||||
//changing it could save 8 bytes per node record (~320k for huge maps)
|
||||
float minx;
|
||||
float miny;
|
||||
float maxx;
|
||||
float maxy;
|
||||
|
||||
uint8 flags;
|
||||
union {
|
||||
uint16 nodes[4]; //index 0 means nullptr, not root
|
||||
struct {
|
||||
uint32 count;
|
||||
uint32 offset;
|
||||
} faces;
|
||||
};
|
||||
} nodeHeader, NODE, *PNODE;
|
||||
|
||||
#pragma pack()
|
||||
|
||||
//special value returned as 'not found'
|
||||
#define NODE_NONE 65534
|
||||
#define MAP_ROOT_NODE 0
|
||||
|
||||
typedef uint16 NodeRef;
|
||||
|
||||
/*typedef struct _node {
|
||||
nodeHeader head;
|
||||
unsigned int * pfaces;
|
||||
char mask;
|
||||
struct _node * node1, *node2, *node3, *node4;
|
||||
}NODE, *PNODE;*/
|
||||
|
||||
class Map {
|
||||
public:
|
||||
static Map* LoadMapfile(const char* in_zonename, const char *directory = nullptr);
|
||||
|
||||
Map();
|
||||
~Map();
|
||||
|
||||
bool loadMap(FILE *fp);
|
||||
|
||||
//the result is always final, except special NODE_NONE
|
||||
NodeRef SeekNode( NodeRef _node, float x, float y ) const;
|
||||
|
||||
//these are untested since rewrite:
|
||||
int *SeekFace( NodeRef _node, float x, float y );
|
||||
float GetFaceHeight( int _idx, float x, float y ) const;
|
||||
|
||||
bool LocWithinNode( NodeRef _node, float x, float y ) const;
|
||||
|
||||
//nodes to these functions must be final
|
||||
bool LineIntersectsNode( NodeRef _node, VERTEX start, VERTEX end, VERTEX *result, FACE **on = nullptr) const;
|
||||
bool LineIntersectsFace( PFACE cface, VERTEX start, VERTEX end, VERTEX *result) const;
|
||||
float FindBestZ( NodeRef _node, VERTEX start, VERTEX *result, FACE **on = nullptr) const;
|
||||
bool LineIntersectsZone(VERTEX start, VERTEX end, float step, VERTEX *result, FACE **on = nullptr) const;
|
||||
|
||||
// inline unsigned int GetVertexNumber( ) {return m_Vertex; }
|
||||
inline uint32 GetFacesNumber( ) const { return m_Faces; }
|
||||
// inline PVERTEX GetVertex( int _idx ) {return mFinalVertex + _idx; }
|
||||
inline PFACE GetFace( int _idx) {return mFinalFaces + _idx; }
|
||||
inline PFACE GetFaceFromlist( int _idx) {return &mFinalFaces[ mFaceLists[_idx] ]; }
|
||||
inline NodeRef GetRoot( ) const { return MAP_ROOT_NODE; }
|
||||
inline PNODE GetNode( NodeRef r ) { return( mNodes + r ); }
|
||||
|
||||
inline float GetMinX() const { return(_minx); }
|
||||
inline float GetMaxX() const { return(_maxx); }
|
||||
inline float GetMinY() const { return(_miny); }
|
||||
inline float GetMaxY() const { return(_maxy); }
|
||||
inline float GetMinZ() const { return(_minz); }
|
||||
inline float GetMaxZ() const { return(_maxz); }
|
||||
bool LineIntersectsZoneNoZLeaps(VERTEX start, VERTEX end, float step_mag, VERTEX *result, FACE **on);
|
||||
float FindClosestZ(VERTEX p ) const;
|
||||
|
||||
private:
|
||||
// unsigned long m_Vertex;
|
||||
uint32 m_Faces;
|
||||
uint32 m_Nodes;
|
||||
uint32 m_FaceLists;
|
||||
// PVERTEX mFinalVertex;
|
||||
PFACE mFinalFaces;
|
||||
PNODE mNodes;
|
||||
uint32 *mFaceLists;
|
||||
|
||||
|
||||
int mCandFaces[100];
|
||||
|
||||
float _minz, _maxz;
|
||||
float _minx, _miny, _maxx, _maxy;
|
||||
|
||||
static void Normalize(VERTEX *p);
|
||||
|
||||
// void RecLoadNode( PNODE _node, FILE *l_f );
|
||||
// void RecFreeNode( PNODE _node );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user