- rewrote SW portal setup to use static data instead of ad-hoc setup.

This was by far the messiest game, there's two reasons for this.
First, the portal links do not need to be in an actual portal sector, so they cannot be used to detect portal sectors.
Second, the game moves portals in place, so all offsets are (0,0,0) so that not even these can be used for detection.

The only working method is the super-complicated original way to look up portals at run time, just being done at map start.
Having static portal links should reduce the render glitches quite significantly because the renderer knows now which sectors belong to a portal and can use this information to ensure proper processing.
This commit is contained in:
Christoph Oelckers 2021-03-25 21:21:48 +01:00
parent af54cf3a3c
commit f6568fee0c
9 changed files with 179 additions and 95 deletions

View file

@ -103,7 +103,6 @@ struct GameInterface
virtual int chaseCamY(binangle ang) { return 0; }
virtual int chaseCamZ(fixedhoriz horiz) { return 0; }
virtual void processSprites(int viewx, int viewy, int viewz, binangle viewang, double smoothRatio) {}
virtual int SetupPortal(FRenderViewpoint& vp) { return -1; }
virtual FString statFPS()
{

View file

@ -26,7 +26,7 @@ inline int portalAdd(int type, int target, int dx = 0, int dy = 0, int dz = 0)
{
auto& pt = allPortals[allPortals.Reserve(1)];
pt.type = type;
pt.targets.Push(target);
if (target >= 0) pt.targets.Push(target);
pt.dx = dx;
pt.dy = dy;
pt.dz = dz;

View file

@ -120,15 +120,6 @@ void BunchDrawer::DeleteBunch(int index)
bool BunchDrawer::CheckClip(walltype* wal)
{
#ifdef _DEBUG
if (wal - wall == 843 || wal - wall == 847)
{
int a = 0;
}
#endif
auto pt2 = &wall[wal->point2];
sectortype* backsector = &sector[wal->nextsector];
sectortype* frontsector = &sector[wall[wal->nextwall].nextsector];
@ -137,10 +128,6 @@ bool BunchDrawer::CheckClip(walltype* wal)
if (frontsector->ceilingstat & backsector->ceilingstat & CSTAT_SECTOR_SKY) return false;
if (frontsector->floorstat & backsector->floorstat & CSTAT_SECTOR_SKY) return false;
// if we are in a sector portal, no two sided line may clip.
// originally this was achieved by temporarily altering the map geometry in the portal sectors.
if (portalState.insectorportal) return false;
float bs_floorheight1;
float bs_floorheight2;
float bs_ceilingheight1;

View file

@ -814,20 +814,10 @@ bool HWSectorStackPortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *c
auto portal = origin;
auto &vp = di->Viewpoint;
if (portal)
{
vp.Pos += DVector3(portal->dx / 16., portal->dy / -16., portal->dz / -256.);
vp.SectNums = portal->targets.Data();
vp.SectCount = portal->targets.Size();
type = origin->type;
}
else
{
if (state->renderdepth > 1) return false; // there is no way to make these portals recursive.
// Shadow Warrior's portals are too poorly defined so that the static approach won't work.
type = gi->SetupPortal(vp);
if (type == -1) return false;
}
state->insectorportal = true;
// avoid recursions!

View file

@ -84,7 +84,7 @@ void HWWall::SkyPlane(HWDrawInfo *di, sectortype *sector, int plane, bool allowr
if ((sector->portalflags == PORTAL_SECTOR_CEILING && plane == plane_ceiling) || (sector->portalflags == PORTAL_SECTOR_FLOOR && plane == plane_floor))
{
if (screen->instack[1 - plane] || sector->portalnum >= (int)allPortals.Size()) return;
portal = sector->portalnum < 0? nullptr : &allPortals[sector->portalnum];
portal = &allPortals[sector->portalnum];
PutPortal(di, PORTALTYPE_SECTORSTACK, plane);
}
else if ((sector->portalflags == PORTAL_SECTOR_CEILING_REFLECT && plane == plane_ceiling) || (sector->portalflags == PORTAL_SECTOR_FLOOR_REFLECT && plane == plane_floor))

View file

@ -1438,26 +1438,6 @@ void UpdateWallPortalState()
}
}
}
// The entire setup here is so catastrophically bad that we have to completely rely on the original information.
for (int i = 0; i < numsectors; i++)
{
if (sector[i].ceilingpicnum == FAF_MIRROR_PIC)
{
sector[i].portalflags = PORTAL_SECTOR_CEILING;
sector[i].portalnum = -1;
}
else if (sector[i].floorpicnum == FAF_MIRROR_PIC)
{
sector[i].portalflags = PORTAL_SECTOR_FLOOR;
sector[i].portalnum = -1;
}
else
{
sector[i].portalflags = 0;
sector[i].portalnum = -1;
}
}
}

