diff --git a/source/build/include/buildtypes.h b/source/build/include/buildtypes.h index 50db1257a..d06f03cda 100644 --- a/source/build/include/buildtypes.h +++ b/source/build/include/buildtypes.h @@ -67,7 +67,7 @@ struct sectortype uint8_t dirty; float ceilingxpan_, ceilingypan_, floorxpan_, floorypan_; uint8_t portalflags; - uint8_t portalnum; + int8_t portalnum; int ceilingxpan() const { return int(ceilingxpan_); } int ceilingypan() const { return int(ceilingypan_); } diff --git a/source/core/gamestruct.h b/source/core/gamestruct.h index 5a073cd35..d176c1870 100644 --- a/source/core/gamestruct.h +++ b/source/core/gamestruct.h @@ -11,6 +11,7 @@ bool System_WantGuiCapture(); // During playing this tells us whether the game m #include "inputstate.h" class FSerializer; +struct FRenderViewpoint; struct GameStats { @@ -102,6 +103,7 @@ 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/scene/hw_bunchdrawer.cpp b/source/core/rendering/scene/hw_bunchdrawer.cpp index 713b339d2..117095b2d 100644 --- a/source/core/rendering/scene/hw_bunchdrawer.cpp +++ b/source/core/rendering/scene/hw_bunchdrawer.cpp @@ -38,6 +38,7 @@ #include "hw_drawstructs.h" #include "automap.h" #include "gamefuncs.h" +#include "hw_portal.h" //========================================================================== @@ -136,6 +137,10 @@ 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 72a569343..165c72aef 100644 --- a/source/core/rendering/scene/hw_portal.cpp +++ b/source/core/rendering/scene/hw_portal.cpp @@ -32,6 +32,7 @@ #include "flatvertices.h" #include "hw_clock.h" #include "texturemanager.h" +#include "gamestruct.h" EXTERN_CVAR(Int, r_mirror_recursions) EXTERN_CVAR(Bool, gl_portals) @@ -813,12 +814,24 @@ bool HWSectorStackPortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *c auto portal = origin; auto &vp = di->Viewpoint; - vp.Pos += DVector3(portal->dx / 16., portal->dy / -16., portal->dz / -256.); - vp.SectNums = portal->targets.Data(); - vp.SectCount = portal->targets.Size(); + 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! - screen->instack[origin->type == PORTAL_SECTOR_CEILING ? 1 : 0]++; + screen->instack[type == PORTAL_SECTOR_CEILING ? 1 : 0]++; di->SetupView(rstate, vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(state->MirrorFlag & 1), !!(state->PlaneMirrorFlag & 1)); //SetupCoverage(di); @@ -830,7 +843,8 @@ bool HWSectorStackPortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *c void HWSectorStackPortal::Shutdown(HWDrawInfo *di, FRenderState &rstate) { - screen->instack[origin->type == PORTAL_SECTOR_CEILING ? 1 : 0]--; + screen->instack[type == PORTAL_SECTOR_CEILING ? 1 : 0]--; + mState->insectorportal = false; } const char *HWSectorStackPortal::GetName() { return "Sectorstack"; } diff --git a/source/core/rendering/scene/hw_portal.h b/source/core/rendering/scene/hw_portal.h index 6b41fdeb3..3001af0c2 100644 --- a/source/core/rendering/scene/hw_portal.h +++ b/source/core/rendering/scene/hw_portal.h @@ -182,6 +182,7 @@ struct FPortalSceneState int PlaneMirrorMode = 0; bool inskybox = 0; + bool insectorportal = false; UniqueList UniqueSkies; UniqueList UniqueHorizons; @@ -350,6 +351,7 @@ public: struct HWSectorStackPortal : public HWScenePortalBase { TArray sectors; + int type = -1; protected: bool Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clipper) override; void Shutdown(HWDrawInfo *di, FRenderState &rstate) override; diff --git a/source/core/rendering/scene/hw_sky.cpp b/source/core/rendering/scene/hw_sky.cpp index 5d0f575b3..01049b3aa 100644 --- a/source/core/rendering/scene/hw_sky.cpp +++ b/source/core/rendering/scene/hw_sky.cpp @@ -81,13 +81,13 @@ void HWWall::SkyPlane(HWDrawInfo *di, sectortype *sector, int plane, bool allowr { int ptype; - if (sector->portalflags == PORTAL_SECTOR_CEILING || sector->portalflags == PORTAL_SECTOR_FLOOR) + if ((sector->portalflags == PORTAL_SECTOR_CEILING && plane == plane_ceiling) || (sector->portalflags == PORTAL_SECTOR_FLOOR && plane == plane_floor)) { - if (screen->instack[1 - plane] || allPortals.Size() == 0) return; - portal = &allPortals[sector->portalnum]; + if (screen->instack[1 - plane] || sector->portalnum >= (int)allPortals.Size()) return; + portal = sector->portalnum < 0? nullptr : &allPortals[sector->portalnum]; PutPortal(di, PORTALTYPE_SECTORSTACK, plane); } - else if (sector->portalflags == PORTAL_SECTOR_CEILING_REFLECT || sector->portalflags == PORTAL_SECTOR_FLOOR_REFLECT) + else if ((sector->portalflags == PORTAL_SECTOR_CEILING_REFLECT && plane == plane_ceiling) || (sector->portalflags == PORTAL_SECTOR_FLOOR_REFLECT && plane == plane_floor)) { ptype = PORTALTYPE_PLANEMIRROR; if (plane == plane_ceiling && (sector->ceilingstat & CSTAT_SECTOR_SLOPE)) return; diff --git a/source/games/sw/src/_polymost.cpp b/source/games/sw/src/_polymost.cpp index 739faf36b..e62edaefa 100644 --- a/source/games/sw/src/_polymost.cpp +++ b/source/games/sw/src/_polymost.cpp @@ -1,310 +1,7 @@ BEGIN_SW_NS -short GlobStackSect[2]; - -void -GetUpperLowerSector(short match, int x, int y, short* upper, short* lower) -{ - int i; - short sectorlist[16]; - int sln = 0; - int SpriteNum; - SPRITEp sp; - - // keep a list of the last stacked sectors the view was in and - // check those fisrt - sln = 0; - for (i = 0; i < (int)SIZ(GlobStackSect); i++) - { - // will not hurt if GlobStackSect is invalid - inside checks for this - if (inside(x, y, GlobStackSect[i]) == 1) - { - bool found = false; - - SectIterator it(GlobStackSect[i]); - while ((SpriteNum = it.NextIndex()) >= 0) - { - sp = &sprite[SpriteNum]; - - if (sp->statnum == STAT_FAF && - (sp->hitag >= VIEW_LEVEL1 && sp->hitag <= VIEW_LEVEL6) - && sp->lotag == match) - { - found = true; - } - } - - if (!found) - continue; - - sectorlist[sln] = GlobStackSect[i]; - sln++; - } - } - - // didn't find it yet so test ALL sectors - if (sln < 2) - { - sln = 0; - for (i = numsectors - 1; i >= 0; i--) - { - if (inside(x, y, (short)i) == 1) - { - bool found = false; - - SectIterator it(i); - while ((SpriteNum = it.NextIndex()) >= 0) - { - sp = &sprite[SpriteNum]; - - if (sp->statnum == STAT_FAF && - (sp->hitag >= VIEW_LEVEL1 && sp->hitag <= VIEW_LEVEL6) - && sp->lotag == match) - { - found = true; - } - } - - if (!found) - continue; - - if (sln < (int)SIZ(GlobStackSect)) - GlobStackSect[sln] = i; - if (sln < (int)SIZ(sectorlist)) - sectorlist[sln] = i; - sln++; - } - } - } - - // might not find ANYTHING if not tagged right - if (sln == 0) - { - *upper = -1; - *lower = -1; - return; - } - // Map rooms have NOT been dragged on top of each other - else if (sln == 1) - { - *lower = sectorlist[0]; - *upper = sectorlist[0]; - return; - } - // Map rooms HAVE been dragged on top of each other - // inside will somtimes find that you are in two different sectors if the x,y - // is exactly on a sector line. - else if (sln > 2) - { - //DSPRINTF(ds, "TOO MANY SECTORS FOUND: x=%d, y=%d, match=%d, num sectors %d, %d, %d, %d, %d, %d", x, y, match, sln, sectorlist[0], sectorlist[1], sectorlist[2], sectorlist[3], sectorlist[4]); - MONO_PRINT(ds); - // try again moving the x,y pos around until you only get two sectors - GetUpperLowerSector(match, x - 1, y, upper, lower); - } - - if (sln == 2) - { - if (sector[sectorlist[0]].floorz < sector[sectorlist[1]].floorz) - { - // swap - // make sectorlist[0] the LOW sector - short hold; - - hold = sectorlist[0]; - sectorlist[0] = sectorlist[1]; - sectorlist[1] = hold; - } - - *lower = sectorlist[0]; - *upper = sectorlist[1]; - } -} - - -bool -FindCeilingView(short match, int32_t* x, int32_t* y, int32_t z, int16_t* sectnum) -{ - int xoff = 0; - int yoff = 0; - int i; - SPRITEp sp = NULL; - int pix_diff; - int newz; - - save.zcount = 0; - - // Search Stat List For closest ceiling view sprite - // Get the match, xoff, yoff from this point - StatIterator it(STAT_FAF); - while ((i = it.NextIndex()) >= 0) - { - sp = &sprite[i]; - - if (sp->hitag == VIEW_THRU_CEILING && sp->lotag == match) - { - xoff = *x - sp->x; - yoff = *y - sp->y; - break; - } - } - - it.Reset(STAT_FAF); - while ((i = it.NextIndex()) >= 0) - { - sp = &sprite[i]; - - if (sp->lotag == match) - { - // determine x,y position - if (sp->hitag == VIEW_THRU_FLOOR) - { - short upper, lower; - - *x = sp->x + xoff; - *y = sp->y + yoff; - - // get new sector - GetUpperLowerSector(match, *x, *y, &upper, &lower); - *sectnum = upper; - break; - } - } - } - - if (*sectnum < 0) - return false; - - ASSERT(sp); - ASSERT(sp->hitag == VIEW_THRU_FLOOR); - - pix_diff = labs(z - sector[sp->sectnum].floorz) >> 8; - newz = sector[sp->sectnum].floorz + ((pix_diff / 128) + 1) * Z(128); - - it.Reset(STAT_FAF); - while ((i = it.NextIndex()) >= 0) - { - sp = &sprite[i]; - - if (sp->lotag == match) - { - // move lower levels ceilings up for the correct view - if (sp->hitag == VIEW_LEVEL2) - { - // save it off - save.sectnum[save.zcount] = sp->sectnum; - save.zval[save.zcount] = sector[sp->sectnum].floorz; - save.pic[save.zcount] = sector[sp->sectnum].floorpicnum; - save.slope[save.zcount] = sector[sp->sectnum].floorheinum; - - sector[sp->sectnum].floorz = newz; - // don't change FAF_MIRROR_PIC - ConnectArea - if (sector[sp->sectnum].floorpicnum != FAF_MIRROR_PIC) - sector[sp->sectnum].floorpicnum = FAF_MIRROR_PIC + 1; - sector[sp->sectnum].floorheinum = 0; - - save.zcount++; - PRODUCTION_ASSERT(save.zcount < ZMAX); - } - } - } - - return true; -} - - -bool -FindFloorView(short match, int32_t* x, int32_t* y, int32_t z, int16_t* sectnum) -{ - int xoff = 0; - int yoff = 0; - int i; - SPRITEp sp = NULL; - int newz; - int pix_diff; - - save.zcount = 0; - - // Search Stat List For closest ceiling view sprite - // Get the match, xoff, yoff from this point - StatIterator it(STAT_FAF); - while ((i = it.NextIndex()) >= 0) - { - sp = &sprite[i]; - - if (sp->hitag == VIEW_THRU_FLOOR && sp->lotag == match) - { - xoff = *x - sp->x; - yoff = *y - sp->y; - break; - } - } - - - it.Reset(STAT_FAF); - while ((i = it.NextIndex()) >= 0) - { - sp = &sprite[i]; - - if (sp->lotag == match) - { - // determine x,y position - if (sp->hitag == VIEW_THRU_CEILING) - { - short upper, lower; - - *x = sp->x + xoff; - *y = sp->y + yoff; - - // get new sector - GetUpperLowerSector(match, *x, *y, &upper, &lower); - *sectnum = lower; - break; - } - } - } - - if (*sectnum < 0) - return false; - - ASSERT(sp); - ASSERT(sp->hitag == VIEW_THRU_CEILING); - - // move ceiling multiple of 128 so that the wall tile will line up - pix_diff = labs(z - sector[sp->sectnum].ceilingz) >> 8; - newz = sector[sp->sectnum].ceilingz - ((pix_diff / 128) + 1) * Z(128); - - it.Reset(STAT_FAF); - while ((i = it.NextIndex()) >= 0) - { - sp = &sprite[i]; - - if (sp->lotag == match) - { - // move upper levels floors down for the correct view - if (sp->hitag == VIEW_LEVEL1) - { - // save it off - save.sectnum[save.zcount] = sp->sectnum; - save.zval[save.zcount] = sector[sp->sectnum].ceilingz; - save.pic[save.zcount] = sector[sp->sectnum].ceilingpicnum; - save.slope[save.zcount] = sector[sp->sectnum].ceilingheinum; - - sector[sp->sectnum].ceilingz = newz; - - // don't change FAF_MIRROR_PIC - ConnectArea - if (sector[sp->sectnum].ceilingpicnum != FAF_MIRROR_PIC) - sector[sp->sectnum].ceilingpicnum = FAF_MIRROR_PIC + 1; - sector[sp->sectnum].ceilingheinum = 0; - - save.zcount++; - PRODUCTION_ASSERT(save.zcount < ZMAX); - } - } - } - - return true; -} - +bool FindCeilingView(short match, int32_t* x, int32_t* y, int32_t z, int16_t* sectnum); +bool FindFloorView(short match, int32_t* x, int32_t* y, int32_t z, int16_t* sectnum); short diff --git a/source/games/sw/src/draw.cpp b/source/games/sw/src/draw.cpp index 38a0ae41a..cac77fcba 100644 --- a/source/games/sw/src/draw.cpp +++ b/source/games/sw/src/draw.cpp @@ -1438,6 +1438,26 @@ 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 411b67e70..ec39e50a8 100644 --- a/source/games/sw/src/game.cpp +++ b/source/games/sw/src/game.cpp @@ -407,7 +407,6 @@ void InitLevel(MapRecord *maprec) PlaceActorsOnTracks(); PostSetupSectorObject(); SetupMirrorTiles(); - SetupSectorPortals(); initlava(); // reset NewGame diff --git a/source/games/sw/src/game.h b/source/games/sw/src/game.h index dff4408a0..0d70bd1a8 100644 --- a/source/games/sw/src/game.h +++ b/source/games/sw/src/game.h @@ -2135,7 +2135,6 @@ void DrawOverlapRoom(int tx,int ty,int tz,fixed_t tq16ang,fixed_t tq16horiz,shor void SetupMirrorTiles(void); // rooms.c bool FAF_Sector(short sectnum); // rooms.c int GetZadjustment(short sectnum,short hitag); // rooms.c -void SetupSectorPortals(); void InitSetup(void); // setup.c @@ -2256,6 +2255,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 36017230a..4f9d890b2 100644 --- a/source/games/sw/src/rooms.cpp +++ b/source/games/sw/src/rooms.cpp @@ -29,6 +29,7 @@ Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms #include "names2.h" #include "panel.h" #include "misc.h" +#include "hw_drawinfo.h" BEGIN_SW_NS @@ -678,50 +679,386 @@ SetupMirrorTiles(void) } } +short GlobStackSect[2]; -void SetupSectorPortals() +void +GetUpperLowerSector(short match, int x, int y, short *upper, short *lower) { - TArray foundf, foundc; - // Search Stat List For closest ceiling view sprite - // Get the match, xoff, yoff from this point - StatIterator it(STAT_FAF); int i; - while ((i = it.NextIndex()) >= 0) + short sectorlist[16]; + int sln = 0; + int SpriteNum; + SPRITEp sp; + + // keep a list of the last stacked sectors the view was in and + // check those fisrt + sln = 0; + for (i = 0; i < (int)SIZ(GlobStackSect); i++) { - auto sp = &sprite[i]; - - if (sp->hitag == VIEW_THRU_CEILING) foundc.Push(i); - if (sp->hitag == VIEW_THRU_FLOOR) foundf.Push(i); - } - - portalClear(); - while (foundf.Size()) - { - auto spf = &sprite[foundf[0]]; - auto cindex = foundc.FindEx([=](int i) { return spf->lotag == sprite[i].lotag; }); - if (cindex != foundc.Size()) + // will not hurt if GlobStackSect is invalid - inside checks for this + if (inside(x, y, GlobStackSect[i]) == 1) { - auto spc = &sprite[foundf[cindex]]; - sector[spf->sectnum].portalflags = PORTAL_SECTOR_FLOOR; - sector[spf->sectnum].portalnum = portalAdd(PORTAL_SECTOR_FLOOR, spc->sectnum, spc->x - spf->x, spc->y - spf->y, 0); + bool found = false; - sector[spc->sectnum].portalflags = PORTAL_SECTOR_CEILING; - sector[spc->sectnum].portalnum = portalAdd(PORTAL_SECTOR_CEILING, spf->sectnum, spf->x - spc->x, spf->y - spc->y, 0); + SectIterator it(GlobStackSect[i]); + while ((SpriteNum = it.NextIndex()) >= 0) + { + sp = &sprite[SpriteNum]; - //Printf("Portal with tag %d\n", sprite[foundf[0]].lotag); - foundf.Delete(0); - foundc.Delete(cindex); - } - else - { - //Printf("Floor portal %d without partner\n", sprite[foundf[0]].lotag); - foundf.Delete(0); + if (sp->statnum == STAT_FAF && + (sp->hitag >= VIEW_LEVEL1 && sp->hitag <= VIEW_LEVEL6) + && sp->lotag == match) + { + found = true; + } + } + + if (!found) + continue; + + sectorlist[sln] = GlobStackSect[i]; + sln++; } } - for (auto c : foundc) + + // didn't find it yet so test ALL sectors + if (sln < 2) { - //Printf("Ceiling portal %d without partner\n", sprite[c].lotag); + sln = 0; + for (i = numsectors - 1; i >= 0; i--) + { + if (inside(x, y, (short) i) == 1) + { + bool found = false; + + SectIterator it(i); + while ((SpriteNum = it.NextIndex()) >= 0) + { + sp = &sprite[SpriteNum]; + + if (sp->statnum == STAT_FAF && + (sp->hitag >= VIEW_LEVEL1 && sp->hitag <= VIEW_LEVEL6) + && sp->lotag == match) + { + found = true; + } + } + + if (!found) + continue; + + if (sln < (int)SIZ(GlobStackSect)) + GlobStackSect[sln] = i; + if (sln < (int)SIZ(sectorlist)) + sectorlist[sln] = i; + sln++; + } + } + } + + // might not find ANYTHING if not tagged right + if (sln == 0) + { + *upper = -1; + *lower = -1; + return; + } + // Map rooms have NOT been dragged on top of each other + else if (sln == 1) + { + *lower = sectorlist[0]; + *upper = sectorlist[0]; + return; + } + // Map rooms HAVE been dragged on top of each other + // inside will somtimes find that you are in two different sectors if the x,y + // is exactly on a sector line. + else if (sln > 2) + { + //DSPRINTF(ds, "TOO MANY SECTORS FOUND: x=%d, y=%d, match=%d, num sectors %d, %d, %d, %d, %d, %d", x, y, match, sln, sectorlist[0], sectorlist[1], sectorlist[2], sectorlist[3], sectorlist[4]); + MONO_PRINT(ds); + // try again moving the x,y pos around until you only get two sectors + GetUpperLowerSector(match, x - 1, y, upper, lower); + } + + if (sln == 2) + { + if (sector[sectorlist[0]].floorz < sector[sectorlist[1]].floorz) + { + // swap + // make sectorlist[0] the LOW sector + short hold; + + hold = sectorlist[0]; + sectorlist[0] = sectorlist[1]; + sectorlist[1] = hold; + } + + *lower = sectorlist[0]; + *upper = sectorlist[1]; } } +bool +FindCeilingView(short match, int32_t* x, int32_t* y, int32_t z, int16_t* sectnum) +{ + int xoff = 0; + int yoff = 0; + int i; + SPRITEp sp = NULL; + int pix_diff; + int newz; + + save.zcount = 0; + + // Search Stat List For closest ceiling view sprite + // Get the match, xoff, yoff from this point + StatIterator it(STAT_FAF); + while ((i = it.NextIndex()) >= 0) + { + sp = &sprite[i]; + + if (sp->hitag == VIEW_THRU_CEILING && sp->lotag == match) + { + xoff = *x - sp->x; + yoff = *y - sp->y; + break; + } + } + + it.Reset(STAT_FAF); + while ((i = it.NextIndex()) >= 0) + { + sp = &sprite[i]; + + if (sp->lotag == match) + { + // determine x,y position + if (sp->hitag == VIEW_THRU_FLOOR) + { + short upper, lower; + + *x = sp->x + xoff; + *y = sp->y + yoff; + + // get new sector + GetUpperLowerSector(match, *x, *y, &upper, &lower); + *sectnum = upper; + break; + } + } + } + + if (*sectnum < 0) + return false; + + ASSERT(sp); + ASSERT(sp->hitag == VIEW_THRU_FLOOR); + + pix_diff = labs(z - sector[sp->sectnum].floorz) >> 8; + newz = sector[sp->sectnum].floorz + ((pix_diff / 128) + 1) * Z(128); + + if (!testnewrenderer) + { + it.Reset(STAT_FAF); + while ((i = it.NextIndex()) >= 0) + { + sp = &sprite[i]; + + if (sp->lotag == match) + { + // move lower levels ceilings up for the correct view + if (sp->hitag == VIEW_LEVEL2) + { + // save it off + save.sectnum[save.zcount] = sp->sectnum; + save.zval[save.zcount] = sector[sp->sectnum].floorz; + save.pic[save.zcount] = sector[sp->sectnum].floorpicnum; + save.slope[save.zcount] = sector[sp->sectnum].floorheinum; + + sector[sp->sectnum].floorz = newz; + // don't change FAF_MIRROR_PIC - ConnectArea + if (sector[sp->sectnum].floorpicnum != FAF_MIRROR_PIC) + sector[sp->sectnum].floorpicnum = FAF_MIRROR_PIC + 1; + sector[sp->sectnum].floorheinum = 0; + + save.zcount++; + PRODUCTION_ASSERT(save.zcount < ZMAX); + } + } + } + } + + return true; +} + +bool +FindFloorView(short match, int32_t* x, int32_t* y, int32_t z, int16_t* sectnum) +{ + int xoff = 0; + int yoff = 0; + int i; + SPRITEp sp = NULL; + int newz; + int pix_diff; + + save.zcount = 0; + + // Search Stat List For closest ceiling view sprite + // Get the match, xoff, yoff from this point + StatIterator it(STAT_FAF); + while ((i = it.NextIndex()) >= 0) + { + sp = &sprite[i]; + + if (sp->hitag == VIEW_THRU_FLOOR && sp->lotag == match) + { + xoff = *x - sp->x; + yoff = *y - sp->y; + break; + } + } + + + it.Reset(STAT_FAF); + while ((i = it.NextIndex()) >= 0) + { + sp = &sprite[i]; + + if (sp->lotag == match) + { + // determine x,y position + if (sp->hitag == VIEW_THRU_CEILING) + { + short upper, lower; + + *x = sp->x + xoff; + *y = sp->y + yoff; + + // get new sector + GetUpperLowerSector(match, *x, *y, &upper, &lower); + *sectnum = lower; + break; + } + } + } + + if (*sectnum < 0) + return false; + + ASSERT(sp); + ASSERT(sp->hitag == VIEW_THRU_CEILING); + + // move ceiling multiple of 128 so that the wall tile will line up + pix_diff = labs(z - sector[sp->sectnum].ceilingz) >> 8; + newz = sector[sp->sectnum].ceilingz - ((pix_diff / 128) + 1) * Z(128); + + if (!testnewrenderer) + { + it.Reset(STAT_FAF); + while ((i = it.NextIndex()) >= 0) + { + sp = &sprite[i]; + + if (sp->lotag == match) + { + // move upper levels floors down for the correct view + if (sp->hitag == VIEW_LEVEL1) + { + // save it off + save.sectnum[save.zcount] = sp->sectnum; + save.zval[save.zcount] = sector[sp->sectnum].ceilingz; + save.pic[save.zcount] = sector[sp->sectnum].ceilingpicnum; + save.slope[save.zcount] = sector[sp->sectnum].ceilingheinum; + + sector[sp->sectnum].ceilingz = newz; + + // don't change FAF_MIRROR_PIC - ConnectArea + if (sector[sp->sectnum].ceilingpicnum != FAF_MIRROR_PIC) + sector[sp->sectnum].ceilingpicnum = FAF_MIRROR_PIC + 1; + sector[sp->sectnum].ceilingheinum = 0; + + save.zcount++; + PRODUCTION_ASSERT(save.zcount < ZMAX); + } + } + } + } + return true; +} + +short +FindViewSectorInScene(short cursectnum, short level) +{ + int i; + SPRITEp sp; + short match; + + StatIterator it(STAT_FAF); + while ((i = it.NextIndex()) >= 0) + { + sp = &sprite[i]; + + if (sp->hitag == level) + { + if (cursectnum == sp->sectnum) + { + // ignore case if sprite is pointing up + if (sp->ang == 1536) + continue; + + // only gets to here is sprite is pointing down + + // found a potential match + match = sp->lotag; + + return match; + } + } + } + + return -1; +} + +int GameInterface::SetupPortal(FRenderViewpoint &vp) +{ + short i; + short match; + + 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; + + match = FindViewSectorInScene(tsectnum, VIEW_LEVEL1); + if (match != -1) + { + FindCeilingView(match, &tx, &ty, tz, &tsectnum); + type = PORTAL_SECTOR_CEILING; + + if (tsectnum < 0) + return -1; + } + else + { + match = FindViewSectorInScene(tsectnum, VIEW_LEVEL2); + if (match != -1) + { + FindFloorView(match, &tx, &ty, tz, &tsectnum); + type = PORTAL_SECTOR_FLOOR; + + if (tsectnum < 0) + return -1; + + } + } + vp.Pos = { tx / 16.f, ty / -16.f, tz / -128.f }; + vp.SectNums = nullptr; + vp.SectCount = tsectnum; + return type; +} + END_SW_NS