#pragma once #include #include #include namespace devilution { inline void AppendClxTransparentRun(unsigned width, std::vector &out) { while (width >= 0x7F) { out.push_back(0x7F); width -= 0x7F; } if (width == 0) return; out.push_back(width); } inline void AppendClxFillRun(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 AppendClxPixelsRun(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 AppendClxPixelsOrFillRun(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) { AppendClxPixelsRun(begin, prevColorBegin - begin, out); AppendClxFillRun(prevColor, prevColorRunLength, out); begin = src; } prevColorBegin = src; prevColorRunLength = 1; prevColor = color; } ++src; } // Here we use 2 instead of `MinFillRunLength` because we know that this run // is followed by transparent pixels. // Width=2 Fill command takes 2 bytes, while the Pixels command is 3 bytes. if (prevColorRunLength >= 2) { AppendClxPixelsRun(begin, prevColorBegin - begin, out); AppendClxFillRun(prevColor, prevColorRunLength, out); } else { AppendClxPixelsRun(begin, prevColorBegin - begin + prevColorRunLength, out); } } } // namespace devilution