# Conflicts:
#	src/p_spec.cpp
#	src/r_bsp.cpp
#	src/r_data/r_interpolate.cpp
#	wadsrc/static/xlat/eternity.txt
This commit is contained in:
Christoph Oelckers 2016-02-14 18:20:56 +01:00
commit b60069bb26
14 changed files with 465 additions and 19 deletions

View file

@ -106,11 +106,7 @@ class ASkyCamCompat : public ASkyViewpoint
DECLARE_CLASS (ASkyCamCompat, ASkyViewpoint)
public:
void BeginPlay ()
{
// Do not call the SkyViewpoint's super method because it would trash our setup
AActor::BeginPlay();
}
void BeginPlay();
};

View file

@ -54,6 +54,7 @@ void ASkyViewpoint::BeginPlay ()
{
level.DefaultSkybox = this;
}
special1 = SKYBOX_SKYVIEWPOINT;
}
void ASkyViewpoint::Serialize (FArchive &arc)
@ -85,6 +86,13 @@ void ASkyViewpoint::Destroy ()
IMPLEMENT_CLASS (ASkyCamCompat)
void ASkyCamCompat::BeginPlay()
{
// Do not call the SkyViewpoint's super method because it would trash our setup
AActor::BeginPlay();
special1 = SKYBOX_SKYVIEWPOINT;
}
//---------------------------------------------------------------------------
@ -154,6 +162,7 @@ void AStackPoint::BeginPlay ()
AActor::BeginPlay ();
bAlways = true;
special1 = SKYBOX_STACKEDSECTORTHING;
}
//---------------------------------------------------------------------------

View file

@ -104,6 +104,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightGoesOut)
sec->floorplane.d = sec->floorplane.PointToDist (spot, newheight);
fixed_t newtheight = sec->floorplane.Zat0();
sec->ChangePlaneTexZ(sector_t::floor, newtheight - oldtheight);
sec->CheckPortalPlane(sector_t::floor);
for (int i = 0; i < 8; ++i)
{

View file

@ -2582,6 +2582,11 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates)
abs(corpsehit->Y() - viletry.y) > maxdist)
continue; // not actually touching
// Let's check if there are floors in between the archvile and its target
// if in a different section of the map, only consider possible if a line of sight exists.
if (corpsehit->Sector->PortalGroup != self->Sector->PortalGroup && !P_CheckSight(self, corpsehit))
continue;
sector_t *vilesec = self->Sector;
sector_t *corpsec = corpsehit->Sector;
// We only need to test if at least one of the sectors has a 3D floor.

View file

