# HG changeset patch # User Peter Nelson # Date 2023-12-22 16:01:33 # Node ID f8a96633c3814838e72e3a2a4ca235f19025dbbe # Parent 65e120920a52ecabd32367654d0d397f8864053d Change: Support custom transparency remaps with 32bpp blitters. This closes a 15 year old TODO... diff --git a/src/blitter/32bpp_anim.cpp b/src/blitter/32bpp_anim.cpp --- a/src/blitter/32bpp_anim.cpp +++ b/src/blitter/32bpp_anim.cpp @@ -9,6 +9,7 @@ #include "../stdafx.h" #include "../video/video_driver.hpp" +#include "../palette_func.h" #include "32bpp_anim.hpp" #include "common.hpp" @@ -190,10 +191,6 @@ inline void Blitter_32bppAnim::Draw(cons break; case BM_TRANSPARENT: - /* TODO -- We make an assumption here that the remap in fact is transparency, not some colour. - * This is never a problem with the code we produce, but newgrfs can make it fail... or at least: - * we produce a result the newgrf maker didn't expect ;) */ - /* Make the current colour a bit more black, so it looks like this image is transparent */ src_n += n; if (src_px->a == 255) { @@ -215,6 +212,24 @@ inline void Blitter_32bppAnim::Draw(cons } break; + case BM_TRANSPARENT_REMAP: + /* Apply custom transparency remap. */ + src_n += n; + if (src_px->a != 0) { + src_px += n; + do { + *dst = this->LookupColourInPalette(bp->remap[GetNearestColourIndex(*dst)]); + *anim = 0; + anim++; + dst++; + } while (--n != 0); + } else { + dst += n; + anim += n; + src_px += n; + } + break; + default: if (src_px->a == 255) { do { @@ -264,6 +279,7 @@ void Blitter_32bppAnim::Draw(Blitter::Bl case BM_NORMAL: Draw (bp, zoom); return; case BM_COLOUR_REMAP: Draw(bp, zoom); return; case BM_TRANSPARENT: Draw (bp, zoom); return; + case BM_TRANSPARENT_REMAP: Draw(bp, zoom); return; case BM_CRASH_REMAP: Draw (bp, zoom); return; case BM_BLACK_REMAP: Draw (bp, zoom); return; } diff --git a/src/blitter/32bpp_anim_sse4.cpp b/src/blitter/32bpp_anim_sse4.cpp --- a/src/blitter/32bpp_anim_sse4.cpp +++ b/src/blitter/32bpp_anim_sse4.cpp @@ -7,6 +7,7 @@ /** @file 32bpp_anim_sse4.cpp Implementation of the SSE4 32 bpp blitter with animation support. */ +#include "palette_func.h" #ifdef WITH_SSE #include "../stdafx.h" @@ -317,6 +318,21 @@ bmcr_alpha_blend_single: } break; + case BM_TRANSPARENT_REMAP: + /* Apply custom transparency remap. */ + for (uint x = (uint) bp->width; x > 0; x--) { + if (src->a != 0) { + *dst = this->LookupColourInPalette(bp->remap[GetNearestColourIndex(*dst)]); + *anim = 0; + } + src_mv++; + dst++; + src++; + anim++; + } + break; + + case BM_CRASH_REMAP: for (uint x = (uint) bp->width; x > 0; x--) { if (src_mv->m == 0) { @@ -351,7 +367,7 @@ bmcr_alpha_blend_single: } next_line: - if (mode != BM_TRANSPARENT) src_mv_line += si->sprite_width; + if (mode != BM_TRANSPARENT && mode != BM_TRANSPARENT_REMAP) src_mv_line += si->sprite_width; src_rgba_line = (const Colour*) ((const byte*) src_rgba_line + si->sprite_line_size); dst_line += bp->pitch; anim_line += this->anim_buf_pitch; @@ -414,6 +430,7 @@ bm_normal: } break; case BM_TRANSPARENT: Draw(bp, zoom); return; + case BM_TRANSPARENT_REMAP: Draw(bp, zoom); return; case BM_CRASH_REMAP: Draw(bp, zoom); return; case BM_BLACK_REMAP: Draw(bp, zoom); return; } diff --git a/src/blitter/32bpp_optimized.cpp b/src/blitter/32bpp_optimized.cpp --- a/src/blitter/32bpp_optimized.cpp +++ b/src/blitter/32bpp_optimized.cpp @@ -10,6 +10,7 @@ #include "../stdafx.h" #include "../zoom_func.h" #include "../settings_type.h" +#include "../palette_func.h" #include "32bpp_optimized.hpp" #include "../safeguards.h" @@ -185,10 +186,6 @@ inline void Blitter_32bppOptimized::Draw break; case BM_TRANSPARENT: - /* TODO -- We make an assumption here that the remap in fact is transparency, not some colour. - * This is never a problem with the code we produce, but newgrfs can make it fail... or at least: - * we produce a result the newgrf maker didn't expect ;) */ - /* Make the current colour a bit more black, so it looks like this image is transparent */ src_n += n; if (src_px->a == 255) { @@ -206,6 +203,21 @@ inline void Blitter_32bppOptimized::Draw } break; + case BM_TRANSPARENT_REMAP: + /* Apply custom transparency remap. */ + src_n += n; + if (src_px->a != 0) { + src_px += n; + do { + *dst = this->LookupColourInPalette(bp->remap[GetNearestColourIndex(*dst)]); + dst++; + } while (--n != 0); + } else { + dst += n; + src_px += n; + } + break; + default: if (src_px->a == 255) { /* faster than memcpy(), n is usually low */ @@ -252,6 +264,7 @@ void Blitter_32bppOptimized::Draw(Blitte case BM_NORMAL: Draw(bp, zoom); return; case BM_COLOUR_REMAP: Draw(bp, zoom); return; case BM_TRANSPARENT: Draw(bp, zoom); return; + case BM_TRANSPARENT_REMAP: Draw(bp, zoom); return; case BM_CRASH_REMAP: Draw(bp, zoom); return; case BM_BLACK_REMAP: Draw(bp, zoom); return; } diff --git a/src/blitter/32bpp_simple.cpp b/src/blitter/32bpp_simple.cpp --- a/src/blitter/32bpp_simple.cpp +++ b/src/blitter/32bpp_simple.cpp @@ -9,6 +9,7 @@ #include "../stdafx.h" #include "../zoom_func.h" +#include "../palette_func.h" #include "32bpp_simple.hpp" #include "../table/sprites.h" @@ -63,12 +64,17 @@ void Blitter_32bppSimple::Draw(Blitter:: break; case BM_TRANSPARENT: - /* TODO -- We make an assumption here that the remap in fact is transparency, not some colour. - * This is never a problem with the code we produce, but newgrfs can make it fail... or at least: - * we produce a result the newgrf maker didn't expect ;) */ + /* Make the current colour a bit more black, so it looks like this image is transparent */ + if (src->a != 0) { + *dst = MakeTransparent(*dst, 192); + } + break; - /* Make the current colour a bit more black, so it looks like this image is transparent */ - if (src->a != 0) *dst = MakeTransparent(*dst, 192); + case BM_TRANSPARENT_REMAP: + /* Apply custom transparency remap. */ + if (src->a != 0) { + *dst = this->LookupColourInPalette(bp->remap[GetNearestColourIndex(*dst)]); + } break; default: diff --git a/src/blitter/32bpp_sse_func.hpp b/src/blitter/32bpp_sse_func.hpp --- a/src/blitter/32bpp_sse_func.hpp +++ b/src/blitter/32bpp_sse_func.hpp @@ -392,6 +392,18 @@ bmcr_alpha_blend_single: } break; + case BM_TRANSPARENT_REMAP: + /* Apply custom transparency remap. */ + for (uint x = (uint) bp->width; x > 0; x--) { + if (src->a != 0) { + *dst = this->LookupColourInPalette(bp->remap[GetNearestColourIndex(*dst)]); + } + src_mv++; + dst++; + src++; + } + break; + case BM_CRASH_REMAP: for (uint x = (uint) bp->width; x > 0; x--) { if (src_mv->m == 0) { @@ -471,6 +483,7 @@ bm_normal: Draw(bp, zoom); return; } case BM_TRANSPARENT: Draw(bp, zoom); return; + case BM_TRANSPARENT_REMAP: Draw(bp, zoom); return; case BM_CRASH_REMAP: Draw(bp, zoom); return; case BM_BLACK_REMAP: Draw(bp, zoom); return; } diff --git a/src/blitter/40bpp_anim.cpp b/src/blitter/40bpp_anim.cpp --- a/src/blitter/40bpp_anim.cpp +++ b/src/blitter/40bpp_anim.cpp @@ -11,6 +11,7 @@ #include "../zoom_func.h" #include "../settings_type.h" #include "../video/video_driver.hpp" +#include "../palette_func.h" #include "40bpp_anim.hpp" #include "common.hpp" @@ -234,10 +235,6 @@ inline void Blitter_40bppAnim::Draw(cons break; case BM_TRANSPARENT: - /* TODO -- We make an assumption here that the remap in fact is transparency, not some colour. - * This is never a problem with the code we produce, but newgrfs can make it fail... or at least: - * we produce a result the newgrf maker didn't expect ;) */ - /* Make the current colour a bit more black, so it looks like this image is transparent */ src_n += n; if (src_px->a == 255) { @@ -263,6 +260,28 @@ inline void Blitter_40bppAnim::Draw(cons } break; + case BM_TRANSPARENT_REMAP: + /* Apply custom transparency remap. */ + src_n += n; + if (src_px->a != 0) { + src_px += n; + do { + if (*anim != 0) { + *anim = bp->remap[*anim]; + } else { + *dst = this->LookupColourInPalette(bp->remap[GetNearestColourIndex(*dst)]); + *anim = 0; + } + anim++; + dst++; + } while (--n != 0); + } else { + dst += n; + anim += n; + src_px += n; + } + break; + default: if (src_px->a == 255) { do { @@ -323,6 +342,7 @@ void Blitter_40bppAnim::Draw(Blitter::Bl case BM_NORMAL: Draw (bp, zoom); return; case BM_COLOUR_REMAP: Draw(bp, zoom); return; case BM_TRANSPARENT: Draw (bp, zoom); return; + case BM_TRANSPARENT_REMAP: Draw(bp, zoom); return; case BM_CRASH_REMAP: Draw (bp, zoom); return; case BM_BLACK_REMAP: Draw (bp, zoom); return; } diff --git a/src/blitter/8bpp_optimized.cpp b/src/blitter/8bpp_optimized.cpp --- a/src/blitter/8bpp_optimized.cpp +++ b/src/blitter/8bpp_optimized.cpp @@ -100,7 +100,8 @@ void Blitter_8bppOptimized::Draw(Blitter dst += pixels; break; - case BM_TRANSPARENT: { + case BM_TRANSPARENT: + case BM_TRANSPARENT_REMAP: { const uint8_t *remap = bp->remap; src += pixels; do { diff --git a/src/blitter/8bpp_simple.cpp b/src/blitter/8bpp_simple.cpp --- a/src/blitter/8bpp_simple.cpp +++ b/src/blitter/8bpp_simple.cpp @@ -42,6 +42,7 @@ void Blitter_8bppSimple::Draw(Blitter::B break; case BM_TRANSPARENT: + case BM_TRANSPARENT_REMAP: if (*src != 0) colour = bp->remap[*dst]; break; diff --git a/src/blitter/base.hpp b/src/blitter/base.hpp --- a/src/blitter/base.hpp +++ b/src/blitter/base.hpp @@ -17,7 +17,8 @@ enum BlitterMode { BM_NORMAL, ///< Perform the simple blitting. BM_COLOUR_REMAP, ///< Perform a colour remapping. - BM_TRANSPARENT, ///< Perform transparency colour remapping. + BM_TRANSPARENT, ///< Perform transparency darkening remapping. + BM_TRANSPARENT_REMAP, ///< Perform transparency colour remapping. BM_CRASH_REMAP, ///< Perform a crash remapping. BM_BLACK_REMAP, ///< Perform remapping to a completely blackened sprite }; diff --git a/src/gfx.cpp b/src/gfx.cpp --- a/src/gfx.cpp +++ b/src/gfx.cpp @@ -978,8 +978,9 @@ void DrawSpriteViewport(SpriteID img, Pa { SpriteID real_sprite = GB(img, 0, SPRITE_WIDTH); if (HasBit(img, PALETTE_MODIFIER_TRANSPARENT)) { - _colour_remap_ptr = GetNonSprite(GB(pal, 0, PALETTE_WIDTH), SpriteType::Recolour) + 1; - GfxMainBlitterViewport(GetSprite(real_sprite, SpriteType::Normal), x, y, BM_TRANSPARENT, sub, real_sprite); + pal = GB(pal, 0, PALETTE_WIDTH); + _colour_remap_ptr = GetNonSprite(pal, SpriteType::Recolour) + 1; + GfxMainBlitterViewport(GetSprite(real_sprite, SpriteType::Normal), x, y, pal == PALETTE_TO_TRANSPARENT ? BM_TRANSPARENT : BM_TRANSPARENT_REMAP, sub, real_sprite); } else if (pal != PAL_NONE) { if (HasBit(pal, PALETTE_TEXT_RECOLOUR)) { SetColourRemap((TextColour)GB(pal, 0, PALETTE_WIDTH)); @@ -1005,8 +1006,9 @@ void DrawSprite(SpriteID img, PaletteID { SpriteID real_sprite = GB(img, 0, SPRITE_WIDTH); if (HasBit(img, PALETTE_MODIFIER_TRANSPARENT)) { - _colour_remap_ptr = GetNonSprite(GB(pal, 0, PALETTE_WIDTH), SpriteType::Recolour) + 1; - GfxMainBlitter(GetSprite(real_sprite, SpriteType::Normal), x, y, BM_TRANSPARENT, sub, real_sprite, zoom); + pal = GB(pal, 0, PALETTE_WIDTH); + _colour_remap_ptr = GetNonSprite(pal, SpriteType::Recolour) + 1; + GfxMainBlitter(GetSprite(real_sprite, SpriteType::Normal), x, y, pal == PALETTE_TO_TRANSPARENT ? BM_TRANSPARENT : BM_TRANSPARENT_REMAP, sub, real_sprite, zoom); } else if (pal != PAL_NONE) { if (HasBit(pal, PALETTE_TEXT_RECOLOUR)) { SetColourRemap((TextColour)GB(pal, 0, PALETTE_WIDTH));