mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-22 12:11:25 +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_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 )
|
||||
message( STATUS "Using system zlib" )
|
||||
else( ZLIB_FOUND )
|
||||
|
|
|
@ -330,6 +330,13 @@ endif( NOT NO_ASM )
|
|||
# Set up flags for GCC
|
||||
|
||||
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" )
|
||||
if( NOT PROFILE )
|
||||
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);
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
if (am_showsubsector >= 0 && am_showsubsector < numsubsectors)
|
||||
|
@ -1682,13 +1698,13 @@ void AM_showSS()
|
|||
red.FromRGB(255,0,0);
|
||||
|
||||
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();
|
||||
|
||||
for(int i=0;i<po_NumPolyobjs;i++)
|
||||
for (int i = 0; i <po_NumPolyobjs; i++)
|
||||
{
|
||||
FPolyObj *po = &polyobjs[i];
|
||||
FPolyNode *pnode = po->subsectorlinks;
|
||||
|
@ -1697,9 +1713,9 @@ void AM_showSS()
|
|||
{
|
||||
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;
|
||||
|
|
|
@ -62,10 +62,17 @@ const int AAPreference = 16;
|
|||
#define D(x) do{}while(0)
|
||||
#endif
|
||||
|
||||
FNodeBuilder::FNodeBuilder(FLevel &level)
|
||||
: Level(level), GLNodes(false), SegsStuffed(0)
|
||||
{
|
||||
|
||||
VertexMap = NULL;
|
||||
}
|
||||
|
||||
FNodeBuilder::FNodeBuilder (FLevel &level,
|
||||
TArray<FPolyStart> &polyspots, TArray<FPolyStart> &anchors,
|
||||
bool makeGLNodes, bool enableSSE2)
|
||||
: Level(level), GLNodes(makeGLNodes), EnableSSE2(enableSSE2), SegsStuffed(0)
|
||||
bool makeGLNodes)
|
||||
: Level(level), GLNodes(makeGLNodes), SegsStuffed(0)
|
||||
{
|
||||
VertexMap = new FVertexMap (*this, Level.MinX, Level.MinY, Level.MaxX, Level.MaxY);
|
||||
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 ()
|
||||
{
|
||||
fixed_t bbox[4];
|
||||
|
@ -90,35 +124,38 @@ void FNodeBuilder::BuildTree ()
|
|||
C_InitTicker ("Building BSP", FRACUNIT);
|
||||
HackSeg = DWORD_MAX;
|
||||
HackMate = DWORD_MAX;
|
||||
CreateNode (0, bbox);
|
||||
CreateNode (0, Segs.Size(), bbox);
|
||||
CreateSubsectorsForReal ();
|
||||
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;
|
||||
int skip, count, selstat;
|
||||
int skip, selstat;
|
||||
DWORD splitseg;
|
||||
|
||||
count = CountSegs (set);
|
||||
skip = count / MaxSegs;
|
||||
skip = int(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 ||
|
||||
(skip > 0 && (selstat = SelectSplitter (set, node, splitseg, 1, true)) > 0) ||
|
||||
(selstat < 0 && (SelectSplitter (set, node, splitseg, skip, false) > 0 ||
|
||||
(skip > 0 && SelectSplitter (set, node, splitseg, 1, false)))) ||
|
||||
CheckSubsector (set, node, splitseg, count))
|
||||
CheckSubsector (set, node, splitseg))
|
||||
{
|
||||
// Create a normal node
|
||||
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(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));
|
||||
node.intchildren[0] = CreateNode (set1, node.bbox[0]);
|
||||
node.intchildren[1] = CreateNode (set2, node.bbox[1]);
|
||||
node.intchildren[0] = CreateNode (set1, count1, node.bbox[0]);
|
||||
node.intchildren[1] = CreateNode (set2, count2, node.bbox[1]);
|
||||
bbox[BOXTOP] = MAX (node.bbox[0][BOXTOP], node.bbox[1][BOXTOP]);
|
||||
bbox[BOXBOTTOM] = MIN (node.bbox[0][BOXBOTTOM], node.bbox[1][BOXBOTTOM]);
|
||||
bbox[BOXLEFT] = MIN (node.bbox[0][BOXLEFT], node.bbox[1][BOXLEFT]);
|
||||
|
@ -173,17 +210,15 @@ void FNodeBuilder::CreateSubsectorsForReal ()
|
|||
subsector_t sub;
|
||||
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.polys = NULL;
|
||||
sub.BSP = NULL;
|
||||
|
||||
for (i = 0; i < SubsectorSets.Size(); ++i)
|
||||
{
|
||||
DWORD set = SubsectorSets[i];
|
||||
DWORD firstline = (DWORD)SegList.Size();
|
||||
|
||||
sub.firstline = (DWORD)SegList.Size();
|
||||
while (set != DWORD_MAX)
|
||||
{
|
||||
USegPtr ptr;
|
||||
|
@ -192,14 +227,15 @@ void FNodeBuilder::CreateSubsectorsForReal ()
|
|||
SegList.Push (ptr);
|
||||
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
|
||||
qsort (&SegList[sub.firstline], sub.numlines, sizeof(USegPtr), SortSegs);
|
||||
qsort (&SegList[firstline], sub.numlines, sizeof(USegPtr), SortSegs);
|
||||
|
||||
// Convert seg pointers into indices
|
||||
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],
|
||||
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
|
||||
// sector. If so, false is returned, and they become a subsector. If not,
|
||||
// a splitter is synthesized, and true is returned to continue processing
|
||||
// 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;
|
||||
DWORD seg;
|
||||
|
@ -506,7 +530,7 @@ int FNodeBuilder::Heuristic (node_t &node, DWORD set, bool honorNoSplit)
|
|||
int realSegs[2] = { 0, 0 };
|
||||
int specialSegs[2] = { 0, 0 };
|
||||
DWORD i = set;
|
||||
int sidev1, sidev2;
|
||||
int sidev[2];
|
||||
int side;
|
||||
bool splitter = false;
|
||||
unsigned int max, m2, p, q;
|
||||
|
@ -525,7 +549,7 @@ int FNodeBuilder::Heuristic (node_t &node, DWORD set, bool honorNoSplit)
|
|||
}
|
||||
else
|
||||
{
|
||||
side = ClassifyLine (node, test, sidev1, sidev2);
|
||||
side = ClassifyLine (node, &Vertices[test->v1], &Vertices[test->v2], sidev);
|
||||
}
|
||||
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
|
||||
// another nosplit seg from the same sector at this vertex. Note that a line
|
||||
// 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();
|
||||
for (p = 0; p < max; ++p)
|
||||
|
@ -735,8 +759,10 @@ int FNodeBuilder::Heuristic (node_t &node, DWORD set, bool honorNoSplit)
|
|||
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;
|
||||
outset1 = DWORD_MAX;
|
||||
|
||||
|
@ -749,18 +775,18 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou
|
|||
FPrivSeg *seg = &Segs[set];
|
||||
int next = seg->next;
|
||||
|
||||
int sidev1, sidev2, side;
|
||||
int sidev[2], side;
|
||||
|
||||
if (HackSeg == set)
|
||||
{
|
||||
HackSeg = DWORD_MAX;
|
||||
side = 1;
|
||||
sidev1 = sidev2 = 0;
|
||||
sidev[0] = sidev[1] = 0;
|
||||
hack = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
side = ClassifyLine (node, seg, sidev1, sidev2);
|
||||
side = ClassifyLine (node, &Vertices[seg->v1], &Vertices[seg->v2], sidev);
|
||||
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
|
||||
seg->next = outset0;
|
||||
outset0 = set;
|
||||
_count0++;
|
||||
break;
|
||||
|
||||
case 1: // seg is entirely in back
|
||||
seg->next = outset1;
|
||||
outset1 = set;
|
||||
_count1++;
|
||||
break;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
seg2 = SplitSeg (set, vertnum, sidev1);
|
||||
seg2 = SplitSeg (set, vertnum, sidev[0]);
|
||||
|
||||
Segs[seg2].next = outset0;
|
||||
outset0 = seg2;
|
||||
Segs[set].next = outset1;
|
||||
outset1 = set;
|
||||
_count0++;
|
||||
_count1++;
|
||||
|
||||
// Also split the seg on the back side
|
||||
if (Segs[set].partner != DWORD_MAX)
|
||||
{
|
||||
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
|
||||
// back seg because it has not been considered for splitting
|
||||
// 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 (sidev1 == 0)
|
||||
if (sidev[0] == 0)
|
||||
{
|
||||
double dist1 = AddIntersection (node, seg->v1);
|
||||
if (sidev2 == 0)
|
||||
if (sidev[1] == 0)
|
||||
{
|
||||
double dist2 = AddIntersection (node, seg->v2);
|
||||
FSplitSharer share = { dist1, set, dist2 > dist1 };
|
||||
SplitSharers.Push (share);
|
||||
}
|
||||
}
|
||||
else if (sidev2 == 0)
|
||||
else if (sidev[1] == 0)
|
||||
{
|
||||
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);
|
||||
}
|
||||
count0 = _count0;
|
||||
count1 = _count1;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
|
||||
|
||||
#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 "tarray.h"
|
||||
#include "r_defs.h"
|
||||
#include "x86.h"
|
||||
|
||||
struct FPolySeg;
|
||||
struct FMiniBSP;
|
||||
|
||||
struct FEventInfo
|
||||
{
|
||||
|
@ -40,6 +44,27 @@ private:
|
|||
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
|
||||
{
|
||||
struct FPrivSeg
|
||||
|
@ -60,9 +85,8 @@ class FNodeBuilder
|
|||
bool planefront;
|
||||
FPrivSeg *hashnext;
|
||||
};
|
||||
struct FPrivVert
|
||||
struct FPrivVert : FSimpleVert
|
||||
{
|
||||
fixed_t x, y;
|
||||
DWORD segs; // segs that use this vertex as v1
|
||||
DWORD segs2; // segs that use this vertex as v2
|
||||
|
||||
|
@ -88,7 +112,17 @@ class FNodeBuilder
|
|||
};
|
||||
|
||||
// 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:
|
||||
FVertexMap (FNodeBuilder &builder, fixed_t minx, fixed_t miny, fixed_t maxx, fixed_t maxy);
|
||||
|
@ -116,12 +150,23 @@ class FNodeBuilder
|
|||
assert (y <= MaxY);
|
||||
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 FVertexMapSimple;
|
||||
|
||||
public:
|
||||
struct FLevel
|
||||
|
@ -132,7 +177,14 @@ public:
|
|||
|
||||
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
|
||||
|
@ -141,9 +193,10 @@ public:
|
|||
fixed_t x, y;
|
||||
};
|
||||
|
||||
FNodeBuilder (FLevel &level);
|
||||
FNodeBuilder (FLevel &level,
|
||||
TArray<FPolyStart> &polyspots, TArray<FPolyStart> &anchors,
|
||||
bool makeGLNodes, bool enableSSE2);
|
||||
bool makeGLNodes);
|
||||
~FNodeBuilder ();
|
||||
|
||||
void Extract (node_t *&nodes, int &nodeCount,
|
||||
|
@ -151,6 +204,13 @@ public:
|
|||
subsector_t *&ssecs, int &subCount,
|
||||
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);
|
||||
|
||||
// < 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);
|
||||
|
||||
private:
|
||||
FVertexMap *VertexMap;
|
||||
IVertexMap *VertexMap;
|
||||
|
||||
TArray<node_t> Nodes;
|
||||
TArray<subsector_t> Subsectors;
|
||||
|
@ -181,7 +241,6 @@ private:
|
|||
DWORD HackMate; // Seg to use in front of hack seg
|
||||
FLevel &Level;
|
||||
bool GLNodes; // Add minisegs to make GL nodes?
|
||||
bool EnableSSE2;
|
||||
|
||||
// Progress meter stuff
|
||||
int SegsStuffed;
|
||||
|
@ -191,29 +250,27 @@ private:
|
|||
void MakeSegsFromSides ();
|
||||
int CreateSeg (int linenum, int sidenum);
|
||||
void GroupSegPlanes ();
|
||||
void GroupSegPlanesSimple ();
|
||||
void FindPolyContainers (TArray<FPolyStart> &spots, TArray<FPolyStart> &anchors);
|
||||
bool GetPolyExtents (int polynum, fixed_t bbox[4]);
|
||||
int MarkLoop (DWORD firstseg, int loopnum);
|
||||
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]);
|
||||
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 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);
|
||||
int Heuristic (node_t &node, DWORD set, bool honorNoSplit);
|
||||
int CountSegs (DWORD set) const;
|
||||
|
||||
// Returns:
|
||||
// 0 = seg is in front
|
||||
// 1 = seg is in back
|
||||
// -1 = seg cuts the node
|
||||
|
||||
inline int ClassifyLine (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2);
|
||||
int ClassifyLine2 (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2);
|
||||
int ClassifyLineSSE2 (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]);
|
||||
|
||||
void FixSplitSharers (const node_t &node);
|
||||
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;
|
||||
}
|
||||
|
||||
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__)
|
||||
return ClassifyLine2 (node, seg, sidev1, sidev2);
|
||||
#elif defined(__SSE2__)
|
||||
#ifdef DISABLE_SSE
|
||||
return ClassifyLine2 (node, v1, v2, sidev);
|
||||
#else
|
||||
#if defined(__SSE2__) || defined(_M_IX64)
|
||||
// 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
|
||||
// VC 6 does not support SSE2 optimizations.
|
||||
return ClassifyLine2 (node, seg, sidev1, sidev2);
|
||||
// VC 6 does not support SSE optimizations.
|
||||
return ClassifyLine2 (node, v1, v2, sidev);
|
||||
#else
|
||||
// Select the routine based on our flag.
|
||||
if (EnableSSE2)
|
||||
return ClassifyLineSSE2 (node, seg, sidev1, sidev2);
|
||||
#ifdef BACKPATCH
|
||||
return ClassifyLineBackpatch (node, v1, v2, sidev);
|
||||
#else
|
||||
if (CPU.bSSE2)
|
||||
return ClassifyLineSSE2 (node, v1, v2, sidev);
|
||||
else
|
||||
return ClassifyLine2 (node, seg, sidev1, sidev2);
|
||||
return ClassifyLine2 (node, v1, v2, sidev);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -3,11 +3,8 @@
|
|||
|
||||
#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_y1 = double(node.y);
|
||||
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)
|
||||
{
|
||||
sidev1 = sidev2 = 1;
|
||||
sidev[0] = sidev[1] = 1;
|
||||
return 1;
|
||||
}
|
||||
if (s_num2 >= FAR_ENOUGH)
|
||||
{
|
||||
sidev1 = 1;
|
||||
sidev2 = -1;
|
||||
sidev[0] = 1;
|
||||
sidev[1] = -1;
|
||||
return -1;
|
||||
}
|
||||
nears = 1;
|
||||
|
@ -41,13 +38,13 @@ int FNodeBuilder::ClassifyLine2 (node_t &node, const FPrivSeg *seg, int &sidev1,
|
|||
{
|
||||
if (s_num2 >= FAR_ENOUGH)
|
||||
{
|
||||
sidev1 = sidev2 = -1;
|
||||
sidev[0] = sidev[1] = -1;
|
||||
return 0;
|
||||
}
|
||||
if (s_num2 <= -FAR_ENOUGH)
|
||||
{
|
||||
sidev1 = -1;
|
||||
sidev2 = 1;
|
||||
sidev[0] = -1;
|
||||
sidev[1] = 1;
|
||||
return -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;
|
||||
if (dist < SIDE_EPSILON*SIDE_EPSILON)
|
||||
{
|
||||
sidev1 = 0;
|
||||
sidev[0] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sidev1 = s_num1 > 0.0 ? -1 : 1;
|
||||
sidev[0] = s_num1 > 0.0 ? -1 : 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sidev1 = s_num1 > 0.0 ? -1 : 1;
|
||||
sidev[0] = s_num1 > 0.0 ? -1 : 1;
|
||||
}
|
||||
if (nears & 1)
|
||||
{
|
||||
double dist = s_num2 * s_num2 * l;
|
||||
if (dist < SIDE_EPSILON*SIDE_EPSILON)
|
||||
{
|
||||
sidev2 = 0;
|
||||
sidev[1] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sidev2 = s_num2 > 0.0 ? -1 : 1;
|
||||
sidev[1] = s_num2 > 0.0 ? -1 : 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sidev2 = s_num2 > 0.0 ? -1 : 1;
|
||||
sidev[1] = s_num2 > 0.0 ? -1 : 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sidev1 = s_num1 > 0.0 ? -1 : 1;
|
||||
sidev2 = s_num2 > 0.0 ? -1 : 1;
|
||||
sidev[0] = s_num1 > 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
|
||||
// which child it ends up in. If it faces the same direction as the splitter,
|
||||
// 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;
|
||||
}
|
||||
else if (sidev1 >= 0 && sidev2 >= 0)
|
||||
else if (sidev[0] >= 0 && sidev[1] >= 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
#ifndef DISABLE_SSE
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "nodebuild.h"
|
||||
|
||||
#define FAR_ENOUGH 17179869184.f // 4<<32
|
||||
|
||||
// This function is identical to the ClassifyLine2 version. So how does it use SSE2?
|
||||
// Easy! By explicitly enabling SSE2 in the configuration properties for this one
|
||||
// file, we can build it with SSE2 enabled without forcing SSE2 on the rest of the
|
||||
// project.
|
||||
// You may notice that this function is identical to ClassifyLine2.
|
||||
// The reason it is SSE2 is because this file is explicitly compiled
|
||||
// with SSE2 math enabled, but the other files are not.
|
||||
|
||||
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_y1 = double(node.y);
|
||||
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)
|
||||
{
|
||||
sidev1 = sidev2 = 1;
|
||||
sidev[0] = sidev[1] = 1;
|
||||
return 1;
|
||||
}
|
||||
if (s_num2 >= FAR_ENOUGH)
|
||||
{
|
||||
sidev1 = 1;
|
||||
sidev2 = -1;
|
||||
sidev[0] = 1;
|
||||
sidev[1] = -1;
|
||||
return -1;
|
||||
}
|
||||
nears = 1;
|
||||
|
@ -46,13 +44,13 @@ int FNodeBuilder::ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &side
|
|||
{
|
||||
if (s_num2 >= FAR_ENOUGH)
|
||||
{
|
||||
sidev1 = sidev2 = -1;
|
||||
sidev[0] = sidev[1] = -1;
|
||||
return 0;
|
||||
}
|
||||
if (s_num2 <= -FAR_ENOUGH)
|
||||
{
|
||||
sidev1 = -1;
|
||||
sidev2 = 1;
|
||||
sidev[0] = -1;
|
||||
sidev[1] = 1;
|
||||
return -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;
|
||||
if (dist < SIDE_EPSILON*SIDE_EPSILON)
|
||||
{
|
||||
sidev1 = 0;
|
||||
sidev[0] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sidev1 = s_num1 > 0.0 ? -1 : 1;
|
||||
sidev[0] = s_num1 > 0.0 ? -1 : 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sidev1 = s_num1 > 0.0 ? -1 : 1;
|
||||
sidev[0] = s_num1 > 0.0 ? -1 : 1;
|
||||
}
|
||||
if (nears & 1)
|
||||
{
|
||||
double dist = s_num2 * s_num2 * l;
|
||||
if (dist < SIDE_EPSILON*SIDE_EPSILON)
|
||||
{
|
||||
sidev2 = 0;
|
||||
sidev[1] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sidev2 = s_num2 > 0.0 ? -1 : 1;
|
||||
sidev[1] = s_num2 > 0.0 ? -1 : 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sidev2 = s_num2 > 0.0 ? -1 : 1;
|
||||
sidev[1] = s_num2 > 0.0 ? -1 : 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sidev1 = s_num1 > 0.0 ? -1 : 1;
|
||||
sidev2 = s_num2 > 0.0 ? -1 : 1;
|
||||
sidev[0] = s_num1 > 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
|
||||
// which child it ends up in. If it faces the same direction as the splitter,
|
||||
// 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;
|
||||
}
|
||||
else if (sidev1 >= 0 && sidev2 >= 0)
|
||||
else if (sidev[0] >= 0 && sidev[1] >= 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -105,7 +105,7 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount,
|
|||
{
|
||||
DWORD numsegs = CloseSubsector (segs, i, outVerts);
|
||||
outSubs[i].numlines = numsegs;
|
||||
outSubs[i].firstline = segs.Size() - numsegs;
|
||||
outSubs[i].firstline = (seg_t *)(size_t)(segs.Size() - numsegs);
|
||||
}
|
||||
|
||||
segCount = segs.Size ();
|
||||
|
@ -142,6 +142,10 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount,
|
|||
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));
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
FPrivSeg *seg, *prev;
|
||||
|
@ -163,7 +247,7 @@ int FNodeBuilder::CloseSubsector (TArray<seg_t> &segs, int subsector, vertex_t *
|
|||
bool diffplanes;
|
||||
int firstplane;
|
||||
|
||||
first = Subsectors[subsector].firstline;
|
||||
first = (DWORD)(size_t)Subsectors[subsector].firstline;
|
||||
max = first + Subsectors[subsector].numlines;
|
||||
count = 0;
|
||||
|
||||
|
@ -322,7 +406,7 @@ int FNodeBuilder::OutputDegenerateSubsector (TArray<seg_t> &segs, int subsector,
|
|||
double dot, x1, y1, dx, dy, dx2, dy2;
|
||||
bool wantside;
|
||||
|
||||
first = Subsectors[subsector].firstline;
|
||||
first = (DWORD)(size_t)Subsectors[subsector].firstline;
|
||||
max = first + Subsectors[subsector].numlines;
|
||||
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.bPolySeg = false;
|
||||
newseg.Subsector = NULL;
|
||||
return (DWORD)segs.Push (newseg);
|
||||
}
|
||||
|
||||
|
@ -417,6 +500,5 @@ void FNodeBuilder::PushConnectingGLSeg (int subsector, TArray<seg_t> &segs, vert
|
|||
newseg.sidedef = NULL;
|
||||
newseg.PartnerSeg = NULL;
|
||||
newseg.bPolySeg = false;
|
||||
newseg.Subsector = NULL;
|
||||
segs.Push (newseg);
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "m_bbox.h"
|
||||
#include "r_main.h"
|
||||
#include "i_system.h"
|
||||
#include "po_man.h"
|
||||
|
||||
static const int PO_LINE_START = 1;
|
||||
static const int PO_LINE_EXPLICIT = 5;
|
||||
|
@ -177,6 +178,86 @@ int FNodeBuilder::CreateSeg (int linenum, int sidenum)
|
|||
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
|
||||
// by SelectSplitter().
|
||||
|
||||
|
@ -269,6 +350,27 @@ void FNodeBuilder::GroupSegPlanes ()
|
|||
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
|
||||
// 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
|
||||
|
@ -507,6 +609,10 @@ void FNodeBuilder::FLevel::FindMapBounds ()
|
|||
MaxY = maxy;
|
||||
}
|
||||
|
||||
FNodeBuilder::IVertexMap::~IVertexMap()
|
||||
{
|
||||
}
|
||||
|
||||
FNodeBuilder::FVertexMap::FVertexMap (FNodeBuilder &builder,
|
||||
fixed_t minx, fixed_t miny, fixed_t maxx, fixed_t maxy)
|
||||
: MyBuilder(builder)
|
||||
|
@ -606,3 +712,52 @@ int FNodeBuilder::FVertexMap::InsertVertex (FNodeBuilder::FPrivVert &vert)
|
|||
|
||||
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;
|
||||
|
||||
seg = &segs[subsectors[i].firstline + j];
|
||||
seg = subsectors[i].firstline + j;
|
||||
seg->v1 = &vertexes[v1];
|
||||
if (j == 0)
|
||||
{
|
||||
|
@ -894,7 +894,7 @@ void P_LoadGLZSegs (FileReaderBase &data, int type)
|
|||
{
|
||||
seg->linedef = 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;
|
||||
|
||||
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;
|
||||
currSeg += numsegs;
|
||||
}
|
||||
|
@ -976,6 +976,11 @@ static void LoadZNodes(FileReaderBase &data, int glnodes)
|
|||
segs = new seg_t[numsegs];
|
||||
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)
|
||||
{
|
||||
P_LoadZSegs (data);
|
||||
|
@ -1141,6 +1146,11 @@ void P_LoadSegs (MapData * map)
|
|||
data = new BYTE[lumplen];
|
||||
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.
|
||||
// Mark those used by linedefs. A marked vertex is one that is not a
|
||||
// candidate for movement further down.
|
||||
|
@ -1329,9 +1339,9 @@ void P_LoadSubsectors (MapData * map)
|
|||
}
|
||||
|
||||
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"
|
||||
"The BSP will be rebuilt.\n", i, subsectors[i].firstline,
|
||||
|
@ -1341,7 +1351,7 @@ void P_LoadSubsectors (MapData * map)
|
|||
delete[] subsectors;
|
||||
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"
|
||||
"The BSP will be rebuilt.\n", i, maxseg,
|
||||
|
@ -2910,20 +2920,7 @@ static void P_GroupLines (bool buildmap)
|
|||
times[0].Clock();
|
||||
for (i = 0; i < numsubsectors; i++)
|
||||
{
|
||||
subsectors[i].sector = segs[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);
|
||||
subsectors[i].sector = subsectors[i].firstline->sidedef->sector;
|
||||
}
|
||||
times[0].Unclock();
|
||||
|
||||
|
@ -3369,6 +3366,13 @@ void P_FreeLevelData ()
|
|||
}
|
||||
if (subsectors != NULL)
|
||||
{
|
||||
for (int i = 0; i < numsubsectors; ++i)
|
||||
{
|
||||
if (subsectors[i].BSP != NULL)
|
||||
{
|
||||
delete subsectors[i].BSP;
|
||||
}
|
||||
}
|
||||
delete[] subsectors;
|
||||
subsectors = NULL;
|
||||
}
|
||||
|
@ -3786,7 +3790,7 @@ void P_SetupLevel (char *lumpname, int position)
|
|||
};
|
||||
leveldata.FindMapBounds ();
|
||||
UsingGLNodes |= genglnodes;
|
||||
FNodeBuilder builder (leveldata, polyspots, anchors, UsingGLNodes, CPU.bSSE2);
|
||||
FNodeBuilder builder (leveldata, polyspots, anchors, UsingGLNodes);
|
||||
delete[] vertexes;
|
||||
builder.Extract (nodes, numnodes,
|
||||
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 InitSegLists ();
|
||||
static void KillSegLists ();
|
||||
static FPolyNode *NewPolyNode();
|
||||
static void FreePolyNode();
|
||||
static void ReleaseAllPolyNodes();
|
||||
|
||||
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
||||
|
||||
|
@ -157,6 +160,7 @@ polyspawns_t *polyspawns; // [RH] Let P_SpawnMapThings() find our thingies for u
|
|||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||
|
||||
static TArray<SDWORD> KnownPolySides;
|
||||
static FPolyNode *FreePolyNodes;
|
||||
|
||||
// CODE --------------------------------------------------------------------
|
||||
|
||||
|
@ -758,7 +762,6 @@ FPolyObj::FPolyObj()
|
|||
subsectorlinks = NULL;
|
||||
specialdata = 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
|
||||
|
@ -1699,11 +1688,6 @@ bool PO_Busy (int polyobj)
|
|||
|
||||
void FPolyObj::ClearSubsectorLinks()
|
||||
{
|
||||
for(unsigned i=0; i<SplitVertices.Size(); i++)
|
||||
{
|
||||
SplitVertices[i]->clear();
|
||||
}
|
||||
SVIndex = -1;
|
||||
while (subsectorlinks != NULL)
|
||||
{
|
||||
assert(subsectorlinks->state == 1337);
|
||||
|
@ -1725,6 +1709,12 @@ void FPolyObj::ClearSubsectorLinks()
|
|||
{
|
||||
subsectorlinks->subsector->polys = subsectorlinks->pnext;
|
||||
}
|
||||
|
||||
if (subsectorlinks->subsector->BSP != NULL)
|
||||
{
|
||||
subsectorlinks->subsector->BSP->bDirty = true;
|
||||
}
|
||||
|
||||
subsectorlinks->state = -1;
|
||||
delete subsectorlinks;
|
||||
subsectorlinks = next;
|
||||
|
@ -1734,10 +1724,11 @@ void FPolyObj::ClearSubsectorLinks()
|
|||
|
||||
void FPolyObj::ClearAllSubsectorLinks()
|
||||
{
|
||||
for(int i=0;i<po_NumPolyobjs;i++)
|
||||
for (int i = 0; i < po_NumPolyobjs; i++)
|
||||
{
|
||||
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 num;
|
||||
double den;
|
||||
|
||||
double v2x = (double)seg->v1->x;
|
||||
double v2y = (double)seg->v1->y;
|
||||
double v2dx = (double)(seg->v2->x - seg->v1->x);
|
||||
double v2dy = (double)(seg->v2->y - seg->v1->y);
|
||||
double v2x = (double)seg->v1.x;
|
||||
double v2y = (double)seg->v1.y;
|
||||
double v2dx = (double)(seg->v2.x - seg->v1.x);
|
||||
double v2dy = (double)(seg->v2.y - seg->v1.y);
|
||||
double v1x = (double)bsp->x;
|
||||
double v1y = (double)bsp->y;
|
||||
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;
|
||||
}
|
||||
|
@ -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])
|
||||
{
|
||||
|
@ -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 TArray<seg_t> lists[2];
|
||||
static TArray<FPolySeg> lists[2];
|
||||
static const double POLY_EPSILON = 0.3125;
|
||||
|
||||
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();
|
||||
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
|
||||
// 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
|
||||
// If the distance is too small, we may decide to
|
||||
// change our idea of sidedness.
|
||||
double dist_v1 = PartitionDistance(seg->v1, bsp);
|
||||
double dist_v2 = PartitionDistance(seg->v2, bsp);
|
||||
double dist_v1 = PartitionDistance(&seg->v1, bsp);
|
||||
double dist_v2 = PartitionDistance(&seg->v2, bsp);
|
||||
|
||||
// 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
|
||||
|
@ -1894,27 +1885,27 @@ static void SplitPoly(FPolyNode *pnode, void *node, fixed_t bbox[4])
|
|||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
int side1 = R_PointOnSide(seg->v1->x, seg->v1->y, bsp);
|
||||
int side2 = R_PointOnSide(seg->v2->x, seg->v2->y, bsp);
|
||||
int side1 = R_PointOnSide(seg->v1.x, seg->v1.y, bsp);
|
||||
int side2 = R_PointOnSide(seg->v2.x, seg->v2.y, bsp);
|
||||
|
||||
if(side1 != side2)
|
||||
{
|
||||
// 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[1].Push(*seg);
|
||||
|
@ -1947,13 +1938,8 @@ static void SplitPoly(FPolyNode *pnode, void *node, fixed_t bbox[4])
|
|||
else
|
||||
{
|
||||
// create the new node
|
||||
FPolyNode *newnode = new FPolyNode;
|
||||
newnode->state = 1337;
|
||||
FPolyNode *newnode = NewPolyNode();
|
||||
newnode->poly = pnode->poly;
|
||||
newnode->pnext = NULL;
|
||||
newnode->pprev = NULL;
|
||||
newnode->subsector = NULL;
|
||||
newnode->snext = NULL;
|
||||
newnode->segs = lists[1];
|
||||
|
||||
// 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)
|
||||
{
|
||||
AddToBBox(pnode->segs[i].v1, subbbox);
|
||||
AddToBBox(pnode->segs[i].v2, subbbox);
|
||||
AddToBBox(&pnode->segs[i].v1, subbbox);
|
||||
AddToBBox(&pnode->segs[i].v2, subbbox);
|
||||
}
|
||||
// Potentially expand the parent node's bounding box to contain these bits of polyobject.
|
||||
AddToBBox(subbbox, bbox);
|
||||
|
@ -2011,31 +1997,23 @@ static void SplitPoly(FPolyNode *pnode, void *node, fixed_t bbox[4])
|
|||
|
||||
void FPolyObj::CreateSubsectorLinks()
|
||||
{
|
||||
FPolyNode *node = new FPolyNode;
|
||||
fixed_t dummybbox[4];
|
||||
FPolyNode *node = NewPolyNode();
|
||||
// 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->pnext = NULL;
|
||||
node->pprev = NULL;
|
||||
node->snext = NULL;
|
||||
node->segs.Resize(Sidedefs.Size());
|
||||
|
||||
for(unsigned i=0; i<Sidedefs.Size(); i++)
|
||||
{
|
||||
seg_t *seg = &node->segs[i];
|
||||
FPolySeg *seg = &node->segs[i];
|
||||
side_t *side = Sidedefs[i];
|
||||
|
||||
seg->v1 = side->V1();
|
||||
seg->v2 = side->V2();
|
||||
seg->sidedef = 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;
|
||||
seg->wall = side;
|
||||
}
|
||||
SplitPoly(node, nodes + numnodes - 1, dummybbox);
|
||||
}
|
||||
|
@ -2055,4 +2033,62 @@ void PO_LinkToSubsectors()
|
|||
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 "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
|
||||
//
|
||||
struct FPolyObj;
|
||||
struct FPolyNode
|
||||
{
|
||||
int state;
|
||||
FPolyObj *poly; // owning polyobject
|
||||
FPolyNode *pnext; // next polyobj in list
|
||||
FPolyNode *pprev; // previous polyobj
|
||||
|
@ -19,25 +38,8 @@ struct FPolyNode
|
|||
subsector_t *subsector; // containimg subsector
|
||||
FPolyNode *snext; // next subsector
|
||||
|
||||
TArray<seg_t> segs; // segs for this node
|
||||
fixed_t dist; // distance for sorting
|
||||
};
|
||||
|
||||
struct FPolyVertex
|
||||
{
|
||||
fixed_t x, y;
|
||||
};
|
||||
|
||||
struct FPolyVertexBlock
|
||||
{
|
||||
int used;
|
||||
vertex_t vertices[10];
|
||||
|
||||
void clear()
|
||||
{
|
||||
used = 0;
|
||||
//memset(vertices, 0, sizeof(vertices));
|
||||
}
|
||||
TArray<FPolySeg> segs; // segs for this node
|
||||
int state;
|
||||
};
|
||||
|
||||
// ===== Polyobj data =====
|
||||
|
@ -51,8 +53,6 @@ struct FPolyObj
|
|||
FPolyVertex StartSpot;
|
||||
FPolyVertex CenterSpot;
|
||||
FBoundingBox Bounds; // Bounds in map coordinates
|
||||
TDeletingArray<FPolyVertexBlock *> SplitVertices;
|
||||
unsigned int SVIndex;
|
||||
|
||||
angle_t angle;
|
||||
int tag; // reference tag assigned in HereticEd
|
||||
|
@ -77,7 +77,6 @@ struct FPolyObj
|
|||
void LinkPolyobj ();
|
||||
void CreateSubsectorLinks();
|
||||
void ClearSubsectorLinks();
|
||||
vertex_t *GetNewVertex();
|
||||
void CalcCenter();
|
||||
static void ClearAllSubsectorLinks();
|
||||
|
||||
|
|
110
src/r_bsp.cpp
110
src/r_bsp.cpp
|
@ -43,6 +43,7 @@
|
|||
#include "r_things.h"
|
||||
#include "a_sharedglobal.h"
|
||||
#include "g_level.h"
|
||||
#include "nodebuild.h"
|
||||
|
||||
// State.
|
||||
#include "doomstat.h"
|
||||
|
@ -108,6 +109,9 @@ WORD MirrorFlags;
|
|||
seg_t *ActiveWallMirror;
|
||||
TArray<size_t> WallMirrors;
|
||||
|
||||
static FNodeBuilder::FLevel PolyNodeLevel;
|
||||
static FNodeBuilder PolyNodeBuilder(PolyNodeLevel);
|
||||
|
||||
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 TArray<FPolyNode *> sortedpolys;
|
||||
|
||||
FPolyNode *pn = sub->polys;
|
||||
sortedpolys.Clear();
|
||||
while (pn != NULL)
|
||||
if (sub->BSP == NULL || sub->BSP->bDirty)
|
||||
{
|
||||
sortedpolys.Push(pn);
|
||||
pn->dist = R_PointToDist2(pn->poly->CenterSpot.x - viewx, pn->poly->CenterSpot.y - viewy);
|
||||
pn = pn->pnext;
|
||||
R_BuildPolyBSP(sub);
|
||||
}
|
||||
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]);
|
||||
}
|
||||
|
||||
for(unsigned i=0; i<sortedpolys.Size(); i++)
|
||||
else
|
||||
{
|
||||
pn = sortedpolys[i];
|
||||
for(unsigned j=0; j<pn->segs.Size(); j++)
|
||||
{
|
||||
R_AddLine(&pn->segs[j]);
|
||||
}
|
||||
R_RenderBSPNode(&sub->BSP->Nodes.Last());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// R_Subsector
|
||||
// Determine floor/ceiling planes.
|
||||
|
@ -1061,15 +1097,25 @@ void R_Subsector (subsector_t *sub)
|
|||
int floorlightlevel; // killough 3/16/98: set floor lightlevel
|
||||
int ceilinglightlevel; // killough 4/11/98
|
||||
|
||||
#if 0
|
||||
#ifdef RANGECHECK
|
||||
if (sub - subsectors >= (ptrdiff_t)numsubsectors)
|
||||
I_Error ("R_Subsector: ss %ti with numss = %i", sub - subsectors, numsubsectors);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
assert(sub->sector != NULL);
|
||||
|
||||
if (sub->polys)
|
||||
{ // Render the polyobjs in the subsector first
|
||||
R_AddPolyobjs(sub);
|
||||
return;
|
||||
}
|
||||
|
||||
frontsector = sub->sector;
|
||||
frontsector->MoreFlags |= SECF_DRAWN;
|
||||
count = sub->numlines;
|
||||
line = &segs[sub->firstline];
|
||||
line = sub->firstline;
|
||||
|
||||
// killough 3/8/98, 4/4/98: Deep water / fake ceiling effect
|
||||
frontsector = R_FakeFlat(frontsector, &tempsec, &floorlightlevel,
|
||||
|
@ -1133,15 +1179,13 @@ void R_Subsector (subsector_t *sub)
|
|||
ceilinglightlevel : floorlightlevel, FakeSide);
|
||||
|
||||
// [RH] Add particles
|
||||
int shade = LIGHT2SHADE((floorlightlevel + ceilinglightlevel)/2 + r_actualextralight);
|
||||
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);
|
||||
if ((unsigned int)(sub - subsectors) < (unsigned int)numsubsectors)
|
||||
{ // Only do it for the main BSP.
|
||||
int shade = LIGHT2SHADE((floorlightlevel + ceilinglightlevel)/2 + r_actualextralight);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
while (count--)
|
||||
|
|
50
src/r_defs.h
50
src/r_defs.h
|
@ -925,22 +925,7 @@ struct msecnode_t
|
|||
};
|
||||
|
||||
struct FPolyNode;
|
||||
|
||||
//
|
||||
// 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;
|
||||
};
|
||||
struct FMiniBSP;
|
||||
|
||||
//
|
||||
// The LineSeg.
|
||||
|
@ -957,12 +942,27 @@ struct seg_t
|
|||
sector_t* frontsector;
|
||||
sector_t* backsector; // NULL for one-sided lines
|
||||
|
||||
subsector_t* Subsector;
|
||||
seg_t* PartnerSeg;
|
||||
|
||||
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
|
||||
struct column_t
|
||||
{
|
||||
|
|
|
@ -1401,7 +1401,7 @@ void RP_Subsector (subsector_t *sub)
|
|||
|
||||
frontsector = sub->sector;
|
||||
count = sub->numlines;
|
||||
line = &segs[sub->firstline];
|
||||
line = sub->firstline;
|
||||
|
||||
// killough 3/8/98, 4/4/98: Deep water / fake ceiling effect
|
||||
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) &&
|
||||
linedef->dx != 0)
|
||||
{
|
||||
rel = int // OMG LEE KILLOUGH LIVES! :/
|
||||
rel = xs_RoundToInt // OMG LEE KILLOUGH LIVES! :/
|
||||
(
|
||||
(float(level.WallHorizLight)
|
||||
+abs(atan(float(linedef->dy)/float(linedef->dx))/float(1.57079))
|
||||
*float(level.WallVertLight - level.WallHorizLight))
|
||||
level.WallHorizLight
|
||||
+ fabs(atan(double(linedef->dy) / linedef->dx) / 1.57079)
|
||||
* (level.WallVertLight - level.WallHorizLight)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
rel = linedef->dx==0? level.WallVertLight :
|
||||
linedef->dy==0? level.WallHorizLight : 0;
|
||||
rel = linedef->dx == 0 ? level.WallVertLight :
|
||||
linedef->dy == 0 ? level.WallHorizLight : 0;
|
||||
}
|
||||
if (pfakecontrast != NULL)
|
||||
{
|
||||
|
@ -2008,80 +2008,12 @@ int WallMost (short *mostbuf, const secplane_t &plane)
|
|||
return bad;
|
||||
}
|
||||
|
||||
void PrepWall (fixed_t *swall, 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;
|
||||
}
|
||||
*/
|
||||
|
||||
static void PrepWallRoundFix(fixed_t *lwall, fixed_t walxrepeat)
|
||||
{
|
||||
// fix for rounding errors
|
||||
fixed_t fix = (MirrorFlags & RF_XFLIP) ? walxrepeat-1 : 0;
|
||||
int x;
|
||||
|
||||
if (WallSX1 > 0)
|
||||
{
|
||||
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)
|
||||
{ // lwall = texturecolumn
|
||||
int x;
|
||||
float top, bot, i;
|
||||
float xrepeat = (float)walxrepeat;
|
||||
float ol, l, topinc, botinc;
|
||||
void PrepWall (fixed_t *swall, fixed_t *lwall, fixed_t walxrepeat)
|
||||
{ // swall = scale, lwall = texturecolumn
|
||||
double top, bot, i;
|
||||
double xrepeat = walxrepeat;
|
||||
double topinc, botinc;
|
||||
|
||||
i = (float)(WallSX1 - centerx);
|
||||
i = WallSX1 - centerx;
|
||||
top = WallUoverZorg + WallUoverZstep * i;
|
||||
bot = WallInvZorg + WallInvZstep * i;
|
||||
topinc = WallUoverZstep * 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;
|
||||
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);
|
||||
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);
|
||||
void PrepLWall (fixed_t *lwall, fixed_t walxrepeat)
|
||||
{ // lwall = texturecolumn
|
||||
double top, bot, i;
|
||||
double xrepeat = walxrepeat;
|
||||
double topinc, botinc;
|
||||
double topstep;
|
||||
|
||||
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);
|
||||
x += 4;
|
||||
}
|
||||
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);
|
||||
}
|
||||
i = WallSX1 - centerx;
|
||||
top = WallUoverZorg + WallUoverZstep * i;
|
||||
bot = WallInvZorg + WallInvZstep * i;
|
||||
topinc = WallUoverZstep * 4.f;
|
||||
botinc = WallInvZstep * 4.f;
|
||||
|
||||
// fix for rounding errors
|
||||
fixed_t fix = (MirrorFlags & RF_XFLIP) ? walxrepeat-1 : 0;
|
||||
if (WallSX1 > 0)
|
||||
top *= xrepeat;
|
||||
topstep = WallUoverZstep * xrepeat;
|
||||
|
||||
for (int x = WallSX1; x < WallSX2; x++)
|
||||
{
|
||||
for (x = WallSX1; x < WallSX2; x++)
|
||||
{
|
||||
if ((unsigned)lwall[x] >= (unsigned)walxrepeat)
|
||||
{
|
||||
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;
|
||||
}
|
||||
lwall[x] = xs_RoundToInt(top / bot);
|
||||
top += topstep;
|
||||
bot += WallInvZstep;
|
||||
}
|
||||
PrepWallRoundFix(lwall, walxrepeat);
|
||||
}
|
||||
|
||||
// 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