From f6568fee0c6dd534345e5a616cb4d53015fd65e4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 25 Mar 2021 21:21:48 +0100 Subject: [PATCH] - 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. --- source/core/gamestruct.h | 1 - source/core/rendering/render.h | 2 +- .../core/rendering/scene/hw_bunchdrawer.cpp | 13 -- source/core/rendering/scene/hw_portal.cpp | 18 +- source/core/rendering/scene/hw_sky.cpp | 2 +- source/games/sw/src/draw.cpp | 20 -- source/games/sw/src/game.cpp | 1 + source/games/sw/src/game.h | 14 +- source/games/sw/src/rooms.cpp | 203 +++++++++++++++--- 9 files changed, 179 insertions(+), 95 deletions(-) diff --git a/source/core/gamestruct.h b/source/core/gamestruct.h index d176c1870..f32c9ac1d 100644 --- a/source/core/gamestruct.h +++ b/source/core/gamestruct.h @@ -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() { diff --git a/source/core/rendering/render.h b/source/core/rendering/render.h index f089a8c47..89eb28477 100644 --- a/source/core/rendering/render.h +++ b/source/core/rendering/render.h @@ -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; diff --git a/source/core/rendering/scene/hw_bunchdrawer.cpp b/source/core/rendering/scene/hw_bunchdrawer.cpp index 117095b2d..9ab483aba 100644 --- a/source/core/rendering/scene/hw_bunchdrawer.cpp +++ b/source/core/rendering/scene/hw_bunchdrawer.cpp @@ -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 = §or[wal->nextsector]; sectortype* frontsector = §or[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; diff --git a/source/core/rendering/scene/hw_portal.cpp b/source/core/rendering/scene/hw_portal.cpp index 165c72aef..70bad241f 100644 --- a/source/core/rendering/scene/hw_portal.cpp +++ b/source/core/rendering/scene/hw_portal.cpp @@ -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; - } + 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; state->insectorportal = true; // avoid recursions! diff --git a/source/core/rendering/scene/hw_sky.cpp b/source/core/rendering/scene/hw_sky.cpp index 01049b3aa..523657396 100644 --- a/source/core/rendering/scene/hw_sky.cpp +++ b/source/core/rendering/scene/hw_sky.cpp @@ -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)) diff --git a/source/games/sw/src/draw.cpp b/source/games/sw/src/draw.cpp index cac77fcba..38a0ae41a 100644 --- a/source/games/sw/src/draw.cpp +++ b/source/games/sw/src/draw.cpp @@ -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; - } - } } diff --git a/source/games/sw/src/game.cpp b/source/games/sw/src/game.cpp index ec39e50a8..0a50d29a6 100644 --- a/source/games/sw/src/game.cpp +++ b/source/games/sw/src/game.cpp @@ -408,6 +408,7 @@ void InitLevel(MapRecord *maprec) PostSetupSectorObject(); SetupMirrorTiles(); initlava(); + CollectPortals(); // reset NewGame NewGame = false; diff --git a/source/games/sw/src/game.h b/source/games/sw/src/game.h index 0d70bd1a8..9d9c1115d 100644 --- a/source/games/sw/src/game.h +++ b/source/games/sw/src/game.h @@ -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,8 +2248,7 @@ 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; }; diff --git a/source/games/sw/src/rooms.cpp b/source/games/sw/src/rooms.cpp index 4f9d890b2..2d18da39a 100644 --- a/source/games/sw/src/rooms.cpp +++ b/source/games/sw/src/rooms.cpp @@ -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 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 floorportals; + TArray ceilingportals; + FixedBitArray floordone, ceilingdone; - match = FindViewSectorInScene(tsectnum, VIEW_LEVEL1); - if (match != -1) + floordone.Zero(); + ceilingdone.Zero(); + + for (int i = 0; i < numsectors; i++) { - FindCeilingView(match, &tx, &ty, tz, &tsectnum); - type = PORTAL_SECTOR_CEILING; - - if (tsectnum < 0) - return -1; - } - else - { - match = FindViewSectorInScene(tsectnum, VIEW_LEVEL2); - if (match != -1) + if (sector[i].floorpicnum == FAF_MIRROR_PIC && !floordone[i]) { - FindFloorView(match, &tx, &ty, tz, &tsectnum); - type = PORTAL_SECTOR_FLOOR; - - if (tsectnum < 0) - return -1; - + auto& fp = floorportals[floorportals.Reserve(1)]; + fp.sectors.Push(i); + floordone.Set(i); + for (unsigned ii = 0; ii < fp.sectors.Size(); ii++) + { + auto sec = §or[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 = §or[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); + } + } } } - vp.Pos = { tx / 16.f, ty / -16.f, tz / -128.f }; - vp.SectNums = nullptr; - vp.SectCount = tsectnum; - return type; + // 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); + if (tsectnum >= 0 && sector[tsectnum].floorpicnum == FAF_MIRROR_PIC) + { + // 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); + 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; + } + } + } + } + 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