mirror of
https://github.com/ZDoom/zdbsp.git
synced 2024-11-30 23:51:55 +00:00
24d4f0b45c
SVN r12 (trunk)
215 lines
5 KiB
C++
215 lines
5 KiB
C++
// The old code used the same algorithm as DoomBSP:
|
|
//
|
|
// Represent each sector by its bounding box. Then for each pair of
|
|
// sectors, see if any chains of one-sided lines can walk from one
|
|
// side of the convex hull for that pair to the other side.
|
|
//
|
|
// It works, but it's far from being perfect. It's quite easy for
|
|
// this algorithm to consider two sectors as being visible from
|
|
// each other when they are really not. But it won't erroneously
|
|
// flag two sectors as obstructed when they're really not, and that's
|
|
// the only thing that really matters when building a REJECT lump.
|
|
//
|
|
// Because that was next to useless, I scrapped that code and adapted
|
|
// Quake's vis utility to work in a 2D world. Since this is basically vis,
|
|
// it depends on GL nodes being present to function. As the usefulness
|
|
// of a REJECT lump is debatable, I have chosen to not compile this module
|
|
// in with ZDBSP. Save yourself some space and run ZDBSP with the -r option.
|
|
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
#include "zdbsp.h"
|
|
#include "nodebuild.h"
|
|
#include "rejectbuilder.h"
|
|
#include "templates.h"
|
|
|
|
bool MergeVis=1;
|
|
|
|
FRejectBuilder::FRejectBuilder (FLevel &level)
|
|
: Level (level), testlevel (2), totalvis (0)
|
|
{
|
|
LoadPortals ();
|
|
|
|
if (MergeVis)
|
|
{
|
|
MergeLeaves ();
|
|
MergeLeafPortals ();
|
|
}
|
|
|
|
CountActivePortals ();
|
|
CalcVis ();
|
|
|
|
BuildReject ();
|
|
}
|
|
|
|
FRejectBuilder::~FRejectBuilder ()
|
|
{
|
|
}
|
|
|
|
BYTE *FRejectBuilder::GetReject ()
|
|
{
|
|
WORD *sectormap;
|
|
int i, j;
|
|
|
|
int rejectSize = (Level.NumSectors*Level.NumSectors + 7) / 8;
|
|
BYTE *reject = new BYTE[rejectSize];
|
|
memset (reject, 0xff, rejectSize);
|
|
|
|
int pvs_size = (Level.NumGLSubsectors * Level.NumGLSubsectors) + 7 / 8;
|
|
Level.GLPVS = new BYTE[pvs_size];
|
|
Level.GLPVSSize = pvs_size;
|
|
memset (Level.GLPVS, 0, pvs_size);
|
|
|
|
sectormap = new WORD[Level.NumGLSubsectors];
|
|
for (i = 0; i < Level.NumGLSubsectors; ++i)
|
|
{
|
|
const MapSegGLEx *seg = &Level.GLSegs[Level.GLSubsectors[i].firstline];
|
|
sectormap[i] = Level.Sides[Level.Lines[seg->linedef].sidenum[seg->side]].sector;
|
|
}
|
|
|
|
for (i = 0; i < Level.NumGLSubsectors; ++i)
|
|
{
|
|
int rowpvs = i*Level.NumGLSubsectors;
|
|
int rowrej = sectormap[i]*Level.NumSectors;
|
|
BYTE *bytes = visBytes + i*leafbytes;
|
|
for (j = 0; j < Level.NumGLSubsectors; ++j)
|
|
{
|
|
if (bytes[j>>3] & (1<<(j&7)))
|
|
{
|
|
int mark = rowpvs + j;
|
|
Level.GLPVS[mark>>3] |= 1<<(mark&7);
|
|
|
|
mark = rowrej + sectormap[j];
|
|
reject[mark>>3] &= ~(1<<(mark&7));
|
|
}
|
|
}
|
|
}
|
|
|
|
return reject;
|
|
}
|
|
|
|
void FRejectBuilder::BuildReject ()
|
|
{
|
|
}
|
|
|
|
inline const WideVertex *FRejectBuilder::GetVertex (WORD vertnum)
|
|
{
|
|
return &Level.Vertices[vertnum];
|
|
}
|
|
|
|
FRejectBuilder::FLeaf::FLeaf ()
|
|
: numportals (0), merged (-1), portals (NULL)
|
|
{
|
|
}
|
|
|
|
FRejectBuilder::FLeaf::~FLeaf ()
|
|
{
|
|
if (portals != NULL)
|
|
{
|
|
delete[] portals;
|
|
}
|
|
}
|
|
|
|
int FRejectBuilder::PointOnSide (const FPoint &point, const FLine &line)
|
|
{
|
|
return FNodeBuilder::PointOnSide (point.x, point.y, line.x, line.y, line.dx, line.dy);
|
|
}
|
|
|
|
void FRejectBuilder::LoadPortals ()
|
|
{
|
|
WORD *segleaf;
|
|
int i, j, k, max;
|
|
VPortal *p;
|
|
FLeaf *l;
|
|
FWinding *w;
|
|
|
|
portalclusters = Level.NumGLSubsectors;
|
|
|
|
for (numportals = 0, i = 0; i < Level.NumGLSegs; ++i)
|
|
{
|
|
if (Level.GLSegs[i].partner != DWORD_MAX)
|
|
{
|
|
++numportals;
|
|
}
|
|
}
|
|
|
|
// these counts should take advantage of 64 bit systems automatically
|
|
leafbytes = ((portalclusters+63)&~63)>>3;
|
|
leaflongs = leafbytes/sizeof(long);
|
|
|
|
portalbytes = ((numportals+63)&~63)>>3;
|
|
portallongs = portalbytes/sizeof(long);
|
|
|
|
portals = new VPortal[numportals];
|
|
memset (portals, 0, numportals*sizeof(VPortal));
|
|
|
|
leafs = new FLeaf[portalclusters];
|
|
|
|
numVisBytes = portalclusters*leafbytes;
|
|
visBytes = new BYTE[numVisBytes];
|
|
|
|
segleaf = new WORD[Level.NumGLSegs];
|
|
for (i = 0; i < Level.NumGLSubsectors; ++i)
|
|
{
|
|
j = Level.GLSubsectors[i].firstline;
|
|
max = j + Level.GLSubsectors[i].numlines;
|
|
|
|
for (; j < max; ++j)
|
|
{
|
|
segleaf[j] = i;
|
|
}
|
|
}
|
|
|
|
p = portals;
|
|
l = leafs;
|
|
for (i = 0; i < Level.NumGLSubsectors; ++i, ++l)
|
|
{
|
|
j = Level.GLSubsectors[i].firstline;
|
|
max = j + Level.GLSubsectors[i].numlines;
|
|
|
|
// Count portals in this leaf
|
|
for (; j < max; ++j)
|
|
{
|
|
if (Level.GLSegs[j].partner != DWORD_MAX)
|
|
{
|
|
++l->numportals;
|
|
}
|
|
}
|
|
|
|
if (l->numportals == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
l->portals = new VPortal *[l->numportals];
|
|
|
|
for (k = 0, j = Level.GLSubsectors[i].firstline; j < max; ++j)
|
|
{
|
|
const MapSegGLEx *seg = &Level.GLSegs[j];
|
|
|
|
if (seg->partner == DWORD_MAX)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// create portal from seg
|
|
l->portals[k++] = p;
|
|
|
|
w = &p->winding;
|
|
w->points[0] = GetVertex (seg->v1);
|
|
w->points[1] = GetVertex (seg->v2);
|
|
|
|
p->hint = seg->linedef != NO_INDEX;
|
|
p->line.x = w->points[1].x;
|
|
p->line.y = w->points[1].y;
|
|
p->line.dx = w->points[0].x - p->line.x;
|
|
p->line.dy = w->points[0].y - p->line.y;
|
|
p->leaf = segleaf[seg->partner];
|
|
|
|
p++;
|
|
}
|
|
}
|
|
|
|
delete[] segleaf;
|
|
}
|