diff --git a/Source/utils/cel_to_clx.cpp b/Source/utils/cel_to_clx.cpp index 30d381f06..385b8f0c6 100644 --- a/Source/utils/cel_to_clx.cpp +++ b/Source/utils/cel_to_clx.cpp @@ -10,6 +10,7 @@ #endif #include "appfat.h" +#include "utils/clx_write.hpp" #include "utils/endian.hpp" namespace devilution { @@ -27,75 +28,6 @@ constexpr uint8_t GetCelTransparentWidth(uint8_t control) return -static_cast(control); } -void AppendCl2TransparentRun(unsigned width, std::vector &out) -{ - while (width >= 0x7F) { - out.push_back(0x7F); - width -= 0x7F; - } - if (width == 0) - return; - out.push_back(width); -} - -void AppendCl2FillRun(uint8_t color, unsigned width, std::vector &out) -{ - while (width >= 0x3F) { - out.push_back(0x80); - out.push_back(color); - width -= 0x3F; - } - if (width == 0) - return; - out.push_back(0xBF - width); - out.push_back(color); -} - -void AppendCl2PixelsRun(const uint8_t *src, unsigned width, std::vector &out) -{ - while (width >= 0x41) { - out.push_back(0xBF); - for (size_t i = 0; i < 0x41; ++i) - out.push_back(src[i]); - width -= 0x41; - src += 0x41; - } - if (width == 0) - return; - out.push_back(256 - width); - for (size_t i = 0; i < width; ++i) - out.push_back(src[i]); -} - -void AppendCl2PixelsOrFillRun(const uint8_t *src, unsigned length, std::vector &out) -{ - const uint8_t *begin = src; - const uint8_t *prevColorBegin = src; - unsigned prevColorRunLength = 1; - uint8_t prevColor = *src++; - while (--length > 0) { - const uint8_t color = *src; - if (prevColor == color) { - ++prevColorRunLength; - } else { - // A tunable parameter that decides at which minimum length we encode a fill run. - // 3 appears to be optimal for most of our data (much better than 2, rarely very slightly worse than 4). - constexpr unsigned MinFillRunLength = 3; - if (prevColorRunLength >= MinFillRunLength) { - AppendCl2PixelsRun(begin, prevColorBegin - begin, out); - AppendCl2FillRun(prevColor, prevColorRunLength, out); - begin = src; - } - prevColorBegin = src; - prevColorRunLength = 1; - prevColor = color; - } - ++src; - } - AppendCl2PixelsRun(begin, prevColorBegin - begin, out); - AppendCl2FillRun(prevColor, prevColorRunLength, out); -} - } // namespace OwnedClxSpriteListOrSheet CelToClx(const uint8_t *data, size_t size, PointerOrValue widthOrWidths) diff --git a/Source/utils/clx_write.hpp b/Source/utils/clx_write.hpp new file mode 100644 index 000000000..921768042 --- /dev/null +++ b/Source/utils/clx_write.hpp @@ -0,0 +1,78 @@ +#pragma once + +#include +#include +#include + +namespace devilution { + +inline void AppendCl2TransparentRun(unsigned width, std::vector &out) +{ + while (width >= 0x7F) { + out.push_back(0x7F); + width -= 0x7F; + } + if (width == 0) + return; + out.push_back(width); +} + +inline void AppendCl2FillRun(uint8_t color, unsigned width, std::vector &out) +{ + while (width >= 0x3F) { + out.push_back(0x80); + out.push_back(color); + width -= 0x3F; + } + if (width == 0) + return; + out.push_back(0xBF - width); + out.push_back(color); +} + +inline void AppendCl2PixelsRun(const uint8_t *src, unsigned width, std::vector &out) +{ + while (width >= 0x41) { + out.push_back(0xBF); + for (size_t i = 0; i < 0x41; ++i) + out.push_back(src[i]); + width -= 0x41; + src += 0x41; + } + if (width == 0) + return; + out.push_back(256 - width); + for (size_t i = 0; i < width; ++i) + out.push_back(src[i]); +} + +inline void AppendCl2PixelsOrFillRun(const uint8_t *src, unsigned length, std::vector &out) +{ + const uint8_t *begin = src; + const uint8_t *prevColorBegin = src; + unsigned prevColorRunLength = 1; + uint8_t prevColor = *src++; + while (--length > 0) { + const uint8_t color = *src; + if (prevColor == color) { + ++prevColorRunLength; + } else { + // A tunable parameter that decides at which minimum length we encode a fill run. + // 3 appears to be optimal for most of our data (much better than 2, rarely very slightly worse than 4). + constexpr unsigned MinFillRunLength = 3; + if (prevColorRunLength >= MinFillRunLength) { + AppendCl2PixelsRun(begin, prevColorBegin - begin, out); + AppendCl2FillRun(prevColor, prevColorRunLength, out); + begin = src; + } + prevColorBegin = src; + prevColorRunLength = 1; + prevColor = color; + } + ++src; + } + AppendCl2PixelsRun(begin, prevColorBegin - begin, out); + AppendCl2FillRun(prevColor, prevColorRunLength, out); +} + +} // namespace devilution diff --git a/Source/utils/pcx_to_clx.cpp b/Source/utils/pcx_to_clx.cpp index 961e53c44..a1130cc85 100644 --- a/Source/utils/pcx_to_clx.cpp +++ b/Source/utils/pcx_to_clx.cpp @@ -8,6 +8,7 @@ #include #include "appfat.h" +#include "utils/clx_write.hpp" #include "utils/endian.hpp" #include "utils/pcx.hpp" #include "utils/stdcompat/cstddef.hpp" @@ -25,75 +26,6 @@ namespace devilution { namespace { -void AppendCl2TransparentRun(unsigned width, std::vector &out) -{ - while (width >= 0x7F) { - out.push_back(0x7F); - width -= 0x7F; - } - if (width == 0) - return; - out.push_back(width); -} - -void AppendCl2FillRun(uint8_t color, unsigned width, std::vector &out) -{ - while (width >= 0x3F) { - out.push_back(0x80); - out.push_back(color); - width -= 0x3F; - } - if (width == 0) - return; - out.push_back(0xBF - width); - out.push_back(color); -} - -void AppendCl2PixelsRun(const uint8_t *src, unsigned width, std::vector &out) -{ - while (width >= 0x41) { - out.push_back(0xBF); - for (size_t i = 0; i < 0x41; ++i) - out.push_back(src[i]); - width -= 0x41; - src += 0x41; - } - if (width == 0) - return; - out.push_back(256 - width); - for (size_t i = 0; i < width; ++i) - out.push_back(src[i]); -} - -void AppendCl2PixelsOrFillRun(const uint8_t *src, unsigned length, std::vector &out) -{ - const uint8_t *begin = src; - const uint8_t *prevColorBegin = src; - unsigned prevColorRunLength = 1; - uint8_t prevColor = *src++; - while (--length > 0) { - const uint8_t color = *src; - if (prevColor == color) { - ++prevColorRunLength; - } else { - // A tunable parameter that decides at which minimum length we encode a fill run. - // 3 appears to be optimal for most of our data (much better than 2, rarely very slightly worse than 4). - constexpr unsigned MinFillRunLength = 3; - if (prevColorRunLength >= MinFillRunLength) { - AppendCl2PixelsRun(begin, prevColorBegin - begin, out); - AppendCl2FillRun(prevColor, prevColorRunLength, out); - begin = src; - } - prevColorBegin = src; - prevColorRunLength = 1; - prevColor = color; - } - ++src; - } - AppendCl2PixelsRun(begin, prevColorBegin - begin, out); - AppendCl2FillRun(prevColor, prevColorRunLength, out); -} - size_t GetReservationSize(size_t pcxSize) { // For the most part, CL2 is smaller than PCX, with a few exceptions.