- 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.
This commit is contained in:
Christoph Oelckers 2016-02-25 16:50:03 +01:00
parent fd78686679
commit eafd2519b4
10 changed files with 92 additions and 70 deletions

View File

@ -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<double>(X() - other->X(), Y() - other->Y()).Length());
fixedvec3 otherpos = absolute ? other->Pos() : other->PosRelative(this);
return xs_RoundToInt(TVector2<double>(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<double>(X() - other->X(), Y() - other->Y(), Z() - other->Z()).Length());
fixedvec3 otherpos = absolute ? other->Pos() : other->PosRelative(this);
return xs_RoundToInt(TVector3<double>(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;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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<line_t*> portallines;
FPortalBlock()
{
neighborContainsLines = false;
}
};
struct FPortalBlockmap

View File

@ -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()

View File

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

View File

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