ZDBSP fixes:

- AddIntersection() should convert to doubles before subtracting the vertex
  from the node, not after, to avoid integer overflow. (See cah.wad, MAP12
  and MAP13.) A simpler dot product will also suffice for distance calculation.
- Splitters that come too close to a vertex should be avoided. (See cata.wad.)
- Red-Black Tree implementation was broken and colored every node red.
- Moved most of the code for outputting degenerate GL subsectors into another
  function.
- Removed forgotten debugging file dump from WriteSSectors2().
- Enabled reference optimization and COMDAT folding in the linker for a slightly
  smaller executable.

SVN r155 (trunk)
This commit is contained in:
Randy Heit 2006-05-31 15:39:58 +00:00
parent 3128c11fd1
commit 1a979de350
7 changed files with 135 additions and 143 deletions

View file

@ -527,6 +527,7 @@ int FNodeBuilder::Heuristic (node_t &node, DWORD set, bool honorNoSplit)
int side;
bool splitter = false;
size_t max, m2, p, q;
double frac;
Touched.Clear ();
Colinear.Clear ();
@ -619,6 +620,13 @@ int FNodeBuilder::Heuristic (node_t &node, DWORD set, bool honorNoSplit)
}
}
// Splitters that are too close to a vertex are bad.
frac = InterceptVector (node, *test);
if (frac < 0.001 || frac > 0.999)
{
score -= int(1 / frac);
}
counts[0]++;
counts[1]++;
if (test->linedef != -1)

View file

@ -32,6 +32,8 @@ public:
FEvent *FindEvent (double distance) const;
void DeleteAll ();
void PrintTree () const { PrintTree (Root); }
private:
FEvent Nil;
FEvent *Root;
@ -43,6 +45,8 @@ private:
void DeletionTraverser (FEvent *event);
FEvent *Successor (FEvent *event) const;
FEvent *Predecessor (FEvent *event) const;
void PrintTree (const FEvent *event) const;
};
class FNodeBuilder
@ -180,6 +184,7 @@ private:
int CloseSubsector (TArray<MapSegGLEx> &segs, int subsector);
DWORD PushGLSeg (TArray<MapSegGLEx> &segs, const FPrivSeg *seg);
void PushConnectingGLSeg (int subsector, TArray<MapSegGLEx> &segs, int v1, int v2);
int OutputDegenerateSubsector (TArray<MapSegGLEx> &segs, int subsector, bool bForward, double lastdot, FPrivSeg *&prev);
static int SortSegs (const void *a, const void *b);

View file

@ -17,12 +17,17 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <string.h>
#include <stdio.h>
#include <math.h>
#include "zdbsp.h"
#include "nodebuild.h"
FEventTree::FEventTree ()
: Root (&Nil), Spare (NULL)
{
memset (&Nil, 0, sizeof(Nil));
Nil.Color = FEvent::BLACK;
}
FEventTree::~FEventTree ()
@ -65,7 +70,7 @@ void FEventTree::LeftRotate (FEvent *x)
y->Left->Parent = x;
}
y->Parent = x->Parent;
if (x->Parent != &Nil)
if (x->Parent == &Nil)
{
Root = y;
}
@ -90,7 +95,7 @@ void FEventTree::RightRotate (FEvent *x)
y->Right->Parent = x;
}
y->Parent = x->Parent;
if (x->Parent != &Nil)
if (x->Parent == &Nil)
{
Root = y;
}
@ -154,9 +159,11 @@ void FEventTree::Insert (FEvent *z)
}
z->Left = &Nil;
z->Right = &Nil;
// printf ("Inserted distance %g, vertex %d, seg %d\n",
// sqrt(z->Distance/4294967296.0), z->Info.Vertex, z->Info.FrontSeg);
z->Color = FEvent::RED;
while (z != Root && z->Parent->Color != FEvent::RED)
while (z != Root && z->Parent->Color == FEvent::RED)
{
if (z->Parent == z->Parent->Parent->Left)
{
@ -199,10 +206,11 @@ void FEventTree::Insert (FEvent *z)
}
z->Parent->Color = FEvent::BLACK;
z->Parent->Parent->Color = FEvent::RED;
RightRotate (z->Parent->Parent);
LeftRotate (z->Parent->Parent);
}
}
}
Root->Color = FEvent::BLACK;
}
void FEventTree::Delete (FEvent *z)
@ -405,3 +413,17 @@ FEvent *FEventTree::GetMinimum ()
}
return node;
}
void FEventTree::PrintTree (const FEvent *event) const
{
if (event->Left != &Nil)
{
PrintTree (event->Left);
}
printf (" Color %s, distance %g, vertex %d, seg %d\n", event->Color ? "BLACK" : " RED ",
sqrt(event->Distance/4294967296.0), event->Info.Vertex, event->Info.FrontSeg);
if (event->Right != &Nil)
{
PrintTree (event->Right);
}
}

View file