View file

@ -408,6 +408,7 @@ void InitLevel(MapRecord *maprec)
PostSetupSectorObject();
SetupMirrorTiles();
initlava();
CollectPortals();
// reset NewGame
NewGame = false;

View file

@ -1969,21 +1969,14 @@ void SetOwner(short, short);
void SetAttach(short, short);
void analyzesprites(int,int,int,bool);
void ChangeState(short SpriteNum, STATEp statep);
void CollectPortals();
void UpdateSectorFAF_Connect(short SpriteNum, int newz);
#if 0
bool FAF_ConnectCeiling(short sectnum);
bool FAF_ConnectFloor(short sectnum);
#else
#define FAF_PLACE_MIRROR_PIC 341
#define FAF_MIRROR_PIC 2356
#define FAF_ConnectCeiling(sectnum) (sector[(sectnum)].ceilingpicnum == FAF_MIRROR_PIC)
#define FAF_ConnectFloor(sectnum) (sector[(sectnum)].floorpicnum == FAF_MIRROR_PIC)
#define FAF_ConnectArea(sectnum) (FAF_ConnectCeiling(sectnum) || FAF_ConnectFloor(sectnum))
#endif
//void updatesectorz(int, int, int, short *);
void FAF_ConnectPlayerCeiling(PLAYERp pp);
void FAF_ConnectPlayerFloor(PLAYERp pp);
bool PlayerCeilingHit(PLAYERp pp, int zlimit);
bool PlayerFloorHit(PLAYERp pp, int zlimit);
@ -2255,7 +2248,6 @@ struct GameInterface : ::GameInterface
int chaseCamX(binangle ang) { return -ang.bcos(-3); }
int chaseCamY(binangle ang) { return -ang.bsin(-3); }
int chaseCamZ(fixedhoriz horiz) { return horiz.asq16() >> 8; }
int SetupPortal(FRenderViewpoint& vp) override;
GameStats getStats() override;

View file

