mirror of
https://github.com/ZDoom/zdbsp.git
synced 2024-11-25 05:11:10 +00:00
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:
parent
3128c11fd1
commit
1a979de350
7 changed files with 135 additions and 143 deletions
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"/>
|
||||
|
|
Loading…
Reference in a new issue