@ -5532,6 +5532,7 @@ bool P_ChangeSector(sector_t *sector, int crunch, int amt, int floorOrCeil, bool
}
}
} while (n);
sec->CheckPortalPlane(!floorOrCeil);
}
}
P_Recalculate3DFloors(sector); // Must recalculate the 3d floor and light lists
@ -5595,6 +5596,8 @@ bool P_ChangeSector(sector_t *sector, int crunch, int amt, int floorOrCeil, bool
}
} while (n); // repeat from scratch until all things left are marked valid
sector->CheckPortalPlane(floorOrCeil); // check for portal obstructions after everything is done.
if (!cpos.nofit && !isreset /* && sector->MoreFlags & (SECF_UNDERWATERMASK)*/)
{
// If this is a control sector for a deep water transfer, all actors in affected

View file

@ -871,6 +871,19 @@ int sector_t::GetTerrain(int pos) const
return terrainnum[pos] >= 0 ? terrainnum[pos] : TerrainTypes[GetTexture(pos)];
}
void sector_t::CheckPortalPlane(int plane)
{
ASkyViewpoint *portal = SkyBoxes[plane];
if (!portal || portal->special1 != SKYBOX_LINKEDPORTAL) return;
fixed_t planeh = planes[plane].TexZ;
int obstructed = PLANEF_OBSTRUCTED * (plane == sector_t::floor ?
planeh > portal->threshold : planeh < portal->threshold);
planes[plane].Flags = (planes[plane].Flags & ~PLANEF_OBSTRUCTED) | obstructed;
}
FArchive &operator<< (FArchive &arc, secspecial_t &p)
{
if (SaveVersion < 4529)

View file

@ -1036,15 +1036,16 @@ static void CopyPortal(int sectortag, int plane, ASkyViewpoint *origin, fixed_t
}
}
void P_SpawnPortal(line_t *line, int sectortag, int plane, int alpha)
void P_SpawnPortal(line_t *line, int sectortag, int plane, int alpha, int linked)
{
if (plane < 0 || plane > 2 || (linked && plane == 2)) return;
for (int i=0;i<numlines;i++)
{
// We must look for the reference line with a linear search unless we want to waste the line ID for it
// which is not a good idea.
if (lines[i].special == Sector_SetPortal &&
lines[i].args[0] == sectortag &&
lines[i].args[1] == 0 &&
lines[i].args[1] == linked &&
lines[i].args[2] == plane &&
lines[i].args[3] == 1)
{
@ -1053,10 +1054,18 @@ void P_SpawnPortal(line_t *line, int sectortag, int plane, int alpha)
fixed_t y1 = fixed_t((SQWORD(line->v1->y) + SQWORD(line->v2->y)) >> 1);
fixed_t x2 = fixed_t((SQWORD(lines[i].v1->x) + SQWORD(lines[i].v2->x)) >> 1);
fixed_t y2 = fixed_t((SQWORD(lines[i].v1->y) + SQWORD(lines[i].v2->y)) >> 1);
fixed_t z = linked ? line->frontsector->planes[plane].TexZ : 0; // the map's sector height defines the portal plane for linked portals
fixed_t alpha = Scale (lines[i].args[4], OPAQUE, 255);
AStackPoint *anchor = Spawn<AStackPoint>(x1, y1, 0, NO_REPLACE);
AStackPoint *reference = Spawn<AStackPoint>(x2, y2, 0, NO_REPLACE);
reference->special1 = linked ? SKYBOX_LINKEDPORTAL : SKYBOX_PORTAL;
anchor->special1 = SKYBOX_ANCHOR;
// store the portal displacement in the unused scaleX/Y members of the portal reference actor.
anchor->scaleX = -(reference->scaleX = x2 - x1);
anchor->scaleY = -(reference->scaleY = y2 - y1);
anchor->threshold = reference->threshold = z;
reference->Mate = anchor;
anchor->Mate = reference;
@ -1445,15 +1454,17 @@ void P_SpawnSpecials (void)
// - 0: normal (handled here)
// - 1: copy (handled by the portal they copy)
// - 2: EE-style skybox (handled by the camera object)
// - 3: EE-style flat portal (HW renderer only for now)
// - 4: EE-style horizon portal (HW renderer only for now)
// - 3: EE-style flat portal (GZDoom HW renderer only for now)
// - 4: EE-style horizon portal (GZDoom HW renderer only for now)
// - 5: copy portal to line (GZDoom HW renderer only for now)
// - 6: linked portal
// other values reserved for later use
// arg 2 = 0:floor, 1:ceiling, 2:both
// arg 3 = 0: anchor, 1: reference line
// arg 4 = for the anchor only: alpha
if (lines[i].args[1] == 0 && lines[i].args[3] == 0)
if ((lines[i].args[1] == 0 || lines[i].args[1] == 6) && lines[i].args[3] == 0)
{
P_SpawnPortal(&lines[i], lines[i].args[0], lines[i].args[2], lines[i].args[4]);
P_SpawnPortal(&lines[i], lines[i].args[0], lines[i].args[2], lines[i].args[4], lines[i].args[1]);
}
else if (lines[i].args[1] == 3 || lines[i].args[1] == 4)
{
@ -1542,6 +1553,7 @@ void P_SpawnSpecials (void)
// [RH] Start running any open scripts on this map
FBehavior::StaticStartTypedScripts (SCRIPT_Open, NULL, false);
P_FinalizePortals();
P_CreateLinkedPortals();
}
// killough 2/28/98:

View file

@ -8,10 +8,15 @@
#include "p_tags.h"
#include "farchive.h"
#include "v_text.h"
#include "a_sharedglobal.h"
#include "i_system.h"
#include "c_dispatch.h"
// simulation recurions maximum
CVAR(Int, sv_portal_recursions, 4, CVAR_ARCHIVE|CVAR_SERVERINFO)
FDisplacementTable Displacements;
TArray<FLinePortal> linePortals;
@ -148,7 +153,19 @@ void P_UpdatePortal(FLinePortal *port)
else
{
port->mFlags = port->mDefFlags;
}
if (port->mType == PORTT_LINKED)
{
if (linePortals[port->mDestination->portalindex].mType != PORTT_LINKED)
{
port->mType = PORTT_INTERACTIVE; // linked portals must be two-way.
}
else
{
port->mXDisplacement = port->mDestination->v2->x - port->mOrigin->v1->x;
port->mYDisplacement = port->mDestination->v2->y - port->mOrigin->v1->y;
}
}
}
}
void P_FinalizePortals()
@ -504,3 +521,336 @@ bool PortalTracer::TraceStep()
return (oDepth != depth); // if a portal has been found, return false
}
//============================================================================
//
// CollectSectors
//
// Collects all sectors that are connected to any sector belonging to a portal
// because they all will need the same displacement values
//
//============================================================================
static bool CollectSectors(int groupid, sector_t *origin)
{
if (origin->PortalGroup != 0) return false; // already processed
origin->PortalGroup = groupid;
TArray<sector_t *> list(16);
list.Push(origin);
for (unsigned i = 0; i < list.Size(); i++)
{
sector_t *sec = list[i];
for (int j = 0; j < sec->linecount; j++)
{
line_t *line = sec->lines[j];
sector_t *other = line->frontsector == sec ? line->backsector : line->frontsector;
if (other != NULL && other != sec && other->PortalGroup != groupid)
{
other->PortalGroup = groupid;
list.Push(other);
}
}
}
return true;
}
//============================================================================
//
// AddDisplacementForPortal
//
// Adds the displacement for one portal to the displacement array
// (one version for sector to sector plane, one for line to line portals)
//
//============================================================================
static void AddDisplacementForPortal(AStackPoint *portal)
{
int thisgroup = portal->Mate->Sector->PortalGroup;
int othergroup = portal->Sector->PortalGroup;
if (thisgroup == othergroup)
{
Printf("Portal between sectors %d and %d has both sides in same group and will be disabled\n", portal->Sector->sectornum, portal->Mate->Sector->sectornum);
portal->special1 = portal->Mate->special1 = SKYBOX_PORTAL;
return;
}
if (thisgroup <= 0 || thisgroup >= Displacements.size || othergroup <= 0 || othergroup >= Displacements.size)
{
Printf("Portal between sectors %d and %d has invalid group and will be disabled\n", portal->Sector->sectornum, portal->Mate->Sector->sectornum);
portal->special1 = portal->Mate->special1 = SKYBOX_PORTAL;
return;
}
FDisplacement & disp = Displacements(thisgroup, othergroup);
if (!disp.isSet)
{
disp.x = portal->scaleX;
disp.y = portal->scaleY;
disp.isSet = true;
}
else
{
if (disp.x != portal->scaleX || disp.y != portal->scaleY)
{
Printf("Portal between sectors %d and %d has displacement mismatch and will be disabled\n", portal->Sector->sectornum, portal->Mate->Sector->sectornum);
portal->special1 = portal->Mate->special1 = SKYBOX_PORTAL;
return;
}
}
}
static void AddDisplacementForPortal(FLinePortal *portal)
{
int thisgroup = portal->mOrigin->frontsector->PortalGroup;
int othergroup = portal->mDestination->frontsector->PortalGroup;
if (thisgroup == othergroup)
{
Printf("Portal between lines %d and %d has both sides in same group\n", int(portal->mOrigin-lines), int(portal->mDestination-lines));
portal->mType = linePortals[portal->mDestination->portalindex].mType = PORTT_TELEPORT;
return;
}
if (thisgroup <= 0 || thisgroup >= Displacements.size || othergroup <= 0 || othergroup >= Displacements.size)
{
Printf("Portal between lines %d and %d has invalid group\n", int(portal->mOrigin - lines), int(portal->mDestination - lines));
portal->mType = linePortals[portal->mDestination->portalindex].mType = PORTT_TELEPORT;
return;
}
FDisplacement & disp = Displacements(thisgroup, othergroup);
if (!disp.isSet)
{
disp.x = portal->mXDisplacement;
disp.y = portal->mYDisplacement;
disp.isSet = true;
}
else
{
if (disp.x != portal->mXDisplacement || disp.y != portal->mYDisplacement)
{
Printf("Portal between lines %d and %d has displacement mismatch\n", int(portal->mOrigin - lines), int(portal->mDestination - lines));
portal->mType = linePortals[portal->mDestination->portalindex].mType = PORTT_TELEPORT;
return;
}
}
}
//============================================================================
//
// ConnectGroups
//
// Do the indirect connections. This loop will run until it cannot find any new connections
//
//============================================================================
static bool ConnectGroups()
{
// Now
BYTE indirect = 1;
bool bogus = false;
bool changed;
do
{
changed = false;
for (int x = 1; x < Displacements.size; x++)
{
for (int y = 1; y < Displacements.size; y++)
{
FDisplacement &dispxy = Displacements(x, y);
if (dispxy.isSet)
{
for (int z = 1; z < Displacements.size; z++)
{
FDisplacement &dispyz = Displacements(y, z);
if (dispyz.isSet)
{
FDisplacement &dispxz = Displacements(x, z);
if (dispxz.isSet)
{
if (dispxy.x + dispyz.x != dispxz.x || dispxy.y + dispyz.y != dispxz.y)
{
bogus = true;
}
}
else
{
dispxz.x = dispxy.x + dispyz.x;
dispxz.y = dispxy.y + dispyz.y;
dispxz.isSet = true;
dispxz.indirect = indirect;
changed = true;
}
}
}
}
}
}
indirect++;
} while (changed);
return bogus;
}
//============================================================================
//
// P_CreateLinkedPortals
//
// Creates the data structures needed for linked portals
// Removes portals from sloped sectors (as they cannot work on them)
// Group all sectors connected to one side of the portal
// Caclculate displacements between all created groups.
//
// Portals with the same offset but different anchors will not be merged.
//
//============================================================================
void P_CreateLinkedPortals()
{
TThinkerIterator<AStackPoint> it;
AStackPoint *mo;
TArray<AStackPoint *> orgs;
int id = 0;
bool bogus = false;
while ((mo = it.Next()))
{
if (mo->special1 == SKYBOX_LINKEDPORTAL)
{
if (mo->Mate != NULL)
{
orgs.Push(mo);
mo->reactiontime = ++id;
}
else
{
// this should never happen, but if it does, the portal needs to be removed
mo->Destroy();
}
}
}
if (orgs.Size() == 0)
{
return;
}
for (int i = 0; i < numsectors; i++)
{
for (int j = 0; j < 2; j++)
{
ASkyViewpoint *box = sectors[i].SkyBoxes[j];
if (box != NULL && box->special1 == SKYBOX_LINKEDPORTAL)
{
secplane_t &plane = j == 0 ? sectors[i].floorplane : sectors[i].ceilingplane;
if (plane.a || plane.b)
{
// The engine cannot deal with portals on a sloped plane.
sectors[i].SkyBoxes[j] = NULL;
Printf("Portal on %s of sector %d is sloped and will be disabled\n", j==0? "floor":"ceiling", i);
}
}
}
}
// Group all sectors, starting at each portal origin.
id = 1;
for (unsigned i = 0; i < orgs.Size(); i++)
{
if (CollectSectors(id, orgs[i]->Sector)) id++;
if (CollectSectors(id, orgs[i]->Mate->Sector)) id++;
}
for (unsigned i = 0; i < linePortals.Size(); i++)
{
if (linePortals[i].mType == PORTT_LINKED)
{
if (CollectSectors(id, linePortals[i].mOrigin->frontsector)) id++;
if (CollectSectors(id, linePortals[i].mDestination->frontsector)) id++;
}
}
Displacements.Create(id);
// Check for leftover sectors that connect to a portal
for (int i = 0; i<numsectors; i++)
{
for (int j = 0; j < 2; j++)
{
ASkyViewpoint *box = sectors[i].SkyBoxes[j];
if (box != NULL)
{
if (box->special1 == SKYBOX_LINKEDPORTAL && box->Sector->PortalGroup == 0)
{
CollectSectors(box->Sector->PortalGroup, box->Sector);
box = box->Mate;
if (box->special1 == SKYBOX_LINKEDPORTAL && box->Sector->PortalGroup == 0)
{
CollectSectors(box->Sector->PortalGroup, box->Sector);
}
}
}
}
}
for (unsigned i = 0; i < orgs.Size(); i++)
{
AddDisplacementForPortal(orgs[i]);
}
for (unsigned i = 0; i < linePortals.Size(); i++)
{
if (linePortals[i].mType == PORTT_LINKED)
{
AddDisplacementForPortal(&linePortals[i]);
}
}
for (int x = 1; x < Displacements.size; x++)
{
for (int y = x + 1; y < Displacements.size; y++)
{
FDisplacement &dispxy = Displacements(x, y);
FDisplacement &dispyx = Displacements(y, x);
if (dispxy.isSet && dispyx.isSet &&
(dispxy.x != -dispyx.x || dispxy.y != -dispyx.y))
{
Printf("Link offset mismatch between groups %d and %d\n", x, y); // need to find some sectors to report.
bogus = true;
}
// todo: Find sectors that have no group but belong to a portal.
}
}
bogus |= ConnectGroups();
if (bogus)
{
// todo: disable all portals whose offsets do not match the associated groups
}
// reject would just get in the way when checking sight through portals.
if (rejectmatrix != NULL)
{
delete[] rejectmatrix;
rejectmatrix = NULL;
}
// finally we must flag all planes which are obstructed by the sector's own ceiling or floor.
for (int i = 0; i < numsectors; i++)
{
sectors[i].CheckPortalPlane(sector_t::floor);
sectors[i].CheckPortalPlane(sector_t::ceiling);
}
//BuildBlockmap();
}
CCMD(dumplinktable)
{
for (int x = 1; x < Displacements.size; x++)
{
for (int y = 1; y < Displacements.size; y++)
{
FDisplacement &disp = Displacements(x, y);
Printf("%c%c(%6d, %6d)", TEXTCOLOR_ESCAPE, 'C' + disp.indirect, disp.x >> FRACBITS, disp.y >> FRACBITS);
}
Printf("\n");
}
}

View file

@ -8,6 +8,30 @@
#include "p_local.h"
#include "m_bbox.h"
struct FDisplacement
{
fixed_t x, y;
bool isSet;
BYTE indirect; // just for illustration.
};
struct FDisplacementTable
{
TArray<FDisplacement> data;
int size;
void Create(int numgroups)
{
data.Resize(numgroups*numgroups);
memset(&data[0], 0, numgroups*numgroups*sizeof(data[0]));
size = numgroups;
}
FDisplacement &operator()(int x, int y)
{
return data[x + size*y];
}
};
enum
{
@ -53,6 +77,7 @@ extern TArray<FLinePortal> linePortals;
void P_SpawnLinePortal(line_t* line);
void P_FinalizePortals();
bool P_ChangePortal(line_t *ln, int thisid, int destid);
void P_CreateLinkedPortals();
/* code ported from prototype */

View file

@ -1094,7 +1094,7 @@ void R_Subsector (subsector_t *sub)
}
skybox = frontsector->GetSkyBox(sector_t::ceiling);
if (skybox != NULL && skybox->special1 != SKYBOX_MAP) skybox = NULL; // HW renderer only.
if (skybox != NULL && skybox->special1 >= SKYBOX_PLANE) skybox = NULL; // skip unsupported portal types
ceilingplane = frontsector->ceilingplane.PointOnSide(viewx, viewy, viewz) > 0 ||
frontsector->GetTexture(sector_t::ceiling) == skyflatnum ||
@ -1137,7 +1137,7 @@ void R_Subsector (subsector_t *sub)
// killough 10/98: add support for skies transferred from sidedefs
skybox = frontsector->GetSkyBox(sector_t::floor);
if (skybox != NULL && skybox->special1 != SKYBOX_MAP) skybox = NULL; // HW renderer only.
if (skybox != NULL && skybox->special1 >= SKYBOX_PLANE) skybox = NULL; // skip unsupported portal types
floorplane = frontsector->floorplane.PointOnSide(viewx, viewy, viewz) > 0 || // killough 3/7/98
frontsector->GetTexture(sector_t::floor) == skyflatnum ||

