- floatified p_scroll.cpp

While testing this it became clear that with the higher precision of doubles it has to be avoided at all costs to compare an actor's z position with a value retrieved from ZatPoint to check if it is standing on a floor. There can be some minor variations, depending on what was done with this value. Added isAbove, isBelow and isAtZ checking methods to AActor which properly deal with the problem.
This commit is contained in:
Christoph Oelckers 2016-03-28 21:04:46 +02:00
parent a46a4c81b1
commit 05504b65d2
8 changed files with 105 additions and 73 deletions

View File

@ -565,6 +565,7 @@ fixed_t P_AproxDistance (fixed_t dx, fixed_t dy); // since we cannot include p_l
angle_t R_PointToAngle2 (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2); // same reason here with r_defs.h
const double MinVel = 1. / 65536;
const double Z_Epsilon = 1. / 65536.;
// Map Object definition.
class AActor : public DThinker
@ -1294,6 +1295,20 @@ public:
{
return __Pos;
}
// Note: Never compare z directly with a plane height if you want to know if the actor is *on* the plane. Some very minor inaccuracies may creep in. Always use these inline functions!
// Comparing with floorz is ok because those values come from the same calculations.
bool isAbove(double checkz) const
{
return Z() > checkz + Z_Epsilon;
}
bool isBelow(double checkz) const
{
return Z() < checkz - Z_Epsilon;
}
bool isAtZ(double checkz)
{
return fabs(Z() - checkz) < Z_Epsilon;
}
fixedvec3 _f_PosRelative(int grp) const;
fixedvec3 _f_PosRelative(const AActor *other) const;

View File

