From 1b88052bbac92a59b73bf751f1acff845c1a7cc5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 16 Feb 2016 16:40:53 +0100 Subject: [PATCH 01/28] - started refactoring ZatPoint calls which need to be portal aware. To summarize, anything that just works with map geometry doesn't need to bother, as does the renderer. (i.e. nearly all r_* files, p_floor.cpp, p_ceiling.cpp et.al) But all calls that are somehow related to actor positions need to be made aware of potential portal transitions: * added FloorAtPoint, CeilingAtPoint and PlaneAtPoint methods to sector_t, which can be used to calculate a plane's height with relation to a given actor, even if that actor is on the other side of a portal. * added HighestCeilingAt and LowestFloorAt methods which traverse all ceiling/floor portals until they find an impassable plane. --- src/basictypes.h | 44 +++++++++++++++-- src/g_doom/a_painelemental.cpp | 6 +-- src/g_shared/a_fastprojectile.cpp | 2 +- src/g_shared/a_pickups.cpp | 5 +- src/g_strife/a_strifestuff.cpp | 2 +- src/p_enemy.cpp | 6 +-- src/p_local.h | 1 + src/p_sectors.cpp | 77 +++++++++++++++++++++++++++++ src/portal.cpp | 31 ++++++------ src/portal.h | 18 ++++++- src/r_defs.h | 80 ++++++++++++++++++++++++++----- 11 files changed, 230 insertions(+), 42 deletions(-) diff --git a/src/basictypes.h b/src/basictypes.h index 0ae68f39b..6caf40a36 100644 --- a/src/basictypes.h +++ b/src/basictypes.h @@ -81,16 +81,50 @@ union QWORD_UNION typedef SDWORD fixed_t; typedef DWORD dsfixed_t; // fixedpt used by span drawer -struct fixedvec3 -{ - fixed_t x, y, z; -}; - struct fixedvec2 { fixed_t x, y; + + fixedvec2 &operator +=(const fixedvec2 &other) + { + x += other.x; + y += other.y; + return *this; + } }; +struct fixedvec3 +{ + fixed_t x, y, z; + + fixedvec3 &operator +=(const fixedvec3 &other) + { + x += other.x; + y += other.y; + z += other.z; + return *this; + } + + fixedvec3 &operator +=(const fixedvec2 &other) + { + x += other.x; + y += other.y; + return *this; + } + +}; + +inline fixedvec2 operator +(const fixedvec2 &v1, const fixedvec2 &v2) +{ + fixedvec2 v = { v1.x + v2.x, v1.y + v2.y }; + return v; +} + +inline fixedvec3 operator +(const fixedvec3 &v1, const fixedvec3 &v2) +{ + fixedvec3 v = { v1.x + v2.x, v1.y + v2.y, v1.z + v2.z }; + return v; +} #define FIXED_MAX (signed)(0x7fffffff) #define FIXED_MIN (signed)(0x80000000) diff --git a/src/g_doom/a_painelemental.cpp b/src/g_doom/a_painelemental.cpp index 6c02c6517..b73af5e1d 100644 --- a/src/g_doom/a_painelemental.cpp +++ b/src/g_doom/a_painelemental.cpp @@ -122,9 +122,9 @@ void A_PainShootSkull (AActor *self, angle_t angle, PClassActor *spawntype, int // Check to see if the new Lost Soul's z value is above the // ceiling of its new sector, or below the floor. If so, kill it. - if ((other->Z() > - (other->Sector->HighestCeiling(other) - other->height)) || - (other->Z() < other->Sector->LowestFloor(other))) + if ((other->Top() > + (other->Sector->HighestCeilingAt(other))) || + (other->Z() < other->Sector->LowestFloorAt(other))) { // kill it immediately P_DamageMobj (other, self, self, TELEFRAG_DAMAGE, NAME_None);// ^ diff --git a/src/g_shared/a_fastprojectile.cpp b/src/g_shared/a_fastprojectile.cpp index 29a72c23c..baad73628 100644 --- a/src/g_shared/a_fastprojectile.cpp +++ b/src/g_shared/a_fastprojectile.cpp @@ -82,7 +82,7 @@ void AFastProjectile::Tick () if (tm.ceilingline && tm.ceilingline->backsector && tm.ceilingline->backsector->GetTexture(sector_t::ceiling) == skyflatnum && - Z() >= tm.ceilingline->backsector->ceilingplane.ZatPoint (this)) + Z() >= tm.ceilingline->backsector->CeilingAtPoint(this)) { // Hack to prevent missiles exploding against the sky. // Does not handle sky floors. diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index 32a4167bb..256ba010c 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -427,7 +427,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialPosition) self->floorz = sec->floorplane.ZatPoint(_x, _y); self->ceilingz = sec->ceilingplane.ZatPoint(_x, _y); self->SetZ(self->floorz); - P_FindFloorCeiling(self, FFCF_ONLYSPAWNPOS); + P_FindFloorCeiling(self, FFCF_ONLYSPAWNPOS | FFCF_NOPORTALS); // no pprtal checks here so that things get spawned in this sector. if (self->flags & MF_SPAWNCEILING) { @@ -451,6 +451,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialPosition) self->SetZ(self->SpawnPoint[2] + self->floorz); } // Redo floor/ceiling check, in case of 3D floors + // we need to get the actual floor and ceiling heights including portals here + self->floorz = sec->LowestFloorAt(self, &self->floorsector); + self->ceilingz = sec->HighestCeilingAt(self, &self->ceilingsector); P_FindFloorCeiling(self, FFCF_SAMESECTOR | FFCF_ONLY3DFLOORS | FFCF_3DRESTRICT); if (self->Z() < self->floorz) { // Do not reappear under the floor, even if that's where we were for the diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index 724deaee2..e24ca6113 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -658,7 +658,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckTerrain) sector_t *sec = self->Sector; - if (self->Z() == sec->floorplane.ZatPoint(self)) + if (self->Z() == sec->floorplane.ZatPoint(self) && sec->PortalBlocksMovement(sector_t::floor)) { if (sec->special == Damage_InstantDeath) { diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index fed155627..49451c5d6 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -558,7 +558,7 @@ bool P_Move (AActor *actor) else { // The monster just hit the floor, so trigger any actions. if (actor->floorsector->SecActTarget != NULL && - actor->floorz == actor->floorsector->floorplane.ZatPoint(actor)) + actor->floorz == actor->floorsector->FloorAtPoint(actor)) { actor->floorsector->SecActTarget->TriggerAction(actor, SECSPAC_HitFloor); } @@ -868,8 +868,8 @@ void P_NewChaseDir(AActor * actor) box.Bottom() < line->bbox[BOXTOP] && box.BoxOnLineSide(line) == -1) { - fixed_t front = line->frontsector->floorplane.ZatPoint(actor); - fixed_t back = line->backsector->floorplane.ZatPoint(actor); + fixed_t front = line->frontsector->FloorAtPoint(actor); + fixed_t back = line->backsector->FloorAtPoint(actor); angle_t angle; // The monster must contact one of the two floors, diff --git a/src/p_local.h b/src/p_local.h index 44a430c27..c4c5d3914 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -287,6 +287,7 @@ enum FFCF_SAMESECTOR = 2, FFCF_ONLY3DFLOORS = 4, // includes 3D midtexes FFCF_3DRESTRICT = 8, // ignore 3D midtexes and floors whose floorz are above thing's z + FFCF_NOPORTALS = 16, // ignore portals (considers them impassable.) }; void P_FindFloorCeiling (AActor *actor, int flags=0); diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index a10568388..1a4d218cf 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -30,6 +30,7 @@ #include "po_man.h" #include "farchive.h" #include "r_utility.h" +#include "portal.h" #include "a_sharedglobal.h" #include "r_data/colormaps.h" @@ -882,7 +883,78 @@ void sector_t::CheckPortalPlane(int plane) planes[plane].Flags = (planes[plane].Flags & ~PLANEF_OBSTRUCTED) | obstructed; } +//=========================================================================== +// +// Finds the highest ceiling at the given position, all portals considered +// +//=========================================================================== +fixed_t sector_t::HighestCeilingAt(fixed_t x, fixed_t y, sector_t **resultsec) +{ + sector_t *check = this; + fixed_t planeheight = FIXED_MIN; + + // Continue until we find a blocking portal or a portal below where we actually are. + while (!check->PortalBlocksMovement(ceiling) && planeheight < check->SkyBoxes[ceiling]->threshold) + { + FDisplacement &disp = check->CeilingDisplacement(); + x += disp.pos.x; + y += disp.pos.y; + planeheight = check->SkyBoxes[ceiling]->threshold; + check = P_PointInSector(x, y); + } + if (resultsec) *resultsec = check; + return check->ceilingplane.ZatPoint(x, y); +} + +//=========================================================================== +// +// Finds the lowest floor at the given position, all portals considered +// +//=========================================================================== + +fixed_t sector_t::LowestFloorAt(fixed_t x, fixed_t y, sector_t **resultsec) +{ + sector_t *check = this; + fixed_t planeheight = FIXED_MAX; + + // Continue until we find a blocking portal or a portal above where we actually are. + while (!check->PortalBlocksMovement(floor) && planeheight > check->SkyBoxes[floor]->threshold) + { + FDisplacement &disp = check->FloorDisplacement(); + x += disp.pos.x; + y += disp.pos.y; + planeheight = check->SkyBoxes[floor]->threshold; + check = P_PointInSector(x, y); + } + if (resultsec) *resultsec = check; + return check->ceilingplane.ZatPoint(x, y); +} + + +//=========================================================================== +// +// Calculates the height of a sector plane, respecting portal offsets +// between two spots +// +//=========================================================================== + +fixed_t sector_t::PlaneAtPoint(const secplane_t &plane, fixed_t x, fixed_t y, int refgroup) const +{ + if (refgroup != PortalGroup) + { + FDisplacement &disp = Displacements(PortalGroup, refgroup); + x += disp.pos.x; + y += disp.pos.y; + } + return plane.ZatPoint(x, y); +} + +//=========================================================================== +// +// +// +//=========================================================================== FArchive &operator<< (FArchive &arc, secspecial_t &p) { @@ -908,6 +980,11 @@ FArchive &operator<< (FArchive &arc, secspecial_t &p) } +//=========================================================================== +// +// +// +//=========================================================================== bool secplane_t::CopyPlaneIfValid (secplane_t *dest, const secplane_t *opp) const { diff --git a/src/portal.cpp b/src/portal.cpp index a525b22f0..b787ae9f3 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -774,13 +774,13 @@ static void AddDisplacementForPortal(AStackPoint *portal) FDisplacement & disp = Displacements(thisgroup, othergroup); if (!disp.isSet) { - disp.x = portal->scaleX; - disp.y = portal->scaleY; + disp.pos.x = portal->scaleX; + disp.pos.y = portal->scaleY; disp.isSet = true; } else { - if (disp.x != portal->scaleX || disp.y != portal->scaleY) + if (disp.pos.x != portal->scaleX || disp.pos.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; @@ -810,13 +810,13 @@ static void AddDisplacementForPortal(FLinePortal *portal) FDisplacement & disp = Displacements(thisgroup, othergroup); if (!disp.isSet) { - disp.x = portal->mXDisplacement; - disp.y = portal->mYDisplacement; + disp.pos.x = portal->mXDisplacement; + disp.pos.y = portal->mYDisplacement; disp.isSet = true; } else { - if (disp.x != portal->mXDisplacement || disp.y != portal->mYDisplacement) + if (disp.pos.x != portal->mXDisplacement || disp.pos.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; @@ -857,15 +857,14 @@ static bool ConnectGroups() FDisplacement &dispxz = Displacements(x, z); if (dispxz.isSet) { - if (dispxy.x + dispyz.x != dispxz.x || dispxy.y + dispyz.y != dispxz.y) + if (dispxy.pos.x + dispyz.pos.x != dispxz.pos.x || dispxy.pos.y + dispyz.pos.y != dispxz.pos.y) { bogus = true; } } else { - dispxz.x = dispxy.x + dispyz.x; - dispxz.y = dispxy.y + dispyz.y; + dispxz.pos = dispxy.pos + dispyz.pos; dispxz.isSet = true; dispxz.indirect = indirect; changed = true; @@ -995,7 +994,7 @@ void P_CreateLinkedPortals() FDisplacement &dispxy = Displacements(x, y); FDisplacement &dispyx = Displacements(y, x); if (dispxy.isSet && dispyx.isSet && - (dispxy.x != -dispyx.x || dispxy.y != -dispyx.y)) + (dispxy.pos.x != -dispyx.pos.x || dispxy.pos.y != -dispyx.pos.y)) { int sec1 = -1, sec2 = -1; for (int i = 0; i < numsectors && (sec1 == -1 || sec2 == -1); i++) @@ -1083,7 +1082,7 @@ bool P_CollectConnectedGroups(AActor *actor, fixed_t newx, fixed_t newy, FPortal FDisplacement &disp = Displacements(thisgroup, othergroup); if (!disp.isSet) continue; // no connection. - FBoundingBox box(newx + disp.x, newy + disp.y, actor->radius); + FBoundingBox box(newx + disp.pos.x, newy + disp.pos.y, actor->radius); if (box.Right() <= ld->bbox[BOXLEFT] || box.Left() >= ld->bbox[BOXRIGHT] @@ -1117,8 +1116,8 @@ bool P_CollectConnectedGroups(AActor *actor, fixed_t newx, fixed_t newy, FPortal { sector_t *othersec = wsec->SkyBoxes[sector_t::ceiling]->Sector; FDisplacement &disp = Displacements(actor->Sector->PortalGroup, othersec->PortalGroup); - fixed_t dx = newx + disp.x; - fixed_t dy = newx + disp.y; + fixed_t dx = newx + disp.pos.x; + fixed_t dy = newx + disp.pos.y; processMask.setBit(othersec->PortalGroup); out.Add(othersec->PortalGroup); wsec = P_PointInSector(dx, dy); // get upper sector at the exact spot we want to check and repeat @@ -1129,8 +1128,8 @@ bool P_CollectConnectedGroups(AActor *actor, fixed_t newx, fixed_t newy, FPortal { sector_t *othersec = wsec->SkyBoxes[sector_t::ceiling]->Sector; FDisplacement &disp = Displacements(actor->Sector->PortalGroup, othersec->PortalGroup); - fixed_t dx = newx + disp.x; - fixed_t dy = newx + disp.y; + fixed_t dx = newx + disp.pos.x; + fixed_t dy = newx + disp.pos.y; processMask.setBit(othersec->PortalGroup); out.Add(othersec->PortalGroup); wsec = P_PointInSector(dx, dy); // get lower sector at the exact spot we want to check and repeat @@ -1153,7 +1152,7 @@ CCMD(dumplinktable) 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("%c%c(%6d, %6d)", TEXTCOLOR_ESCAPE, 'C' + disp.indirect, disp.pos.x >> FRACBITS, disp.pos.y >> FRACBITS); } Printf("\n"); } diff --git a/src/portal.h b/src/portal.h index 40c4a30fc..88eee2d64 100644 --- a/src/portal.h +++ b/src/portal.h @@ -30,9 +30,14 @@ struct FPortalGroupArray; struct FDisplacement { - fixed_t x, y; + fixedvec2 pos; bool isSet; BYTE indirect; // just for illustration. + + operator fixedvec2() + { + return pos; + } }; struct FDisplacementTable @@ -222,4 +227,15 @@ inline bool sector_t::PortalBlocksSound(int plane) return !!(planes[plane].Flags & (PLANEF_BLOCKSOUND | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); } +// These may only be called if the portal has been validated +inline FDisplacement §or_t::FloorDisplacement() +{ + return Displacements(PortalGroup, SkyBoxes[sector_t::floor]->Sector->PortalGroup); +} + +inline FDisplacement §or_t::CeilingDisplacement() +{ + return Displacements(PortalGroup, SkyBoxes[sector_t::ceiling]->Sector->PortalGroup); +} + #endif \ No newline at end of file diff --git a/src/r_defs.h b/src/r_defs.h index 6913d868b..15b7337cd 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -55,6 +55,7 @@ enum }; extern size_t MaxDrawSegs; +struct FDisplacement; enum @@ -242,6 +243,16 @@ struct secplane_t return ic < 0 ? d : -d; } + fixed_t ZatPoint(const fixedvec2 &spot) const + { + return FixedMul(ic, -d - DMulScale16(a, spot.x, b, spot.y)); + } + + fixed_t ZatPoint(const fixedvec3 &spot) const + { + return FixedMul(ic, -d - DMulScale16(a, spot.x, b, spot.y)); + } + // Returns the value of z at (x,y) fixed_t ZatPoint (fixed_t x, fixed_t y) const { @@ -702,17 +713,6 @@ struct sector_t return pos == floor? floorplane:ceilingplane; } - fixed_t HighestCeiling(AActor *a) const - { - return ceilingplane.ZatPoint(a); - } - - fixed_t LowestFloor(AActor *a) const - { - return floorplane.ZatPoint(a); - } - - bool isSecret() const { return !!(Flags & SECF_SECRET); @@ -750,6 +750,63 @@ struct sector_t void SetSpecial(const secspecial_t *spec); bool PlaneMoving(int pos); + // Portal-aware height calculation + fixed_t HighestCeilingAt(fixed_t x, fixed_t y, sector_t **resultsec = NULL); + fixed_t LowestFloorAt(fixed_t x, fixed_t y, sector_t **resultsec = NULL); + + fixed_t HighestCeilingAt(AActor *a, sector_t **resultsec = NULL) + { + return HighestCeilingAt(a->X(), a->X(), resultsec); + } + + fixed_t LowestFloorAt(AActor *a, sector_t **resultsec = NULL) + { + return LowestFloorAt(a->X(), a->Y(), resultsec); + } + + // ... for ceilings + fixed_t CeilingAtPoint(fixed_t x, fixed_t y, int refgroup) const + { + return PlaneAtPoint(ceilingplane, x, y, refgroup); + } + fixed_t CeilingAtPoint(AActor *actor) const + { + return PlaneAtPoint(ceilingplane, actor->X(), actor->Y(), actor->Sector->PortalGroup); + } + fixed_t CeilingAtPoint(fixed_t x, fixed_t y, sector_t *refsector) const + { + return PlaneAtPoint(ceilingplane, x, y, refsector->PortalGroup); + } + + // ... for floors + fixed_t FloorAtPoint(fixed_t x, fixed_t y, int refgroup) const + { + return PlaneAtPoint(floorplane, x, y, refgroup); + } + fixed_t FloorAtPoint(AActor *actor) const + { + return PlaneAtPoint(floorplane, actor->X(), actor->Y(), actor->Sector->PortalGroup); + } + fixed_t FloorAtPoint(fixed_t x, fixed_t y, sector_t *refsector) const + { + return PlaneAtPoint(floorplane, x, y, refsector->PortalGroup); + } + + // ... for control sectors + fixed_t PlaneAtPoint(const secplane_t &plane, AActor *actor) const + { + return PlaneAtPoint(plane, actor->X(), actor->Y(), actor->Sector->PortalGroup); + } + fixed_t PlaneAtPoint(const secplane_t &plane, fixed_t x, fixed_t y, sector_t *refsector) const + { + return PlaneAtPoint(plane, x, y, refsector->PortalGroup); + } + + // The worker function for all the above. + fixed_t PlaneAtPoint(const secplane_t &plane, fixed_t x, fixed_t y, int refgroup) const; + + FDisplacement &FloorDisplacement(); + FDisplacement &CeilingDisplacement(); // Member variables fixed_t CenterFloor () const { return floorplane.ZatPoint (soundorg[0], soundorg[1]); } @@ -1165,5 +1222,6 @@ inline sector_t *P_PointInSector(fixed_t x, fixed_t y) return P_PointInSubsector(x, y)->sector; } +#define _ZatPoint ZatPoint // so that it still compiles during the transition #endif From ae02b2fcaf9758ba011288933650e7b20b17f978 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 16 Feb 2016 21:00:34 +0100 Subject: [PATCH 02/28] - added NextHighestCeiling/NextLowestFloorAt functions. Not tested yet! --- src/p_acs.cpp | 41 +++--------------- src/p_sectors.cpp | 108 ++++++++++++++++++++++++++++++++++++++++++++++ src/r_defs.h | 13 ++++++ 3 files changed, 127 insertions(+), 35 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 7155c98e6..9d2899d7e 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4181,47 +4181,18 @@ bool DLevelScript::DoCheckActorTexture(int tid, AActor *activator, int string, b } int i, numff; FTextureID secpic; - sector_t *sec = actor->Sector; - numff = sec->e->XFloor.ffloors.Size(); + sector_t *resultsec; + F3DFloor *resffloor; if (floor) { - // Looking through planes from top to bottom - for (i = 0; i < numff; ++i) - { - F3DFloor *ff = sec->e->XFloor.ffloors[i]; - - if ((ff->flags & (FF_EXISTS | FF_SOLID)) == (FF_EXISTS | FF_SOLID) && - actor->Z() >= ff->top.plane->ZatPoint(actor)) - { // This floor is beneath our feet. - secpic = *ff->top.texture; - break; - } - } - if (i == numff) - { // Use sector's floor - secpic = sec->GetTexture(sector_t::floor); - } + actor->Sector->NextLowestFloorAt(actor, actor->Z(), &resultsec, &resffloor); + secpic = resffloor ? *resffloor->top.texture : resultsec->planes[sector_t::floor].Texture; } else { - fixed_t z = actor->Top(); - // Looking through planes from bottom to top - for (i = numff-1; i >= 0; --i) - { - F3DFloor *ff = sec->e->XFloor.ffloors[i]; - - if ((ff->flags & (FF_EXISTS | FF_SOLID)) == (FF_EXISTS | FF_SOLID) && - z <= ff->bottom.plane->ZatPoint(actor)) - { // This floor is above our eyes. - secpic = *ff->bottom.texture; - break; - } - } - if (i < 0) - { // Use sector's ceiling - secpic = sec->GetTexture(sector_t::ceiling); - } + actor->Sector->NextHighestCeilingAt(actor, actor->Top(), &resultsec, &resffloor); + secpic = resffloor ? *resffloor->bottom.texture : resultsec->planes[sector_t::ceiling].Texture; } return tex == TexMan[secpic]; } diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 1a4d218cf..51d007878 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -932,6 +932,74 @@ fixed_t sector_t::LowestFloorAt(fixed_t x, fixed_t y, sector_t **resultsec) } +fixed_t sector_t::NextHighestCeilingAt(fixed_t x, fixed_t y, fixed_t z, sector_t **resultsec, F3DFloor **resultffloor) +{ + sector_t *sec = this; + while (true) + { + // Looking through planes from bottom to top + for (int i = sec->e->XFloor.ffloors.Size() - 1; i >= 0; --i) + { + F3DFloor *ff = sec->e->XFloor.ffloors[i]; + + fixed_t ffz = ff->bottom.plane->ZatPoint(x, y); + if ((ff->flags & (FF_EXISTS | FF_SOLID)) == (FF_EXISTS | FF_SOLID) && z <= ffz) + { // This floor is above our eyes. + if (resultsec) *resultsec = sec; + if (resultffloor) *resultffloor = ff; + return ffz; + } + } + if (sec->PortalBlocksMovement(sector_t::ceiling)) + { // Use sector's floor + if (resultffloor) *resultffloor = NULL; + if (resultsec) *resultsec = sec; + return sec->ceilingplane.ZatPoint(x, y); + } + else + { + FDisplacement &disp = sec->CeilingDisplacement(); + x += disp.pos.x; + y += disp.pos.y; + } + } +} + +fixed_t sector_t::NextLowestFloorAt(fixed_t x, fixed_t y, fixed_t z, sector_t **resultsec, F3DFloor **resultffloor) +{ + sector_t *sec = this; + while (true) + { + // Looking through planes from top to bottom + unsigned numff = sec->e->XFloor.ffloors.Size(); + for (unsigned i = 0; i < numff; ++i) + { + F3DFloor *ff = sec->e->XFloor.ffloors[i]; + + fixed_t ffz = ff->top.plane->ZatPoint(x, y); + if ((ff->flags & (FF_EXISTS | FF_SOLID)) == (FF_EXISTS | FF_SOLID) && z >= ffz) + { // This floor is beneath our feet. + if (resultsec) *resultsec = sec; + if (resultffloor) *resultffloor = ff; + return ffz; + } + } + if (sec->PortalBlocksMovement(sector_t::floor)) + { // Use sector's floor + if (resultffloor) *resultffloor = NULL; + if (resultsec) *resultsec = sec; + return sec->floorplane.ZatPoint(x, y); + } + else + { + FDisplacement &disp = sec->FloorDisplacement(); + x += disp.pos.x; + y += disp.pos.y; + sec = P_PointInSector(x, y); + } + } +} + //=========================================================================== // // Calculates the height of a sector plane, respecting portal offsets @@ -1163,3 +1231,43 @@ int side_t::GetLightLevel (bool foggy, int baselight, bool is3dlight, int *pfake return baselight; } +#include "c_dispatch.h" +#include "d_player.h" + +CCMD(highestceiling) +{ + sector_t *sec; + fixed_t h = players[consoleplayer].mo->Sector->HighestCeilingAt(players[consoleplayer].mo, &sec); + Printf("Check at position %f,%f, height = %f, srcsector = %d dstsector = %d, srcgroup = %d, dstgroup = %d\n", + players[consoleplayer].mo->X() / 65536., players[consoleplayer].mo->Y() / 65536., h / 65536., + players[consoleplayer].mo->Sector->sectornum, sec->sectornum, players[consoleplayer].mo->Sector->PortalGroup, sec->PortalGroup); +} + +CCMD(lowestfloor) +{ + sector_t *sec; + fixed_t h = players[consoleplayer].mo->Sector->LowestFloorAt(players[consoleplayer].mo, &sec); + Printf("Check at position %f,%f, height = %f, srcsector = %d dstsector = %d, srcgroup = %d, dstgroup = %d\n", + players[consoleplayer].mo->X() / 65536., players[consoleplayer].mo->Y() / 65536., h / 65536., + players[consoleplayer].mo->Sector->sectornum, sec->sectornum, players[consoleplayer].mo->Sector->PortalGroup, sec->PortalGroup); +} + +CCMD(nexthighestceiling) +{ + sector_t *sec; + F3DFloor *ff; + fixed_t h = players[consoleplayer].mo->Sector->NextHighestCeilingAt(players[consoleplayer].mo, players[consoleplayer].mo->Top(), &sec, &ff); + Printf("Check at position %f,%f, height = %f, srcsector = %d dstsector = %d, srcgroup = %d, dstgroup = %d, 3dfloor = %d\n", + players[consoleplayer].mo->X() / 65536., players[consoleplayer].mo->Y() / 65536., h / 65536., + players[consoleplayer].mo->Sector->sectornum, sec->sectornum, players[consoleplayer].mo->Sector->PortalGroup, sec->PortalGroup, !!ff); +} + +CCMD(nextlowestfloor) +{ + sector_t *sec; + F3DFloor *ff; + fixed_t h = players[consoleplayer].mo->Sector->NextLowestFloorAt(players[consoleplayer].mo, players[consoleplayer].mo->Z(), &sec, &ff); + Printf("Check at position %f,%f, height = %f, srcsector = %d dstsector = %d, srcgroup = %d, dstgroup = %d, 3dfloor = %d\n", + players[consoleplayer].mo->X() / 65536., players[consoleplayer].mo->Y() / 65536., h / 65536., + players[consoleplayer].mo->Sector->sectornum, sec->sectornum, players[consoleplayer].mo->Sector->PortalGroup, sec->PortalGroup, !!ff); +} diff --git a/src/r_defs.h b/src/r_defs.h index 15b7337cd..739151c06 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -764,6 +764,19 @@ struct sector_t return LowestFloorAt(a->X(), a->Y(), resultsec); } + fixed_t NextHighestCeilingAt(fixed_t x, fixed_t y, fixed_t z, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL); + fixed_t NextLowestFloorAt(fixed_t x, fixed_t y, fixed_t z, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL); + + fixed_t NextHighestCeilingAt(AActor *a, fixed_t z, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL) + { + return NextHighestCeilingAt(a->X(), a->Y(), z, resultsec, resultffloor); + } + + fixed_t NextLowestFloorAt(AActor *a, fixed_t z, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL) + { + return NextLowestFloorAt(a->X(), a->Y(), z, resultsec, resultffloor); + } + // ... for ceilings fixed_t CeilingAtPoint(fixed_t x, fixed_t y, int refgroup) const { From 8d53f6176eadb65c0fe4811a0a9819914f7d8192 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 16 Feb 2016 22:56:36 +0100 Subject: [PATCH 03/28] - fixed conditions for PortalBlocksView. Created a new function PortalBlocksSight that's relevant for playsim-related sight checks. --- src/portal.h | 7 +++++++ src/r_defs.h | 1 + 2 files changed, 8 insertions(+) diff --git a/src/portal.h b/src/portal.h index 88eee2d64..1e00acf81 100644 --- a/src/portal.h +++ b/src/portal.h @@ -210,6 +210,13 @@ inline int line_t::getPortalAlignment() const } inline bool sector_t::PortalBlocksView(int plane) +{ + if (SkyBoxes[plane] == NULL) return true; + if (SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return false; + return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); +} + +inline bool sector_t::PortalBlocksSight(int plane) { if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true; return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); diff --git a/src/r_defs.h b/src/r_defs.h index 739151c06..eb08cec7b 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -740,6 +740,7 @@ struct sector_t } bool PortalBlocksView(int plane); + bool PortalBlocksSight(int plane); bool PortalBlocksMovement(int plane); bool PortalBlocksSound(int plane); From fd7e6ae604814adc908f300fb0c534a596e25791 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 16 Feb 2016 23:11:20 +0100 Subject: [PATCH 04/28] - fixed copy&paste error in LowestFloorAt. --- src/p_sectors.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 51d007878..606e85575 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -928,7 +928,7 @@ fixed_t sector_t::LowestFloorAt(fixed_t x, fixed_t y, sector_t **resultsec) check = P_PointInSector(x, y); } if (resultsec) *resultsec = check; - return check->ceilingplane.ZatPoint(x, y); + return check->floorplane.ZatPoint(x, y); } From 5611df1f3ebd26565f0f6e2e5157dae3f0e7fa2e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 17 Feb 2016 00:29:50 +0100 Subject: [PATCH 05/28] - fixed the portal aware ceiling and floor functions. --- src/p_sectors.cpp | 10 ++++++++-- src/r_defs.h | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 606e85575..db439f4a5 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -935,6 +935,8 @@ fixed_t sector_t::LowestFloorAt(fixed_t x, fixed_t y, sector_t **resultsec) fixed_t sector_t::NextHighestCeilingAt(fixed_t x, fixed_t y, fixed_t z, sector_t **resultsec, F3DFloor **resultffloor) { sector_t *sec = this; + fixed_t planeheight = FIXED_MIN; + while (true) { // Looking through planes from bottom to top @@ -950,7 +952,7 @@ fixed_t sector_t::NextHighestCeilingAt(fixed_t x, fixed_t y, fixed_t z, sector_t return ffz; } } - if (sec->PortalBlocksMovement(sector_t::ceiling)) + if (sec->PortalBlocksMovement(ceiling) || planeheight >= sec->SkyBoxes[ceiling]->threshold) { // Use sector's floor if (resultffloor) *resultffloor = NULL; if (resultsec) *resultsec = sec; @@ -961,6 +963,8 @@ fixed_t sector_t::NextHighestCeilingAt(fixed_t x, fixed_t y, fixed_t z, sector_t FDisplacement &disp = sec->CeilingDisplacement(); x += disp.pos.x; y += disp.pos.y; + planeheight = sec->SkyBoxes[ceiling]->threshold; + sec = P_PointInSector(x, y); } } } @@ -968,6 +972,7 @@ fixed_t sector_t::NextHighestCeilingAt(fixed_t x, fixed_t y, fixed_t z, sector_t fixed_t sector_t::NextLowestFloorAt(fixed_t x, fixed_t y, fixed_t z, sector_t **resultsec, F3DFloor **resultffloor) { sector_t *sec = this; + fixed_t planeheight = FIXED_MAX; while (true) { // Looking through planes from top to bottom @@ -984,7 +989,7 @@ fixed_t sector_t::NextLowestFloorAt(fixed_t x, fixed_t y, fixed_t z, sector_t ** return ffz; } } - if (sec->PortalBlocksMovement(sector_t::floor)) + if (sec->PortalBlocksMovement(sector_t::floor) || planeheight <= sec->SkyBoxes[floor]->threshold) { // Use sector's floor if (resultffloor) *resultffloor = NULL; if (resultsec) *resultsec = sec; @@ -995,6 +1000,7 @@ fixed_t sector_t::NextLowestFloorAt(fixed_t x, fixed_t y, fixed_t z, sector_t ** FDisplacement &disp = sec->FloorDisplacement(); x += disp.pos.x; y += disp.pos.y; + planeheight = sec->SkyBoxes[floor]->threshold; sec = P_PointInSector(x, y); } } diff --git a/src/r_defs.h b/src/r_defs.h index eb08cec7b..6376dd71e 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -757,7 +757,7 @@ struct sector_t fixed_t HighestCeilingAt(AActor *a, sector_t **resultsec = NULL) { - return HighestCeilingAt(a->X(), a->X(), resultsec); + return HighestCeilingAt(a->X(), a->Y(), resultsec); } fixed_t LowestFloorAt(AActor *a, sector_t **resultsec = NULL) From 094844898801be3832a56203de7f430c37a0963f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 17 Feb 2016 02:21:26 +0100 Subject: [PATCH 06/28] - some more checking and refactoring of ZatPoint calls. - removed Plane/Floor/CeilingAtPoint functions because they are overkill for the problem they were meant to solve. Calling ZatPoint with adjusted coordinates created with AActor::PosRelative is just as easy in the few places where this is needed. - made P_HitWater and P_CheckSplash portal aware. --- src/g_shared/a_fastprojectile.cpp | 2 +- src/p_enemy.cpp | 6 ++--- src/p_maputl.cpp | 4 +-- src/p_mobj.cpp | 39 ++++++++++++++++++----------- src/p_sectors.cpp | 18 -------------- src/p_spec.cpp | 9 ++++--- src/r_defs.h | 41 ------------------------------- 7 files changed, 35 insertions(+), 84 deletions(-) diff --git a/src/g_shared/a_fastprojectile.cpp b/src/g_shared/a_fastprojectile.cpp index baad73628..3a8e8e5ec 100644 --- a/src/g_shared/a_fastprojectile.cpp +++ b/src/g_shared/a_fastprojectile.cpp @@ -82,7 +82,7 @@ void AFastProjectile::Tick () if (tm.ceilingline && tm.ceilingline->backsector && tm.ceilingline->backsector->GetTexture(sector_t::ceiling) == skyflatnum && - Z() >= tm.ceilingline->backsector->CeilingAtPoint(this)) + Z() >= tm.ceilingline->backsector->ceilingplane.ZatPoint(PosRelative(tm.ceilingline)) { // Hack to prevent missiles exploding against the sky. // Does not handle sky floors. diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 49451c5d6..9ffb17c27 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -558,7 +558,7 @@ bool P_Move (AActor *actor) else { // The monster just hit the floor, so trigger any actions. if (actor->floorsector->SecActTarget != NULL && - actor->floorz == actor->floorsector->FloorAtPoint(actor)) + actor->floorz == actor->floorsector->floorplane.ZatPoint(actor->PosRelative(actor->floorsector)) { actor->floorsector->SecActTarget->TriggerAction(actor, SECSPAC_HitFloor); } @@ -868,8 +868,8 @@ void P_NewChaseDir(AActor * actor) box.Bottom() < line->bbox[BOXTOP] && box.BoxOnLineSide(line) == -1) { - fixed_t front = line->frontsector->FloorAtPoint(actor); - fixed_t back = line->backsector->FloorAtPoint(actor); + fixed_t front = line->frontsector->floorplane.ZatPoint(actor->PosRelative(line)); + fixed_t back = line->backsector->floorplane.ZatPoint(actor->PosRelative(line)); angle_t angle; // The monster must contact one of the two floors, diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index e09c86eb4..53d7d14e9 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -513,8 +513,8 @@ void AActor::SetOrigin (fixed_t ix, fixed_t iy, fixed_t iz, bool moving) SetXYZ(ix, iy, iz); if (moving) SetMovement(ix - X(), iy - Y(), iz - Z()); LinkToWorld (); - floorz = Sector->floorplane.ZatPoint (ix, iy); - ceilingz = Sector->ceilingplane.ZatPoint (ix, iy); + floorz = Sector->LowestFloorAt(ix, iy, &floorsector); + ceilingz = Sector->HighestCeilingAt(ix, iy, &ceilingsector); P_FindFloorCeiling(this, FFCF_ONLYSPAWNPOS); } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 82326c39b..60724bbe5 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -2186,7 +2186,7 @@ explode: if (tm.ceilingline && tm.ceilingline->backsector && tm.ceilingline->backsector->GetTexture(sector_t::ceiling) == skyflatnum && - mo->Z() >= tm.ceilingline->backsector->ceilingplane.ZatPoint(mo)) + mo->Z() >= tm.ceilingline->backsector->ceilingplane.ZatPoint(mo->PosRelative(tm.ceilingline))) { // Hack to prevent missiles exploding against the sky. // Does not handle sky floors. @@ -3640,7 +3640,8 @@ void AActor::Tick () { continue; } - height = sec->floorplane.ZatPoint (this); + fixedvec3 pos = PosRelative(sec); + height = sec->floorplane.ZatPoint (pos); if (Z() > height) { if (heightsec == NULL) @@ -3648,7 +3649,7 @@ void AActor::Tick () continue; } - waterheight = heightsec->floorplane.ZatPoint (this); + waterheight = heightsec->floorplane.ZatPoint (pos); if (waterheight > height && Z() >= waterheight) { continue; @@ -3689,7 +3690,7 @@ void AActor::Tick () floorplane = P_FindFloorPlane(floorsector, X(), Y(), floorz); if (floorplane.c < STEEPSLOPE && - floorplane.ZatPoint (this) <= floorz) + floorplane.ZatPoint (PosRelative(floorsector)) <= floorz) { const msecnode_t *node; bool dopush = true; @@ -3701,7 +3702,7 @@ void AActor::Tick () const sector_t *sec = node->m_sector; if (sec->floorplane.c >= STEEPSLOPE) { - if (floorplane.ZatPoint (this) >= Z() - MaxStepHeight) + if (floorplane.ZatPoint (PosRelative(node->m_sector)) >= Z() - MaxStepHeight) { dopush = false; break; @@ -4171,6 +4172,8 @@ AActor *AActor::StaticSpawn (PClassActor *type, fixed_t ix, fixed_t iy, fixed_t // z-coordinate. if (!SpawningMapThing) { + actor->ceilingz = actor->Sector->HighestCeilingAt(actor, &actor->ceilingsector); + actor->dropoffz = actor->floorz = actor->Sector->LowestFloorAt(actor, &actor->floorsector); P_FindFloorCeiling(actor, FFCF_ONLYSPAWNPOS); } else @@ -4477,15 +4480,16 @@ void AActor::AdjustFloorClip () const msecnode_t *m; // possibly standing on a 3D-floor - if (Sector->e->XFloor.ffloors.Size() && Z()>Sector->floorplane.ZatPoint(this)) floorclip=0; + if (Sector->e->XFloor.ffloors.Size() && Z() > Sector->floorplane.ZatPoint(this)) floorclip = 0; // [RH] clip based on shallowest floor player is standing on // If the sector has a deep water effect, then let that effect // do the floorclipping instead of the terrain type. for (m = touching_sectorlist; m; m = m->m_tnext) { + fixedvec3 pos = PosRelative(m->m_sector); sector_t *hsec = m->m_sector->GetHeightSec(); - if (hsec == NULL && m->m_sector->floorplane.ZatPoint (this) == Z()) + if (hsec == NULL && m->m_sector->floorplane.ZatPoint (pos) == Z()) { fixed_t clip = Terrains[m->m_sector->GetTerrain(sector_t::floor)].FootClip; if (clip < shallowestclip) @@ -5523,9 +5527,9 @@ bool P_HitWater (AActor * thing, sector_t * sec, fixed_t x, fixed_t y, fixed_t z fixed_t planez = rover->top.plane->ZatPoint(x, y); if (z > planez - FRACUNIT / 2 && z < planez + FRACUNIT / 2) // allow minor imprecisions { - if (rover->flags & (FF_SOLID | FF_SWIMMABLE)) + if (rover->flags & (FF_SOLID | FF_SWIMMABLE)) { - terrainnum = rover->model->GetTerrain(rover->top.isceiling); + terrainnum = rover->model->GetTerrain(rover->top.isceiling); goto foundone; } } @@ -5638,9 +5642,11 @@ bool P_HitFloor (AActor *thing) return false; // don't splash if landing on the edge above water/lava/etc.... + fixedvec3 pos; for (m = thing->touching_sectorlist; m; m = m->m_tnext) { - if (thing->Z() == m->m_sector->floorplane.ZatPoint(thing)) + pos = thing->PosRelative(m->m_sector); + if (thing->Z() == m->m_sector->floorplane.ZatPoint(pos.x, pos.y)) { break; } @@ -5652,9 +5658,9 @@ bool P_HitFloor (AActor *thing) if (!(rover->flags & FF_EXISTS)) continue; if (rover->flags & (FF_SOLID|FF_SWIMMABLE)) { - if (rover->top.plane->ZatPoint(thing) == thing->Z()) + if (rover->top.plane->ZatPoint(pos.x, pos.y) == thing->Z()) { - return P_HitWater (thing, m->m_sector); + return P_HitWater (thing, m->m_sector, pos.x, pos.y, pos.z); } } } @@ -5664,7 +5670,7 @@ bool P_HitFloor (AActor *thing) return false; } - return P_HitWater (thing, m->m_sector); + return P_HitWater (thing, m->m_sector, pos.x, pos.y, pos.z); } //--------------------------------------------------------------------------- @@ -5677,12 +5683,15 @@ bool P_HitFloor (AActor *thing) void P_CheckSplash(AActor *self, fixed_t distance) { - if (self->Z() <= self->floorz + (distance<floorsector == self->Sector && self->Sector->GetHeightSec() == NULL) + sector_t *floorsec; + self->Sector->LowestFloorAt(self, &floorsec); + if (self->Z() <= self->floorz + (distance<floorsector == floorsec && self->Sector->GetHeightSec() == NULL && floorsec->heightsec == NULL) { // Explosion splashes never alert monsters. This is because A_Explode has // a separate parameter for that so this would get in the way of proper // behavior. - P_HitWater (self, self->Sector, self->X(), self->Y(), self->floorz, false, false); + fixedvec3 pos = self->PosRelative(floorsec); + P_HitWater (self, floorsec, pos.x, pos.y, self->floorz, false, false); } } diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 606e85575..f6d126cc0 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -1000,24 +1000,6 @@ fixed_t sector_t::NextLowestFloorAt(fixed_t x, fixed_t y, fixed_t z, sector_t ** } } -//=========================================================================== -// -// Calculates the height of a sector plane, respecting portal offsets -// between two spots -// -//=========================================================================== - -fixed_t sector_t::PlaneAtPoint(const secplane_t &plane, fixed_t x, fixed_t y, int refgroup) const -{ - if (refgroup != PortalGroup) - { - FDisplacement &disp = Displacements(PortalGroup, refgroup); - x += disp.pos.x; - y += disp.pos.y; - } - return plane.ZatPoint(x, y); -} - //=========================================================================== // // diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 45ed51be2..7e57cd0f8 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -440,7 +440,7 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector) { // Falling, not all the way down yet? sector = player->mo->Sector; - if (player->mo->Z() != sector->floorplane.ZatPoint(player->mo) + if (player->mo->Z() != sector->LowestFloorAt(player->mo) && !player->mo->waterlevel) { return; @@ -480,7 +480,7 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector) } if (sector->Flags & SECF_DMGTERRAINFX) { - P_HitWater(player->mo, sector, INT_MIN, INT_MIN, INT_MIN, false, true, true); + P_HitWater(player->mo, player->mo->Sector, INT_MIN, INT_MIN, INT_MIN, false, true, true); } } } @@ -2299,6 +2299,7 @@ void DPusher::Tick () continue; sector_t *hsec = sec->GetHeightSec(); + fixedvec2 pos = thing->PosRelative(sec); if (m_Type == p_wind) { if (hsec == NULL) @@ -2316,7 +2317,7 @@ void DPusher::Tick () } else // special water sector { - ht = hsec->floorplane.ZatPoint(thing); + ht = hsec->floorplane.ZatPoint(pos); if (thing->Z() > ht) // above ground { xspeed = m_Xmag; // full force @@ -2345,7 +2346,7 @@ void DPusher::Tick () { // special water sector floor = &hsec->floorplane; } - if (thing->Z() > floor->ZatPoint(thing)) + if (thing->Z() > floor->ZatPoint(pos)) { // above ground xspeed = yspeed = 0; // no force } diff --git a/src/r_defs.h b/src/r_defs.h index eb08cec7b..90d71dcd0 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -778,47 +778,6 @@ struct sector_t return NextLowestFloorAt(a->X(), a->Y(), z, resultsec, resultffloor); } - // ... for ceilings - fixed_t CeilingAtPoint(fixed_t x, fixed_t y, int refgroup) const - { - return PlaneAtPoint(ceilingplane, x, y, refgroup); - } - fixed_t CeilingAtPoint(AActor *actor) const - { - return PlaneAtPoint(ceilingplane, actor->X(), actor->Y(), actor->Sector->PortalGroup); - } - fixed_t CeilingAtPoint(fixed_t x, fixed_t y, sector_t *refsector) const - { - return PlaneAtPoint(ceilingplane, x, y, refsector->PortalGroup); - } - - // ... for floors - fixed_t FloorAtPoint(fixed_t x, fixed_t y, int refgroup) const - { - return PlaneAtPoint(floorplane, x, y, refgroup); - } - fixed_t FloorAtPoint(AActor *actor) const - { - return PlaneAtPoint(floorplane, actor->X(), actor->Y(), actor->Sector->PortalGroup); - } - fixed_t FloorAtPoint(fixed_t x, fixed_t y, sector_t *refsector) const - { - return PlaneAtPoint(floorplane, x, y, refsector->PortalGroup); - } - - // ... for control sectors - fixed_t PlaneAtPoint(const secplane_t &plane, AActor *actor) const - { - return PlaneAtPoint(plane, actor->X(), actor->Y(), actor->Sector->PortalGroup); - } - fixed_t PlaneAtPoint(const secplane_t &plane, fixed_t x, fixed_t y, sector_t *refsector) const - { - return PlaneAtPoint(plane, x, y, refsector->PortalGroup); - } - - // The worker function for all the above. - fixed_t PlaneAtPoint(const secplane_t &plane, fixed_t x, fixed_t y, int refgroup) const; - FDisplacement &FloorDisplacement(); FDisplacement &CeilingDisplacement(); From 10a3d75556f44a95c76ac3073bbc60f6915ab24b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 17 Feb 2016 11:39:14 +0100 Subject: [PATCH 07/28] - reviewed and adjusted ZatPoint calls in p_map.cpp. --- src/p_map.cpp | 57 +++++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index b77d6c55a..1a17aa5b8 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -242,11 +242,9 @@ void P_GetFloorCeilingZ(FCheckPosition &tmf, int flags) if (!(flags & FFCF_ONLYSPAWNPOS)) { sec = !(flags & FFCF_SAMESECTOR) ? P_PointInSector(tmf.x, tmf.y) : tmf.thing->Sector; - tmf.floorsector = sec; - tmf.ceilingsector = sec; - tmf.floorz = tmf.dropoffz = sec->floorplane.ZatPoint(tmf.x, tmf.y); - tmf.ceilingz = sec->ceilingplane.ZatPoint(tmf.x, tmf.y); + tmf.floorz = tmf.dropoffz = sec->LowestFloorAt(tmf.x, tmf.y, &tmf.floorsector); + tmf.ceilingz = sec->HighestCeilingAt(tmf.x, tmf.y, &tmf.ceilingsector); tmf.floorpic = sec->GetTexture(sector_t::floor); tmf.floorterrain = sec->GetTerrain(sector_t::floor); tmf.ceilingpic = sec->GetTexture(sector_t::ceiling); @@ -584,7 +582,7 @@ int P_GetFriction(const AActor *mo, int *frictionfactor) int movefactor = ORIG_FRICTION_FACTOR; fixed_t newfriction; const msecnode_t *m; - const sector_t *sec; + sector_t *sec; if (mo->IsNoClip2()) { @@ -627,6 +625,7 @@ int P_GetFriction(const AActor *mo, int *frictionfactor) for (m = mo->touching_sectorlist; m; m = m->m_tnext) { sec = m->m_sector; + fixedvec3 pos = mo->PosRelative(sec); // 3D floors must be checked, too for (unsigned i = 0; i < sec->e->XFloor.ffloors.Size(); i++) @@ -637,13 +636,13 @@ int P_GetFriction(const AActor *mo, int *frictionfactor) if (rover->flags & FF_SOLID) { // Must be standing on a solid floor - if (mo->Z() != rover->top.plane->ZatPoint(mo)) continue; + if (mo->Z() != rover->top.plane->ZatPoint(pos)) continue; } else if (rover->flags & FF_SWIMMABLE) { // Or on or inside a swimmable floor (e.g. in shallow water) - if (mo->Z() > rover->top.plane->ZatPoint(mo) || - (mo->Top()) < rover->bottom.plane->ZatPoint(mo)) + if (mo->Z() > rover->top.plane->ZatPoint(pos) || + (mo->Top()) < rover->bottom.plane->ZatPoint(pos)) continue; } else @@ -664,9 +663,9 @@ int P_GetFriction(const AActor *mo, int *frictionfactor) } newfriction = secfriction(sec); if ((newfriction < friction || friction == ORIG_FRICTION) && - (mo->Z() <= sec->floorplane.ZatPoint(mo) || + (mo->Z() <= sec->floorplane.ZatPoint(pos) || (sec->GetHeightSec() != NULL && - mo->Z() <= sec->heightsec->floorplane.ZatPoint(mo)))) + mo->Z() <= sec->heightsec->floorplane.ZatPoint(pos)))) { friction = newfriction; movefactor = secmovefac(sec); @@ -1462,13 +1461,11 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo // The base floor / ceiling is from the subsector that contains the point. // Any contacted lines the step closer together will adjust them. - tm.floorz = tm.dropoffz = newsec->floorplane.ZatPoint(x, y); - tm.ceilingz = newsec->ceilingplane.ZatPoint(x, y); - tm.floorpic = newsec->GetTexture(sector_t::floor); - tm.floorterrain = newsec->GetTerrain(sector_t::floor); - tm.floorsector = newsec; - tm.ceilingpic = newsec->GetTexture(sector_t::ceiling); - tm.ceilingsector = newsec; + tm.floorz = tm.dropoffz = newsec->LowestFloorAt(x, y, &tm.floorsector); + tm.ceilingz = newsec->HighestCeilingAt(x, y, &tm.ceilingsector); + tm.floorpic = tm.floorsector->GetTexture(sector_t::floor); + tm.floorterrain = tm.floorsector->GetTerrain(sector_t::floor); + tm.ceilingpic = tm.ceilingsector->GetTexture(sector_t::ceiling); tm.touchmidtex = false; tm.abovemidtex = false; @@ -1815,10 +1812,11 @@ static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, bool windo if (windowcheck && !(ib_compatflags & BCOMPATF_NOWINDOWCHECK) && line->backsector != NULL) { // Make sure this line actually blocks us and is not a window // or similar construct we are standing inside of. - fixed_t fzt = line->frontsector->ceilingplane.ZatPoint(mobj); - fixed_t fzb = line->frontsector->floorplane.ZatPoint(mobj); - fixed_t bzt = line->backsector->ceilingplane.ZatPoint(mobj); - fixed_t bzb = line->backsector->floorplane.ZatPoint(mobj); + fixedvec3 pos = mobj->PosRelative(line); + fixed_t fzt = line->frontsector->ceilingplane.ZatPoint(pos); + fixed_t fzb = line->frontsector->floorplane.ZatPoint(pos); + fixed_t bzt = line->backsector->ceilingplane.ZatPoint(pos); + fixed_t bzb = line->backsector->floorplane.ZatPoint(pos); if (fzt >= mobj->Top() && bzt >= mobj->Top() && fzb <= mobj->Z() && bzb <= mobj->Z()) { @@ -1829,8 +1827,8 @@ static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, bool windo if (!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue; - fixed_t ff_bottom = rover->bottom.plane->ZatPoint(mobj); - fixed_t ff_top = rover->top.plane->ZatPoint(mobj); + fixed_t ff_bottom = rover->bottom.plane->ZatPoint(pos); + fixed_t ff_top = rover->top.plane->ZatPoint(pos); if (ff_bottom < mobj->Top() && ff_top > mobj->Z()) { @@ -2760,15 +2758,16 @@ const secplane_t * P_CheckSlopeWalk(AActor *actor, fixed_t &xmove, fixed_t &ymov return NULL; } + fixedvec3 pos = actor->PosRelative(actor->floorsector); const secplane_t *plane = &actor->floorsector->floorplane; - fixed_t planezhere = plane->ZatPoint(actor); + fixed_t planezhere = plane->ZatPoint(pos); for (unsigned int i = 0; ifloorsector->e->XFloor.ffloors.Size(); i++) { F3DFloor * rover = actor->floorsector->e->XFloor.ffloors[i]; if (!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue; - fixed_t thisplanez = rover->top.plane->ZatPoint(actor); + fixed_t thisplanez = rover->top.plane->ZatPoint(pos); if (thisplanez>planezhere && thisplanez <= actor->Z() + actor->MaxStepHeight) { @@ -2836,10 +2835,14 @@ const secplane_t * P_CheckSlopeWalk(AActor *actor, fixed_t &xmove, fixed_t &ymov { for (node = actor->touching_sectorlist; node; node = node->m_tnext) { - const sector_t *sec = node->m_sector; + sector_t *sec = node->m_sector; if (sec->floorplane.c >= STEEPSLOPE) { - if (sec->floorplane.ZatPoint(destx, desty) >= actor->Z() - actor->MaxStepHeight) + fixedvec3 pos = actor->PosRelative(sec); + pos.x += xmove; + pos.y += ymove; + + if (sec->floorplane.ZatPoint(pos) >= actor->Z() - actor->MaxStepHeight) { dopush = false; break; From 884a265d4a0801411b5e2a463bd97e53f62d3de8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 17 Feb 2016 21:57:52 +0100 Subject: [PATCH 08/28] - refactored P_FindFloorCeiling to be portal aware and cleaned up its interface. A big problem with this function was that some flags required setting up some variables before calling it and others did not. It will now set everything up itself so all initializations to AActor::floorz and ceilingz that were made before these calls (which were all identical to begin with) could be removed and the internal initialization logic streamlined. --- src/g_shared/a_fastprojectile.cpp | 2 +- src/g_shared/a_pickups.cpp | 14 +++--------- src/p_enemy.cpp | 2 +- src/p_map.cpp | 38 ++++++++++++------------------- src/p_maputl.cpp | 2 -- src/p_mobj.cpp | 4 +--- src/p_spec.cpp | 2 +- src/p_user.cpp | 5 ++-- 8 files changed, 23 insertions(+), 46 deletions(-) diff --git a/src/g_shared/a_fastprojectile.cpp b/src/g_shared/a_fastprojectile.cpp index 3a8e8e5ec..ca57ad557 100644 --- a/src/g_shared/a_fastprojectile.cpp +++ b/src/g_shared/a_fastprojectile.cpp @@ -82,7 +82,7 @@ void AFastProjectile::Tick () if (tm.ceilingline && tm.ceilingline->backsector && tm.ceilingline->backsector->GetTexture(sector_t::ceiling) == skyflatnum && - Z() >= tm.ceilingline->backsector->ceilingplane.ZatPoint(PosRelative(tm.ceilingline)) + Z() >= tm.ceilingline->backsector->ceilingplane.ZatPoint(PosRelative(tm.ceilingline))) { // Hack to prevent missiles exploding against the sky. // Does not handle sky floors. diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index 256ba010c..f66659df9 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -414,7 +414,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialPosition) // Move item back to its original location fixed_t _x, _y; - sector_t *sec; _x = self->SpawnPoint[0]; _y = self->SpawnPoint[1]; @@ -422,12 +421,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialPosition) self->UnlinkFromWorld(); self->SetXY(_x, _y); self->LinkToWorld(true); - sec = self->Sector; - self->dropoffz = - self->floorz = sec->floorplane.ZatPoint(_x, _y); - self->ceilingz = sec->ceilingplane.ZatPoint(_x, _y); - self->SetZ(self->floorz); - P_FindFloorCeiling(self, FFCF_ONLYSPAWNPOS | FFCF_NOPORTALS); // no pprtal checks here so that things get spawned in this sector. + self->SetZ(self->Sector->floorplane.ZatPoint(_x, _y)); + P_FindFloorCeiling(self, FFCF_ONLYSPAWNPOS | FFCF_NOPORTALS); // no portal checks here so that things get spawned in this sector. if (self->flags & MF_SPAWNCEILING) { @@ -450,10 +445,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialPosition) { self->SetZ(self->SpawnPoint[2] + self->floorz); } - // Redo floor/ceiling check, in case of 3D floors - // we need to get the actual floor and ceiling heights including portals here - self->floorz = sec->LowestFloorAt(self, &self->floorsector); - self->ceilingz = sec->HighestCeilingAt(self, &self->ceilingsector); + // Redo floor/ceiling check, in case of 3D floors and portals P_FindFloorCeiling(self, FFCF_SAMESECTOR | FFCF_ONLY3DFLOORS | FFCF_3DRESTRICT); if (self->Z() < self->floorz) { // Do not reappear under the floor, even if that's where we were for the diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 9ffb17c27..47ac85d1f 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -558,7 +558,7 @@ bool P_Move (AActor *actor) else { // The monster just hit the floor, so trigger any actions. if (actor->floorsector->SecActTarget != NULL && - actor->floorz == actor->floorsector->floorplane.ZatPoint(actor->PosRelative(actor->floorsector)) + actor->floorz == actor->floorsector->floorplane.ZatPoint(actor->PosRelative(actor->floorsector))) { actor->floorsector->SecActTarget->TriggerAction(actor, SECSPAC_HitFloor); } diff --git a/src/p_map.cpp b/src/p_map.cpp index 1a17aa5b8..2b9faa03a 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -238,21 +238,24 @@ static bool PIT_FindFloorCeiling(line_t *ld, const FBoundingBox &box, FCheckPosi void P_GetFloorCeilingZ(FCheckPosition &tmf, int flags) { - sector_t *sec; - if (!(flags & FFCF_ONLYSPAWNPOS)) - { - sec = !(flags & FFCF_SAMESECTOR) ? P_PointInSector(tmf.x, tmf.y) : tmf.thing->Sector; + sector_t *sec = !(flags & FFCF_SAMESECTOR) ? P_PointInSector(tmf.x, tmf.y) : tmf.thing->Sector; - tmf.floorz = tmf.dropoffz = sec->LowestFloorAt(tmf.x, tmf.y, &tmf.floorsector); - tmf.ceilingz = sec->HighestCeilingAt(tmf.x, tmf.y, &tmf.ceilingsector); - tmf.floorpic = sec->GetTexture(sector_t::floor); - tmf.floorterrain = sec->GetTerrain(sector_t::floor); - tmf.ceilingpic = sec->GetTexture(sector_t::ceiling); + if (flags & FFCF_NOPORTALS) + { + tmf.thing->dropoffz = tmf.thing->floorz = sec->floorplane.ZatPoint(tmf.x, tmf.y); + tmf.thing->ceilingz = sec->ceilingplane.ZatPoint(tmf.x, tmf.y); + tmf.ceilingsector = tmf.floorsector = sec; } else { - sec = tmf.thing->Sector; + tmf.floorz = tmf.dropoffz = sec->LowestFloorAt(tmf.x, tmf.y, &tmf.floorsector); + tmf.ceilingz = sec->HighestCeilingAt(tmf.x, tmf.y, &tmf.ceilingsector); } + tmf.floorpic = tmf.floorsector->GetTexture(sector_t::floor); + tmf.floorterrain = tmf.floorsector->GetTerrain(sector_t::floor); + tmf.ceilingpic = tmf.ceilingsector->GetTexture(sector_t::ceiling); + + tmf.sector = sec; for (unsigned int i = 0; ie->XFloor.ffloors.Size(); i++) { @@ -299,21 +302,8 @@ void P_FindFloorCeiling(AActor *actor, int flags) { flags |= FFCF_3DRESTRICT; } - if (!(flags & FFCF_ONLYSPAWNPOS)) - { - P_GetFloorCeilingZ(tmf, flags); - } - else - { - tmf.ceilingsector = tmf.floorsector = actor->Sector; + P_GetFloorCeilingZ(tmf, flags); - tmf.floorz = tmf.dropoffz = actor->floorz; - tmf.ceilingz = actor->ceilingz; - tmf.floorpic = actor->floorpic; - tmf.floorterrain = actor->floorterrain; - tmf.ceilingpic = actor->ceilingpic; - P_GetFloorCeilingZ(tmf, flags); - } actor->floorz = tmf.floorz; actor->dropoffz = tmf.dropoffz; actor->ceilingz = tmf.ceilingz; diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 53d7d14e9..12fdaf427 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -513,8 +513,6 @@ void AActor::SetOrigin (fixed_t ix, fixed_t iy, fixed_t iz, bool moving) SetXYZ(ix, iy, iz); if (moving) SetMovement(ix - X(), iy - Y(), iz - Z()); LinkToWorld (); - floorz = Sector->LowestFloorAt(ix, iy, &floorsector); - ceilingz = Sector->HighestCeilingAt(ix, iy, &ceilingsector); P_FindFloorCeiling(this, FFCF_ONLYSPAWNPOS); } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 60724bbe5..da5208b6a 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3558,7 +3558,7 @@ void AActor::Tick () for (node = touching_sectorlist; node; node = node->m_tnext) { - const sector_t *sec = node->m_sector; + sector_t *sec = node->m_sector; fixed_t scrollx, scrolly; if (level.Scrolls != NULL) @@ -4172,8 +4172,6 @@ AActor *AActor::StaticSpawn (PClassActor *type, fixed_t ix, fixed_t iy, fixed_t // z-coordinate. if (!SpawningMapThing) { - actor->ceilingz = actor->Sector->HighestCeilingAt(actor, &actor->ceilingsector); - actor->dropoffz = actor->floorz = actor->Sector->LowestFloorAt(actor, &actor->floorsector); P_FindFloorCeiling(actor, FFCF_ONLYSPAWNPOS); } else diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 7e57cd0f8..6007963c6 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -2299,7 +2299,7 @@ void DPusher::Tick () continue; sector_t *hsec = sec->GetHeightSec(); - fixedvec2 pos = thing->PosRelative(sec); + fixedvec3 pos = thing->PosRelative(sec); if (m_Type == p_wind) { if (hsec == NULL) diff --git a/src/p_user.cpp b/src/p_user.cpp index 529420347..fbcf41238 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -769,10 +769,9 @@ void APlayerPawn::PostBeginPlay() // Voodoo dolls: restore original floorz/ceilingz logic if (player == NULL || player->mo != this) { - dropoffz = floorz = Sector->floorplane.ZatPoint(this); - ceilingz = Sector->ceilingplane.ZatPoint(this); - P_FindFloorCeiling(this, FFCF_ONLYSPAWNPOS); + P_FindFloorCeiling(this, FFCF_ONLYSPAWNPOS|FFCF_NOPORTALS); SetZ(floorz); + P_FindFloorCeiling(this, FFCF_ONLYSPAWNPOS); } else { From 3841a5f6265d82a724639fa26be244cdc910abdf Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 19 Feb 2016 10:39:40 +0100 Subject: [PATCH 09/28] - implemented FMultiBlockLinesIterator for checking a position across portals. This is not fully tested yet. --- src/actor.h | 19 ++----- src/p_checkposition.h | 58 ---------------------- src/p_maputl.cpp | 83 ++++++++++++++++++++++++++++++- src/p_maputl.h | 112 ++++++++++++++++++++++++++++++++++++++++++ src/portal.cpp | 32 ++++++------ src/portal.h | 23 ++++++++- 6 files changed, 236 insertions(+), 91 deletions(-) diff --git a/src/actor.h b/src/actor.h index 42865543c..4c636638e 100644 --- a/src/actor.h +++ b/src/actor.h @@ -1185,21 +1185,10 @@ public: fixedvec3 ret = { X(), Y(), Z() }; return ret; } - fixedvec3 PosRelative(AActor *other) const - { - fixedvec3 ret = { X(), Y(), Z() }; - return ret; - } - fixedvec3 PosRelative(sector_t *sec) const - { - fixedvec3 ret = { X(), Y(), Z() }; - return ret; - } - fixedvec3 PosRelative(line_t *line) const - { - fixedvec3 ret = { X(), Y(), Z() }; - return ret; - } + fixedvec3 PosRelative(AActor *other) const; + fixedvec3 PosRelative(sector_t *sec) const; + fixedvec3 PosRelative(line_t *line) const; + fixed_t SoundX() const { return X(); diff --git a/src/p_checkposition.h b/src/p_checkposition.h index 6eee5374a..4ab67634e 100644 --- a/src/p_checkposition.h +++ b/src/p_checkposition.h @@ -2,63 +2,6 @@ #define P_CHECKPOS_H -//============================================================================ -// -// This is a dynamic array which holds its first MAX_STATIC entries in normal -// variables to avoid constant allocations which this would otherwise -// require. -// -// When collecting touched portal groups the normal cases are either -// no portals == one group or -// two portals = two groups -// -// Anything with more can happen but far less infrequently, so this -// organization helps avoiding the overhead from heap allocations -// in the vast majority of situations. -// -//============================================================================ - -struct FPortalGroupArray -{ - enum - { - MAX_STATIC = 2 - }; - - FPortalGroupArray() - { - varused = 0; - } - - void Clear() - { - data.Clear(); - varused = 0; - } - - void Add(DWORD num) - { - if (varused < MAX_STATIC) entry[varused++] = num; - else data.Push(num); - } - - unsigned Size() - { - return varused + data.Size(); - } - - DWORD operator[](unsigned index) - { - return index < MAX_STATIC ? entry[index] : data[index - MAX_STATIC]; - } - -private: - DWORD entry[MAX_STATIC]; - unsigned varused; - TArray data; -}; - - //============================================================================ // // Used by P_CheckPosition and P_TryMove in place of the original @@ -95,7 +38,6 @@ struct FCheckPosition bool DoRipping; TMap LastRipped; - FPortalGroupArray Groups; int PushTime; FCheckPosition(bool rip=false) diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 12fdaf427..80190e624 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -39,6 +39,7 @@ #include "p_3dmidtex.h" #include "p_blockmap.h" #include "r_utility.h" +#include "portal.h" // State. #include "r_state.h" @@ -572,7 +573,7 @@ FBlockLinesIterator::FBlockLinesIterator(int _minx, int _miny, int _maxx, int _m Reset(); } -FBlockLinesIterator::FBlockLinesIterator(const FBoundingBox &box) +void FBlockLinesIterator::init(const FBoundingBox &box) { validcount++; maxy = GetSafeBlockY(box.Top() - bmaporgy); @@ -582,6 +583,10 @@ FBlockLinesIterator::FBlockLinesIterator(const FBoundingBox &box) Reset(); } +FBlockLinesIterator::FBlockLinesIterator(const FBoundingBox &box) +{ + init(box); +} //=========================================================================== // @@ -681,6 +686,82 @@ line_t *FBlockLinesIterator::Next() } } +//=========================================================================== +// +// FMultiBlockLinesIterator :: FMultiBlockLinesIterator +// +// An iterator that can check multiple portal groups. +// +//=========================================================================== + +FMultiBlockLinesIterator::FMultiBlockLinesIterator(AActor *origin, fixed_t checkx, fixed_t checky, fixed_t checkradius) +{ + checkpoint = origin->Pos(); + if (checkx != FIXED_MAX) checkpoint.x = checkx; + if (checky != FIXED_MAX) checkpoint.y = checky; + P_CollectConnectedGroups(origin->Sector->PortalGroup, checkpoint, origin->Top(), checkradius, checklist); + checkpoint.z = checkradius; + basegroup = origin->Sector->PortalGroup; + Reset(); +} + +bool FMultiBlockLinesIterator::Next(FMultiBlockLinesIterator::CheckResult *item) +{ + line_t *line = blockIterator.Next(); + if (line != NULL) + { + item->line = line; + item->position = offset; + item->portalposition = portalposition; + return true; + } + else if (checklist[index] & FPortalGroupArray::UPPER) + { + if (continueup) + { + sector_t *sector = P_PointInSector(offset.x, offset.y); + if (!sector->PortalBlocksMovement(sector_t::ceiling)) + { + startIteratorForGroup(sector->SkyBoxes[sector_t::ceiling]->Sector->PortalGroup); + return Next(item); + } + } + } + else if (checklist[index] & FPortalGroupArray::LOWER) + { + if (continuedown) + { + sector_t *sector = P_PointInSector(offset.x, offset.y); + if (!sector->PortalBlocksMovement(sector_t::floor)) + { + startIteratorForGroup(sector->SkyBoxes[sector_t::floor]->Sector->PortalGroup); + return Next(item); + } + } + } + index++; + if (index >= checklist.Size()) return false; + startIteratorForGroup(checklist[index]); + return Next(item); +} + +void FMultiBlockLinesIterator::startIteratorForGroup(int group) +{ + offset = Displacements(basegroup, group); + offset.x += checkpoint.x; + offset.y += checkpoint.y; + FBoundingBox box(offset.x, offset.y, checkpoint.z); + blockIterator.init(box); +} + +void FMultiBlockLinesIterator::Reset() +{ + continueup = continueup = true; + index = -1; + portalposition = PP_ORIGIN; + startIteratorForGroup(basegroup); +} + //=========================================================================== // // FBlockThingsIterator :: FBlockThingsIterator diff --git a/src/p_maputl.h b/src/p_maputl.h index dbc4eaf9a..0686b507b 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -108,8 +108,72 @@ void P_LineOpening (FLineOpening &open, AActor *thing, const line_t *linedef, fi class FBoundingBox; struct polyblock_t; +//============================================================================ +// +// This is a dynamic array which holds its first MAX_STATIC entries in normal +// variables to avoid constant allocations which this would otherwise +// require. +// +// When collecting touched portal groups the normal cases are either +// no portals == one group or +// two portals = two groups +// +// Anything with more can happen but far less infrequently, so this +// organization helps avoiding the overhead from heap allocations +// in the vast majority of situations. +// +//============================================================================ + +struct FPortalGroupArray +{ + enum + { + LOWER = 0x4000, + UPPER = 0x8000, + FLAT = 0xc000, + }; + + enum + { + MAX_STATIC = 4 + }; + + FPortalGroupArray() + { + varused = 0; + } + + void Clear() + { + data.Clear(); + varused = 0; + } + + void Add(DWORD num) + { + if (varused < MAX_STATIC) entry[varused++] = (WORD)num; + else data.Push((WORD)num); + } + + unsigned Size() + { + return varused + data.Size(); + } + + DWORD operator[](unsigned index) + { + return index < MAX_STATIC ? entry[index] : data[index - MAX_STATIC]; + } + +private: + WORD entry[MAX_STATIC]; + unsigned varused; + TArray data; +}; + class FBlockLinesIterator { + friend class FMultiBlockLinesIterator; int minx, maxx; int miny, maxy; @@ -120,6 +184,8 @@ class FBlockLinesIterator void StartBlock(int x, int y); + FBlockLinesIterator() {} + void init(const FBoundingBox &box); public: FBlockLinesIterator(int minx, int miny, int maxx, int maxy, bool keepvalidcount = false); FBlockLinesIterator(const FBoundingBox &box); @@ -127,6 +193,52 @@ public: void Reset() { StartBlock(minx, miny); } }; +class FMultiBlockLinesIterator +{ + fixedvec3 checkpoint; + fixedvec2 offset; + short basegroup; + short portalposition; + WORD index; + bool continueup; + bool continuedown; + FBlockLinesIterator blockIterator; + FPortalGroupArray checklist; + + void startIteratorForGroup(int group); + +public: + + enum + { + PP_ORIGIN, + PP_ABOVE, + PP_BELOW, + PP_THROUGHLINE + }; + + struct CheckResult + { + line_t *line; + fixedvec2 position; + int portalposition; + }; + + FMultiBlockLinesIterator(AActor *origin, fixed_t checkx = FIXED_MAX, fixed_t checky = FIXED_MAX, fixed_t checkradius = -1); + bool Next(CheckResult *item); + void Reset(); + // for stopping group traversal through portals. Only the calling code can decide whether this is needed so this needs to be set from the outside. + void StopUp() + { + continueup = false; + } + void StopDown() + { + continuedown = false; + } +}; + + class FBlockThingsIterator { int minx, maxx; diff --git a/src/portal.cpp b/src/portal.cpp index b787ae9f3..a247aafcc 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -1053,7 +1053,7 @@ void P_CreateLinkedPortals() // //============================================================================ -bool P_CollectConnectedGroups(AActor *actor, fixed_t newx, fixed_t newy, FPortalGroupArray &out) +bool P_CollectConnectedGroups(int startgroup, const fixedvec3 &position, fixed_t upperz, fixed_t checkradius, FPortalGroupArray &out) { // Keep this temporary work stuff static. This function can never be called recursively // and this would have to be reallocated for each call otherwise. @@ -1071,9 +1071,9 @@ bool P_CollectConnectedGroups(AActor *actor, fixed_t newx, fixed_t newy, FPortal processMask.clear(); foundPortals.Clear(); - int thisgroup = actor->Sector->PortalGroup; + int thisgroup = startgroup; processMask.setBit(thisgroup); - out.Add(thisgroup); + //out.Add(thisgroup); for (unsigned i = 0; i < linkedPortals.Size(); i++) { @@ -1082,7 +1082,7 @@ bool P_CollectConnectedGroups(AActor *actor, fixed_t newx, fixed_t newy, FPortal FDisplacement &disp = Displacements(thisgroup, othergroup); if (!disp.isSet) continue; // no connection. - FBoundingBox box(newx + disp.pos.x, newy + disp.pos.y, actor->radius); + FBoundingBox box(position.x + disp.pos.x, position.y + disp.pos.y, checkradius); if (box.Right() <= ld->bbox[BOXLEFT] || box.Left() >= ld->bbox[BOXRIGHT] @@ -1110,27 +1110,27 @@ bool P_CollectConnectedGroups(AActor *actor, fixed_t newx, fixed_t newy, FPortal } } } - sector_t *sec = P_PointInSector(newx, newy); + sector_t *sec = P_PointInSector(position.x, position.y); sector_t *wsec = sec; - while (!wsec->PortalBlocksMovement(sector_t::ceiling) && actor->Top() > wsec->SkyBoxes[sector_t::ceiling]->threshold) + while (!wsec->PortalBlocksMovement(sector_t::ceiling) && upperz > wsec->SkyBoxes[sector_t::ceiling]->threshold) { sector_t *othersec = wsec->SkyBoxes[sector_t::ceiling]->Sector; - FDisplacement &disp = Displacements(actor->Sector->PortalGroup, othersec->PortalGroup); - fixed_t dx = newx + disp.pos.x; - fixed_t dy = newx + disp.pos.y; + FDisplacement &disp = Displacements(startgroup, othersec->PortalGroup); + fixed_t dx = position.x + disp.pos.x; + fixed_t dy = position.y + disp.pos.y; processMask.setBit(othersec->PortalGroup); - out.Add(othersec->PortalGroup); + out.Add(othersec->PortalGroup|FPortalGroupArray::UPPER); wsec = P_PointInSector(dx, dy); // get upper sector at the exact spot we want to check and repeat retval = true; } wsec = sec; - while (!wsec->PortalBlocksMovement(sector_t::floor) && actor->Z() < wsec->SkyBoxes[sector_t::floor]->threshold) + while (!wsec->PortalBlocksMovement(sector_t::floor) && position.z < wsec->SkyBoxes[sector_t::floor]->threshold) { - sector_t *othersec = wsec->SkyBoxes[sector_t::ceiling]->Sector; - FDisplacement &disp = Displacements(actor->Sector->PortalGroup, othersec->PortalGroup); - fixed_t dx = newx + disp.pos.x; - fixed_t dy = newx + disp.pos.y; - processMask.setBit(othersec->PortalGroup); + sector_t *othersec = wsec->SkyBoxes[sector_t::floor]->Sector; + FDisplacement &disp = Displacements(startgroup, othersec->PortalGroup); + fixed_t dx = position.x + disp.pos.x; + fixed_t dy = position.y + disp.pos.y; + processMask.setBit(othersec->PortalGroup|FPortalGroupArray::LOWER); out.Add(othersec->PortalGroup); wsec = P_PointInSector(dx, dy); // get lower sector at the exact spot we want to check and repeat retval = true; diff --git a/src/portal.h b/src/portal.h index 1e00acf81..fcf6c545b 100644 --- a/src/portal.h +++ b/src/portal.h @@ -125,7 +125,7 @@ void P_SpawnLinePortal(line_t* line); void P_FinalizePortals(); bool P_ChangePortal(line_t *ln, int thisid, int destid); void P_CreateLinkedPortals(); -bool P_CollectConnectedGroups(AActor *actor, fixed_t newx, fixed_t newy, FPortalGroupArray &out); +bool P_CollectConnectedGroups(int startgroup, const fixedvec3 &position, fixed_t upperz, fixed_t checkradius, FPortalGroupArray &out); void P_CollectLinkedPortals(); inline int P_NumPortalGroups() { @@ -245,4 +245,25 @@ inline FDisplacement §or_t::CeilingDisplacement() return Displacements(PortalGroup, SkyBoxes[sector_t::ceiling]->Sector->PortalGroup); } +inline fixedvec3 AActor::PosRelative(AActor *other) const +{ + FDisplacement &disp = Displacements(Sector->PortalGroup, other->Sector->PortalGroup); + fixedvec3 ret = { X() + disp.pos.x, Y() + disp.pos.y, Z() }; + return ret; +} + +inline fixedvec3 AActor::PosRelative(sector_t *sec) const +{ + FDisplacement &disp = Displacements(Sector->PortalGroup, sec->PortalGroup); + fixedvec3 ret = { X() + disp.pos.x, Y() + disp.pos.y, Z() }; + return ret; +} + +inline fixedvec3 AActor::PosRelative(line_t *line) const +{ + FDisplacement &disp = Displacements(Sector->PortalGroup, line->frontsector->PortalGroup); + fixedvec3 ret = { X() + disp.pos.x, Y() + disp.pos.y, Z() }; + return ret; +} + #endif \ No newline at end of file From 02d75723434f9b7d3debc86f9b8d9e62251ce72c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 19 Feb 2016 14:08:41 +0100 Subject: [PATCH 10/28] =?UTF-8?q?-=20some=20header=20dependency=20cleanup?= =?UTF-8?q?=20so=20that=20it=20is=20no=20longer=20needed=20to=20include=20?= =?UTF-8?q?portal.h=20to=20get=20the=20inline=20functions.=20Portal.h=20ha?= =?UTF-8?q?s=20been=20reduced=20of=20most=20dependencies=20now=20so=20that?= =?UTF-8?q?=20including=20it=20is=20cheap=20and=20can=20be=20done=20in=20o?= =?UTF-8?q?ther=20headers.=20-=20some=20consolidation=20in=20p=5Fmap.cpp.?= =?UTF-8?q?=20PIT=5FCheckLine=20and=20PIT=5FFindFloorCeiling=20had=20quite?= =?UTF-8?q?=20a=20bit=20of=20redundancy=20which=20has=20been=20merged.=20-?= =?UTF-8?q?=20=C4=8Dontinued=20work=20on=20FMultiBlockLinesIterator.=20It'?= =?UTF-8?q?s=20still=20not=20completely=20finished.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/actor.h | 10 +- src/basictypes.h | 6 ++ src/m_bbox.cpp | 2 +- src/m_bbox.h | 7 +- src/p_acs.cpp | 1 - src/p_buildmap.cpp | 1 - src/p_lnspec.cpp | 1 - src/p_local.h | 2 + src/p_map.cpp | 252 ++++++++++++++++++++++----------------------- src/p_maputl.cpp | 30 ++++-- src/p_maputl.h | 28 ++--- src/p_saveg.cpp | 1 - src/p_sectors.cpp | 5 +- src/p_setup.cpp | 1 - src/p_spec.cpp | 21 ++-- src/p_udmf.cpp | 1 - src/portal.cpp | 7 +- src/portal.h | 90 ---------------- src/r_bsp.cpp | 1 - src/r_bsp.h | 2 +- src/r_defs.h | 87 +++++++++++++--- src/r_main.cpp | 1 - src/r_plane.cpp | 1 - src/r_segs.cpp | 1 - src/r_utility.cpp | 3 +- 25 files changed, 269 insertions(+), 293 deletions(-) diff --git a/src/actor.h b/src/actor.h index 4c636638e..35afef397 100644 --- a/src/actor.h +++ b/src/actor.h @@ -40,6 +40,7 @@ #include "memarena.h" #include "g_level.h" #include "tflags.h" +#include "portal.h" struct subsector_t; class PClassAmmo; @@ -1182,9 +1183,9 @@ public: } fixedvec3 Pos() const { - fixedvec3 ret = { X(), Y(), Z() }; - return ret; + return __pos; } + fixedvec3 PosRelative(AActor *other) const; fixedvec3 PosRelative(sector_t *sec) const; fixedvec3 PosRelative(line_t *line) const; @@ -1366,11 +1367,6 @@ inline fixedvec2 Vec2Angle(fixed_t length, angle_t angle) return ret; } -inline fixedvec3 PosRelative(const fixedvec3 &pos, line_t *line, sector_t *refsec = NULL) -{ - return pos; -} - void PrintMiscActorInfo(AActor * query); AActor *P_LinePickActor(AActor *t1, angle_t angle, fixed_t distance, int pitch, ActorFlags actorMask, DWORD wallMask); diff --git a/src/basictypes.h b/src/basictypes.h index 6caf40a36..ea56e9093 100644 --- a/src/basictypes.h +++ b/src/basictypes.h @@ -126,6 +126,12 @@ inline fixedvec3 operator +(const fixedvec3 &v1, const fixedvec3 &v2) return v; } +inline fixedvec3 operator +(const fixedvec3 &v1, const fixedvec2 &v2) +{ + fixedvec3 v = { v1.x + v2.x, v1.y + v2.y, v1.z }; + return v; +} + #define FIXED_MAX (signed)(0x7fffffff) #define FIXED_MIN (signed)(0x80000000) diff --git a/src/m_bbox.cpp b/src/m_bbox.cpp index f7827ef72..a8f55e4cf 100644 --- a/src/m_bbox.cpp +++ b/src/m_bbox.cpp @@ -34,7 +34,7 @@ // //========================================================================== -FBoundingBox::FBoundingBox(fixed_t x, fixed_t y, fixed_t radius) +void FBoundingBox::setBox(fixed_t x, fixed_t y, fixed_t radius) { m_Box[BOXTOP] = (fixed_t)MIN((SQWORD)y + radius, FIXED_MAX); m_Box[BOXLEFT] = (fixed_t)MAX((SQWORD)x - radius, FIXED_MIN); diff --git a/src/m_bbox.h b/src/m_bbox.h index 174cd6ecf..c43bb3c79 100644 --- a/src/m_bbox.h +++ b/src/m_bbox.h @@ -43,7 +43,12 @@ public: m_Box[BOXBOTTOM] = bottom; } - FBoundingBox(fixed_t x, fixed_t y, fixed_t radius); + FBoundingBox(fixed_t x, fixed_t y, fixed_t radius) + { + setBox(x, y, radius); + } + + void setBox(fixed_t x, fixed_t y, fixed_t radius); void ClearBox () { diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 9d2899d7e..c6b96252d 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -76,7 +76,6 @@ #include "actorptrselect.h" #include "farchive.h" #include "decallib.h" -#include "portal.h" #include "p_terrain.h" #include "version.h" #include "p_effect.h" diff --git a/src/p_buildmap.cpp b/src/p_buildmap.cpp index 116c9ff6d..8d7e75076 100644 --- a/src/p_buildmap.cpp +++ b/src/p_buildmap.cpp @@ -17,7 +17,6 @@ #include "g_level.h" #include "r_data/colormaps.h" #include "gi.h" -#include "portal.h" #include "p_spec.h" // MACROS ------------------------------------------------------------------ diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 1e45c0fe5..1af76d6d9 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -57,7 +57,6 @@ #include "d_net.h" #include "d_event.h" #include "gstrings.h" -#include "portal.h" #include "po_man.h" #include "d_player.h" #include "r_utility.h" diff --git a/src/p_local.h b/src/p_local.h index c4c5d3914..dac4dbc26 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -288,6 +288,8 @@ enum FFCF_ONLY3DFLOORS = 4, // includes 3D midtexes FFCF_3DRESTRICT = 8, // ignore 3D midtexes and floors whose floorz are above thing's z FFCF_NOPORTALS = 16, // ignore portals (considers them impassable.) + FFCF_NOFLOOR = 32, + FFCF_NOCEILING = 64, }; void P_FindFloorCeiling (AActor *actor, int flags=0); diff --git a/src/p_map.cpp b/src/p_map.cpp index 2b9faa03a..bce8c7739 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -80,6 +80,7 @@ TArray spechit; // Temporary holder for thing_sectorlist threads msecnode_t* sector_list = NULL; // phares 3/16/98 + //========================================================================== // // GetCoefficientClosestPointInLine24 @@ -91,8 +92,9 @@ msecnode_t* sector_list = NULL; // phares 3/16/98 // //========================================================================== -static fixed_t GetCoefficientClosestPointInLine24(line_t *ld, FCheckPosition &tm) +static inline fixed_t GetCoefficientClosestPointInLine24(line_t *ld, fixedvec2 pos) { +#ifndef USE_FLOAT // [EP] Use 64 bit integers in order to keep the exact result of the // multiplication, because in the case the vertexes have both the // distance coordinates equal to the map limit (32767 units, which is @@ -102,8 +104,8 @@ static fixed_t GetCoefficientClosestPointInLine24(line_t *ld, FCheckPosition &tm // fixed_t notation, which is 1.52587890625e-05 in float notation), the // product and the sum can be 1 in the worst case, which is very tiny. - SQWORD r_num = ((SQWORD(tm.x - ld->v1->x)*ld->dx) + - (SQWORD(tm.y - ld->v1->y)*ld->dy)); + SQWORD r_num = ((SQWORD(pos.x - ld->v1->x)*ld->dx) + + (SQWORD(pos.y - ld->v1->y)*ld->dy)); // The denominator is always positive. Use this to avoid useless // calculations. @@ -131,16 +133,58 @@ static fixed_t GetCoefficientClosestPointInLine24(line_t *ld, FCheckPosition &tm // Thanks to the fact that in this code path the denominator is greater // than the numerator, it's possible to avoid this bad situation by // just checking the last 24 bits of the numerator. - if ((r_num >> (63-24)) != 0) { + if ((r_num >> (63 - 24)) != 0) { // [EP] In fact, if the numerator is greater than // (1 << (63-24)), the denominator must be greater than // (1 << (63-24)), hence the denominator won't be zero after // the right shift by 24 places. - return (fixed_t)(r_num/(r_den >> 24)); + return (fixed_t)(r_num / (r_den >> 24)); } // [EP] Having the last 24 bits all zero allows left shifting // the numerator by 24 bits without overflow. - return (fixed_t)((r_num << 24)/r_den); + return (fixed_t)((r_num << 24) / r_den); +#else + double dx = ld->dx; + double dy = ld->dy; + return xs_CRoundToInt(((double)(pos.x - ld->v1->x) * dx + (double)(pos.y - ld->v1->y) * dy) / (dx*dx + dy*dy) * 16777216.f); +#endif +} + + +//========================================================================== +// +// FindRefPoint +// +// Finds the point on the line closest to the given coordinate +// +//========================================================================== + +static inline fixedvec2 FindRefPoint(line_t *ld, fixedvec2 pos) +{ + if (!((((ld->frontsector->floorplane.a | ld->frontsector->floorplane.b) | + (ld->backsector->floorplane.a | ld->backsector->floorplane.b) | + (ld->frontsector->ceilingplane.a | ld->frontsector->ceilingplane.b) | + (ld->backsector->ceilingplane.a | ld->backsector->ceilingplane.b)) == 0) + && ld->backsector->e->XFloor.ffloors.Size() == 0 && ld->frontsector->e->XFloor.ffloors.Size() == 0)) + { + fixed_t r = GetCoefficientClosestPointInLine24(ld, pos); + if (r <= 0) + { + pos.x = ld->v1->x; + pos.y = ld->v1->y; + } + else if (r >= (1 << 24)) + { + pos.x = ld->v2->x; + pos.y = ld->v2->y; + } + else + { + pos.x = ld->v1->x + MulScale24(r, ld->dx); + pos.y = ld->v1->y + MulScale24(r, ld->dy); + } + } + return pos; } //========================================================================== @@ -151,8 +195,10 @@ static fixed_t GetCoefficientClosestPointInLine24(line_t *ld, FCheckPosition &tm // //========================================================================== -static bool PIT_FindFloorCeiling(line_t *ld, const FBoundingBox &box, FCheckPosition &tmf, int flags) +static bool PIT_FindFloorCeiling(FMultiBlockLinesIterator::CheckResult &cres, const FBoundingBox &box, FCheckPosition &tmf, int flags) { + line_t *ld = cres.line; + if (box.Right() <= ld->bbox[BOXLEFT] || box.Left() >= ld->bbox[BOXRIGHT] || box.Top() <= ld->bbox[BOXBOTTOM] @@ -169,76 +215,52 @@ static bool PIT_FindFloorCeiling(line_t *ld, const FBoundingBox &box, FCheckPosi return true; } - fixed_t sx, sy; + fixedvec2 refpoint = FindRefPoint(ld, cres.position); FLineOpening open; - // set openrange, opentop, openbottom - if ((((ld->frontsector->floorplane.a | ld->frontsector->floorplane.b) | - (ld->backsector->floorplane.a | ld->backsector->floorplane.b) | - (ld->frontsector->ceilingplane.a | ld->frontsector->ceilingplane.b) | - (ld->backsector->ceilingplane.a | ld->backsector->ceilingplane.b)) == 0) - && ld->backsector->e->XFloor.ffloors.Size() == 0 && ld->frontsector->e->XFloor.ffloors.Size() == 0) - { - P_LineOpening(open, tmf.thing, ld, sx = tmf.x, sy = tmf.y, tmf.x, tmf.y, flags); - } - else - { // Find the point on the line closest to the actor's center, and use - // that to calculate openings - double dx = ld->dx; - double dy = ld->dy; - fixed_t r = xs_CRoundToInt(((double)(tmf.x - ld->v1->x) * dx + - (double)(tmf.y - ld->v1->y) * dy) / - (dx*dx + dy*dy) * 16777216.f); - if (r <= 0) - { - P_LineOpening(open, tmf.thing, ld, sx = ld->v1->x, sy = ld->v1->y, tmf.x, tmf.y, flags); - } - else if (r >= (1 << 24)) - { - P_LineOpening(open, tmf.thing, ld, sx = ld->v2->x, sy = ld->v2->y, tmf.thing->X(), tmf.thing->Y(), flags); - } - else - { - P_LineOpening(open, tmf.thing, ld, sx = ld->v1->x + MulScale24(r, ld->dx), - sy = ld->v1->y + MulScale24(r, ld->dy), tmf.x, tmf.y, flags); - } - } + P_LineOpening(open, tmf.thing, ld, refpoint.x, refpoint.y, cres.position.x, cres.position.y, flags); // adjust floor / ceiling heights - if (open.top < tmf.ceilingz) + if (!(flags & FFCF_NOCEILING)) { - tmf.ceilingz = open.top; + if (open.top < tmf.ceilingz) + { + tmf.ceilingz = open.top; + } } - if (open.bottom > tmf.floorz) + if (!(flags & FFCF_NOFLOOR)) { - tmf.floorz = open.bottom; - if (open.bottomsec != NULL) tmf.floorsector = open.bottomsec; - tmf.touchmidtex = open.touchmidtex; - tmf.abovemidtex = open.abovemidtex; - } - else if (open.bottom == tmf.floorz) - { - tmf.touchmidtex |= open.touchmidtex; - tmf.abovemidtex |= open.abovemidtex; - } - - if (open.lowfloor < tmf.dropoffz) - tmf.dropoffz = open.lowfloor; + if (open.bottom > tmf.floorz) + { + tmf.floorz = open.bottom; + if (open.bottomsec != NULL) tmf.floorsector = open.bottomsec; + tmf.touchmidtex = open.touchmidtex; + tmf.abovemidtex = open.abovemidtex; + } + else if (open.bottom == tmf.floorz) + { + tmf.touchmidtex |= open.touchmidtex; + tmf.abovemidtex |= open.abovemidtex; + } + if (open.lowfloor < tmf.dropoffz) + tmf.dropoffz = open.lowfloor; + } return true; } //========================================================================== // -// +// calculates the actual floor and ceiling position at a given +// coordinate. Traverses through portals unless being told not to. // //========================================================================== void P_GetFloorCeilingZ(FCheckPosition &tmf, int flags) { - sector_t *sec = !(flags & FFCF_SAMESECTOR) ? P_PointInSector(tmf.x, tmf.y) : tmf.thing->Sector; + sector_t *sec = (!(flags & FFCF_SAMESECTOR) || tmf.thing->Sector == NULL)? P_PointInSector(tmf.x, tmf.y) : tmf.thing->Sector; if (flags & FFCF_NOPORTALS) { @@ -268,17 +290,20 @@ void P_GetFloorCeilingZ(FCheckPosition &tmf, int flags) if (ff_top > tmf.floorz) { - if (ff_top <= tmf.z || (!(flags & FFCF_3DRESTRICT) && (tmf.thing != NULL && ff_bottom < tmf.z && ff_top < tmf.z + tmf.thing->MaxStepHeight))) + // either with feet above the 3D floor or feet with less than 'stepheight' map units inside + if (ff_top <= tmf.z || (!(flags & FFCF_3DRESTRICT) && (ff_bottom < tmf.z && ff_top < tmf.z + tmf.thing->MaxStepHeight))) { tmf.dropoffz = tmf.floorz = ff_top; tmf.floorpic = *rover->top.texture; tmf.floorterrain = rover->model->GetTerrain(rover->top.isceiling); + tmf.floorsector = sec; } } if (ff_bottom <= tmf.ceilingz && ff_bottom > tmf.z + tmf.thing->height) { tmf.ceilingz = ff_bottom; tmf.ceilingpic = *rover->bottom.texture; + tmf.ceilingsector = sec; } } } @@ -303,6 +328,7 @@ void P_FindFloorCeiling(AActor *actor, int flags) flags |= FFCF_3DRESTRICT; } P_GetFloorCeilingZ(tmf, flags); + assert(tmf.thing->Sector != NULL); actor->floorz = tmf.floorz; actor->dropoffz = tmf.dropoffz; @@ -313,44 +339,44 @@ void P_FindFloorCeiling(AActor *actor, int flags) actor->ceilingpic = tmf.ceilingpic; actor->ceilingsector = tmf.ceilingsector; - FBoundingBox box(tmf.x, tmf.y, actor->radius); - tmf.touchmidtex = false; tmf.abovemidtex = false; validcount++; - FBlockLinesIterator it(box); - line_t *ld; + FPortalGroupArray grouplist; + FMultiBlockLinesIterator mit(grouplist, actor, tmf.x, tmf.y, actor->radius); + FMultiBlockLinesIterator::CheckResult cres; - while ((ld = it.Next())) + // if we already have a valid floor/ceiling sector within the current sector, + // we do not need to iterate through plane portals to find a floor or ceiling. + if (actor->floorsector == actor->Sector) mit.StopDown(); + if (actor->ceilingsector == actor->Sector) mit.StopUp(); + + while ((mit.Next(&cres))) { - PIT_FindFloorCeiling(ld, box, tmf, flags); + PIT_FindFloorCeiling(cres, mit.Box(), tmf, flags|cres.portalflags); } if (tmf.touchmidtex) tmf.dropoffz = tmf.floorz; - if (!(flags & FFCF_ONLYSPAWNPOS) || (tmf.abovemidtex && (tmf.floorz <= actor->Z()))) + bool usetmf = !(flags & FFCF_ONLYSPAWNPOS) || (tmf.abovemidtex && (tmf.floorz <= actor->Z())); + + // when actual floor or ceiling are beyond a portal plane we also need to use the result of the blockmap iterator, regardless of the flags being specified. + if (usetmf || tmf.floorsector->PortalGroup != actor->Sector->PortalGroup) { actor->floorz = tmf.floorz; actor->dropoffz = tmf.dropoffz; - actor->ceilingz = tmf.ceilingz; actor->floorpic = tmf.floorpic; actor->floorterrain = tmf.floorterrain; actor->floorsector = tmf.floorsector; + } + + if (usetmf || tmf.ceilingsector->PortalGroup != actor->Sector->PortalGroup) + { + actor->ceilingz = tmf.ceilingz; actor->ceilingpic = tmf.ceilingpic; actor->ceilingsector = tmf.ceilingsector; } - else - { - actor->floorsector = actor->ceilingsector = actor->Sector; - // [BB] Don't forget to update floorpic and ceilingpic. - if (actor->Sector != NULL) - { - actor->floorpic = actor->Sector->GetTexture(sector_t::floor); - actor->floorterrain = actor->Sector->GetTerrain(sector_t::floor); - actor->ceilingpic = actor->Sector->GetTexture(sector_t::ceiling); - } - } } //========================================================================== @@ -392,16 +418,17 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra bool StompAlwaysFrags = ((thing->flags2 & MF2_TELESTOMP) || (level.flags & LEVEL_MONSTERSTELEFRAG) || telefrag) && !(thing->flags7 & MF7_NOTELESTOMP); - FBoundingBox box(x, y, thing->radius); - FBlockLinesIterator it(box); - line_t *ld; - // P_LineOpening requires the thing's z to be the destination z in order to work. fixed_t savedz = thing->Z(); thing->SetZ(z); - while ((ld = it.Next())) + + FPortalGroupArray grouplist; + FMultiBlockLinesIterator mit(grouplist, thing, tmf.x, tmf.y, thing->radius); + FMultiBlockLinesIterator::CheckResult cres; + + while (mit.Next(&cres)) { - PIT_FindFloorCeiling(ld, box, tmf, 0); + PIT_FindFloorCeiling(cres, mit.Box(), tmf, 0); } thing->SetZ(savedz); @@ -714,6 +741,7 @@ int P_GetMoveFactor(const AActor *mo, int *frictionp) return movefactor; } + // // MOVEMENT ITERATOR FUNCTIONS // @@ -825,56 +853,18 @@ bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm) } } - fixed_t sx = 0, sy = 0; + fixedvec2 rpos = { tm.x, tm.y }; + fixedvec2 ref = FindRefPoint(ld, rpos); FLineOpening open; - // set openrange, opentop, openbottom - if ((((ld->frontsector->floorplane.a | ld->frontsector->floorplane.b) | - (ld->backsector->floorplane.a | ld->backsector->floorplane.b) | - (ld->frontsector->ceilingplane.a | ld->frontsector->ceilingplane.b) | - (ld->backsector->ceilingplane.a | ld->backsector->ceilingplane.b)) == 0) - && ld->backsector->e->XFloor.ffloors.Size() == 0 && ld->frontsector->e->XFloor.ffloors.Size() == 0) + // the floorplane on both sides is identical with the current one + // so don't mess around with the z-position. + if (ld->frontsector->floorplane == ld->backsector->floorplane && + ld->frontsector->floorplane == tm.thing->Sector->floorplane && + !ld->frontsector->e->XFloor.ffloors.Size() && !ld->backsector->e->XFloor.ffloors.Size() && + !open.abovemidtex) { - P_LineOpening(open, tm.thing, ld, sx = tm.x, sy = tm.y, tm.x, tm.y); - } - else - { // Find the point on the line closest to the actor's center, and use - // that to calculate openings - fixed_t r = GetCoefficientClosestPointInLine24(ld, tm); - - /* Printf ("%d:%d: %d (%d %d %d %d) (%d %d %d %d)\n", level.time, ld-lines, r, - ld->frontsector->floorplane.a, - ld->frontsector->floorplane.b, - ld->frontsector->floorplane.c, - ld->frontsector->floorplane.ic, - ld->backsector->floorplane.a, - ld->backsector->floorplane.b, - ld->backsector->floorplane.c, - ld->backsector->floorplane.ic);*/ - if (r <= 0) - { - P_LineOpening(open, tm.thing, ld, sx = ld->v1->x, sy = ld->v1->y, tm.x, tm.y); - } - else if (r >= (1 << 24)) - { - P_LineOpening(open, tm.thing, ld, sx = ld->v2->x, sy = ld->v2->y, pos.x, pos.y); - } - else - { - P_LineOpening(open, tm.thing, ld, sx = ld->v1->x + MulScale24(r, ld->dx), - sy = ld->v1->y + MulScale24(r, ld->dy), tm.x, tm.y); - } - - // the floorplane on both sides is identical with the current one - // so don't mess around with the z-position - if (ld->frontsector->floorplane == ld->backsector->floorplane && - ld->frontsector->floorplane == tm.thing->Sector->floorplane && - !ld->frontsector->e->XFloor.ffloors.Size() && !ld->backsector->e->XFloor.ffloors.Size() && - !open.abovemidtex) - { - open.bottom = INT_MIN; - } - /* Printf (" %d %d %d\n", sx, sy, openbottom);*/ + open.bottom = INT_MIN; } if (rail && @@ -886,7 +876,7 @@ bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm) // from either side. How long until somebody reports this as a bug and I'm // forced to say, "It's not a bug. It's a feature?" Ugh. (!(level.flags2 & LEVEL2_RAILINGHACK) || - open.bottom == tm.thing->Sector->floorplane.ZatPoint(sx, sy))) + open.bottom == tm.thing->Sector->floorplane.ZatPoint(ref.x, ref.y))) { open.bottom += 32 * FRACUNIT; } diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 80190e624..38be280d6 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -39,7 +39,6 @@ #include "p_3dmidtex.h" #include "p_blockmap.h" #include "r_utility.h" -#include "portal.h" // State. #include "r_state.h" @@ -694,7 +693,8 @@ line_t *FBlockLinesIterator::Next() // //=========================================================================== -FMultiBlockLinesIterator::FMultiBlockLinesIterator(AActor *origin, fixed_t checkx, fixed_t checky, fixed_t checkradius) +FMultiBlockLinesIterator::FMultiBlockLinesIterator(FPortalGroupArray &check, AActor *origin, fixed_t checkx, fixed_t checky, fixed_t checkradius) + : checklist(check) { checkpoint = origin->Pos(); if (checkx != FIXED_MAX) checkpoint.x = checkx; @@ -712,7 +712,7 @@ bool FMultiBlockLinesIterator::Next(FMultiBlockLinesIterator::CheckResult *item) { item->line = line; item->position = offset; - item->portalposition = portalposition; + item->portalflags = portalflags; return true; } else if (checklist[index] & FPortalGroupArray::UPPER) @@ -723,6 +723,7 @@ bool FMultiBlockLinesIterator::Next(FMultiBlockLinesIterator::CheckResult *item) if (!sector->PortalBlocksMovement(sector_t::ceiling)) { startIteratorForGroup(sector->SkyBoxes[sector_t::ceiling]->Sector->PortalGroup); + portalflags = FFCF_NOFLOOR; return Next(item); } } @@ -735,13 +736,28 @@ bool FMultiBlockLinesIterator::Next(FMultiBlockLinesIterator::CheckResult *item) if (!sector->PortalBlocksMovement(sector_t::floor)) { startIteratorForGroup(sector->SkyBoxes[sector_t::floor]->Sector->PortalGroup); + portalflags = FFCF_NOCEILING; return Next(item); } } } index++; if (index >= checklist.Size()) return false; - startIteratorForGroup(checklist[index]); + startIteratorForGroup(checklist[index] & ~FPortalGroupArray::FLAT); + switch (checklist[index] & FPortalGroupArray::FLAT) + { + case FPortalGroupArray::UPPER: + portalflags = FFCF_NOFLOOR; + break; + + case FPortalGroupArray::LOWER: + portalflags = FFCF_NOCEILING; + break; + + default: + portalflags = 0; + } + return Next(item); } @@ -750,15 +766,15 @@ void FMultiBlockLinesIterator::startIteratorForGroup(int group) offset = Displacements(basegroup, group); offset.x += checkpoint.x; offset.y += checkpoint.y; - FBoundingBox box(offset.x, offset.y, checkpoint.z); - blockIterator.init(box); + bbox.setBox(offset.x, offset.y, checkpoint.z); + blockIterator.init(bbox); } void FMultiBlockLinesIterator::Reset() { continueup = continueup = true; index = -1; - portalposition = PP_ORIGIN; + portalflags = 0; startIteratorForGroup(basegroup); } diff --git a/src/p_maputl.h b/src/p_maputl.h index 0686b507b..3ebc02f31 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -3,6 +3,7 @@ #include "r_defs.h" #include "doomstat.h" +#include "m_bbox.h" extern int validcount; @@ -141,12 +142,14 @@ struct FPortalGroupArray FPortalGroupArray() { varused = 0; + inited = false; } void Clear() { data.Clear(); varused = 0; + inited = false; } void Add(DWORD num) @@ -165,9 +168,11 @@ struct FPortalGroupArray return index < MAX_STATIC ? entry[index] : data[index - MAX_STATIC]; } + bool inited; + private: WORD entry[MAX_STATIC]; - unsigned varused; + BYTE varused; TArray data; }; @@ -195,36 +200,29 @@ public: class FMultiBlockLinesIterator { + FPortalGroupArray &checklist; fixedvec3 checkpoint; fixedvec2 offset; short basegroup; - short portalposition; + short portalflags; WORD index; bool continueup; bool continuedown; FBlockLinesIterator blockIterator; - FPortalGroupArray checklist; + FBoundingBox bbox; void startIteratorForGroup(int group); public: - enum - { - PP_ORIGIN, - PP_ABOVE, - PP_BELOW, - PP_THROUGHLINE - }; - struct CheckResult { line_t *line; fixedvec2 position; - int portalposition; + int portalflags; }; - FMultiBlockLinesIterator(AActor *origin, fixed_t checkx = FIXED_MAX, fixed_t checky = FIXED_MAX, fixed_t checkradius = -1); + FMultiBlockLinesIterator(FPortalGroupArray &check, AActor *origin, fixed_t checkx = FIXED_MAX, fixed_t checky = FIXED_MAX, fixed_t checkradius = -1); bool Next(CheckResult *item); void Reset(); // for stopping group traversal through portals. Only the calling code can decide whether this is needed so this needs to be set from the outside. @@ -236,6 +234,10 @@ public: { continuedown = false; } + const FBoundingBox &Box() const + { + return bbox; + } }; diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index a72c9d897..2f113810d 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -55,7 +55,6 @@ #include "p_lnspec.h" #include "p_acs.h" #include "p_terrain.h" -#include "portal.h" static void CopyPlayer (player_t *dst, player_t *src, const char *name); static void ReadOnePlayer (FArchive &arc, bool skipload); diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index ac42da11f..ab1cc40d7 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -30,7 +30,6 @@ #include "po_man.h" #include "farchive.h" #include "r_utility.h" -#include "portal.h" #include "a_sharedglobal.h" #include "r_data/colormaps.h" @@ -806,7 +805,7 @@ int sector_t::GetCeilingLight () const ASkyViewpoint *sector_t::GetSkyBox(int which) { - if (SkyBoxes[which] != NULL) return SkyBoxes[which]; + if (SkyBoxes[which] != NULL) return barrier_cast(SkyBoxes[which]); if (MoreFlags & (SECF_NOFLOORSKYBOX << which)) return NULL; return level.DefaultSkybox; } @@ -874,7 +873,7 @@ int sector_t::GetTerrain(int pos) const void sector_t::CheckPortalPlane(int plane) { - ASkyViewpoint *portal = SkyBoxes[plane]; + AActor *portal = SkyBoxes[plane]; if (!portal || portal->special1 != SKYBOX_LINKEDPORTAL) return; fixed_t planeh = planes[plane].TexZ; diff --git a/src/p_setup.cpp b/src/p_setup.cpp index c5780e912..55dbdfcac 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -69,7 +69,6 @@ #include "po_man.h" #include "r_renderer.h" #include "r_data/colormaps.h" -#include "portal.h" #include "p_blockmap.h" #include "r_utility.h" #include "p_spec.h" diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 6007963c6..e18f78b29 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -67,7 +67,6 @@ #include "c_dispatch.h" #include "r_sky.h" #include "d_player.h" -#include "portal.h" #include "p_maputl.h" #include "p_blockmap.h" #ifndef NO_EDATA @@ -919,10 +918,11 @@ static void SetupFloorPortal (AStackPoint *point) { NActorIterator it (NAME_LowerStackLookOnly, point->tid); sector_t *Sector = point->Sector; - Sector->SkyBoxes[sector_t::floor] = static_cast(it.Next()); - if (Sector->SkyBoxes[sector_t::floor] != NULL && Sector->SkyBoxes[sector_t::floor]->bAlways) + ASkyViewpoint *skyv = static_cast(it.Next()); + Sector->SkyBoxes[sector_t::floor] = skyv; + if (skyv != NULL && skyv->bAlways) { - Sector->SkyBoxes[sector_t::floor]->Mate = point; + skyv->Mate = point; if (Sector->GetAlpha(sector_t::floor) == OPAQUE) Sector->SetAlpha(sector_t::floor, Scale (point->args[0], OPAQUE, 255)); } @@ -932,12 +932,13 @@ static void SetupCeilingPortal (AStackPoint *point) { NActorIterator it (NAME_UpperStackLookOnly, point->tid); sector_t *Sector = point->Sector; - Sector->SkyBoxes[sector_t::ceiling] = static_cast(it.Next()); - if (Sector->SkyBoxes[sector_t::ceiling] != NULL && Sector->SkyBoxes[sector_t::ceiling]->bAlways) + ASkyViewpoint *skyv = static_cast(it.Next()); + Sector->SkyBoxes[sector_t::ceiling] = skyv; + if (skyv != NULL && skyv->bAlways) { - Sector->SkyBoxes[sector_t::ceiling]->Mate = point; + skyv->Mate = point; if (Sector->GetAlpha(sector_t::ceiling) == OPAQUE) - Sector->SetAlpha(sector_t::ceiling, Scale (point->args[0], OPAQUE, 255)); + Sector->SetAlpha(sector_t::ceiling, Scale(point->args[0], OPAQUE, 255)); } } @@ -968,7 +969,7 @@ static void SetPortal(sector_t *sector, int plane, ASkyViewpoint *portal, fixed_ // plane: 0=floor, 1=ceiling, 2=both if (plane > 0) { - if (sector->SkyBoxes[sector_t::ceiling] == NULL || !sector->SkyBoxes[sector_t::ceiling]->bAlways) + if (sector->SkyBoxes[sector_t::ceiling] == NULL || !barrier_cast(sector->SkyBoxes[sector_t::ceiling])->bAlways) { sector->SkyBoxes[sector_t::ceiling] = portal; if (sector->GetAlpha(sector_t::ceiling) == OPAQUE) @@ -979,7 +980,7 @@ static void SetPortal(sector_t *sector, int plane, ASkyViewpoint *portal, fixed_ } if (plane == 2 || plane == 0) { - if (sector->SkyBoxes[sector_t::floor] == NULL || !sector->SkyBoxes[sector_t::floor]->bAlways) + if (sector->SkyBoxes[sector_t::floor] == NULL || !barrier_cast(sector->SkyBoxes[sector_t::floor])->bAlways) { sector->SkyBoxes[sector_t::floor] = portal; } diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 2b01be372..e86093a8c 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -47,7 +47,6 @@ #include "r_data/colormaps.h" #include "w_wad.h" #include "p_tags.h" -#include "portal.h" #include "p_terrain.h" //=========================================================================== diff --git a/src/portal.cpp b/src/portal.cpp index a247aafcc..efd46d851 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -37,7 +37,6 @@ */ -#include "portal.h" #include "p_local.h" #include "p_lnspec.h" #include "r_bsp.h" @@ -925,7 +924,7 @@ void P_CreateLinkedPortals() { for (int j = 0; j < 2; j++) { - ASkyViewpoint *box = sectors[i].SkyBoxes[j]; + AActor *box = sectors[i].SkyBoxes[j]; if (box != NULL && box->special1 == SKYBOX_LINKEDPORTAL) { secplane_t &plane = j == 0 ? sectors[i].floorplane : sectors[i].ceilingplane; @@ -961,7 +960,7 @@ void P_CreateLinkedPortals() { for (int j = 0; j < 2; j++) { - ASkyViewpoint *box = sectors[i].SkyBoxes[j]; + ASkyViewpoint *box = barrier_cast(sectors[i].SkyBoxes[j]); if (box != NULL) { if (box->special1 == SKYBOX_LINKEDPORTAL && sectors[i].PortalGroup == 0) @@ -1061,10 +1060,10 @@ bool P_CollectConnectedGroups(int startgroup, const fixedvec3 &position, fixed_t static TArray foundPortals; bool retval = false; + out.inited = true; if (linkedPortals.Size() == 0) { // If there are no portals, all sectors are in group 0. - out.Add(0); return false; } processMask.setSize(linkedPortals.Size()); diff --git a/src/portal.h b/src/portal.h index fcf6c545b..c974d8049 100644 --- a/src/portal.h +++ b/src/portal.h @@ -3,11 +3,7 @@ #include "basictypes.h" #include "v_video.h" -#include "r_defs.h" -#include "actor.h" -#include "p_local.h" #include "m_bbox.h" -#include "a_sharedglobal.h" struct FPortalGroupArray; //============================================================================ @@ -180,90 +176,4 @@ public: /* new code */ fixed_t P_PointLineDistance(line_t* line, fixed_t x, fixed_t y); -//============================================================================ -// -// some wrappers around the portal data. -// -//============================================================================ - - -// returns true if the portal is crossable by actors -inline bool line_t::isLinePortal() const -{ - return portalindex >= linePortals.Size() ? false : !!(linePortals[portalindex].mFlags & PORTF_PASSABLE); -} - -// returns true if the portal needs to be handled by the renderer -inline bool line_t::isVisualPortal() const -{ - return portalindex >= linePortals.Size() ? false : !!(linePortals[portalindex].mFlags & PORTF_VISIBLE); -} - -inline line_t *line_t::getPortalDestination() const -{ - return portalindex >= linePortals.Size() ? (line_t*)NULL : linePortals[portalindex].mDestination; -} - -inline int line_t::getPortalAlignment() const -{ - return portalindex >= linePortals.Size() ? 0 : linePortals[portalindex].mAlign; -} - -inline bool sector_t::PortalBlocksView(int plane) -{ - if (SkyBoxes[plane] == NULL) return true; - if (SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return false; - return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); -} - -inline bool sector_t::PortalBlocksSight(int plane) -{ - if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true; - return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); -} - -inline bool sector_t::PortalBlocksMovement(int plane) -{ - if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true; - return !!(planes[plane].Flags & (PLANEF_NOPASS | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); -} - -inline bool sector_t::PortalBlocksSound(int plane) -{ - if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true; - return !!(planes[plane].Flags & (PLANEF_BLOCKSOUND | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); -} - -// These may only be called if the portal has been validated -inline FDisplacement §or_t::FloorDisplacement() -{ - return Displacements(PortalGroup, SkyBoxes[sector_t::floor]->Sector->PortalGroup); -} - -inline FDisplacement §or_t::CeilingDisplacement() -{ - return Displacements(PortalGroup, SkyBoxes[sector_t::ceiling]->Sector->PortalGroup); -} - -inline fixedvec3 AActor::PosRelative(AActor *other) const -{ - FDisplacement &disp = Displacements(Sector->PortalGroup, other->Sector->PortalGroup); - fixedvec3 ret = { X() + disp.pos.x, Y() + disp.pos.y, Z() }; - return ret; -} - -inline fixedvec3 AActor::PosRelative(sector_t *sec) const -{ - FDisplacement &disp = Displacements(Sector->PortalGroup, sec->PortalGroup); - fixedvec3 ret = { X() + disp.pos.x, Y() + disp.pos.y, Z() }; - return ret; -} - -inline fixedvec3 AActor::PosRelative(line_t *line) const -{ - FDisplacement &disp = Displacements(Sector->PortalGroup, line->frontsector->PortalGroup); - fixedvec3 ret = { X() + disp.pos.x, Y() + disp.pos.y, Z() }; - return ret; -} - #endif \ No newline at end of file diff --git a/src/r_bsp.cpp b/src/r_bsp.cpp index 8fba4a8e3..a95bd97a0 100644 --- a/src/r_bsp.cpp +++ b/src/r_bsp.cpp @@ -56,7 +56,6 @@ #include "r_sky.h" #include "po_man.h" #include "r_data/colormaps.h" -#include "portal.h" seg_t* curline; side_t* sidedef; diff --git a/src/r_bsp.h b/src/r_bsp.h index 8c19a2670..30ddf3b0e 100644 --- a/src/r_bsp.h +++ b/src/r_bsp.h @@ -25,7 +25,7 @@ #include "tarray.h" #include -#include "portal.h" +#include "r_defs.h" // The 3072 below is just an arbitrary value picked to avoid // drawing lines the player is too close to that would overflow diff --git a/src/r_defs.h b/src/r_defs.h index 80764fe21..07903403e 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -739,10 +739,41 @@ struct sector_t Flags &= ~SECF_SPECIALFLAGS; } - bool PortalBlocksView(int plane); - bool PortalBlocksSight(int plane); - bool PortalBlocksMovement(int plane); - bool PortalBlocksSound(int plane); + bool PortalBlocksView(int plane) + { + if (SkyBoxes[plane] == NULL) return true; + if (SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return false; + return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); + } + + bool PortalBlocksSight(int plane) + { + if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true; + return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); + } + + bool PortalBlocksMovement(int plane) + { + if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true; + return !!(planes[plane].Flags & (PLANEF_NOPASS | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); + } + + bool PortalBlocksSound(int plane) + { + if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true; + return !!(planes[plane].Flags & (PLANEF_BLOCKSOUND | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); + } + + // These may only be called if the portal has been validated + FDisplacement &FloorDisplacement() + { + return Displacements(PortalGroup, SkyBoxes[sector_t::floor]->Sector->PortalGroup); + } + + FDisplacement &CeilingDisplacement() + { + return Displacements(PortalGroup, SkyBoxes[sector_t::ceiling]->Sector->PortalGroup); + } int GetTerrain(int pos) const; @@ -778,9 +809,6 @@ struct sector_t return NextLowestFloorAt(a->X(), a->Y(), z, resultsec, resultffloor); } - FDisplacement &FloorDisplacement(); - FDisplacement &CeilingDisplacement(); - // Member variables fixed_t CenterFloor () const { return floorplane.ZatPoint (soundorg[0], soundorg[1]); } fixed_t CenterCeiling () const { return ceilingplane.ZatPoint (soundorg[0], soundorg[1]); } @@ -864,7 +892,7 @@ struct sector_t // [RH] The sky box to render for this sector. NULL means use a // regular sky. - TObjPtr SkyBoxes[2]; + TObjPtr SkyBoxes[2]; int PortalGroup; int sectornum; // for comparing sector copies @@ -1045,11 +1073,26 @@ struct line_t unsigned portalindex; // returns true if the portal is crossable by actors - bool isLinePortal() const; + bool isLinePortal() const + { + return portalindex >= linePortals.Size() ? false : !!(linePortals[portalindex].mFlags & PORTF_PASSABLE); + } + // returns true if the portal needs to be handled by the renderer - bool isVisualPortal() const; - line_t *getPortalDestination() const; - int getPortalAlignment() const; + bool isVisualPortal() const + { + return portalindex >= linePortals.Size() ? false : !!(linePortals[portalindex].mFlags & PORTF_VISIBLE); + } + + line_t *getPortalDestination() const + { + return portalindex >= linePortals.Size() ? (line_t*)NULL : linePortals[portalindex].mDestination; + } + + int getPortalAlignment() const + { + return portalindex >= linePortals.Size() ? 0 : linePortals[portalindex].mAlign; + } }; // phares 3/14/98 @@ -1195,6 +1238,24 @@ inline sector_t *P_PointInSector(fixed_t x, fixed_t y) return P_PointInSubsector(x, y)->sector; } -#define _ZatPoint ZatPoint // so that it still compiles during the transition +inline fixedvec3 AActor::PosRelative(AActor *other) const +{ + return __pos + Displacements(Sector->PortalGroup, other->Sector->PortalGroup); +} + +inline fixedvec3 AActor::PosRelative(sector_t *sec) const +{ + return __pos + Displacements(Sector->PortalGroup, sec->PortalGroup); +} + +inline fixedvec3 AActor::PosRelative(line_t *line) const +{ + return __pos + Displacements(Sector->PortalGroup, line->frontsector->PortalGroup); +} + +inline fixedvec3 PosRelative(const fixedvec3 &pos, line_t *line, sector_t *refsec = NULL) +{ + return pos + Displacements(refsec->PortalGroup, line->frontsector->PortalGroup); +} #endif diff --git a/src/r_main.cpp b/src/r_main.cpp index 90b8d865b..02a3349a3 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -58,7 +58,6 @@ #include "v_font.h" #include "r_data/colormaps.h" #include "farchive.h" -#include "portal.h" // MACROS ------------------------------------------------------------------ diff --git a/src/r_plane.cpp b/src/r_plane.cpp index f1deceb9f..862eed3fb 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -58,7 +58,6 @@ #include "r_3dfloors.h" #include "v_palette.h" #include "r_data/colormaps.h" -#include "portal.h" #ifdef _MSC_VER #pragma warning(disable:4244) diff --git a/src/r_segs.cpp b/src/r_segs.cpp index 96a0595d7..ae38b3978 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -52,7 +52,6 @@ #include "r_3dfloors.h" #include "v_palette.h" #include "r_data/colormaps.h" -#include "portal.h" #define WALLYREPEAT 8 diff --git a/src/r_utility.cpp b/src/r_utility.cpp index 45760a5ce..10a39ba57 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -34,7 +34,6 @@ #include "doomstat.h" #include "m_random.h" #include "m_bbox.h" -#include "portal.h" #include "r_sky.h" #include "st_stuff.h" #include "c_cvars.h" @@ -57,7 +56,7 @@ #include "farchive.h" #include "r_utility.h" #include "d_player.h" -#include "portal.h" +#include "p_local.h" // EXTERNAL DATA DECLARATIONS ---------------------------------------------- From 28799c4b510c44c81eb8a2d35cd15b55270059cc Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 19 Feb 2016 16:13:36 +0100 Subject: [PATCH 11/28] - some logic fixes in FMultiBlockLinesIterator. --- src/p_maputl.cpp | 77 +++++++++++++++++++++++++++++++++--------------- src/p_maputl.h | 2 ++ 2 files changed, 55 insertions(+), 24 deletions(-) diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 38be280d6..c1177caf8 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -705,6 +705,38 @@ FMultiBlockLinesIterator::FMultiBlockLinesIterator(FPortalGroupArray &check, AAc Reset(); } +bool FMultiBlockLinesIterator::GoUp(fixed_t x, fixed_t y) +{ + if (continueup) + { + sector_t *sector = P_PointInSector(x, y); + if (!sector->PortalBlocksMovement(sector_t::ceiling)) + { + startIteratorForGroup(sector->SkyBoxes[sector_t::ceiling]->Sector->PortalGroup); + portalflags = FFCF_NOFLOOR; + return true; + } + else continueup = false; + } + return false; +} + +bool FMultiBlockLinesIterator::GoDown(fixed_t x, fixed_t y) +{ + if (continuedown) + { + sector_t *sector = P_PointInSector(x, y); + if (!sector->PortalBlocksMovement(sector_t::floor)) + { + startIteratorForGroup(sector->SkyBoxes[sector_t::floor]->Sector->PortalGroup); + portalflags = FFCF_NOCEILING; + return true; + } + else continuedown = false; + } + return false; +} + bool FMultiBlockLinesIterator::Next(FMultiBlockLinesIterator::CheckResult *item) { line_t *line = blockIterator.Next(); @@ -715,36 +747,33 @@ bool FMultiBlockLinesIterator::Next(FMultiBlockLinesIterator::CheckResult *item) item->portalflags = portalflags; return true; } - else if (checklist[index] & FPortalGroupArray::UPPER) + bool onlast = unsigned(index + 1) >= checklist.Size(); + int nextflags = onlast ? 0 : checklist[index + 1] & FPortalGroupArray::FLAT; + + if (portalflags == FFCF_NOFLOOR && nextflags != FPortalGroupArray::UPPER) { - if (continueup) - { - sector_t *sector = P_PointInSector(offset.x, offset.y); - if (!sector->PortalBlocksMovement(sector_t::ceiling)) - { - startIteratorForGroup(sector->SkyBoxes[sector_t::ceiling]->Sector->PortalGroup); - portalflags = FFCF_NOFLOOR; - return Next(item); - } - } + // if this is the last upper portal in the list, check if we need to go further up to find the real ceiling. + if (GoUp(offset.x, offset.y)) return Next(item); } - else if (checklist[index] & FPortalGroupArray::LOWER) + else if (portalflags == FFCF_NOCEILING && nextflags != FPortalGroupArray::LOWER) { - if (continuedown) - { - sector_t *sector = P_PointInSector(offset.x, offset.y); - if (!sector->PortalBlocksMovement(sector_t::floor)) - { - startIteratorForGroup(sector->SkyBoxes[sector_t::floor]->Sector->PortalGroup); - portalflags = FFCF_NOCEILING; - return Next(item); - } - } + // if this is the last lower portal in the list, check if we need to go further down to find the real floor. + if (GoDown(offset.x, offset.y)) return Next(item); } + if (onlast) + { + // We reached the end of the list. Check if we still need to check up- and downwards. + if (GoUp(checkpoint.x, checkpoint.y) || + GoDown(checkpoint.x, checkpoint.y)) + { + return Next(item); + } + return false; + } + index++; - if (index >= checklist.Size()) return false; startIteratorForGroup(checklist[index] & ~FPortalGroupArray::FLAT); - switch (checklist[index] & FPortalGroupArray::FLAT) + switch (nextflags) { case FPortalGroupArray::UPPER: portalflags = FFCF_NOFLOOR; diff --git a/src/p_maputl.h b/src/p_maputl.h index 3ebc02f31..d7ab7b62b 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -211,6 +211,8 @@ class FMultiBlockLinesIterator FBlockLinesIterator blockIterator; FBoundingBox bbox; + bool GoUp(fixed_t x, fixed_t y); + bool GoDown(fixed_t x, fixed_t y); void startIteratorForGroup(int group); public: From cb0e7c6ca5a7d8dcd4dd6b2730d48b0610ebd5c1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 19 Feb 2016 19:14:49 +0100 Subject: [PATCH 12/28] - fixed some issues with P_FindFloorCeiling rework. --- src/p_map.cpp | 2 ++ src/portal.cpp | 2 ++ src/portal.h | 6 ++++++ 3 files changed, 10 insertions(+) diff --git a/src/p_map.cpp b/src/p_map.cpp index bce8c7739..eb537a3b1 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -857,6 +857,8 @@ bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm) fixedvec2 ref = FindRefPoint(ld, rpos); FLineOpening open; + P_LineOpening(open, tm.thing, ld, ref.x, ref.y, tm.x, tm.y, 0); + // the floorplane on both sides is identical with the current one // so don't mess around with the z-position. if (ld->frontsector->floorplane == ld->backsector->floorplane && diff --git a/src/portal.cpp b/src/portal.cpp index efd46d851..62c44ce2f 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -918,6 +918,8 @@ void P_CreateLinkedPortals() } if (orgs.Size() == 0) { + // Create the 0->0 translation which is always needed. + Displacements.Create(1); return; } for (int i = 0; i < numsectors; i++) diff --git a/src/portal.h b/src/portal.h index c974d8049..33fb86692 100644 --- a/src/portal.h +++ b/src/portal.h @@ -41,6 +41,11 @@ struct FDisplacementTable TArray data; int size; + FDisplacementTable() + { + Create(1); + } + void Create(int numgroups) { data.Resize(numgroups*numgroups); @@ -50,6 +55,7 @@ struct FDisplacementTable FDisplacement &operator()(int x, int y) { + if (x == y) return data[0]; // shortcut for the most common case return data[x + size*y]; } }; From dc37f78566afc6e1edd4566b05355ed58b99a4a2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 19 Feb 2016 20:51:47 +0100 Subject: [PATCH 13/28] - fixed: Old portal data must be deleted before loading a new level. --- src/p_acs.cpp | 1 - src/p_setup.cpp | 2 +- src/portal.cpp | 14 ++++++++++++++ src/portal.h | 1 + 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index c6b96252d..54101ae13 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4178,7 +4178,6 @@ bool DLevelScript::DoCheckActorTexture(int tid, AActor *activator, int string, b // they're obviously not the same. return 0; } - int i, numff; FTextureID secpic; sector_t *resultsec; F3DFloor *resffloor; diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 55dbdfcac..b1cb43c25 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -3392,12 +3392,12 @@ void P_FreeLevelData () FPolyObj::ClearAllSubsectorLinks(); // can't be done as part of the polyobj deletion process. SN_StopAllSequences (); DThinker::DestroyAllThinkers (); + P_ClearPortals(); tagManager.Clear(); level.total_monsters = level.total_items = level.total_secrets = level.killed_monsters = level.found_items = level.found_secrets = wminfo.maxfrags = 0; - linePortals.Clear(); FBehavior::StaticUnloadModules (); if (vertexes != NULL) { diff --git a/src/portal.cpp b/src/portal.cpp index 62c44ce2f..ef22eade3 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -359,6 +359,20 @@ bool P_ChangePortal(line_t *ln, int thisid, int destid) return res; } +//============================================================================ +// +// clears all portal dat for a new level start +// +//============================================================================ + +void P_ClearPortals() +{ + Displacements.Create(1); + linePortals.Clear(); + linkedPortals.Clear(); +} + + //============================================================================ // // Calculate the intersection between two lines. diff --git a/src/portal.h b/src/portal.h index 33fb86692..5ea0293ac 100644 --- a/src/portal.h +++ b/src/portal.h @@ -123,6 +123,7 @@ struct FLinePortal extern TArray linePortals; +void P_ClearPortals(); void P_SpawnLinePortal(line_t* line); void P_FinalizePortals(); bool P_ChangePortal(line_t *ln, int thisid, int destid); From 6132f6971af9fa77ed909e77d10318978737ce31 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 19 Feb 2016 22:03:29 +0100 Subject: [PATCH 14/28] - added support for FFCF_NOPORTALS and FFCF_3DRESTRICT to FindNextLowestFloorAt and FindNextHighestCeilingAt - use these functions in P_GetFloorCeiling instead of duplicating all this code. - removed some debug CCMDs. --- src/p_acs.cpp | 4 +-- src/p_map.cpp | 47 +++++++-------------------------- src/p_sectors.cpp | 66 ++++++++++++----------------------------------- src/r_defs.h | 12 ++++----- 4 files changed, 34 insertions(+), 95 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 54101ae13..4ca32bd49 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4184,12 +4184,12 @@ bool DLevelScript::DoCheckActorTexture(int tid, AActor *activator, int string, b if (floor) { - actor->Sector->NextLowestFloorAt(actor, actor->Z(), &resultsec, &resffloor); + actor->Sector->NextLowestFloorAt(actor, actor->Z(), 0, &resultsec, &resffloor); secpic = resffloor ? *resffloor->top.texture : resultsec->planes[sector_t::floor].Texture; } else { - actor->Sector->NextHighestCeilingAt(actor, actor->Top(), &resultsec, &resffloor); + actor->Sector->NextHighestCeilingAt(actor, actor->Top(), 0, &resultsec, &resffloor); secpic = resffloor ? *resffloor->bottom.texture : resultsec->planes[sector_t::ceiling].Texture; } return tex == TexMan[secpic]; diff --git a/src/p_map.cpp b/src/p_map.cpp index eb537a3b1..1bfd280f3 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -261,51 +261,24 @@ static bool PIT_FindFloorCeiling(FMultiBlockLinesIterator::CheckResult &cres, co void P_GetFloorCeilingZ(FCheckPosition &tmf, int flags) { sector_t *sec = (!(flags & FFCF_SAMESECTOR) || tmf.thing->Sector == NULL)? P_PointInSector(tmf.x, tmf.y) : tmf.thing->Sector; + F3DFloor *ffc, *fff; - if (flags & FFCF_NOPORTALS) + tmf.ceilingz = sec->NextHighestCeilingAt(tmf.thing, tmf.z + tmf.thing->height, flags, &tmf.floorsector, &ffc); + tmf.floorz = tmf.dropoffz = sec->NextLowestFloorAt(tmf.thing, tmf.z, flags, &tmf.ceilingsector, &fff); + + if (fff) { - tmf.thing->dropoffz = tmf.thing->floorz = sec->floorplane.ZatPoint(tmf.x, tmf.y); - tmf.thing->ceilingz = sec->ceilingplane.ZatPoint(tmf.x, tmf.y); - tmf.ceilingsector = tmf.floorsector = sec; + tmf.floorpic = *fff->top.texture; + tmf.floorterrain = fff->model->GetTerrain(fff->top.isceiling); } else { - tmf.floorz = tmf.dropoffz = sec->LowestFloorAt(tmf.x, tmf.y, &tmf.floorsector); - tmf.ceilingz = sec->HighestCeilingAt(tmf.x, tmf.y, &tmf.ceilingsector); + tmf.floorpic = tmf.floorsector->GetTexture(sector_t::floor); + tmf.floorterrain = tmf.floorsector->GetTerrain(sector_t::floor); } - tmf.floorpic = tmf.floorsector->GetTexture(sector_t::floor); - tmf.floorterrain = tmf.floorsector->GetTerrain(sector_t::floor); - tmf.ceilingpic = tmf.ceilingsector->GetTexture(sector_t::ceiling); - + tmf.ceilingpic = ffc ? *ffc->bottom.texture : tmf.ceilingsector->GetTexture(sector_t::ceiling); tmf.sector = sec; - for (unsigned int i = 0; ie->XFloor.ffloors.Size(); i++) - { - F3DFloor* rover = sec->e->XFloor.ffloors[i]; - - if (!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue; - - fixed_t ff_bottom = rover->bottom.plane->ZatPoint(tmf.x, tmf.y); - fixed_t ff_top = rover->top.plane->ZatPoint(tmf.x, tmf.y); - - if (ff_top > tmf.floorz) - { - // either with feet above the 3D floor or feet with less than 'stepheight' map units inside - if (ff_top <= tmf.z || (!(flags & FFCF_3DRESTRICT) && (ff_bottom < tmf.z && ff_top < tmf.z + tmf.thing->MaxStepHeight))) - { - tmf.dropoffz = tmf.floorz = ff_top; - tmf.floorpic = *rover->top.texture; - tmf.floorterrain = rover->model->GetTerrain(rover->top.isceiling); - tmf.floorsector = sec; - } - } - if (ff_bottom <= tmf.ceilingz && ff_bottom > tmf.z + tmf.thing->height) - { - tmf.ceilingz = ff_bottom; - tmf.ceilingpic = *rover->bottom.texture; - tmf.ceilingsector = sec; - } - } } //========================================================================== diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index ab1cc40d7..756495ac8 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -31,6 +31,7 @@ #include "farchive.h" #include "r_utility.h" #include "a_sharedglobal.h" +#include "p_local.h" #include "r_data/colormaps.h" @@ -931,7 +932,7 @@ fixed_t sector_t::LowestFloorAt(fixed_t x, fixed_t y, sector_t **resultsec) } -fixed_t sector_t::NextHighestCeilingAt(fixed_t x, fixed_t y, fixed_t z, sector_t **resultsec, F3DFloor **resultffloor) +fixed_t sector_t::NextHighestCeilingAt(fixed_t x, fixed_t y, fixed_t z, int flags, sector_t **resultsec, F3DFloor **resultffloor) { sector_t *sec = this; fixed_t planeheight = FIXED_MIN; @@ -951,7 +952,7 @@ fixed_t sector_t::NextHighestCeilingAt(fixed_t x, fixed_t y, fixed_t z, sector_t return ffz; } } - if (sec->PortalBlocksMovement(ceiling) || planeheight >= sec->SkyBoxes[ceiling]->threshold) + if ((flags & FFCF_NOPORTALS) || sec->PortalBlocksMovement(ceiling) || planeheight >= sec->SkyBoxes[ceiling]->threshold) { // Use sector's floor if (resultffloor) *resultffloor = NULL; if (resultsec) *resultsec = sec; @@ -968,7 +969,7 @@ fixed_t sector_t::NextHighestCeilingAt(fixed_t x, fixed_t y, fixed_t z, sector_t } } -fixed_t sector_t::NextLowestFloorAt(fixed_t x, fixed_t y, fixed_t z, sector_t **resultsec, F3DFloor **resultffloor) +fixed_t sector_t::NextLowestFloorAt(fixed_t x, fixed_t y, fixed_t z, int flags, fixed_t steph, sector_t **resultsec, F3DFloor **resultffloor) { sector_t *sec = this; fixed_t planeheight = FIXED_MAX; @@ -981,14 +982,20 @@ fixed_t sector_t::NextLowestFloorAt(fixed_t x, fixed_t y, fixed_t z, sector_t ** F3DFloor *ff = sec->e->XFloor.ffloors[i]; fixed_t ffz = ff->top.plane->ZatPoint(x, y); - if ((ff->flags & (FF_EXISTS | FF_SOLID)) == (FF_EXISTS | FF_SOLID) && z >= ffz) - { // This floor is beneath our feet. - if (resultsec) *resultsec = sec; - if (resultffloor) *resultffloor = ff; - return ffz; + fixed_t ffb = ff->bottom.plane->ZatPoint(x, y); + + // either with feet above the 3D floor or feet with less than 'stepheight' map units inside + if ((ff->flags & (FF_EXISTS | FF_SOLID)) == (FF_EXISTS | FF_SOLID)) + { + if (z >= ffz || (!(flags & FFCF_3DRESTRICT) && (ffb < z && ffz < z + steph))) + { // This floor is beneath our feet. + if (resultsec) *resultsec = sec; + if (resultffloor) *resultffloor = ff; + return ffz; + } } } - if (sec->PortalBlocksMovement(sector_t::floor) || planeheight <= sec->SkyBoxes[floor]->threshold) + if ((flags & FFCF_NOPORTALS) || sec->PortalBlocksMovement(sector_t::floor) || planeheight <= sec->SkyBoxes[floor]->threshold) { // Use sector's floor if (resultffloor) *resultffloor = NULL; if (resultsec) *resultsec = sec; @@ -1217,44 +1224,3 @@ int side_t::GetLightLevel (bool foggy, int baselight, bool is3dlight, int *pfake } return baselight; } - -#include "c_dispatch.h" -#include "d_player.h" - -CCMD(highestceiling) -{ - sector_t *sec; - fixed_t h = players[consoleplayer].mo->Sector->HighestCeilingAt(players[consoleplayer].mo, &sec); - Printf("Check at position %f,%f, height = %f, srcsector = %d dstsector = %d, srcgroup = %d, dstgroup = %d\n", - players[consoleplayer].mo->X() / 65536., players[consoleplayer].mo->Y() / 65536., h / 65536., - players[consoleplayer].mo->Sector->sectornum, sec->sectornum, players[consoleplayer].mo->Sector->PortalGroup, sec->PortalGroup); -} - -CCMD(lowestfloor) -{ - sector_t *sec; - fixed_t h = players[consoleplayer].mo->Sector->LowestFloorAt(players[consoleplayer].mo, &sec); - Printf("Check at position %f,%f, height = %f, srcsector = %d dstsector = %d, srcgroup = %d, dstgroup = %d\n", - players[consoleplayer].mo->X() / 65536., players[consoleplayer].mo->Y() / 65536., h / 65536., - players[consoleplayer].mo->Sector->sectornum, sec->sectornum, players[consoleplayer].mo->Sector->PortalGroup, sec->PortalGroup); -} - -CCMD(nexthighestceiling) -{ - sector_t *sec; - F3DFloor *ff; - fixed_t h = players[consoleplayer].mo->Sector->NextHighestCeilingAt(players[consoleplayer].mo, players[consoleplayer].mo->Top(), &sec, &ff); - Printf("Check at position %f,%f, height = %f, srcsector = %d dstsector = %d, srcgroup = %d, dstgroup = %d, 3dfloor = %d\n", - players[consoleplayer].mo->X() / 65536., players[consoleplayer].mo->Y() / 65536., h / 65536., - players[consoleplayer].mo->Sector->sectornum, sec->sectornum, players[consoleplayer].mo->Sector->PortalGroup, sec->PortalGroup, !!ff); -} - -CCMD(nextlowestfloor) -{ - sector_t *sec; - F3DFloor *ff; - fixed_t h = players[consoleplayer].mo->Sector->NextLowestFloorAt(players[consoleplayer].mo, players[consoleplayer].mo->Z(), &sec, &ff); - Printf("Check at position %f,%f, height = %f, srcsector = %d dstsector = %d, srcgroup = %d, dstgroup = %d, 3dfloor = %d\n", - players[consoleplayer].mo->X() / 65536., players[consoleplayer].mo->Y() / 65536., h / 65536., - players[consoleplayer].mo->Sector->sectornum, sec->sectornum, players[consoleplayer].mo->Sector->PortalGroup, sec->PortalGroup, !!ff); -} diff --git a/src/r_defs.h b/src/r_defs.h index 07903403e..c4444e9f1 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -796,17 +796,17 @@ struct sector_t return LowestFloorAt(a->X(), a->Y(), resultsec); } - fixed_t NextHighestCeilingAt(fixed_t x, fixed_t y, fixed_t z, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL); - fixed_t NextLowestFloorAt(fixed_t x, fixed_t y, fixed_t z, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL); + fixed_t NextHighestCeilingAt(fixed_t x, fixed_t y, fixed_t z, int flags = 0, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL); + fixed_t NextLowestFloorAt(fixed_t x, fixed_t y, fixed_t z, int flags = 0, fixed_t steph = 0, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL); - fixed_t NextHighestCeilingAt(AActor *a, fixed_t z, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL) + fixed_t NextHighestCeilingAt(AActor *a, fixed_t z, int flags = 0, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL) { - return NextHighestCeilingAt(a->X(), a->Y(), z, resultsec, resultffloor); + return NextHighestCeilingAt(a->X(), a->Y(), z, flags, resultsec, resultffloor); } - fixed_t NextLowestFloorAt(AActor *a, fixed_t z, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL) + fixed_t NextLowestFloorAt(AActor *a, fixed_t z, int flags, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL) { - return NextLowestFloorAt(a->X(), a->Y(), z, resultsec, resultffloor); + return NextLowestFloorAt(a->X(), a->Y(), z, flags, a->MaxStepHeight, resultsec, resultffloor); } // Member variables From d876a95152f3d9f806a7bcb477fa62d246b2888e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 19 Feb 2016 23:54:55 +0100 Subject: [PATCH 15/28] - set floor and ceiling sector when it comes from a 3D floor. There's code in p_mobj.cpp which needs this to pick the correct plane. --- src/p_3dfloors.cpp | 5 +++++ src/p_map.cpp | 3 +++ 2 files changed, 8 insertions(+) diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index 61c4564b9..397d2be1e 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -775,6 +775,7 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li FTextureID highestfloorpic; int highestfloorterrain = -1; FTextureID lowestceilingpic; + sector_t *lowestceilingsec = NULL, *highestfloorsec = NULL; highestfloorpic.SetInvalid(); lowestceilingpic.SetInvalid(); @@ -798,6 +799,7 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li { lowestceiling = ff_bottom; lowestceilingpic = *rover->bottom.texture; + lowestceilingsec = j == 0 ? linedef->frontsector : linedef->backsector; } if(ff_top > highestfloor && delta1 < delta2 && (!restrict || thing->Z() >= ff_top)) @@ -805,6 +807,7 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li highestfloor = ff_top; highestfloorpic = *rover->top.texture; highestfloorterrain = rover->model->GetTerrain(rover->top.isceiling); + highestfloorsec = j == 0 ? linedef->frontsector : linedef->backsector; } if(ff_top > lowestfloor[j] && ff_top <= thing->Z() + thing->MaxStepHeight) lowestfloor[j] = ff_top; } @@ -815,12 +818,14 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li open.bottom = highestfloor; open.floorpic = highestfloorpic; open.floorterrain = highestfloorterrain; + open.bottomsec = highestfloorsec; } if(lowestceiling < open.top) { open.top = lowestceiling; open.ceilingpic = lowestceilingpic; + open.topsec = lowestceilingsec; } open.lowfloor = MIN(lowestfloor[0], lowestfloor[1]); diff --git a/src/p_map.cpp b/src/p_map.cpp index 1bfd280f3..f357253af 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -226,6 +226,7 @@ static bool PIT_FindFloorCeiling(FMultiBlockLinesIterator::CheckResult &cres, co if (open.top < tmf.ceilingz) { tmf.ceilingz = open.top; + if (open.topsec != NULL) tmf.floorsector = open.topsec; } } @@ -245,7 +246,9 @@ static bool PIT_FindFloorCeiling(FMultiBlockLinesIterator::CheckResult &cres, co } if (open.lowfloor < tmf.dropoffz) + { tmf.dropoffz = open.lowfloor; + } } return true; } From cfbb3bcbb2c266bf9b34137bada862355cc64d27 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 20 Feb 2016 02:19:09 +0100 Subject: [PATCH 16/28] - completed work on P_FindFloorCeiling and all functions it calls. Note: The debug output is left in so that in cases of an error it can still be used. --- src/p_map.cpp | 33 +++++++++++++++++++++++++++------ src/p_maputl.cpp | 26 ++++++++++++++++++++++---- src/p_maputl.h | 2 +- 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index f357253af..c372fa3ef 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -194,8 +194,9 @@ static inline fixedvec2 FindRefPoint(line_t *ld, fixedvec2 pos) // only3d set means to only check against 3D floors and midtexes. // //========================================================================== +bool ffcf_verbose; -static bool PIT_FindFloorCeiling(FMultiBlockLinesIterator::CheckResult &cres, const FBoundingBox &box, FCheckPosition &tmf, int flags) +static bool PIT_FindFloorCeiling(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::CheckResult &cres, const FBoundingBox &box, FCheckPosition &tmf, int flags) { line_t *ld = cres.line; @@ -210,6 +211,12 @@ static bool PIT_FindFloorCeiling(FMultiBlockLinesIterator::CheckResult &cres, co // A line has been hit + if (ffcf_verbose) + { + Printf("Hit line %d at position %f,%f, group %d\n", + int(ld - lines), FIXED2FLOAT(cres.position.x), FIXED2FLOAT(cres.position.y), ld->frontsector->PortalGroup); + } + if (!ld->backsector) { // One sided line return true; @@ -227,6 +234,8 @@ static bool PIT_FindFloorCeiling(FMultiBlockLinesIterator::CheckResult &cres, co { tmf.ceilingz = open.top; if (open.topsec != NULL) tmf.floorsector = open.topsec; + if (ffcf_verbose) Printf(" Adjust ceilingz to %f\n", FIXED2FLOAT(open.top)); + mit.StopUp(); } } @@ -238,6 +247,8 @@ static bool PIT_FindFloorCeiling(FMultiBlockLinesIterator::CheckResult &cres, co if (open.bottomsec != NULL) tmf.floorsector = open.bottomsec; tmf.touchmidtex = open.touchmidtex; tmf.abovemidtex = open.abovemidtex; + if (ffcf_verbose) Printf(" Adjust floorz to %f\n", FIXED2FLOAT(open.bottom)); + if (tmf.floorz > tmf.dropoffz + tmf.thing->MaxDropOffHeight) mit.StopDown(); } else if (open.bottom == tmf.floorz) { @@ -245,9 +256,11 @@ static bool PIT_FindFloorCeiling(FMultiBlockLinesIterator::CheckResult &cres, co tmf.abovemidtex |= open.abovemidtex; } - if (open.lowfloor < tmf.dropoffz) + if (open.lowfloor < tmf.dropoffz && open.lowfloor > FIXED_MIN) { tmf.dropoffz = open.lowfloor; + if (ffcf_verbose) Printf(" Adjust dropoffz to %f\n", FIXED2FLOAT(open.bottom)); + if (tmf.floorz > tmf.dropoffz + tmf.thing->MaxDropOffHeight) mit.StopDown(); } } return true; @@ -266,8 +279,8 @@ void P_GetFloorCeilingZ(FCheckPosition &tmf, int flags) sector_t *sec = (!(flags & FFCF_SAMESECTOR) || tmf.thing->Sector == NULL)? P_PointInSector(tmf.x, tmf.y) : tmf.thing->Sector; F3DFloor *ffc, *fff; - tmf.ceilingz = sec->NextHighestCeilingAt(tmf.thing, tmf.z + tmf.thing->height, flags, &tmf.floorsector, &ffc); - tmf.floorz = tmf.dropoffz = sec->NextLowestFloorAt(tmf.thing, tmf.z, flags, &tmf.ceilingsector, &fff); + tmf.ceilingz = sec->NextHighestCeilingAt(tmf.thing, tmf.z + tmf.thing->height, flags, &tmf.ceilingsector, &ffc); + tmf.floorz = tmf.dropoffz = sec->NextLowestFloorAt(tmf.thing, tmf.z, flags, &tmf.floorsector, &fff); if (fff) { @@ -314,6 +327,7 @@ void P_FindFloorCeiling(AActor *actor, int flags) actor->floorsector = tmf.floorsector; actor->ceilingpic = tmf.ceilingpic; actor->ceilingsector = tmf.ceilingsector; + if (ffcf_verbose) Printf("Starting with ceilingz = %f, floorz = %f\n", FIXED2FLOAT(tmf.ceilingz), FIXED2FLOAT(tmf.floorz)); tmf.touchmidtex = false; tmf.abovemidtex = false; @@ -330,7 +344,7 @@ void P_FindFloorCeiling(AActor *actor, int flags) while ((mit.Next(&cres))) { - PIT_FindFloorCeiling(cres, mit.Box(), tmf, flags|cres.portalflags); + PIT_FindFloorCeiling(mit, cres, mit.Box(), tmf, flags|cres.portalflags); } if (tmf.touchmidtex) tmf.dropoffz = tmf.floorz; @@ -355,6 +369,13 @@ void P_FindFloorCeiling(AActor *actor, int flags) } } +// Debug CCMD for checking errors in the MultiBlockLinesIterator (needs to be removed when this code is complete) +CCMD(ffcf) +{ + ffcf_verbose = true; + P_FindFloorCeiling(players[0].mo, 0); + ffcf_verbose = false; +} //========================================================================== // // TELEPORT MOVE @@ -404,7 +425,7 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra while (mit.Next(&cres)) { - PIT_FindFloorCeiling(cres, mit.Box(), tmf, 0); + PIT_FindFloorCeiling(mit, cres, mit.Box(), tmf, 0); } thing->SetZ(savedz); diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index c1177caf8..e5396e484 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -162,10 +162,28 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef, front = linedef->frontsector; back = linedef->backsector; - fc = front->ceilingplane.ZatPoint (x, y); - ff = front->floorplane.ZatPoint (x, y); - bc = back->ceilingplane.ZatPoint (x, y); - bf = back->floorplane.ZatPoint (x, y); + if (!(flags & FFCF_NOPORTALS) && !linedef->frontsector->PortalBlocksMovement(sector_t::ceiling) && + linedef->backsector->SkyBoxes[sector_t::ceiling] && + linedef->frontsector->SkyBoxes[sector_t::ceiling]->Sector->PortalGroup == linedef->backsector->SkyBoxes[sector_t::ceiling]->Sector->PortalGroup) + { + fc = bc = FIXED_MAX; + } + else + { + fc = front->ceilingplane.ZatPoint(x, y); + bc = back->ceilingplane.ZatPoint(x, y); + } + if (!(flags & FFCF_NOPORTALS) && !linedef->frontsector->PortalBlocksMovement(sector_t::floor) && + linedef->backsector->SkyBoxes[sector_t::floor] && + linedef->frontsector->SkyBoxes[sector_t::floor]->Sector->PortalGroup == linedef->backsector->SkyBoxes[sector_t::floor]->Sector->PortalGroup) + { + ff = bf = FIXED_MIN; + } + else + { + ff = front->floorplane.ZatPoint(x, y); + bf = back->floorplane.ZatPoint(x, y); + } /*Printf ("]]]]]] %d %d\n", ff, bf);*/ diff --git a/src/p_maputl.h b/src/p_maputl.h index d7ab7b62b..a939855bf 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -205,7 +205,7 @@ class FMultiBlockLinesIterator fixedvec2 offset; short basegroup; short portalflags; - WORD index; + short index; bool continueup; bool continuedown; FBlockLinesIterator blockIterator; From 58fcd8d742c95bb7976b60e0454ded9ab1e235ca Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 20 Feb 2016 20:36:45 +0100 Subject: [PATCH 17/28] - implemented the FMultiBlockThingsIterator and converted P_TeleportMove to use it. --- src/p_map.cpp | 14 +++-- src/p_maputl.cpp | 153 +++++++++++++++++++++++++++++++++++++++++++++-- src/p_maputl.h | 43 ++++++++++++- 3 files changed, 196 insertions(+), 14 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index c372fa3ef..5ce9b837a 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -334,7 +334,7 @@ void P_FindFloorCeiling(AActor *actor, int flags) validcount++; FPortalGroupArray grouplist; - FMultiBlockLinesIterator mit(grouplist, actor, tmf.x, tmf.y, actor->radius); + FMultiBlockLinesIterator mit(grouplist, actor); FMultiBlockLinesIterator::CheckResult cres; // if we already have a valid floor/ceiling sector within the current sector, @@ -420,7 +420,7 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra thing->SetZ(z); FPortalGroupArray grouplist; - FMultiBlockLinesIterator mit(grouplist, thing, tmf.x, tmf.y, thing->radius); + FMultiBlockLinesIterator mit(grouplist, x, y, z, thing->height, thing->radius); FMultiBlockLinesIterator::CheckResult cres; while (mit.Next(&cres)) @@ -431,11 +431,13 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra if (tmf.touchmidtex) tmf.dropoffz = tmf.floorz; - FBlockThingsIterator it2(FBoundingBox(x, y, thing->radius)); - AActor *th; + FMultiBlockThingsIterator mit2(grouplist, x, y, z, thing->height, thing->radius); + FMultiBlockThingsIterator::CheckResult cres2; - while ((th = it2.Next())) + while (mit2.Next(&cres2)) { + AActor *th = cres2.thing; + if (!(th->flags & MF_SHOOTABLE)) continue; @@ -444,7 +446,7 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra continue; fixed_t blockdist = th->radius + tmf.thing->radius; - if (abs(th->X() - tmf.x) >= blockdist || abs(th->Y() - tmf.y) >= blockdist) + if (abs(th->X() - cres.position.x) >= blockdist || abs(th->Y() - cres.position.y) >= blockdist) continue; if ((th->flags2 | tmf.thing->flags2) & MF2_THRUACTORS) diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index e5396e484..59a7b9b54 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -711,18 +711,34 @@ line_t *FBlockLinesIterator::Next() // //=========================================================================== -FMultiBlockLinesIterator::FMultiBlockLinesIterator(FPortalGroupArray &check, AActor *origin, fixed_t checkx, fixed_t checky, fixed_t checkradius) +FMultiBlockLinesIterator::FMultiBlockLinesIterator(FPortalGroupArray &check, AActor *origin, fixed_t checkradius) : checklist(check) { checkpoint = origin->Pos(); - if (checkx != FIXED_MAX) checkpoint.x = checkx; - if (checky != FIXED_MAX) checkpoint.y = checky; - P_CollectConnectedGroups(origin->Sector->PortalGroup, checkpoint, origin->Top(), checkradius, checklist); + if (!check.inited) P_CollectConnectedGroups(origin->Sector->PortalGroup, checkpoint, origin->Top(), checkradius, checklist); checkpoint.z = checkradius; basegroup = origin->Sector->PortalGroup; Reset(); } +FMultiBlockLinesIterator::FMultiBlockLinesIterator(FPortalGroupArray &check, fixed_t checkx, fixed_t checky, fixed_t checkz, fixed_t checkh, fixed_t checkradius) + : checklist(check) +{ + checkpoint.x = checkx; + checkpoint.y = checky; + checkpoint.z = checkz; + basegroup = P_PointInSector(checkx, checky)->PortalGroup; + if (!check.inited) P_CollectConnectedGroups(basegroup, checkpoint, checkz + checkh, checkradius, checklist); + checkpoint.z = checkradius; + Reset(); +} + +//=========================================================================== +// +// Go up a ceiling portal +// +//=========================================================================== + bool FMultiBlockLinesIterator::GoUp(fixed_t x, fixed_t y) { if (continueup) @@ -739,6 +755,12 @@ bool FMultiBlockLinesIterator::GoUp(fixed_t x, fixed_t y) return false; } +//=========================================================================== +// +// Go down a floor portal +// +//=========================================================================== + bool FMultiBlockLinesIterator::GoDown(fixed_t x, fixed_t y) { if (continuedown) @@ -755,6 +777,12 @@ bool FMultiBlockLinesIterator::GoDown(fixed_t x, fixed_t y) return false; } +//=========================================================================== +// +// Gets the next line - also manages switching between portal groups +// +//=========================================================================== + bool FMultiBlockLinesIterator::Next(FMultiBlockLinesIterator::CheckResult *item) { line_t *line = blockIterator.Next(); @@ -808,6 +836,12 @@ bool FMultiBlockLinesIterator::Next(FMultiBlockLinesIterator::CheckResult *item) return Next(item); } +//=========================================================================== +// +// start iterating a new group +// +//=========================================================================== + void FMultiBlockLinesIterator::startIteratorForGroup(int group) { offset = Displacements(basegroup, group); @@ -817,6 +851,12 @@ void FMultiBlockLinesIterator::startIteratorForGroup(int group) blockIterator.init(bbox); } +//=========================================================================== +// +// Resets the iterator +// +//=========================================================================== + void FMultiBlockLinesIterator::Reset() { continueup = continueup = true; @@ -851,8 +891,7 @@ FBlockThingsIterator::FBlockThingsIterator(int _minx, int _miny, int _maxx, int Reset(); } -FBlockThingsIterator::FBlockThingsIterator(const FBoundingBox &box) -: DynHash(0) +void FBlockThingsIterator::init(const FBoundingBox &box) { maxy = GetSafeBlockY(box.Top() - bmaporgy); miny = GetSafeBlockY(box.Bottom() - bmaporgy); @@ -994,6 +1033,108 @@ AActor *FBlockThingsIterator::Next(bool centeronly) } + +//=========================================================================== +// +// FMultiBlockThingsIterator :: FMultiBlockThingsIterator +// +// An iterator that can check multiple portal groups. +// +//=========================================================================== + +FMultiBlockThingsIterator::FMultiBlockThingsIterator(FPortalGroupArray &check, AActor *origin, fixed_t checkradius) + : checklist(check) +{ + checkpoint = origin->Pos(); + if (!check.inited) P_CollectConnectedGroups(origin->Sector->PortalGroup, checkpoint, origin->Top(), checkradius, checklist); + checkpoint.z = checkradius; + basegroup = origin->Sector->PortalGroup; + Reset(); +} + +FMultiBlockThingsIterator::FMultiBlockThingsIterator(FPortalGroupArray &check, fixed_t checkx, fixed_t checky, fixed_t checkz, fixed_t checkh, fixed_t checkradius) + : checklist(check) +{ + checkpoint.x = checkx; + checkpoint.y = checky; + checkpoint.z = checkz; + basegroup = P_PointInSector(checkx, checky)->PortalGroup; + if (!check.inited) P_CollectConnectedGroups(basegroup, checkpoint, checkz + checkh, checkradius, checklist); + checkpoint.z = checkradius; + Reset(); +} + +//=========================================================================== +// +// Gets the next line - also manages switching between portal groups +// +//=========================================================================== + +bool FMultiBlockThingsIterator::Next(FMultiBlockThingsIterator::CheckResult *item) +{ + AActor *thing = blockIterator.Next(); + if (thing != NULL) + { + item->thing = thing; + item->position = checkpoint + Displacements(basegroup, thing->Sector->PortalGroup); + item->portalflags = portalflags; + return true; + } + bool onlast = unsigned(index + 1) >= checklist.Size(); + int nextflags = onlast ? 0 : checklist[index + 1] & FPortalGroupArray::FLAT; + + if (onlast) + { + return false; + } + + index++; + startIteratorForGroup(checklist[index] & ~FPortalGroupArray::FLAT); + switch (nextflags) + { + case FPortalGroupArray::UPPER: + portalflags = FFCF_NOFLOOR; + break; + + case FPortalGroupArray::LOWER: + portalflags = FFCF_NOCEILING; + break; + + default: + portalflags = 0; + } + + return Next(item); +} + +//=========================================================================== +// +// start iterating a new group +// +//=========================================================================== + +void FMultiBlockThingsIterator::startIteratorForGroup(int group) +{ + fixedvec2 offset = Displacements(basegroup, group); + offset.x += checkpoint.x; + offset.y += checkpoint.y; + bbox.setBox(offset.x, offset.y, checkpoint.z); + blockIterator.init(bbox); +} + +//=========================================================================== +// +// Resets the iterator +// +//=========================================================================== + +void FMultiBlockThingsIterator::Reset() +{ + index = -1; + portalflags = 0; + startIteratorForGroup(basegroup); +} + //=========================================================================== // // FPathTraverse :: Intercepts diff --git a/src/p_maputl.h b/src/p_maputl.h index a939855bf..2aacf3dd1 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -224,7 +224,8 @@ public: int portalflags; }; - FMultiBlockLinesIterator(FPortalGroupArray &check, AActor *origin, fixed_t checkx = FIXED_MAX, fixed_t checky = FIXED_MAX, fixed_t checkradius = -1); + FMultiBlockLinesIterator(FPortalGroupArray &check, AActor *origin, fixed_t checkradius = -1); + FMultiBlockLinesIterator(FPortalGroupArray &check, fixed_t checkx, fixed_t checky, fixed_t checkz, fixed_t checkh, fixed_t checkradius); bool Next(CheckResult *item); void Reset(); // for stopping group traversal through portals. Only the calling code can decide whether this is needed so this needs to be set from the outside. @@ -274,14 +275,52 @@ class FBlockThingsIterator FBlockThingsIterator(); friend class FPathTraverse; + friend class FMultiBlockThingsIterator; public: FBlockThingsIterator(int minx, int miny, int maxx, int maxy); - FBlockThingsIterator(const FBoundingBox &box); + FBlockThingsIterator(const FBoundingBox &box) + { + init(box); + } + void init(const FBoundingBox &box); AActor *Next(bool centeronly = false); void Reset() { StartBlock(minx, miny); } }; +class FMultiBlockThingsIterator +{ + FPortalGroupArray &checklist; + fixedvec3 checkpoint; + short basegroup; + short portalflags; + short index; + FBlockThingsIterator blockIterator; + FBoundingBox bbox; + + void startIteratorForGroup(int group); + +public: + + struct CheckResult + { + AActor *thing; + fixedvec3 position; + int portalflags; + }; + + FMultiBlockThingsIterator(FPortalGroupArray &check, AActor *origin, fixed_t checkradius = -1); + FMultiBlockThingsIterator(FPortalGroupArray &check, fixed_t checkx, fixed_t checky, fixed_t checkz, fixed_t checkh, fixed_t checkradius); + bool Next(CheckResult *item); + void Reset(); + const FBoundingBox &Box() const + { + return bbox; + } +}; + + + class FPathTraverse { static TArray intercepts; From f8a8d8eed2aaeeeeadd2f8091fd30fccb1e04bd0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 20 Feb 2016 22:53:47 +0100 Subject: [PATCH 18/28] - fixed use of wrong position variable in P_TeleportMove's thing iterator. --- src/p_map.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 5ce9b837a..81ab1db20 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -446,7 +446,7 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra continue; fixed_t blockdist = th->radius + tmf.thing->radius; - if (abs(th->X() - cres.position.x) >= blockdist || abs(th->Y() - cres.position.y) >= blockdist) + if (abs(th->X() - cres2.position.x) >= blockdist || abs(th->Y() - cres2.position.y) >= blockdist) continue; if ((th->flags2 | tmf.thing->flags2) & MF2_THRUACTORS) From 26967bd0ee205152e4baae829f1e0a2c0ade9910 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 20 Feb 2016 23:07:37 +0100 Subject: [PATCH 19/28] - migrated P_PlayerStartStomp to FMultiThingIterator. Note: This replaces AActor::intersects with a direct calculation. Although that function could be adjusted it'd mean some redundant distance calculations which are easily avoided. --- src/p_map.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 81ab1db20..66c95d495 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -531,11 +531,14 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra void P_PlayerStartStomp(AActor *actor, bool mononly) { - AActor *th; - FBlockThingsIterator it(FBoundingBox(actor->X(), actor->Y(), actor->radius)); + FPortalGroupArray grouplist; + FMultiBlockThingsIterator mit(grouplist, actor); + FMultiBlockThingsIterator::CheckResult cres; - while ((th = it.Next())) + while ((mit.Next(&cres))) { + AActor *th = cres.thing; + if (!(th->flags & MF_SHOOTABLE)) continue; @@ -543,7 +546,8 @@ void P_PlayerStartStomp(AActor *actor, bool mononly) if (th == actor || (th->player == actor->player && th->player != NULL)) continue; - if (!th->intersects(actor)) + fixed_t blockdist = th->radius + actor->radius; + if (abs(th->X() - cres.position.x) >= blockdist || abs(th->Y() - cres.position.y) >= blockdist) continue; // only kill monsters and other players From abcc6049b9bbcd6e18998cd37268c20caac7433d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 21 Feb 2016 12:04:52 +0100 Subject: [PATCH 20/28] - made the z coordinate part of the CheckResults for the MultiBlock iterators and use these for all height checks in the iterator loops. This will later make it easier to support arbitrary portals with height displacements. --- src/basictypes.h | 6 ++++++ src/p_map.cpp | 8 ++++---- src/p_maputl.cpp | 10 +++++++++- src/p_maputl.h | 2 +- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/basictypes.h b/src/basictypes.h index ea56e9093..3159de428 100644 --- a/src/basictypes.h +++ b/src/basictypes.h @@ -112,6 +112,12 @@ struct fixedvec3 return *this; } + operator fixedvec2() + { + fixedvec2 ret = { x, y }; + return ret; + } + }; inline fixedvec2 operator +(const fixedvec2 &v1, const fixedvec2 &v2) diff --git a/src/p_map.cpp b/src/p_map.cpp index 66c95d495..a7346fa17 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -462,8 +462,8 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra { if (!(th->flags3 & thing->flags3 & MF3_DONTOVERLAP)) { - if (z > th->Top() || // overhead - z + thing->height < th->Z()) // underneath + if (z > cres.position.z + th->height || // overhead + z + thing->height < cres.position.z) // underneath continue; } } @@ -557,9 +557,9 @@ void P_PlayerStartStomp(AActor *actor, bool mononly) if (th->player != NULL && mononly) continue; - if (actor->Z() > th->Top()) + if (actor->Z() > cres.position.z + th->height) continue; // overhead - if (actor->Top() < th->Z()) + if (actor->Top() < cres.position.z) continue; // underneath P_DamageMobj(th, actor, actor, TELEFRAG_DAMAGE, NAME_Telefrag); diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 59a7b9b54..722d1a6dd 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -534,6 +534,12 @@ void AActor::SetOrigin (fixed_t ix, fixed_t iy, fixed_t iz, bool moving) P_FindFloorCeiling(this, FFCF_ONLYSPAWNPOS); } +//=========================================================================== +// +// FBlockNode - allows to link actors into multiple blocks in the blockmap +// +//=========================================================================== + FBlockNode *FBlockNode::FreeBlocks = NULL; FBlockNode *FBlockNode::Create (AActor *who, int x, int y, int group) @@ -789,7 +795,9 @@ bool FMultiBlockLinesIterator::Next(FMultiBlockLinesIterator::CheckResult *item) if (line != NULL) { item->line = line; - item->position = offset; + item->position.x = offset.x; + item->position.y = offset.y; + item->position.z = checkpoint.z; item->portalflags = portalflags; return true; } diff --git a/src/p_maputl.h b/src/p_maputl.h index 2aacf3dd1..11260bcbf 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -220,7 +220,7 @@ public: struct CheckResult { line_t *line; - fixedvec2 position; + fixedvec3 position; int portalflags; }; From 98c7fabb8975955d2390246ec2d08bcd4803d49e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 21 Feb 2016 16:56:21 +0100 Subject: [PATCH 21/28] - untested partial refactoring of P_CheckPosition. (This is just a safety commit before doing some more extensive behind-the-scenes refactoring.) Notable changes here: * use the same logic for determining whether a 3D floor is 'below' or 'above' the actor as all the other functions. * removed the broken code which tried to detect whether an actor was touching a steep slope. Better use P_LineOpening to find the correct planes and store the results. * improved detection whether the slopes on both sides of a plane are identical, using the same data as for steep slope detection. --- src/p_3dfloors.cpp | 12 +++ src/p_3dmidtex.cpp | 4 +- src/p_map.cpp | 212 ++++++++++++++++++--------------------------- src/p_maputl.cpp | 6 ++ src/p_maputl.h | 4 + src/r_defs.h | 15 ++++ 6 files changed, 125 insertions(+), 128 deletions(-) diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index 397d2be1e..08050133a 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -776,6 +776,7 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li int highestfloorterrain = -1; FTextureID lowestceilingpic; sector_t *lowestceilingsec = NULL, *highestfloorsec = NULL; + secplane_t *highestfloorplanes[2] = { NULL, NULL }; highestfloorpic.SetInvalid(); lowestceilingpic.SetInvalid(); @@ -808,6 +809,7 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li highestfloorpic = *rover->top.texture; highestfloorterrain = rover->model->GetTerrain(rover->top.isceiling); highestfloorsec = j == 0 ? linedef->frontsector : linedef->backsector; + highestfloorplanes[j] = rover->top.plane; } if(ff_top > lowestfloor[j] && ff_top <= thing->Z() + thing->MaxStepHeight) lowestfloor[j] = ff_top; } @@ -826,6 +828,16 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li open.top = lowestceiling; open.ceilingpic = lowestceilingpic; open.topsec = lowestceilingsec; + if (highestfloorplanes[0]) + { + open.frontfloorplane = *highestfloorplanes[0]; + if (open.frontfloorplane.c < 0) open.frontfloorplane.FlipVert(); + } + if (highestfloorplanes[1]) + { + open.backfloorplane = *highestfloorplanes[1]; + if (open.backfloorplane.c < 0) open.backfloorplane.FlipVert(); + } } open.lowfloor = MIN(lowestfloor[0], lowestfloor[1]); diff --git a/src/p_3dmidtex.cpp b/src/p_3dmidtex.cpp index 1c4ba7b7c..c5a205891 100644 --- a/src/p_3dmidtex.cpp +++ b/src/p_3dmidtex.cpp @@ -294,7 +294,9 @@ bool P_LineOpening_3dMidtex(AActor *thing, const line_t *linedef, FLineOpening & open.abovemidtex = true; open.floorpic = linedef->sidedef[0]->GetTexture(side_t::mid); open.floorterrain = TerrainTypes[open.floorpic]; - + open.frontfloorplane.SetAtHeight(tt, sector_t::floor); + open.backfloorplane.SetAtHeight(tt, sector_t::floor); + } // returns true if it touches the midtexture return (abs(thing->Z() - tt) <= thing->MaxStepHeight); diff --git a/src/p_map.cpp b/src/p_map.cpp index a7346fa17..287ba0eee 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -276,7 +276,7 @@ static bool PIT_FindFloorCeiling(FMultiBlockLinesIterator &mit, FMultiBlockLines void P_GetFloorCeilingZ(FCheckPosition &tmf, int flags) { - sector_t *sec = (!(flags & FFCF_SAMESECTOR) || tmf.thing->Sector == NULL)? P_PointInSector(tmf.x, tmf.y) : tmf.thing->Sector; + sector_t *sec = (!(flags & FFCF_SAMESECTOR) || tmf.thing->Sector == NULL)? P_PointInSector(tmf.x, tmf.y) : tmf.sector; F3DFloor *ffc, *fff; tmf.ceilingz = sec->NextHighestCeilingAt(tmf.thing, tmf.z + tmf.thing->height, flags, &tmf.ceilingsector, &ffc); @@ -316,6 +316,10 @@ void P_FindFloorCeiling(AActor *actor, int flags) { flags |= FFCF_3DRESTRICT; } + if (flags & FFCF_SAMESECTOR) + { + tmf.sector = actor->Sector; + } P_GetFloorCeilingZ(tmf, flags); assert(tmf.thing->Sector != NULL); @@ -759,8 +763,9 @@ int P_GetMoveFactor(const AActor *mo, int *frictionp) //========================================================================== static // killough 3/26/98: make static -bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm) +bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::CheckResult &cres, const FBoundingBox &box, FCheckPosition &tm) { + line_t *ld = cres.line; bool rail = false; if (box.Right() <= ld->bbox[BOXLEFT] @@ -802,7 +807,6 @@ bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm) bool NotBlocked = ((tm.thing->flags3 & MF3_NOBLOCKMONST) || ((i_compatflags & COMPATF_NOBLOCKFRIENDS) && (tm.thing->flags & MF_FRIENDLY))); - fixedvec3 pos = tm.thing->PosRelative(ld); if (!(Projectile) || (ld->flags & (ML_BLOCKEVERYTHING | ML_BLOCKPROJECTILE))) { if (ld->flags & ML_RAILING) @@ -821,55 +825,33 @@ bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm) } tm.thing->BlockingLine = ld; // Calculate line side based on the actor's original position, not the new one. - CheckForPushSpecial(ld, P_PointOnLineSide(pos.x, pos.y, ld), tm.thing, false); + CheckForPushSpecial(ld, P_PointOnLineSide(cres.position.x, cres.position.y, ld), tm.thing, false); return false; } } - // [RH] Steep sectors count as dropoffs (unless already in one) + fixedvec2 ref = FindRefPoint(ld, cres.position); + FLineOpening open; + + P_LineOpening(open, tm.thing, ld, ref.x, ref.y, cres.position.x, cres.position.y, cres.portalflags); + + // [RH] Steep sectors count as dropoffs, if the actor touches the boundary between a steep slope and something else if (!(tm.thing->flags & MF_DROPOFF) && !(tm.thing->flags & (MF_NOGRAVITY | MF_NOCLIP))) { - secplane_t frontplane, backplane; // Check 3D floors as well - frontplane = P_FindFloorPlane(ld->frontsector, pos.x, pos.y, tm.thing->floorz); - backplane = P_FindFloorPlane(ld->backsector, pos.x, pos.y, tm.thing->floorz); - if (frontplane.c < STEEPSLOPE || backplane.c < STEEPSLOPE) + if ((open.frontfloorplane.c < STEEPSLOPE) != (open.backfloorplane.c < STEEPSLOPE)) { - const msecnode_t *node = tm.thing->touching_sectorlist; - bool allow = false; - int count = 0; - while (node != NULL) - { - count++; - if (node->m_sector->floorplane.c < STEEPSLOPE) - { - allow = true; - break; - } - node = node->m_tnext; - } - if (!allow) - { - return false; - } + // on the boundary of a steep slope + return false; } } - fixedvec2 rpos = { tm.x, tm.y }; - fixedvec2 ref = FindRefPoint(ld, rpos); - FLineOpening open; - - P_LineOpening(open, tm.thing, ld, ref.x, ref.y, tm.x, tm.y, 0); - - // the floorplane on both sides is identical with the current one - // so don't mess around with the z-position. - if (ld->frontsector->floorplane == ld->backsector->floorplane && - ld->frontsector->floorplane == tm.thing->Sector->floorplane && - !ld->frontsector->e->XFloor.ffloors.Size() && !ld->backsector->e->XFloor.ffloors.Size() && - !open.abovemidtex) + // If the floor planes on both sides we should recalculate open.bottom at the actual position we are checking + // This is to avoid bumpy movement when crossing a linedef with the same slope on both sides. + if (open.frontfloorplane == open.backfloorplane) { - open.bottom = INT_MIN; + open.bottom = open.frontfloorplane.ZatPoint(cres.position.x, cres.position.y); } if (rail && @@ -1017,8 +999,9 @@ static bool CanAttackHurt(AActor *victim, AActor *shooter) // //========================================================================== -bool PIT_CheckThing(AActor *thing, FCheckPosition &tm) +bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::CheckResult &cres, const FBoundingBox &box, FCheckPosition &tm) { + AActor *thing = cres.thing; fixed_t topz; bool solid; int damage; @@ -1440,56 +1423,29 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo tm.x = x; tm.y = y; + tm.z = thing->Z(); - newsec = P_PointInSector(x, y); + newsec = tm.sector = P_PointInSector(x, y); tm.ceilingline = thing->BlockingLine = NULL; - // The base floor / ceiling is from the subsector that contains the point. + // Retrieve the base floor / ceiling from the target location. // Any contacted lines the step closer together will adjust them. - tm.floorz = tm.dropoffz = newsec->LowestFloorAt(x, y, &tm.floorsector); - tm.ceilingz = newsec->HighestCeilingAt(x, y, &tm.ceilingsector); - tm.floorpic = tm.floorsector->GetTexture(sector_t::floor); - tm.floorterrain = tm.floorsector->GetTerrain(sector_t::floor); - tm.ceilingpic = tm.ceilingsector->GetTexture(sector_t::ceiling); - tm.touchmidtex = false; - tm.abovemidtex = false; - - //Added by MC: Fill the tmsector. - tm.sector = newsec; - - //Check 3D floors - if (!thing->IsNoClip2() && newsec->e->XFloor.ffloors.Size()) + if (!thing->IsNoClip2()) { - F3DFloor* rover; - fixed_t delta1; - fixed_t delta2; - int thingtop = thing->Z() + (thing->height == 0 ? 1 : thing->height); - - for (unsigned i = 0; ie->XFloor.ffloors.Size(); i++) - { - rover = newsec->e->XFloor.ffloors[i]; - if (!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue; - - fixed_t ff_bottom = rover->bottom.plane->ZatPoint(x, y); - fixed_t ff_top = rover->top.plane->ZatPoint(x, y); - - delta1 = thing->Z() - (ff_bottom + ((ff_top - ff_bottom) / 2)); - delta2 = thingtop - (ff_bottom + ((ff_top - ff_bottom) / 2)); - - if (ff_top > tm.floorz && abs(delta1) < abs(delta2)) - { - tm.floorz = tm.dropoffz = ff_top; - tm.floorpic = *rover->top.texture; - tm.floorterrain = rover->model->GetTerrain(rover->top.isceiling); - } - if (ff_bottom < tm.ceilingz && abs(delta1) >= abs(delta2)) - { - tm.ceilingz = ff_bottom; - tm.ceilingpic = *rover->bottom.texture; - } - } + P_GetFloorCeilingZ(tm, FFCF_SAMESECTOR); + } + else + { + // With noclip2, we must ignore 3D floors and go right to the uppermost ceiling and lowermost floor. + tm.floorz = tm.dropoffz = newsec->LowestFloorAt(x, y, &tm.floorsector); + tm.ceilingz = newsec->HighestCeilingAt(x, y, &tm.ceilingsector); + tm.floorpic = tm.floorsector->GetTexture(sector_t::floor); + tm.floorterrain = tm.floorsector->GetTerrain(sector_t::floor); + tm.ceilingpic = tm.ceilingsector->GetTexture(sector_t::ceiling); } + tm.touchmidtex = false; + tm.abovemidtex = false; validcount++; spechit.Clear(); @@ -1507,51 +1463,52 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo tm.stepthing = NULL; FBoundingBox box(x, y, thing->radius); - { - FBlockThingsIterator it2(box); - AActor *th; - while ((th = it2.Next())) - { - if (!PIT_CheckThing(th, tm)) - { // [RH] If a thing can be stepped up on, we need to continue checking - // other things in the blocks and see if we hit something that is - // definitely blocking. Otherwise, we need to check the lines, or we - // could end up stuck inside a wall. - AActor *BlockingMobj = thing->BlockingMobj; + FPortalGroupArray pcheck; + FMultiBlockThingsIterator it2(pcheck, x, y, thing->Z(), thing->height, thing->radius); + FMultiBlockThingsIterator::CheckResult tcres; - if (BlockingMobj == NULL || (i_compatflags & COMPATF_NO_PASSMOBJ)) - { // Thing slammed into something; don't let it move now. - thing->height = realheight; - return false; - } - else if (!BlockingMobj->player && !(thing->flags & (MF_FLOAT | MF_MISSILE | MF_SKULLFLY)) && - BlockingMobj->Top() - thing->Z() <= thing->MaxStepHeight) - { - if (thingblocker == NULL || - BlockingMobj->Z() > thingblocker->Z()) - { - thingblocker = BlockingMobj; - } - thing->BlockingMobj = NULL; - } - else if (thing->player && - thing->Top() - BlockingMobj->Z() <= thing->MaxStepHeight) - { - if (thingblocker) - { // There is something to step up on. Return this thing as - // the blocker so that we don't step up. - thing->height = realheight; - return false; - } - // Nothing is blocking us, but this actor potentially could - // if there is something else to step on. - thing->BlockingMobj = NULL; - } - else - { // Definitely blocking + while ((it2.Next(&tcres))) + { + if (!PIT_CheckThing(it2, tcres, it2.Box(), tm)) + { // [RH] If a thing can be stepped up on, we need to continue checking + // other things in the blocks and see if we hit something that is + // definitely blocking. Otherwise, we need to check the lines, or we + // could end up stuck inside a wall. + AActor *BlockingMobj = thing->BlockingMobj; + + // If this blocks through a line portal with a vertical displacement, it will always completely block. There is no way to step up onto such an actor. + if (BlockingMobj == NULL || (i_compatflags & COMPATF_NO_PASSMOBJ) || tcres.zdiff != 0) + { // Thing slammed into something; don't let it move now. + thing->height = realheight; + return false; + } + else if (!BlockingMobj->player && !(thing->flags & (MF_FLOAT | MF_MISSILE | MF_SKULLFLY)) && + BlockingMobj->Top() - thing->Z() <= thing->MaxStepHeight) + { + if (thingblocker == NULL || + BlockingMobj->Z() > thingblocker->Z()) + { + thingblocker = BlockingMobj; + } + thing->BlockingMobj = NULL; + } + else if (thing->player && + thing->Top() - BlockingMobj->Z() <= thing->MaxStepHeight) + { + if (thingblocker) + { // There is something to step up on. Return this thing as + // the blocker so that we don't step up. thing->height = realheight; return false; } + // Nothing is blocking us, but this actor potentially could + // if there is something else to step on. + thing->BlockingMobj = NULL; + } + else + { // Definitely blocking + thing->height = realheight; + return false; } } } @@ -1574,7 +1531,8 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo if (actorsonly || (thing->flags & MF_NOCLIP)) return (thing->BlockingMobj = thingblocker) == NULL; - FBlockLinesIterator it(box); + FMultiBlockLinesIterator it(pcheck, thing); + FMultiBlockLinesIterator::CheckResult lcres; line_t *ld; fixed_t thingdropoffz = tm.floorz; @@ -1583,9 +1541,9 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo bool good = true; - while ((ld = it.Next())) + while (it.Next(&lcres)) { - good &= PIT_CheckLine(ld, box, tm); + good &= PIT_CheckLine(it, lcres, it.Box(), tm); } if (!good) { diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 722d1a6dd..0e82bf112 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -229,6 +229,8 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef, open.floorterrain = back->GetTerrain(sector_t::floor); open.lowfloor = ff; } + open.frontfloorplane = front->floorplane; + open.backfloorplane = back->floorplane; } else { // Dummy stuff to have some sort of opening for the 3D checks to modify @@ -240,6 +242,8 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef, open.floorterrain = -1; open.bottom = FIXED_MIN; open.lowfloor = FIXED_MAX; + open.frontfloorplane.SetAtHeight(FIXED_MIN, sector_t::floor); + open.backfloorplane.SetAtHeight(FIXED_MIN, sector_t::floor); } // Check 3D floors @@ -798,6 +802,7 @@ bool FMultiBlockLinesIterator::Next(FMultiBlockLinesIterator::CheckResult *item) item->position.x = offset.x; item->position.y = offset.y; item->position.z = checkpoint.z; + item->zdiff = 0; item->portalflags = portalflags; return true; } @@ -1085,6 +1090,7 @@ bool FMultiBlockThingsIterator::Next(FMultiBlockThingsIterator::CheckResult *ite { item->thing = thing; item->position = checkpoint + Displacements(basegroup, thing->Sector->PortalGroup); + item->zdiff = 0; item->portalflags = portalflags; return true; } diff --git a/src/p_maputl.h b/src/p_maputl.h index 11260bcbf..3027df3d4 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -99,6 +99,8 @@ struct FLineOpening sector_t *topsec; FTextureID ceilingpic; FTextureID floorpic; + secplane_t frontfloorplane; + secplane_t backfloorplane; int floorterrain; bool touchmidtex; bool abovemidtex; @@ -221,6 +223,7 @@ public: { line_t *line; fixedvec3 position; + fixed_t zdiff; int portalflags; }; @@ -306,6 +309,7 @@ public: { AActor *thing; fixedvec3 position; + fixed_t zdiff; int portalflags; }; diff --git a/src/r_defs.h b/src/r_defs.h index c4444e9f1..ab55201f9 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -345,6 +345,21 @@ struct secplane_t return -TMulScale16 (a, v->x, b, v->y, z, c); } + void SetAtHeight(fixed_t height, int ceiling) + { + a = b = 0; + if (ceiling) + { + c = ic = -FRACUNIT; + d = height; + } + else + { + c = ic = FRACUNIT; + d = -height; + } + } + bool CopyPlaneIfValid (secplane_t *dest, const secplane_t *opp) const; }; From ca2fc47fa31908a4287a839542b5b320d16c88d0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 21 Feb 2016 19:06:56 +0100 Subject: [PATCH 22/28] - refactoring of PIT_CheckThing. --- src/p_local.h | 1 + src/p_map.cpp | 107 ++++++++++++++++++++++++++------------------------ 2 files changed, 57 insertions(+), 51 deletions(-) diff --git a/src/p_local.h b/src/p_local.h index dac4dbc26..26eb72bd2 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -290,6 +290,7 @@ enum FFCF_NOPORTALS = 16, // ignore portals (considers them impassable.) FFCF_NOFLOOR = 32, FFCF_NOCEILING = 64, + FFCF_RESTRICTEDPORTAL = 128, // current values in the iterator's return are through a restricted portal type (i.e. some features are blocked.) }; void P_FindFloorCeiling (AActor *actor, int flags=0); diff --git a/src/p_map.cpp b/src/p_map.cpp index 287ba0eee..dc3ca7644 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -76,6 +76,7 @@ static FRandom pr_crunch("DoCrunch"); // keep track of special lines as they are hit, // but don't process them until the move is proven valid TArray spechit; +TArray portalhit; // Temporary holder for thing_sectorlist threads msecnode_t* sector_list = NULL; // phares 3/16/98 @@ -415,8 +416,6 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra tmf.abovemidtex = false; P_GetFloorCeilingZ(tmf, 0); - spechit.Clear(); - bool StompAlwaysFrags = ((thing->flags2 & MF2_TELESTOMP) || (level.flags & LEVEL_MONSTERSTELEFRAG) || telefrag) && !(thing->flags7 & MF7_NOTELESTOMP); // P_LineOpening requires the thing's z to be the destination z in order to work. @@ -839,7 +838,6 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec if (!(tm.thing->flags & MF_DROPOFF) && !(tm.thing->flags & (MF_NOGRAVITY | MF_NOCLIP))) { - // Check 3D floors as well if ((open.frontfloorplane.c < STEEPSLOPE) != (open.backfloorplane.c < STEEPSLOPE)) { // on the boundary of a steep slope @@ -847,7 +845,7 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec } } - // If the floor planes on both sides we should recalculate open.bottom at the actual position we are checking + // If the floor planes on both sides match we should recalculate open.bottom at the actual position we are checking // This is to avoid bumpy movement when crossing a linedef with the same slope on both sides. if (open.frontfloorplane == open.backfloorplane) { @@ -902,6 +900,10 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec { spechit.Push(ld); } + if (ld->portalindex >= 0) + { + portalhit.Push(ld); + } return true; } @@ -1013,9 +1015,8 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch if (!((thing->flags & (MF_SOLID | MF_SPECIAL | MF_SHOOTABLE)) || thing->flags6 & MF6_TOUCHY)) return true; // can't hit thing - fixedvec3 thingpos = thing->PosRelative(tm.thing); fixed_t blockdist = thing->radius + tm.thing->radius; - if (abs(thingpos.x - tm.x) >= blockdist || abs(thingpos.y - tm.y) >= blockdist) + if (abs(thing->X() - cres.position.x) >= blockdist || abs(thing->Y() - cres.position.y) >= blockdist) return true; if ((thing->flags2 | tm.thing->flags2) & MF2_THRUACTORS) @@ -1026,50 +1027,55 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch tm.thing->BlockingMobj = thing; topz = thing->Top(); - if (!(i_compatflags & COMPATF_NO_PASSMOBJ) && !(tm.thing->flags & (MF_FLOAT | MF_MISSILE | MF_SKULLFLY | MF_NOGRAVITY)) && - (thing->flags & MF_SOLID) && (thing->flags4 & MF4_ACTLIKEBRIDGE)) - { - // [RH] Let monsters walk on actors as well as floors - if ((tm.thing->flags3 & MF3_ISMONSTER) && - topz >= tm.floorz && topz <= tm.thing->Z() + tm.thing->MaxStepHeight) - { - // The commented-out if is an attempt to prevent monsters from walking off a - // thing further than they would walk off a ledge. I can't think of an easy - // way to do this, so I restrict them to only walking on bridges instead. - // Uncommenting the if here makes it almost impossible for them to walk on - // anything, bridge or otherwise. - // if (abs(thing->x - tmx) <= thing->radius && - // abs(thing->y - tmy) <= thing->radius) - { - tm.stepthing = thing; - tm.floorz = topz; - } - } - } // Both things overlap in x or y direction bool unblocking = false; - if ((tm.FromPMove || tm.thing->player != NULL) && thing->flags&MF_SOLID) + // walking on other actors and unblocking is too messy through restricted portal types so disable it. + if (!(cres.portalflags & FFCF_RESTRICTEDPORTAL)) { - // Both actors already overlap. To prevent them from remaining stuck allow the move if it - // takes them further apart or the move does not change the position (when called from P_ChangeSector.) - if (tm.x == tm.thing->X() && tm.y == tm.thing->Y()) + if (!(i_compatflags & COMPATF_NO_PASSMOBJ) && !(tm.thing->flags & (MF_FLOAT | MF_MISSILE | MF_SKULLFLY | MF_NOGRAVITY)) && + (thing->flags & MF_SOLID) && (thing->flags4 & MF4_ACTLIKEBRIDGE)) { - unblocking = true; - } - else if (abs(thingpos.x - tm.thing->X()) < (thing->radius+tm.thing->radius) && - abs(thingpos.y - tm.thing->Y()) < (thing->radius+tm.thing->radius)) - - { - fixed_t newdist = thing->AproxDistance(tm.x, tm.y, tm.thing); - fixed_t olddist = thing->AproxDistance(tm.thing); - - if (newdist > olddist) + // [RH] Let monsters walk on actors as well as floors + if (cres.zdiff != 0 && (tm.thing->flags3 & MF3_ISMONSTER) && + topz >= tm.floorz && topz <= cres.position.z + tm.thing->MaxStepHeight) { - // ... but not if they did not overlap in z-direction before but would after the move. - unblocking = !((tm.thing->Z() >= topz && tm.z < topz) || - (tm.thing->Top() <= thingpos.z && tm.thing->Top() > thingpos.z)); + // The commented-out if is an attempt to prevent monsters from walking off a + // thing further than they would walk off a ledge. I can't think of an easy + // way to do this, so I restrict them to only walking on bridges instead. + // Uncommenting the if here makes it almost impossible for them to walk on + // anything, bridge or otherwise. + // if (abs(thing->x - tmx) <= thing->radius && + // abs(thing->y - tmy) <= thing->radius) + { + tm.stepthing = thing; + tm.floorz = topz; + } + } + } + + if (((tm.FromPMove || tm.thing->player != NULL) && thing->flags&MF_SOLID)) + { + fixedvec3 oldpos = tm.thing->PosRelative(thing); + // Both actors already overlap. To prevent them from remaining stuck allow the move if it + // takes them further apart or the move does not change the position (when called from P_ChangeSector.) + if (oldpos.x == thing->X() && oldpos.y == thing->Y()) + { + unblocking = true; + } + else if (abs(thing->X() - oldpos.x) < (thing->radius + tm.thing->radius) && + abs(thing->Y() - oldpos.y) < (thing->radius + tm.thing->radius)) + + { + fixed_t newdist = thing->AproxDistance(cres.position.x, cres.position.y); + fixed_t olddist = thing->AproxDistance(oldpos.x, oldpos.y); + + if (newdist > olddist) + { + // unblock only if there's already a vertical overlap (or both actors are flagged not to overlap) + unblocking = (cres.position.z + tm.thing->height > thing->Z() && cres.position.z < topz) || (tm.thing->flags3 & thing->flags3 & MF3_DONTOVERLAP); + } } } } @@ -1087,7 +1093,7 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch { // Some things prefer not to overlap each other, if possible return unblocking; } - if ((tm.thing->Z() >= topz) || (tm.thing->Top() <= thing->Z())) + if ((cres.position.z >= topz) || (cres.position.z + tm.thing->height <= thing->Z())) return true; } } @@ -1103,7 +1109,7 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch // or different species if DONTHARMSPECIES (!(thing->flags6 & MF6_DONTHARMSPECIES) || thing->GetSpecies() != tm.thing->GetSpecies()) && // touches vertically - topz >= tm.thing->Z() && tm.thing->Z() + tm.thing->height >= thingpos.z && + topz >= cres.position.z && cres.position.z + tm.thing->height >= thing->Z() && // prevents lost souls from exploding when fired by pain elementals (thing->master != tm.thing && tm.thing->master != thing)) // Difference with MBF: MBF hardcodes the LS/PE check and lets actors of the same species @@ -1206,11 +1212,11 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch } // Check if it went over / under - if (tm.thing->Z() > thingpos.z + clipheight) + if (cres.position.z > thing->Z() + clipheight) { // Over thing return true; } - if (tm.thing->Top() < thingpos.z) + if (cres.position.z + tm.thing->height < thing->Z()) { // Under thing return true; } @@ -1361,7 +1367,7 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch // [RH] The next condition is to compensate for the extra height // that gets added by P_CheckPosition() so that you cannot pick // up things that are above your true height. - && thingpos.z < tm.thing->Top() - tm.thing->MaxStepHeight) + && thing->Z() < cres.position.z + tm.thing->height - tm.thing->MaxStepHeight) { // Can be picked up by tmthing P_TouchSpecialThing(thing, tm.thing); // can remove thing } @@ -1476,8 +1482,8 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo // could end up stuck inside a wall. AActor *BlockingMobj = thing->BlockingMobj; - // If this blocks through a line portal with a vertical displacement, it will always completely block. There is no way to step up onto such an actor. - if (BlockingMobj == NULL || (i_compatflags & COMPATF_NO_PASSMOBJ) || tcres.zdiff != 0) + // If this blocks through a restricted line portal, it will always completely block. + if (BlockingMobj == NULL || (i_compatflags & COMPATF_NO_PASSMOBJ) || (tcres.portalflags & FFCF_RESTRICTEDPORTAL)) { // Thing slammed into something; don't let it move now. thing->height = realheight; return false; @@ -1533,7 +1539,6 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo FMultiBlockLinesIterator it(pcheck, thing); FMultiBlockLinesIterator::CheckResult lcres; - line_t *ld; fixed_t thingdropoffz = tm.floorz; //bool onthing = (thingdropoffz != tmdropoffz); From 730145d1fc429cea73824e0606ba768921b1a43f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 21 Feb 2016 23:08:51 +0100 Subject: [PATCH 23/28] - more transition to FMultiBlock* iterators: * removed all code for dealing with z-displacing portals in the iterator loops. This would cause too many problems so I decided to scrap any provisions for allowing interactive portals with z-displacement. They will remain restricted to pure teleporter portals. * changed spechit to carry a position along with the special line. If something is activated through an interactive portal this is needed to calculate movement. * pass the abovementioned position to CheckForPushSpecial. * collect touched portal lines in a second array analogous to spechit. * use FMultiBlockThingsIterator in P_TestMobjZ. --- src/b_move.cpp | 4 ++- src/p_enemy.cpp | 10 +++--- src/p_local.h | 9 ++++- src/p_map.cpp | 85 ++++++++++++++++++++++++++---------------------- src/p_maputl.cpp | 6 ++-- src/p_maputl.h | 6 ++-- 6 files changed, 67 insertions(+), 53 deletions(-) diff --git a/src/b_move.cpp b/src/b_move.cpp index 1fcf207ed..dbecd2a48 100644 --- a/src/b_move.cpp +++ b/src/b_move.cpp @@ -83,10 +83,12 @@ bool DBot::Move (ticcmd_t *cmd) player->mo->movedir = DI_NODIR; good = 0; + spechit_t spechit1; line_t *ld; - while (spechit.Pop (ld)) + while (spechit.Pop (spechit1)) { + ld = spechit1.line; bool tryit = true; if (ld->special == Door_LockedRaise && !P_CheckKeys (player->mo, ld->args[3], false)) diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 47ac85d1f..2049d5f22 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -612,18 +612,18 @@ bool P_Move (AActor *actor) // Do NOT simply return false 1/4th of the time (causes monsters to // back out when they shouldn't, and creates secondary stickiness). - line_t *ld; + spechit_t spec; int good = 0; if (!(actor->flags6 & MF6_NOTRIGGER)) { - while (spechit.Pop (ld)) + while (spechit.Pop (spec)) { // [RH] let monsters push lines, as well as use them - if (((actor->flags4 & MF4_CANUSEWALLS) && P_ActivateLine (ld, actor, 0, SPAC_Use)) || - ((actor->flags2 & MF2_PUSHWALL) && P_ActivateLine (ld, actor, 0, SPAC_Push))) + if (((actor->flags4 & MF4_CANUSEWALLS) && P_ActivateLine (spec.line, actor, 0, SPAC_Use)) || + ((actor->flags2 & MF2_PUSHWALL) && P_ActivateLine (spec.line, actor, 0, SPAC_Push))) { - good |= ld == actor->BlockingLine ? 1 : 2; + good |= spec.line == actor->BlockingLine ? 1 : 2; } } } diff --git a/src/p_local.h b/src/p_local.h index 26eb72bd2..35dbb8b22 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -240,7 +240,14 @@ AActor *P_RoughMonsterSearch (AActor *mo, int distance, bool onlyseekable=false) // if within "tmfloorz - tmceilingz". extern msecnode_t *sector_list; // phares 3/16/98 -extern TArray spechit; +struct spechit_t +{ + line_t *line; + fixedvec2 refpos; +}; + +extern TArray spechit; +extern TArray portalhit; bool P_TestMobjLocation (AActor *mobj); diff --git a/src/p_map.cpp b/src/p_map.cpp index dc3ca7644..70043d815 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -63,7 +63,7 @@ CVAR(Bool, cl_bloodsplats, true, CVAR_ARCHIVE) CVAR(Int, sv_smartaim, 0, CVAR_ARCHIVE | CVAR_SERVERINFO) CVAR(Bool, cl_doautoaim, false, CVAR_ARCHIVE) -static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, bool windowcheck); +static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, fixedvec2 * posforwindowcheck = NULL); static void SpawnShootDecal(AActor *t1, const FTraceResults &trace); static void SpawnDeepSplash(AActor *t1, const FTraceResults &trace, AActor *puff, fixed_t vx, fixed_t vy, fixed_t vz, fixed_t shootz, bool ffloor = false); @@ -75,8 +75,8 @@ static FRandom pr_crunch("DoCrunch"); // keep track of special lines as they are hit, // but don't process them until the move is proven valid -TArray spechit; -TArray portalhit; +TArray spechit; +TArray portalhit; // Temporary holder for thing_sectorlist threads msecnode_t* sector_list = NULL; // phares 3/16/98 @@ -465,8 +465,8 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra { if (!(th->flags3 & thing->flags3 & MF3_DONTOVERLAP)) { - if (z > cres.position.z + th->height || // overhead - z + thing->height < cres.position.z) // underneath + if (z > th->Top() || // overhead + z + thing->height < th->Z()) // underneath continue; } } @@ -560,9 +560,9 @@ void P_PlayerStartStomp(AActor *actor, bool mononly) if (th->player != NULL && mononly) continue; - if (actor->Z() > cres.position.z + th->height) + if (actor->Z() > th->Top()) continue; // overhead - if (actor->Top() < cres.position.z) + if (actor->Top() < th->Z()) continue; // underneath P_DamageMobj(th, actor, actor, TELEFRAG_DAMAGE, NAME_Telefrag); @@ -793,7 +793,7 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec P_DamageMobj(tm.thing, NULL, NULL, tm.thing->Mass >> 5, NAME_Melee); } tm.thing->BlockingLine = ld; - CheckForPushSpecial(ld, 0, tm.thing, false); + CheckForPushSpecial(ld, 0, tm.thing); return false; } @@ -824,7 +824,7 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec } tm.thing->BlockingLine = ld; // Calculate line side based on the actor's original position, not the new one. - CheckForPushSpecial(ld, P_PointOnLineSide(cres.position.x, cres.position.y, ld), tm.thing, false); + CheckForPushSpecial(ld, P_PointOnLineSide(cres.position.x, cres.position.y, ld), tm.thing); return false; } } @@ -896,13 +896,18 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec tm.dropoffz = open.lowfloor; // if contacted a special line, add it to the list + spechit_t spec; if (ld->special) { - spechit.Push(ld); + spec.line = ld; + spec.refpos = cres.position; + spechit.Push(spec); } if (ld->portalindex >= 0) { - portalhit.Push(ld); + spec.line = ld; + spec.refpos = cres.position; + portalhit.Push(spec); } return true; @@ -1038,8 +1043,8 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch (thing->flags & MF_SOLID) && (thing->flags4 & MF4_ACTLIKEBRIDGE)) { // [RH] Let monsters walk on actors as well as floors - if (cres.zdiff != 0 && (tm.thing->flags3 & MF3_ISMONSTER) && - topz >= tm.floorz && topz <= cres.position.z + tm.thing->MaxStepHeight) + if ((tm.thing->flags3 & MF3_ISMONSTER) && + topz >= tm.floorz && topz <= tm.thing->Z() + tm.thing->MaxStepHeight) { // The commented-out if is an attempt to prevent monsters from walking off a // thing further than they would walk off a ledge. I can't think of an easy @@ -1074,7 +1079,7 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch if (newdist > olddist) { // unblock only if there's already a vertical overlap (or both actors are flagged not to overlap) - unblocking = (cres.position.z + tm.thing->height > thing->Z() && cres.position.z < topz) || (tm.thing->flags3 & thing->flags3 & MF3_DONTOVERLAP); + unblocking = (tm.thing->Top() > thing->Z() && tm.thing->Z() < topz) || (tm.thing->flags3 & thing->flags3 & MF3_DONTOVERLAP); } } } @@ -1093,7 +1098,7 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch { // Some things prefer not to overlap each other, if possible return unblocking; } - if ((cres.position.z >= topz) || (cres.position.z + tm.thing->height <= thing->Z())) + if ((tm.thing->Z() >= topz) || (tm.thing->Top() <= thing->Z())) return true; } } @@ -1109,7 +1114,7 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch // or different species if DONTHARMSPECIES (!(thing->flags6 & MF6_DONTHARMSPECIES) || thing->GetSpecies() != tm.thing->GetSpecies()) && // touches vertically - topz >= cres.position.z && cres.position.z + tm.thing->height >= thing->Z() && + topz >= tm.thing->Z() && tm.thing->Top() >= thing->Z() && // prevents lost souls from exploding when fired by pain elementals (thing->master != tm.thing && tm.thing->master != thing)) // Difference with MBF: MBF hardcodes the LS/PE check and lets actors of the same species @@ -1212,11 +1217,11 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch } // Check if it went over / under - if (cres.position.z > thing->Z() + clipheight) + if (tm.thing->Z() > thing->Z() + clipheight) { // Over thing return true; } - if (cres.position.z + tm.thing->height < thing->Z()) + if (tm.thing->Top() < thing->Z()) { // Under thing return true; } @@ -1367,7 +1372,7 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch // [RH] The next condition is to compensate for the extra height // that gets added by P_CheckPosition() so that you cannot pick // up things that are above your true height. - && thing->Z() < cres.position.z + tm.thing->height - tm.thing->MaxStepHeight) + && thing->Z() < tm.thing->Top() - tm.thing->MaxStepHeight) { // Can be picked up by tmthing P_TouchSpecialThing(thing, tm.thing); // can remove thing } @@ -1641,12 +1646,16 @@ bool P_TestMobjZ(AActor *actor, bool quick, AActor **pOnmobj) return true; } - FBlockThingsIterator it(FBoundingBox(actor->X(), actor->Y(), actor->radius)); - AActor *thing; + FPortalGroupArray check; + FMultiBlockThingsIterator it(check, actor, -1, true); + FMultiBlockThingsIterator::CheckResult cres; - while ((thing = it.Next())) + while (it.Next(&cres)) { - if (!thing->intersects(actor)) + AActor *thing = cres.thing; + + fixed_t blockdist = thing->radius + actor->radius; + if (abs(thing->X() - cres.position.x) >= blockdist || abs(thing->Y() - cres.position.y) >= blockdist) { continue; } @@ -1753,18 +1762,18 @@ void P_FakeZMovement(AActor *mo) // //=========================================================================== -static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, bool windowcheck) +static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, fixedvec2 *posforwindowcheck) { if (line->special && !(mobj->flags6 & MF6_NOTRIGGER)) { - if (windowcheck && !(ib_compatflags & BCOMPATF_NOWINDOWCHECK) && line->backsector != NULL) + if (posforwindowcheck && !(ib_compatflags & BCOMPATF_NOWINDOWCHECK) && line->backsector != NULL) { // Make sure this line actually blocks us and is not a window // or similar construct we are standing inside of. fixedvec3 pos = mobj->PosRelative(line); - fixed_t fzt = line->frontsector->ceilingplane.ZatPoint(pos); - fixed_t fzb = line->frontsector->floorplane.ZatPoint(pos); - fixed_t bzt = line->backsector->ceilingplane.ZatPoint(pos); - fixed_t bzb = line->backsector->floorplane.ZatPoint(pos); + fixed_t fzt = line->frontsector->ceilingplane.ZatPoint(*posforwindowcheck); + fixed_t fzb = line->frontsector->floorplane.ZatPoint(*posforwindowcheck); + fixed_t bzt = line->backsector->ceilingplane.ZatPoint(*posforwindowcheck); + fixed_t bzb = line->backsector->floorplane.ZatPoint(*posforwindowcheck); if (fzt >= mobj->Top() && bzt >= mobj->Top() && fzb <= mobj->Z() && bzb <= mobj->Z()) { @@ -1775,8 +1784,8 @@ static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, bool windo if (!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue; - fixed_t ff_bottom = rover->bottom.plane->ZatPoint(pos); - fixed_t ff_top = rover->top.plane->ZatPoint(pos); + fixed_t ff_bottom = rover->bottom.plane->ZatPoint(*posforwindowcheck); + fixed_t ff_top = rover->top.plane->ZatPoint(*posforwindowcheck); if (ff_bottom < mobj->Top() && ff_top > mobj->Z()) { @@ -2081,12 +2090,13 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, // if any special lines were hit, do the effect if (!(thing->flags & (MF_TELEPORT | MF_NOCLIP))) { - while (spechit.Pop(ld)) + spechit_t spec; + while (spechit.Pop(spec)) { - fixedvec3 thingpos = thing->PosRelative(ld); + line_t *ld = spec.line; fixedvec3 oldrelpos = PosRelative(oldpos, ld, oldsector); // see if the line was crossed - side = P_PointOnLineSide(thingpos.x, thingpos.y, ld); + side = P_PointOnLineSide(spec.refpos.x, spec.refpos.y, ld); oldside = P_PointOnLineSide(oldrelpos.x, oldrelpos.y, ld); if (side != oldside && ld->special && !(thing->flags6 & MF6_NOTRIGGER)) { @@ -2185,10 +2195,9 @@ pushline: while (numSpecHitTemp > 0) { // see which lines were pushed - ld = spechit[--numSpecHitTemp]; - fixedvec3 pos = thing->PosRelative(ld); - side = P_PointOnLineSide(pos.x, pos.y, ld); - CheckForPushSpecial(ld, side, thing, true); + spechit_t &spec = spechit[--numSpecHitTemp]; + side = P_PointOnLineSide(spec.refpos.x, spec.refpos.y, spec.line); + CheckForPushSpecial(spec.line, side, thing, &spec.refpos); } } return false; diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 0e82bf112..60d94e4b4 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -802,7 +802,6 @@ bool FMultiBlockLinesIterator::Next(FMultiBlockLinesIterator::CheckResult *item) item->position.x = offset.x; item->position.y = offset.y; item->position.z = checkpoint.z; - item->zdiff = 0; item->portalflags = portalflags; return true; } @@ -1055,7 +1054,7 @@ AActor *FBlockThingsIterator::Next(bool centeronly) // //=========================================================================== -FMultiBlockThingsIterator::FMultiBlockThingsIterator(FPortalGroupArray &check, AActor *origin, fixed_t checkradius) +FMultiBlockThingsIterator::FMultiBlockThingsIterator(FPortalGroupArray &check, AActor *origin, fixed_t checkradius, bool ignorerestricted) : checklist(check) { checkpoint = origin->Pos(); @@ -1065,7 +1064,7 @@ FMultiBlockThingsIterator::FMultiBlockThingsIterator(FPortalGroupArray &check, A Reset(); } -FMultiBlockThingsIterator::FMultiBlockThingsIterator(FPortalGroupArray &check, fixed_t checkx, fixed_t checky, fixed_t checkz, fixed_t checkh, fixed_t checkradius) +FMultiBlockThingsIterator::FMultiBlockThingsIterator(FPortalGroupArray &check, fixed_t checkx, fixed_t checky, fixed_t checkz, fixed_t checkh, fixed_t checkradius, bool ignorerestricted) : checklist(check) { checkpoint.x = checkx; @@ -1090,7 +1089,6 @@ bool FMultiBlockThingsIterator::Next(FMultiBlockThingsIterator::CheckResult *ite { item->thing = thing; item->position = checkpoint + Displacements(basegroup, thing->Sector->PortalGroup); - item->zdiff = 0; item->portalflags = portalflags; return true; } diff --git a/src/p_maputl.h b/src/p_maputl.h index 3027df3d4..452f99b3d 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -223,7 +223,6 @@ public: { line_t *line; fixedvec3 position; - fixed_t zdiff; int portalflags; }; @@ -309,12 +308,11 @@ public: { AActor *thing; fixedvec3 position; - fixed_t zdiff; int portalflags; }; - FMultiBlockThingsIterator(FPortalGroupArray &check, AActor *origin, fixed_t checkradius = -1); - FMultiBlockThingsIterator(FPortalGroupArray &check, fixed_t checkx, fixed_t checky, fixed_t checkz, fixed_t checkh, fixed_t checkradius); + FMultiBlockThingsIterator(FPortalGroupArray &check, AActor *origin, fixed_t checkradius = -1, bool ignorerestricted = false); + FMultiBlockThingsIterator(FPortalGroupArray &check, fixed_t checkx, fixed_t checky, fixed_t checkz, fixed_t checkh, fixed_t checkradius, bool ignorerestricted = false); bool Next(CheckResult *item); void Reset(); const FBoundingBox &Box() const From 31cf712db3dc2bc563702bf155b8d8467418bf6f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 22 Feb 2016 12:03:03 +0100 Subject: [PATCH 24/28] - replaced R_PointToAngle2 in blood splatter functions. --- src/g_doom/a_painelemental.cpp | 2 +- src/p_mobj.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/g_doom/a_painelemental.cpp b/src/g_doom/a_painelemental.cpp index b73af5e1d..1f88fa033 100644 --- a/src/g_doom/a_painelemental.cpp +++ b/src/g_doom/a_painelemental.cpp @@ -111,7 +111,7 @@ void A_PainShootSkull (AActor *self, angle_t angle, PClassActor *spawntype, int if (!inportal) break; // recalculate position and redo the check on the other side of the portal - pos = self->Vec3Offset(dist.x, dist.y, 8 * FRACUNIT, false); + pos = self->Vec3Offset(dist.x, dist.y, 8 * FRACUNIT); src.x = pos.x - dist.x; src.y = pos.y - dist.y; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 0f941699f..7228ffbff 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -5358,7 +5358,7 @@ void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator) } if (bloodtype >= 1) { - P_DrawSplash2 (40, x, y, z, R_PointToAngle2 (x, y, originator->X(), originator->Y()), 2, bloodcolor); + P_DrawSplash2 (40, x, y, z, 0u - originator->AngleTo(x, y), 2, bloodcolor); } } @@ -5398,7 +5398,7 @@ void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator) } if (bloodtype >= 1) { - P_DrawSplash2 (100, x, y, z, R_PointToAngle2 (0, 0, originator->X() - x, originator->Y() - y), 2, bloodcolor); + P_DrawSplash2 (100, x, y, z, 0u - originator->AngleTo(x, y), 2, bloodcolor); } } From 89ca14a587b0ed95f19718e40a56f3cece3ecd59 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Mon, 22 Feb 2016 14:24:34 +0200 Subject: [PATCH 25/28] Fixed memory leak caused by return statement parsing --- src/thingdef/thingdef_exp.h | 1 + src/thingdef/thingdef_expression.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 3221debb8..0802c08f8 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -900,6 +900,7 @@ class FxReturnStatement : public FxExpression public: FxReturnStatement(FxVMFunctionCall *call, const FScriptPosition &pos); + ~FxReturnStatement(); FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); VMFunction *GetDirectFunction(); diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 714cb6c3e..f9ab32b73 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -3525,6 +3525,11 @@ FxReturnStatement::FxReturnStatement(FxVMFunctionCall *call, const FScriptPositi { } +FxReturnStatement::~FxReturnStatement() +{ + SAFE_DELETE(Call); +} + FxExpression *FxReturnStatement::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); From ed2b107bc9f4c8710fd1eab7ebe2406128c54173 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 22 Feb 2016 13:31:15 +0100 Subject: [PATCH 26/28] - fixed: P_LineOpening_XFloors set some floor-related info in the ceiling case so that it never reached the point where it is needed. - fixed: FMultiBlockLinesIterator/FMultiBlockThingsIterator need to treat radius=-1 as 'use default from actor.' --- src/p_3dfloors.cpp | 14 +++++++------- src/p_maputl.cpp | 5 ++--- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index 08050133a..cec3b1c50 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -821,13 +821,6 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li open.floorpic = highestfloorpic; open.floorterrain = highestfloorterrain; open.bottomsec = highestfloorsec; - } - - if(lowestceiling < open.top) - { - open.top = lowestceiling; - open.ceilingpic = lowestceilingpic; - open.topsec = lowestceilingsec; if (highestfloorplanes[0]) { open.frontfloorplane = *highestfloorplanes[0]; @@ -840,6 +833,13 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li } } + if(lowestceiling < open.top) + { + open.top = lowestceiling; + open.ceilingpic = lowestceilingpic; + open.topsec = lowestceilingsec; + } + open.lowfloor = MIN(lowestfloor[0], lowestfloor[1]); } } diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 60d94e4b4..1f32d6faa 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -726,7 +726,7 @@ FMultiBlockLinesIterator::FMultiBlockLinesIterator(FPortalGroupArray &check, AAc { checkpoint = origin->Pos(); if (!check.inited) P_CollectConnectedGroups(origin->Sector->PortalGroup, checkpoint, origin->Top(), checkradius, checklist); - checkpoint.z = checkradius; + checkpoint.z = checkradius == -1? origin->radius : checkradius; basegroup = origin->Sector->PortalGroup; Reset(); } @@ -801,7 +801,6 @@ bool FMultiBlockLinesIterator::Next(FMultiBlockLinesIterator::CheckResult *item) item->line = line; item->position.x = offset.x; item->position.y = offset.y; - item->position.z = checkpoint.z; item->portalflags = portalflags; return true; } @@ -1059,7 +1058,7 @@ FMultiBlockThingsIterator::FMultiBlockThingsIterator(FPortalGroupArray &check, A { checkpoint = origin->Pos(); if (!check.inited) P_CollectConnectedGroups(origin->Sector->PortalGroup, checkpoint, origin->Top(), checkradius, checklist); - checkpoint.z = checkradius; + checkpoint.z = checkradius == -1? origin->radius : checkradius; basegroup = origin->Sector->PortalGroup; Reset(); } From 4b0af5967e13ff56a88c45c846f76146f72e2b2d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 22 Feb 2016 14:47:08 +0100 Subject: [PATCH 27/28] - use proper constructor for FMultiBlockLinesIterator in P_CheckPosition. --- src/p_map.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 70043d815..77e2003c5 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -1542,7 +1542,7 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo if (actorsonly || (thing->flags & MF_NOCLIP)) return (thing->BlockingMobj = thingblocker) == NULL; - FMultiBlockLinesIterator it(pcheck, thing); + FMultiBlockLinesIterator it(pcheck, x, y, thing->Z(), thing->height, thing->radius); FMultiBlockLinesIterator::CheckResult lcres; fixed_t thingdropoffz = tm.floorz; @@ -1835,7 +1835,6 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, fixed_t oldz; int side; int oldside; - line_t* ld; sector_t* oldsec = thing->Sector; // [RH] for sector actions sector_t* newsec; From 62f6a5e4bfb53c66bbc4d82f27d3becf081d1647 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 22 Feb 2016 15:48:07 +0100 Subject: [PATCH 28/28] - fixed: GetFloorCeilingZ used the actor's actual position, not the tmf.x, tmf.y for which information is supposed to be retrieved. --- src/p_map.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 77e2003c5..6f118c1f3 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -280,8 +280,8 @@ void P_GetFloorCeilingZ(FCheckPosition &tmf, int flags) sector_t *sec = (!(flags & FFCF_SAMESECTOR) || tmf.thing->Sector == NULL)? P_PointInSector(tmf.x, tmf.y) : tmf.sector; F3DFloor *ffc, *fff; - tmf.ceilingz = sec->NextHighestCeilingAt(tmf.thing, tmf.z + tmf.thing->height, flags, &tmf.ceilingsector, &ffc); - tmf.floorz = tmf.dropoffz = sec->NextLowestFloorAt(tmf.thing, tmf.z, flags, &tmf.floorsector, &fff); + tmf.ceilingz = sec->NextHighestCeilingAt(tmf.x, tmf.y, tmf.z + tmf.thing->height, flags, &tmf.ceilingsector, &ffc); + tmf.floorz = tmf.dropoffz = sec->NextLowestFloorAt(tmf.x, tmf.y, tmf.z, flags, tmf.thing->MaxStepHeight, &tmf.floorsector, &fff); if (fff) {