mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-26 05:51:20 +00:00
- Merge BSP-able polyobjects back into the trunk.
SVN r2480 (trunk)
This commit is contained in:
parent
8d5ca6501a
commit
677d07f837
17 changed files with 1242 additions and 810 deletions
|
@ -64,13 +64,6 @@ set( CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} ${REL_C_FLAGS}" )
|
||||||
set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${REL_C_FLAGS}" )
|
set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${REL_C_FLAGS}" )
|
||||||
set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${DEB_C_FLAGS} -D_DEBUG" )
|
set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${DEB_C_FLAGS} -D_DEBUG" )
|
||||||
|
|
||||||
if( CMAKE_COMPILER_IS_GNUCXX AND PROFILE )
|
|
||||||
set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -pg" )
|
|
||||||
set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pg" )
|
|
||||||
set( CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -pg" )
|
|
||||||
set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -pg" )
|
|
||||||
endif( CMAKE_COMPILER_IS_GNUCXX AND PROFILE )
|
|
||||||
|
|
||||||
if( ZLIB_FOUND )
|
if( ZLIB_FOUND )
|
||||||
message( STATUS "Using system zlib" )
|
message( STATUS "Using system zlib" )
|
||||||
else( ZLIB_FOUND )
|
else( ZLIB_FOUND )
|
||||||
|
|
|
@ -330,6 +330,13 @@ endif( NOT NO_ASM )
|
||||||
# Set up flags for GCC
|
# Set up flags for GCC
|
||||||
|
|
||||||
if( CMAKE_COMPILER_IS_GNUCXX )
|
if( CMAKE_COMPILER_IS_GNUCXX )
|
||||||
|
if( PROFILE )
|
||||||
|
set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -pg" )
|
||||||
|
set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pg" )
|
||||||
|
set( CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -pg" )
|
||||||
|
set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -pg" )
|
||||||
|
endif( PROFILE )
|
||||||
|
|
||||||
set( REL_CXX_FLAGS "-fno-rtti" )
|
set( REL_CXX_FLAGS "-fno-rtti" )
|
||||||
if( NOT PROFILE )
|
if( NOT PROFILE )
|
||||||
set( REL_CXX_FLAGS "${REL_CXX_FLAGS} -fomit-frame-pointer" )
|
set( REL_CXX_FLAGS "${REL_CXX_FLAGS} -fomit-frame-pointer" )
|
||||||
|
|
|
@ -1672,6 +1672,22 @@ void AM_drawSeg(seg_t *seg, const AMColor &color)
|
||||||
AM_drawMline(&l, color);
|
AM_drawMline(&l, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AM_drawPolySeg(FPolySeg *seg, const AMColor &color)
|
||||||
|
{
|
||||||
|
mline_t l;
|
||||||
|
l.a.x = seg->v1.x >> FRACTOMAPBITS;
|
||||||
|
l.a.y = seg->v1.y >> FRACTOMAPBITS;
|
||||||
|
l.b.x = seg->v2.x >> FRACTOMAPBITS;
|
||||||
|
l.b.y = seg->v2.y >> FRACTOMAPBITS;
|
||||||
|
|
||||||
|
if (am_rotate == 1 || (am_rotate == 2 && viewactive))
|
||||||
|
{
|
||||||
|
AM_rotatePoint (&l.a.x, &l.a.y);
|
||||||
|
AM_rotatePoint (&l.b.x, &l.b.y);
|
||||||
|
}
|
||||||
|
AM_drawMline(&l, color);
|
||||||
|
}
|
||||||
|
|
||||||
void AM_showSS()
|
void AM_showSS()
|
||||||
{
|
{
|
||||||
if (am_showsubsector >= 0 && am_showsubsector < numsubsectors)
|
if (am_showsubsector >= 0 && am_showsubsector < numsubsectors)
|
||||||
|
@ -1682,13 +1698,13 @@ void AM_showSS()
|
||||||
red.FromRGB(255,0,0);
|
red.FromRGB(255,0,0);
|
||||||
|
|
||||||
subsector_t *sub = &subsectors[am_showsubsector];
|
subsector_t *sub = &subsectors[am_showsubsector];
|
||||||
for(unsigned int i=0;i<sub->numlines;i++)
|
for (unsigned int i = 0; i < sub->numlines; i++)
|
||||||
{
|
{
|
||||||
AM_drawSeg(&segs[sub->firstline+i], yellow);
|
AM_drawSeg(sub->firstline + i, yellow);
|
||||||
}
|
}
|
||||||
PO_LinkToSubsectors();
|
PO_LinkToSubsectors();
|
||||||
|
|
||||||
for(int i=0;i<po_NumPolyobjs;i++)
|
for (int i = 0; i <po_NumPolyobjs; i++)
|
||||||
{
|
{
|
||||||
FPolyObj *po = &polyobjs[i];
|
FPolyObj *po = &polyobjs[i];
|
||||||
FPolyNode *pnode = po->subsectorlinks;
|
FPolyNode *pnode = po->subsectorlinks;
|
||||||
|
@ -1697,9 +1713,9 @@ void AM_showSS()
|
||||||
{
|
{
|
||||||
if (pnode->subsector == sub)
|
if (pnode->subsector == sub)
|
||||||
{
|
{
|
||||||
for(unsigned j=0;j<pnode->segs.Size();j++)
|
for (unsigned j = 0; j < pnode->segs.Size(); j++)
|
||||||
{
|
{
|
||||||
AM_drawSeg(&pnode->segs[j], red);
|
AM_drawPolySeg(&pnode->segs[j], red);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pnode = pnode->snext;
|
pnode = pnode->snext;
|
||||||
|
|
|
@ -62,10 +62,17 @@ const int AAPreference = 16;
|
||||||
#define D(x) do{}while(0)
|
#define D(x) do{}while(0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
FNodeBuilder::FNodeBuilder(FLevel &level)
|
||||||
|
: Level(level), GLNodes(false), SegsStuffed(0)
|
||||||
|
{
|
||||||
|
|
||||||
|
VertexMap = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
FNodeBuilder::FNodeBuilder (FLevel &level,
|
FNodeBuilder::FNodeBuilder (FLevel &level,
|
||||||
TArray<FPolyStart> &polyspots, TArray<FPolyStart> &anchors,
|
TArray<FPolyStart> &polyspots, TArray<FPolyStart> &anchors,
|
||||||
bool makeGLNodes, bool enableSSE2)
|
bool makeGLNodes)
|
||||||
: Level(level), GLNodes(makeGLNodes), EnableSSE2(enableSSE2), SegsStuffed(0)
|
: Level(level), GLNodes(makeGLNodes), SegsStuffed(0)
|
||||||
{
|
{
|
||||||
VertexMap = new FVertexMap (*this, Level.MinX, Level.MinY, Level.MaxX, Level.MaxY);
|
VertexMap = new FVertexMap (*this, Level.MinX, Level.MinY, Level.MaxX, Level.MaxY);
|
||||||
FindUsedVertices (Level.Vertices, Level.NumVertices);
|
FindUsedVertices (Level.Vertices, Level.NumVertices);
|
||||||
|
@ -83,6 +90,33 @@ FNodeBuilder::~FNodeBuilder()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FNodeBuilder::BuildMini(bool makeGLNodes)
|
||||||
|
{
|
||||||
|
GLNodes = makeGLNodes;
|
||||||
|
GroupSegPlanesSimple();
|
||||||
|
BuildTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FNodeBuilder::Clear()
|
||||||
|
{
|
||||||
|
SegsStuffed = 0;
|
||||||
|
Nodes.Clear();
|
||||||
|
Subsectors.Clear();
|
||||||
|
SubsectorSets.Clear();
|
||||||
|
Segs.Clear();
|
||||||
|
Vertices.Clear();
|
||||||
|
SegList.Clear();
|
||||||
|
PlaneChecked.Clear();
|
||||||
|
Planes.Clear();
|
||||||
|
Touched.Clear();
|
||||||
|
Colinear.Clear();
|
||||||
|
SplitSharers.Clear();
|
||||||
|
if (VertexMap == NULL)
|
||||||
|
{
|
||||||
|
VertexMap = new FVertexMapSimple(*this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void FNodeBuilder::BuildTree ()
|
void FNodeBuilder::BuildTree ()
|
||||||
{
|
{
|
||||||
fixed_t bbox[4];
|
fixed_t bbox[4];
|
||||||
|
@ -90,35 +124,38 @@ void FNodeBuilder::BuildTree ()
|
||||||
C_InitTicker ("Building BSP", FRACUNIT);
|
C_InitTicker ("Building BSP", FRACUNIT);
|
||||||
HackSeg = DWORD_MAX;
|
HackSeg = DWORD_MAX;
|
||||||
HackMate = DWORD_MAX;
|
HackMate = DWORD_MAX;
|
||||||
CreateNode (0, bbox);
|
CreateNode (0, Segs.Size(), bbox);
|
||||||
CreateSubsectorsForReal ();
|
CreateSubsectorsForReal ();
|
||||||
C_InitTicker (NULL, 0);
|
C_InitTicker (NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int FNodeBuilder::CreateNode (DWORD set, fixed_t bbox[4])
|
int FNodeBuilder::CreateNode (DWORD set, unsigned int count, fixed_t bbox[4])
|
||||||
{
|
{
|
||||||
node_t node;
|
node_t node;
|
||||||
int skip, count, selstat;
|
int skip, selstat;
|
||||||
DWORD splitseg;
|
DWORD splitseg;
|
||||||
|
|
||||||
count = CountSegs (set);
|
skip = int(count / MaxSegs);
|
||||||
skip = count / MaxSegs;
|
|
||||||
|
|
||||||
|
// When building GL nodes, count may not be an exact count of the number of segs
|
||||||
|
// in the set. That's okay, because we just use it to get a skip count, so an
|
||||||
|
// estimate is fine.
|
||||||
if ((selstat = SelectSplitter (set, node, splitseg, skip, true)) > 0 ||
|
if ((selstat = SelectSplitter (set, node, splitseg, skip, true)) > 0 ||
|
||||||
(skip > 0 && (selstat = SelectSplitter (set, node, splitseg, 1, true)) > 0) ||
|
(skip > 0 && (selstat = SelectSplitter (set, node, splitseg, 1, true)) > 0) ||
|
||||||
(selstat < 0 && (SelectSplitter (set, node, splitseg, skip, false) > 0 ||
|
(selstat < 0 && (SelectSplitter (set, node, splitseg, skip, false) > 0 ||
|
||||||
(skip > 0 && SelectSplitter (set, node, splitseg, 1, false)))) ||
|
(skip > 0 && SelectSplitter (set, node, splitseg, 1, false)))) ||
|
||||||
CheckSubsector (set, node, splitseg, count))
|
CheckSubsector (set, node, splitseg))
|
||||||
{
|
{
|
||||||
// Create a normal node
|
// Create a normal node
|
||||||
DWORD set1, set2;
|
DWORD set1, set2;
|
||||||
|
unsigned int count1, count2;
|
||||||
|
|
||||||
SplitSegs (set, node, splitseg, set1, set2);
|
SplitSegs (set, node, splitseg, set1, set2, count1, count2);
|
||||||
D(PrintSet (1, set1));
|
D(PrintSet (1, set1));
|
||||||
D(Printf (PRINT_LOG, "(%d,%d) delta (%d,%d) from seg %d\n", node.x>>16, node.y>>16, node.dx>>16, node.dy>>16, splitseg));
|
D(Printf (PRINT_LOG, "(%d,%d) delta (%d,%d) from seg %d\n", node.x>>16, node.y>>16, node.dx>>16, node.dy>>16, splitseg));
|
||||||
D(PrintSet (2, set2));
|
D(PrintSet (2, set2));
|
||||||
node.intchildren[0] = CreateNode (set1, node.bbox[0]);
|
node.intchildren[0] = CreateNode (set1, count1, node.bbox[0]);
|
||||||
node.intchildren[1] = CreateNode (set2, node.bbox[1]);
|
node.intchildren[1] = CreateNode (set2, count2, node.bbox[1]);
|
||||||
bbox[BOXTOP] = MAX (node.bbox[0][BOXTOP], node.bbox[1][BOXTOP]);
|
bbox[BOXTOP] = MAX (node.bbox[0][BOXTOP], node.bbox[1][BOXTOP]);
|
||||||
bbox[BOXBOTTOM] = MIN (node.bbox[0][BOXBOTTOM], node.bbox[1][BOXBOTTOM]);
|
bbox[BOXBOTTOM] = MIN (node.bbox[0][BOXBOTTOM], node.bbox[1][BOXBOTTOM]);
|
||||||
bbox[BOXLEFT] = MIN (node.bbox[0][BOXLEFT], node.bbox[1][BOXLEFT]);
|
bbox[BOXLEFT] = MIN (node.bbox[0][BOXLEFT], node.bbox[1][BOXLEFT]);
|
||||||
|
@ -173,17 +210,15 @@ void FNodeBuilder::CreateSubsectorsForReal ()
|
||||||
subsector_t sub;
|
subsector_t sub;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
sub.validcount = 0;
|
|
||||||
sub.CenterX = 0; // Code in p_setup.cpp will set these for us later.
|
|
||||||
sub.CenterY = 0;
|
|
||||||
sub.sector = NULL;
|
sub.sector = NULL;
|
||||||
sub.polys = NULL;
|
sub.polys = NULL;
|
||||||
|
sub.BSP = NULL;
|
||||||
|
|
||||||
for (i = 0; i < SubsectorSets.Size(); ++i)
|
for (i = 0; i < SubsectorSets.Size(); ++i)
|
||||||
{
|
{
|
||||||
DWORD set = SubsectorSets[i];
|
DWORD set = SubsectorSets[i];
|
||||||
|
DWORD firstline = (DWORD)SegList.Size();
|
||||||
|
|
||||||
sub.firstline = (DWORD)SegList.Size();
|
|
||||||
while (set != DWORD_MAX)
|
while (set != DWORD_MAX)
|
||||||
{
|
{
|
||||||
USegPtr ptr;
|
USegPtr ptr;
|
||||||
|
@ -192,14 +227,15 @@ void FNodeBuilder::CreateSubsectorsForReal ()
|
||||||
SegList.Push (ptr);
|
SegList.Push (ptr);
|
||||||
set = ptr.SegPtr->next;
|
set = ptr.SegPtr->next;
|
||||||
}
|
}
|
||||||
sub.numlines = (DWORD)(SegList.Size() - sub.firstline);
|
sub.numlines = (DWORD)(SegList.Size() - firstline);
|
||||||
|
sub.firstline = (seg_t *)firstline;
|
||||||
|
|
||||||
// Sort segs by linedef for special effects
|
// Sort segs by linedef for special effects
|
||||||
qsort (&SegList[sub.firstline], sub.numlines, sizeof(USegPtr), SortSegs);
|
qsort (&SegList[firstline], sub.numlines, sizeof(USegPtr), SortSegs);
|
||||||
|
|
||||||
// Convert seg pointers into indices
|
// Convert seg pointers into indices
|
||||||
D(Printf (PRINT_LOG, "Output subsector %d:\n", Subsectors.Size()));
|
D(Printf (PRINT_LOG, "Output subsector %d:\n", Subsectors.Size()));
|
||||||
for (unsigned int i = sub.firstline; i < SegList.Size(); ++i)
|
for (unsigned int i = firstline; i < SegList.Size(); ++i)
|
||||||
{
|
{
|
||||||
D(Printf (PRINT_LOG, " Seg %5d%c(%5d,%5d)-(%5d,%5d)\n", SegList[i].SegPtr - &Segs[0],
|
D(Printf (PRINT_LOG, " Seg %5d%c(%5d,%5d)-(%5d,%5d)\n", SegList[i].SegPtr - &Segs[0],
|
||||||
SegList[i].SegPtr->linedef == -1 ? '+' : ' ',
|
SegList[i].SegPtr->linedef == -1 ? '+' : ' ',
|
||||||
|
@ -273,24 +309,12 @@ int STACK_ARGS FNodeBuilder::SortSegs (const void *a, const void *b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int FNodeBuilder::CountSegs (DWORD set) const
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
while (set != DWORD_MAX)
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
set = Segs[set].next;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Given a set of segs, checks to make sure they all belong to a single
|
// Given a set of segs, checks to make sure they all belong to a single
|
||||||
// sector. If so, false is returned, and they become a subsector. If not,
|
// sector. If so, false is returned, and they become a subsector. If not,
|
||||||
// a splitter is synthesized, and true is returned to continue processing
|
// a splitter is synthesized, and true is returned to continue processing
|
||||||
// down this branch of the tree.
|
// down this branch of the tree.
|
||||||
|
|
||||||
bool FNodeBuilder::CheckSubsector (DWORD set, node_t &node, DWORD &splitseg, int setsize)
|
bool FNodeBuilder::CheckSubsector (DWORD set, node_t &node, DWORD &splitseg)
|
||||||
{
|
{
|
||||||
sector_t *sec;
|
sector_t *sec;
|
||||||
DWORD seg;
|
DWORD seg;
|
||||||
|
@ -506,7 +530,7 @@ int FNodeBuilder::Heuristic (node_t &node, DWORD set, bool honorNoSplit)
|
||||||
int realSegs[2] = { 0, 0 };
|
int realSegs[2] = { 0, 0 };
|
||||||
int specialSegs[2] = { 0, 0 };
|
int specialSegs[2] = { 0, 0 };
|
||||||
DWORD i = set;
|
DWORD i = set;
|
||||||
int sidev1, sidev2;
|
int sidev[2];
|
||||||
int side;
|
int side;
|
||||||
bool splitter = false;
|
bool splitter = false;
|
||||||
unsigned int max, m2, p, q;
|
unsigned int max, m2, p, q;
|
||||||
|
@ -525,7 +549,7 @@ int FNodeBuilder::Heuristic (node_t &node, DWORD set, bool honorNoSplit)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
side = ClassifyLine (node, test, sidev1, sidev2);
|
side = ClassifyLine (node, &Vertices[test->v1], &Vertices[test->v2], sidev);
|
||||||
}
|
}
|
||||||
switch (side)
|
switch (side)
|
||||||
{
|
{
|
||||||
|
@ -535,9 +559,9 @@ int FNodeBuilder::Heuristic (node_t &node, DWORD set, bool honorNoSplit)
|
||||||
// The "right" thing to do in this case is to only reject it if there is
|
// The "right" thing to do in this case is to only reject it if there is
|
||||||
// another nosplit seg from the same sector at this vertex. Note that a line
|
// another nosplit seg from the same sector at this vertex. Note that a line
|
||||||
// that lies exactly on top of the splitter is okay.
|
// that lies exactly on top of the splitter is okay.
|
||||||
if (test->loopnum && honorNoSplit && (sidev1 == 0 || sidev2 == 0))
|
if (test->loopnum && honorNoSplit && (sidev[0] == 0 || sidev[1] == 0))
|
||||||
{
|
{
|
||||||
if ((sidev1 | sidev2) != 0)
|
if ((sidev[0] | sidev[1]) != 0)
|
||||||
{
|
{
|
||||||
max = Touched.Size();
|
max = Touched.Size();
|
||||||
for (p = 0; p < max; ++p)
|
for (p = 0; p < max; ++p)
|
||||||
|
@ -735,8 +759,10 @@ int FNodeBuilder::Heuristic (node_t &node, DWORD set, bool honorNoSplit)
|
||||||
return score;
|
return score;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &outset0, DWORD &outset1)
|
void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &outset0, DWORD &outset1, unsigned int &count0, unsigned int &count1)
|
||||||
{
|
{
|
||||||
|
unsigned int _count0 = 0;
|
||||||
|
unsigned int _count1 = 0;
|
||||||
outset0 = DWORD_MAX;
|
outset0 = DWORD_MAX;
|
||||||
outset1 = DWORD_MAX;
|
outset1 = DWORD_MAX;
|
||||||
|
|
||||||
|
@ -749,18 +775,18 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou
|
||||||
FPrivSeg *seg = &Segs[set];
|
FPrivSeg *seg = &Segs[set];
|
||||||
int next = seg->next;
|
int next = seg->next;
|
||||||
|
|
||||||
int sidev1, sidev2, side;
|
int sidev[2], side;
|
||||||
|
|
||||||
if (HackSeg == set)
|
if (HackSeg == set)
|
||||||
{
|
{
|
||||||
HackSeg = DWORD_MAX;
|
HackSeg = DWORD_MAX;
|
||||||
side = 1;
|
side = 1;
|
||||||
sidev1 = sidev2 = 0;
|
sidev[0] = sidev[1] = 0;
|
||||||
hack = true;
|
hack = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
side = ClassifyLine (node, seg, sidev1, sidev2);
|
side = ClassifyLine (node, &Vertices[seg->v1], &Vertices[seg->v2], sidev);
|
||||||
hack = false;
|
hack = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -769,11 +795,13 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou
|
||||||
case 0: // seg is entirely in front
|
case 0: // seg is entirely in front
|
||||||
seg->next = outset0;
|
seg->next = outset0;
|
||||||
outset0 = set;
|
outset0 = set;
|
||||||
|
_count0++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1: // seg is entirely in back
|
case 1: // seg is entirely in back
|
||||||
seg->next = outset1;
|
seg->next = outset1;
|
||||||
outset1 = set;
|
outset1 = set;
|
||||||
|
_count1++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: // seg needs to be split
|
default: // seg needs to be split
|
||||||
|
@ -803,18 +831,20 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou
|
||||||
Printf("SelectVertexClose selected endpoint of seg %u\n", set);
|
Printf("SelectVertexClose selected endpoint of seg %u\n", set);
|
||||||
}
|
}
|
||||||
|
|
||||||
seg2 = SplitSeg (set, vertnum, sidev1);
|
seg2 = SplitSeg (set, vertnum, sidev[0]);
|
||||||
|
|
||||||
Segs[seg2].next = outset0;
|
Segs[seg2].next = outset0;
|
||||||
outset0 = seg2;
|
outset0 = seg2;
|
||||||
Segs[set].next = outset1;
|
Segs[set].next = outset1;
|
||||||
outset1 = set;
|
outset1 = set;
|
||||||
|
_count0++;
|
||||||
|
_count1++;
|
||||||
|
|
||||||
// Also split the seg on the back side
|
// Also split the seg on the back side
|
||||||
if (Segs[set].partner != DWORD_MAX)
|
if (Segs[set].partner != DWORD_MAX)
|
||||||
{
|
{
|
||||||
int partner1 = Segs[set].partner;
|
int partner1 = Segs[set].partner;
|
||||||
int partner2 = SplitSeg (partner1, vertnum, sidev2);
|
int partner2 = SplitSeg (partner1, vertnum, sidev[1]);
|
||||||
// The newly created seg stays in the same set as the
|
// The newly created seg stays in the same set as the
|
||||||
// back seg because it has not been considered for splitting
|
// back seg because it has not been considered for splitting
|
||||||
// yet. If it had been, then the front seg would have already
|
// yet. If it had been, then the front seg would have already
|
||||||
|
@ -835,17 +865,17 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou
|
||||||
}
|
}
|
||||||
if (side >= 0 && GLNodes)
|
if (side >= 0 && GLNodes)
|
||||||
{
|
{
|
||||||
if (sidev1 == 0)
|
if (sidev[0] == 0)
|
||||||
{
|
{
|
||||||
double dist1 = AddIntersection (node, seg->v1);
|
double dist1 = AddIntersection (node, seg->v1);
|
||||||
if (sidev2 == 0)
|
if (sidev[1] == 0)
|
||||||
{
|
{
|
||||||
double dist2 = AddIntersection (node, seg->v2);
|
double dist2 = AddIntersection (node, seg->v2);
|
||||||
FSplitSharer share = { dist1, set, dist2 > dist1 };
|
FSplitSharer share = { dist1, set, dist2 > dist1 };
|
||||||
SplitSharers.Push (share);
|
SplitSharers.Push (share);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (sidev2 == 0)
|
else if (sidev[1] == 0)
|
||||||
{
|
{
|
||||||
AddIntersection (node, seg->v2);
|
AddIntersection (node, seg->v2);
|
||||||
}
|
}
|
||||||
|
@ -881,6 +911,8 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou
|
||||||
{
|
{
|
||||||
AddMinisegs (node, splitseg, outset0, outset1);
|
AddMinisegs (node, splitseg, outset0, outset1);
|
||||||
}
|
}
|
||||||
|
count0 = _count0;
|
||||||
|
count1 = _count1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FNodeBuilder::SetNodeFromSeg (node_t &node, const FPrivSeg *pseg) const
|
void FNodeBuilder::SetNodeFromSeg (node_t &node, const FPrivSeg *pseg) const
|
||||||
|
@ -1038,3 +1070,92 @@ void FNodeBuilder::PrintSet (int l, DWORD set)
|
||||||
}
|
}
|
||||||
Printf (PRINT_LOG, "*\n");
|
Printf (PRINT_LOG, "*\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef BACKPATCH
|
||||||
|
#ifdef _WIN32
|
||||||
|
extern "C" {
|
||||||
|
__declspec(dllimport) int __stdcall VirtualProtect(void *, unsigned long, unsigned long, unsigned long *);
|
||||||
|
}
|
||||||
|
#define PAGE_EXECUTE_READWRITE 64
|
||||||
|
#else
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
extern "C" int ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2])
|
||||||
|
#else
|
||||||
|
static int *CallerOffset;
|
||||||
|
int ClassifyLineBackpatchC (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2])
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
// Select the routine based on SSE2 availability and patch the caller so that
|
||||||
|
// they call that routine directly next time instead of going through here.
|
||||||
|
int *calleroffset;
|
||||||
|
int diff;
|
||||||
|
int (*func)(node_t &, const FSimpleVert *, const FSimpleVert *, int[2]);
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
calleroffset = (int *)__builtin_return_address(0);
|
||||||
|
#else
|
||||||
|
calleroffset = CallerOffset;
|
||||||
|
#endif
|
||||||
|
// printf ("Patching for SSE %d @ %p %d\n", SSELevel, calleroffset, *calleroffset);
|
||||||
|
|
||||||
|
if (CPU.bSSE2)
|
||||||
|
{
|
||||||
|
func = ClassifyLineSSE2;
|
||||||
|
diff = (char *)ClassifyLineSSE2 - (char *)calleroffset;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
func = ClassifyLine2;
|
||||||
|
diff = (char *)ClassifyLine2 - (char *)calleroffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
calleroffset--;
|
||||||
|
// Patch the caller.
|
||||||
|
#ifdef _WIN32
|
||||||
|
unsigned long oldprotect;
|
||||||
|
if (VirtualProtect (calleroffset, 4, PAGE_EXECUTE_READWRITE, &oldprotect))
|
||||||
|
#else
|
||||||
|
// must make this page-aligned for mprotect
|
||||||
|
long pagesize = sysconf(_SC_PAGESIZE);
|
||||||
|
char *callerpage = (char *)((intptr_t)calleroffset & ~(pagesize - 1));
|
||||||
|
size_t protectlen = (intptr_t)calleroffset + sizeof(void*) - (intptr_t)callerpage;
|
||||||
|
int ptect;
|
||||||
|
if (!(ptect = mprotect(callerpage, protectlen, PROT_READ|PROT_WRITE|PROT_EXEC)))
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
*calleroffset = diff;
|
||||||
|
#ifdef _WIN32
|
||||||
|
VirtualProtect (calleroffset, sizeof(void*), oldprotect, &oldprotect);
|
||||||
|
#else
|
||||||
|
mprotect(callerpage, protectlen, PROT_READ|PROT_EXEC);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// And return by calling the real function.
|
||||||
|
return func (node, v1, v2, sidev);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef __GNUC__
|
||||||
|
// The ClassifyLineBackpatch() function here is a stub that uses inline assembly and nakedness
|
||||||
|
// to retrieve the return address of the stack before sending control to the real
|
||||||
|
// ClassifyLineBackpatchC() function. Since BACKPATCH shouldn't be defined on 64-bit builds,
|
||||||
|
// we're okay that VC++ can't do inline assembly on that target.
|
||||||
|
|
||||||
|
extern "C" __declspec(noinline) __declspec(naked) int ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2])
|
||||||
|
{
|
||||||
|
// We store the return address in a global, so as not to need to mess with the parameter list.
|
||||||
|
__asm
|
||||||
|
{
|
||||||
|
mov eax, [esp]
|
||||||
|
mov CallerOffset, eax
|
||||||
|
jmp ClassifyLineBackpatchC
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
115
src/nodebuild.h
115
src/nodebuild.h
|
@ -1,6 +1,10 @@
|
||||||
#include "doomdata.h"
|
#include "doomdata.h"
|
||||||
#include "tarray.h"
|
#include "tarray.h"
|
||||||
#include "r_defs.h"
|
#include "r_defs.h"
|
||||||
|
#include "x86.h"
|
||||||
|
|
||||||
|
struct FPolySeg;
|
||||||
|
struct FMiniBSP;
|
||||||
|
|
||||||
struct FEventInfo
|
struct FEventInfo
|
||||||
{
|
{
|
||||||
|
@ -40,6 +44,27 @@ private:
|
||||||
FEvent *Predecessor (FEvent *event) const;
|
FEvent *Predecessor (FEvent *event) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FSimpleVert
|
||||||
|
{
|
||||||
|
fixed_t x, y;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
int ClassifyLine2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]);
|
||||||
|
#ifndef DISABLE_SSE
|
||||||
|
int ClassifyLineSSE1 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]);
|
||||||
|
int ClassifyLineSSE2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]);
|
||||||
|
#ifdef BACKPATCH
|
||||||
|
#ifdef __GNUC__
|
||||||
|
int ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]) __attribute__((noinline));
|
||||||
|
#else
|
||||||
|
int __declspec(noinline) ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
class FNodeBuilder
|
class FNodeBuilder
|
||||||
{
|
{
|
||||||
struct FPrivSeg
|
struct FPrivSeg
|
||||||
|
@ -60,9 +85,8 @@ class FNodeBuilder
|
||||||
bool planefront;
|
bool planefront;
|
||||||
FPrivSeg *hashnext;
|
FPrivSeg *hashnext;
|
||||||
};
|
};
|
||||||
struct FPrivVert
|
struct FPrivVert : FSimpleVert
|
||||||
{
|
{
|
||||||
fixed_t x, y;
|
|
||||||
DWORD segs; // segs that use this vertex as v1
|
DWORD segs; // segs that use this vertex as v1
|
||||||
DWORD segs2; // segs that use this vertex as v2
|
DWORD segs2; // segs that use this vertex as v2
|
||||||
|
|
||||||
|
@ -88,7 +112,17 @@ class FNodeBuilder
|
||||||
};
|
};
|
||||||
|
|
||||||
// Like a blockmap, but for vertices instead of lines
|
// Like a blockmap, but for vertices instead of lines
|
||||||
class FVertexMap
|
class IVertexMap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~IVertexMap();
|
||||||
|
virtual int SelectVertexExact(FPrivVert &vert) = 0;
|
||||||
|
virtual int SelectVertexClose(FPrivVert &vert) = 0;
|
||||||
|
private:
|
||||||
|
IVertexMap &operator=(const IVertexMap &);
|
||||||
|
};
|
||||||
|
|
||||||
|
class FVertexMap : public IVertexMap
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FVertexMap (FNodeBuilder &builder, fixed_t minx, fixed_t miny, fixed_t maxx, fixed_t maxy);
|
FVertexMap (FNodeBuilder &builder, fixed_t minx, fixed_t miny, fixed_t maxx, fixed_t maxy);
|
||||||
|
@ -116,12 +150,23 @@ class FNodeBuilder
|
||||||
assert (y <= MaxY);
|
assert (y <= MaxY);
|
||||||
return (unsigned(x - MinX) >> BLOCK_SHIFT) + (unsigned(y - MinY) >> BLOCK_SHIFT) * BlocksWide;
|
return (unsigned(x - MinX) >> BLOCK_SHIFT) + (unsigned(y - MinY) >> BLOCK_SHIFT) * BlocksWide;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
FVertexMap &operator= (const FVertexMap &) { return *this; }
|
class FVertexMapSimple : public IVertexMap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FVertexMapSimple(FNodeBuilder &builder);
|
||||||
|
|
||||||
|
int SelectVertexExact(FPrivVert &vert);
|
||||||
|
int SelectVertexClose(FPrivVert &vert);
|
||||||
|
private:
|
||||||
|
int InsertVertex(FPrivVert &vert);
|
||||||
|
|
||||||
|
FNodeBuilder &MyBuilder;
|
||||||
};
|
};
|
||||||
|
|
||||||
friend class FVertexMap;
|
friend class FVertexMap;
|
||||||
|
friend class FVertexMapSimple;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct FLevel
|
struct FLevel
|
||||||
|
@ -132,7 +177,14 @@ public:
|
||||||
|
|
||||||
fixed_t MinX, MinY, MaxX, MaxY;
|
fixed_t MinX, MinY, MaxX, MaxY;
|
||||||
|
|
||||||
void FindMapBounds ();
|
void FindMapBounds();
|
||||||
|
void ResetMapBounds()
|
||||||
|
{
|
||||||
|
MinX = FIXED_MAX;
|
||||||
|
MinY = FIXED_MAX;
|
||||||
|
MaxX = FIXED_MIN;
|
||||||
|
MaxY = FIXED_MIN;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FPolyStart
|
struct FPolyStart
|
||||||
|
@ -141,9 +193,10 @@ public:
|
||||||
fixed_t x, y;
|
fixed_t x, y;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
FNodeBuilder (FLevel &level);
|
||||||
FNodeBuilder (FLevel &level,
|
FNodeBuilder (FLevel &level,
|
||||||
TArray<FPolyStart> &polyspots, TArray<FPolyStart> &anchors,
|
TArray<FPolyStart> &polyspots, TArray<FPolyStart> &anchors,
|
||||||
bool makeGLNodes, bool enableSSE2);
|
bool makeGLNodes);
|
||||||
~FNodeBuilder ();
|
~FNodeBuilder ();
|
||||||
|
|
||||||
void Extract (node_t *&nodes, int &nodeCount,
|
void Extract (node_t *&nodes, int &nodeCount,
|
||||||
|
@ -151,6 +204,13 @@ public:
|
||||||
subsector_t *&ssecs, int &subCount,
|
subsector_t *&ssecs, int &subCount,
|
||||||
vertex_t *&verts, int &vertCount);
|
vertex_t *&verts, int &vertCount);
|
||||||
|
|
||||||
|
// These are used for building sub-BSP trees for polyobjects.
|
||||||
|
void Clear();
|
||||||
|
void AddPolySegs(FPolySeg *segs, int numsegs);
|
||||||
|
void AddSegs(seg_t *segs, int numsegs);
|
||||||
|
void BuildMini(bool makeGLNodes);
|
||||||
|
void ExtractMini(FMiniBSP *bsp);
|
||||||
|
|
||||||
static angle_t PointToAngle (fixed_t dx, fixed_t dy);
|
static angle_t PointToAngle (fixed_t dx, fixed_t dy);
|
||||||
|
|
||||||
// < 0 : in front of line
|
// < 0 : in front of line
|
||||||
|
@ -160,7 +220,7 @@ public:
|
||||||
static inline int PointOnSide (int x, int y, int x1, int y1, int dx, int dy);
|
static inline int PointOnSide (int x, int y, int x1, int y1, int dx, int dy);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FVertexMap *VertexMap;
|
IVertexMap *VertexMap;
|
||||||
|
|
||||||
TArray<node_t> Nodes;
|
TArray<node_t> Nodes;
|
||||||
TArray<subsector_t> Subsectors;
|
TArray<subsector_t> Subsectors;
|
||||||
|
@ -181,7 +241,6 @@ private:
|
||||||
DWORD HackMate; // Seg to use in front of hack seg
|
DWORD HackMate; // Seg to use in front of hack seg
|
||||||
FLevel &Level;
|
FLevel &Level;
|
||||||
bool GLNodes; // Add minisegs to make GL nodes?
|
bool GLNodes; // Add minisegs to make GL nodes?
|
||||||
bool EnableSSE2;
|
|
||||||
|
|
||||||
// Progress meter stuff
|
// Progress meter stuff
|
||||||
int SegsStuffed;
|
int SegsStuffed;
|
||||||
|
@ -191,29 +250,27 @@ private:
|
||||||
void MakeSegsFromSides ();
|
void MakeSegsFromSides ();
|
||||||
int CreateSeg (int linenum, int sidenum);
|
int CreateSeg (int linenum, int sidenum);
|
||||||
void GroupSegPlanes ();
|
void GroupSegPlanes ();
|
||||||
|
void GroupSegPlanesSimple ();
|
||||||
void FindPolyContainers (TArray<FPolyStart> &spots, TArray<FPolyStart> &anchors);
|
void FindPolyContainers (TArray<FPolyStart> &spots, TArray<FPolyStart> &anchors);
|
||||||
bool GetPolyExtents (int polynum, fixed_t bbox[4]);
|
bool GetPolyExtents (int polynum, fixed_t bbox[4]);
|
||||||
int MarkLoop (DWORD firstseg, int loopnum);
|
int MarkLoop (DWORD firstseg, int loopnum);
|
||||||
void AddSegToBBox (fixed_t bbox[4], const FPrivSeg *seg);
|
void AddSegToBBox (fixed_t bbox[4], const FPrivSeg *seg);
|
||||||
int CreateNode (DWORD set, fixed_t bbox[4]);
|
int CreateNode (DWORD set, unsigned int count, fixed_t bbox[4]);
|
||||||
int CreateSubsector (DWORD set, fixed_t bbox[4]);
|
int CreateSubsector (DWORD set, fixed_t bbox[4]);
|
||||||
void CreateSubsectorsForReal ();
|
void CreateSubsectorsForReal ();
|
||||||
bool CheckSubsector (DWORD set, node_t &node, DWORD &splitseg, int setsize);
|
bool CheckSubsector (DWORD set, node_t &node, DWORD &splitseg);
|
||||||
bool CheckSubsectorOverlappingSegs (DWORD set, node_t &node, DWORD &splitseg);
|
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);
|
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);
|
void SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &outset0, DWORD &outset1, unsigned int &count0, unsigned int &count1);
|
||||||
DWORD SplitSeg (DWORD segnum, int splitvert, int v1InFront);
|
DWORD SplitSeg (DWORD segnum, int splitvert, int v1InFront);
|
||||||
int Heuristic (node_t &node, DWORD set, bool honorNoSplit);
|
int Heuristic (node_t &node, DWORD set, bool honorNoSplit);
|
||||||
int CountSegs (DWORD set) const;
|
|
||||||
|
|
||||||
// Returns:
|
// Returns:
|
||||||
// 0 = seg is in front
|
// 0 = seg is in front
|
||||||
// 1 = seg is in back
|
// 1 = seg is in back
|
||||||
// -1 = seg cuts the node
|
// -1 = seg cuts the node
|
||||||
|
|
||||||
inline int ClassifyLine (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2);
|
inline int ClassifyLine (node_t &node, const FPrivVert *v1, const FPrivVert *v2, int sidev[2]);
|
||||||
int ClassifyLine2 (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2);
|
|
||||||
int ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2);
|
|
||||||
|
|
||||||
void FixSplitSharers (const node_t &node);
|
void FixSplitSharers (const node_t &node);
|
||||||
double AddIntersection (const node_t &node, int vertex);
|
double AddIntersection (const node_t &node, int vertex);
|
||||||
|
@ -273,21 +330,27 @@ inline int FNodeBuilder::PointOnSide (int x, int y, int x1, int y1, int dx, int
|
||||||
return s_num > 0.0 ? -1 : 1;
|
return s_num > 0.0 ? -1 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int FNodeBuilder::ClassifyLine (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2)
|
inline int FNodeBuilder::ClassifyLine (node_t &node, const FPrivVert *v1, const FPrivVert *v2, int sidev[2])
|
||||||
{
|
{
|
||||||
#if !defined(_M_IX86) && !defined(_M_X64) && !defined(__i386__) && !defined(__amd64__)
|
#ifdef DISABLE_SSE
|
||||||
return ClassifyLine2 (node, seg, sidev1, sidev2);
|
return ClassifyLine2 (node, v1, v2, sidev);
|
||||||
#elif defined(__SSE2__)
|
#else
|
||||||
|
#if defined(__SSE2__) || defined(_M_IX64)
|
||||||
// If compiling with SSE2 support everywhere, just use the SSE2 version.
|
// If compiling with SSE2 support everywhere, just use the SSE2 version.
|
||||||
return ClassifyLineSSE2 (node, seg, sidev1, sidev2);
|
return ClassifyLineSSE2 (node, v1, v2, sidev);
|
||||||
#elif defined(_MSC_VER) && _MSC_VER < 1300
|
#elif defined(_MSC_VER) && _MSC_VER < 1300
|
||||||
// VC 6 does not support SSE2 optimizations.
|
// VC 6 does not support SSE optimizations.
|
||||||
return ClassifyLine2 (node, seg, sidev1, sidev2);
|
return ClassifyLine2 (node, v1, v2, sidev);
|
||||||
#else
|
#else
|
||||||
// Select the routine based on our flag.
|
// Select the routine based on our flag.
|
||||||
if (EnableSSE2)
|
#ifdef BACKPATCH
|
||||||
return ClassifyLineSSE2 (node, seg, sidev1, sidev2);
|
return ClassifyLineBackpatch (node, v1, v2, sidev);
|
||||||
|
#else
|
||||||
|
if (CPU.bSSE2)
|
||||||
|
return ClassifyLineSSE2 (node, v1, v2, sidev);
|
||||||
else
|
else
|
||||||
return ClassifyLine2 (node, seg, sidev1, sidev2);
|
return ClassifyLine2 (node, v1, v2, sidev);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,8 @@
|
||||||
|
|
||||||
#define FAR_ENOUGH 17179869184.f // 4<<32
|
#define FAR_ENOUGH 17179869184.f // 4<<32
|
||||||
|
|
||||||
int FNodeBuilder::ClassifyLine2 (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2)
|
extern "C" int ClassifyLine2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2])
|
||||||
{
|
{
|
||||||
const FPrivVert *v1 = &Vertices[seg->v1];
|
|
||||||
const FPrivVert *v2 = &Vertices[seg->v2];
|
|
||||||
|
|
||||||
double d_x1 = double(node.x);
|
double d_x1 = double(node.x);
|
||||||
double d_y1 = double(node.y);
|
double d_y1 = double(node.y);
|
||||||
double d_dx = double(node.dx);
|
double d_dx = double(node.dx);
|
||||||
|
@ -26,13 +23,13 @@ int FNodeBuilder::ClassifyLine2 (node_t &node, const FPrivSeg *seg, int &sidev1,
|
||||||
{
|
{
|
||||||
if (s_num2 <= -FAR_ENOUGH)
|
if (s_num2 <= -FAR_ENOUGH)
|
||||||
{
|
{
|
||||||
sidev1 = sidev2 = 1;
|
sidev[0] = sidev[1] = 1;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (s_num2 >= FAR_ENOUGH)
|
if (s_num2 >= FAR_ENOUGH)
|
||||||
{
|
{
|
||||||
sidev1 = 1;
|
sidev[0] = 1;
|
||||||
sidev2 = -1;
|
sidev[1] = -1;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
nears = 1;
|
nears = 1;
|
||||||
|
@ -41,13 +38,13 @@ int FNodeBuilder::ClassifyLine2 (node_t &node, const FPrivSeg *seg, int &sidev1,
|
||||||
{
|
{
|
||||||
if (s_num2 >= FAR_ENOUGH)
|
if (s_num2 >= FAR_ENOUGH)
|
||||||
{
|
{
|
||||||
sidev1 = sidev2 = -1;
|
sidev[0] = sidev[1] = -1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (s_num2 <= -FAR_ENOUGH)
|
if (s_num2 <= -FAR_ENOUGH)
|
||||||
{
|
{
|
||||||
sidev1 = -1;
|
sidev[0] = -1;
|
||||||
sidev2 = 1;
|
sidev[1] = 1;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
nears = 1;
|
nears = 1;
|
||||||
|
@ -65,41 +62,41 @@ int FNodeBuilder::ClassifyLine2 (node_t &node, const FPrivSeg *seg, int &sidev1,
|
||||||
double dist = s_num1 * s_num1 * l;
|
double dist = s_num1 * s_num1 * l;
|
||||||
if (dist < SIDE_EPSILON*SIDE_EPSILON)
|
if (dist < SIDE_EPSILON*SIDE_EPSILON)
|
||||||
{
|
{
|
||||||
sidev1 = 0;
|
sidev[0] = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sidev1 = s_num1 > 0.0 ? -1 : 1;
|
sidev[0] = s_num1 > 0.0 ? -1 : 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sidev1 = s_num1 > 0.0 ? -1 : 1;
|
sidev[0] = s_num1 > 0.0 ? -1 : 1;
|
||||||
}
|
}
|
||||||
if (nears & 1)
|
if (nears & 1)
|
||||||
{
|
{
|
||||||
double dist = s_num2 * s_num2 * l;
|
double dist = s_num2 * s_num2 * l;
|
||||||
if (dist < SIDE_EPSILON*SIDE_EPSILON)
|
if (dist < SIDE_EPSILON*SIDE_EPSILON)
|
||||||
{
|
{
|
||||||
sidev2 = 0;
|
sidev[1] = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sidev2 = s_num2 > 0.0 ? -1 : 1;
|
sidev[1] = s_num2 > 0.0 ? -1 : 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sidev2 = s_num2 > 0.0 ? -1 : 1;
|
sidev[1] = s_num2 > 0.0 ? -1 : 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sidev1 = s_num1 > 0.0 ? -1 : 1;
|
sidev[0] = s_num1 > 0.0 ? -1 : 1;
|
||||||
sidev2 = s_num2 > 0.0 ? -1 : 1;
|
sidev[1] = s_num2 > 0.0 ? -1 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((sidev1 | sidev2) == 0)
|
if ((sidev[0] | sidev[1]) == 0)
|
||||||
{ // seg is coplanar with the splitter, so use its orientation to determine
|
{ // seg is coplanar with the splitter, so use its orientation to determine
|
||||||
// which child it ends up in. If it faces the same direction as the splitter,
|
// which child it ends up in. If it faces the same direction as the splitter,
|
||||||
// it goes in front. Otherwise, it goes in back.
|
// it goes in front. Otherwise, it goes in back.
|
||||||
|
@ -127,11 +124,11 @@ int FNodeBuilder::ClassifyLine2 (node_t &node, const FPrivSeg *seg, int &sidev1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (sidev1 <= 0 && sidev2 <= 0)
|
else if (sidev[0] <= 0 && sidev[1] <= 0)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else if (sidev1 >= 0 && sidev2 >= 0)
|
else if (sidev[0] >= 0 && sidev[1] >= 0)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
|
#ifndef DISABLE_SSE
|
||||||
|
|
||||||
#include "doomtype.h"
|
#include "doomtype.h"
|
||||||
#include "nodebuild.h"
|
#include "nodebuild.h"
|
||||||
|
|
||||||
#define FAR_ENOUGH 17179869184.f // 4<<32
|
#define FAR_ENOUGH 17179869184.f // 4<<32
|
||||||
|
|
||||||
// This function is identical to the ClassifyLine2 version. So how does it use SSE2?
|
// You may notice that this function is identical to ClassifyLine2.
|
||||||
// Easy! By explicitly enabling SSE2 in the configuration properties for this one
|
// The reason it is SSE2 is because this file is explicitly compiled
|
||||||
// file, we can build it with SSE2 enabled without forcing SSE2 on the rest of the
|
// with SSE2 math enabled, but the other files are not.
|
||||||
// project.
|
|
||||||
|
|
||||||
int FNodeBuilder::ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2)
|
extern "C" int ClassifyLineSSE2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2])
|
||||||
{
|
{
|
||||||
const FPrivVert *v1 = &Vertices[seg->v1];
|
|
||||||
const FPrivVert *v2 = &Vertices[seg->v2];
|
|
||||||
|
|
||||||
double d_x1 = double(node.x);
|
double d_x1 = double(node.x);
|
||||||
double d_y1 = double(node.y);
|
double d_y1 = double(node.y);
|
||||||
double d_dx = double(node.dx);
|
double d_dx = double(node.dx);
|
||||||
|
@ -31,13 +29,13 @@ int FNodeBuilder::ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &side
|
||||||
{
|
{
|
||||||
if (s_num2 <= -FAR_ENOUGH)
|
if (s_num2 <= -FAR_ENOUGH)
|
||||||
{
|
{
|
||||||
sidev1 = sidev2 = 1;
|
sidev[0] = sidev[1] = 1;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (s_num2 >= FAR_ENOUGH)
|
if (s_num2 >= FAR_ENOUGH)
|
||||||
{
|
{
|
||||||
sidev1 = 1;
|
sidev[0] = 1;
|
||||||
sidev2 = -1;
|
sidev[1] = -1;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
nears = 1;
|
nears = 1;
|
||||||
|
@ -46,13 +44,13 @@ int FNodeBuilder::ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &side
|
||||||
{
|
{
|
||||||
if (s_num2 >= FAR_ENOUGH)
|
if (s_num2 >= FAR_ENOUGH)
|
||||||
{
|
{
|
||||||
sidev1 = sidev2 = -1;
|
sidev[0] = sidev[1] = -1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (s_num2 <= -FAR_ENOUGH)
|
if (s_num2 <= -FAR_ENOUGH)
|
||||||
{
|
{
|
||||||
sidev1 = -1;
|
sidev[0] = -1;
|
||||||
sidev2 = 1;
|
sidev[1] = 1;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
nears = 1;
|
nears = 1;
|
||||||
|
@ -70,41 +68,41 @@ int FNodeBuilder::ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &side
|
||||||
double dist = s_num1 * s_num1 * l;
|
double dist = s_num1 * s_num1 * l;
|
||||||
if (dist < SIDE_EPSILON*SIDE_EPSILON)
|
if (dist < SIDE_EPSILON*SIDE_EPSILON)
|
||||||
{
|
{
|
||||||
sidev1 = 0;
|
sidev[0] = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sidev1 = s_num1 > 0.0 ? -1 : 1;
|
sidev[0] = s_num1 > 0.0 ? -1 : 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sidev1 = s_num1 > 0.0 ? -1 : 1;
|
sidev[0] = s_num1 > 0.0 ? -1 : 1;
|
||||||
}
|
}
|
||||||
if (nears & 1)
|
if (nears & 1)
|
||||||
{
|
{
|
||||||
double dist = s_num2 * s_num2 * l;
|
double dist = s_num2 * s_num2 * l;
|
||||||
if (dist < SIDE_EPSILON*SIDE_EPSILON)
|
if (dist < SIDE_EPSILON*SIDE_EPSILON)
|
||||||
{
|
{
|
||||||
sidev2 = 0;
|
sidev[1] = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sidev2 = s_num2 > 0.0 ? -1 : 1;
|
sidev[1] = s_num2 > 0.0 ? -1 : 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sidev2 = s_num2 > 0.0 ? -1 : 1;
|
sidev[1] = s_num2 > 0.0 ? -1 : 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sidev1 = s_num1 > 0.0 ? -1 : 1;
|
sidev[0] = s_num1 > 0.0 ? -1 : 1;
|
||||||
sidev2 = s_num2 > 0.0 ? -1 : 1;
|
sidev[1] = s_num2 > 0.0 ? -1 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((sidev1 | sidev2) == 0)
|
if ((sidev[0] | sidev[1]) == 0)
|
||||||
{ // seg is coplanar with the splitter, so use its orientation to determine
|
{ // seg is coplanar with the splitter, so use its orientation to determine
|
||||||
// which child it ends up in. If it faces the same direction as the splitter,
|
// which child it ends up in. If it faces the same direction as the splitter,
|
||||||
// it goes in front. Otherwise, it goes in back.
|
// it goes in front. Otherwise, it goes in back.
|
||||||
|
@ -132,13 +130,15 @@ int FNodeBuilder::ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &side
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (sidev1 <= 0 && sidev2 <= 0)
|
else if (sidev[0] <= 0 && sidev[1] <= 0)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else if (sidev1 >= 0 && sidev2 >= 0)
|
else if (sidev[0] >= 0 && sidev[1] >= 0)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -105,7 +105,7 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount,
|
||||||
{
|
{
|
||||||
DWORD numsegs = CloseSubsector (segs, i, outVerts);
|
DWORD numsegs = CloseSubsector (segs, i, outVerts);
|
||||||
outSubs[i].numlines = numsegs;
|
outSubs[i].numlines = numsegs;
|
||||||
outSubs[i].firstline = segs.Size() - numsegs;
|
outSubs[i].firstline = (seg_t *)(size_t)(segs.Size() - numsegs);
|
||||||
}
|
}
|
||||||
|
|
||||||
segCount = segs.Size ();
|
segCount = segs.Size ();
|
||||||
|
@ -142,6 +142,10 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount,
|
||||||
out->bPolySeg = false;
|
out->bPolySeg = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (i = 0; i < subCount; ++i)
|
||||||
|
{
|
||||||
|
outSubs[i].firstline = &outSegs[(size_t)outSubs[i].firstline];
|
||||||
|
}
|
||||||
|
|
||||||
D(Printf("%i segs, %i nodes, %i subsectors\n", segCount, nodeCount, subCount));
|
D(Printf("%i segs, %i nodes, %i subsectors\n", segCount, nodeCount, subCount));
|
||||||
|
|
||||||
|
@ -152,6 +156,86 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FNodeBuilder::ExtractMini (FMiniBSP *bsp)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
bsp->Verts.Resize(Vertices.Size());
|
||||||
|
for (i = 0; i < Vertices.Size(); ++i)
|
||||||
|
{
|
||||||
|
bsp->Verts[i].x = Vertices[i].x;
|
||||||
|
bsp->Verts[i].y = Vertices[i].y;
|
||||||
|
}
|
||||||
|
|
||||||
|
bsp->Subsectors.Resize(Subsectors.Size());
|
||||||
|
memset(&bsp->Subsectors[0], 0, Subsectors.Size() * sizeof(subsector_t));
|
||||||
|
|
||||||
|
bsp->Nodes.Resize(Nodes.Size());
|
||||||
|
memcpy(&bsp->Nodes[0], &Nodes[0], Nodes.Size()*sizeof(node_t));
|
||||||
|
for (i = 0; i < Nodes.Size(); ++i)
|
||||||
|
{
|
||||||
|
D(Printf(PRINT_LOG, "Node %d:\n", i));
|
||||||
|
// Go backwards because on 64-bit systems, both of the intchildren are
|
||||||
|
// inside the first in-game child.
|
||||||
|
for (int j = 1; j >= 0; --j)
|
||||||
|
{
|
||||||
|
if (bsp->Nodes[i].intchildren[j] & 0x80000000)
|
||||||
|
{
|
||||||
|
D(Printf(PRINT_LOG, " subsector %d\n", bsp->Nodes[i].intchildren[j] & 0x7FFFFFFF));
|
||||||
|
bsp->Nodes[i].children[j] = (BYTE *)&bsp->Subsectors[bsp->Nodes[i].intchildren[j] & 0x7fffffff] + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
D(Printf(PRINT_LOG, " node %d\n", bsp->Nodes[i].intchildren[j]));
|
||||||
|
bsp->Nodes[i].children[j] = &bsp->Nodes[bsp->Nodes[i].intchildren[j]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GLNodes)
|
||||||
|
{
|
||||||
|
for (i = 0; i < Subsectors.Size(); ++i)
|
||||||
|
{
|
||||||
|
DWORD numsegs = CloseSubsector (bsp->Segs, i, &bsp->Verts[0]);
|
||||||
|
bsp->Subsectors[i].numlines = numsegs;
|
||||||
|
bsp->Subsectors[i].firstline = &bsp->Segs[bsp->Segs.Size() - numsegs];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < Segs.Size(); ++i)
|
||||||
|
{
|
||||||
|
if (bsp->Segs[i].PartnerSeg != NULL)
|
||||||
|
{
|
||||||
|
bsp->Segs[i].PartnerSeg = &bsp->Segs[Segs[(unsigned int)(size_t)bsp->Segs[i].PartnerSeg-1].storedseg];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(&bsp->Subsectors[0], &Subsectors[0], Subsectors.Size()*sizeof(subsector_t));
|
||||||
|
bsp->Segs.Resize(Segs.Size());
|
||||||
|
for (i = 0; i < Segs.Size(); ++i)
|
||||||
|
{
|
||||||
|
const FPrivSeg *org = &Segs[SegList[i].SegNum];
|
||||||
|
seg_t *out = &bsp->Segs[i];
|
||||||
|
|
||||||
|
D(Printf(PRINT_LOG, "Seg %d: v1(%d) -> v2(%d)\n", i, org->v1, org->v2));
|
||||||
|
|
||||||
|
out->v1 = &bsp->Verts[org->v1];
|
||||||
|
out->v2 = &bsp->Verts[org->v2];
|
||||||
|
out->backsector = org->backsector;
|
||||||
|
out->frontsector = org->frontsector;
|
||||||
|
out->linedef = Level.Lines + org->linedef;
|
||||||
|
out->sidedef = Level.Sides + org->sidedef;
|
||||||
|
out->PartnerSeg = NULL;
|
||||||
|
out->bPolySeg = false;
|
||||||
|
}
|
||||||
|
for (i = 0; i < bsp->Subsectors.Size(); ++i)
|
||||||
|
{
|
||||||
|
bsp->Subsectors[i].firstline = &bsp->Segs[(size_t)bsp->Subsectors[i].firstline];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int FNodeBuilder::CloseSubsector (TArray<seg_t> &segs, int subsector, vertex_t *outVerts)
|
int FNodeBuilder::CloseSubsector (TArray<seg_t> &segs, int subsector, vertex_t *outVerts)
|
||||||
{
|
{
|
||||||
FPrivSeg *seg, *prev;
|
FPrivSeg *seg, *prev;
|
||||||
|
@ -163,7 +247,7 @@ int FNodeBuilder::CloseSubsector (TArray<seg_t> &segs, int subsector, vertex_t *
|
||||||
bool diffplanes;
|
bool diffplanes;
|
||||||
int firstplane;
|
int firstplane;
|
||||||
|
|
||||||
first = Subsectors[subsector].firstline;
|
first = (DWORD)(size_t)Subsectors[subsector].firstline;
|
||||||
max = first + Subsectors[subsector].numlines;
|
max = first + Subsectors[subsector].numlines;
|
||||||
count = 0;
|
count = 0;
|
||||||
|
|
||||||
|
@ -322,7 +406,7 @@ int FNodeBuilder::OutputDegenerateSubsector (TArray<seg_t> &segs, int subsector,
|
||||||
double dot, x1, y1, dx, dy, dx2, dy2;
|
double dot, x1, y1, dx, dy, dx2, dy2;
|
||||||
bool wantside;
|
bool wantside;
|
||||||
|
|
||||||
first = Subsectors[subsector].firstline;
|
first = (DWORD)(size_t)Subsectors[subsector].firstline;
|
||||||
max = first + Subsectors[subsector].numlines;
|
max = first + Subsectors[subsector].numlines;
|
||||||
count = 0;
|
count = 0;
|
||||||
|
|
||||||
|
@ -401,7 +485,6 @@ DWORD FNodeBuilder::PushGLSeg (TArray<seg_t> &segs, const FPrivSeg *seg, vertex_
|
||||||
}
|
}
|
||||||
newseg.PartnerSeg = (seg_t *)(seg->partner == DWORD_MAX ? 0 : (size_t)seg->partner + 1);
|
newseg.PartnerSeg = (seg_t *)(seg->partner == DWORD_MAX ? 0 : (size_t)seg->partner + 1);
|
||||||
newseg.bPolySeg = false;
|
newseg.bPolySeg = false;
|
||||||
newseg.Subsector = NULL;
|
|
||||||
return (DWORD)segs.Push (newseg);
|
return (DWORD)segs.Push (newseg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,6 +500,5 @@ void FNodeBuilder::PushConnectingGLSeg (int subsector, TArray<seg_t> &segs, vert
|
||||||
newseg.sidedef = NULL;
|
newseg.sidedef = NULL;
|
||||||
newseg.PartnerSeg = NULL;
|
newseg.PartnerSeg = NULL;
|
||||||
newseg.bPolySeg = false;
|
newseg.bPolySeg = false;
|
||||||
newseg.Subsector = NULL;
|
|
||||||
segs.Push (newseg);
|
segs.Push (newseg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
#include "m_bbox.h"
|
#include "m_bbox.h"
|
||||||
#include "r_main.h"
|
#include "r_main.h"
|
||||||
#include "i_system.h"
|
#include "i_system.h"
|
||||||
|
#include "po_man.h"
|
||||||
|
|
||||||
static const int PO_LINE_START = 1;
|
static const int PO_LINE_START = 1;
|
||||||
static const int PO_LINE_EXPLICIT = 5;
|
static const int PO_LINE_EXPLICIT = 5;
|
||||||
|
@ -177,6 +178,86 @@ int FNodeBuilder::CreateSeg (int linenum, int sidenum)
|
||||||
return segnum;
|
return segnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For every seg, create FPrivSegs and FPrivVerts.
|
||||||
|
|
||||||
|
void FNodeBuilder::AddSegs(seg_t *segs, int numsegs)
|
||||||
|
{
|
||||||
|
assert(numsegs > 0);
|
||||||
|
|
||||||
|
for (int i = 0; i < numsegs; ++i)
|
||||||
|
{
|
||||||
|
FPrivSeg seg;
|
||||||
|
FPrivVert vert;
|
||||||
|
int segnum;
|
||||||
|
|
||||||
|
seg.next = DWORD_MAX;
|
||||||
|
seg.loopnum = 0;
|
||||||
|
seg.partner = DWORD_MAX;
|
||||||
|
seg.hashnext = NULL;
|
||||||
|
seg.planefront = false;
|
||||||
|
seg.planenum = DWORD_MAX;
|
||||||
|
seg.storedseg = DWORD_MAX;
|
||||||
|
|
||||||
|
seg.frontsector = segs[i].frontsector;
|
||||||
|
seg.backsector = segs[i].backsector;
|
||||||
|
vert.x = segs[i].v1->x;
|
||||||
|
vert.y = segs[i].v1->y;
|
||||||
|
seg.v1 = VertexMap->SelectVertexExact(vert);
|
||||||
|
vert.x = segs[i].v2->x;
|
||||||
|
vert.y = segs[i].v2->y;
|
||||||
|
seg.v2 = VertexMap->SelectVertexExact(vert);
|
||||||
|
seg.linedef = int(segs[i].linedef - Level.Lines);
|
||||||
|
seg.sidedef = segs[i].sidedef != NULL ? int(segs[i].sidedef - Level.Sides) : int(NO_SIDE);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FNodeBuilder::AddPolySegs(FPolySeg *segs, int numsegs)
|
||||||
|
{
|
||||||
|
assert(numsegs > 0);
|
||||||
|
|
||||||
|
for (int i = 0; i < numsegs; ++i)
|
||||||
|
{
|
||||||
|
FPrivSeg seg;
|
||||||
|
FPrivVert vert;
|
||||||
|
int segnum;
|
||||||
|
|
||||||
|
seg.next = DWORD_MAX;
|
||||||
|
seg.loopnum = 0;
|
||||||
|
seg.partner = DWORD_MAX;
|
||||||
|
seg.hashnext = NULL;
|
||||||
|
seg.planefront = false;
|
||||||
|
seg.planenum = DWORD_MAX;
|
||||||
|
seg.storedseg = DWORD_MAX;
|
||||||
|
|
||||||
|
side_t *side = segs[i].wall;
|
||||||
|
assert(side != NULL);
|
||||||
|
|
||||||
|
seg.frontsector = side->sector;
|
||||||
|
seg.backsector = side->linedef->frontsector == side->sector ? side->linedef->backsector : side->linedef->frontsector;
|
||||||
|
vert.x = segs[i].v1.x;
|
||||||
|
vert.y = segs[i].v1.y;
|
||||||
|
seg.v1 = VertexMap->SelectVertexExact(vert);
|
||||||
|
vert.x = segs[i].v2.x;
|
||||||
|
vert.y = segs[i].v2.y;
|
||||||
|
seg.v2 = VertexMap->SelectVertexExact(vert);
|
||||||
|
seg.linedef = int(side->linedef - Level.Lines);
|
||||||
|
seg.sidedef = int(side - Level.Sides);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Group colinear segs together so that only one seg per line needs to be checked
|
// Group colinear segs together so that only one seg per line needs to be checked
|
||||||
// by SelectSplitter().
|
// by SelectSplitter().
|
||||||
|
|
||||||
|
@ -269,6 +350,27 @@ void FNodeBuilder::GroupSegPlanes ()
|
||||||
PlaneChecked.Reserve ((planenum + 7) / 8);
|
PlaneChecked.Reserve ((planenum + 7) / 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Just create one plane per seg. Should be good enough for mini BSPs.
|
||||||
|
void FNodeBuilder::GroupSegPlanesSimple()
|
||||||
|
{
|
||||||
|
Planes.Resize(Segs.Size());
|
||||||
|
for (int i = 0; i < (int)Segs.Size(); ++i)
|
||||||
|
{
|
||||||
|
FPrivSeg *seg = &Segs[i];
|
||||||
|
FSimpleLine *pline = &Planes[i];
|
||||||
|
seg->next = i+1;
|
||||||
|
seg->hashnext = NULL;
|
||||||
|
seg->planenum = i;
|
||||||
|
seg->planefront = true;
|
||||||
|
pline->x = Vertices[seg->v1].x;
|
||||||
|
pline->y = Vertices[seg->v1].y;
|
||||||
|
pline->dx = Vertices[seg->v2].x - Vertices[seg->v1].x;
|
||||||
|
pline->dy = Vertices[seg->v2].y - Vertices[seg->v1].y;
|
||||||
|
}
|
||||||
|
Segs.Last().next = DWORD_MAX;
|
||||||
|
PlaneChecked.Reserve((Segs.Size() + 7) / 8);
|
||||||
|
}
|
||||||
|
|
||||||
// Find "loops" of segs surrounding polyobject's origin. Note that a polyobject's origin
|
// Find "loops" of segs surrounding polyobject's origin. Note that a polyobject's origin
|
||||||
// is not solely defined by the polyobject's anchor, but also by the polyobject itself.
|
// is not solely defined by the polyobject's anchor, but also by the polyobject itself.
|
||||||
// For the split avoidance to work properly, you must have a convex, complete loop of
|
// For the split avoidance to work properly, you must have a convex, complete loop of
|
||||||
|
@ -507,6 +609,10 @@ void FNodeBuilder::FLevel::FindMapBounds ()
|
||||||
MaxY = maxy;
|
MaxY = maxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FNodeBuilder::IVertexMap::~IVertexMap()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
FNodeBuilder::FVertexMap::FVertexMap (FNodeBuilder &builder,
|
FNodeBuilder::FVertexMap::FVertexMap (FNodeBuilder &builder,
|
||||||
fixed_t minx, fixed_t miny, fixed_t maxx, fixed_t maxy)
|
fixed_t minx, fixed_t miny, fixed_t maxx, fixed_t maxy)
|
||||||
: MyBuilder(builder)
|
: MyBuilder(builder)
|
||||||
|
@ -606,3 +712,52 @@ int FNodeBuilder::FVertexMap::InsertVertex (FNodeBuilder::FPrivVert &vert)
|
||||||
|
|
||||||
return vertnum;
|
return vertnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FNodeBuilder::FVertexMapSimple::FVertexMapSimple(FNodeBuilder &builder)
|
||||||
|
: MyBuilder(builder)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int FNodeBuilder::FVertexMapSimple::SelectVertexExact(FNodeBuilder::FPrivVert &vert)
|
||||||
|
{
|
||||||
|
FPrivVert *verts = &MyBuilder.Vertices[0];
|
||||||
|
unsigned int stop = MyBuilder.Vertices.Size();
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < stop; ++i)
|
||||||
|
{
|
||||||
|
if (verts[i].x == vert.x && verts[i].y == vert.y)
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Not present: add it!
|
||||||
|
return InsertVertex(vert);
|
||||||
|
}
|
||||||
|
|
||||||
|
int FNodeBuilder::FVertexMapSimple::SelectVertexClose(FNodeBuilder::FPrivVert &vert)
|
||||||
|
{
|
||||||
|
FPrivVert *verts = &MyBuilder.Vertices[0];
|
||||||
|
unsigned int stop = MyBuilder.Vertices.Size();
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < stop; ++i)
|
||||||
|
{
|
||||||
|
#if VERTEX_EPSILON <= 1
|
||||||
|
if (verts[i].x == vert.x && verts[i].y == y)
|
||||||
|
#else
|
||||||
|
if (abs(verts[i].x - vert.x) < VERTEX_EPSILON &&
|
||||||
|
abs(verts[i].y - vert.y) < VERTEX_EPSILON)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Not present: add it!
|
||||||
|
return InsertVertex (vert);
|
||||||
|
}
|
||||||
|
|
||||||
|
int FNodeBuilder::FVertexMapSimple::InsertVertex (FNodeBuilder::FPrivVert &vert)
|
||||||
|
{
|
||||||
|
vert.segs = DWORD_MAX;
|
||||||
|
vert.segs2 = DWORD_MAX;
|
||||||
|
return (int)MyBuilder.Vertices.Push (vert);
|
||||||
|
}
|
||||||
|
|
|
@ -855,7 +855,7 @@ void P_LoadGLZSegs (FileReaderBase &data, int type)
|
||||||
}
|
}
|
||||||
data >> side;
|
data >> side;
|
||||||
|
|
||||||
seg = &segs[subsectors[i].firstline + j];
|
seg = subsectors[i].firstline + j;
|
||||||
seg->v1 = &vertexes[v1];
|
seg->v1 = &vertexes[v1];
|
||||||
if (j == 0)
|
if (j == 0)
|
||||||
{
|
{
|
||||||
|
@ -894,7 +894,7 @@ void P_LoadGLZSegs (FileReaderBase &data, int type)
|
||||||
{
|
{
|
||||||
seg->linedef = NULL;
|
seg->linedef = NULL;
|
||||||
seg->sidedef = NULL;
|
seg->sidedef = NULL;
|
||||||
seg->frontsector = seg->backsector = segs[subsectors[i].firstline].frontsector;
|
seg->frontsector = seg->backsector = subsectors[i].firstline->frontsector;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -952,7 +952,7 @@ static void LoadZNodes(FileReaderBase &data, int glnodes)
|
||||||
DWORD numsegs;
|
DWORD numsegs;
|
||||||
|
|
||||||
data >> numsegs;
|
data >> numsegs;
|
||||||
subsectors[i].firstline = currSeg;
|
subsectors[i].firstline = (seg_t *)(size_t)currSeg; // Oh damn. I should have stored the seg count sooner.
|
||||||
subsectors[i].numlines = numsegs;
|
subsectors[i].numlines = numsegs;
|
||||||
currSeg += numsegs;
|
currSeg += numsegs;
|
||||||
}
|
}
|
||||||
|
@ -976,6 +976,11 @@ static void LoadZNodes(FileReaderBase &data, int glnodes)
|
||||||
segs = new seg_t[numsegs];
|
segs = new seg_t[numsegs];
|
||||||
memset (segs, 0, numsegs*sizeof(seg_t));
|
memset (segs, 0, numsegs*sizeof(seg_t));
|
||||||
|
|
||||||
|
for (i = 0; i < numSubs; ++i)
|
||||||
|
{
|
||||||
|
subsectors[i].firstline = &segs[(size_t)subsectors[i].firstline];
|
||||||
|
}
|
||||||
|
|
||||||
if (glnodes == 0)
|
if (glnodes == 0)
|
||||||
{
|
{
|
||||||
P_LoadZSegs (data);
|
P_LoadZSegs (data);
|
||||||
|
@ -1141,6 +1146,11 @@ void P_LoadSegs (MapData * map)
|
||||||
data = new BYTE[lumplen];
|
data = new BYTE[lumplen];
|
||||||
map->Read(ML_SEGS, data);
|
map->Read(ML_SEGS, data);
|
||||||
|
|
||||||
|
for (i = 0; i < numsubsectors; ++i)
|
||||||
|
{
|
||||||
|
subsectors[i].firstline = &segs[(size_t)subsectors[i].firstline];
|
||||||
|
}
|
||||||
|
|
||||||
// phares: 10/4/98: Vertchanged is an array that represents the vertices.
|
// phares: 10/4/98: Vertchanged is an array that represents the vertices.
|
||||||
// Mark those used by linedefs. A marked vertex is one that is not a
|
// Mark those used by linedefs. A marked vertex is one that is not a
|
||||||
// candidate for movement further down.
|
// candidate for movement further down.
|
||||||
|
@ -1329,9 +1339,9 @@ void P_LoadSubsectors (MapData * map)
|
||||||
}
|
}
|
||||||
|
|
||||||
subsectors[i].numlines = subd.numsegs;
|
subsectors[i].numlines = subd.numsegs;
|
||||||
subsectors[i].firstline = subd.firstseg;
|
subsectors[i].firstline = (seg_t *)(size_t)subd.firstseg;
|
||||||
|
|
||||||
if (subsectors[i].firstline >= maxseg)
|
if ((size_t)subsectors[i].firstline >= maxseg)
|
||||||
{
|
{
|
||||||
Printf ("Subsector %d contains invalid segs %u-%u\n"
|
Printf ("Subsector %d contains invalid segs %u-%u\n"
|
||||||
"The BSP will be rebuilt.\n", i, subsectors[i].firstline,
|
"The BSP will be rebuilt.\n", i, subsectors[i].firstline,
|
||||||
|
@ -1341,7 +1351,7 @@ void P_LoadSubsectors (MapData * map)
|
||||||
delete[] subsectors;
|
delete[] subsectors;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (subsectors[i].firstline + subsectors[i].numlines > maxseg)
|
else if ((size_t)subsectors[i].firstline + subsectors[i].numlines > maxseg)
|
||||||
{
|
{
|
||||||
Printf ("Subsector %d contains invalid segs %u-%u\n"
|
Printf ("Subsector %d contains invalid segs %u-%u\n"
|
||||||
"The BSP will be rebuilt.\n", i, maxseg,
|
"The BSP will be rebuilt.\n", i, maxseg,
|
||||||
|
@ -2910,20 +2920,7 @@ static void P_GroupLines (bool buildmap)
|
||||||
times[0].Clock();
|
times[0].Clock();
|
||||||
for (i = 0; i < numsubsectors; i++)
|
for (i = 0; i < numsubsectors; i++)
|
||||||
{
|
{
|
||||||
subsectors[i].sector = segs[subsectors[i].firstline].sidedef->sector;
|
subsectors[i].sector = subsectors[i].firstline->sidedef->sector;
|
||||||
subsectors[i].validcount = validcount;
|
|
||||||
|
|
||||||
double accumx = 0.0, accumy = 0.0;
|
|
||||||
|
|
||||||
for (jj = 0; jj < subsectors[i].numlines; ++jj)
|
|
||||||
{
|
|
||||||
seg_t *seg = &segs[subsectors[i].firstline + jj];
|
|
||||||
seg->Subsector = &subsectors[i];
|
|
||||||
accumx += seg->v1->x + seg->v2->x;
|
|
||||||
accumy += seg->v1->y + seg->v2->y;
|
|
||||||
}
|
|
||||||
subsectors[i].CenterX = fixed_t(accumx * 0.5 / subsectors[i].numlines);
|
|
||||||
subsectors[i].CenterY = fixed_t(accumy * 0.5 / subsectors[i].numlines);
|
|
||||||
}
|
}
|
||||||
times[0].Unclock();
|
times[0].Unclock();
|
||||||
|
|
||||||
|
@ -3369,6 +3366,13 @@ void P_FreeLevelData ()
|
||||||
}
|
}
|
||||||
if (subsectors != NULL)
|
if (subsectors != NULL)
|
||||||
{
|
{
|
||||||
|
for (int i = 0; i < numsubsectors; ++i)
|
||||||
|
{
|
||||||
|
if (subsectors[i].BSP != NULL)
|
||||||
|
{
|
||||||
|
delete subsectors[i].BSP;
|
||||||
|
}
|
||||||
|
}
|
||||||
delete[] subsectors;
|
delete[] subsectors;
|
||||||
subsectors = NULL;
|
subsectors = NULL;
|
||||||
}
|
}
|
||||||
|
@ -3786,7 +3790,7 @@ void P_SetupLevel (char *lumpname, int position)
|
||||||
};
|
};
|
||||||
leveldata.FindMapBounds ();
|
leveldata.FindMapBounds ();
|
||||||
UsingGLNodes |= genglnodes;
|
UsingGLNodes |= genglnodes;
|
||||||
FNodeBuilder builder (leveldata, polyspots, anchors, UsingGLNodes, CPU.bSSE2);
|
FNodeBuilder builder (leveldata, polyspots, anchors, UsingGLNodes);
|
||||||
delete[] vertexes;
|
delete[] vertexes;
|
||||||
builder.Extract (nodes, numnodes,
|
builder.Extract (nodes, numnodes,
|
||||||
segs, numsegs,
|
segs, numsegs,
|
||||||
|
|
160
src/po_man.cpp
160
src/po_man.cpp
|
@ -142,6 +142,9 @@ static void TranslateToStartSpot (int tag, int originX, int originY);
|
||||||
static void DoMovePolyobj (FPolyObj *po, int x, int y);
|
static void DoMovePolyobj (FPolyObj *po, int x, int y);
|
||||||
static void InitSegLists ();
|
static void InitSegLists ();
|
||||||
static void KillSegLists ();
|
static void KillSegLists ();
|
||||||
|
static FPolyNode *NewPolyNode();
|
||||||
|
static void FreePolyNode();
|
||||||
|
static void ReleaseAllPolyNodes();
|
||||||
|
|
||||||
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
||||||
|
|
||||||
|
@ -157,6 +160,7 @@ polyspawns_t *polyspawns; // [RH] Let P_SpawnMapThings() find our thingies for u
|
||||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||||
|
|
||||||
static TArray<SDWORD> KnownPolySides;
|
static TArray<SDWORD> KnownPolySides;
|
||||||
|
static FPolyNode *FreePolyNodes;
|
||||||
|
|
||||||
// CODE --------------------------------------------------------------------
|
// CODE --------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -758,7 +762,6 @@ FPolyObj::FPolyObj()
|
||||||
subsectorlinks = NULL;
|
subsectorlinks = NULL;
|
||||||
specialdata = NULL;
|
specialdata = NULL;
|
||||||
interpolation = NULL;
|
interpolation = NULL;
|
||||||
SVIndex = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -1279,20 +1282,6 @@ void FPolyObj::ClosestPoint(fixed_t fx, fixed_t fy, fixed_t &ox, fixed_t &oy, si
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vertex_t *FPolyObj::GetNewVertex()
|
|
||||||
{
|
|
||||||
if (SVIndex == ~0u || SplitVertices[SVIndex]->used == 10)
|
|
||||||
{
|
|
||||||
SVIndex++;
|
|
||||||
if (SVIndex >= SplitVertices.Size())
|
|
||||||
{
|
|
||||||
SplitVertices.Push(new FPolyVertexBlock);
|
|
||||||
}
|
|
||||||
SplitVertices[SVIndex]->clear();
|
|
||||||
}
|
|
||||||
return &SplitVertices[SVIndex]->vertices[SplitVertices[SVIndex]->used++];
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// InitBlockMap
|
// InitBlockMap
|
||||||
|
@ -1699,11 +1688,6 @@ bool PO_Busy (int polyobj)
|
||||||
|
|
||||||
void FPolyObj::ClearSubsectorLinks()
|
void FPolyObj::ClearSubsectorLinks()
|
||||||
{
|
{
|
||||||
for(unsigned i=0; i<SplitVertices.Size(); i++)
|
|
||||||
{
|
|
||||||
SplitVertices[i]->clear();
|
|
||||||
}
|
|
||||||
SVIndex = -1;
|
|
||||||
while (subsectorlinks != NULL)
|
while (subsectorlinks != NULL)
|
||||||
{
|
{
|
||||||
assert(subsectorlinks->state == 1337);
|
assert(subsectorlinks->state == 1337);
|
||||||
|
@ -1725,6 +1709,12 @@ void FPolyObj::ClearSubsectorLinks()
|
||||||
{
|
{
|
||||||
subsectorlinks->subsector->polys = subsectorlinks->pnext;
|
subsectorlinks->subsector->polys = subsectorlinks->pnext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (subsectorlinks->subsector->BSP != NULL)
|
||||||
|
{
|
||||||
|
subsectorlinks->subsector->BSP->bDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
subsectorlinks->state = -1;
|
subsectorlinks->state = -1;
|
||||||
delete subsectorlinks;
|
delete subsectorlinks;
|
||||||
subsectorlinks = next;
|
subsectorlinks = next;
|
||||||
|
@ -1734,10 +1724,11 @@ void FPolyObj::ClearSubsectorLinks()
|
||||||
|
|
||||||
void FPolyObj::ClearAllSubsectorLinks()
|
void FPolyObj::ClearAllSubsectorLinks()
|
||||||
{
|
{
|
||||||
for(int i=0;i<po_NumPolyobjs;i++)
|
for (int i = 0; i < po_NumPolyobjs; i++)
|
||||||
{
|
{
|
||||||
polyobjs[i].ClearSubsectorLinks();
|
polyobjs[i].ClearSubsectorLinks();
|
||||||
}
|
}
|
||||||
|
ReleaseAllPolyNodes();
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -1748,16 +1739,16 @@ void FPolyObj::ClearAllSubsectorLinks()
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
static bool GetIntersection(seg_t *seg, node_t *bsp, vertex_t *v)
|
static bool GetIntersection(FPolySeg *seg, node_t *bsp, FPolyVertex *v)
|
||||||
{
|
{
|
||||||
double frac;
|
double frac;
|
||||||
double num;
|
double num;
|
||||||
double den;
|
double den;
|
||||||
|
|
||||||
double v2x = (double)seg->v1->x;
|
double v2x = (double)seg->v1.x;
|
||||||
double v2y = (double)seg->v1->y;
|
double v2y = (double)seg->v1.y;
|
||||||
double v2dx = (double)(seg->v2->x - seg->v1->x);
|
double v2dx = (double)(seg->v2.x - seg->v1.x);
|
||||||
double v2dy = (double)(seg->v2->y - seg->v1->y);
|
double v2dy = (double)(seg->v2.y - seg->v1.y);
|
||||||
double v1x = (double)bsp->x;
|
double v1x = (double)bsp->x;
|
||||||
double v1y = (double)bsp->y;
|
double v1y = (double)bsp->y;
|
||||||
double v1dx = (double)bsp->dx;
|
double v1dx = (double)bsp->dx;
|
||||||
|
@ -1786,7 +1777,7 @@ static bool GetIntersection(seg_t *seg, node_t *bsp, vertex_t *v)
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
static double PartitionDistance(vertex_t *vt, node_t *node)
|
static double PartitionDistance(FPolyVertex *vt, node_t *node)
|
||||||
{
|
{
|
||||||
return fabs(double(-node->dy) * (vt->x - node->x) + double(node->dx) * (vt->y - node->y)) / node->len;
|
return fabs(double(-node->dy) * (vt->x - node->x) + double(node->dx) * (vt->y - node->y)) / node->len;
|
||||||
}
|
}
|
||||||
|
@ -1823,7 +1814,7 @@ static void AddToBBox(fixed_t child[4], fixed_t parent[4])
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
static void AddToBBox(vertex_t *v, fixed_t bbox[4])
|
static void AddToBBox(FPolyVertex *v, fixed_t bbox[4])
|
||||||
{
|
{
|
||||||
if (v->x < bbox[BOXLEFT])
|
if (v->x < bbox[BOXLEFT])
|
||||||
{
|
{
|
||||||
|
@ -1851,7 +1842,7 @@ static void AddToBBox(vertex_t *v, fixed_t bbox[4])
|
||||||
|
|
||||||
static void SplitPoly(FPolyNode *pnode, void *node, fixed_t bbox[4])
|
static void SplitPoly(FPolyNode *pnode, void *node, fixed_t bbox[4])
|
||||||
{
|
{
|
||||||
static TArray<seg_t> lists[2];
|
static TArray<FPolySeg> lists[2];
|
||||||
static const double POLY_EPSILON = 0.3125;
|
static const double POLY_EPSILON = 0.3125;
|
||||||
|
|
||||||
if (!((size_t)node & 1)) // Keep going until found a subsector
|
if (!((size_t)node & 1)) // Keep going until found a subsector
|
||||||
|
@ -1864,7 +1855,7 @@ static void SplitPoly(FPolyNode *pnode, void *node, fixed_t bbox[4])
|
||||||
lists[1].Clear();
|
lists[1].Clear();
|
||||||
for(unsigned i=0;i<pnode->segs.Size(); i++)
|
for(unsigned i=0;i<pnode->segs.Size(); i++)
|
||||||
{
|
{
|
||||||
seg_t *seg = &pnode->segs[i];
|
FPolySeg *seg = &pnode->segs[i];
|
||||||
|
|
||||||
// Parts of the following code were taken from Eternity and are
|
// Parts of the following code were taken from Eternity and are
|
||||||
// being used with permission.
|
// being used with permission.
|
||||||
|
@ -1872,8 +1863,8 @@ static void SplitPoly(FPolyNode *pnode, void *node, fixed_t bbox[4])
|
||||||
// get distance of vertices from partition line
|
// get distance of vertices from partition line
|
||||||
// If the distance is too small, we may decide to
|
// If the distance is too small, we may decide to
|
||||||
// change our idea of sidedness.
|
// change our idea of sidedness.
|
||||||
double dist_v1 = PartitionDistance(seg->v1, bsp);
|
double dist_v1 = PartitionDistance(&seg->v1, bsp);
|
||||||
double dist_v2 = PartitionDistance(seg->v2, bsp);
|
double dist_v2 = PartitionDistance(&seg->v2, bsp);
|
||||||
|
|
||||||
// If the distances are less than epsilon, consider the points as being
|
// If the distances are less than epsilon, consider the points as being
|
||||||
// on the same side as the polyobj origin. Why? People like to build
|
// on the same side as the polyobj origin. Why? People like to build
|
||||||
|
@ -1894,27 +1885,27 @@ static void SplitPoly(FPolyNode *pnode, void *node, fixed_t bbox[4])
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int side = R_PointOnSide(seg->v2->x, seg->v2->y, bsp);
|
int side = R_PointOnSide(seg->v2.x, seg->v2.y, bsp);
|
||||||
lists[side].Push(*seg);
|
lists[side].Push(*seg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (dist_v2 <= POLY_EPSILON)
|
else if (dist_v2 <= POLY_EPSILON)
|
||||||
{
|
{
|
||||||
int side = R_PointOnSide(seg->v1->x, seg->v1->y, bsp);
|
int side = R_PointOnSide(seg->v1.x, seg->v1.y, bsp);
|
||||||
lists[side].Push(*seg);
|
lists[side].Push(*seg);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int side1 = R_PointOnSide(seg->v1->x, seg->v1->y, bsp);
|
int side1 = R_PointOnSide(seg->v1.x, seg->v1.y, bsp);
|
||||||
int side2 = R_PointOnSide(seg->v2->x, seg->v2->y, bsp);
|
int side2 = R_PointOnSide(seg->v2.x, seg->v2.y, bsp);
|
||||||
|
|
||||||
if(side1 != side2)
|
if(side1 != side2)
|
||||||
{
|
{
|
||||||
// if the partition line crosses this seg, we must split it.
|
// if the partition line crosses this seg, we must split it.
|
||||||
|
|
||||||
vertex_t *vert = pnode->poly->GetNewVertex();
|
FPolyVertex vert;
|
||||||
|
|
||||||
if (GetIntersection(seg, bsp, vert))
|
if (GetIntersection(seg, bsp, &vert))
|
||||||
{
|
{
|
||||||
lists[0].Push(*seg);
|
lists[0].Push(*seg);
|
||||||
lists[1].Push(*seg);
|
lists[1].Push(*seg);
|
||||||
|
@ -1947,13 +1938,8 @@ static void SplitPoly(FPolyNode *pnode, void *node, fixed_t bbox[4])
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// create the new node
|
// create the new node
|
||||||
FPolyNode *newnode = new FPolyNode;
|
FPolyNode *newnode = NewPolyNode();
|
||||||
newnode->state = 1337;
|
|
||||||
newnode->poly = pnode->poly;
|
newnode->poly = pnode->poly;
|
||||||
newnode->pnext = NULL;
|
|
||||||
newnode->pprev = NULL;
|
|
||||||
newnode->subsector = NULL;
|
|
||||||
newnode->snext = NULL;
|
|
||||||
newnode->segs = lists[1];
|
newnode->segs = lists[1];
|
||||||
|
|
||||||
// set segs for original node
|
// set segs for original node
|
||||||
|
@ -1995,8 +1981,8 @@ static void SplitPoly(FPolyNode *pnode, void *node, fixed_t bbox[4])
|
||||||
|
|
||||||
for (unsigned i = 0; i < pnode->segs.Size(); ++i)
|
for (unsigned i = 0; i < pnode->segs.Size(); ++i)
|
||||||
{
|
{
|
||||||
AddToBBox(pnode->segs[i].v1, subbbox);
|
AddToBBox(&pnode->segs[i].v1, subbbox);
|
||||||
AddToBBox(pnode->segs[i].v2, subbbox);
|
AddToBBox(&pnode->segs[i].v2, subbbox);
|
||||||
}
|
}
|
||||||
// Potentially expand the parent node's bounding box to contain these bits of polyobject.
|
// Potentially expand the parent node's bounding box to contain these bits of polyobject.
|
||||||
AddToBBox(subbbox, bbox);
|
AddToBBox(subbbox, bbox);
|
||||||
|
@ -2011,31 +1997,23 @@ static void SplitPoly(FPolyNode *pnode, void *node, fixed_t bbox[4])
|
||||||
|
|
||||||
void FPolyObj::CreateSubsectorLinks()
|
void FPolyObj::CreateSubsectorLinks()
|
||||||
{
|
{
|
||||||
FPolyNode *node = new FPolyNode;
|
FPolyNode *node = NewPolyNode();
|
||||||
fixed_t dummybbox[4];
|
// Even though we don't care about it, we need to initialize this
|
||||||
|
// bounding box to something so that Valgrind won't complain about it
|
||||||
|
// when SplitPoly modifies it.
|
||||||
|
fixed_t dummybbox[4] = { 0 };
|
||||||
|
|
||||||
node->state = 1337;
|
|
||||||
node->poly = this;
|
node->poly = this;
|
||||||
node->pnext = NULL;
|
|
||||||
node->pprev = NULL;
|
|
||||||
node->snext = NULL;
|
|
||||||
node->segs.Resize(Sidedefs.Size());
|
node->segs.Resize(Sidedefs.Size());
|
||||||
|
|
||||||
for(unsigned i=0; i<Sidedefs.Size(); i++)
|
for(unsigned i=0; i<Sidedefs.Size(); i++)
|
||||||
{
|
{
|
||||||
seg_t *seg = &node->segs[i];
|
FPolySeg *seg = &node->segs[i];
|
||||||
side_t *side = Sidedefs[i];
|
side_t *side = Sidedefs[i];
|
||||||
|
|
||||||
seg->v1 = side->V1();
|
seg->v1 = side->V1();
|
||||||
seg->v2 = side->V2();
|
seg->v2 = side->V2();
|
||||||
seg->sidedef = side;
|
seg->wall = side;
|
||||||
seg->linedef = side->linedef;
|
|
||||||
seg->frontsector = side->sector;
|
|
||||||
seg->backsector = side->linedef->frontsector == side->sector?
|
|
||||||
side->linedef->backsector : side->linedef->frontsector;
|
|
||||||
seg->Subsector = NULL;
|
|
||||||
seg->PartnerSeg = NULL;
|
|
||||||
seg->bPolySeg = true;
|
|
||||||
}
|
}
|
||||||
SplitPoly(node, nodes + numnodes - 1, dummybbox);
|
SplitPoly(node, nodes + numnodes - 1, dummybbox);
|
||||||
}
|
}
|
||||||
|
@ -2055,4 +2033,62 @@ void PO_LinkToSubsectors()
|
||||||
polyobjs[i].CreateSubsectorLinks();
|
polyobjs[i].CreateSubsectorLinks();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// NewPolyNode
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
static FPolyNode *NewPolyNode()
|
||||||
|
{
|
||||||
|
FPolyNode *node;
|
||||||
|
|
||||||
|
if (FreePolyNodes != NULL)
|
||||||
|
{
|
||||||
|
node = FreePolyNodes;
|
||||||
|
FreePolyNodes = node->pnext;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node = new FPolyNode;
|
||||||
|
}
|
||||||
|
node->state = 1337;
|
||||||
|
node->poly = NULL;
|
||||||
|
node->pnext = NULL;
|
||||||
|
node->pprev = NULL;
|
||||||
|
node->subsector = NULL;
|
||||||
|
node->snext = NULL;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FreePolyNode
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void FreePolyNode(FPolyNode *node)
|
||||||
|
{
|
||||||
|
node->segs.Clear();
|
||||||
|
node->pnext = FreePolyNodes;
|
||||||
|
FreePolyNodes = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// ReleaseAllPolyNodes
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void ReleaseAllPolyNodes()
|
||||||
|
{
|
||||||
|
FPolyNode *node, *next;
|
||||||
|
|
||||||
|
for (node = FreePolyNodes; node != NULL; node = next)
|
||||||
|
{
|
||||||
|
next = node->pnext;
|
||||||
|
delete node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
45
src/po_man.h
45
src/po_man.h
|
@ -5,13 +5,32 @@
|
||||||
#include "r_defs.h"
|
#include "r_defs.h"
|
||||||
#include "m_bbox.h"
|
#include "m_bbox.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct FPolyVertex
|
||||||
|
{
|
||||||
|
fixed_t x, y;
|
||||||
|
|
||||||
|
FPolyVertex &operator=(vertex_t *v)
|
||||||
|
{
|
||||||
|
x = v->x;
|
||||||
|
y = v->y;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FPolySeg
|
||||||
|
{
|
||||||
|
FPolyVertex v1;
|
||||||
|
FPolyVertex v2;
|
||||||
|
side_t *wall;
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// Linked lists of polyobjects
|
// Linked lists of polyobjects
|
||||||
//
|
//
|
||||||
struct FPolyObj;
|
struct FPolyObj;
|
||||||
struct FPolyNode
|
struct FPolyNode
|
||||||
{
|
{
|
||||||
int state;
|
|
||||||
FPolyObj *poly; // owning polyobject
|
FPolyObj *poly; // owning polyobject
|
||||||
FPolyNode *pnext; // next polyobj in list
|
FPolyNode *pnext; // next polyobj in list
|
||||||
FPolyNode *pprev; // previous polyobj
|
FPolyNode *pprev; // previous polyobj
|
||||||
|
@ -19,25 +38,8 @@ struct FPolyNode
|
||||||
subsector_t *subsector; // containimg subsector
|
subsector_t *subsector; // containimg subsector
|
||||||
FPolyNode *snext; // next subsector
|
FPolyNode *snext; // next subsector
|
||||||
|
|
||||||
TArray<seg_t> segs; // segs for this node
|
TArray<FPolySeg> segs; // segs for this node
|
||||||
fixed_t dist; // distance for sorting
|
int state;
|
||||||
};
|
|
||||||
|
|
||||||
struct FPolyVertex
|
|
||||||
{
|
|
||||||
fixed_t x, y;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FPolyVertexBlock
|
|
||||||
{
|
|
||||||
int used;
|
|
||||||
vertex_t vertices[10];
|
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
used = 0;
|
|
||||||
//memset(vertices, 0, sizeof(vertices));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// ===== Polyobj data =====
|
// ===== Polyobj data =====
|
||||||
|
@ -51,8 +53,6 @@ struct FPolyObj
|
||||||
FPolyVertex StartSpot;
|
FPolyVertex StartSpot;
|
||||||
FPolyVertex CenterSpot;
|
FPolyVertex CenterSpot;
|
||||||
FBoundingBox Bounds; // Bounds in map coordinates
|
FBoundingBox Bounds; // Bounds in map coordinates
|
||||||
TDeletingArray<FPolyVertexBlock *> SplitVertices;
|
|
||||||
unsigned int SVIndex;
|
|
||||||
|
|
||||||
angle_t angle;
|
angle_t angle;
|
||||||
int tag; // reference tag assigned in HereticEd
|
int tag; // reference tag assigned in HereticEd
|
||||||
|
@ -77,7 +77,6 @@ struct FPolyObj
|
||||||
void LinkPolyobj ();
|
void LinkPolyobj ();
|
||||||
void CreateSubsectorLinks();
|
void CreateSubsectorLinks();
|
||||||
void ClearSubsectorLinks();
|
void ClearSubsectorLinks();
|
||||||
vertex_t *GetNewVertex();
|
|
||||||
void CalcCenter();
|
void CalcCenter();
|
||||||
static void ClearAllSubsectorLinks();
|
static void ClearAllSubsectorLinks();
|
||||||
|
|
||||||
|
|
110
src/r_bsp.cpp
110
src/r_bsp.cpp
|
@ -43,6 +43,7 @@
|
||||||
#include "r_things.h"
|
#include "r_things.h"
|
||||||
#include "a_sharedglobal.h"
|
#include "a_sharedglobal.h"
|
||||||
#include "g_level.h"
|
#include "g_level.h"
|
||||||
|
#include "nodebuild.h"
|
||||||
|
|
||||||
// State.
|
// State.
|
||||||
#include "doomstat.h"
|
#include "doomstat.h"
|
||||||
|
@ -108,6 +109,9 @@ WORD MirrorFlags;
|
||||||
seg_t *ActiveWallMirror;
|
seg_t *ActiveWallMirror;
|
||||||
TArray<size_t> WallMirrors;
|
TArray<size_t> WallMirrors;
|
||||||
|
|
||||||
|
static FNodeBuilder::FLevel PolyNodeLevel;
|
||||||
|
static FNodeBuilder PolyNodeBuilder(PolyNodeLevel);
|
||||||
|
|
||||||
CVAR (Bool, r_drawflat, false, 0) // [RH] Don't texture segs?
|
CVAR (Bool, r_drawflat, false, 0) // [RH] Don't texture segs?
|
||||||
|
|
||||||
|
|
||||||
|
@ -1009,44 +1013,76 @@ void R_GetExtraLight (int *light, const secplane_t &plane, FExtraLight *el)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int STACK_ARGS polycmp(const void *a, const void *b)
|
|
||||||
{
|
|
||||||
const FPolyNode *A = *(FPolyNode **)a;
|
|
||||||
const FPolyNode *B = *(FPolyNode **)b;
|
|
||||||
|
|
||||||
return A->dist - B->dist;
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FMiniBSP Constructor
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FMiniBSP::FMiniBSP()
|
||||||
|
{
|
||||||
|
bDirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// P_BuildPolyBSP
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
static void R_BuildPolyBSP(subsector_t *sub)
|
||||||
|
{
|
||||||
|
assert((sub->BSP == NULL || sub->BSP->bDirty) && "BSP computed more than once");
|
||||||
|
|
||||||
|
// Set up level information for the node builder.
|
||||||
|
PolyNodeLevel.Sides = sides;
|
||||||
|
PolyNodeLevel.NumSides = numsides;
|
||||||
|
PolyNodeLevel.Lines = lines;
|
||||||
|
PolyNodeLevel.NumLines = numlines;
|
||||||
|
|
||||||
|
// Feed segs to the nodebuilder and build the nodes.
|
||||||
|
PolyNodeBuilder.Clear();
|
||||||
|
PolyNodeBuilder.AddSegs(sub->firstline, sub->numlines);
|
||||||
|
for (FPolyNode *pn = sub->polys; pn != NULL; pn = pn->pnext)
|
||||||
|
{
|
||||||
|
PolyNodeBuilder.AddPolySegs(&pn->segs[0], (int)pn->segs.Size());
|
||||||
|
}
|
||||||
|
PolyNodeBuilder.BuildMini(false);
|
||||||
|
if (sub->BSP == NULL)
|
||||||
|
{
|
||||||
|
sub->BSP = new FMiniBSP;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sub->BSP->bDirty = false;
|
||||||
|
}
|
||||||
|
PolyNodeBuilder.ExtractMini(sub->BSP);
|
||||||
|
for (unsigned int i = 0; i < sub->BSP->Subsectors.Size(); ++i)
|
||||||
|
{
|
||||||
|
sub->BSP->Subsectors[i].sector = sub->sector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void R_Subsector (subsector_t *sub);
|
||||||
static void R_AddPolyobjs(subsector_t *sub)
|
static void R_AddPolyobjs(subsector_t *sub)
|
||||||
{
|
{
|
||||||
static TArray<FPolyNode *> sortedpolys;
|
if (sub->BSP == NULL || sub->BSP->bDirty)
|
||||||
|
|
||||||
FPolyNode *pn = sub->polys;
|
|
||||||
sortedpolys.Clear();
|
|
||||||
while (pn != NULL)
|
|
||||||
{
|
{
|
||||||
sortedpolys.Push(pn);
|
R_BuildPolyBSP(sub);
|
||||||
pn->dist = R_PointToDist2(pn->poly->CenterSpot.x - viewx, pn->poly->CenterSpot.y - viewy);
|
|
||||||
pn = pn->pnext;
|
|
||||||
}
|
}
|
||||||
if (sortedpolys.Size() > 1)
|
if (sub->BSP->Nodes.Size() == 0)
|
||||||
{
|
{
|
||||||
qsort(&sortedpolys[0], sortedpolys.Size(), sizeof (sortedpolys[0]), polycmp);
|
R_Subsector(&sub->BSP->Subsectors[0]);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
for(unsigned i=0; i<sortedpolys.Size(); i++)
|
|
||||||
{
|
{
|
||||||
pn = sortedpolys[i];
|
R_RenderBSPNode(&sub->BSP->Nodes.Last());
|
||||||
for(unsigned j=0; j<pn->segs.Size(); j++)
|
|
||||||
{
|
|
||||||
R_AddLine(&pn->segs[j]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// R_Subsector
|
// R_Subsector
|
||||||
// Determine floor/ceiling planes.
|
// Determine floor/ceiling planes.
|
||||||
|
@ -1061,15 +1097,25 @@ void R_Subsector (subsector_t *sub)
|
||||||
int floorlightlevel; // killough 3/16/98: set floor lightlevel
|
int floorlightlevel; // killough 3/16/98: set floor lightlevel
|
||||||
int ceilinglightlevel; // killough 4/11/98
|
int ceilinglightlevel; // killough 4/11/98
|
||||||
|
|
||||||
|
#if 0
|
||||||
#ifdef RANGECHECK
|
#ifdef RANGECHECK
|
||||||
if (sub - subsectors >= (ptrdiff_t)numsubsectors)
|
if (sub - subsectors >= (ptrdiff_t)numsubsectors)
|
||||||
I_Error ("R_Subsector: ss %ti with numss = %i", sub - subsectors, numsubsectors);
|
I_Error ("R_Subsector: ss %ti with numss = %i", sub - subsectors, numsubsectors);
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
assert(sub->sector != NULL);
|
||||||
|
|
||||||
|
if (sub->polys)
|
||||||
|
{ // Render the polyobjs in the subsector first
|
||||||
|
R_AddPolyobjs(sub);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
frontsector = sub->sector;
|
frontsector = sub->sector;
|
||||||
frontsector->MoreFlags |= SECF_DRAWN;
|
frontsector->MoreFlags |= SECF_DRAWN;
|
||||||
count = sub->numlines;
|
count = sub->numlines;
|
||||||
line = &segs[sub->firstline];
|
line = sub->firstline;
|
||||||
|
|
||||||
// killough 3/8/98, 4/4/98: Deep water / fake ceiling effect
|
// killough 3/8/98, 4/4/98: Deep water / fake ceiling effect
|
||||||
frontsector = R_FakeFlat(frontsector, &tempsec, &floorlightlevel,
|
frontsector = R_FakeFlat(frontsector, &tempsec, &floorlightlevel,
|
||||||
|
@ -1133,15 +1179,13 @@ void R_Subsector (subsector_t *sub)
|
||||||
ceilinglightlevel : floorlightlevel, FakeSide);
|
ceilinglightlevel : floorlightlevel, FakeSide);
|
||||||
|
|
||||||
// [RH] Add particles
|
// [RH] Add particles
|
||||||
int shade = LIGHT2SHADE((floorlightlevel + ceilinglightlevel)/2 + r_actualextralight);
|
if ((unsigned int)(sub - subsectors) < (unsigned int)numsubsectors)
|
||||||
for (WORD i = ParticlesInSubsec[(unsigned int)(sub-subsectors)]; i != NO_PARTICLE; i = Particles[i].snext)
|
{ // Only do it for the main BSP.
|
||||||
{
|
int shade = LIGHT2SHADE((floorlightlevel + ceilinglightlevel)/2 + r_actualextralight);
|
||||||
R_ProjectParticle (Particles + i, subsectors[sub-subsectors].sector, shade, FakeSide);
|
for (WORD i = ParticlesInSubsec[(unsigned int)(sub-subsectors)]; i != NO_PARTICLE; i = Particles[i].snext)
|
||||||
}
|
{
|
||||||
|
R_ProjectParticle (Particles + i, subsectors[sub-subsectors].sector, shade, FakeSide);
|
||||||
if (sub->polys)
|
}
|
||||||
{ // Render the polyobjs in the subsector first
|
|
||||||
R_AddPolyobjs(sub);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (count--)
|
while (count--)
|
||||||
|
|
50
src/r_defs.h
50
src/r_defs.h
|
@ -925,22 +925,7 @@ struct msecnode_t
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FPolyNode;
|
struct FPolyNode;
|
||||||
|
struct FMiniBSP;
|
||||||
//
|
|
||||||
// A SubSector.
|
|
||||||
// References a Sector.
|
|
||||||
// Basically, this is a list of LineSegs indicating the visible walls that
|
|
||||||
// define (all or some) sides of a convex BSP leaf.
|
|
||||||
//
|
|
||||||
struct subsector_t
|
|
||||||
{
|
|
||||||
sector_t *sector;
|
|
||||||
DWORD numlines;
|
|
||||||
DWORD firstline;
|
|
||||||
FPolyNode *polys;
|
|
||||||
int validcount;
|
|
||||||
fixed_t CenterX, CenterY;
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// The LineSeg.
|
// The LineSeg.
|
||||||
|
@ -957,12 +942,27 @@ struct seg_t
|
||||||
sector_t* frontsector;
|
sector_t* frontsector;
|
||||||
sector_t* backsector; // NULL for one-sided lines
|
sector_t* backsector; // NULL for one-sided lines
|
||||||
|
|
||||||
subsector_t* Subsector;
|
|
||||||
seg_t* PartnerSeg;
|
seg_t* PartnerSeg;
|
||||||
|
|
||||||
BITFIELD bPolySeg:1;
|
BITFIELD bPolySeg:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// A SubSector.
|
||||||
|
// References a Sector.
|
||||||
|
// Basically, this is a list of LineSegs indicating the visible walls that
|
||||||
|
// define (all or some) sides of a convex BSP leaf.
|
||||||
|
//
|
||||||
|
struct subsector_t
|
||||||
|
{
|
||||||
|
sector_t *sector;
|
||||||
|
FPolyNode *polys;
|
||||||
|
FMiniBSP *BSP;
|
||||||
|
seg_t *firstline;
|
||||||
|
DWORD numlines;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -985,6 +985,22 @@ struct node_t
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// An entire BSP tree.
|
||||||
|
|
||||||
|
struct FMiniBSP
|
||||||
|
{
|
||||||
|
FMiniBSP();
|
||||||
|
|
||||||
|
bool bDirty;
|
||||||
|
|
||||||
|
TArray<node_t> Nodes;
|
||||||
|
TArray<seg_t> Segs;
|
||||||
|
TArray<subsector_t> Subsectors;
|
||||||
|
TArray<vertex_t> Verts;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// posts are runs of non masked source pixels
|
// posts are runs of non masked source pixels
|
||||||
struct column_t
|
struct column_t
|
||||||
{
|
{
|
||||||
|
|
|
@ -1401,7 +1401,7 @@ void RP_Subsector (subsector_t *sub)
|
||||||
|
|
||||||
frontsector = sub->sector;
|
frontsector = sub->sector;
|
||||||
count = sub->numlines;
|
count = sub->numlines;
|
||||||
line = &segs[sub->firstline];
|
line = sub->firstline;
|
||||||
|
|
||||||
// killough 3/8/98, 4/4/98: Deep water / fake ceiling effect
|
// killough 3/8/98, 4/4/98: Deep water / fake ceiling effect
|
||||||
frontsector = R_FakeFlat(frontsector, &tempsec, &floorlightlevel,
|
frontsector = R_FakeFlat(frontsector, &tempsec, &floorlightlevel,
|
||||||
|
|
191
src/r_segs.cpp
191
src/r_segs.cpp
|
@ -1480,17 +1480,17 @@ int side_t::GetLightLevel (bool foggy, int baselight, int *pfakecontrast) const
|
||||||
if (((level.flags2 & LEVEL2_SMOOTHLIGHTING) || (Flags & WALLF_SMOOTHLIGHTING) || r_fakecontrast == 2) &&
|
if (((level.flags2 & LEVEL2_SMOOTHLIGHTING) || (Flags & WALLF_SMOOTHLIGHTING) || r_fakecontrast == 2) &&
|
||||||
linedef->dx != 0)
|
linedef->dx != 0)
|
||||||
{
|
{
|
||||||
rel = int // OMG LEE KILLOUGH LIVES! :/
|
rel = xs_RoundToInt // OMG LEE KILLOUGH LIVES! :/
|
||||||
(
|
(
|
||||||
(float(level.WallHorizLight)
|
level.WallHorizLight
|
||||||
+abs(atan(float(linedef->dy)/float(linedef->dx))/float(1.57079))
|
+ fabs(atan(double(linedef->dy) / linedef->dx) / 1.57079)
|
||||||
*float(level.WallVertLight - level.WallHorizLight))
|
* (level.WallVertLight - level.WallHorizLight)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rel = linedef->dx==0? level.WallVertLight :
|
rel = linedef->dx == 0 ? level.WallVertLight :
|
||||||
linedef->dy==0? level.WallHorizLight : 0;
|
linedef->dy == 0 ? level.WallHorizLight : 0;
|
||||||
}
|
}
|
||||||
if (pfakecontrast != NULL)
|
if (pfakecontrast != NULL)
|
||||||
{
|
{
|
||||||
|
@ -2008,80 +2008,12 @@ int WallMost (short *mostbuf, const secplane_t &plane)
|
||||||
return bad;
|
return bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrepWall (fixed_t *swall, fixed_t *lwall, fixed_t walxrepeat)
|
static void PrepWallRoundFix(fixed_t *lwall, fixed_t walxrepeat)
|
||||||
{ // swall = scale, lwall = texturecolumn
|
{
|
||||||
int x;
|
|
||||||
float top, bot, i;
|
|
||||||
float xrepeat = (float)walxrepeat;
|
|
||||||
float ol, l, topinc, botinc;
|
|
||||||
|
|
||||||
i = (float)(WallSX1 - centerx);
|
|
||||||
top = WallUoverZorg + WallUoverZstep * i;
|
|
||||||
bot = WallInvZorg + WallInvZstep * i;
|
|
||||||
topinc = WallUoverZstep * 4.f;
|
|
||||||
botinc = WallInvZstep * 4.f;
|
|
||||||
|
|
||||||
x = WallSX1;
|
|
||||||
|
|
||||||
l = top / bot;
|
|
||||||
swall[x] = xs_RoundToInt(l * WallDepthScale + WallDepthOrg);
|
|
||||||
lwall[x] = xs_RoundToInt(l * xrepeat);
|
|
||||||
// As long as l is invalid, step one column at a time so that
|
|
||||||
// we can get as many correct texture columns as possible.
|
|
||||||
while (l > 1.0 && x+1 < WallSX2)
|
|
||||||
{
|
|
||||||
l = (top += WallUoverZstep) / (bot += WallInvZstep);
|
|
||||||
x++;
|
|
||||||
swall[x] = xs_RoundToInt(l * WallDepthScale + WallDepthOrg);
|
|
||||||
lwall[x] = xs_RoundToInt(l * xrepeat);
|
|
||||||
}
|
|
||||||
l *= xrepeat;
|
|
||||||
while (x+4 < WallSX2)
|
|
||||||
{
|
|
||||||
top += topinc; bot += botinc;
|
|
||||||
ol = l; l = top / bot;
|
|
||||||
swall[x+4] = xs_RoundToInt(l * WallDepthScale + WallDepthOrg);
|
|
||||||
lwall[x+4] = xs_RoundToInt(l *= xrepeat);
|
|
||||||
|
|
||||||
i = (ol+l) * 0.5f;
|
|
||||||
lwall[x+2] = xs_RoundToInt(i);
|
|
||||||
lwall[x+1] = xs_RoundToInt((ol+i) * 0.5f);
|
|
||||||
lwall[x+3] = xs_RoundToInt((l+i) * 0.5f);
|
|
||||||
swall[x+2] = ((swall[x]+swall[x+4])>>1);
|
|
||||||
swall[x+1] = ((swall[x]+swall[x+2])>>1);
|
|
||||||
swall[x+3] = ((swall[x+4]+swall[x+2])>>1);
|
|
||||||
x += 4;
|
|
||||||
}
|
|
||||||
if (x+2 < WallSX2)
|
|
||||||
{
|
|
||||||
top += topinc * 0.5f; bot += botinc * 0.5f;
|
|
||||||
ol = l; l = top / bot;
|
|
||||||
swall[x+2] = xs_RoundToInt(l * WallDepthScale + WallDepthOrg);
|
|
||||||
lwall[x+2] = xs_RoundToInt(l *= xrepeat);
|
|
||||||
|
|
||||||
lwall[x+1] = xs_RoundToInt((l+ol)*0.5f);
|
|
||||||
swall[x+1] = (swall[x]+swall[x+2])>>1;
|
|
||||||
x += 2;
|
|
||||||
}
|
|
||||||
if (x+1 < WallSX2)
|
|
||||||
{
|
|
||||||
l = (top + WallUoverZstep) / (bot + WallInvZstep);
|
|
||||||
swall[x+1] = xs_RoundToInt(l * WallDepthScale + WallDepthOrg);
|
|
||||||
lwall[x+1] = xs_RoundToInt(l * xrepeat);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
for (x = WallSX1; x < WallSX2; x++)
|
|
||||||
{
|
|
||||||
frac = top / bot;
|
|
||||||
lwall[x] = xs_RoundToInt(frac * xrepeat);
|
|
||||||
swall[x] = xs_RoundToInt(frac * WallDepthScale + WallDepthOrg);
|
|
||||||
top += WallUoverZstep;
|
|
||||||
bot += WallInvZstep;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// fix for rounding errors
|
// fix for rounding errors
|
||||||
fixed_t fix = (MirrorFlags & RF_XFLIP) ? walxrepeat-1 : 0;
|
fixed_t fix = (MirrorFlags & RF_XFLIP) ? walxrepeat-1 : 0;
|
||||||
|
int x;
|
||||||
|
|
||||||
if (WallSX1 > 0)
|
if (WallSX1 > 0)
|
||||||
{
|
{
|
||||||
for (x = WallSX1; x < WallSX2; x++)
|
for (x = WallSX1; x < WallSX2; x++)
|
||||||
|
@ -2110,85 +2042,52 @@ void PrepWall (fixed_t *swall, fixed_t *lwall, fixed_t walxrepeat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrepLWall (fixed_t *lwall, fixed_t walxrepeat)
|
void PrepWall (fixed_t *swall, fixed_t *lwall, fixed_t walxrepeat)
|
||||||
{ // lwall = texturecolumn
|
{ // swall = scale, lwall = texturecolumn
|
||||||
int x;
|
double top, bot, i;
|
||||||
float top, bot, i;
|
double xrepeat = walxrepeat;
|
||||||
float xrepeat = (float)walxrepeat;
|
double topinc, botinc;
|
||||||
float ol, l, topinc, botinc;
|
|
||||||
|
|
||||||
i = (float)(WallSX1 - centerx);
|
i = WallSX1 - centerx;
|
||||||
top = WallUoverZorg + WallUoverZstep * i;
|
top = WallUoverZorg + WallUoverZstep * i;
|
||||||
bot = WallInvZorg + WallInvZstep * i;
|
bot = WallInvZorg + WallInvZstep * i;
|
||||||
topinc = WallUoverZstep * 4.f;
|
topinc = WallUoverZstep * 4.f;
|
||||||
botinc = WallInvZstep * 4.f;
|
botinc = WallInvZstep * 4.f;
|
||||||
|
|
||||||
x = WallSX1;
|
for (int x = WallSX1; x < WallSX2; x++)
|
||||||
|
{
|
||||||
|
double frac = top / bot;
|
||||||
|
lwall[x] = xs_RoundToInt(frac * xrepeat);
|
||||||
|
swall[x] = xs_RoundToInt(frac * WallDepthScale + WallDepthOrg);
|
||||||
|
top += WallUoverZstep;
|
||||||
|
bot += WallInvZstep;
|
||||||
|
}
|
||||||
|
PrepWallRoundFix(lwall, walxrepeat);
|
||||||
|
}
|
||||||
|
|
||||||
l = top / bot;
|
void PrepLWall (fixed_t *lwall, fixed_t walxrepeat)
|
||||||
lwall[x] = xs_RoundToInt(l * xrepeat);
|
{ // lwall = texturecolumn
|
||||||
// As long as l is invalid, step one column at a time so that
|
double top, bot, i;
|
||||||
// we can get as many correct texture columns as possible.
|
double xrepeat = walxrepeat;
|
||||||
while (l > 1.0 && x+1 < WallSX2)
|
double topinc, botinc;
|
||||||
{
|
double topstep;
|
||||||
l = (top += WallUoverZstep) / (bot += WallInvZstep);
|
|
||||||
lwall[++x] = xs_RoundToInt(l * xrepeat);
|
|
||||||
}
|
|
||||||
l *= xrepeat;
|
|
||||||
while (x+4 < WallSX2)
|
|
||||||
{
|
|
||||||
top += topinc; bot += botinc;
|
|
||||||
ol = l; l = top / bot;
|
|
||||||
lwall[x+4] = xs_RoundToInt(l *= xrepeat);
|
|
||||||
|
|
||||||
i = (ol+l) * 0.5f;
|
i = WallSX1 - centerx;
|
||||||
lwall[x+2] = xs_RoundToInt(i);
|
top = WallUoverZorg + WallUoverZstep * i;
|
||||||
lwall[x+1] = xs_RoundToInt((ol+i) * 0.5f);
|
bot = WallInvZorg + WallInvZstep * i;
|
||||||
lwall[x+3] = xs_RoundToInt((l+i) * 0.5f);
|
topinc = WallUoverZstep * 4.f;
|
||||||
x += 4;
|
botinc = WallInvZstep * 4.f;
|
||||||
}
|
|
||||||
if (x+2 < WallSX2)
|
|
||||||
{
|
|
||||||
top += topinc * 0.5f; bot += botinc * 0.5f;
|
|
||||||
ol = l; l = top / bot;
|
|
||||||
lwall[x+2] = xs_RoundToInt(l *= xrepeat);
|
|
||||||
lwall[x+1] = xs_RoundToInt((l+ol)*0.5f);
|
|
||||||
x += 2;
|
|
||||||
}
|
|
||||||
if (x+1 < WallSX2)
|
|
||||||
{
|
|
||||||
l = (top + WallUoverZstep) / (bot + WallInvZstep);
|
|
||||||
lwall[x+1] = xs_RoundToInt(l * xrepeat);
|
|
||||||
}
|
|
||||||
|
|
||||||
// fix for rounding errors
|
top *= xrepeat;
|
||||||
fixed_t fix = (MirrorFlags & RF_XFLIP) ? walxrepeat-1 : 0;
|
topstep = WallUoverZstep * xrepeat;
|
||||||
if (WallSX1 > 0)
|
|
||||||
|
for (int x = WallSX1; x < WallSX2; x++)
|
||||||
{
|
{
|
||||||
for (x = WallSX1; x < WallSX2; x++)
|
lwall[x] = xs_RoundToInt(top / bot);
|
||||||
{
|
top += topstep;
|
||||||
if ((unsigned)lwall[x] >= (unsigned)walxrepeat)
|
bot += WallInvZstep;
|
||||||
{
|
|
||||||
lwall[x] = fix;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fix = walxrepeat - 1 - fix;
|
|
||||||
for (x = WallSX2-1; x >= WallSX1; x--)
|
|
||||||
{
|
|
||||||
if ((unsigned)lwall[x] >= (unsigned)walxrepeat)
|
|
||||||
{
|
|
||||||
lwall[x] = fix;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
PrepWallRoundFix(lwall, walxrepeat);
|
||||||
}
|
}
|
||||||
|
|
||||||
// pass = 0: when seg is first drawn
|
// pass = 0: when seg is first drawn
|
||||||
|
|
748
zdoom.vcproj
748
zdoom.vcproj
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue