- ClassifyLine now chooses either SSE2 or regular x87 math depending on whether
or not SSE2 is available at runtime. Since most of the time is spent in ClassifyLine, using SSE2 in just this one function helps the most. - Nodebuilding is a little faster if we inline PointOnSide. - Changed FEventTree into a regular binary tree, since there just aren't enough nodes inserted into it to make a red-black tree worthwhile. - Added more checks at the start of ClassifyLine so that it has a better chance of avoiding the more complicated checking, and it seems to have paid off with a reasonably modest performance boost. - Added a "vertex map" for ZDBSP's vertex selection. (Think BLOCKMAP for vertices instead of lines.) On large maps, this can result in a very significant speed up. (In one particular map, ZDBSP had previously spent 40% of its time just scanning through all the vertices in the map. Now the time it spends finding vertices is immeasurable.) On small maps, this won't make much of a difference, because the number of vertices to search was so small to begin with. SVN r173 (trunk)
This commit is contained in:
parent
6975103dd9
commit
7a601515df
13 changed files with 604 additions and 369 deletions
122
src/nodebuild.h
122
src/nodebuild.h
|
|
@ -11,7 +11,6 @@ struct FEventInfo
|
|||
struct FEvent
|
||||
{
|
||||
FEvent *Parent, *Left, *Right;
|
||||
enum { RED, BLACK } Color;
|
||||
double Distance;
|
||||
FEventInfo Info;
|
||||
};
|
||||
|
|
@ -28,7 +27,6 @@ public:
|
|||
|
||||
FEvent *GetNewNode ();
|
||||
void Insert (FEvent *event);
|
||||
void Delete (FEvent *event);
|
||||
FEvent *FindEvent (double distance) const;
|
||||
void DeleteAll ();
|
||||
|
||||
|
|
@ -37,9 +35,6 @@ private:
|
|||
FEvent *Root;
|
||||
FEvent *Spare;
|
||||
|
||||
void LeftRotate (FEvent *event);
|
||||
void RightRotate (FEvent *event);
|
||||
void DeleteFixUp (FEvent *event);
|
||||
void DeletionTraverser (FEvent *event);
|
||||
FEvent *Successor (FEvent *event) const;
|
||||
FEvent *Predecessor (FEvent *event) const;
|
||||
|
|
@ -91,12 +86,51 @@ class FNodeBuilder
|
|||
DWORD Seg;
|
||||
bool Forward;
|
||||
};
|
||||
|
||||
// Like a blockmap, but for vertices instead of lines
|
||||
class FVertexMap
|
||||
{
|
||||
public:
|
||||
FVertexMap (FNodeBuilder &builder, fixed_t minx, fixed_t miny, fixed_t maxx, fixed_t maxy);
|
||||
~FVertexMap ();
|
||||
|
||||
int SelectVertexExact (FPrivVert &vert);
|
||||
int SelectVertexClose (FPrivVert &vert);
|
||||
|
||||
private:
|
||||
FNodeBuilder &MyBuilder;
|
||||
TArray<int> *VertexGrid;
|
||||
|
||||
fixed_t MinX, MinY, MaxX, MaxY;
|
||||
int BlocksWide, BlocksTall;
|
||||
|
||||
enum { BLOCK_SHIFT = 8 + FRACBITS };
|
||||
enum { BLOCK_SIZE = 1 << BLOCK_SHIFT };
|
||||
|
||||
int InsertVertex (FPrivVert &vert);
|
||||
inline int GetBlock (fixed_t x, fixed_t y)
|
||||
{
|
||||
assert (x >= MinX);
|
||||
assert (y >= MinY);
|
||||
assert (x <= MaxX);
|
||||
assert (y <= MaxY);
|
||||
return (unsigned(x - MinX) >> BLOCK_SHIFT) + (unsigned(y - MinY) >> BLOCK_SHIFT) * BlocksWide;
|
||||
}
|
||||
};
|
||||
|
||||
friend class FVertexMap;
|
||||
|
||||
|
||||
public:
|
||||
struct FLevel
|
||||
{
|
||||
vertex_t *Vertices; int NumVertices;
|
||||
side_t *Sides; int NumSides;
|
||||
line_t *Lines; int NumLines;
|
||||
|
||||
fixed_t MinX, MinY, MaxX, MaxY;
|
||||
|
||||
void FindMapBounds ();
|
||||
};
|
||||
|
||||
struct FPolyStart
|
||||
|
|
@ -107,7 +141,8 @@ public:
|
|||
|
||||
FNodeBuilder (FLevel &level,
|
||||
TArray<FPolyStart> &polyspots, TArray<FPolyStart> &anchors,
|
||||
bool makeGLNodes);
|
||||
bool makeGLNodes, bool enableSSE2);
|
||||
~FNodeBuilder ();
|
||||
|
||||
void Extract (node_t *&nodes, int &nodeCount,
|
||||
seg_t *&segs, int &segCount,
|
||||
|
|
@ -116,7 +151,15 @@ public:
|
|||
|
||||
static angle_t PointToAngle (fixed_t dx, fixed_t dy);
|
||||
|
||||
// < 0 : in front of line
|
||||
// == 0 : on line
|
||||
// > 0 : behind line
|
||||
|
||||
static inline int PointOnSide (int x, int y, int x1, int y1, int dx, int dy);
|
||||
|
||||
private:
|
||||
FVertexMap *VertexMap;
|
||||
|
||||
TArray<node_t> Nodes;
|
||||
TArray<subsector_t> Subsectors;
|
||||
TArray<DWORD> SubsectorSets;
|
||||
|
|
@ -130,18 +173,18 @@ private:
|
|||
TArray<int> Colinear; // Loops with edges colinear to a splitter
|
||||
FEventTree Events; // Vertices intersected by the current splitter
|
||||
|
||||
TArray<FSplitSharer> SplitSharers; // Segs collinear with the current splitter
|
||||
TArray<FSplitSharer> SplitSharers; // Segs colinear with the current splitter
|
||||
|
||||
DWORD HackSeg; // Seg to force to back of splitter
|
||||
DWORD HackMate; // Seg to use in front of hack seg
|
||||
FLevel &Level;
|
||||
bool GLNodes; // Add minisegs to make GL nodes?
|
||||
bool EnableSSE2;
|
||||
|
||||
// Progress meter stuff
|
||||
int SegsStuffed;
|
||||
|
||||
void FindUsedVertices (vertex_t *vertices, int max);
|
||||
int SelectVertexExact (FPrivVert &vertex);
|
||||
void BuildTree ();
|
||||
void MakeSegsFromSides ();
|
||||
int CreateSeg (int linenum, int sidenum);
|
||||
|
|
@ -159,9 +202,17 @@ private:
|
|||
void SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &outset0, DWORD &outset1);
|
||||
DWORD SplitSeg (DWORD segnum, int splitvert, int v1InFront);
|
||||
int Heuristic (node_t &node, DWORD set, bool honorNoSplit);
|
||||
int ClassifyLine (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2);
|
||||
int CountSegs (DWORD set) const;
|
||||
|
||||
// Returns:
|
||||
// 0 = seg is in front
|
||||
// 1 = seg is in back
|
||||
// -1 = seg cuts the node
|
||||
|
||||
inline int ClassifyLine (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2);
|
||||
int ClassifyLine2 (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2);
|
||||
int ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2);
|
||||
|
||||
void FixSplitSharers (const node_t &node);
|
||||
double AddIntersection (const node_t &node, int vertex);
|
||||
void AddMinisegs (const node_t &node, DWORD splitseg, DWORD &fset, DWORD &rset);
|
||||
|
|
@ -179,12 +230,55 @@ private:
|
|||
|
||||
static int STACK_ARGS SortSegs (const void *a, const void *b);
|
||||
|
||||
// < 0 : in front of line
|
||||
// == 0 : on line
|
||||
// > 0 : behind line
|
||||
|
||||
int PointOnSide (int x, int y, int x1, int y1, int dx, int dy);
|
||||
double InterceptVector (const node_t &splitter, const FPrivSeg &seg);
|
||||
|
||||
void PrintSet (int l, DWORD set);
|
||||
};
|
||||
|
||||
// Points within this distance of a line will be considered on the line.
|
||||
// Units are in fixed_ts.
|
||||
const double SIDE_EPSILON = 6.5536;
|
||||
|
||||
inline int FNodeBuilder::PointOnSide (int x, int y, int x1, int y1, int dx, int dy)
|
||||
{
|
||||
// For most cases, a simple dot product is enough.
|
||||
double d_dx = double(dx);
|
||||
double d_dy = double(dy);
|
||||
double d_x = double(x);
|
||||
double d_y = double(y);
|
||||
double d_x1 = double(x1);
|
||||
double d_y1 = double(y1);
|
||||
|
||||
double s_num = (d_y1-d_y)*d_dx - (d_x1-d_x)*d_dy;
|
||||
|
||||
if (fabs(s_num) < 17179869184.f) // 4<<32
|
||||
{
|
||||
// Either the point is very near the line, or the segment defining
|
||||
// the line is very short: Do a more expensive test to determine
|
||||
// just how far from the line the point is.
|
||||
double l = d_dx*d_dx + d_dy*d_dy; // double l = sqrt(d_dx*d_dx+d_dy*d_dy);
|
||||
double dist = s_num * s_num / l; // double dist = fabs(s_num)/l;
|
||||
if (dist < SIDE_EPSILON*SIDE_EPSILON) // if (dist < SIDE_EPSILON)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return s_num > 0.0 ? -1 : 1;
|
||||
}
|
||||
|
||||
inline int FNodeBuilder::ClassifyLine (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2)
|
||||
{
|
||||
#ifdef __SSE2__
|
||||
// If compiling with SSE2 support everywhere, just use the SSE2 version.
|
||||
return ClassifyLineSSE2 (node, seg, sidev1, sidev2);
|
||||
#elif defined(_MSC_VER) && _MSC_VER < 1300
|
||||
// VC 6 does not support SSE2 optimizations.
|
||||
return ClassifyLine2 (node, seg, sidev1, sidev2);
|
||||
#else
|
||||
// Select the routine based on our flag.
|
||||
if (EnableSSE2)
|
||||
return ClassifyLineSSE2 (node, seg, sidev1, sidev2);
|
||||
else
|
||||
return ClassifyLine2 (node, seg, sidev1, sidev2);
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue