From eafd2519b4285396a4b0c0787ddd6526bc1793c1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 25 Feb 2016 16:50:03 +0100 Subject: [PATCH] - fixed a few incorrect uses of AngleTo function. - added portal offsetting to all AproxDistance, AngleTo and Vec*To members of AActor. - optimized displacement retrieval so that the most common case with no offset retrieves a constant null-vector which can be optimized away fully by the compiler. - early out in P_GetOffsetPosition if there's no portal lines nearby, so that the common case can skip the traverser completely even on maps with line portals. --- src/actor.h | 55 ++++++++++++++++--------------- src/g_hexen/a_korax.cpp | 4 +-- src/p_maputl.cpp | 6 ++-- src/p_sectors.cpp | 24 +++++++------- src/p_things.cpp | 6 ++-- src/portal.cpp | 27 +++++++++++---- src/portal.h | 18 +++++++--- src/r_defs.h | 18 +++++----- src/r_utility.cpp | 2 +- src/thingdef/thingdef_codeptr.cpp | 2 +- 10 files changed, 92 insertions(+), 70 deletions(-) diff --git a/src/actor.h b/src/actor.h index 8492c81a30..b9bc2d268a 100644 --- a/src/actor.h +++ b/src/actor.h @@ -818,22 +818,28 @@ public: return ( abs(X() - other->X()) < blockdist && abs(Y() - other->Y()) < blockdist); } - // 'absolute' is reserved for a linked portal implementation which needs - // to distinguish between portal-aware and portal-unaware distance calculation. - fixed_t AproxDistance(AActor *other, bool absolute = false) - { - return P_AproxDistance(X() - other->X(), Y() - other->Y()); - } - - // same with 'ref' here. - fixed_t AproxDistance(fixed_t otherx, fixed_t othery, AActor *ref = NULL) + fixed_t AproxDistance(fixed_t otherx, fixed_t othery) { return P_AproxDistance(X() - otherx, Y() - othery); } + fixed_t AngleTo(fixed_t otherx, fixed_t othery) + { + return R_PointToAngle2(X(), Y(), otherx, othery); + } + + // 'absolute' is reserved for a linked portal implementation which needs + // to distinguish between portal-aware and portal-unaware distance calculation. + fixed_t AproxDistance(AActor *other, bool absolute = false) + { + fixedvec3 otherpos = absolute ? other->Pos() : other->PosRelative(this); + return P_AproxDistance(X() - otherpos.x, Y() - otherpos.y); + } + fixed_t AproxDistance(AActor *other, fixed_t xadd, fixed_t yadd, bool absolute = false) { - return P_AproxDistance(X() - other->X() + xadd, Y() - other->Y() + yadd); + fixedvec3 otherpos = absolute ? other->Pos() : other->PosRelative(this); + return P_AproxDistance(X() - otherpos.x + xadd, Y() - otherpos.y + yadd); } fixed_t AproxDistance3D(AActor *other, bool absolute = false) @@ -844,18 +850,21 @@ public: // more precise, but slower version, being used in a few places fixed_t Distance2D(AActor *other, bool absolute = false) { - return xs_RoundToInt(TVector2(X() - other->X(), Y() - other->Y()).Length()); + fixedvec3 otherpos = absolute ? other->Pos() : other->PosRelative(this); + return xs_RoundToInt(TVector2(X() - otherpos.x, Y() - otherpos.y).Length()); } // a full 3D version of the above fixed_t Distance3D(AActor *other, bool absolute = false) { - return xs_RoundToInt(TVector3(X() - other->X(), Y() - other->Y(), Z() - other->Z()).Length()); + fixedvec3 otherpos = absolute ? other->Pos() : other->PosRelative(this); + return xs_RoundToInt(TVector3(X() - otherpos.x, Y() - otherpos.y, Z() - otherpos.z).Length()); } - angle_t AngleTo(AActor *other, bool absolute = false) const + angle_t AngleTo(AActor *other, bool absolute = false) { - return R_PointToAngle2(X(), Y(), other->X(), other->Y()); + fixedvec3 otherpos = absolute ? other->Pos() : other->PosRelative(this); + return R_PointToAngle2(X(), Y(), otherpos.x, otherpos.y); } angle_t AngleTo(AActor *other, fixed_t oxofs, fixed_t oyofs, bool absolute = false) const @@ -863,25 +872,17 @@ public: return R_PointToAngle2(X(), Y(), other->X() + oxofs, other->Y() + oyofs); } - fixed_t AngleTo(fixed_t otherx, fixed_t othery, AActor *ref = NULL) - { - return R_PointToAngle2(X(), Y(), otherx, othery); - } - - fixed_t AngleXYTo(fixed_t myx, fixed_t myy, AActor *other, bool absolute = false) - { - return R_PointToAngle2(myx, myy, other->X(), other->Y()); - } - fixedvec2 Vec2To(AActor *other) const { - fixedvec2 ret = { other->X() - X(), other->Y() - Y() }; + fixedvec3 otherpos = other->PosRelative(this); + fixedvec2 ret = { otherpos.x - X(), otherpos.y - Y() }; return ret; } fixedvec3 Vec3To(AActor *other) const { - fixedvec3 ret = { other->X() - X(), other->Y() - Y(), other->Z() - Z() }; + fixedvec3 otherpos = other->PosRelative(this); + fixedvec3 ret = { otherpos.x - X(), otherpos.y - Y(), otherpos.z - Z() }; return ret; } @@ -1190,7 +1191,7 @@ public: return __pos; } - fixedvec3 PosRelative(AActor *other) const; + fixedvec3 PosRelative(const AActor *other) const; fixedvec3 PosRelative(sector_t *sec) const; fixedvec3 PosRelative(line_t *line) const; diff --git a/src/g_hexen/a_korax.cpp b/src/g_hexen/a_korax.cpp index b0e57b618e..c68fce87b4 100644 --- a/src/g_hexen/a_korax.cpp +++ b/src/g_hexen/a_korax.cpp @@ -513,7 +513,7 @@ AActor *P_SpawnKoraxMissile (fixed_t x, fixed_t y, fixed_t z, z -= source->floorclip; th = Spawn (type, x, y, z, ALLOW_REPLACE); th->target = source; // Originator - an = source->AngleXYTo(x, y, dest); + an = th->AngleTo(dest); if (dest->flags & MF_SHADOW) { // Invisible target an += pr_kmissile.Random2()<<21; @@ -522,7 +522,7 @@ AActor *P_SpawnKoraxMissile (fixed_t x, fixed_t y, fixed_t z, an >>= ANGLETOFINESHIFT; th->velx = FixedMul (th->Speed, finecosine[an]); th->vely = FixedMul (th->Speed, finesine[an]); - dist = dest->AproxDistance (x, y, source) / th->Speed; + dist = dest->AproxDistance (th) / th->Speed; if (dist < 1) { dist = 1; diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index eee5167ce8..67c2303e79 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -856,7 +856,7 @@ bool FMultiBlockLinesIterator::Next(FMultiBlockLinesIterator::CheckResult *item) void FMultiBlockLinesIterator::startIteratorForGroup(int group) { - offset = Displacements(basegroup, group); + offset = Displacements.getOffset(basegroup, group); offset.x += checkpoint.x; offset.y += checkpoint.y; bbox.setBox(offset.x, offset.y, checkpoint.z); @@ -1088,7 +1088,7 @@ bool FMultiBlockThingsIterator::Next(FMultiBlockThingsIterator::CheckResult *ite if (thing != NULL) { item->thing = thing; - item->position = checkpoint + Displacements(basegroup, thing->Sector->PortalGroup); + item->position = checkpoint + Displacements.getOffset(basegroup, thing->Sector->PortalGroup); item->portalflags = portalflags; return true; } @@ -1127,7 +1127,7 @@ bool FMultiBlockThingsIterator::Next(FMultiBlockThingsIterator::CheckResult *ite void FMultiBlockThingsIterator::startIteratorForGroup(int group) { - fixedvec2 offset = Displacements(basegroup, group); + fixedvec2 offset = Displacements.getOffset(basegroup, group); offset.x += checkpoint.x; offset.y += checkpoint.y; bbox.setBox(offset.x, offset.y, checkpoint.z); diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 756495ac81..8c21ff5fff 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -897,9 +897,9 @@ fixed_t sector_t::HighestCeilingAt(fixed_t x, fixed_t y, sector_t **resultsec) // 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; + fixedvec2 pos = check->CeilingDisplacement(); + x += pos.x; + y += pos.y; planeheight = check->SkyBoxes[ceiling]->threshold; check = P_PointInSector(x, y); } @@ -921,9 +921,9 @@ fixed_t sector_t::LowestFloorAt(fixed_t x, fixed_t y, sector_t **resultsec) // 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; + fixedvec2 pos = check->FloorDisplacement(); + x += pos.x; + y += pos.y; planeheight = check->SkyBoxes[floor]->threshold; check = P_PointInSector(x, y); } @@ -960,9 +960,9 @@ fixed_t sector_t::NextHighestCeilingAt(fixed_t x, fixed_t y, fixed_t z, int flag } else { - FDisplacement &disp = sec->CeilingDisplacement(); - x += disp.pos.x; - y += disp.pos.y; + fixedvec2 pos = sec->CeilingDisplacement(); + x += pos.x; + y += pos.y; planeheight = sec->SkyBoxes[ceiling]->threshold; sec = P_PointInSector(x, y); } @@ -1003,9 +1003,9 @@ fixed_t sector_t::NextLowestFloorAt(fixed_t x, fixed_t y, fixed_t z, int flags, } else { - FDisplacement &disp = sec->FloorDisplacement(); - x += disp.pos.x; - y += disp.pos.y; + fixedvec2 pos = sec->FloorDisplacement(); + x += pos.x; + y += pos.y; planeheight = sec->SkyBoxes[floor]->threshold; sec = P_PointInSector(x, y); } diff --git a/src/p_things.cpp b/src/p_things.cpp index 357fdcef6c..82fe0d5a24 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -786,7 +786,7 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, if (flags & WARPF_WARPINTERPOLATION) { // This just translates the movement but doesn't change the vector - fixedvec3 displacedold = old + Displacements(oldpgroup, caller->Sector->PortalGroup); + fixedvec3 displacedold = old + Displacements.getOffset(oldpgroup, caller->Sector->PortalGroup); caller->PrevX += caller->X() - displacedold.x; caller->PrevY += caller->Y() - displacedold.y; caller->PrevZ += caller->Z() - displacedold.z; @@ -795,8 +795,8 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, else if (flags & WARPF_COPYINTERPOLATION) { // Map both positions of the reference actor to the current portal group - fixedvec3 displacedold = old + Displacements(reference->PrevPortalGroup, caller->Sector->PortalGroup); - fixedvec3 displacedref = old + Displacements(reference->Sector->PortalGroup, caller->Sector->PortalGroup); + fixedvec3 displacedold = old + Displacements.getOffset(reference->PrevPortalGroup, caller->Sector->PortalGroup); + fixedvec3 displacedref = old + Displacements.getOffset(reference->Sector->PortalGroup, caller->Sector->PortalGroup); caller->PrevX = caller->X() + displacedold.x - displacedref.x; caller->PrevY = caller->Y() + displacedold.y - displacedref.y; caller->PrevZ = caller->Z() + displacedold.z - displacedref.z; diff --git a/src/portal.cpp b/src/portal.cpp index 8446b3151a..e9a2d91566 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -121,6 +121,11 @@ static void BuildBlockmap() { PortalBlockmap.containsLines = true; block.portallines.Push(ld); + block.neighborContainsLines = true; + if (x > 0) PortalBlockmap(x - 1, y).neighborContainsLines = true; + if (y > 0) PortalBlockmap(x, y - 1).neighborContainsLines = true; + if (x < PortalBlockmap.dx - 1) PortalBlockmap(x + 1, y).neighborContainsLines = true; + if (y < PortalBlockmap.dy - 1) PortalBlockmap(x, y + 1).neighborContainsLines = true; } } } @@ -691,10 +696,18 @@ void P_NormalizeVXVY(fixed_t& vx, fixed_t& vy) fixedvec2 P_GetOffsetPosition(AActor *actor, fixed_t dx, fixed_t dy) { - fixedvec3 dest = { actor->X() + dx, actor->Y() + dy }; + fixedvec2 dest = { actor->X() + dx, actor->Y() + dy }; if (PortalBlockmap.containsLines) { fixed_t actx = actor->X(), acty = actor->Y(); + // Try some easily discoverable early-out first. If we know that the trace cannot possibly find a portal, this saves us from calling the traverser completely for vast parts of the map. + if (dx < 128 * FRACUNIT && dy < 128 * FRACUNIT) + { + fixed_t blockx = GetSafeBlockX(actx - bmaporgx); + fixed_t blocky = GetSafeBlockX(acty - bmaporgy); + if (blockx < 0 || blocky < 0 || blockx >= bmapwidth || blocky >= bmapheight || !PortalBlockmap(blockx, blocky).neighborContainsLines) return dest; + } + FLinePortalTraverse it; bool repeat; do @@ -1159,9 +1172,9 @@ bool P_CollectConnectedGroups(int startgroup, const fixedvec3 &position, fixed_t 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(startgroup, othersec->PortalGroup); - fixed_t dx = position.x + disp.pos.x; - fixed_t dy = position.y + disp.pos.y; + fixedvec2 pos = Displacements.getOffset(startgroup, othersec->PortalGroup); + fixed_t dx = position.x + pos.x; + fixed_t dy = position.y + pos.y; processMask.setBit(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 @@ -1171,9 +1184,9 @@ bool P_CollectConnectedGroups(int startgroup, const fixedvec3 &position, fixed_t while (!wsec->PortalBlocksMovement(sector_t::floor) && position.z < wsec->SkyBoxes[sector_t::floor]->threshold) { 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; + fixedvec2 pos = Displacements.getOffset(startgroup, othersec->PortalGroup); + fixed_t dx = position.x + pos.x; + fixed_t dy = position.y + 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 diff --git a/src/portal.h b/src/portal.h index 942a44c4ac..5099d6da50 100644 --- a/src/portal.h +++ b/src/portal.h @@ -30,10 +30,6 @@ struct FDisplacement bool isSet; BYTE indirect; // just for illustration. - operator fixedvec2() - { - return pos; - } }; struct FDisplacementTable @@ -55,9 +51,15 @@ 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]; } + + fixedvec2 getOffset(int x, int y) const + { + static const fixedvec2 nulvec = { 0,0 }; + if (x == y) return nulvec; // shortcut for the most common case + return data[x + size*y].pos; + } }; extern FDisplacementTable Displacements; @@ -72,7 +74,13 @@ extern FDisplacementTable Displacements; struct FPortalBlock { + bool neighborContainsLines; // this is for skipping the traverser and exiting early if we can quickly decide that there's no portals nearby. TArray portallines; + + FPortalBlock() + { + neighborContainsLines = false; + } }; struct FPortalBlockmap diff --git a/src/r_defs.h b/src/r_defs.h index 2222fbe05e..18eba3b7be 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -785,14 +785,14 @@ struct sector_t } // These may only be called if the portal has been validated - FDisplacement &FloorDisplacement() + fixedvec2 FloorDisplacement() { - return Displacements(PortalGroup, SkyBoxes[sector_t::floor]->Sector->PortalGroup); + return Displacements.getOffset(PortalGroup, SkyBoxes[sector_t::floor]->Sector->PortalGroup); } - FDisplacement &CeilingDisplacement() + fixedvec2 CeilingDisplacement() { - return Displacements(PortalGroup, SkyBoxes[sector_t::ceiling]->Sector->PortalGroup); + return Displacements.getOffset(PortalGroup, SkyBoxes[sector_t::ceiling]->Sector->PortalGroup); } int GetTerrain(int pos) const; @@ -1263,24 +1263,24 @@ inline sector_t *P_PointInSector(fixed_t x, fixed_t y) return P_PointInSubsector(x, y)->sector; } -inline fixedvec3 AActor::PosRelative(AActor *other) const +inline fixedvec3 AActor::PosRelative(const AActor *other) const { - return __pos + Displacements(Sector->PortalGroup, other->Sector->PortalGroup); + return __pos + Displacements.getOffset(Sector->PortalGroup, other->Sector->PortalGroup); } inline fixedvec3 AActor::PosRelative(sector_t *sec) const { - return __pos + Displacements(Sector->PortalGroup, sec->PortalGroup); + return __pos + Displacements.getOffset(Sector->PortalGroup, sec->PortalGroup); } inline fixedvec3 AActor::PosRelative(line_t *line) const { - return __pos + Displacements(Sector->PortalGroup, line->frontsector->PortalGroup); + return __pos + Displacements.getOffset(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); + return pos + Displacements.getOffset(refsec->PortalGroup, line->frontsector->PortalGroup); } inline void AActor::ClearInterpolation() diff --git a/src/r_utility.cpp b/src/r_utility.cpp index a97ebc65ec..628310fcec 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -583,7 +583,7 @@ void R_InterpolateView (player_t *player, fixed_t frac, InterpolationViewer *ivi } int oldgroup = R_PointInSubsector(iview->oviewx, iview->oviewy)->sector->PortalGroup; int newgroup = R_PointInSubsector(iview->nviewx, iview->nviewy)->sector->PortalGroup; - fixedvec2 disp = Displacements(oldgroup, newgroup); + fixedvec2 disp = Displacements.getOffset(oldgroup, newgroup); viewx = iview->oviewx + FixedMul (frac, iview->nviewx - iview->oviewx - disp.x); viewy = iview->oviewy + FixedMul (frac, iview->nviewy - iview->oviewy - disp.y); viewz = iview->oviewz + FixedMul (frac, iview->nviewz - iview->oviewz); diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 957f3e361f..ec876da15e 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -5181,7 +5181,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack) if (spawnblood) { P_SpawnBlood(bloodpos, angle, newdam > 0 ? newdam : damage, self->target); - P_TraceBleed(newdam > 0 ? newdam : damage, self->target, self->AngleTo(dx, dy, self->target), 0); + P_TraceBleed(newdam > 0 ? newdam : damage, self->target, self); } } }