From 1a979de350a9728363281b345570b127e7375c6d Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 31 May 2006 15:39:58 +0000 Subject: [PATCH] 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) --- nodebuild.cpp | 8 ++ nodebuild.h | 5 ++ nodebuild_events.cpp | 30 ++++++- nodebuild_extract.cpp | 181 ++++++++++++++++-------------------------- nodebuild_gl.cpp | 43 +++++----- processor.cpp | 6 -- zdbsp.vcproj | 5 +- 7 files changed, 135 insertions(+), 143 deletions(-) diff --git a/nodebuild.cpp b/nodebuild.cpp index d7e9cf6..8472277 100644 --- a/nodebuild.cpp +++ b/nodebuild.cpp @@ -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) diff --git a/nodebuild.h b/nodebuild.h index 42426a9..63fb7f3 100644 --- a/nodebuild.h +++ b/nodebuild.h @@ -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 &segs, int subsector); DWORD PushGLSeg (TArray &segs, const FPrivSeg *seg); void PushConnectingGLSeg (int subsector, TArray &segs, int v1, int v2); + int OutputDegenerateSubsector (TArray &segs, int subsector, bool bForward, double lastdot, FPrivSeg *&prev); static int SortSegs (const void *a, const void *b); diff --git a/nodebuild_events.cpp b/nodebuild_events.cpp index adccb63..b950b03 100644 --- a/nodebuild_events.cpp +++ b/nodebuild_events.cpp @@ -17,12 +17,17 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include +#include +#include #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); + } +} diff --git a/nodebuild_extract.cpp b/nodebuild_extract.cpp index 174d4da..444bf6f 100644 --- a/nodebuild_extract.cpp +++ b/nodebuild_extract.cpp @@ -207,13 +207,6 @@ int FNodeBuilder::CloseSubsector (TArray &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 &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 &segs, int subsector) return count; } +int FNodeBuilder::OutputDegenerateSubsector (TArray &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 &segs, const FPrivSeg *seg) { MapSegGLEx newseg; diff --git a/nodebuild_gl.cpp b/nodebuild_gl.cpp index 5461627..2bce8cd 100644 --- a/nodebuild_gl.cpp +++ b/nodebuild_gl.cpp @@ -18,6 +18,7 @@ */ #include +#include #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); diff --git a/processor.cpp b/processor.cpp index 3f84efe..5447e0c 100644 --- a/processor.cpp +++ b/processor.cpp @@ -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) diff --git a/zdbsp.vcproj b/zdbsp.vcproj index e6d6508..8f22c22 100644 --- a/zdbsp.vcproj +++ b/zdbsp.vcproj @@ -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"/>