View file

@ -469,6 +469,7 @@ void DSectorPlaneInterpolation::Restore()
sector->SetPlaneTexZ(sector_t::ceiling, baktexz, true);
}
P_RecalculateAttached3DFloors(sector);
sector->CheckPortalPlane(ceiling? sector_t::ceiling : sector_t::floor);
}
//==========================================================================
@ -505,6 +506,7 @@ void DSectorPlaneInterpolation::Interpolate(fixed_t smoothratio)
*pheight = oldheight + FixedMul(bakheight - oldheight, smoothratio);
sector->SetPlaneTexZ(pos, oldtexz + FixedMul(baktexz - oldtexz, smoothratio), true);
P_RecalculateAttached3DFloors(sector);
sector->CheckPortalPlane(pos);
}
}

View file

@ -60,6 +60,18 @@ enum
extern size_t MaxDrawSegs;
enum
{
SKYBOX_ANCHOR = -1,
SKYBOX_SKYVIEWPOINT = 0, // a regular skybox
SKYBOX_STACKEDSECTORTHING, // stacked sectors with the thing method
SKYBOX_PORTAL, // stacked sectors with Sector_SetPortal
SKYBOX_LINKEDPORTAL, // linked portal (interactive)
SKYBOX_PLANE, // EE-style plane portal (not implemented in SW renderer)
SKYBOX_HORIZON, // EE-style horizon portal (not implemented in SW renderer)
};
//
// INTERNAL MAP TYPES
// used by play and refresh
@ -545,6 +557,7 @@ struct sector_t
DInterpolation *SetInterpolation(int position, bool attach);
ASkyViewpoint *GetSkyBox(int which);
void CheckPortalPlane(int plane);
enum
{
@ -779,6 +792,22 @@ struct sector_t
Flags &= ~SECF_SPECIALFLAGS;
}
inline bool PortalBlocksView(int plane)
{
return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
}
inline bool PortalBlocksMovement(int plane)
{
return !!(planes[plane].Flags & (PLANEF_NOPASS | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
}
inline bool PortalBlocksSound(int plane)
{
return !!(planes[plane].Flags & (PLANEF_BLOCKSOUND | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
}
int GetTerrain(int pos) const;
void TransferSpecial(sector_t *model);
@ -871,6 +900,7 @@ struct sector_t
// [RH] The sky box to render for this sector. NULL means use a
// regular sky.
TObjPtr<ASkyViewpoint> SkyBoxes[2];
int PortalGroup;
int sectornum; // for comparing sector copies

Binary file not shown.

View file

@ -131,11 +131,11 @@ enum
356 = 0, Polyobj_RotateLeft(0)
357 = 0, Polyobj_OR_RotateLeft(0)
// Eternity's linked portals, vertical link version (floor-to-ceiling) (NOTE: Type needs changing!)
358 = 0, Sector_SetPortal(tag, 0, 1, 1, 0) // "Portal_AnchoredCeiling"
359 = 0, Sector_SetPortal(tag, 0, 0, 1, 0) // "Portal_AnchoredFloor"
360 = 0, Sector_SetPortal(tag, 0, 1, 0, 0) // "Portal_AnchorLine"
361 = 0, Sector_SetPortal(tag, 0, 0, 0, 0) // "Portal_AnchorLineFloor"
// Eternity's linked portals, vertical link version (floor-to-ceiling)
358 = 0, Sector_SetPortal(tag, 6, 1, 1, 0) // "Portal_AnchoredCeiling"
359 = 0, Sector_SetPortal(tag, 6, 0, 1, 0) // "Portal_AnchoredFloor"
360 = 0, Sector_SetPortal(tag, 6, 1, 0, 0) // "Portal_AnchorLine"
361 = 0, Sector_SetPortal(tag, 6, 0, 0, 0) // "Portal_AnchorLineFloor"
// Even more parameterized linedefs
362 = 0, Pillar_Build(0)