Browse Source

Fix CLX outline clipped rendering on the right

The actual fix is the diff in `RenderClxOutlineRowClipped`.
The rest is a refactorings that make the code easier to
follow.

Fixes #6199
pull/6349/head
Gleb Mazovetskiy 3 years ago
parent
commit
14ce84b056
  1. 102
      Source/engine/render/clx_render.cpp

102
Source/engine/render/clx_render.cpp

@ -92,12 +92,19 @@ struct SkipSize {
int_fast16_t wholeLines;
int_fast16_t xOffset;
};
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT SkipSize GetSkipSize(int_fast16_t overrun, int_fast16_t srcWidth)
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT SkipSize GetSkipSize(int_fast16_t remainingWidth, int_fast16_t srcWidth)
{
SkipSize result;
result.wholeLines = overrun / srcWidth;
result.xOffset = overrun - srcWidth * result.wholeLines;
return result;
if (remainingWidth < 0) {
// If `remainingWidth` is negative, `-remainingWidth` is the overrun.
const int_fast16_t overrunLines = -remainingWidth / srcWidth;
return {
static_cast<int_fast16_t>(1 + overrunLines),
static_cast<int_fast16_t>(-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(
@ -109,13 +116,7 @@ DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT const uint8_t *SkipRestOfLineWithOverrun(
src = cmd.srcEnd;
remainingWidth -= cmd.length;
}
if (remainingWidth < 0) {
skipSize = GetSkipSize(-remainingWidth, srcWidth);
++skipSize.wholeLines;
} else {
skipSize.wholeLines = 1;
skipSize.xOffset = 0;
}
skipSize = GetSkipSize(remainingWidth, srcWidth);
return src;
}
@ -123,7 +124,7 @@ DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT const uint8_t *SkipRestOfLineWithOverrun(
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT int_fast16_t SkipLinesForRenderBackwardsWithOverrun(
Point &position, RenderSrc &src, int_fast16_t dstHeight)
{
SkipSize skipSize = { 0, 0 };
SkipSize skipSize { 0, 0 };
while (position.y >= dstHeight && src.begin != src.end) {
src.begin = SkipRestOfLineWithOverrun(
src.begin, static_cast<int_fast16_t>(src.width), skipSize);
@ -154,15 +155,10 @@ void DoRenderBackwardsClipY(
dst += cmd.length;
remainingWidth -= cmd.length;
}
dst -= dstPitch + src.width - remainingWidth;
if (remainingWidth < 0) {
const auto skipSize = GetSkipSize(-remainingWidth, static_cast<int_fast16_t>(src.width));
xOffset = skipSize.xOffset;
dst -= skipSize.wholeLines * dstPitch;
} else {
xOffset = 0;
}
const SkipSize skipSize = GetSkipSize(remainingWidth, static_cast<int_fast16_t>(src.width));
xOffset = skipSize.xOffset;
dst -= skipSize.wholeLines * dstPitch + src.width - remainingWidth;
}
}
@ -213,25 +209,19 @@ void DoRenderBackwardsClipXY(
remainingWidth -= unclippedLength; // result can be negative
}
// We've advanced `dst` by `clipX.width`.
//
// Set dst to (position.y - 1, position.x)
dst -= dstPitch + clipX.width;
// `remainingWidth` can be negative, in which case it is the amount of pixels
// that the source has overran the line.
remainingWidth += clipX.right;
SkipSize skipSize { 0, 0 };
SkipSize skipSize;
if (remainingWidth > 0) {
skipSize.xOffset = static_cast<int_fast16_t>(src.width) - remainingWidth;
src.begin = SkipRestOfLineWithOverrun(
src.begin, static_cast<int_fast16_t>(src.width), skipSize);
--skipSize.wholeLines;
} else if (remainingWidth < 0) {
skipSize = GetSkipSize(-remainingWidth, static_cast<int_fast16_t>(src.width));
} else {
skipSize = GetSkipSize(remainingWidth, static_cast<int_fast16_t>(src.width));
}
xOffset = skipSize.xOffset;
dst -= dstPitch * skipSize.wholeLines;
dst -= dstPitch * skipSize.wholeLines + clipX.width;
}
}
@ -293,7 +283,7 @@ DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderOutlineForPixels(uint8_t *dst, in
std::memset(dst + dstPitch, color, width);
}
template <bool North, bool West, bool South, bool East, bool SkipColorIndexZero = true>
template <bool North, bool West, bool South, bool East, bool SkipColorIndexZero>
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderOutlineForPixels(uint8_t *dst, int dstPitch, int width, const uint8_t *src, uint8_t color)
{
if (SkipColorIndexZero) {
@ -305,7 +295,7 @@ DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderOutlineForPixels(uint8_t *dst, in
}
template <bool Fill, bool North, bool West, bool South, bool East, bool SkipColorIndexZero>
uint8_t *RenderClxOutlinePixelsCheckFirstColumn(
void RenderClxOutlinePixelsCheckFirstColumn(
uint8_t *dst, int dstPitch, int dstX,
const uint8_t *src, uint8_t width, uint8_t color)
{
@ -333,18 +323,16 @@ uint8_t *RenderClxOutlinePixelsCheckFirstColumn(
} else {
RenderOutlineForPixels<North, West, South, East, SkipColorIndexZero>(dst, dstPitch, width, src, color);
}
dst += width;
}
return dst;
}
template <bool Fill, bool North, bool West, bool South, bool East, bool SkipColorIndexZero>
uint8_t *RenderClxOutlinePixelsCheckLastColumn(
void RenderClxOutlinePixelsCheckLastColumn(
uint8_t *dst, int dstPitch, int dstX, int dstW,
const uint8_t *src, uint8_t width, uint8_t color)
{
const bool lastPixel = dstX < dstW && width >= 1;
const bool oobPixel = dstX + width > dstW;
const bool lastPixel = dstX != dstW;
const bool oobPixel = dstX + width == dstW + 1;
const int numSpecialPixels = (lastPixel ? 1 : 0) + (oobPixel ? 1 : 0);
if (width > numSpecialPixels) {
width -= numSpecialPixels;
@ -365,36 +353,32 @@ uint8_t *RenderClxOutlinePixelsCheckLastColumn(
}
if (oobPixel) {
if (Fill) {
RenderOutlineForPixel</*North=*/false, West, /*South=*/false, /*East=*/false>(dst++, dstPitch, color);
RenderOutlineForPixel</*North=*/false, West, /*South=*/false, /*East=*/false>(dst, dstPitch, color);
} else {
RenderOutlineForPixel</*North=*/false, West, /*South=*/false, /*East=*/false, SkipColorIndexZero>(dst++, dstPitch, *src++, color);
RenderOutlineForPixel</*North=*/false, West, /*South=*/false, /*East=*/false, SkipColorIndexZero>(dst, dstPitch, *src, color);
}
}
return dst;
}
template <bool Fill, bool North, bool West, bool South, bool East, bool SkipColorIndexZero, bool CheckFirstColumn, bool CheckLastColumn>
uint8_t *RenderClxOutlinePixels(
void RenderClxOutlinePixels(
uint8_t *dst, int dstPitch, int dstX, int dstW,
const uint8_t *src, uint8_t width, uint8_t color)
{
if (SkipColorIndexZero && Fill && *src == 0)
return dst + width;
return;
if (CheckFirstColumn && dstX <= 0) {
return RenderClxOutlinePixelsCheckFirstColumn<Fill, North, West, South, East, SkipColorIndexZero>(
RenderClxOutlinePixelsCheckFirstColumn<Fill, North, West, South, East, SkipColorIndexZero>(
dst, dstPitch, dstX, src, width, color);
}
if (CheckLastColumn && dstX + width >= dstW) {
return RenderClxOutlinePixelsCheckLastColumn<Fill, North, West, South, East, SkipColorIndexZero>(
} else if (CheckLastColumn && dstX + width >= dstW) {
RenderClxOutlinePixelsCheckLastColumn<Fill, North, West, South, East, SkipColorIndexZero>(
dst, dstPitch, dstX, dstW, src, width, color);
}
if (Fill) {
} else if (Fill) {
RenderOutlineForPixels<North, West, South, East>(dst, dstPitch, width, color);
} else {
RenderOutlineForPixels<North, West, South, East, SkipColorIndexZero>(dst, dstPitch, width, src, color);
}
return dst + width;
}
template <bool North, bool West, bool South, bool East, bool SkipColorIndexZero,
@ -411,14 +395,15 @@ const uint8_t *RenderClxOutlineRowClipped( // NOLINT(readability-function-cognit
const auto renderPixels = [&](bool fill, uint8_t w) {
if (fill) {
dst = RenderClxOutlinePixels</*Fill=*/true, North, West, South, East, SkipColorIndexZero, CheckFirstColumn, CheckLastColumn>(
RenderClxOutlinePixels</*Fill=*/true, North, West, South, East, SkipColorIndexZero, CheckFirstColumn, CheckLastColumn>(
dst, dstPitch, position.x, out.w(), src, w, color);
++src;
} else {
dst = RenderClxOutlinePixels</*Fill=*/false, North, West, South, East, SkipColorIndexZero, CheckFirstColumn, CheckLastColumn>(
RenderClxOutlinePixels</*Fill=*/false, North, West, South, East, SkipColorIndexZero, CheckFirstColumn, CheckLastColumn>(
dst, dstPitch, position.x, out.w(), src, w, color);
src += v;
}
dst += w;
};
if (ClipWidth) {
@ -472,19 +457,10 @@ const uint8_t *RenderClxOutlineRowClipped( // NOLINT(readability-function-cognit
remainingWidth += clipX.right;
if (remainingWidth > 0) {
skipSize.xOffset = static_cast<int_fast16_t>(srcWidth) - remainingWidth;
src = SkipRestOfLineWithOverrun(src, static_cast<int_fast16_t>(srcWidth), skipSize);
if (skipSize.wholeLines > 1)
dst -= dstPitch * (skipSize.wholeLines - 1);
remainingWidth = -skipSize.xOffset;
return SkipRestOfLineWithOverrun(src, static_cast<int_fast16_t>(srcWidth), skipSize);
}
}
if (remainingWidth < 0) {
skipSize = GetSkipSize(-remainingWidth, static_cast<int_fast16_t>(srcWidth));
++skipSize.wholeLines;
} else {
skipSize.xOffset = 0;
skipSize.wholeLines = 1;
}
skipSize = GetSkipSize(remainingWidth, srcWidth);
return src;
}

Loading…
Cancel
Save