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; int side;
bool splitter = false; bool splitter = false;
size_t max, m2, p, q; size_t max, m2, p, q;
double frac;
Touched.Clear (); Touched.Clear ();
Colinear.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[0]++;
counts[1]++; counts[1]++;
if (test->linedef != -1) if (test->linedef != -1)

View file

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

View file

@ -17,12 +17,17 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include <string.h>
#include <stdio.h>
#include <math.h>
#include "zdbsp.h" #include "zdbsp.h"
#include "nodebuild.h" #include "nodebuild.h"
FEventTree::FEventTree () FEventTree::FEventTree ()
: Root (&Nil), Spare (NULL) : Root (&Nil), Spare (NULL)
{ {
memset (&Nil, 0, sizeof(Nil));
Nil.Color = FEvent::BLACK;
} }
FEventTree::~FEventTree () FEventTree::~FEventTree ()
@ -65,7 +70,7 @@ void FEventTree::LeftRotate (FEvent *x)
y->Left->Parent = x; y->Left->Parent = x;
} }
y->Parent = x->Parent; y->Parent = x->Parent;
if (x->Parent != &Nil) if (x->Parent == &Nil)
{ {
Root = y; Root = y;
} }
@ -90,7 +95,7 @@ void FEventTree::RightRotate (FEvent *x)
y->Right->Parent = x; y->Right->Parent = x;
} }
y->Parent = x->Parent; y->Parent = x->Parent;
if (x->Parent != &Nil) if (x->Parent == &Nil)
{ {
Root = y; Root = y;
} }
@ -154,9 +159,11 @@ void FEventTree::Insert (FEvent *z)
} }
z->Left = &Nil; z->Left = &Nil;
z->Right = &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; 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) if (z->Parent == z->Parent->Parent->Left)
{ {
@ -199,10 +206,11 @@ void FEventTree::Insert (FEvent *z)
} }
z->Parent->Color = FEvent::BLACK; z->Parent->Color = FEvent::BLACK;
z->Parent->Parent->Color = FEvent::RED; z->Parent->Parent->Color = FEvent::RED;
RightRotate (z->Parent->Parent); LeftRotate (z->Parent->Parent);
} }
} }
} }
Root->Color = FEvent::BLACK;
} }
void FEventTree::Delete (FEvent *z) void FEventTree::Delete (FEvent *z)
@ -405,3 +413,17 @@ FEvent *FEventTree::GetMinimum ()
} }
return node; 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. // A dot product serves to determine distance from the start seg.
D(printf("degenerate subsector\n")); 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 #if 0
for (j = first + 1; j < max; ++j) for (j = first + 1; j < max; ++j)
@ -227,114 +220,13 @@ int FNodeBuilder::CloseSubsector (TArray<MapSegGLEx> &segs, int subsector)
} }
#endif #endif
// Stage 1. Go forward. // Stage 1. Go forward.
for (i = first + 1; i < max; ++i) count += OutputDegenerateSubsector (segs, subsector, true, 0, prev);
{
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;
}
}
// Stage 2. Go backward. // Stage 2. Go backward.
lastdot = DBL_MAX; count += OutputDegenerateSubsector (segs, subsector, false, DBL_MAX, prev);
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;
}
}
// Stage 3. Go forward again. // Stage 3. Go forward again.
lastdot = -DBL_MAX; count += OutputDegenerateSubsector (segs, subsector, true, -DBL_MAX, prev);
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;
}
}
} }
if (prev->v2 != firstVert) if (prev->v2 != firstVert)
@ -358,6 +250,73 @@ int FNodeBuilder::CloseSubsector (TArray<MapSegGLEx> &segs, int subsector)
return count; 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) DWORD FNodeBuilder::PushGLSeg (TArray<MapSegGLEx> &segs, const FPrivSeg *seg)
{ {
MapSegGLEx newseg; MapSegGLEx newseg;

View file

@ -18,6 +18,7 @@
*/ */
#include <assert.h> #include <assert.h>
#include <math.h>
#include "zdbsp.h" #include "zdbsp.h"
#include "nodebuild.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. // Calculate signed distance of intersection vertex from start of splitter.
// Only ordering is important, so we don't need a sqrt. // Only ordering is important, so we don't need a sqrt.
FPrivVert *v = &Vertices[vertex]; FPrivVert *v = &Vertices[vertex];
double dx = double(v->x - node.x); double dist = (double(v->x) - node.x)*(node.dx) + (double(v->y) - node.y)*(node.dy);
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;
}
}
FEvent *event = Events.FindEvent (dist); 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. // seg information will be messed up in the generated tree.
void FNodeBuilder::FixSplitSharers () void FNodeBuilder::FixSplitSharers ()
{ {
D(printf("events:\n"));
D(Events.PrintTree());
for (size_t i = 0; i < SplitSharers.Size(); ++i) for (size_t i = 0; i < SplitSharers.Size(); ++i)
{ {
DWORD seg = SplitSharers[i].Seg; DWORD seg = SplitSharers[i].Seg;
@ -92,6 +78,15 @@ void FNodeBuilder::FixSplitSharers ()
continue; 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) if (SplitSharers[i].Forward)
{ {
event = Events.GetSuccessor (event); event = Events.GetSuccessor (event);
@ -113,11 +108,17 @@ void FNodeBuilder::FixSplitSharers ()
while (event != NULL && next != NULL && event->Info.Vertex != v2) while (event != NULL && next != NULL && event->Info.Vertex != v2)
{ {
D(Printf("Forced split of seg %d(%d->%d) at %d(%d,%d)\n", seg, D(printf("Forced split of seg %d(%d[%d,%d]->%d[%d,%d]) at %d(%d,%d):%g\n", seg,
Segs[seg].v1, Segs[seg].v2, 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, event->Info.Vertex,
Vertices[event->Info.Vertex].x>>16, 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); 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); ssec[i].numlines = SHORT((WORD)subs[i].numlines);
} }
out.WriteLump (name, ssec, sizeof(*ssec)*count); out.WriteLump (name, ssec, sizeof(*ssec)*count);
FILE *f = fopen (name, "wb");
if (f)
{
fwrite (ssec, count, sizeof(*ssec), f);
fclose (f);
}
delete[] ssec; delete[] ssec;
if (count >= 65536) if (count >= 65536)

View file

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