diff options
author | Michael Lutz <michi@icosahedron.de> | 2021-01-16 16:43:44 +0100 |
---|---|---|
committer | Michael Lutz <michi@icosahedron.de> | 2021-02-22 22:16:07 +0100 |
commit | 94d8acb7d007150606c0756060c6f0cf90ee7f70 (patch) | |
tree | 57d5c1399f5eaa8005daf0d85ae86cb10a48cda8 /src | |
parent | ae7c63cc35362932500f42f4a11ae2160566b718 (diff) | |
download | openttd-94d8acb7d007150606c0756060c6f0cf90ee7f70.tar.xz |
Add: A 32 bpp blitter that uses the animation buffer from the video backend to speed up palette animation.
Diffstat (limited to 'src')
-rw-r--r-- | src/blitter/32bpp_base.hpp | 22 | ||||
-rw-r--r-- | src/blitter/32bpp_optimized.cpp | 12 | ||||
-rw-r--r-- | src/blitter/32bpp_optimized.hpp | 3 | ||||
-rw-r--r-- | src/blitter/40bpp_anim.cpp | 500 | ||||
-rw-r--r-- | src/blitter/40bpp_anim.hpp | 63 | ||||
-rw-r--r-- | src/blitter/CMakeLists.txt | 7 | ||||
-rw-r--r-- | src/gfxinit.cpp | 3 |
7 files changed, 607 insertions, 3 deletions
diff --git a/src/blitter/32bpp_base.hpp b/src/blitter/32bpp_base.hpp index f09719450..9d80ec2ce 100644 --- a/src/blitter/32bpp_base.hpp +++ b/src/blitter/32bpp_base.hpp @@ -125,6 +125,18 @@ public: } /** + * Make a colour dark grey, for specialized 32bpp remapping. + * @param colour the colour to make dark. + * @return the new colour, now darker. + */ + static inline Colour MakeDark(Colour colour) + { + uint8 d = MakeDark(colour.r, colour.g, colour.b); + + return Colour(d, d, d); + } + + /** * Make a colour grey - based. * @param colour the colour to make grey. * @return the new colour, now grey. @@ -154,6 +166,16 @@ public: return ReallyAdjustBrightness(colour, brightness); } + + static inline uint8 GetColourBrightness(Colour colour) + { + uint8 rgb_max = std::max(colour.r, std::max(colour.g, colour.b)); + + /* Black pixel (8bpp or old 32bpp image), so use default value */ + if (rgb_max == 0) rgb_max = DEFAULT_BRIGHTNESS; + + return rgb_max; + } }; #endif /* BLITTER_32BPP_BASE_HPP */ diff --git a/src/blitter/32bpp_optimized.cpp b/src/blitter/32bpp_optimized.cpp index ad15b8f81..1f8e0bbd2 100644 --- a/src/blitter/32bpp_optimized.cpp +++ b/src/blitter/32bpp_optimized.cpp @@ -252,7 +252,7 @@ void Blitter_32bppOptimized::Draw(Blitter::BlitterParams *bp, BlitterMode mode, } } -Sprite *Blitter_32bppOptimized::Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) +template <bool Tpal_to_rgb> Sprite *Blitter_32bppOptimized::EncodeInternal(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) { /* streams of pixels (a, r, g, b channels) * @@ -322,7 +322,7 @@ Sprite *Blitter_32bppOptimized::Encode(const SpriteLoader::Sprite *sprite, Alloc if (a != 0) { dst_px->a = a; *dst_n = src->m; - if (src->m != 0) { + if (Tpal_to_rgb && src->m != 0) { /* Get brightest value */ uint8 rgb_max = std::max({src->r, src->g, src->b}); @@ -397,3 +397,11 @@ Sprite *Blitter_32bppOptimized::Encode(const SpriteLoader::Sprite *sprite, Alloc return dest_sprite; } + +template Sprite *Blitter_32bppOptimized::EncodeInternal<true>(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator); +template Sprite *Blitter_32bppOptimized::EncodeInternal<false>(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator); + +Sprite *Blitter_32bppOptimized::Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) +{ + return this->EncodeInternal<true>(sprite, allocator); +} diff --git a/src/blitter/32bpp_optimized.hpp b/src/blitter/32bpp_optimized.hpp index a9c732902..9bee600b1 100644 --- a/src/blitter/32bpp_optimized.hpp +++ b/src/blitter/32bpp_optimized.hpp @@ -27,6 +27,9 @@ public: const char *GetName() override { return "32bpp-optimized"; } template <BlitterMode mode> void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom); + +protected: + template <bool Tpal_to_rgb> Sprite *EncodeInternal(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator); }; /** Factory for the optimised 32 bpp blitter (without palette animation). */ diff --git a/src/blitter/40bpp_anim.cpp b/src/blitter/40bpp_anim.cpp new file mode 100644 index 000000000..2cc3be5be --- /dev/null +++ b/src/blitter/40bpp_anim.cpp @@ -0,0 +1,500 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>. + */ + +/** @file 40bpp_optimized.cpp Implementation of the optimized 40 bpp blitter. */ + +#include "../stdafx.h" +#include "../zoom_func.h" +#include "../settings_type.h" +#include "../video/video_driver.hpp" +#include "40bpp_anim.hpp" + +#include "../table/sprites.h" + +#include "../safeguards.h" + + +/** Instantiation of the 40bpp with animation blitter factory. */ +static FBlitter_40bppAnim iFBlitter_40bppAnim; + +/** Cached black value. */ +static const Colour _black_colour(0, 0, 0); + + +void Blitter_40bppAnim::SetPixel(void *video, int x, int y, uint8 colour) +{ + if (_screen_disable_anim) { + Blitter_32bppOptimized::SetPixel(video, x, y, colour); + } else { + *((Colour *)video + x + y * _screen.pitch) = _black_colour; + + VideoDriver::GetInstance()->GetAnimBuffer()[((uint32 *)video - (uint32 *)_screen.dst_ptr) + x + y * _screen.pitch] = colour; + } +} + +void Blitter_40bppAnim::DrawRect(void *video, int width, int height, uint8 colour) +{ + if (_screen_disable_anim) { + /* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent DrawRect() */ + Blitter_32bppOptimized::DrawRect(video, width, height, colour); + return; + } + + assert(VideoDriver::GetInstance()->GetAnimBuffer() != nullptr); + uint8 *anim_line = ((uint32 *)video - (uint32 *)_screen.dst_ptr) + VideoDriver::GetInstance()->GetAnimBuffer(); + + do { + Colour *dst = (Colour *)video; + uint8 *anim = anim_line; + + for (int i = width; i > 0; i--) { + *dst = _black_colour; + *anim = colour; + dst++; + anim++; + } + video = (uint32 *)video + _screen.pitch; + anim_line += _screen.pitch; + } while (--height); +} + +/** + * Draws a sprite to a (screen) buffer. It is templated to allow faster operation. + * + * @tparam mode blitter mode + * @param bp further blitting parameters + * @param zoom zoom level at which we are drawing + */ +template <BlitterMode mode> +inline void Blitter_40bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom) +{ + const SpriteData *src = (const SpriteData *)bp->sprite; + + /* src_px : each line begins with uint32 n = 'number of bytes in this line', + * then n times is the Colour struct for this line */ + const Colour *src_px = (const Colour *)(src->data + src->offset[zoom][0]); + /* src_n : each line begins with uint32 n = 'number of bytes in this line', + * then interleaved stream of 'm' and 'n' channels. 'm' is remap, + * 'n' is number of bytes with the same alpha channel class */ + const uint16 *src_n = (const uint16 *)(src->data + src->offset[zoom][1]); + + /* skip upper lines in src_px and src_n */ + for (uint i = bp->skip_top; i != 0; i--) { + src_px = (const Colour *)((const byte *)src_px + *(const uint32 *)src_px); + src_n = (const uint16 *)((const byte *)src_n + *(const uint32 *)src_n); + } + + /* skip lines in dst */ + Colour *dst = (Colour *)bp->dst + bp->top * bp->pitch + bp->left; + assert(VideoDriver::GetInstance()->GetAnimBuffer() != nullptr); + uint8 *anim = VideoDriver::GetInstance()->GetAnimBuffer() + ((uint32 *)bp->dst - (uint32 *)_screen.dst_ptr) + bp->top * bp->pitch + bp->left; + + /* store so we don't have to access it via bp everytime (compiler assumes pointer aliasing) */ + const byte *remap = bp->remap; + + for (int y = 0; y < bp->height; y++) { + /* next dst line begins here */ + Colour *dst_ln = dst + bp->pitch; + uint8 *anim_ln = anim + bp->pitch; + + /* next src line begins here */ + const Colour *src_px_ln = (const Colour *)((const byte *)src_px + *(const uint32 *)src_px); + src_px++; + + /* next src_n line begins here */ + const uint16 *src_n_ln = (const uint16 *)((const byte *)src_n + *(const uint32 *)src_n); + src_n += 2; + + /* we will end this line when we reach this point */ + Colour *dst_end = dst + bp->skip_left; + + /* number of pixels with the same alpha channel class */ + uint n; + + while (dst < dst_end) { + n = *src_n++; + + if (src_px->a == 0) { + dst += n; + src_px++; + src_n++; + + if (dst > dst_end) anim += dst - dst_end; + } else { + if (dst + n > dst_end) { + uint d = dst_end - dst; + src_px += d; + src_n += d; + + dst = dst_end - bp->skip_left; + dst_end = dst + bp->width; + + n = std::min<uint>(n - d, (uint)bp->width); + goto draw; + } + dst += n; + src_px += n; + src_n += n; + } + } + + dst -= bp->skip_left; + dst_end -= bp->skip_left; + + dst_end += bp->width; + + while (dst < dst_end) { + n = std::min<uint>(*src_n++, (uint)(dst_end - dst)); + + if (src_px->a == 0) { + anim += n; + dst += n; + src_px++; + src_n++; + continue; + } + + draw:; + + switch (mode) { + case BM_COLOUR_REMAP: + case BM_CRASH_REMAP: + if (src_px->a == 255) { + do { + uint8 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 = mode == BM_CRASH_REMAP ? this->MakeDark(*src_px) : *src_px; + *anim = 0; + } else { + uint r = remap[m]; + if (r != 0) { + *dst = src_px->data; + *anim = r; + } + } + anim++; + dst++; + src_px++; + src_n++; + } while (--n != 0); + } else { + do { + uint8 m = GB(*src_n, 0, 8); + Colour b = this->RealizeBlendedColour(*anim, *dst); + if (m == 0) { + Colour c = mode == BM_CRASH_REMAP ? this->MakeDark(*src_px) : *src_px; + *dst = this->ComposeColourRGBANoCheck(c.r, c.g, c.b, src_px->a, b); + *anim = 0; + } else { + uint r = remap[m]; + if (r != 0) { + *dst = this->ComposeColourPANoCheck(this->LookupColourInPalette(r), src_px->a, b); + *anim = 0; // Animation colours don't work with alpha-blending. + } + } + anim++; + dst++; + src_px++; + src_n++; + } while (--n != 0); + } + break; + + case BM_BLACK_REMAP: + do { + *anim++ = 0; + *dst++ = _black_colour; + src_px++; + src_n++; + } while (--n != 0); + 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) { + src_px += n; + do { + /* If the anim buffer contains a color value, the image composition will + * only look at the RGB brightness value. As such, we can simply darken the + * RGB value to darken the anim color. */ + Colour b = *anim != 0 ? Colour(this->GetColourBrightness(*dst), 0, 0) : *dst; + *dst = this->MakeTransparent(b, 3, 4); + anim++; + dst++; + } while (--n != 0); + } else { + do { + Colour b = this->RealizeBlendedColour(*anim, *dst); + *dst = this->MakeTransparent(b, (256 * 4 - src_px->a), 256 * 4); + *anim = 0; // Animation colours don't work with alpha-blending. + anim++; + dst++; + src_px++; + } while (--n != 0); + } + break; + + default: + if (src_px->a == 255) { + do { + *anim++ = GB(*src_n, 0, 8); + *dst++ = src_px->data; + src_px++; + src_n++; + } while (--n != 0); + break; + } else { + do { + uint8 m = GB(*src_n, 0, 8); + Colour b = this->RealizeBlendedColour(*anim, *dst); + + if (m == 0) { + *dst = this->ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, b); + *anim = 0; + } else { + *dst = this->ComposeColourPANoCheck(this->LookupColourInPalette(m), src_px->a, b); + *anim = m; + } + + anim++; + dst++; + src_px++; + src_n++; + } while (--n != 0); + } + } + } + + dst = dst_ln; + anim = anim_ln; + src_px = src_px_ln; + src_n = src_n_ln; + } +} + +/** + * Draws a sprite to a (screen) buffer. Calls adequate templated function. + * + * @param bp further blitting parameters + * @param mode blitter mode + * @param zoom zoom level at which we are drawing + */ +void Blitter_40bppAnim::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) +{ + assert(_screen.dst_ptr != nullptr); + + if (_screen_disable_anim || VideoDriver::GetInstance()->GetAnimBuffer() == nullptr) { + /* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent Draw() */ + Blitter_32bppOptimized::Draw(bp, mode, zoom); + return; + } + + switch (mode) { + default: NOT_REACHED(); + case BM_NORMAL: Draw<BM_NORMAL> (bp, zoom); return; + case BM_COLOUR_REMAP: Draw<BM_COLOUR_REMAP>(bp, zoom); return; + case BM_TRANSPARENT: Draw<BM_TRANSPARENT> (bp, zoom); return; + case BM_CRASH_REMAP: Draw<BM_CRASH_REMAP> (bp, zoom); return; + case BM_BLACK_REMAP: Draw<BM_BLACK_REMAP> (bp, zoom); return; + } +} + +void Blitter_40bppAnim::DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) +{ + if (_screen_disable_anim) { + /* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent DrawColourMappingRect() */ + Blitter_32bppOptimized::DrawColourMappingRect(dst, width, height, pal); + return; + } + + Colour *udst = (Colour *)dst; + uint8 *anim = VideoDriver::GetInstance()->GetAnimBuffer() + ((uint32 *)dst - (uint32 *)_screen.dst_ptr); + + if (pal == PALETTE_TO_TRANSPARENT) { + /* If the anim buffer contains a color value, the image composition will + * only look at the RGB brightness value. As such, we can simply darken the + * RGB value to darken the anim color. */ + do { + for (int i = 0; i != width; i++) { + Colour b = *anim != 0 ? Colour(this->GetColourBrightness(*udst), 0, 0) : *udst; + *udst = MakeTransparent(b, 154); + udst++; + anim++; + } + udst = udst - width + _screen.pitch; + anim = anim - width + _screen.pitch; + } while (--height); + } else if (pal == PALETTE_NEWSPAPER) { + const uint8 *remap = GetNonSprite(pal, ST_RECOLOUR) + 1; + do { + for (int i = 0; i != width; i++) { + if (*anim == 0) *udst = MakeGrey(*udst); + *anim = remap[*anim]; + udst++; + anim++; + } + udst = udst - width + _screen.pitch; + anim = anim - width + _screen.pitch; + } while (--height); + } else { + const uint8 *remap = GetNonSprite(pal, ST_RECOLOUR) + 1; + do { + for (int i = 0; i != width; i++) { + *anim = remap[*anim]; + anim++; + } + anim = anim - width + _screen.pitch; + } while (--height); + } +} + +Sprite *Blitter_40bppAnim::Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) +{ + return this->EncodeInternal<false>(sprite, allocator); +} + + +void Blitter_40bppAnim::CopyFromBuffer(void *video, const void *src, int width, int height) +{ + assert(!_screen_disable_anim); + assert(video >= _screen.dst_ptr && video <= (uint32 *)_screen.dst_ptr + _screen.width + _screen.height * _screen.pitch); + uint32 *dst = (uint32 *)video; + const uint32 *usrc = (const uint32 *)src; + + uint8 *anim_buf = VideoDriver::GetInstance()->GetAnimBuffer(); + if (anim_buf == nullptr) return; + uint8 *anim_line = ((uint32 *)video - (uint32 *)_screen.dst_ptr) + anim_buf; + + for (; height > 0; height--) { + memcpy(dst, usrc, width * sizeof(uint32)); + usrc += width; + dst += _screen.pitch; + /* Copy back the anim-buffer */ + memcpy(anim_line, usrc, width * sizeof(uint8)); + usrc = (const uint32 *)((const uint8 *)usrc + width); + anim_line += _screen.pitch; + } +} + +void Blitter_40bppAnim::CopyToBuffer(const void *video, void *dst, int width, int height) +{ + assert(!_screen_disable_anim); + assert(video >= _screen.dst_ptr && video <= (uint32 *)_screen.dst_ptr + _screen.width + _screen.height * _screen.pitch); + uint32 *udst = (uint32 *)dst; + const uint32 *src = (const uint32 *)video; + + uint8 *anim_buf = VideoDriver::GetInstance()->GetAnimBuffer(); + if (anim_buf == nullptr) return; + const uint8 *anim_line = ((const uint32 *)video - (uint32 *)_screen.dst_ptr) + anim_buf; + + for (; height > 0; height--) { + memcpy(udst, src, width * sizeof(uint32)); + src += _screen.pitch; + udst += width; + /* Copy the anim-buffer */ + memcpy(udst, anim_line, width * sizeof(uint8)); + udst = (uint32 *)((uint8 *)udst + width); + anim_line += _screen.pitch; + } +} + +void Blitter_40bppAnim::CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) +{ + uint8 *anim_buf = VideoDriver::GetInstance()->GetAnimBuffer(); + if (anim_buf == nullptr) { + Blitter_32bppOptimized::CopyImageToBuffer(video, dst, width, height, dst_pitch); + return; + } + + uint32 *udst = (uint32 *)dst; + const uint32 *src = (const uint32 *)video; + const uint8 *anim_line = ((const uint32 *)video - (uint32 *)_screen.dst_ptr) + anim_buf; + + for (; height > 0; height--) { + for (int x = 0; x < width; x++) { + udst[x] = this->RealizeBlendedColour(anim_line[x], src[x]).data; + } + src += _screen.pitch; + anim_line += _screen.pitch; + udst += dst_pitch; + } +} + +void Blitter_40bppAnim::ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y) +{ + assert(!_screen_disable_anim); + assert(video >= _screen.dst_ptr && video <= (uint32 *)_screen.dst_ptr + _screen.width + _screen.height * _screen.pitch); + uint8 *anim_buf = VideoDriver::GetInstance()->GetAnimBuffer(); + uint8 *dst, *src; + + /* We need to scroll the anim-buffer too */ + if (scroll_y > 0) { + dst = anim_buf + left + (top + height - 1) * _screen.pitch; + src = dst - scroll_y * _screen.pitch; + + /* Adjust left & width */ + if (scroll_x >= 0) { + dst += scroll_x; + } else { + src -= scroll_x; + } + + uint tw = width + (scroll_x >= 0 ? -scroll_x : scroll_x); + uint th = height - scroll_y; + for (; th > 0; th--) { + memcpy(dst, src, tw * sizeof(uint8)); + src -= _screen.pitch; + dst -= _screen.pitch; + } + } else { + /* Calculate pointers */ + dst = anim_buf + left + top * _screen.pitch; + src = dst - scroll_y * _screen.pitch; + + /* Adjust left & width */ + if (scroll_x >= 0) { + dst += scroll_x; + } else { + src -= scroll_x; + } + + /* the y-displacement may be 0 therefore we have to use memmove, + * because source and destination may overlap */ + uint tw = width + (scroll_x >= 0 ? -scroll_x : scroll_x); + uint th = height + scroll_y; + for (; th > 0; th--) { + memmove(dst, src, tw * sizeof(uint8)); + src += _screen.pitch; + dst += _screen.pitch; + } + } + + Blitter_32bppBase::ScrollBuffer(video, left, top, width, height, scroll_x, scroll_y); +} + +int Blitter_40bppAnim::BufferSize(int width, int height) +{ + return width * height * (sizeof(uint32) + sizeof(uint8)); +} + +Blitter::PaletteAnimation Blitter_40bppAnim::UsePaletteAnimation() +{ + return Blitter::PALETTE_ANIMATION_VIDEO_BACKEND; +} + +bool Blitter_40bppAnim::NeedsAnimationBuffer() +{ + return true; +} diff --git a/src/blitter/40bpp_anim.hpp b/src/blitter/40bpp_anim.hpp new file mode 100644 index 000000000..8d7e6ce32 --- /dev/null +++ b/src/blitter/40bpp_anim.hpp @@ -0,0 +1,63 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>. + */ + +/** @file 40bpp_optimized.hpp Optimized 40 bpp blitter. */ + +#ifndef BLITTER_40BPP_OPTIMIZED_HPP +#define BLITTER_40BPP_OPTIMIZED_HPP + + +#include "32bpp_optimized.hpp" +#include "../video/video_driver.hpp" + +/** The optimized 40 bpp blitter (for OpenGL video driver). */ +class Blitter_40bppAnim : public Blitter_32bppOptimized { +public: + + // void *MoveTo(void *video, int x, int y) override; + void SetPixel(void *video, int x, int y, uint8 colour) override; + void DrawRect(void *video, int width, int height, uint8 colour) override; + void CopyFromBuffer(void *video, const void *src, int width, int height) override; + void CopyToBuffer(const void *video, void *dst, int width, int height) override; + void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) override; + void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y) override; + void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override; + void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) override; + Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) override; + int BufferSize(int width, int height) override; + Blitter::PaletteAnimation UsePaletteAnimation() override; + bool NeedsAnimationBuffer() override; + + const char *GetName() override { return "40bpp-anim"; } + int GetBytesPerPixel() override { return 5; } + + template <BlitterMode mode> void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom); + +protected: + static inline Colour RealizeBlendedColour(uint8 anim, Colour c) + { + return anim != 0 ? AdjustBrightness(LookupColourInPalette(anim), GetColourBrightness(c)) : c; + } + +}; + +/** Factory for the 40 bpp animated blitter (for OpenGL). */ +class FBlitter_40bppAnim : public BlitterFactory { +protected: + bool IsUsable() const override + { + return VideoDriver::GetInstance() == nullptr || VideoDriver::GetInstance()->HasAnimBuffer(); + } + +public: + FBlitter_40bppAnim() : BlitterFactory("40bpp-anim", "40bpp Animation Blitter (OpenGL)") {} + Blitter *CreateInstance() override { return new Blitter_40bppAnim(); } +}; + +#endif /* BLITTER_40BPP_OPTIMIZED_HPP */ diff --git a/src/blitter/CMakeLists.txt b/src/blitter/CMakeLists.txt index 0aff38141..ddcc9a008 100644 --- a/src/blitter/CMakeLists.txt +++ b/src/blitter/CMakeLists.txt @@ -32,6 +32,13 @@ add_files( CONDITION NOT OPTION_DEDICATED AND SSE_FOUND ) +add_files( + 40bpp_anim.cpp + 40bpp_anim.hpp + CONDITION NOT OPTION_DEDICATED AND OPENGL_FOUND +) + + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") set_compile_flags( 32bpp_anim_sse2.cpp diff --git a/src/gfxinit.cpp b/src/gfxinit.cpp index 441f18863..fe37c3eb5 100644 --- a/src/gfxinit.cpp +++ b/src/gfxinit.cpp @@ -275,13 +275,14 @@ static bool SwitchNewGRFBlitter() uint animation; ///< 0: no support, 1: do support, 2: both uint min_base_depth, max_base_depth, min_grf_depth, max_grf_depth; } replacement_blitters[] = { + { "8bpp-optimized", 2, 8, 8, 8, 8 }, + { "40bpp-anim", 2, 8, 32, 8, 32 }, #ifdef WITH_SSE { "32bpp-sse4", 0, 32, 32, 8, 32 }, { "32bpp-ssse3", 0, 32, 32, 8, 32 }, { "32bpp-sse2", 0, 32, 32, 8, 32 }, { "32bpp-sse4-anim", 1, 32, 32, 8, 32 }, #endif - { "8bpp-optimized", 2, 8, 8, 8, 8 }, { "32bpp-optimized", 0, 8, 32, 8, 32 }, #ifdef WITH_SSE { "32bpp-sse2-anim", 1, 8, 32, 8, 32 }, |