@ -1955,7 +1955,7 @@ FUNC(LS_FloorAndCeiling_RaiseByValue)
FUNC(LS_FloorAndCeiling_LowerRaise)
// FloorAndCeiling_LowerRaise (tag, fspeed, cspeed, boomemu)
{
bool res = EV_DoCeiling (DCeiling::ceilRaiseToHighest, ln, arg0, SPEED(arg2), 0, 0, 0, 0, 0, false);
bool res = EV_DoCeiling (DCeiling::ceilRaiseToHighest, ln, arg0, SPEED(arg2), 0, 0, 0, 0, 0);
// The switch based Boom equivalents of FloorandCeiling_LowerRaise do incorrect checks
// which cause the floor only to move when the ceiling fails to do so.
// To avoid problems with maps that have incorrect args this only uses a
@ -2241,8 +2241,8 @@ FUNC(LS_Sector_SetLink)
return false;
}
void SetWallScroller(int id, int sidechoice, fixed_t dx, fixed_t dy, EScrollPos Where);
void SetScroller(int tag, EScroll type, fixed_t dx, fixed_t dy);
void SetWallScroller(int id, int sidechoice, double dx, double dy, EScrollPos Where);
void SetScroller(int tag, EScroll type, double dx, double dy);
FUNC(LS_Scroll_Texture_Both)
@ -2251,8 +2251,8 @@ FUNC(LS_Scroll_Texture_Both)
if (arg0 == 0)
return false;
fixed_t dx = (arg1 - arg2) * (FRACUNIT/64);
fixed_t dy = (arg4 - arg3) * (FRACUNIT/64);
double dx = (arg1 - arg2) / 64.;
double dy = (arg4 - arg3) / 64.;
int sidechoice;
if (arg0 < 0)
@ -2276,7 +2276,7 @@ FUNC(LS_Scroll_Wall)
if (arg0 == 0)
return false;
SetWallScroller (arg0, !!arg3, arg1, arg2, EScrollPos(arg4));
SetWallScroller (arg0, !!arg3, arg1 / 65536., arg2 / 65536., EScrollPos(arg4));
return true;
}
@ -2287,8 +2287,8 @@ FUNC(LS_Scroll_Wall)
FUNC(LS_Scroll_Floor)
// Scroll_Floor (tag, x-move, y-move, s/c)
{
fixed_t dx = arg1 * FRACUNIT/32;
fixed_t dy = arg2 * FRACUNIT/32;
double dx = arg1 / 32.;
double dy = arg2 / 32.;
if (arg3 == 0 || arg3 == 2)
{
@ -2312,8 +2312,8 @@ FUNC(LS_Scroll_Floor)
FUNC(LS_Scroll_Ceiling)
// Scroll_Ceiling (tag, x-move, y-move, 0)
{
fixed_t dx = arg1 * FRACUNIT/32;
fixed_t dy = arg2 * FRACUNIT/32;
double dx = arg1 / 32.;
double dy = arg2 / 32.;
SetScroller (arg0, EScroll::sc_ceiling, -dx, dy);
return true;

View File

@ -2992,7 +2992,7 @@ const secplane_t * P_CheckSlopeWalk(AActor *actor, DVector2 &move)
}
else if (t > 0)
{ // Desired location is in front of (above) the plane
if (fabs(planezhere - actor->Z() < (1/65536.))) // it is very important not to be too precise here.
if (actor->isAtZ(planezhere)) // it is very important not to be too precise here.
{
// Actor's current spot is on/in the plane, so walk down it
// Same principle as walking up, except reversed

View File

@ -3597,7 +3597,8 @@ void AActor::Tick ()
}
DVector3 pos = PosRelative(sec);
height = sec->floorplane.ZatPoint (pos);
if (Z() > height)
double height2 = sec->floorplane.ZatPoint(this);
if (isAbove(height))
{
if (heightsec == NULL)
{

View File

@ -42,8 +42,8 @@ class DScroller : public DThinker
HAS_OBJECT_POINTERS
public:
DScroller (EScroll type, fixed_t dx, fixed_t dy, int control, int affectee, int accel, EScrollPos scrollpos = EScrollPos::scw_all);
DScroller (fixed_t dx, fixed_t dy, const line_t *l, int control, int accel, EScrollPos scrollpos = EScrollPos::scw_all);
DScroller (EScroll type, double dx, double dy, int control, int affectee, int accel, EScrollPos scrollpos = EScrollPos::scw_all);
DScroller (double dx, double dy, const line_t *l, int control, int accel, EScrollPos scrollpos = EScrollPos::scw_all);
void Destroy();
void Serialize (FArchive &arc);
@ -51,18 +51,18 @@ public:
bool AffectsWall (int wallnum) const { return m_Type == EScroll::sc_side && m_Affectee == wallnum; }
int GetWallNum () const { return m_Type == EScroll::sc_side ? m_Affectee : -1; }
void SetRate (fixed_t dx, fixed_t dy) { m_dx = dx; m_dy = dy; }
void SetRate (double dx, double dy) { m_dx = dx; m_dy = dy; }
bool IsType (EScroll type) const { return type == m_Type; }
int GetAffectee () const { return m_Affectee; }
EScrollPos GetScrollParts() const { return m_Parts; }
protected:
EScroll m_Type; // Type of scroll effect
fixed_t m_dx, m_dy; // (dx,dy) scroll speeds
double m_dx, m_dy; // (dx,dy) scroll speeds
int m_Affectee; // Number of affected sidedef, sector, tag, or whatever
int m_Control; // Control sector (-1 if none) used to control scrolling
fixed_t m_LastHeight; // Last known height of control sector
fixed_t m_vdx, m_vdy; // Accumulated velocity if accelerative
double m_LastHeight; // Last known height of control sector
double m_vdx, m_vdy; // Accumulated velocity if accelerative
int m_Accel; // Whether it's accelerative
EScrollPos m_Parts; // Which parts of a sidedef are being scrolled?
TObjPtr<DInterpolation> m_Interpolations[3];
@ -137,9 +137,9 @@ void DScroller::Serialize (FArchive &arc)
//
//-----------------------------------------------------------------------------
static void RotationComp(const sector_t *sec, int which, fixed_t dx, fixed_t dy, fixed_t &tdx, fixed_t &tdy)
static void RotationComp(const sector_t *sec, int which, double dx, double dy, double &tdx, double &tdy)
{
angle_t an = sec->GetAngle(which);
DAngle an = sec->GetAngleF(which);
if (an == 0)
{
tdx = dx;
@ -147,11 +147,10 @@ static void RotationComp(const sector_t *sec, int which, fixed_t dx, fixed_t dy,
}
else
{
an = an >> ANGLETOFINESHIFT;
fixed_t ca = -finecosine[an];
fixed_t sa = -finesine[an];
tdx = DMulScale16(dx, ca, -dy, sa);
tdy = DMulScale16(dy, ca, dx, sa);
double ca = an.Cos();
double sa = an.Sin();
tdx = dx*ca - dy*sa;
tdy = dy*ca + dx*sa;
}
}
@ -180,16 +179,16 @@ static void RotationComp(const sector_t *sec, int which, fixed_t dx, fixed_t dy,
void DScroller::Tick ()
{
fixed_t dx = m_dx, dy = m_dy, tdx, tdy;
double dx = m_dx, dy = m_dy, tdx, tdy;
if (m_Control != -1)
{ // compute scroll amounts based on a sector's height changes
fixed_t height = sectors[m_Control].CenterFloor () +
sectors[m_Control].CenterCeiling ();
fixed_t delta = height - m_LastHeight;
double height = sectors[m_Control].CenterFloorF () +
sectors[m_Control].CenterCeilingF ();
double delta = height - m_LastHeight;
m_LastHeight = height;
dx = FixedMul(dx, delta);
dy = FixedMul(dy, delta);
dx *= delta;
dy *= delta;
}
// killough 3/14/98: Add acceleration
@ -199,7 +198,7 @@ void DScroller::Tick ()
m_vdy = dy += m_vdy;
}
if (!(dx | dy)) // no-op if both (x,y) offsets are 0
if (dx == 0 && dy == 0)
return;
switch (m_Type)
@ -237,8 +236,8 @@ void DScroller::Tick ()
// [RH] Don't actually carry anything here. That happens later.
case EScroll::sc_carry:
level.Scrolls[m_Affectee].Scroll.X += FIXED2DBL(dx);
level.Scrolls[m_Affectee].Scroll.Y += FIXED2DBL(dy);
level.Scrolls[m_Affectee].Scroll.X += dx;
level.Scrolls[m_Affectee].Scroll.Y += dy;
break;
case EScroll::sc_carry_ceiling: // to be added later
@ -266,7 +265,7 @@ void DScroller::Tick ()
//
//-----------------------------------------------------------------------------
DScroller::DScroller (EScroll type, fixed_t dx, fixed_t dy,
DScroller::DScroller (EScroll type, double dx, double dy,
int control, int affectee, int accel, EScrollPos scrollpos)
: DThinker (STAT_SCROLLER)
{
@ -278,7 +277,7 @@ DScroller::DScroller (EScroll type, fixed_t dx, fixed_t dy,
m_vdx = m_vdy = 0;
if ((m_Control = control) != -1)
m_LastHeight =
sectors[control].CenterFloor () + sectors[control].CenterCeiling ();
sectors[control].CenterFloorF () + sectors[control].CenterCeilingF ();
m_Affectee = affectee;
m_Interpolations[0] = m_Interpolations[1] = m_Interpolations[2] = NULL;
@ -342,17 +341,16 @@ void DScroller::Destroy ()
//
//-----------------------------------------------------------------------------
DScroller::DScroller (fixed_t dx, fixed_t dy, const line_t *l,
DScroller::DScroller (double dx, double dy, const line_t *l,
int control, int accel, EScrollPos scrollpos)
: DThinker (STAT_SCROLLER)
{
fixed_t x = abs(l->dx), y = abs(l->dy), d;
if (y > x)
d = x, x = y, y = d;
d = FixedDiv (x, finesine[(tantoangle[FixedDiv(y,x) >> DBITS] + ANG90)
>> ANGLETOFINESHIFT]);
x = -FixedDiv (FixedMul(dy, l->dy) + FixedMul(dx, l->dx), d);
y = -FixedDiv (FixedMul(dx, l->dy) - FixedMul(dy, l->dx), d);
double x = fabs(l->Delta().X), y = fabs(l->Delta().Y), d;
if (y > x) d = x, x = y, y = d;
d = x / g_sin(g_atan2(y, x) + M_PI / 2);
x = (-dy * l->Delta().Y + dx * l->Delta().X) / d;
y = (-dx * l->Delta().Y - dy * l->Delta().Y) / d;
m_Type = EScroll::sc_side;
m_dx = x;
@ -412,8 +410,8 @@ void P_SpawnScrollers(void)
for (i = 0; i < numlines; i++, l++)
{
fixed_t dx; // direction and speed of scrolling
fixed_t dy;
double dx; // direction and speed of scrolling
double dy;
int control = -1, accel = 0; // no control sector or acceleration
int special = l->special;
@ -463,14 +461,14 @@ void P_SpawnScrollers(void)
{
// The line housing the special controls the
// direction and speed of scrolling.
dx = l->dx >> SCROLL_SHIFT;
dy = l->dy >> SCROLL_SHIFT;
dx = l->Delta().X / 32.;
dy = l->Delta().Y / 32.;
}
else
{
// The speed and direction are parameters to the special.
dx = (l->args[3] - 128) * (FRACUNIT / 32);
dy = (l->args[4] - 128) * (FRACUNIT / 32);
dx = (l->args[3] - 128) / 32.;
dy = (l->args[4] - 128) / 32.;
}
}
@ -558,36 +556,36 @@ void P_SpawnScrollers(void)
case Scroll_Texture_Left:
l->special = special; // Restore the special, for compat_useblocking's benefit.
s = int(lines[i].sidedef[0] - sides);
new DScroller (EScroll::sc_side, l->args[0] * (FRACUNIT/64), 0,
new DScroller (EScroll::sc_side, l->args[0] / 64., 0,
-1, s, accel, SCROLLTYPE(l->args[1]));
break;
case Scroll_Texture_Right:
l->special = special;
s = int(lines[i].sidedef[0] - sides);
new DScroller (EScroll::sc_side, l->args[0] * (-FRACUNIT/64), 0,
new DScroller (EScroll::sc_side, -l->args[0] / 64., 0,
-1, s, accel, SCROLLTYPE(l->args[1]));
break;
case Scroll_Texture_Up:
l->special = special;
s = int(lines[i].sidedef[0] - sides);
new DScroller (EScroll::sc_side, 0, l->args[0] * (FRACUNIT/64),
new DScroller (EScroll::sc_side, 0, l->args[0] / 64.,
-1, s, accel, SCROLLTYPE(l->args[1]));
break;
case Scroll_Texture_Down:
l->special = special;
s = int(lines[i].sidedef[0] - sides);
new DScroller (EScroll::sc_side, 0, l->args[0] * (-FRACUNIT/64),
new DScroller (EScroll::sc_side, 0, -l->args[0] / 64.,
-1, s, accel, SCROLLTYPE(l->args[1]));
break;
case Scroll_Texture_Both:
s = int(lines[i].sidedef[0] - sides);
if (l->args[0] == 0) {
dx = (l->args[1] - l->args[2]) * (FRACUNIT/64);
dy = (l->args[4] - l->args[3]) * (FRACUNIT/64);
dx = (l->args[1] - l->args[2]) / 64.;
dy = (l->args[4] - l->args[3]) / 64.;
new DScroller (EScroll::sc_side, dx, dy, -1, s, accel);
}
break;
@ -606,12 +604,12 @@ void P_SpawnScrollers(void)
//
//-----------------------------------------------------------------------------
void SetWallScroller (int id, int sidechoice, fixed_t dx, fixed_t dy, EScrollPos Where)
void SetWallScroller (int id, int sidechoice, double dx, double dy, EScrollPos Where)
{
Where = Where & scw_all;
if (Where == 0) return;
if ((dx | dy) == 0)
if (dx == 0 && dy == 0)
{
// Special case: Remove the scroller, because the deltas are both 0.
TThinkerIterator<DScroller> iterator (STAT_SCROLLER);
@ -676,7 +674,7 @@ void SetWallScroller (int id, int sidechoice, fixed_t dx, fixed_t dy, EScrollPos
}
}
void SetScroller (int tag, EScroll type, fixed_t dx, fixed_t dy)
void SetScroller (int tag, EScroll type, double dx, double dy)
{
TThinkerIterator<DScroller> iterator (STAT_SCROLLER);
DScroller *scroller;
@ -700,7 +698,7 @@ void SetScroller (int tag, EScroll type, fixed_t dx, fixed_t dy)
}
}
if (i > 0 || (dx|dy) == 0)
if (i > 0 || (dx == 0 && dy == 0))
{
return;
}
@ -713,7 +711,7 @@ void SetScroller (int tag, EScroll type, fixed_t dx, fixed_t dy)
}
}
void P_CreateScroller(EScroll type, fixed_t dx, fixed_t dy, int control, int affectee, int accel, EScrollPos scrollpos)
void P_CreateScroller(EScroll type, double dx, double dy, int control, int affectee, int accel, EScrollPos scrollpos)
{
new DScroller(type, dx, dy, control, affectee, accel, scrollpos);
}

View File

@ -402,7 +402,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->LowestFloorAt(player->mo)
if (!player->mo->isAtZ(sector->LowestFloorAt(player->mo))
&& !player->mo->waterlevel)
{
return;
@ -1203,8 +1203,7 @@ void P_InitSectorSpecial(sector_t *sector, int special, bool nothinkers)
if (!nothinkers)
{
new DStrobe(sector, STROBEBRIGHT, FASTDARK, false);
P_CreateScroller(EScroll::sc_floor, -((FRACUNIT / 2) << 3),
0, -1, int(sector - sectors), 0);
P_CreateScroller(EScroll::sc_floor, -4., 0, -1, int(sector - sectors), 0);
}
keepspecial = true;
break;
@ -1248,7 +1247,7 @@ void P_InitSectorSpecial(sector_t *sector, int special, bool nothinkers)
if (sector->special >= Scroll_North_Slow &&
sector->special <= Scroll_SouthWest_Fast)
{ // Hexen scroll special
static const char hexenScrollies[24][2] =
static const SBYTE hexenScrollies[24][2] =
{
{ 0, 1 }, { 0, 2 }, { 0, 4 },
{ -1, 0 }, { -2, 0 }, { -4, 0 },
@ -1262,8 +1261,8 @@ void P_InitSectorSpecial(sector_t *sector, int special, bool nothinkers)
int i = sector->special - Scroll_North_Slow;
fixed_t dx = hexenScrollies[i][0] * (FRACUNIT/2);
fixed_t dy = hexenScrollies[i][1] * (FRACUNIT/2);
double dx = hexenScrollies[i][0] / 2.;
double dy = hexenScrollies[i][1] / 2.;
if (!nothinkers) P_CreateScroller(EScroll::sc_floor, dx, dy, -1, int(sector-sectors), 0);
}
else if (sector->special >= Carry_East5 &&
@ -1271,8 +1270,7 @@ void P_InitSectorSpecial(sector_t *sector, int special, bool nothinkers)
{ // Heretic scroll special
// Only east scrollers also scroll the texture
if (!nothinkers) P_CreateScroller(EScroll::sc_floor,
(-FRACUNIT/2)<<(sector->special - Carry_East5),
0, -1, int(sector-sectors), 0);
-0.5 * (1 << ((sector->special & 0xff) - Carry_East5)), 0, -1, int(sector-sectors), 0);
}
keepspecial = true;
break;

View File

@ -55,7 +55,7 @@ enum EScrollPos : int
scw_all = 7,
};
void P_CreateScroller(EScroll type, fixed_t dx, fixed_t dy, int control, int affectee, int accel, EScrollPos scrollpos = EScrollPos::scw_all);
void P_CreateScroller(EScroll type, double dx, double dy, int control, int affectee, int accel, EScrollPos scrollpos = EScrollPos::scw_all);
//jff 2/23/98 identify the special classes that can share sectors
@ -660,14 +660,14 @@ bool EV_DoCeiling (DCeiling::ECeiling type, line_t *line,
inline bool EV_DoCeiling(DCeiling::ECeiling type, line_t *line,
int tag, double speed, double speed2, fixed_t height,
int crush, int silent, int change, bool hexencrush)
int crush, int silent, int change, DCeiling::ECrushMode hexencrush = DCeiling::ECrushMode::crushDoom)
{
return EV_DoCeiling(type, line, tag, FLOAT2FIXED(speed), FLOAT2FIXED(speed2), height, crush, silent, change, hexencrush);
}
inline bool EV_DoCeiling(DCeiling::ECeiling type, line_t *line,
int tag, double speed, int speed2, fixed_t height,
int crush, int silent, int change, bool hexencrush)
int crush, int silent, int change, DCeiling::ECrushMode hexencrush = DCeiling::ECrushMode::crushDoom)
{
return EV_DoCeiling(type, line, tag, FLOAT2FIXED(speed), speed2, height, crush, silent, change, hexencrush);
}

View File

@ -330,7 +330,7 @@ struct secplane_t
double ZatPointF(const AActor *ac) const
{
return FIXED2DBL(ZatPoint(ac));
return (d + a*ac->X() + b*ac->Y()) * ic / (-65536.0 * 65536.0);
}
// Returns the value of z at (x,y) if d is equal to dist
@ -643,6 +643,11 @@ struct sector_t
planes[pos].xform.xoffs += o;
}
void AddXOffset(int pos, double o)
{
planes[pos].xform.xoffs += FLOAT2FIXED(o);
}
fixed_t GetXOffset(int pos) const
{
return planes[pos].xform.xoffs;
@ -663,6 +668,11 @@ struct sector_t
planes[pos].xform.yoffs += o;
}
void AddYOffset(int pos, double o)
{
planes[pos].xform.yoffs += FLOAT2FIXED(o);
}
fixed_t GetYOffset(int pos, bool addbase = true) const
{
if (!addbase)
@ -945,6 +955,8 @@ struct sector_t
// Member variables
fixed_t CenterFloor () const { return floorplane.ZatPoint (_f_centerspot()); }
fixed_t CenterCeiling () const { return ceilingplane.ZatPoint (_f_centerspot()); }
double CenterFloorF() const { return floorplane.ZatPoint(centerspot); }
double CenterCeilingF() const { return ceilingplane.ZatPoint(centerspot); }
// [RH] store floor and ceiling planes instead of heights
secplane_t floorplane, ceilingplane;
@ -1134,6 +1146,10 @@ struct side_t
{
textures[which].xoffset += delta;
}
void AddTextureXOffset(int which, double delta)
{
textures[which].xoffset += FLOAT2FIXED(delta);
}
void SetTextureYOffset(int which, fixed_t offset)
{
@ -1157,6 +1173,10 @@ struct side_t
{
textures[which].yoffset += delta;
}
void AddTextureYOffset(int which, double delta)
{
textures[which].yoffset += FLOAT2FIXED(delta);
}
void SetTextureXScale(int which, fixed_t scale)
{