- made SW's sector portals operational.

Unlike the other games these are so poorly defined that the engine has to rely on the original fudging to pick the proper portal to link to. As a result they are just as limited as they always were.
In addition all the portal search code had to be reinstated.
This commit is contained in:
Christoph Oelckers 2021-03-25 16:45:40 +01:00
parent 168b0385cf
commit af54cf3a3c
11 changed files with 426 additions and 350 deletions

View file

@ -67,7 +67,7 @@ struct sectortype
uint8_t dirty; uint8_t dirty;
float ceilingxpan_, ceilingypan_, floorxpan_, floorypan_; float ceilingxpan_, ceilingypan_, floorxpan_, floorypan_;
uint8_t portalflags; uint8_t portalflags;
uint8_t portalnum; int8_t portalnum;
int ceilingxpan() const { return int(ceilingxpan_); } int ceilingxpan() const { return int(ceilingxpan_); }
int ceilingypan() const { return int(ceilingypan_); } int ceilingypan() const { return int(ceilingypan_); }

View file

@ -11,6 +11,7 @@ bool System_WantGuiCapture(); // During playing this tells us whether the game m
#include "inputstate.h" #include "inputstate.h"
class FSerializer; class FSerializer;
struct FRenderViewpoint;
struct GameStats struct GameStats
{ {
@ -102,6 +103,7 @@ struct GameInterface
virtual int chaseCamY(binangle ang) { return 0; } virtual int chaseCamY(binangle ang) { return 0; }
virtual int chaseCamZ(fixedhoriz horiz) { return 0; } virtual int chaseCamZ(fixedhoriz horiz) { return 0; }
virtual void processSprites(int viewx, int viewy, int viewz, binangle viewang, double smoothRatio) {} virtual void processSprites(int viewx, int viewy, int viewz, binangle viewang, double smoothRatio) {}
virtual int SetupPortal(FRenderViewpoint& vp) { return -1; }
virtual FString statFPS() virtual FString statFPS()
{ {

View file

@ -38,6 +38,7 @@
#include "hw_drawstructs.h" #include "hw_drawstructs.h"
#include "automap.h" #include "automap.h"
#include "gamefuncs.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->ceilingstat & backsector->ceilingstat & CSTAT_SECTOR_SKY) return false;
if (frontsector->floorstat & backsector->floorstat & 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_floorheight1;
float bs_floorheight2; float bs_floorheight2;
float bs_ceilingheight1; float bs_ceilingheight1;

View file

@ -32,6 +32,7 @@
#include "flatvertices.h" #include "flatvertices.h"
#include "hw_clock.h" #include "hw_clock.h"
#include "texturemanager.h" #include "texturemanager.h"
#include "gamestruct.h"
EXTERN_CVAR(Int, r_mirror_recursions) EXTERN_CVAR(Int, r_mirror_recursions)
EXTERN_CVAR(Bool, gl_portals) EXTERN_CVAR(Bool, gl_portals)
@ -813,12 +814,24 @@ bool HWSectorStackPortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *c
auto portal = origin; auto portal = origin;
auto &vp = di->Viewpoint; auto &vp = di->Viewpoint;
vp.Pos += DVector3(portal->dx / 16., portal->dy / -16., portal->dz / -256.); if (portal)
vp.SectNums = portal->targets.Data(); {
vp.SectCount = portal->targets.Size(); 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! // 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)); di->SetupView(rstate, vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(state->MirrorFlag & 1), !!(state->PlaneMirrorFlag & 1));
//SetupCoverage(di); //SetupCoverage(di);
@ -830,7 +843,8 @@ bool HWSectorStackPortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *c
void HWSectorStackPortal::Shutdown(HWDrawInfo *di, FRenderState &rstate) 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"; } const char *HWSectorStackPortal::GetName() { return "Sectorstack"; }

View file

@ -182,6 +182,7 @@ struct FPortalSceneState
int PlaneMirrorMode = 0; int PlaneMirrorMode = 0;
bool inskybox = 0; bool inskybox = 0;
bool insectorportal = false;
UniqueList<HWSkyInfo> UniqueSkies; UniqueList<HWSkyInfo> UniqueSkies;
UniqueList<HWHorizonInfo> UniqueHorizons; UniqueList<HWHorizonInfo> UniqueHorizons;
@ -350,6 +351,7 @@ public:
struct HWSectorStackPortal : public HWScenePortalBase struct HWSectorStackPortal : public HWScenePortalBase
{ {
TArray<sectortype *> sectors; TArray<sectortype *> sectors;
int type = -1;
protected: protected:
bool Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clipper) override; bool Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clipper) override;
void Shutdown(HWDrawInfo *di, FRenderState &rstate) override; void Shutdown(HWDrawInfo *di, FRenderState &rstate) override;

View file

@ -81,13 +81,13 @@ void HWWall::SkyPlane(HWDrawInfo *di, sectortype *sector, int plane, bool allowr
{ {
int ptype; 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; if (screen->instack[1 - plane] || sector->portalnum >= (int)allPortals.Size()) return;
portal = &allPortals[sector->portalnum]; portal = sector->portalnum < 0? nullptr : &allPortals[sector->portalnum];
PutPortal(di, PORTALTYPE_SECTORSTACK, plane); 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; ptype = PORTALTYPE_PLANEMIRROR;
if (plane == plane_ceiling && (sector->ceilingstat & CSTAT_SECTOR_SLOPE)) return; if (plane == plane_ceiling && (sector->ceilingstat & CSTAT_SECTOR_SLOPE)) return;

View file

@ -1,310 +1,7 @@
BEGIN_SW_NS BEGIN_SW_NS
short GlobStackSect[2]; 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);
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;
}
short short

View file

@ -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;
}
}
} }

View file

@ -407,7 +407,6 @@ void InitLevel(MapRecord *maprec)
PlaceActorsOnTracks(); PlaceActorsOnTracks();
PostSetupSectorObject(); PostSetupSectorObject();
SetupMirrorTiles(); SetupMirrorTiles();
SetupSectorPortals();
initlava(); initlava();
// reset NewGame // reset NewGame

View file

@ -2135,7 +2135,6 @@ void DrawOverlapRoom(int tx,int ty,int tz,fixed_t tq16ang,fixed_t tq16horiz,shor
void SetupMirrorTiles(void); // rooms.c void SetupMirrorTiles(void); // rooms.c
bool FAF_Sector(short sectnum); // rooms.c bool FAF_Sector(short sectnum); // rooms.c
int GetZadjustment(short sectnum,short hitag); // rooms.c int GetZadjustment(short sectnum,short hitag); // rooms.c
void SetupSectorPortals();
void InitSetup(void); // setup.c void InitSetup(void); // setup.c
@ -2256,6 +2255,7 @@ struct GameInterface : ::GameInterface
int chaseCamX(binangle ang) { return -ang.bcos(-3); } int chaseCamX(binangle ang) { return -ang.bcos(-3); }
int chaseCamY(binangle ang) { return -ang.bsin(-3); } int chaseCamY(binangle ang) { return -ang.bsin(-3); }
int chaseCamZ(fixedhoriz horiz) { return horiz.asq16() >> 8; } int chaseCamZ(fixedhoriz horiz) { return horiz.asq16() >> 8; }
int SetupPortal(FRenderViewpoint& vp) override;
GameStats getStats() override; GameStats getStats() override;

View file

@ -29,6 +29,7 @@ Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
#include "names2.h" #include "names2.h"
#include "panel.h" #include "panel.h"
#include "misc.h" #include "misc.h"
#include "hw_drawinfo.h"
BEGIN_SW_NS 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<int> foundf, foundc;
// Search Stat List For closest ceiling view sprite
// Get the match, xoff, yoff from this point
StatIterator it(STAT_FAF);
int i; 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]; // will not hurt if GlobStackSect is invalid - inside checks for this
if (inside(x, y, GlobStackSect[i]) == 1)
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())
{ {
auto spc = &sprite[foundf[cindex]]; bool found = false;
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);
sector[spc->sectnum].portalflags = PORTAL_SECTOR_CEILING; SectIterator it(GlobStackSect[i]);
sector[spc->sectnum].portalnum = portalAdd(PORTAL_SECTOR_CEILING, spf->sectnum, spf->x - spc->x, spf->y - spc->y, 0); while ((SpriteNum = it.NextIndex()) >= 0)
{
sp = &sprite[SpriteNum];
//Printf("Portal with tag %d\n", sprite[foundf[0]].lotag); if (sp->statnum == STAT_FAF &&
foundf.Delete(0); (sp->hitag >= VIEW_LEVEL1 && sp->hitag <= VIEW_LEVEL6)
foundc.Delete(cindex); && sp->lotag == match)
} {
else found = true;
{ }
//Printf("Floor portal %d without partner\n", sprite[foundf[0]].lotag); }
foundf.Delete(0);
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 END_SW_NS