Browse Source

Stip stippled transparency

pull/3817/merge
Anders Jenbo 4 years ago
parent
commit
b6bdbcfc98
  1. 20
      Source/engine.cpp
  2. 31
      Source/engine/render/cel_render.cpp
  3. 2
      Source/engine/render/cel_render.hpp
  4. 156
      Source/engine/render/dun_render.cpp
  5. 8
      Source/options.cpp
  6. 2
      Source/options.h
  7. 32
      Source/palette.cpp

20
Source/engine.cpp

@ -87,20 +87,6 @@ void DrawHalfTransparentBlendedRectTo(const Surface &out, unsigned sx, unsigned
// Now everything is divisible by 4. Draw the aligned part.
DrawHalfTransparentAligned32BlendedRectTo(out, sx, sy, width, height);
}
void DrawHalfTransparentStippledRectTo(const Surface &out, int sx, int sy, int width, int height)
{
BYTE *pix = out.at(sx, sy);
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
if (((row & 1) != 0 && (col & 1) != 0) || ((row & 1) == 0 && (col & 1) == 0))
*pix = 0;
pix++;
}
pix += out.pitch() - width;
}
}
} // namespace
void DrawHorizontalLine(const Surface &out, Point from, int width, std::uint8_t colorIndex)
@ -169,11 +155,7 @@ void DrawHalfTransparentRectTo(const Surface &out, int sx, int sy, int width, in
height = out.h() - sy;
}
if (*sgOptions.Graphics.blendedTransparancy) {
DrawHalfTransparentBlendedRectTo(out, sx, sy, width, height);
} else {
DrawHalfTransparentStippledRectTo(out, sx, sy, width, height);
}
DrawHalfTransparentBlendedRectTo(out, sx, sy, width, height);
}
/**

31
Source/engine/render/cel_render.cpp

@ -537,32 +537,6 @@ void CelBlitSafeTo(const Surface &out, Point position, const byte *pRLEBytes, in
RenderCel(out, position, pRLEBytes, nDataSize, nWidth, RenderLineMemcpy, NullLineEndFn);
}
/**
* @brief Same as CelBlitLightSafeTo but with stippled transparency applied
* @param out Target buffer
* @param position Target buffer coordinate
* @param pRLEBytes CEL pixel stream (run-length encoded)
* @param nDataSize Size of CEL in bytes
*/
void CelBlitLightTransSafeTo(const Surface &out, Point position, const byte *pRLEBytes, int nDataSize, int nWidth)
{
assert(pRLEBytes != nullptr);
const std::uint8_t *tbl = &LightTables[LightTableIndex * 256];
bool shift = (reinterpret_cast<uintptr_t>(&out[position]) % 2 == 1);
const bool pitchIsEven = (out.pitch() % 2 == 0);
RenderCel(
out, position, pRLEBytes, nDataSize, nWidth,
[tbl, &shift](std::uint8_t *dst, const std::uint8_t *src, std::size_t width) {
if (reinterpret_cast<uintptr_t>(dst) % 2 == (shift ? 1 : 0)) {
++dst, ++src, --width;
}
for (const auto *dstEnd = dst + width; dst < dstEnd; dst += 2, src += 2) {
*dst = tbl[*src];
}
},
[pitchIsEven, &shift]() { if (pitchIsEven) shift = !shift; });
}
/**
* @brief Same as CelBlitLightSafe, with blended transparency applied
* @param out The output buffer
@ -665,10 +639,7 @@ void CelClippedBlitLightTransTo(const Surface &out, Point position, const CelSpr
const byte *pRLEBytes = CelGetFrameClipped(cel.Data(), frame, &nDataSize);
if (cel_transparency_active) {
if (*sgOptions.Graphics.blendedTransparancy)
CelBlitLightBlendedSafeTo(out, position, pRLEBytes, nDataSize, cel.Width(frame), nullptr);
else
CelBlitLightTransSafeTo(out, position, pRLEBytes, nDataSize, cel.Width(frame));
CelBlitLightBlendedSafeTo(out, position, pRLEBytes, nDataSize, cel.Width(frame), nullptr);
} else if (LightTableIndex != 0)
CelBlitLightSafeTo(out, position, pRLEBytes, nDataSize, cel.Width(frame), nullptr);
else

2
Source/engine/render/cel_render.hpp

@ -66,7 +66,7 @@ void CelDrawLightTo(const Surface &out, Point position, const CelSprite &cel, in
void CelClippedDrawLightTo(const Surface &out, Point position, const CelSprite &cel, int frame);
/**
* @brief Same as CelBlitLightTransSafeTo
* @brief Same as CelBlitLightSafeTo but with transparency applied
* @param out Target buffer
* @param position Target buffer coordinate
* @param cel CEL sprite

156
Source/engine/render/dun_render.cpp

@ -239,111 +239,6 @@ const std::uint32_t LeftMaskTransparent[TILE_HEIGHT] = {
0xFFFFFFFF,
0xFFFFFFFF
};
/** Specifies the draw masks used to render transparency of the right side of tiles. */
const std::uint32_t RightMask[TILE_HEIGHT] = {
0xEAAAAAAA,
0xF5555555,
0xFEAAAAAA,
0xFF555555,
0xFFEAAAAA,
0xFFF55555,
0xFFFEAAAA,
0xFFFF5555,
0xFFFFEAAA,
0xFFFFF555,
0xFFFFFEAA,
0xFFFFFF55,
0xFFFFFFEA,
0xFFFFFFF5,
0xFFFFFFFE,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF
};
/** Specifies the draw masks used to render transparency of the left side of tiles. */
const std::uint32_t LeftMask[TILE_HEIGHT] = {
0xAAAAAAAB,
0x5555555F,
0xAAAAAABF,
0x555555FF,
0xAAAAABFF,
0x55555FFF,
0xAAAABFFF,
0x5555FFFF,
0xAAABFFFF,
0x555FFFFF,
0xAABFFFFF,
0x55FFFFFF,
0xABFFFFFF,
0x5FFFFFFF,
0xBFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF
};
/** Specifies the draw masks used to render transparency of wall tiles. */
const std::uint32_t WallMask[TILE_HEIGHT] = {
0xAAAAAAAA,
0x55555555,
0xAAAAAAAA,
0x55555555,
0xAAAAAAAA,
0x55555555,
0xAAAAAAAA,
0x55555555,
0xAAAAAAAA,
0x55555555,
0xAAAAAAAA,
0x55555555,
0xAAAAAAAA,
0x55555555,
0xAAAAAAAA,
0x55555555,
0xAAAAAAAA,
0x55555555,
0xAAAAAAAA,
0x55555555,
0xAAAAAAAA,
0x55555555,
0xAAAAAAAA,
0x55555555,
0xAAAAAAAA,
0x55555555,
0xAAAAAAAA,
0x55555555,
0xAAAAAAAA,
0x55555555,
0xAAAAAAAA,
0x55555555
};
/** Fully opaque mask */
const std::uint32_t SolidMask[TILE_HEIGHT] = {
0xFFFFFFFF,
@ -491,7 +386,6 @@ DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void ForEachSetBit(std::uint32_t mask, const
enum class TransparencyType {
Solid,
Blended,
Stippled,
};
enum class LightType {
@ -558,22 +452,6 @@ DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderLineBlended(std::uint8_t *dst, co
#endif
}
template <LightType Light>
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderLineStippled(std::uint8_t *dst, const std::uint8_t *src, 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]; });
#else
ForEachSetBit(mask, [=](int i) { dst[i] = DBGCOLOR; });
#endif
} else { // Partially lit
ForEachSetBit(mask, [=](int i) { dst[i] = tbl[src[i]]; });
}
}
template <TransparencyType Transparency, LightType Light>
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT 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)
{
@ -591,8 +469,6 @@ DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderLine(std::uint8_t *dst, const std
RenderLineOpaque<Light>(dst, src, n, tbl);
} else if (Transparency == TransparencyType::Blended) {
RenderLineBlended<Light>(dst, src, n, tbl, mask);
} else {
RenderLineStippled<Light>(dst, src, tbl, mask);
}
}
}
@ -1252,24 +1128,18 @@ const std::uint32_t *GetMask(TileType tile)
if (cel_transparency_active) {
if (arch_draw_type == 0) {
if (*sgOptions.Graphics.blendedTransparancy) // Use a fully transparent mask
return &WallMaskFullyTrasparent[TILE_HEIGHT - 1];
return &WallMask[TILE_HEIGHT - 1];
return &WallMaskFullyTrasparent[TILE_HEIGHT - 1];
}
if (arch_draw_type == 1 && tile != TileType::LeftTriangle) {
const auto c = block_lvid[level_piece_id];
if (c == 1 || c == 3) {
if (*sgOptions.Graphics.blendedTransparancy) // Use a fully transparent mask
return &LeftMaskTransparent[TILE_HEIGHT - 1];
return &LeftMask[TILE_HEIGHT - 1];
return &LeftMaskTransparent[TILE_HEIGHT - 1];
}
}
if (arch_draw_type == 2 && tile != TileType::RightTriangle) {
const auto c = block_lvid[level_piece_id];
if (c == 2 || c == 3) {
if (*sgOptions.Graphics.blendedTransparancy) // Use a fully transparent mask
return &RightMaskTransparent[TILE_HEIGHT - 1];
return &RightMask[TILE_HEIGHT - 1];
return &RightMaskTransparent[TILE_HEIGHT - 1];
}
}
} else if (arch_draw_type != 0 && cel_foliage_active) {
@ -1412,22 +1282,12 @@ void RenderTile(const Surface &out, Point position)
}
} else {
mask -= clip.bottom;
if (*sgOptions.Graphics.blendedTransparancy) {
if (LightTableIndex == LightsMax) {
RenderTileType<TransparencyType::Blended, LightType::FullyDark>(tile, dst, dstPitch, src, mask, tbl, clip);
} else if (LightTableIndex == 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);
}
if (LightTableIndex == LightsMax) {
RenderTileType<TransparencyType::Blended, LightType::FullyDark>(tile, dst, dstPitch, src, mask, tbl, clip);
} else if (LightTableIndex == 0) {
RenderTileType<TransparencyType::Blended, LightType::FullyLit>(tile, dst, dstPitch, src, mask, tbl, clip);
} else {
if (LightTableIndex == LightsMax) {
RenderTileType<TransparencyType::Stippled, LightType::FullyDark>(tile, dst, dstPitch, src, mask, tbl, clip);
} else if (LightTableIndex == 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);
}
RenderTileType<TransparencyType::Blended, LightType::PartiallyLit>(tile, dst, dstPitch, src, mask, tbl, clip);
}
}
}

8
Source/options.cpp

@ -179,12 +179,6 @@ void SetIniValue(const char *keyname, const char *valuename, int value)
GetIni().SetLongValue(keyname, valuename, value, nullptr, false, true);
}
void SetIniValue(const char *keyname, const char *valuename, std::uint8_t value)
{
IniChangedChecker changedChecker(keyname, valuename);
GetIni().SetLongValue(keyname, valuename, value, nullptr, false, true);
}
void SetIniValue(const char *keyname, const char *valuename, std::uint32_t value)
{
IniChangedChecker changedChecker(keyname, valuename);
@ -780,7 +774,6 @@ GraphicsOptions::GraphicsOptions()
, integerScaling("Integer Scaling", OptionEntryFlags::CantChangeInGame | OptionEntryFlags::RecreateUI, N_("Integer Scaling"), N_("Scales the image using whole number pixel ratio."), false)
, vSync("Vertical Sync", OptionEntryFlags::RecreateUI, N_("Vertical Sync"), N_("Forces waiting for Vertical Sync. Prevents tearing effect when drawing a frame. Disabling it can help with mouse lag on some systems."), true)
#endif
, blendedTransparancy("Blended Transparency", OptionEntryFlags::CantChangeInGame, N_("Blended Transparency"), N_("Enables uniform transparency mode. This setting affects the transparency on walls, game text menus, and boxes. If disabled will default to old checkerboard transparency."), true)
, colorCycling("Color Cycling", OptionEntryFlags::None, N_("Color Cycling"), N_("Color cycling effect used for water, lava, and acid animation."), true)
#if SDL_VERSION_ATLEAST(2, 0, 0)
, hardwareCursor("Hardware Cursor", OptionEntryFlags::CantChangeInGame | OptionEntryFlags::RecreateUI | (HardwareCursorSupported() ? OptionEntryFlags::None : OptionEntryFlags::Invisible), N_("Hardware Cursor"), N_("Use a hardware cursor"), HardwareCursorDefault())
@ -820,7 +813,6 @@ std::vector<OptionEntryBase *> GraphicsOptions::GetEntries()
&integerScaling,
&vSync,
#endif
&blendedTransparancy,
&colorCycling,
#if SDL_VERSION_ATLEAST(2, 0, 0)
&hardwareCursor,

2
Source/options.h

@ -390,8 +390,6 @@ struct GraphicsOptions : OptionCategoryBase {
/** @brief Enable vsync on the output. */
OptionEntryBoolean vSync;
#endif
/** @brief Use blended transparency rather than stippled. */
OptionEntryBoolean blendedTransparancy;
/** @brief Gamma correction level. */
int nGammaCorrection;
/** @brief Enable color cycling animations. */

32
Source/palette.cpp

@ -118,9 +118,6 @@ void CycleColors(int from, int to)
system_palette[to] = col;
}
if (!*sgOptions.Graphics.blendedTransparancy)
return;
for (auto &palette : paletteTransparencyLookup) {
Uint8 col = palette[from];
for (int j = from; j < to; j++) {
@ -152,9 +149,6 @@ void CycleColorsReverse(int from, int to)
system_palette[from] = col;
}
if (!*sgOptions.Graphics.blendedTransparancy)
return;
for (auto &palette : paletteTransparencyLookup) {
Uint8 col = palette[to];
for (int j = to; j > from; j--) {
@ -224,7 +218,7 @@ void LoadPalette(const char *pszFileName, bool blend /*= true*/)
#endif
}
if (blend && *sgOptions.Graphics.blendedTransparancy) {
if (blend) {
if (leveltype == DTYPE_CAVES || leveltype == DTYPE_CRYPT) {
GenerateBlendedLookupTable(orig_palette, 1, 31);
} else if (leveltype == DTYPE_NEST) {
@ -407,20 +401,18 @@ void palette_update_quest_palette(int n)
logical_palette[i] = orig_palette[i];
ApplyGamma(system_palette, logical_palette, 32);
palette_update(0, 31);
if (*sgOptions.Graphics.blendedTransparancy) {
// Update blended transparency, but only for the color that was updated
for (int j = 0; j < 256; j++) {
if (i == j) { // No need to calculate transparency between 2 identical colors
paletteTransparencyLookup[i][j] = j;
continue;
}
SDL_Color blendedColor;
blendedColor.r = ((int)logical_palette[i].r + (int)logical_palette[j].r) / 2;
blendedColor.g = ((int)logical_palette[i].g + (int)logical_palette[j].g) / 2;
blendedColor.b = ((int)logical_palette[i].b + (int)logical_palette[j].b) / 2;
Uint8 best = FindBestMatchForColor(logical_palette, blendedColor, 1, 31);
paletteTransparencyLookup[i][j] = paletteTransparencyLookup[j][i] = best;
// Update blended transparency, but only for the color that was updated
for (int j = 0; j < 256; j++) {
if (i == j) { // No need to calculate transparency between 2 identical colors
paletteTransparencyLookup[i][j] = j;
continue;
}
SDL_Color blendedColor;
blendedColor.r = ((int)logical_palette[i].r + (int)logical_palette[j].r) / 2;
blendedColor.g = ((int)logical_palette[i].g + (int)logical_palette[j].g) / 2;
blendedColor.b = ((int)logical_palette[i].b + (int)logical_palette[j].b) / 2;
Uint8 best = FindBestMatchForColor(logical_palette, blendedColor, 1, 31);
paletteTransparencyLookup[i][j] = paletteTransparencyLookup[j][i] = best;
}
}

Loading…
Cancel
Save