diff --git a/rts/Sim/Units/Scripts/UnitScript.cpp b/rts/Sim/Units/Scripts/UnitScript.cpp index 7a018a601e..9ebe6d85a0 100644 --- a/rts/Sim/Units/Scripts/UnitScript.cpp +++ b/rts/Sim/Units/Scripts/UnitScript.cpp @@ -372,7 +372,7 @@ void CUnitScript::StopSpin(int piece, int axis, float decel) void CUnitScript::Turn(int piece, int axis, float speed, float destination) { - AddAnim(ATurn, piece, axis, std::max(speed, -speed), destination, 0); + AddAnim(ATurn, piece, axis, std::max(speed, -speed), ClampRad(destination), 0); } @@ -406,7 +406,7 @@ void CUnitScript::TurnNow(int piece, int axis, float destination) ShowUnitScriptError("[US::TurnNow] invalid script piece index"); return; } - destination = math::fmod(destination, math::TWOPI); + destination = ClampRad(destination); LocalModelPiece* p = pieces[piece]; diff --git a/rts/Sim/Units/Scripts/UnitScript.h b/rts/Sim/Units/Scripts/UnitScript.h index 257bcc0af0..c0cec58d0b 100644 --- a/rts/Sim/Units/Scripts/UnitScript.h +++ b/rts/Sim/Units/Scripts/UnitScript.h @@ -109,8 +109,8 @@ class CUnitScript bool Tick(int tickRate); // note: must copy-and-set here (LMP dirty flag, etc) bool TickMoveAnim(int tickRate, LocalModelPiece& lmp, AnimInfo& ai) { float3 pos = lmp.GetPosition(); const bool ret = MoveToward(pos[ai.axis], ai.dest, ai.speed / tickRate); lmp.SetPosition(pos); return ret; } - bool TickTurnAnim(int tickRate, LocalModelPiece& lmp, AnimInfo& ai) { float3 rot = lmp.GetRotation(); rot[ai.axis] = math::fmod(rot[ai.axis], math::TWOPI); const bool ret = TurnToward(rot[ai.axis], ai.dest, ai.speed / tickRate ); lmp.SetRotation(rot); return ret; } - bool TickSpinAnim(int tickRate, LocalModelPiece& lmp, AnimInfo& ai) { float3 rot = lmp.GetRotation(); rot[ai.axis] = math::fmod(rot[ai.axis], math::TWOPI); const bool ret = DoSpin(rot[ai.axis], ai.dest, ai.speed, ai.accel, tickRate); lmp.SetRotation(rot); return ret; } + bool TickTurnAnim(int tickRate, LocalModelPiece& lmp, AnimInfo& ai) { float3 rot = lmp.GetRotation(); rot[ai.axis] = ClampRad(rot[ai.axis]); const bool ret = TurnToward(rot[ai.axis], ai.dest, ai.speed / tickRate ); lmp.SetRotation(rot); return ret; } + bool TickSpinAnim(int tickRate, LocalModelPiece& lmp, AnimInfo& ai) { float3 rot = lmp.GetRotation(); rot[ai.axis] = ClampRad(rot[ai.axis]); const bool ret = DoSpin(rot[ai.axis], ai.dest, ai.speed, ai.accel, tickRate); lmp.SetRotation(rot); return ret; } void TickAnims(int tickRate, const TickAnimFunc& tickAnimFunc, AnimContainerType& liveAnims, AnimContainerType& doneAnims); // animation, used by CCobThread diff --git a/rts/System/FastMath.h b/rts/System/FastMath.h index 6377f87591..fafabab818 100644 --- a/rts/System/FastMath.h +++ b/rts/System/FastMath.h @@ -36,7 +36,7 @@ namespace fastmath { float apxsqrt2(float x) _const; float sin(float x) _const; float cos(float x) _const; - template float floor(const T& f) _const; + template T floor(T f) _const; /****************** Square root functions ******************/ @@ -198,13 +198,21 @@ namespace fastmath { /** * @brief fast version of std::floor * - * Like 2-3x faster than glibc ones. - * Note: The results differ at the end of the 32bit precision range. + * About 2x faster than glibc ones. + * + * Unlike std::floor, this one returns the different (positive) + * result for negative float zero input (0.0f). */ template - inline float floor(const T& f) + inline T floor(T f) { - return (f >= 0) ? int(f) : int(f+0.000001f)-1; + //return (f >= 0) ? int(f) : int(f+0.000001f)-1; + // it's about the same performance as the former code above, + // but without arbitratry number shenanigans + // Perf comparison: + // https://quick-bench.com/q/rwmaN33UJ4cTEViBGqQYuVgyyOc + T truncX = static_cast(static_cast(f)); + return truncX - static_cast(truncX > f); } } diff --git a/rts/System/SpringMath.inl b/rts/System/SpringMath.inl index f9813e2136..1dc7387716 100644 --- a/rts/System/SpringMath.inl +++ b/rts/System/SpringMath.inl @@ -144,8 +144,17 @@ inline int2 IdxToCoord(unsigned x, unsigned array_width) inline float ClampRad(float f) { + // handle a special case of f==-0.0f, it can be elliminated by adding 0.0f + f += 0.0f; + // fmod is not good here because it calculates the remainder, but we need the arithmetic modulus + /* f = math::fmod(f, math::TWOPI); f += (math::TWOPI * (f < 0.0f)); + */ + f = f - math::TWOPI * math::floor(f / math::TWOPI); + + // there should be no negative zeros (-0.0f) or negatives in general + assert(!std::signbit(f)); return f; } @@ -172,7 +181,7 @@ inline float3 GetRadAngleToward(float3 v1, float3 v2) { inline bool RadsAreEqual(const float f1, const float f2) { - return (math::fmod(f1 - f2, math::TWOPI) == 0.0f); + return ClampRad(f1 - f2) == 0.0f; } inline float GetRadFromXY(const float dx, const float dy)