mirror of
https://github.com/ZDoom/zdbsp.git
synced 2024-11-10 06:31:35 +00:00
- 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. Now 68% of its time on that map is spent inside ClassifyLine--because that routine is called more than 16 million times, which suggests that even a minor speedup in that routine should have a big impact--if I could just think of how that might happen.) 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 r167 (trunk)
This commit is contained in:
parent
30436092ed
commit
6d799f0a1c
7 changed files with 188 additions and 70 deletions
4
Makefile
4
Makefile
|
@ -1,10 +1,10 @@
|
|||
CFLAGS = -Wall -fomit-frame-pointer -Izlib -pipe -ffast-math -MMD
|
||||
|
||||
# Optimization flags
|
||||
CFLAGS += -O3 -fomit-frame-pointer
|
||||
CFLAGS += -O3 -fomit-frame-pointer -DNDEBUG
|
||||
|
||||
# Unoptimization flags
|
||||
#CFLAGS += -g
|
||||
#CFLAGS += -g -D_DEBUG
|
||||
|
||||
# Processor features flags
|
||||
CFLAGS += -mtune=i686
|
||||
|
|
|
@ -177,28 +177,16 @@ void FBlockmapBuilder::BuildBlockmap ()
|
|||
WORD adder;
|
||||
int bmapwidth, bmapheight;
|
||||
int minx, maxx, miny, maxy;
|
||||
int i;
|
||||
WORD line;
|
||||
|
||||
if (Level.NumVertices <= 0)
|
||||
return;
|
||||
|
||||
// Find map extents for the blockmap
|
||||
minx = maxx = Level.Vertices[0].x;
|
||||
miny = maxy = Level.Vertices[0].y;
|
||||
|
||||
for (i = 1; i < Level.NumVertices; ++i)
|
||||
{
|
||||
if (Level.Vertices[i].x < minx) minx = Level.Vertices[i].x;
|
||||
else if (Level.Vertices[i].x > maxx) maxx = Level.Vertices[i].x;
|
||||
if (Level.Vertices[i].y < miny) miny = Level.Vertices[i].y;
|
||||
else if (Level.Vertices[i].y > maxy) maxy = Level.Vertices[i].y;
|
||||
}
|
||||
|
||||
maxx >>= FRACBITS;
|
||||
minx >>= FRACBITS;
|
||||
maxy >>= FRACBITS;
|
||||
miny >>= FRACBITS;
|
||||
// Get map extents for the blockmap
|
||||
minx = Level.MinX >> FRACBITS;
|
||||
miny = Level.MinY >> FRACBITS;
|
||||
maxx = Level.MaxX >> FRACBITS;
|
||||
maxy = Level.MaxY >> FRACBITS;
|
||||
|
||||
/*
|
||||
// DoomBSP did this to give the map a margin when drawing it
|
||||
|
|
|
@ -164,6 +164,9 @@ struct FLevel
|
|||
|
||||
int NumOrgVerts;
|
||||
|
||||
fixed_t MinX, MinY, MaxX, MaxY;
|
||||
|
||||
void FindMapBounds ();
|
||||
void RemoveExtraLines ();
|
||||
void RemoveExtraSides ();
|
||||
void RemoveExtraSectors ();
|
||||
|
|
|
@ -33,10 +33,6 @@
|
|||
// Units are in fixed_ts.
|
||||
const double SIDE_EPSILON = 6.5536;
|
||||
|
||||
// Vertices within this distance of each other vertically and horizontally
|
||||
// will be considered as the same vertex.
|
||||
const fixed_t VERTEX_EPSILON = 6;
|
||||
|
||||
#define Printf printf
|
||||
#define STACK_ARGS
|
||||
|
||||
|
@ -49,8 +45,9 @@ const fixed_t VERTEX_EPSILON = 6;
|
|||
FNodeBuilder::FNodeBuilder (FLevel &level,
|
||||
TArray<FPolyStart> &polyspots, TArray<FPolyStart> &anchors,
|
||||
const char *name, bool makeGLnodes)
|
||||
: Level (level), SegsStuffed (0), MapName (name)
|
||||
: Level(level), SegsStuffed(0), MapName(name)
|
||||
{
|
||||
VertexMap = new FVertexMap (*this, Level.MinX, Level.MinY, Level.MaxX, Level.MaxY);
|
||||
GLNodes = makeGLnodes;
|
||||
FindUsedVertices (Level.Vertices, Level.NumVertices);
|
||||
MakeSegsFromSides ();
|
||||
|
@ -59,6 +56,14 @@ FNodeBuilder::FNodeBuilder (FLevel &level,
|
|||
BuildTree ();
|
||||
}
|
||||
|
||||
FNodeBuilder::~FNodeBuilder()
|
||||
{
|
||||
if (VertexMap != 0)
|
||||
{
|
||||
delete VertexMap;
|
||||
}
|
||||
}
|
||||
|
||||
void FNodeBuilder::BuildTree ()
|
||||
{
|
||||
fixed_t bbox[4];
|
||||
|
@ -739,10 +744,10 @@ int FNodeBuilder::ClassifyLine (node_t &node, const FPrivSeg *seg, int &sidev1,
|
|||
int near = (fabs(s_num1) < 17179869184.0) | ((fabs(s_num2) < 17179869184.0) << 1);
|
||||
if (near)
|
||||
{
|
||||
double l = d_dx*d_dx + d_dy*d_dy;
|
||||
double l = 1.0 / (d_dx*d_dx + d_dy*d_dy);
|
||||
if (near & 1)
|
||||
{
|
||||
double dist = s_num1 * s_num1 / l;
|
||||
double dist = s_num1 * s_num1 * l;
|
||||
if (dist < SIDE_EPSILON*SIDE_EPSILON)
|
||||
{
|
||||
sidev1 = 0;
|
||||
|
@ -758,7 +763,7 @@ int FNodeBuilder::ClassifyLine (node_t &node, const FPrivSeg *seg, int &sidev1,
|
|||
}
|
||||
if (near & 2)
|
||||
{
|
||||
double dist = s_num2 * s_num2 / l;
|
||||
double dist = s_num2 * s_num2 * l;
|
||||
if (dist < SIDE_EPSILON*SIDE_EPSILON)
|
||||
{
|
||||
sidev2 = 0;
|
||||
|
@ -870,7 +875,6 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou
|
|||
FPrivVert newvert;
|
||||
unsigned int vertnum;
|
||||
int seg2;
|
||||
unsigned int i;
|
||||
|
||||
//Printf ("%u is cut\n", set);
|
||||
if (seg->loopnum)
|
||||
|
@ -887,26 +891,7 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou
|
|||
newvert.y = Vertices[seg->v1].y;
|
||||
newvert.x += fixed_t(frac * double(Vertices[seg->v2].x - newvert.x));
|
||||
newvert.y += fixed_t(frac * double(Vertices[seg->v2].y - newvert.y));
|
||||
for (i = 0; i < Vertices.Size(); ++i)
|
||||
{
|
||||
if (abs(Vertices[i].x - newvert.x) < VERTEX_EPSILON &&
|
||||
abs(Vertices[i].y - newvert.y) < VERTEX_EPSILON)
|
||||
// if (uint32_t(Vertices[i].x - newvert.x + VERTEX_EPSILON) < 2u*VERTEX_EPSILON &&
|
||||
// uint32_t(Vertices[i].y - newvert.y + VERTEX_EPSILON) < 2u*VERTEX_EPSILON)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < Vertices.Size())
|
||||
{
|
||||
vertnum = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
newvert.segs = DWORD_MAX;
|
||||
newvert.segs2 = DWORD_MAX;
|
||||
vertnum = (int)Vertices.Push (newvert);
|
||||
}
|
||||
vertnum = VertexMap->SelectVertexClose (newvert);
|
||||
|
||||
seg2 = SplitSeg (set, vertnum, sidev1);
|
||||
|
||||
|
|
35
nodebuild.h
35
nodebuild.h
|
@ -97,6 +97,37 @@ 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_SIZE = 256 << FRACBITS };
|
||||
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 (x - MinX) / BLOCK_SIZE + ((y - MinY) / BLOCK_SIZE) * BlocksWide;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
struct FPolyStart
|
||||
{
|
||||
|
@ -107,6 +138,7 @@ public:
|
|||
FNodeBuilder (FLevel &level,
|
||||
TArray<FPolyStart> &polyspots, TArray<FPolyStart> &anchors,
|
||||
const char *name, bool makeGLnodes);
|
||||
~FNodeBuilder ();
|
||||
|
||||
void GetVertices (WideVertex *&verts, int &count);
|
||||
void GetNodes (MapNodeEx *&nodes, int &nodeCount,
|
||||
|
@ -124,6 +156,8 @@ public:
|
|||
static 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;
|
||||
|
@ -149,7 +183,6 @@ private:
|
|||
const char *MapName;
|
||||
|
||||
void FindUsedVertices (WideVertex *vertices, int max);
|
||||
int SelectVertexExact (FPrivVert &vertex);
|
||||
void BuildTree ();
|
||||
void MakeSegsFromSides ();
|
||||
int CreateSeg (int linenum, int sidenum);
|
||||
|
|
|
@ -23,10 +23,15 @@
|
|||
|
||||
#include "zdbsp.h"
|
||||
#include "nodebuild.h"
|
||||
#include "templates.h"
|
||||
|
||||
static const int PO_LINE_START = 1;
|
||||
static const int PO_LINE_EXPLICIT = 5;
|
||||
|
||||
// Vertices within this distance of each other vertically and horizontally
|
||||
// will be considered as the same vertex.
|
||||
const fixed_t VERTEX_EPSILON = 6;
|
||||
|
||||
#if 0
|
||||
#define D(x) x
|
||||
#else
|
||||
|
@ -42,31 +47,28 @@ static const int PO_LINE_EXPLICIT = 5;
|
|||
|
||||
void FNodeBuilder::FindUsedVertices (WideVertex *oldverts, int max)
|
||||
{
|
||||
size_t *map = (size_t *)alloca (max*sizeof(size_t));
|
||||
int *map = (int *)alloca (max*sizeof(int));
|
||||
int i;
|
||||
FPrivVert newvert;
|
||||
|
||||
memset (&map[0], -1, sizeof(size_t)*max);
|
||||
|
||||
newvert.segs = DWORD_MAX;
|
||||
newvert.segs2 = DWORD_MAX;
|
||||
memset (&map[0], -1, sizeof(int)*max);
|
||||
|
||||
for (i = 0; i < Level.NumLines; ++i)
|
||||
{
|
||||
int v1 = Level.Lines[i].v1;
|
||||
int v2 = Level.Lines[i].v2;
|
||||
|
||||
if (map[v1] == (size_t)-1)
|
||||
if (map[v1] == -1)
|
||||
{
|
||||
newvert.x = oldverts[v1].x;
|
||||
newvert.y = oldverts[v1].y;
|
||||
map[v1] = SelectVertexExact (newvert);
|
||||
map[v1] = VertexMap->SelectVertexExact (newvert);
|
||||
}
|
||||
if (map[v2] == (size_t)-1)
|
||||
if (map[v2] == -1)
|
||||
{
|
||||
newvert.x = oldverts[v2].x;
|
||||
newvert.y = oldverts[v2].y;
|
||||
map[v2] = SelectVertexExact (newvert);
|
||||
map[v2] = VertexMap->SelectVertexExact (newvert);
|
||||
}
|
||||
|
||||
Level.Lines[i].v1 = (WORD)map[v1];
|
||||
|
@ -76,18 +78,6 @@ void FNodeBuilder::FindUsedVertices (WideVertex *oldverts, int max)
|
|||
Level.NumOrgVerts = (int)InitialVertices;
|
||||
}
|
||||
|
||||
int FNodeBuilder::SelectVertexExact (FPrivVert &vertex)
|
||||
{
|
||||
for (unsigned int i = 0; i < Vertices.Size(); ++i)
|
||||
{
|
||||
if (Vertices[i].x == vertex.x && Vertices[i].y == vertex.y)
|
||||
{
|
||||
return (int)i;
|
||||
}
|
||||
}
|
||||
return (int)Vertices.Push (vertex);
|
||||
}
|
||||
|
||||
// For every sidedef in the map, create a corresponding seg.
|
||||
|
||||
void FNodeBuilder::MakeSegsFromSides ()
|
||||
|
@ -461,3 +451,99 @@ void FNodeBuilder::AddSegToBBox (fixed_t bbox[4], const FPrivSeg *seg)
|
|||
if (v2->y < bbox[BOXBOTTOM]) bbox[BOXBOTTOM] = v2->y;
|
||||
if (v2->y > bbox[BOXTOP]) bbox[BOXTOP] = v2->y;
|
||||
}
|
||||
|
||||
FNodeBuilder::FVertexMap::FVertexMap (FNodeBuilder &builder,
|
||||
fixed_t minx, fixed_t miny, fixed_t maxx, fixed_t maxy)
|
||||
: MyBuilder(builder)
|
||||
{
|
||||
MinX = minx;
|
||||
MinY = miny;
|
||||
BlocksWide = ((maxx - minx + 1) + (BLOCK_SIZE - 1)) / BLOCK_SIZE;
|
||||
BlocksTall = ((maxy - miny + 1) + (BLOCK_SIZE - 1)) / BLOCK_SIZE;
|
||||
MaxX = MinX + BlocksWide * BLOCK_SIZE - 1;
|
||||
MaxY = MinY + BlocksTall * BLOCK_SIZE - 1;
|
||||
VertexGrid = new TArray<int>[BlocksWide * BlocksTall];
|
||||
}
|
||||
|
||||
FNodeBuilder::FVertexMap::~FVertexMap ()
|
||||
{
|
||||
delete[] VertexGrid;
|
||||
}
|
||||
|
||||
int FNodeBuilder::FVertexMap::SelectVertexExact (FNodeBuilder::FPrivVert &vert)
|
||||
{
|
||||
TArray<int> &block = VertexGrid[GetBlock (vert.x, vert.y)];
|
||||
FPrivVert *vertices = &MyBuilder.Vertices[0];
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < block.Size(); ++i)
|
||||
{
|
||||
if (vertices[block[i]].x == vert.x && vertices[block[i]].y == vert.y)
|
||||
{
|
||||
return (int)i;
|
||||
}
|
||||
}
|
||||
|
||||
// Not present: add it!
|
||||
return InsertVertex (vert);
|
||||
}
|
||||
|
||||
int FNodeBuilder::FVertexMap::SelectVertexClose (FNodeBuilder::FPrivVert &vert)
|
||||
{
|
||||
TArray<int> &block = VertexGrid[GetBlock (vert.x, vert.y)];
|
||||
FPrivVert *vertices = &MyBuilder.Vertices[0];
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < block.Size(); ++i)
|
||||
{
|
||||
if (abs(vertices[block[i]].x - vert.x) < VERTEX_EPSILON &&
|
||||
abs(vertices[block[i]].y - vert.y) < VERTEX_EPSILON)
|
||||
{
|
||||
return (int)i;
|
||||
}
|
||||
}
|
||||
|
||||
// Not present: add it!
|
||||
return InsertVertex (vert);
|
||||
}
|
||||
|
||||
int FNodeBuilder::FVertexMap::InsertVertex (FNodeBuilder::FPrivVert &vert)
|
||||
{
|
||||
int vertnum;
|
||||
|
||||
vert.segs = DWORD_MAX;
|
||||
vert.segs2 = DWORD_MAX;
|
||||
vertnum = (int)MyBuilder.Vertices.Push (vert);
|
||||
|
||||
// If a vertex is near a block boundary, then it will be inserted on
|
||||
// both sides of the boundary so that SelectVertexClose can find
|
||||
// it by checking in only one block.
|
||||
fixed_t minx = MAX (MinX, vert.x - VERTEX_EPSILON);
|
||||
fixed_t maxx = MIN (MaxX, vert.x + VERTEX_EPSILON);
|
||||
fixed_t miny = MAX (MinY, vert.y - VERTEX_EPSILON);
|
||||
fixed_t maxy = MIN (MaxY, vert.y + VERTEX_EPSILON);
|
||||
|
||||
int blk[4] =
|
||||
{
|
||||
GetBlock (minx, miny),
|
||||
GetBlock (maxx, miny),
|
||||
GetBlock (minx, maxy),
|
||||
GetBlock (maxx, maxy)
|
||||
};
|
||||
unsigned int blkcount[4] =
|
||||
{
|
||||
VertexGrid[blk[0]].Size(),
|
||||
VertexGrid[blk[1]].Size(),
|
||||
VertexGrid[blk[2]].Size(),
|
||||
VertexGrid[blk[3]].Size()
|
||||
};
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
if (VertexGrid[blk[i]].Size() == blkcount[i])
|
||||
{
|
||||
VertexGrid[blk[i]].Push (vertnum);
|
||||
}
|
||||
}
|
||||
|
||||
return vertnum;
|
||||
}
|
||||
|
|
|
@ -90,6 +90,8 @@ FProcessor::FProcessor (FWadReader &inwad, int lump)
|
|||
{
|
||||
GetPolySpots ();
|
||||
}
|
||||
|
||||
Level.FindMapBounds ();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,6 +200,27 @@ void FProcessor::LoadSectors ()
|
|||
ReadMapLump<MapSector> (Wad, "SECTORS", Lump, Level.Sectors, Level.NumSectors);
|
||||
}
|
||||
|
||||
void FLevel::FindMapBounds ()
|
||||
{
|
||||
fixed_t minx, maxx, miny, maxy;
|
||||
|
||||
minx = maxx = Vertices[0].x;
|
||||
miny = maxy = Vertices[0].y;
|
||||
|
||||
for (int i = 1; i < NumVertices; ++i)
|
||||
{
|
||||
if (Vertices[i].x < minx) minx = Vertices[i].x;
|
||||
else if (Vertices[i].x > maxx) maxx = Vertices[i].x;
|
||||
if (Vertices[i].y < miny) miny = Vertices[i].y;
|
||||
else if (Vertices[i].y > maxy) maxy = Vertices[i].y;
|
||||
}
|
||||
|
||||
MinX = minx;
|
||||
MinY = miny;
|
||||
MaxX = maxx;
|
||||
MaxY = maxy;
|
||||
}
|
||||
|
||||
void FLevel::RemoveExtraLines ()
|
||||
{
|
||||
int i, newNumLines;
|
||||
|
|
Loading…
Reference in a new issue