mirror of https://github.com/OpenTTD/OpenTTD
Codechange: Add support for RGBA recolour remaps.
parent
79a2af5d44
commit
bec34c38f7
|
@ -37,6 +37,7 @@ inline void Blitter_32bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel
|
|||
uint16_t *anim = this->anim_buf + this->ScreenToAnimOffset((uint32_t *)bp->dst) + bp->top * this->anim_buf_pitch + bp->left;
|
||||
|
||||
const uint8_t *remap = bp->remap->GetPaletteRemap(); // store so we don't have to access it via bp every time
|
||||
const Colour *remap_rgba = mode == BlitterMode::RGBAColourRemap ? bp->remap->GetRGBARemap() : nullptr;
|
||||
|
||||
for (int y = 0; y < bp->height; y++) {
|
||||
Colour *dst_ln = dst + bp->pitch;
|
||||
|
@ -135,6 +136,43 @@ inline void Blitter_32bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel
|
|||
}
|
||||
break;
|
||||
|
||||
case BlitterMode::RGBAColourRemap:
|
||||
if (src_px->a == 255) {
|
||||
do {
|
||||
uint m = *src_n;
|
||||
/* In case the m-channel is zero, do not remap this pixel in any way */
|
||||
if (m == 0) {
|
||||
*dst = src_px->data;
|
||||
*anim = 0;
|
||||
} else {
|
||||
const Colour &c = remap_rgba[GB(m, 0, 8)];
|
||||
*anim = 0;
|
||||
*dst = AdjustBrightness(c, GB(m, 8, 8));
|
||||
}
|
||||
anim++;
|
||||
dst++;
|
||||
src_px++;
|
||||
src_n++;
|
||||
} while (--n != 0);
|
||||
} else {
|
||||
do {
|
||||
uint m = *src_n;
|
||||
if (m == 0) {
|
||||
*dst = ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, *dst);
|
||||
*anim = 0;
|
||||
} else {
|
||||
const Colour &c = remap_rgba[GB(m, 0, 8)];
|
||||
*anim = 0;
|
||||
*dst = ComposeColourPANoCheck(AdjustBrightness(c, GB(m, 8, 8)), c.a * src_px->a / 255, *dst);
|
||||
}
|
||||
anim++;
|
||||
dst++;
|
||||
src_px++;
|
||||
src_n++;
|
||||
} while (--n != 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case BlitterMode::CrashRemap:
|
||||
if (src_px->a == 255) {
|
||||
do {
|
||||
|
@ -273,6 +311,7 @@ void Blitter_32bppAnim::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomL
|
|||
default: NOT_REACHED();
|
||||
case BlitterMode::Normal: Draw<BlitterMode::Normal>(bp, zoom); return;
|
||||
case BlitterMode::ColourRemap: Draw<BlitterMode::ColourRemap>(bp, zoom); return;
|
||||
case BlitterMode::RGBAColourRemap: Draw<BlitterMode::RGBAColourRemap>(bp, zoom); return;
|
||||
case BlitterMode::Transparent: Draw<BlitterMode::Transparent>(bp, zoom); return;
|
||||
case BlitterMode::TransparentRemap: Draw<BlitterMode::TransparentRemap>(bp, zoom); return;
|
||||
case BlitterMode::CrashRemap: Draw<BlitterMode::CrashRemap>(bp, zoom); return;
|
||||
|
|
|
@ -49,6 +49,7 @@ inline void Blitter_32bppOptimized::Draw(const Blitter::BlitterParams *bp, ZoomL
|
|||
|
||||
/* store so we don't have to access it via bp every time (compiler assumes pointer aliasing) */
|
||||
const uint8_t *remap = bp->remap->GetPaletteRemap();
|
||||
const Colour *remap_rgba = mode == BlitterMode::RGBAColourRemap ? bp->remap->GetRGBARemap() : nullptr;
|
||||
|
||||
for (int y = 0; y < bp->height; y++) {
|
||||
/* next dst line begins here */
|
||||
|
@ -142,6 +143,37 @@ inline void Blitter_32bppOptimized::Draw(const Blitter::BlitterParams *bp, ZoomL
|
|||
}
|
||||
break;
|
||||
|
||||
case BlitterMode::RGBAColourRemap:
|
||||
if (src_px->a == 255) {
|
||||
do {
|
||||
uint m = *src_n;
|
||||
/* In case the m-channel is zero, do not remap this pixel in any way */
|
||||
if (m == 0) {
|
||||
*dst = src_px->data;
|
||||
} else {
|
||||
const Colour c = remap_rgba[GB(m, 0, 8)];
|
||||
*dst = AdjustBrightness(c, GB(m, 8, 8));
|
||||
}
|
||||
dst++;
|
||||
src_px++;
|
||||
src_n++;
|
||||
} while (--n != 0);
|
||||
} else {
|
||||
do {
|
||||
uint m = *src_n;
|
||||
if (m == 0) {
|
||||
*dst = ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, *dst);
|
||||
} else {
|
||||
const Colour c = remap_rgba[GB(m, 0, 8)];
|
||||
*dst = ComposeColourPANoCheck(AdjustBrightness(c, GB(m, 8, 8)), src_px->a, *dst);
|
||||
}
|
||||
dst++;
|
||||
src_px++;
|
||||
src_n++;
|
||||
} while (--n != 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case BlitterMode::CrashRemap:
|
||||
if (src_px->a == 255) {
|
||||
do {
|
||||
|
@ -263,6 +295,7 @@ void Blitter_32bppOptimized::Draw(Blitter::BlitterParams *bp, BlitterMode mode,
|
|||
default: NOT_REACHED();
|
||||
case BlitterMode::Normal: Draw<BlitterMode::Normal, Tpal_to_rgb>(bp, zoom); return;
|
||||
case BlitterMode::ColourRemap: Draw<BlitterMode::ColourRemap, Tpal_to_rgb>(bp, zoom); return;
|
||||
case BlitterMode::RGBAColourRemap: Draw<BlitterMode::RGBAColourRemap, Tpal_to_rgb>(bp, zoom); return;
|
||||
case BlitterMode::Transparent: Draw<BlitterMode::Transparent, Tpal_to_rgb>(bp, zoom); return;
|
||||
case BlitterMode::TransparentRemap: Draw<BlitterMode::TransparentRemap, Tpal_to_rgb>(bp, zoom); return;
|
||||
case BlitterMode::CrashRemap: Draw<BlitterMode::CrashRemap, Tpal_to_rgb>(bp, zoom); return;
|
||||
|
|
|
@ -24,6 +24,7 @@ void Blitter_32bppSimple::Draw(Blitter::BlitterParams *bp, BlitterMode mode, Zoo
|
|||
const Blitter_32bppSimple::Pixel *src, *src_line;
|
||||
Colour *dst, *dst_line;
|
||||
const uint8_t *remap = bp->remap->GetPaletteRemap();
|
||||
const Colour *remap_rgba = mode == BlitterMode::RGBAColourRemap ? bp->remap->GetRGBARemap() : nullptr;
|
||||
|
||||
/* Find where to start reading in the source sprite */
|
||||
src_line = (const Blitter_32bppSimple::Pixel *)bp->sprite + (bp->skip_top * bp->sprite_width + bp->skip_left) * ScaleByZoom(1, zoom);
|
||||
|
@ -47,6 +48,18 @@ void Blitter_32bppSimple::Draw(Blitter::BlitterParams *bp, BlitterMode mode, Zoo
|
|||
}
|
||||
break;
|
||||
|
||||
case BlitterMode::RGBAColourRemap:
|
||||
/* In case the m-channel is zero, do not remap this pixel in any way */
|
||||
if (src->m == 0) {
|
||||
if (src->a != 0) *dst = ComposeColourRGBA(src->r, src->g, src->b, src->a, *dst);
|
||||
} else {
|
||||
const Colour &c = remap_rgba[src->m];
|
||||
if (c.a != 0) {
|
||||
*dst = ComposeColourPA(AdjustBrightness(c, src->v), src->a, *dst);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BlitterMode::CrashRemap:
|
||||
if (src->m == 0) {
|
||||
if (src->a != 0) {
|
||||
|
|
|
@ -127,6 +127,7 @@ inline void Blitter_40bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel
|
|||
|
||||
/* store so we don't have to access it via bp every time (compiler assumes pointer aliasing) */
|
||||
const uint8_t *remap = bp->remap->GetPaletteRemap();
|
||||
const Colour *remap_rgba = mode == BlitterMode::RGBAColourRemap ? bp->remap->GetRGBARemap() : nullptr;
|
||||
|
||||
for (int y = 0; y < bp->height; y++) {
|
||||
/* next dst line begins here */
|
||||
|
@ -237,6 +238,49 @@ inline void Blitter_40bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel
|
|||
}
|
||||
break;
|
||||
|
||||
case BlitterMode::RGBAColourRemap:
|
||||
if (src_px->a == 255) {
|
||||
do {
|
||||
uint8_t m = GB(*src_n, 0, 8);
|
||||
/* In case the m-channel is zero, only apply the crash remap by darkening the RGB colour. */
|
||||
if (m == 0) {
|
||||
*dst = *src_px;
|
||||
*anim = 0;
|
||||
} else {
|
||||
const Colour &c = remap_rgba[GB(m, 0, 8)];
|
||||
if (c.a != 0) {
|
||||
*dst = ComposeColourRGBANoCheck(c.r, c.g, c.b, c.a, *dst);
|
||||
*anim = 0;
|
||||
}
|
||||
}
|
||||
anim++;
|
||||
dst++;
|
||||
src_px++;
|
||||
src_n++;
|
||||
} while (--n != 0);
|
||||
} else {
|
||||
do {
|
||||
uint8_t m = GB(*src_n, 0, 8);
|
||||
Colour b = this->RealizeBlendedColour(*anim, *dst);
|
||||
if (m == 0) {
|
||||
Colour c = *src_px;
|
||||
*dst = this->ComposeColourRGBANoCheck(c.r, c.g, c.b, src_px->a / 255, b);
|
||||
*anim = 0;
|
||||
} else {
|
||||
const Colour &c = remap_rgba[m];
|
||||
if (c.a != 0) {
|
||||
*dst = this->ComposeColourPANoCheck(c, c.a * src_px->a / 255, b);
|
||||
*anim = 0; // Animation colours don't work with alpha-blending.
|
||||
}
|
||||
}
|
||||
anim++;
|
||||
dst++;
|
||||
src_px++;
|
||||
src_n++;
|
||||
} while (--n != 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case BlitterMode::BlackRemap:
|
||||
do {
|
||||
*anim++ = 0;
|
||||
|
@ -353,6 +397,7 @@ void Blitter_40bppAnim::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomL
|
|||
default: NOT_REACHED();
|
||||
case BlitterMode::Normal: Draw<BlitterMode::Normal>(bp, zoom); return;
|
||||
case BlitterMode::ColourRemap: Draw<BlitterMode::ColourRemap>(bp, zoom); return;
|
||||
case BlitterMode::RGBAColourRemap: Draw<BlitterMode::RGBAColourRemap>(bp, zoom); return;
|
||||
case BlitterMode::Transparent: Draw<BlitterMode::Transparent>(bp, zoom); return;
|
||||
case BlitterMode::TransparentRemap: Draw<BlitterMode::TransparentRemap>(bp, zoom); return;
|
||||
case BlitterMode::CrashRemap: Draw<BlitterMode::CrashRemap>(bp, zoom); return;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
enum class BlitterMode : uint8_t {
|
||||
Normal, ///< Perform the simple blitting.
|
||||
ColourRemap, ///< Perform a colour remapping.
|
||||
RGBAColourRemap, ///< Perform a colour remapping.
|
||||
Transparent, ///< Perform transparency darkening remapping.
|
||||
TransparentRemap, ///< Perform transparency colour remapping.
|
||||
CrashRemap, ///< Perform a crash remapping.
|
||||
|
|
|
@ -983,13 +983,13 @@ Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
|
|||
* @param pal The palette to get the blitter mode for.
|
||||
* @return The blitter mode associated with the palette.
|
||||
*/
|
||||
static BlitterMode GetBlitterMode(PaletteID pal)
|
||||
static BlitterMode GetBlitterMode(PaletteID pal, const RecolourSprite &recolour)
|
||||
{
|
||||
switch (pal) {
|
||||
case PAL_NONE: return BlitterMode::Normal;
|
||||
case PALETTE_CRASH: return BlitterMode::CrashRemap;
|
||||
case PALETTE_ALL_BLACK: return BlitterMode::BlackRemap;
|
||||
default: return BlitterMode::ColourRemap;
|
||||
default: return recolour.IsRGB() && BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 32 ? BlitterMode::RGBAColourRemap : BlitterMode::ColourRemap;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1014,7 +1014,7 @@ void DrawSpriteViewport(SpriteID img, PaletteID pal, int x, int y, const SubSpri
|
|||
} else {
|
||||
_colour_remap_ptr = GetRecolourSprite(GB(pal, 0, PALETTE_WIDTH));
|
||||
}
|
||||
GfxMainBlitterViewport(GetSprite(real_sprite, SpriteType::Normal), x, y, GetBlitterMode(pal), sub, real_sprite);
|
||||
GfxMainBlitterViewport(GetSprite(real_sprite, SpriteType::Normal), x, y, GetBlitterMode(pal, *_colour_remap_ptr), sub, real_sprite);
|
||||
} else {
|
||||
GfxMainBlitterViewport(GetSprite(real_sprite, SpriteType::Normal), x, y, BlitterMode::Normal, sub, real_sprite);
|
||||
}
|
||||
|
@ -1042,7 +1042,7 @@ void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub,
|
|||
} else {
|
||||
_colour_remap_ptr = GetRecolourSprite(GB(pal, 0, PALETTE_WIDTH));
|
||||
}
|
||||
GfxMainBlitter(GetSprite(real_sprite, SpriteType::Normal), x, y, GetBlitterMode(pal), sub, real_sprite, zoom);
|
||||
GfxMainBlitter(GetSprite(real_sprite, SpriteType::Normal), x, y, GetBlitterMode(pal, *_colour_remap_ptr), sub, real_sprite, zoom);
|
||||
} else {
|
||||
GfxMainBlitter(GetSprite(real_sprite, SpriteType::Normal), x, y, BlitterMode::Normal, sub, real_sprite, zoom);
|
||||
}
|
||||
|
|
|
@ -556,8 +556,16 @@ void SetupColoursAndInitialWindow()
|
|||
const RecolourSprite *rs = GetRecolourSprite(GetColourPalette(i));
|
||||
assert(rs != nullptr);
|
||||
const uint8_t *remap = rs->GetPaletteRemap();
|
||||
for (ColourShade j = SHADE_BEGIN; j < SHADE_END; j++) {
|
||||
SetColourGradient(i, j, PixelColour{remap[0xC6 + j]});
|
||||
if (rs->IsRGB()) {
|
||||
const Colour *rgba_remap = rs->GetRGBARemap();
|
||||
for (ColourShade j = SHADE_BEGIN; j < SHADE_END; j++) {
|
||||
const Colour &c = rgba_remap[j];
|
||||
SetColourGradient(i, j, PixelColour{remap[0xC6 + j], c});
|
||||
}
|
||||
} else {
|
||||
for (ColourShade j = SHADE_BEGIN; j < SHADE_END; j++) {
|
||||
SetColourGradient(i, j, PixelColour{remap[0xC6 + j]});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -427,6 +427,19 @@ void RecolourSprite::Read(SpriteFile &file, size_t entries)
|
|||
}
|
||||
}
|
||||
|
||||
void RecolourSpriteRGBA::Read(SpriteFile &file, size_t entries)
|
||||
{
|
||||
this->RecolourSprite::Read(file, entries);
|
||||
|
||||
/* Colour is byte-arranged differently by platform, so read components individually. */
|
||||
for (uint i = 0; i < entries; ++i) {
|
||||
this->rgba[i].r = file.ReadByte();
|
||||
this->rgba[i].g = file.ReadByte();
|
||||
this->rgba[i].b = file.ReadByte();
|
||||
this->rgba[i].a = file.ReadByte();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a recolour sprite into memory.
|
||||
* @param file GRF we're reading from.
|
||||
|
@ -450,7 +463,8 @@ static void *ReadRecolourSprite(SpriteFile &file, size_t file_pos, uint num, Spr
|
|||
entries = num;
|
||||
}
|
||||
|
||||
RecolourSprite *rs = allocator.New<RecolourSprite>();
|
||||
num -= entries;
|
||||
RecolourSprite *rs = (num == entries * 4) ? allocator.New<RecolourSpriteRGBA>() : allocator.New<RecolourSprite>();
|
||||
rs->Read(file, entries);
|
||||
return rs;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#define SPRITECACHE_TYPE_H
|
||||
|
||||
#include "core/enum_type.hpp"
|
||||
#include "gfx_type.h"
|
||||
#include "spriteloader/sprite_file_type.hpp"
|
||||
|
||||
/** Data structure describing a sprite. */
|
||||
|
@ -27,12 +28,24 @@ class RecolourSprite {
|
|||
public:
|
||||
static constexpr size_t PALETTE_SIZE = 256; ///< Number of entries in a recolour sprite.
|
||||
|
||||
void Read(SpriteFile &file, size_t entries);
|
||||
virtual ~RecolourSprite() {}
|
||||
virtual void Read(SpriteFile &file, size_t entries);
|
||||
inline const uint8_t *GetPaletteRemap() const { return this->palette.data(); }
|
||||
virtual bool IsRGB() const { return false; }
|
||||
virtual const Colour *GetRGBARemap() const { return nullptr; }
|
||||
|
||||
std::array<uint8_t, PALETTE_SIZE> palette{}; ///< Palette index remap, mapping from one palette index to another.
|
||||
};
|
||||
|
||||
class RecolourSpriteRGBA : public RecolourSprite {
|
||||
public:
|
||||
void Read(SpriteFile &file, size_t entries) override;
|
||||
bool IsRGB() const override { return true; }
|
||||
const Colour *GetRGBARemap() const override { return this->rgba.data(); }
|
||||
|
||||
std::array<Colour, PALETTE_SIZE> rgba{}; ///< RGBA remap, mapping from palette index to colour.
|
||||
};
|
||||
|
||||
enum class SpriteCacheCtrlFlag : uint8_t {
|
||||
AllowZoomMin1xPal, ///< Allow use of sprite min zoom setting at 1x in palette mode.
|
||||
AllowZoomMin1x32bpp, ///< Allow use of sprite min zoom setting at 1x in 32bpp mode.
|
||||
|
|
Loading…
Reference in New Issue