diff --git a/Source/engine/render/blit_impl.hpp b/Source/engine/render/blit_impl.hpp index 08d9689a7..7fffcc62f 100644 --- a/Source/engine/render/blit_impl.hpp +++ b/Source/engine/render/blit_impl.hpp @@ -49,11 +49,13 @@ struct BlitDirect { DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void BlitFillWithMap(uint8_t *dst, unsigned length, uint8_t color, const uint8_t *DVL_RESTRICT colorMap) { + assert(length != 0); std::memset(dst, colorMap[color], length); } DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void BlitPixelsWithMap(uint8_t *DVL_RESTRICT dst, const uint8_t *DVL_RESTRICT src, unsigned length, const uint8_t *DVL_RESTRICT colorMap) { + assert(length != 0); const uint8_t *end = src + length; while (src < end - 3) { *dst++ = colorMap[*src++]; @@ -68,6 +70,7 @@ DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void BlitPixelsWithMap(uint8_t *DVL_RESTRICT DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void BlitFillBlended(uint8_t *dst, unsigned length, uint8_t color) { + assert(length != 0); const uint8_t *end = dst + length; const uint8_t *tbl = paletteTransparencyLookup[color]; while (dst < end - 3) { @@ -88,6 +91,7 @@ DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void BlitFillBlended(uint8_t *dst, unsigned DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void BlitPixelsBlended(uint8_t *DVL_RESTRICT dst, const uint8_t *DVL_RESTRICT src, unsigned length) { + assert(length != 0); const uint8_t *end = src + length; while (src < end - 3) { *dst = paletteTransparencyLookup[*dst][*src++]; @@ -125,6 +129,7 @@ struct BlitWithMap { DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void BlitPixelsBlendedWithMap(uint8_t *DVL_RESTRICT dst, const uint8_t *DVL_RESTRICT src, unsigned length, const uint8_t *DVL_RESTRICT colorMap) { + assert(length != 0); const uint8_t *end = src + length; while (src < end - 3) { *dst = paletteTransparencyLookup[*dst][colorMap[*src++]]; diff --git a/Source/engine/render/dun_render.cpp b/Source/engine/render/dun_render.cpp index f30c96720..e8d7c250d 100644 --- a/Source/engine/render/dun_render.cpp +++ b/Source/engine/render/dun_render.cpp @@ -241,8 +241,16 @@ DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderLine(uint8_t *DVL_RESTRICT dst, c { if (PrefixIncrement == 0) { RenderLineTransparentOrOpaque(dst, src, n, tbl); - } else { - RenderLineTransparentAndOpaque(dst, src, clamp(prefix, 0, n), n, tbl); + } else if (prefix >= n) { + // We clamp the prefix to (0, n] and avoid calling `RenderLineTransparent/Opaque` with width=0. + if (OpaquePrefix) { + RenderLineOpaque(dst, src, n, tbl); + } else { + if (!SkipTransparentPixels) + RenderLineTransparent(dst, src, n, tbl); + } + } else if (prefix > 0) { + RenderLineTransparentAndOpaque(dst, src, prefix, n, tbl); } } @@ -713,12 +721,40 @@ DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderRightTriangle(uint8_t *DVL_RESTRI template DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderTrapezoidUpperHalf(uint8_t *DVL_RESTRICT dst, uint16_t dstPitch, const uint8_t *DVL_RESTRICT src, const uint8_t *DVL_RESTRICT tbl) { - uint_fast8_t prefixWidth = PrefixIncrement < 0 ? 32 : 0; - for (auto i = 0; i < TrapezoidUpperHeight; ++i, dst -= dstPitch) { - RenderLineTransparentAndOpaque(dst, src, prefixWidth, Width, tbl); - if (PrefixIncrement != 0) - prefixWidth += PrefixIncrement; + if (PrefixIncrement != 0) { + // The first and the last line are always fully transparent/opaque (or vice-versa). + // We handle them specially to avoid calling the blitter with width=0. + const uint8_t *srcEnd = src + Width * (TrapezoidUpperHeight - 1); + constexpr bool FirstLineIsTransparent = OpaquePrefix ^ (PrefixIncrement < 0); + constexpr bool LastLineIsTransparent = !FirstLineIsTransparent; + if (FirstLineIsTransparent) { + if (!SkipTransparentPixels) + RenderLineTransparent(dst, src, Width, tbl); + } else { + RenderLineOpaque(dst, src, Width, tbl); + } src += Width; + dst -= dstPitch; + uint8_t prefixWidth = (PrefixIncrement < 0 ? 32 : 0) + PrefixIncrement; + do { + RenderLineTransparentAndOpaque(dst, src, prefixWidth, Width, tbl); + prefixWidth += PrefixIncrement; + src += Width; + dst -= dstPitch; + } while (src != srcEnd); + if (LastLineIsTransparent) { + if (!SkipTransparentPixels) + RenderLineTransparent(dst, src, Width, tbl); + } else { + RenderLineOpaque(dst, src, Width, tbl); + } + } else { // PrefixIncrement == 0; + const uint8_t *srcEnd = src + Width * TrapezoidUpperHeight; + do { + RenderLineTransparentOrOpaque(dst, src, Width, tbl); + src += Width; + dst -= dstPitch; + } while (src != srcEnd); } }