diff --git a/Source/engine/render/clx_render.cpp b/Source/engine/render/clx_render.cpp index ec8d2bd47..64315809a 100644 --- a/Source/engine/render/clx_render.cpp +++ b/Source/engine/render/clx_render.cpp @@ -70,25 +70,6 @@ struct RenderSrc { uint_fast16_t width; }; -struct SkipSize { - int_fast16_t wholeLines; - int_fast16_t xOffset; -}; - -DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT SkipSize GetSkipSize(int_fast16_t remainingWidth, int_fast16_t srcWidth) -{ - if (remainingWidth < 0) { - // If `remainingWidth` is negative, `-remainingWidth` is the overrun. - const int_fast16_t overrunLines = -remainingWidth / srcWidth; - return { - static_cast(1 + overrunLines), - static_cast(-remainingWidth - srcWidth * overrunLines) - }; - } - // If `remainingWidth` is non-negative, then it is 0, meaning we drew a whole line. - return { 1, 0 }; -} - DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT const uint8_t *SkipRestOfLineWithOverrun( const uint8_t *src, int_fast16_t srcWidth, SkipSize &skipSize) { diff --git a/Source/utils/cl2_to_clx.cpp b/Source/utils/cl2_to_clx.cpp index d1c4ae7cb..43cfef0a0 100644 --- a/Source/utils/cl2_to_clx.cpp +++ b/Source/utils/cl2_to_clx.cpp @@ -11,24 +11,6 @@ namespace devilution { -namespace { - -constexpr size_t FrameHeaderSize = 10; - -struct SkipSize { - int_fast16_t wholeLines; - int_fast16_t xOffset; -}; -SkipSize GetSkipSize(int_fast16_t overrun, int_fast16_t srcWidth) -{ - SkipSize result; - result.wholeLines = overrun / srcWidth; - result.xOffset = overrun - srcWidth * result.wholeLines; - return result; -} - -} // namespace - uint16_t Cl2ToClx(const uint8_t *data, size_t size, PointerOrValue widthOrWidths, std::vector &clxData) { @@ -74,6 +56,7 @@ uint16_t Cl2ToClx(const uint8_t *data, size_t size, const uint16_t frameWidth = widthOrWidths.HoldsPointer() ? widthOrWidths.AsPointer()[frame - 1] : widthOrWidths.AsValue(); const size_t frameHeaderPos = clxData.size(); + constexpr size_t FrameHeaderSize = 10; clxData.resize(clxData.size() + FrameHeaderSize); WriteLE16(&clxData[frameHeaderPos], FrameHeaderSize); WriteLE16(&clxData[frameHeaderPos + 2], frameWidth); @@ -110,14 +93,9 @@ uint16_t Cl2ToClx(const uint8_t *data, size_t size, } } - ++frameHeight; - if (remainingWidth < 0) { - const auto skipSize = GetSkipSize(-remainingWidth, static_cast(frameWidth)); - xOffset = skipSize.xOffset; - frameHeight += skipSize.wholeLines; - } else { - xOffset = 0; - } + const auto skipSize = GetSkipSize(remainingWidth, static_cast(frameWidth)); + xOffset = skipSize.xOffset; + frameHeight += skipSize.wholeLines; } if (!pixels.empty()) { AppendClxPixelsOrFillRun(pixels.data(), pixels.size(), clxData); diff --git a/Source/utils/clx_decode.hpp b/Source/utils/clx_decode.hpp index 6606e9ea1..9533fdcb1 100644 --- a/Source/utils/clx_decode.hpp +++ b/Source/utils/clx_decode.hpp @@ -2,6 +2,9 @@ #include +#include "appfat.h" +#include "utils/attributes.h" + namespace devilution { [[nodiscard]] constexpr bool IsClxOpaque(uint8_t control) @@ -27,4 +30,29 @@ namespace devilution { return ClxFillEnd - control; } +struct SkipSize { + int_fast16_t wholeLines; + int_fast16_t xOffset; +}; + +// Returns the number of lines and the x-offset by which the rendering has overrun +// the current line (when a CLX command overruns the current line). +// +// Requires: remainingWidth <= 0. +DVL_ALWAYS_INLINE SkipSize GetSkipSize(int_fast16_t remainingWidth, int_fast16_t srcWidth) +{ + // If `remainingWidth` is negative, `-remainingWidth` is the overrun. + // Otherwise, `remainingWidth` is always 0. + + // Remaining width of 0 (= no overrun) is a common case. + // The calculation below would result in the same result. + // However, checking for 0 and skipping it entirely turns out to be faster. + if (remainingWidth == 0) return { 1, 0 }; + + const auto overrun = static_cast(-remainingWidth); + const uint_fast16_t overrunLines = overrun / srcWidth + 1; + const uint_fast16_t xOffset = overrun % srcWidth; + return { static_cast(overrunLines), static_cast(xOffset) }; +} + } // namespace devilution