mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2024-11-15 16:51:31 +00:00
- Merged in recent ZDBSP fixes:
- Added code to explicitly handle outputting overlapping segs when building GL nodes with ZDBSP, removing the check that discarded them early on. - 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. SVN r160 (trunk)
This commit is contained in:
parent
fd1a239c66
commit
4325fb8993
7 changed files with 213 additions and 291 deletions
|
@ -1,3 +1,20 @@
|
|||
May 31, 2006
|
||||
- Merged in recent ZDBSP fixes:
|
||||
- Added code to explicitly handle outputting overlapping segs when
|
||||
building GL nodes with ZDBSP, removing the check that discarded
|
||||
them early on.
|
||||
- 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.
|
||||
|
||||
|
||||
May 31, 2006 (Changes by Graf Zahl)
|
||||
- Fixed: Ammo items dropped by monsters that have a default amount of 1 didn't
|
||||
contain any ammo at all.
|
||||
|
|
|
@ -88,6 +88,7 @@ void FNodeBuilder::BuildTree ()
|
|||
|
||||
C_InitTicker ("Building BSP", FRACUNIT);
|
||||
HackSeg = DWORD_MAX;
|
||||
HackMate = DWORD_MAX;
|
||||
CreateNode (0, bbox);
|
||||
CreateSubsectorsForReal ();
|
||||
C_InitTicker (NULL, 0);
|
||||
|
@ -320,7 +321,11 @@ bool FNodeBuilder::CheckSubsector (DWORD set, node_t &node, DWORD &splitseg, int
|
|||
} while (seg != DWORD_MAX);
|
||||
|
||||
if (seg == DWORD_MAX)
|
||||
{ // It's a valid subsector
|
||||
{ // It's a valid non-GL subsector, and probably a valid GL subsector too.
|
||||
if (GLNodes)
|
||||
{
|
||||
return CheckSubsectorOverlappingSegs (set, node, splitseg);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -331,20 +336,60 @@ bool FNodeBuilder::CheckSubsector (DWORD set, node_t &node, DWORD &splitseg, int
|
|||
// from multiple sectors, and it seems ZenNode does something
|
||||
// similar. It is the only technique I could find that makes the
|
||||
// "transparent water" in nb_bmtrk.wad work properly.
|
||||
//
|
||||
return ShoveSegBehind (set, node, seg, DWORD_MAX);
|
||||
}
|
||||
|
||||
// When creating GL nodes, we need to check for segs with the same start and
|
||||
// end vertices and split them into two subsectors.
|
||||
|
||||
bool FNodeBuilder::CheckSubsectorOverlappingSegs (DWORD set, node_t &node, DWORD &splitseg)
|
||||
{
|
||||
int v1, v2;
|
||||
DWORD seg1, seg2;
|
||||
|
||||
for (seg1 = set; seg1 != DWORD_MAX; seg1 = Segs[seg1].next)
|
||||
{
|
||||
if (Segs[seg1].linedef == -1)
|
||||
{ // Do not check minisegs.
|
||||
continue;
|
||||
}
|
||||
v1 = Segs[seg1].v1;
|
||||
v2 = Segs[seg1].v2;
|
||||
for (seg2 = Segs[seg1].next; seg2 != DWORD_MAX; seg2 = Segs[seg2].next)
|
||||
{
|
||||
if (Segs[seg2].v1 == v1 && Segs[seg2].v2 == v2)
|
||||
{
|
||||
if (Segs[seg2].linedef == -1)
|
||||
{ // Do not put minisegs into a new subsector.
|
||||
swap (seg1, seg2);
|
||||
}
|
||||
D(Printf("Need to synthesize a splitter for set %d on seg %d (ov)\n", set, seg2));
|
||||
splitseg = DWORD_MAX;
|
||||
|
||||
return ShoveSegBehind (set, node, seg2, seg1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// It really is a good subsector.
|
||||
return false;
|
||||
}
|
||||
|
||||
// The seg is marked to indicate that it should be forced to the
|
||||
// back of the splitter. Because these segs already form a convex
|
||||
// set, all the other segs will be in front of the splitter. Since
|
||||
// the splitter is formed from this seg, the back of the splitter
|
||||
// will have a one-dimensional subsector. SplitSegs() will add two
|
||||
// new minisegs to close it: one seg replaces this one on the front
|
||||
// of the splitter, and the other is its partner on the back.
|
||||
//
|
||||
// Old code that will actually create valid two-dimensional sectors
|
||||
// is included below for reference but is not likely to be used again.
|
||||
// will have a one-dimensional subsector. SplitSegs() will add one
|
||||
// or two new minisegs to close it: If mate is DWORD_MAX, then a
|
||||
// new seg is created to replace this one on the front of the
|
||||
// splitter. Otherwise, mate takes its place. In either case, the
|
||||
// seg in front of the splitter is partnered with a new miniseg on
|
||||
// the back so that the back will have two segs.
|
||||
|
||||
bool FNodeBuilder::ShoveSegBehind (DWORD set, node_t &node, DWORD seg, DWORD mate)
|
||||
{
|
||||
SetNodeFromSeg (node, &Segs[seg]);
|
||||
HackSeg = seg;
|
||||
HackMate = mate;
|
||||
if (!Segs[seg].planefront)
|
||||
{
|
||||
node.x += node.dx;
|
||||
|
@ -353,79 +398,6 @@ bool FNodeBuilder::CheckSubsector (DWORD set, node_t &node, DWORD &splitseg, int
|
|||
node.dy = -node.dy;
|
||||
}
|
||||
return Heuristic (node, set, false) != 0;
|
||||
|
||||
#if 0
|
||||
// If there are only two segs in the set, and they form two sides
|
||||
// of a triangle, the splitter should pass through their shared
|
||||
// point and the (imaginary) third side of the triangle
|
||||
if (setsize == 2)
|
||||
{
|
||||
FPrivVert *v1, *v2, *v3;
|
||||
|
||||
if (Vertices[Segs[set].v2] == Vertices[Segs[seg].v1])
|
||||
{
|
||||
v1 = &Vertices[Segs[set].v1];
|
||||
v2 = &Vertices[Segs[seg].v2];
|
||||
v3 = &Vertices[Segs[set].v2];
|
||||
}
|
||||
else if (Vertices[Segs[set].v1] == Vertices[Segs[seg].v2])
|
||||
{
|
||||
v1 = &Vertices[Segs[seg].v1];
|
||||
v2 = &Vertices[Segs[set].v2];
|
||||
v3 = &Vertices[Segs[seg].v2];
|
||||
}
|
||||
else
|
||||
{
|
||||
v1 = v2 = v3 = NULL;
|
||||
}
|
||||
if (v1 != NULL)
|
||||
{
|
||||
node.x = v3->x;
|
||||
node.y = v3->y;
|
||||
node.dx = v1->x + (v2->x-v1->x)/2 - node.x;
|
||||
node.dy = v1->y + (v2->y-v1->y)/2 - node.y;
|
||||
return Heuristic (node, set, false) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool nosplit = true;
|
||||
int firsthit = seg;
|
||||
|
||||
do
|
||||
{
|
||||
seg = firsthit;
|
||||
do
|
||||
{
|
||||
if (Segs[seg].linedef != -1 &&
|
||||
Segs[seg].frontsector != sec &&
|
||||
Segs[seg].frontsector == Segs[seg].backsector)
|
||||
{
|
||||
node.x = Vertices[Segs[set].v1].x;
|
||||
node.y = Vertices[Segs[set].v1].y;
|
||||
node.dx = Vertices[Segs[seg].v2].x - node.x;
|
||||
node.dy = Vertices[Segs[seg].v2].y - node.y;
|
||||
|
||||
if (Heuristic (node, set, nosplit) != 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
node.dx = Vertices[Segs[seg].v1].x - node.x;
|
||||
node.dy = Vertices[Segs[seg].v1].y - node.y;
|
||||
|
||||
if (Heuristic (node, set, nosplit) != 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
seg = Segs[seg].next;
|
||||
} while (seg != DWORD_MAX);
|
||||
} while ((nosplit ^= 1) == 0);
|
||||
|
||||
// Give up.
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Splitters are chosen to coincide with segs in the given set. To reduce the
|
||||
|
@ -525,6 +497,7 @@ int FNodeBuilder::Heuristic (node_t &node, DWORD set, bool honorNoSplit)
|
|||
int side;
|
||||
bool splitter = false;
|
||||
unsigned int max, m2, p, q;
|
||||
double frac;
|
||||
|
||||
Touched.Clear ();
|
||||
Colinear.Clear ();
|
||||
|
@ -616,6 +589,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)
|
||||
|
@ -900,15 +880,24 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou
|
|||
DWORD newback, newfront;
|
||||
|
||||
newback = AddMiniseg (seg->v2, seg->v1, DWORD_MAX, set, splitseg);
|
||||
if (HackMate == DWORD_MAX)
|
||||
{
|
||||
newfront = AddMiniseg (Segs[set].v1, Segs[set].v2, newback, set, splitseg);
|
||||
Segs[newfront].next = outset0;
|
||||
outset0 = newfront;
|
||||
}
|
||||
else
|
||||
{
|
||||
newfront = HackMate;
|
||||
Segs[newfront].partner = newback;
|
||||
Segs[newback].partner = newfront;
|
||||
}
|
||||
Segs[newback].frontsector = Segs[newback].backsector =
|
||||
Segs[newfront].frontsector = Segs[newfront].backsector =
|
||||
Segs[set].frontsector;
|
||||
|
||||
Segs[newback].next = outset1;
|
||||
outset1 = newback;
|
||||
Segs[newfront].next = outset0;
|
||||
outset0 = newfront;
|
||||
}
|
||||
set = next;
|
||||
}
|
||||
|
|
|
@ -133,6 +133,7 @@ private:
|
|||
TArray<FSplitSharer> SplitSharers; // Segs collinear with the current splitter
|
||||
|
||||
DWORD HackSeg; // Seg to force to back of splitter
|
||||
DWORD HackMate; // Seg to use in front of hack seg
|
||||
FLevel &Level;
|
||||
bool GLNodes; // Add minisegs to make GL nodes?
|
||||
|
||||
|
@ -143,7 +144,7 @@ private:
|
|||
int SelectVertexExact (FPrivVert &vertex);
|
||||
void BuildTree ();
|
||||
void MakeSegsFromSides ();
|
||||
FPrivSeg *CheckSegForDuplicate (const FPrivSeg *check);
|
||||
int CreateSeg (int linenum, int sidenum);
|
||||
void GroupSegPlanes ();
|
||||
void FindPolyContainers (TArray<FPolyStart> &spots, TArray<FPolyStart> &anchors);
|
||||
bool GetPolyExtents (int polynum, fixed_t bbox[4]);
|
||||
|
@ -153,7 +154,8 @@ private:
|
|||
int CreateSubsector (DWORD set, fixed_t bbox[4]);
|
||||
void CreateSubsectorsForReal ();
|
||||
bool CheckSubsector (DWORD set, node_t &node, DWORD &splitseg, int setsize);
|
||||
int SelectSplitter (DWORD set, node_t &node, DWORD &splitseg, int step, bool nosplit);
|
||||
bool CheckSubsectorOverlappingSegs (DWORD set, node_t &node, DWORD &splitseg);
|
||||
bool ShoveSegBehind (DWORD set, node_t &node, DWORD seg, DWORD mate); int SelectSplitter (DWORD set, node_t &node, DWORD &splitseg, int step, bool nosplit);
|
||||
void SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &outset0, DWORD &outset1);
|
||||
DWORD SplitSeg (DWORD segnum, int splitvert, int v1InFront);
|
||||
int Heuristic (node_t &node, DWORD set, bool honorNoSplit);
|
||||
|
@ -173,6 +175,7 @@ private:
|
|||
int CloseSubsector (TArray<seg_t> &segs, int subsector, vertex_t *outVerts);
|
||||
DWORD PushGLSeg (TArray<seg_t> &segs, const FPrivSeg *seg, vertex_t *outVerts);
|
||||
void PushConnectingGLSeg (int subsector, TArray<seg_t> &segs, vertex_t *v1, vertex_t *v2);
|
||||
int OutputDegenerateSubsector (TArray<seg_t> &segs, int subsector, bool bForward, double lastdot, FPrivSeg *&prev, vertex_t *outVerts);
|
||||
|
||||
static int STACK_ARGS SortSegs (const void *a, const void *b);
|
||||
|
||||
|
|
|
@ -37,12 +37,15 @@
|
|||
**
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "doomtype.h"
|
||||
#include "nodebuild.h"
|
||||
|
||||
FEventTree::FEventTree ()
|
||||
: Root (&Nil), Spare (NULL)
|
||||
{
|
||||
memset (&Nil, 0, sizeof(Nil));
|
||||
Nil.Color = FEvent::BLACK;
|
||||
}
|
||||
|
||||
FEventTree::~FEventTree ()
|
||||
|
@ -85,7 +88,7 @@ void FEventTree::LeftRotate (FEvent *x)
|
|||
y->Left->Parent = x;
|
||||
}
|
||||
y->Parent = x->Parent;
|
||||
if (x->Parent != &Nil)
|
||||
if (x->Parent == &Nil)
|
||||
{
|
||||
Root = y;
|
||||
}
|
||||
|
@ -110,7 +113,7 @@ void FEventTree::RightRotate (FEvent *x)
|
|||
y->Right->Parent = x;
|
||||
}
|
||||
y->Parent = x->Parent;
|
||||
if (x->Parent != &Nil)
|
||||
if (x->Parent == &Nil)
|
||||
{
|
||||
Root = y;
|
||||
}
|
||||
|
@ -176,7 +179,7 @@ void FEventTree::Insert (FEvent *z)
|
|||
z->Right = &Nil;
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -219,10 +222,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)
|
||||
|
|
|
@ -246,125 +246,15 @@ int FNodeBuilder::CloseSubsector (TArray<seg_t> &segs, int subsector, vertex_t *
|
|||
// to the start seg.
|
||||
// A dot product serves to determine distance from the start seg.
|
||||
|
||||
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;
|
||||
|
||||
// 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, &outVerts[prev->v2], &outVerts[bestseg->v1]);
|
||||
count++;
|
||||
}
|
||||
seg->storedseg = PushGLSeg (segs, bestseg, outVerts);
|
||||
count++;
|
||||
prev = bestseg;
|
||||
lastdot = bestdot;
|
||||
}
|
||||
}
|
||||
count += OutputDegenerateSubsector (segs, subsector, true, 0, prev, outVerts);
|
||||
|
||||
// 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, &outVerts[prev->v2], &outVerts[bestseg->v1]);
|
||||
count++;
|
||||
}
|
||||
seg->storedseg = PushGLSeg (segs, bestseg, outVerts);
|
||||
count++;
|
||||
prev = bestseg;
|
||||
lastdot = bestdot;
|
||||
}
|
||||
}
|
||||
count += OutputDegenerateSubsector (segs, subsector, false, DBL_MAX, prev, outVerts);
|
||||
|
||||
// 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;
|
||||
count += OutputDegenerateSubsector (segs, subsector, true, -DBL_MAX, prev, outVerts);
|
||||
}
|
||||
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, &outVerts[prev->v2], &outVerts[bestseg->v1]);
|
||||
count++;
|
||||
}
|
||||
seg->storedseg = PushGLSeg (segs, bestseg, outVerts);
|
||||
count++;
|
||||
prev = bestseg;
|
||||
lastdot = bestdot;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (prev->v2 != firstVert)
|
||||
{
|
||||
|
@ -375,6 +265,73 @@ int FNodeBuilder::CloseSubsector (TArray<seg_t> &segs, int subsector, vertex_t *
|
|||
return count;
|
||||
}
|
||||
|
||||
int FNodeBuilder::OutputDegenerateSubsector (TArray<seg_t> &segs, int subsector, bool bForward, double lastdot, FPrivSeg *&prev, vertex_t *outVerts)
|
||||
{
|
||||
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, &outVerts[prev->v2], &outVerts[bestseg->v1]);
|
||||
count++;
|
||||
}
|
||||
seg->storedseg = PushGLSeg (segs, bestseg, outVerts);
|
||||
count++;
|
||||
prev = bestseg;
|
||||
lastdot = bestdot;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
DWORD FNodeBuilder::PushGLSeg (TArray<seg_t> &segs, const FPrivSeg *seg, vertex_t *outVerts)
|
||||
{
|
||||
seg_t newseg;
|
||||
|
|
|
@ -63,24 +63,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);
|
||||
if (event == NULL)
|
||||
|
|
|
@ -125,14 +125,8 @@ int FNodeBuilder::SelectVertexExact (FPrivVert &vertex)
|
|||
|
||||
void FNodeBuilder::MakeSegsFromSides ()
|
||||
{
|
||||
FPrivSeg *share1, *share2;
|
||||
FPrivSeg seg;
|
||||
int i, j;
|
||||
|
||||
seg.next = DWORD_MAX;
|
||||
seg.loopnum = 0;
|
||||
seg.partner = DWORD_MAX;
|
||||
|
||||
if (Level.NumLines == 0)
|
||||
{
|
||||
I_Error ("Map is empty.\n");
|
||||
|
@ -140,28 +134,9 @@ void FNodeBuilder::MakeSegsFromSides ()
|
|||
|
||||
for (i = 0; i < Level.NumLines; ++i)
|
||||
{
|
||||
share1 = NULL;
|
||||
if (Level.Lines[i].sidenum[0] != NO_SIDE)
|
||||
{
|
||||
seg.linedef = i;
|
||||
seg.sidedef = Level.Lines[i].sidenum[0];
|
||||
seg.frontsector = Level.Lines[i].frontsector;
|
||||
seg.backsector = Level.Lines[i].backsector;
|
||||
seg.v1 = (int)(size_t)Level.Lines[i].v1;
|
||||
seg.v2 = (int)(size_t)Level.Lines[i].v2;
|
||||
seg.nextforvert = Vertices[seg.v1].segs;
|
||||
seg.nextforvert2 = Vertices[seg.v2].segs2;
|
||||
share1 = CheckSegForDuplicate (&seg);
|
||||
if (share1 == NULL)
|
||||
{
|
||||
j = (int)Segs.Push (seg);
|
||||
Vertices[seg.v1].segs = j;
|
||||
Vertices[seg.v2].segs2 = j;
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf ("Linedefs %d and %d share endpoints.\n", i, share1->linedef);
|
||||
}
|
||||
CreateSeg (i, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -170,55 +145,49 @@ void FNodeBuilder::MakeSegsFromSides ()
|
|||
|
||||
if (Level.Lines[i].sidenum[1] != NO_SIDE)
|
||||
{
|
||||
seg.linedef = i;
|
||||
seg.sidedef = Level.Lines[i].sidenum[1];
|
||||
seg.frontsector = Level.Lines[i].backsector;
|
||||
seg.backsector = Level.Lines[i].frontsector;
|
||||
seg.v1 = (int)(size_t)Level.Lines[i].v2;
|
||||
seg.v2 = (int)(size_t)Level.Lines[i].v1;
|
||||
seg.nextforvert = Vertices[seg.v1].segs;
|
||||
seg.nextforvert2 = Vertices[seg.v2].segs2;
|
||||
share2 = CheckSegForDuplicate (&seg);
|
||||
if (share2 == NULL)
|
||||
{
|
||||
j = (int)Segs.Push (seg);
|
||||
Vertices[seg.v1].segs = j;
|
||||
Vertices[seg.v2].segs2 = j;
|
||||
|
||||
if (Level.Lines[i].sidenum[0] != NO_SIDE && share1 == NULL)
|
||||
j = CreateSeg (i, 1);
|
||||
if (Level.Lines[i].sidenum[0] != NO_SIDE)
|
||||
{
|
||||
Segs[j-1].partner = j;
|
||||
Segs[j].partner = j-1;
|
||||
}
|
||||
}
|
||||
else if (share1 == NULL || share2->linedef != share1->linedef)
|
||||
{
|
||||
Printf ("Linedefs %d and %d share endpoints.\n", i, share2->linedef);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for another seg with the same start and end vertices as this one.
|
||||
// Combined with its use above, this will find two-sided lines that are shadowed
|
||||
// by another one- or two-sided line, and it will also find one-sided lines that
|
||||
// shadow each other. It will not find one-sided lines that share endpoints but
|
||||
// face opposite directions. Although they should probably be a single two-sided
|
||||
// line, leaving them in will not generate bad nodes.
|
||||
int FNodeBuilder::CreateSeg (int linenum, int sidenum)
|
||||
{
|
||||
FPrivSeg seg;
|
||||
int segnum;
|
||||
|
||||
FNodeBuilder::FPrivSeg *FNodeBuilder::CheckSegForDuplicate (const FNodeBuilder::FPrivSeg *check)
|
||||
{
|
||||
DWORD segnum;
|
||||
seg.next = DWORD_MAX;
|
||||
seg.loopnum = 0;
|
||||
seg.partner = DWORD_MAX;
|
||||
|
||||
// Check for segs facing the same direction
|
||||
for (segnum = check->nextforvert; segnum != DWORD_MAX; segnum = Segs[segnum].nextforvert)
|
||||
{
|
||||
if (Segs[segnum].v2 == check->v2)
|
||||
{
|
||||
return &Segs[segnum];
|
||||
if (sidenum == 0)
|
||||
{ // front
|
||||
seg.frontsector = Level.Lines[linenum].frontsector;
|
||||
seg.backsector = Level.Lines[linenum].backsector;
|
||||
seg.v1 = (int)(size_t)Level.Lines[linenum].v1;
|
||||
seg.v2 = (int)(size_t)Level.Lines[linenum].v2;
|
||||
}
|
||||
else
|
||||
{ // back
|
||||
seg.frontsector = Level.Lines[linenum].backsector;
|
||||
seg.backsector = Level.Lines[linenum].frontsector;
|
||||
seg.v2 = (int)(size_t)Level.Lines[linenum].v1;
|
||||
seg.v1 = (int)(size_t)Level.Lines[linenum].v2;
|
||||
}
|
||||
return NULL;
|
||||
seg.linedef = linenum;
|
||||
seg.sidedef = Level.Lines[linenum].sidenum[sidenum];
|
||||
seg.nextforvert = Vertices[seg.v1].segs;
|
||||
seg.nextforvert2 = Vertices[seg.v2].segs2;
|
||||
|
||||
segnum = (int)Segs.Push (seg);
|
||||
Vertices[seg.v1].segs = segnum;
|
||||
Vertices[seg.v2].segs2 = segnum;
|
||||
|
||||
return segnum;
|
||||
}
|
||||
|
||||
// Group colinear segs together so that only one seg per line needs to be checked
|
||||
|
|
Loading…
Reference in a new issue