Browse Source

💨 dun_render.cpp: Faster RenderLine

Turns RenderLine line branches into template parameters, allowing the
compiler to eliminate the branches and also fully inline it.

Example FPS change

* In dungeon: 1450 -> 1530
* In town: 1655 -> 1700

Also splits RenderLine into 3 functions

Easier to read and also gives more useful profiling.
Apparently the most time is spent in `RenderLineOpaque`.

Also, mark them `inline` because that apparently hints GCC to inline
the function (in a later refactoring we can introduce attribute
always_inline instead where supported).
pull/1943/head
Gleb Mazovetskiy 5 years ago committed by Anders Jenbo
parent
commit
fb27ee3907
  1. 366
      Source/engine/render/dun_render.cpp

366
Source/engine/render/dun_render.cpp

@ -487,79 +487,111 @@ void ForEachSetBit(std::uint32_t mask, const F &f)
}
}
inline void RenderLine(std::uint8_t *dst, const std::uint8_t *src, size_t n, const std::uint8_t *tbl, std::uint32_t mask)
enum class TransparencyType {
Solid,
Blended,
Stippled,
};
enum class LightType {
FullyDark,
PartiallyLit,
FullyLit,
};
template <LightType Light>
inline void RenderLineOpaque(std::uint8_t *dst, const std::uint8_t *src, std::uint_fast8_t n, const std::uint8_t *tbl)
{
// The number of iterations is limited by the size of the mask.
// So we can limit it by ANDing the mask with another mask that only keeps
// iterations that are lower than n. We can now avoid testing if i < n
// at every loop iteration.
assert(n != 0 && n <= sizeof(std::uint32_t) * CHAR_BIT);
const std::uint32_t firstNOnes = std::uint32_t(-1) << ((sizeof(std::uint32_t) * CHAR_BIT) - n);
mask &= firstNOnes;
if (mask == firstNOnes) { // Opaque line
if (light_table_index == lightmax) { // Complete darkness
memset(dst, 0, n);
} else if (light_table_index == 0) { // Fully lit
if (Light == LightType::FullyDark) {
memset(dst, 0, n);
} else if (Light == LightType::FullyLit) {
#ifndef DEBUG_RENDER_COLOR
memcpy(dst, src, n);
memcpy(dst, src, n);
#else
memset(dst, DBGCOLOR, n);
memset(dst, DBGCOLOR, n);
#endif
} else { // Partially lit
} else { // Partially lit
#ifndef DEBUG_RENDER_COLOR
for (size_t i = 0; i < n; i++) {
dst[i] = tbl[src[i]];
}
for (size_t i = 0; i < n; i++) {
dst[i] = tbl[src[i]];
}
#else
memset(dst, tbl[DBGCOLOR], n);
memset(dst, tbl[DBGCOLOR], n);
#endif
}
} else {
if (sgOptions.Graphics.bBlendedTransparancy) { // Blended transparancy
}
}
template <LightType Light>
inline void RenderLineBlended(std::uint8_t *dst, const std::uint8_t *src, std::uint_fast8_t n, const std::uint8_t *tbl, std::uint32_t mask)
{
#ifndef DEBUG_RENDER_COLOR
if (light_table_index == lightmax) { // Complete darkness
for (size_t i = 0; i < n; i++, mask <<= 1) {
if ((mask & 0x80000000) != 0)
dst[i] = 0;
else
dst[i] = paletteTransparencyLookup[0][dst[i]];
}
} else if (light_table_index == 0) { // Fully lit
for (size_t i = 0; i < n; i++, mask <<= 1) {
if ((mask & 0x80000000) != 0)
dst[i] = src[i];
else
dst[i] = paletteTransparencyLookup[dst[i]][src[i]];
}
} else { // Partially lit
for (size_t i = 0; i < n; i++, mask <<= 1) {
if ((mask & 0x80000000) != 0)
dst[i] = tbl[src[i]];
else
dst[i] = paletteTransparencyLookup[dst[i]][tbl[src[i]]];
}
}
if (Light == LightType::FullyDark) {
for (size_t i = 0; i < n; i++, mask <<= 1) {
if ((mask & 0x80000000) != 0)
dst[i] = 0;
else
dst[i] = paletteTransparencyLookup[0][dst[i]];
}
} else if (Light == LightType::FullyLit) {
for (size_t i = 0; i < n; i++, mask <<= 1) {
if ((mask & 0x80000000) != 0)
dst[i] = src[i];
else
dst[i] = paletteTransparencyLookup[dst[i]][src[i]];
}
} else { // Partially lit
for (size_t i = 0; i < n; i++, mask <<= 1) {
if ((mask & 0x80000000) != 0)
dst[i] = tbl[src[i]];
else
dst[i] = paletteTransparencyLookup[dst[i]][tbl[src[i]]];
}
}
#else
for (size_t i = 0; i < n; i++, mask <<= 1) {
if ((mask & 0x80000000) != 0)
dst[i] = tbl[DBGCOLOR];
else
dst[i] = paletteTransparencyLookup[dst[i]][tbl[DBGCOLOR]];
}
for (size_t i = 0; i < n; i++, mask <<= 1) {
if ((mask & 0x80000000) != 0)
dst[i] = tbl[DBGCOLOR];
else
dst[i] = paletteTransparencyLookup[dst[i]][tbl[DBGCOLOR]];
}
#endif
} else { // Stippled transparancy
if (light_table_index == lightmax) { // Complete darkness
ForEachSetBit(mask, [=](int i) { dst[i] = 0; });
} else if (light_table_index == 0) { // Fully lit
}
template <LightType Light>
inline void RenderLineStippled(std::uint8_t *dst, const std::uint8_t *src, std::uint_fast8_t n, const std::uint8_t *tbl, std::uint32_t mask)
{
if (Light == LightType::FullyDark) {
ForEachSetBit(mask, [=](int i) { dst[i] = 0; });
} else if (Light == LightType::FullyLit) {
#ifndef DEBUG_RENDER_COLOR
ForEachSetBit(mask, [=](int i) { dst[i] = src[i]; });
ForEachSetBit(mask, [=](int i) { dst[i] = src[i]; });
#else
ForEachSetBit(mask, [=](int i) { dst[i] = DBGCOLOR; });
ForEachSetBit(mask, [=](int i) { dst[i] = DBGCOLOR; });
#endif
} else { // Partially lit
ForEachSetBit(mask, [=](int i) { dst[i] = tbl[src[i]]; });
}
} else { // Partially lit
ForEachSetBit(mask, [=](int i) { dst[i] = tbl[src[i]]; });
}
}
template <TransparencyType Transparency, LightType Light>
inline void RenderLine(std::uint8_t *dst, const std::uint8_t *src, std::uint_fast8_t n, const std::uint8_t *tbl, std::uint32_t mask)
{
if (Transparency == TransparencyType::Solid) {
RenderLineOpaque<Light>(dst, src, n, tbl);
} else {
// The number of iterations is limited by the size of the mask.
// So we can limit it by ANDing the mask with another mask that only keeps
// iterations that are lower than n. We can now avoid testing if i < n
// at every loop iteration.
assert(n != 0 && n <= sizeof(std::uint32_t) * CHAR_BIT);
const std::uint32_t firstNOnes = std::uint32_t(-1) << ((sizeof(std::uint32_t) * CHAR_BIT) - n);
mask &= firstNOnes;
if (mask == firstNOnes) {
RenderLineOpaque<Light>(dst, src, n, tbl);
} else if (Transparency == TransparencyType::Blended) {
RenderLineBlended<Light>(dst, src, n, tbl, mask);
} else {
RenderLineStippled<Light>(dst, src, n, tbl, mask);
}
}
}
@ -585,32 +617,36 @@ Clip CalculateClip(std::int_fast16_t x, std::int_fast16_t y, std::int_fast16_t w
return clip;
}
template <TransparencyType Transparency, LightType Light>
void RenderSquareFull(std::uint8_t *dst, int dstPitch, const std::uint8_t *src, const std::uint32_t *mask, const std::uint8_t *tbl)
{
for (auto i = 0; i < Height; ++i, dst -= dstPitch, --mask) {
RenderLine(dst, src, Width, tbl, *mask);
RenderLine<Transparency, Light>(dst, src, Width, tbl, *mask);
src += Width;
}
}
template <TransparencyType Transparency, LightType Light>
void RenderSquareClipped(std::uint8_t *dst, int dstPitch, const std::uint8_t *src, const std::uint32_t *mask, const std::uint8_t *tbl, Clip clip)
{
src += clip.bottom * Height + clip.left;
for (auto i = 0; i < clip.height; ++i, dst -= dstPitch, --mask) {
RenderLine(dst, src, clip.width, tbl, (*mask) << clip.left);
RenderLine<Transparency, Light>(dst, src, clip.width, tbl, (*mask) << clip.left);
src += Width;
}
}
template <TransparencyType Transparency, LightType Light>
void RenderSquare(std::uint8_t *dst, int dstPitch, const std::uint8_t *src, const std::uint32_t *mask, const std::uint8_t *tbl, Clip clip)
{
if (clip.width == Width && clip.height == Height) {
RenderSquareFull(dst, dstPitch, src, mask, tbl);
RenderSquareFull<Transparency, Light>(dst, dstPitch, src, mask, tbl);
} else {
RenderSquareClipped(dst, dstPitch, src, mask, tbl, clip);
RenderSquareClipped<Transparency, Light>(dst, dstPitch, src, mask, tbl, clip);
}
}
template <TransparencyType Transparency, LightType Light>
void RenderTransparentSquareFull(std::uint8_t *dst, int dstPitch, const std::uint8_t *src, const std::uint32_t *mask, const std::uint8_t *tbl)
{
for (auto i = 0; i < Height; ++i, dst -= dstPitch + Width, --mask) {
@ -620,7 +656,7 @@ void RenderTransparentSquareFull(std::uint8_t *dst, int dstPitch, const std::uin
while (drawWidth > 0) {
auto v = static_cast<std::int8_t>(*src++);
if (v > 0) {
RenderLine(dst, src, v, tbl, m);
RenderLine<Transparency, Light>(dst, src, v, tbl, m);
src += v;
} else {
v = -v;
@ -632,6 +668,7 @@ void RenderTransparentSquareFull(std::uint8_t *dst, int dstPitch, const std::uin
}
}
template <TransparencyType Transparency, LightType Light>
// NOLINTNEXTLINE(readability-function-cognitive-complexity): Actually complex and has to be fast.
void RenderTransparentSquareClipped(std::uint8_t *dst, int dstPitch, const std::uint8_t *src, const std::uint32_t *mask, const std::uint8_t *tbl, Clip clip)
{
@ -666,7 +703,7 @@ void RenderTransparentSquareClipped(std::uint8_t *dst, int dstPitch, const std::
if (v > 0) {
if (v > remainingLeftClip) {
const auto overshoot = v - remainingLeftClip;
RenderLine(dst, src + remainingLeftClip, overshoot, tbl, m);
RenderLine<Transparency, Light>(dst, src + remainingLeftClip, overshoot, tbl, m);
dst += overshoot;
drawWidth -= overshoot;
}
@ -688,13 +725,13 @@ void RenderTransparentSquareClipped(std::uint8_t *dst, int dstPitch, const std::
auto v = static_cast<std::int8_t>(*src++);
if (v > 0) {
if (v > drawWidth) {
RenderLine(dst, src, drawWidth, tbl, m);
RenderLine<Transparency, Light>(dst, src, drawWidth, tbl, m);
src += v;
dst += drawWidth;
drawWidth -= v;
break;
}
RenderLine(dst, src, v, tbl, m);
RenderLine<Transparency, Light>(dst, src, v, tbl, m);
src += v;
} else {
v = -v;
@ -715,12 +752,13 @@ void RenderTransparentSquareClipped(std::uint8_t *dst, int dstPitch, const std::
}
}
template <TransparencyType Transparency, LightType Light>
void RenderTransparentSquare(std::uint8_t *dst, int dstPitch, const std::uint8_t *src, const std::uint32_t *mask, const std::uint8_t *tbl, Clip clip)
{
if (clip.width == Width && clip.height == Height) {
RenderTransparentSquareFull(dst, dstPitch, src, mask, tbl);
RenderTransparentSquareFull<Transparency, Light>(dst, dstPitch, src, mask, tbl);
} else {
RenderTransparentSquareClipped(dst, dstPitch, src, mask, tbl, clip);
RenderTransparentSquareClipped<Transparency, Light>(dst, dstPitch, src, mask, tbl, clip);
}
}
@ -762,24 +800,26 @@ std::size_t CalculateTriangleSourceSkipUpperBottom(std::int_fast16_t numLines)
return 2 * TriangleUpperHeight * numLines - numLines * (numLines - 1) + 2 * ((numLines + 1) / 2);
}
template <TransparencyType Transparency, LightType Light>
void RenderLeftTriangleFull(std::uint8_t *dst, int dstPitch, const std::uint8_t *src, const std::uint32_t *mask, const std::uint8_t *tbl)
{
dst += XStep * (LowerHeight - 1);
for (auto i = 1; i <= LowerHeight; ++i, dst -= dstPitch + XStep, --mask) {
src += 2 * (i % 2);
const auto width = XStep * i;
RenderLine(dst, src, width, tbl, *mask);
RenderLine<Transparency, Light>(dst, src, width, tbl, *mask);
src += width;
}
dst += 2 * XStep;
for (auto i = 1; i <= TriangleUpperHeight; ++i, dst -= dstPitch - XStep, --mask) {
src += 2 * (i % 2);
const auto width = Width - XStep * i;
RenderLine(dst, src, width, tbl, *mask);
RenderLine<Transparency, Light>(dst, src, width, tbl, *mask);
src += width;
}
}
template <TransparencyType Transparency, LightType Light>
void RenderLeftTriangleClipVertical(std::uint8_t *dst, int dstPitch, const std::uint8_t *src, const std::uint32_t *mask, const std::uint8_t *tbl, Clip clip)
{
const auto clipY = CalculateDiamondClipY(clip);
@ -789,7 +829,7 @@ void RenderLeftTriangleClipVertical(std::uint8_t *dst, int dstPitch, const std::
for (auto i = 1 + clipY.lowerBottom; i <= lowerMax; ++i, dst -= dstPitch + XStep, --mask) {
src += 2 * (i % 2);
const auto width = XStep * i;
RenderLine(dst, src, width, tbl, *mask);
RenderLine<Transparency, Light>(dst, src, width, tbl, *mask);
src += width;
}
src += CalculateTriangleSourceSkipUpperBottom(clipY.upperBottom);
@ -798,11 +838,12 @@ void RenderLeftTriangleClipVertical(std::uint8_t *dst, int dstPitch, const std::
for (auto i = 1 + clipY.upperBottom; i <= upperMax; ++i, dst -= dstPitch - XStep, --mask) {
src += 2 * (i % 2);
const auto width = Width - XStep * i;
RenderLine(dst, src, width, tbl, *mask);
RenderLine<Transparency, Light>(dst, src, width, tbl, *mask);
src += width;
}
}
template <TransparencyType Transparency, LightType Light>
void RenderLeftTriangleClipLeftAndVertical(std::uint8_t *dst, int dstPitch, const std::uint8_t *src, const std::uint32_t *mask, const std::uint8_t *tbl, Clip clip)
{
const auto clipY = CalculateDiamondClipY(clip);
@ -816,7 +857,7 @@ void RenderLeftTriangleClipLeftAndVertical(std::uint8_t *dst, int dstPitch, cons
const auto startX = Width - XStep * i;
const auto skip = startX < clipLeft ? clipLeft - startX : 0;
if (width > skip)
RenderLine(dst + skip, src + skip, width - skip, tbl, (*mask) << skip);
RenderLine<Transparency, Light>(dst + skip, src + skip, width - skip, tbl, (*mask) << skip);
src += width;
}
src += CalculateTriangleSourceSkipUpperBottom(clipY.upperBottom);
@ -828,11 +869,12 @@ void RenderLeftTriangleClipLeftAndVertical(std::uint8_t *dst, int dstPitch, cons
const auto startX = XStep * i;
const auto skip = startX < clipLeft ? clipLeft - startX : 0;
if (width > skip)
RenderLine(dst + skip, src + skip, width - skip, tbl, (*mask) << skip);
RenderLine<Transparency, Light>(dst + skip, src + skip, width - skip, tbl, (*mask) << skip);
src += width;
}
}
template <TransparencyType Transparency, LightType Light>
void RenderLeftTriangleClipRightAndVertical(std::uint8_t *dst, int dstPitch, const std::uint8_t *src, const std::uint32_t *mask, const std::uint8_t *tbl, Clip clip)
{
const auto clipY = CalculateDiamondClipY(clip);
@ -844,7 +886,7 @@ void RenderLeftTriangleClipRightAndVertical(std::uint8_t *dst, int dstPitch, con
src += 2 * (i % 2);
const auto width = XStep * i;
if (width > clipRight)
RenderLine(dst, src, width - clipRight, tbl, *mask);
RenderLine<Transparency, Light>(dst, src, width - clipRight, tbl, *mask);
src += width;
}
src += CalculateTriangleSourceSkipUpperBottom(clipY.upperBottom);
@ -855,40 +897,43 @@ void RenderLeftTriangleClipRightAndVertical(std::uint8_t *dst, int dstPitch, con
const auto width = Width - XStep * i;
if (width <= clipRight)
break;
RenderLine(dst, src, width - clipRight, tbl, *mask);
RenderLine<Transparency, Light>(dst, src, width - clipRight, tbl, *mask);
src += width;
}
}
template <TransparencyType Transparency, LightType Light>
void RenderLeftTriangle(std::uint8_t *dst, int dstPitch, const std::uint8_t *src, const std::uint32_t *mask, const std::uint8_t *tbl, Clip clip)
{
if (clip.width == Width) {
if (clip.height == TriangleHeight) {
RenderLeftTriangleFull(dst, dstPitch, src, mask, tbl);
RenderLeftTriangleFull<Transparency, Light>(dst, dstPitch, src, mask, tbl);
} else {
RenderLeftTriangleClipVertical(dst, dstPitch, src, mask, tbl, clip);
RenderLeftTriangleClipVertical<Transparency, Light>(dst, dstPitch, src, mask, tbl, clip);
}
} else if (clip.right == 0) {
RenderLeftTriangleClipLeftAndVertical(dst, dstPitch, src, mask, tbl, clip);
RenderLeftTriangleClipLeftAndVertical<Transparency, Light>(dst, dstPitch, src, mask, tbl, clip);
} else {
RenderLeftTriangleClipRightAndVertical(dst, dstPitch, src, mask, tbl, clip);
RenderLeftTriangleClipRightAndVertical<Transparency, Light>(dst, dstPitch, src, mask, tbl, clip);
}
}
template <TransparencyType Transparency, LightType Light>
void RenderRightTriangleFull(std::uint8_t *dst, int dstPitch, const std::uint8_t *src, const std::uint32_t *mask, const std::uint8_t *tbl)
{
for (auto i = 1; i <= LowerHeight; ++i, dst -= dstPitch, --mask) {
const auto width = XStep * i;
RenderLine(dst, src, width, tbl, *mask);
RenderLine<Transparency, Light>(dst, src, width, tbl, *mask);
src += width + 2 * (i % 2);
}
for (auto i = 1; i <= TriangleUpperHeight; ++i, dst -= dstPitch, --mask) {
const auto width = Width - XStep * i;
RenderLine(dst, src, width, tbl, *mask);
RenderLine<Transparency, Light>(dst, src, width, tbl, *mask);
src += width + 2 * (i % 2);
}
}
template <TransparencyType Transparency, LightType Light>
void RenderRightTriangleClipVertical(std::uint8_t *dst, int dstPitch, const std::uint8_t *src, const std::uint32_t *mask, const std::uint8_t *tbl, Clip clip)
{
const auto clipY = CalculateDiamondClipY(clip);
@ -896,18 +941,19 @@ void RenderRightTriangleClipVertical(std::uint8_t *dst, int dstPitch, const std:
const auto lowerMax = LowerHeight - clipY.lowerTop;
for (auto i = 1 + clipY.lowerBottom; i <= lowerMax; ++i, dst -= dstPitch, --mask) {
const auto width = XStep * i;
RenderLine(dst, src, width, tbl, *mask);
RenderLine<Transparency, Light>(dst, src, width, tbl, *mask);
src += width + 2 * (i % 2);
}
src += CalculateTriangleSourceSkipUpperBottom(clipY.upperBottom);
const auto upperMax = TriangleUpperHeight - clipY.upperTop;
for (auto i = 1 + clipY.upperBottom; i <= upperMax; ++i, dst -= dstPitch, --mask) {
const auto width = Width - XStep * i;
RenderLine(dst, src, width, tbl, *mask);
RenderLine<Transparency, Light>(dst, src, width, tbl, *mask);
src += width + 2 * (i % 2);
}
}
template <TransparencyType Transparency, LightType Light>
void RenderRightTriangleClipLeftAndVertical(std::uint8_t *dst, int dstPitch, const std::uint8_t *src, const std::uint32_t *mask, const std::uint8_t *tbl, Clip clip)
{
const auto clipY = CalculateDiamondClipY(clip);
@ -917,7 +963,7 @@ void RenderRightTriangleClipLeftAndVertical(std::uint8_t *dst, int dstPitch, con
for (auto i = 1 + clipY.lowerBottom; i <= lowerMax; ++i, dst -= dstPitch, --mask) {
const auto width = XStep * i;
if (width > clipLeft)
RenderLine(dst, src + clipLeft, width - clipLeft, tbl, (*mask) << clipLeft);
RenderLine<Transparency, Light>(dst, src + clipLeft, width - clipLeft, tbl, (*mask) << clipLeft);
src += width + 2 * (i % 2);
}
src += CalculateTriangleSourceSkipUpperBottom(clipY.upperBottom);
@ -926,11 +972,12 @@ void RenderRightTriangleClipLeftAndVertical(std::uint8_t *dst, int dstPitch, con
const auto width = Width - XStep * i;
if (width <= clipLeft)
break;
RenderLine(dst, src + clipLeft, width - clipLeft, tbl, (*mask) << clipLeft);
RenderLine<Transparency, Light>(dst, src + clipLeft, width - clipLeft, tbl, (*mask) << clipLeft);
src += width + 2 * (i % 2);
}
}
template <TransparencyType Transparency, LightType Light>
void RenderRightTriangleClipRightAndVertical(std::uint8_t *dst, int dstPitch, const std::uint8_t *src, const std::uint32_t *mask, const std::uint8_t *tbl, Clip clip)
{
const auto clipY = CalculateDiamondClipY(clip);
@ -941,7 +988,7 @@ void RenderRightTriangleClipRightAndVertical(std::uint8_t *dst, int dstPitch, co
const auto width = XStep * i;
const auto skip = Width - width < clipRight ? clipRight - (Width - width) : 0;
if (width > skip)
RenderLine(dst, src, width - skip, tbl, *mask);
RenderLine<Transparency, Light>(dst, src, width - skip, tbl, *mask);
src += width + 2 * (i % 2);
}
src += CalculateTriangleSourceSkipUpperBottom(clipY.upperBottom);
@ -950,42 +997,45 @@ void RenderRightTriangleClipRightAndVertical(std::uint8_t *dst, int dstPitch, co
const auto width = Width - XStep * i;
const auto skip = Width - width < clipRight ? clipRight - (Width - width) : 0;
if (width > skip)
RenderLine(dst, src, width - skip, tbl, *mask);
RenderLine<Transparency, Light>(dst, src, width - skip, tbl, *mask);
src += width + 2 * (i % 2);
}
}
template <TransparencyType Transparency, LightType Light>
void RenderRightTriangle(std::uint8_t *dst, int dstPitch, const std::uint8_t *src, const std::uint32_t *mask, const std::uint8_t *tbl, Clip clip)
{
if (clip.width == Width) {
if (clip.height == TriangleHeight) {
RenderRightTriangleFull(dst, dstPitch, src, mask, tbl);
RenderRightTriangleFull<Transparency, Light>(dst, dstPitch, src, mask, tbl);
} else {
RenderRightTriangleClipVertical(dst, dstPitch, src, mask, tbl, clip);
RenderRightTriangleClipVertical<Transparency, Light>(dst, dstPitch, src, mask, tbl, clip);
}
} else if (clip.right == 0) {
RenderRightTriangleClipLeftAndVertical(dst, dstPitch, src, mask, tbl, clip);
RenderRightTriangleClipLeftAndVertical<Transparency, Light>(dst, dstPitch, src, mask, tbl, clip);
} else {
RenderRightTriangleClipRightAndVertical(dst, dstPitch, src, mask, tbl, clip);
RenderRightTriangleClipRightAndVertical<Transparency, Light>(dst, dstPitch, src, mask, tbl, clip);
}
}
template <TransparencyType Transparency, LightType Light>
void RenderLeftTrapezoidFull(std::uint8_t *dst, int dstPitch, const std::uint8_t *src, const std::uint32_t *mask, const std::uint8_t *tbl)
{
dst += XStep * (LowerHeight - 1);
for (auto i = 1; i <= LowerHeight; ++i, dst -= dstPitch + XStep, --mask) {
src += 2 * (i % 2);
const auto width = XStep * i;
RenderLine(dst, src, width, tbl, *mask);
RenderLine<Transparency, Light>(dst, src, width, tbl, *mask);
src += width;
}
dst += XStep;
for (auto i = 1; i <= TrapezoidUpperHeight; ++i, dst -= dstPitch, --mask) {
RenderLine(dst, src, Width, tbl, *mask);
RenderLine<Transparency, Light>(dst, src, Width, tbl, *mask);
src += Width;
}
}
template <TransparencyType Transparency, LightType Light>
void RenderLeftTrapezoidClipVertical(std::uint8_t *dst, int dstPitch, const std::uint8_t *src, const std::uint32_t *mask, const std::uint8_t *tbl, Clip clip)
{
const auto clipY = CalculateDiamondClipY<TrapezoidUpperHeight>(clip);
@ -995,18 +1045,19 @@ void RenderLeftTrapezoidClipVertical(std::uint8_t *dst, int dstPitch, const std:
for (auto i = 1 + clipY.lowerBottom; i <= lowerMax; ++i, dst -= dstPitch + XStep, --mask) {
src += 2 * (i % 2);
const auto width = XStep * i;
RenderLine(dst, src, width, tbl, *mask);
RenderLine<Transparency, Light>(dst, src, width, tbl, *mask);
src += width;
}
src += clipY.upperBottom * Width;
dst += XStep;
const auto upperMax = TrapezoidUpperHeight - clipY.upperTop;
for (auto i = 1 + clipY.upperBottom; i <= upperMax; ++i, dst -= dstPitch, --mask) {
RenderLine(dst, src, Width, tbl, *mask);
RenderLine<Transparency, Light>(dst, src, Width, tbl, *mask);
src += Width;
}
}
template <TransparencyType Transparency, LightType Light>
void RenderLeftTrapezoidClipLeftAndVertical(std::uint8_t *dst, int dstPitch, const std::uint8_t *src, const std::uint32_t *mask, const std::uint8_t *tbl, Clip clip)
{
const auto clipY = CalculateDiamondClipY<TrapezoidUpperHeight>(clip);
@ -1020,18 +1071,19 @@ void RenderLeftTrapezoidClipLeftAndVertical(std::uint8_t *dst, int dstPitch, con
const auto startX = Width - XStep * i;
const auto skip = startX < clipLeft ? clipLeft - startX : 0;
if (width > skip)
RenderLine(dst + skip, src + skip, width - skip, tbl, (*mask) << skip);
RenderLine<Transparency, Light>(dst + skip, src + skip, width - skip, tbl, (*mask) << skip);
src += width;
}
src += clipY.upperBottom * Width + clipLeft;
dst += XStep + clipLeft;
const auto upperMax = TrapezoidUpperHeight - clipY.upperTop;
for (auto i = 1 + clipY.upperBottom; i <= upperMax; ++i, dst -= dstPitch, --mask) {
RenderLine(dst, src, clip.width, tbl, (*mask) << clipLeft);
RenderLine<Transparency, Light>(dst, src, clip.width, tbl, (*mask) << clipLeft);
src += Width;
}
}
template <TransparencyType Transparency, LightType Light>
void RenderLeftTrapezoidClipRightAndVertical(std::uint8_t *dst, int dstPitch, const std::uint8_t *src, const std::uint32_t *mask, const std::uint8_t *tbl, Clip clip)
{
const auto clipY = CalculateDiamondClipY<TrapezoidUpperHeight>(clip);
@ -1043,46 +1095,49 @@ void RenderLeftTrapezoidClipRightAndVertical(std::uint8_t *dst, int dstPitch, co
src += 2 * (i % 2);
const auto width = XStep * i;
if (width > clipRight)
RenderLine(dst, src, width - clipRight, tbl, *mask);
RenderLine<Transparency, Light>(dst, src, width - clipRight, tbl, *mask);
src += width;
}
src += clipY.upperBottom * Width;
dst += XStep;
const auto upperMax = TrapezoidUpperHeight - clipY.upperTop;
for (auto i = 1 + clipY.upperBottom; i <= upperMax; ++i, dst -= dstPitch, --mask) {
RenderLine(dst, src, clip.width, tbl, *mask);
RenderLine<Transparency, Light>(dst, src, clip.width, tbl, *mask);
src += Width;
}
}
template <TransparencyType Transparency, LightType Light>
void RenderLeftTrapezoid(std::uint8_t *dst, int dstPitch, const std::uint8_t *src, const std::uint32_t *mask, const std::uint8_t *tbl, Clip clip)
{
if (clip.width == Width) {
if (clip.height == Height) {
RenderLeftTrapezoidFull(dst, dstPitch, src, mask, tbl);
RenderLeftTrapezoidFull<Transparency, Light>(dst, dstPitch, src, mask, tbl);
} else {
RenderLeftTrapezoidClipVertical(dst, dstPitch, src, mask, tbl, clip);
RenderLeftTrapezoidClipVertical<Transparency, Light>(dst, dstPitch, src, mask, tbl, clip);
}
} else if (clip.right == 0) {
RenderLeftTrapezoidClipLeftAndVertical(dst, dstPitch, src, mask, tbl, clip);
RenderLeftTrapezoidClipLeftAndVertical<Transparency, Light>(dst, dstPitch, src, mask, tbl, clip);
} else {
RenderLeftTrapezoidClipRightAndVertical(dst, dstPitch, src, mask, tbl, clip);
RenderLeftTrapezoidClipRightAndVertical<Transparency, Light>(dst, dstPitch, src, mask, tbl, clip);
}
}
template <TransparencyType Transparency, LightType Light>
void RenderRightTrapezoidFull(std::uint8_t *dst, int dstPitch, const std::uint8_t *src, const std::uint32_t *mask, const std::uint8_t *tbl)
{
for (auto i = 1; i <= LowerHeight; ++i, dst -= dstPitch, --mask) {
const auto width = XStep * i;
RenderLine(dst, src, width, tbl, *mask);
RenderLine<Transparency, Light>(dst, src, width, tbl, *mask);
src += width + 2 * (i % 2);
}
for (auto i = 1; i <= TrapezoidUpperHeight; ++i, dst -= dstPitch, --mask) {
RenderLine(dst, src, Width, tbl, *mask);
RenderLine<Transparency, Light>(dst, src, Width, tbl, *mask);
src += Width;
}
}
template <TransparencyType Transparency, LightType Light>
void RenderRightTrapezoidClipVertical(std::uint8_t *dst, int dstPitch, const std::uint8_t *src, const std::uint32_t *mask, const std::uint8_t *tbl, Clip clip)
{
const auto clipY = CalculateDiamondClipY<TrapezoidUpperHeight>(clip);
@ -1090,17 +1145,18 @@ void RenderRightTrapezoidClipVertical(std::uint8_t *dst, int dstPitch, const std
src += CalculateTriangleSourceSkipLowerBottom(clipY.lowerBottom);
for (auto i = 1 + clipY.lowerBottom; i <= lowerMax; ++i, dst -= dstPitch, --mask) {
const auto width = XStep * i;
RenderLine(dst, src, width, tbl, *mask);
RenderLine<Transparency, Light>(dst, src, width, tbl, *mask);
src += width + 2 * (i % 2);
}
src += clipY.upperBottom * Width;
const auto upperMax = TrapezoidUpperHeight - clipY.upperTop;
for (auto i = 1 + clipY.upperBottom; i <= upperMax; ++i, dst -= dstPitch, --mask) {
RenderLine(dst, src, Width, tbl, *mask);
RenderLine<Transparency, Light>(dst, src, Width, tbl, *mask);
src += Width;
}
}
template <TransparencyType Transparency, LightType Light>
void RenderRightTrapezoidClipLeftAndVertical(std::uint8_t *dst, int dstPitch, const std::uint8_t *src, const std::uint32_t *mask, const std::uint8_t *tbl, Clip clip)
{
const auto clipY = CalculateDiamondClipY<TrapezoidUpperHeight>(clip);
@ -1110,17 +1166,18 @@ void RenderRightTrapezoidClipLeftAndVertical(std::uint8_t *dst, int dstPitch, co
for (auto i = 1 + clipY.lowerBottom; i <= lowerMax; ++i, dst -= dstPitch, --mask) {
const auto width = XStep * i;
if (width > clipLeft)
RenderLine(dst, src + clipLeft, width - clipLeft, tbl, (*mask) << clipLeft);
RenderLine<Transparency, Light>(dst, src + clipLeft, width - clipLeft, tbl, (*mask) << clipLeft);
src += width + 2 * (i % 2);
}
src += clipY.upperBottom * Width + clipLeft;
const auto upperMax = TrapezoidUpperHeight - clipY.upperTop;
for (auto i = 1 + clipY.upperBottom; i <= upperMax; ++i, dst -= dstPitch, --mask) {
RenderLine(dst, src, clip.width, tbl, (*mask) << clipLeft);
RenderLine<Transparency, Light>(dst, src, clip.width, tbl, (*mask) << clipLeft);
src += Width;
}
}
template <TransparencyType Transparency, LightType Light>
void RenderRightTrapezoidClipRightAndVertical(std::uint8_t *dst, int dstPitch, const std::uint8_t *src, const std::uint32_t *mask, const std::uint8_t *tbl, Clip clip)
{
const auto clipY = CalculateDiamondClipY<TrapezoidUpperHeight>(clip);
@ -1131,29 +1188,55 @@ void RenderRightTrapezoidClipRightAndVertical(std::uint8_t *dst, int dstPitch, c
const auto width = XStep * i;
const auto skip = Width - width < clipRight ? clipRight - (Width - width) : 0;
if (width > skip)
RenderLine(dst, src, width - skip, tbl, *mask);
RenderLine<Transparency, Light>(dst, src, width - skip, tbl, *mask);
src += width + 2 * (i % 2);
}
src += clipY.upperBottom * Width;
const auto upperMax = TrapezoidUpperHeight - clipY.upperTop;
for (auto i = 1 + clipY.upperBottom; i <= upperMax; ++i, dst -= dstPitch, --mask) {
RenderLine(dst, src, clip.width, tbl, *mask);
RenderLine<Transparency, Light>(dst, src, clip.width, tbl, *mask);
src += Width;
}
}
template <TransparencyType Transparency, LightType Light>
void RenderRightTrapezoid(std::uint8_t *dst, int dstPitch, const std::uint8_t *src, const std::uint32_t *mask, const std::uint8_t *tbl, Clip clip)
{
if (clip.width == Width) {
if (clip.height == Height) {
RenderRightTrapezoidFull(dst, dstPitch, src, mask, tbl);
RenderRightTrapezoidFull<Transparency, Light>(dst, dstPitch, src, mask, tbl);
} else {
RenderRightTrapezoidClipVertical(dst, dstPitch, src, mask, tbl, clip);
RenderRightTrapezoidClipVertical<Transparency, Light>(dst, dstPitch, src, mask, tbl, clip);
}
} else if (clip.right == 0) {
RenderRightTrapezoidClipLeftAndVertical(dst, dstPitch, src, mask, tbl, clip);
RenderRightTrapezoidClipLeftAndVertical<Transparency, Light>(dst, dstPitch, src, mask, tbl, clip);
} else {
RenderRightTrapezoidClipRightAndVertical(dst, dstPitch, src, mask, tbl, clip);
RenderRightTrapezoidClipRightAndVertical<Transparency, Light>(dst, dstPitch, src, mask, tbl, clip);
}
}
template <TransparencyType Transparency, LightType Light>
void RenderTileType(TileType tile, std::uint8_t *dst, int dstPitch, const std::uint8_t *src, const std::uint32_t *mask, const std::uint8_t *tbl, Clip clip)
{
switch (tile) {
case TileType::Square:
RenderSquare<Transparency, Light>(dst, dstPitch, src, mask, tbl, clip);
break;
case TileType::TransparentSquare:
RenderTransparentSquare<Transparency, Light>(dst, dstPitch, src, mask, tbl, clip);
break;
case TileType::LeftTriangle:
RenderLeftTriangle<Transparency, Light>(dst, dstPitch, src, mask, tbl, clip);
break;
case TileType::RightTriangle:
RenderRightTriangle<Transparency, Light>(dst, dstPitch, src, mask, tbl, clip);
break;
case TileType::LeftTrapezoid:
RenderLeftTrapezoid<Transparency, Light>(dst, dstPitch, src, mask, tbl, clip);
break;
case TileType::RightTrapezoid:
RenderRightTrapezoid<Transparency, Light>(dst, dstPitch, src, mask, tbl, clip);
break;
}
}
@ -1317,27 +1400,34 @@ void RenderTile(const CelOutputBuffer &out, int x, int y)
const auto *src = reinterpret_cast<const std::uint8_t *>(&pDungeonCels[SDL_SwapLE32(pFrameTable[level_cel_block & 0xFFF])]);
std::uint8_t *dst = out.at(static_cast<int>(x + clip.left), static_cast<int>(y - clip.bottom));
const auto dstPitch = out.pitch();
mask -= clip.bottom;
switch (tile) {
case TileType::Square:
RenderSquare(dst, dstPitch, src, mask, tbl, clip);
break;
case TileType::TransparentSquare:
RenderTransparentSquare(dst, dstPitch, src, mask, tbl, clip);
break;
case TileType::LeftTriangle:
RenderLeftTriangle(dst, dstPitch, src, mask, tbl, clip);
break;
case TileType::RightTriangle:
RenderRightTriangle(dst, dstPitch, src, mask, tbl, clip);
break;
case TileType::LeftTrapezoid:
RenderLeftTrapezoid(dst, dstPitch, src, mask, tbl, clip);
break;
case TileType::RightTrapezoid:
RenderRightTrapezoid(dst, dstPitch, src, mask, tbl, clip);
break;
if (mask == &SolidMask[TILE_HEIGHT - 1]) {
if (light_table_index == lightmax) {
RenderTileType<TransparencyType::Solid, LightType::FullyDark>(tile, dst, dstPitch, src, mask, tbl, clip);
} else if (light_table_index == 0) {
RenderTileType<TransparencyType::Solid, LightType::FullyLit>(tile, dst, dstPitch, src, mask, tbl, clip);
} else {
RenderTileType<TransparencyType::Solid, LightType::PartiallyLit>(tile, dst, dstPitch, src, mask, tbl, clip);
}
} else {
mask -= clip.bottom;
if (sgOptions.Graphics.bBlendedTransparancy) {
if (light_table_index == lightmax) {
RenderTileType<TransparencyType::Blended, LightType::FullyDark>(tile, dst, dstPitch, src, mask, tbl, clip);
} else if (light_table_index == 0) {
RenderTileType<TransparencyType::Blended, LightType::FullyLit>(tile, dst, dstPitch, src, mask, tbl, clip);
} else {
RenderTileType<TransparencyType::Blended, LightType::PartiallyLit>(tile, dst, dstPitch, src, mask, tbl, clip);
}
} else {
if (light_table_index == lightmax) {
RenderTileType<TransparencyType::Stippled, LightType::FullyDark>(tile, dst, dstPitch, src, mask, tbl, clip);
} else if (light_table_index == 0) {
RenderTileType<TransparencyType::Stippled, LightType::FullyLit>(tile, dst, dstPitch, src, mask, tbl, clip);
} else {
RenderTileType<TransparencyType::Stippled, LightType::PartiallyLit>(tile, dst, dstPitch, src, mask, tbl, clip);
}
}
}
}

Loading…
Cancel
Save