@ -689,7 +689,7 @@ GetUpperLowerSector(short match, int x, int y, short *upper, short *lower)
int sln = 0;
int SpriteNum;
SPRITEp sp;
#if 0
// keep a list of the last stacked sectors the view was in and
// check those fisrt
sln = 0;
@ -720,12 +720,13 @@ GetUpperLowerSector(short match, int x, int y, short *upper, short *lower)
sln++;
}
}
#endif
// didn't find it yet so test ALL sectors
if (sln < 2)
{
sln = 0;
for (i = numsectors - 1; i >= 0; i--)
for (i = 0; i < numsectors; i++)// - 1; i >= 0; i--)
{
if (inside(x, y, (short) i) == 1)
{
@ -1020,45 +1021,179 @@ FindViewSectorInScene(short cursectnum, short level)
return -1;
}
int GameInterface::SetupPortal(FRenderViewpoint &vp)
struct PortalGroup
{
short i;
short match;
TArray<int> sectors;
int othersector = -1;
vec3_t offset = { 0,0,0 };
};
save.zcount = 0;
int16_t tsectnum = int16_t(vp.SectNums == nullptr ? vp.SectCount : vp.SectNums[0]);
int tx = vp.Pos.X * 16;
int ty = vp.Pos.Y * -16;
int tz = vp.Pos.Z * -128;
int type = -1;
int looktype = -1;
// This is very messy because some portals are linked outside the actual portal sectors, so we have to use the complicated original linking logic to find the connection. :?
void CollectPortals()
{
int t = testnewrenderer;
testnewrenderer = true;
TArray<PortalGroup> floorportals;
TArray<PortalGroup> ceilingportals;
FixedBitArray<MAXSECTORS> floordone, ceilingdone;
match = FindViewSectorInScene(tsectnum, VIEW_LEVEL1);
floordone.Zero();
ceilingdone.Zero();
for (int i = 0; i < numsectors; i++)
{
if (sector[i].floorpicnum == FAF_MIRROR_PIC && !floordone[i])
{
auto& fp = floorportals[floorportals.Reserve(1)];
fp.sectors.Push(i);
floordone.Set(i);
for (unsigned ii = 0; ii < fp.sectors.Size(); ii++)
{
auto sec = &sector[fp.sectors[ii]];
for (int w = 0; w < sec->wallnum; w++)
{
auto ns = wall[sec->wallptr + w].nextsector;
if (ns < 0 || floordone[ns] || sector[ns].floorpicnum != FAF_MIRROR_PIC) continue;
fp.sectors.Push(ns);
floordone.Set(ns);
}
}
}
if (sector[i].ceilingpicnum == FAF_MIRROR_PIC && !ceilingdone[i])
{
auto& fp = ceilingportals[ceilingportals.Reserve(1)];
fp.sectors.Push(i);
ceilingdone.Set(i);
for (unsigned ii = 0; ii < fp.sectors.Size(); ii++)
{
auto sec = &sector[fp.sectors[ii]];
for (int w = 0; w < sec->wallnum; w++)
{
auto ns = wall[sec->wallptr + w].nextsector;
if (ns < 0 || ceilingdone[ns] || sector[ns].ceilingpicnum != FAF_MIRROR_PIC) continue;
fp.sectors.Push(ns);
ceilingdone.Set(ns);
}
}
}
}
// now try to find connections.
for (auto& fp : ceilingportals)
{
// pick one sprite out of the sectors, repeat until we get a valid connection
for (auto sec : fp.sectors)
{
SectIterator it(sec);
int spr;
while ((spr = it.NextIndex()) >= 0)
{
int tx = sprite[spr].x;
int ty = sprite[spr].y;
int tz = sprite[spr].z;
int16_t tsectnum = sec;
int match = FindViewSectorInScene(tsectnum, VIEW_LEVEL1);
if (match != -1)
{
FindCeilingView(match, &tx, &ty, tz, &tsectnum);
type = PORTAL_SECTOR_CEILING;
if (tsectnum < 0)
return -1;
}
else
if (tsectnum >= 0 && sector[tsectnum].floorpicnum == FAF_MIRROR_PIC)
{
match = FindViewSectorInScene(tsectnum, VIEW_LEVEL2);
// got something!
fp.othersector = tsectnum;
fp.offset = { tx, ty, tz };
fp.offset -= sprite[spr].pos;
goto nextfg;
}
}
}
}
nextfg:;
}
for (auto& fp : floorportals)
{
for (auto sec : fp.sectors)
{
SectIterator it(sec);
int spr;
while ((spr = it.NextIndex()) >= 0)
{
int tx = sprite[spr].x;
int ty = sprite[spr].y;
int tz = sprite[spr].z;
int16_t tsectnum = sec;
int match = FindViewSectorInScene(tsectnum, VIEW_LEVEL2);
if (match != -1)
{
FindFloorView(match, &tx, &ty, tz, &tsectnum);
type = PORTAL_SECTOR_FLOOR;
if (tsectnum < 0)
return -1;
if (tsectnum >= 0 && sector[tsectnum].ceilingpicnum == FAF_MIRROR_PIC)
{
// got something!
fp.othersector = tsectnum;
fp.offset = { tx, ty, tz };
fp.offset -= sprite[spr].pos;
goto nextcg;
}
}
vp.Pos = { tx / 16.f, ty / -16.f, tz / -128.f };
vp.SectNums = nullptr;
vp.SectCount = tsectnum;
return type;
}
}
nextcg:;
}
for (auto& pt : floorportals)
{
if (pt.othersector > -1)
{
auto findother = [&](int other) -> PortalGroup*
{
for (auto& pt2 : ceilingportals)
{
if (pt2.sectors.Find(other) != pt2.sectors.Size()) return &pt2;
}
return nullptr;
};
auto pt2 = findother(pt.othersector);
if (pt2)
{
int pnum = portalAdd(PORTAL_SECTOR_FLOOR, -1, pt.offset.x, pt.offset.y, 0);
allPortals[pnum].targets = pt2->sectors; // do not move! We still need the original.
for (auto sec : pt.sectors)
{
sector[sec].portalflags = PORTAL_SECTOR_FLOOR;
sector[sec].portalnum = pnum;
}
}
}
}
for (auto& pt : ceilingportals)
{
if (pt.othersector > -1)
{
auto findother = [&](int other) -> PortalGroup*
{
for (auto& pt2 : floorportals)
{
if (pt2.sectors.Find(other) != pt2.sectors.Size()) return &pt2;
}
return nullptr;
};
auto pt2 = findother(pt.othersector);
if (pt2)
{
int pnum = portalAdd(PORTAL_SECTOR_FLOOR, -1, pt.offset.x, pt.offset.y, 0);
allPortals[pnum].targets = std::move(pt2->sectors);
for (auto sec : pt.sectors)
{
sector[sec].portalflags = PORTAL_SECTOR_CEILING;
sector[sec].portalnum = pnum;
}
}
}
}
testnewrenderer = false;
}
END_SW_NS