From 05504b65d2b038c3c94b12e587fdc17b99f566ba Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 28 Mar 2016 21:04:46 +0200 Subject: [PATCH] - 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. --- src/actor.h | 15 ++++++++ src/p_lnspec.cpp | 20 +++++----- src/p_map.cpp | 2 +- src/p_mobj.cpp | 3 +- src/p_scroll.cpp | 96 ++++++++++++++++++++++++------------------------ src/p_spec.cpp | 14 +++---- src/p_spec.h | 6 +-- src/r_defs.h | 22 ++++++++++- 8 files changed, 105 insertions(+), 73 deletions(-) diff --git a/src/actor.h b/src/actor.h index 8d7e530e9..9f9f5efb8 100644 --- a/src/actor.h +++ b/src/actor.h @@ -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; diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 904756023..3ff43f27a 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -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; diff --git a/src/p_map.cpp b/src/p_map.cpp index 6c3f965ab..3e2fca2e2 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -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 diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index a4f359d73..467d01d0e 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -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) { diff --git a/src/p_scroll.cpp b/src/p_scroll.cpp index 47605d1ae..aad56aa67 100644 --- a/src/p_scroll.cpp +++ b/src/p_scroll.cpp @@ -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 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 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 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); } diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 0979f8ea9..830f20a26 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -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; diff --git a/src/p_spec.h b/src/p_spec.h index ce4cfdb76..0ba82c0bc 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -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); } diff --git a/src/r_defs.h b/src/r_defs.h index 37b0389de..6def54ebe 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -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) {