@ -207,13 +207,6 @@ int FNodeBuilder::CloseSubsector (TArray<MapSegGLEx> &segs, int subsector)
// A dot product serves to determine distance from the start seg.
D(printf("degenerate subsector\n"));
seg = &Segs[SegList[first].SegNum];
double x1 = Vertices[seg->v1].x;
double y1 = Vertices[seg->v1].y;
double dx = Vertices[seg->v2].x - x1, dx2;
double dy = Vertices[seg->v2].y - y1, dy2;
double lastdot = 0, dot;
bool firstside = seg->planefront;
#if 0
for (j = first + 1; j < max; ++j)
@ -227,114 +220,13 @@ int FNodeBuilder::CloseSubsector (TArray<MapSegGLEx> &segs, int subsector)
}
#endif
// Stage 1. Go forward.
for (i = first + 1; i < max; ++i)
{
double bestdot = DBL_MAX;
FPrivSeg *bestseg = NULL;
for (j = first + 1; j < max; ++j)
{
seg = &Segs[SegList[j].SegNum];
if (seg->planefront != firstside)
{
continue;
}
dx2 = Vertices[seg->v1].x - x1;
dy2 = Vertices[seg->v1].y - y1;
dot = dx*dx2 + dy*dy2;
if (dot < bestdot && dot > lastdot)
{
bestdot = dot;
bestseg = seg;
}
}
if (bestseg != NULL)
{
if (prev->v2 != bestseg->v1)
{
PushConnectingGLSeg (subsector, segs, prev->v2, bestseg->v1);
count++;
}
seg->storedseg = PushGLSeg (segs, bestseg);
count++;
prev = bestseg;
lastdot = bestdot;
}
}
count += OutputDegenerateSubsector (segs, subsector, true, 0, prev);
// Stage 2. Go backward.
lastdot = DBL_MAX;
for (i = first + 1; i < max; ++i)
{
double bestdot = -DBL_MAX;
FPrivSeg *bestseg = NULL;
for (j = first + 1; j < max; ++j)
{
seg = &Segs[SegList[j].SegNum];
if (seg->planefront == firstside)
{
continue;
}
dx2 = Vertices[seg->v1].x - x1;
dy2 = Vertices[seg->v1].y - y1;
dot = dx*dx2 + dy*dy2;
if (dot > bestdot && dot < lastdot)
{
bestdot = dot;
bestseg = seg;
}
}
if (bestseg != NULL)
{
if (prev->v2 != bestseg->v1)
{
PushConnectingGLSeg (subsector, segs, prev->v2, bestseg->v1);
count++;
}
seg->storedseg = PushGLSeg (segs, bestseg);
count++;
prev = bestseg;
lastdot = bestdot;
}
}
count += OutputDegenerateSubsector (segs, subsector, false, DBL_MAX, prev);
// Stage 3. Go forward again.
lastdot = -DBL_MAX;
for (i = first + 1; i < max; ++i)
{
double bestdot = 0;
FPrivSeg *bestseg = NULL;
for (j = first + 1; j < max; ++j)
{
seg = &Segs[SegList[j].SegNum];
if (seg->planefront != firstside)
{
continue;
}
dx2 = Vertices[seg->v1].x - x1;
dy2 = Vertices[seg->v1].y - y1;
dot = dx*dx2 + dy*dy2;
if (dot < bestdot && dot > lastdot)
{
bestdot = dot;
bestseg = seg;
}
}
if (bestseg != NULL)
{
if (prev->v2 != bestseg->v1)
{
PushConnectingGLSeg (subsector, segs, prev->v2, bestseg->v1);
count++;
}
seg->storedseg = PushGLSeg (segs, bestseg);
count++;
prev = bestseg;
lastdot = bestdot;
}
}
count += OutputDegenerateSubsector (segs, subsector, true, -DBL_MAX, prev);
}
if (prev->v2 != firstVert)
@ -358,6 +250,73 @@ int FNodeBuilder::CloseSubsector (TArray<MapSegGLEx> &segs, int subsector)
return count;
}
int FNodeBuilder::OutputDegenerateSubsector (TArray<MapSegGLEx> &segs, int subsector, bool bForward, double lastdot, FPrivSeg *&prev)
{
static const double bestinit[2] = { -DBL_MAX, DBL_MAX };
FPrivSeg *seg;
int i, j, first, max, count;
double dot, x1, y1, dx, dy, dx2, dy2;
bool wantside;
first = Subsectors[subsector].firstline;
max = first + Subsectors[subsector].numlines;
count = 0;
seg = &Segs[SegList[first].SegNum];
x1 = Vertices[seg->v1].x;
y1 = Vertices[seg->v1].y;
dx = Vertices[seg->v2].x - x1;
dy = Vertices[seg->v2].y - y1;
wantside = seg->planefront ^ !bForward;
for (i = first + 1; i < max; ++i)
{
double bestdot = bestinit[bForward];
FPrivSeg *bestseg = NULL;
for (j = first + 1; j < max; ++j)
{
seg = &Segs[SegList[j].SegNum];
if (seg->planefront != wantside)
{
continue;
}
dx2 = Vertices[seg->v1].x - x1;
dy2 = Vertices[seg->v1].y - y1;
dot = dx*dx2 + dy*dy2;
if (bForward)
{
if (dot < bestdot && dot > lastdot)
{
bestdot = dot;
bestseg = seg;
}
}
else
{
if (dot > bestdot && dot < lastdot)
{
bestdot = dot;
bestseg = seg;
}
}
}
if (bestseg != NULL)
{
if (prev->v2 != bestseg->v1)
{
PushConnectingGLSeg (subsector, segs, prev->v2, bestseg->v1);
count++;
}
seg->storedseg = PushGLSeg (segs, bestseg);
count++;
prev = bestseg;
lastdot = bestdot;
}
}
return count;
}
DWORD FNodeBuilder::PushGLSeg (TArray<MapSegGLEx> &segs, const FPrivSeg *seg)
{
MapSegGLEx newseg;

View file

@ -18,6 +18,7 @@
*/
#include <assert.h>
#include <math.h>
#include "zdbsp.h"
#include "nodebuild.h"
@ -40,24 +41,7 @@ double FNodeBuilder::AddIntersection (const node_t &node, int vertex)
// Calculate signed distance of intersection vertex from start of splitter.
// Only ordering is important, so we don't need a sqrt.
FPrivVert *v = &Vertices[vertex];
double dx = double(v->x - node.x);
double dy = double(v->y - node.y);
double dist = dx*dx + dy*dy;
if (node.dx != 0)
{
if ((node.dx > 0 && dx < 0.0) || (node.dx < 0 && dx > 0.0))
{
dist = -dist;
}
}
else
{
if ((node.dy > 0 && dy < 0.0) || (node.dy < 0 && dy > 0.0))
{
dist = -dist;
}
}
double dist = (double(v->x) - node.x)*(node.dx) + (double(v->y) - node.y)*(node.dy);
FEvent *event = Events.FindEvent (dist);
@ -80,6 +64,8 @@ double FNodeBuilder::AddIntersection (const node_t &node, int vertex)
// seg information will be messed up in the generated tree.
void FNodeBuilder::FixSplitSharers ()
{
D(printf("events:\n"));
D(Events.PrintTree());
for (size_t i = 0; i < SplitSharers.Size(); ++i)
{
DWORD seg = SplitSharers[i].Seg;
@ -92,6 +78,15 @@ void FNodeBuilder::FixSplitSharers ()
continue;
}
D(printf("Considering events on seg %d(%d[%d,%d]->%d[%d,%d]) [%g:%g]\n", seg,
Segs[seg].v1,
Vertices[Segs[seg].v1].x>>16,
Vertices[Segs[seg].v1].y>>16,
Segs[seg].v2,
Vertices[Segs[seg].v2].x>>16,
Vertices[Segs[seg].v2].y>>16,
SplitSharers[i].Distance, event->Distance));
if (SplitSharers[i].Forward)
{
event = Events.GetSuccessor (event);
@ -113,11 +108,17 @@ void FNodeBuilder::FixSplitSharers ()
while (event != NULL && next != NULL && event->Info.Vertex != v2)
{
D(Printf("Forced split of seg %d(%d->%d) at %d(%d,%d)\n", seg,
Segs[seg].v1, Segs[seg].v2,
D(printf("Forced split of seg %d(%d[%d,%d]->%d[%d,%d]) at %d(%d,%d):%g\n", seg,
Segs[seg].v1,
Vertices[Segs[seg].v1].x>>16,
Vertices[Segs[seg].v1].y>>16,
Segs[seg].v2,
Vertices[Segs[seg].v2].x>>16,
Vertices[Segs[seg].v2].y>>16,
event->Info.Vertex,
Vertices[event->Info.Vertex].x>>16,
Vertices[event->Info.Vertex].y>>16));
Vertices[event->Info.Vertex].y>>16,
event->Distance));
DWORD newseg = SplitSeg (seg, event->Info.Vertex, 1);

View file

@ -876,12 +876,6 @@ void FProcessor::WriteSSectors2 (FWadWriter &out, const char *name, const MapSub
ssec[i].numlines = SHORT((WORD)subs[i].numlines);
}
out.WriteLump (name, ssec, sizeof(*ssec)*count);
FILE *f = fopen (name, "wb");
if (f)
{
fwrite (ssec, count, sizeof(*ssec), f);
fclose (f);
}
delete[] ssec;
if (count >= 65536)

View file

@ -34,6 +34,7 @@
StringPooling="TRUE"
RuntimeLibrary="4"
EnableFunctionLevelLinking="TRUE"
EnableEnhancedInstructionSet="2"
UsePrecompiledHeader="0"
PrecompiledHeaderFile=".\Release/zdbsp.pch"
AssemblerListingLocation=".\Release/"
@ -53,7 +54,9 @@
GenerateDebugInformation="TRUE"
ProgramDatabaseFile=".\Release/zdbsp.pdb"
SubSystem="1"
OptimizeForWindows98="1"/>
OptimizeReferences="2"
EnableCOMDATFolding="2"
OptimizeForWindows98="0"/>
<Tool
Name="VCMIDLTool"
TypeLibraryName=".\Release/zdbsp.tlb"/>