summaryrefslogtreecommitdiff
path: root/src/blitter/32bpp_anim.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/blitter/32bpp_anim.cpp')
-rw-r--r--src/blitter/32bpp_anim.cpp205
1 files changed, 155 insertions, 50 deletions
diff --git a/src/blitter/32bpp_anim.cpp b/src/blitter/32bpp_anim.cpp
index 720a769bb..9523c2dec 100644
--- a/src/blitter/32bpp_anim.cpp
+++ b/src/blitter/32bpp_anim.cpp
@@ -15,64 +15,118 @@
static FBlitter_32bppAnim iFBlitter_32bppAnim;
-void Blitter_32bppAnim::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom)
+template <BlitterMode mode>
+inline void Blitter_32bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom)
{
- 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 Draw() */
- Blitter_32bppOptimized::Draw(bp, mode, zoom);
- return;
- }
+ const SpriteData *src = (const SpriteData *)bp->sprite;
- const SpriteLoader::CommonPixel *src, *src_line;
- uint32 *dst, *dst_line;
- uint8 *anim, *anim_line;
+ const Colour *src_px = (const Colour *)(src->data + src->offset[zoom][0]);
+ const uint8 *src_n = (const uint8 *)(src->data + src->offset[zoom][1]);
- if (_screen.width != this->anim_buf_width || _screen.height != this->anim_buf_height) {
- /* The size of the screen changed; we can assume we can wipe all data from our buffer */
- free(this->anim_buf);
- this->anim_buf = CallocT<uint8>(_screen.width * _screen.height);
- this->anim_buf_width = _screen.width;
- this->anim_buf_height = _screen.height;
+ for (uint i = bp->skip_top; i != 0; i--) {
+ src_px = (const Colour *)((const byte *)src_px + *(const uint32 *)src_px);
+ src_n += *(const uint32 *)src_n;
}
- /* Find where to start reading in the source sprite */
- src_line = (const SpriteLoader::CommonPixel *)bp->sprite + (bp->skip_top * bp->sprite_width + bp->skip_left) * ScaleByZoom(1, zoom);
- dst_line = (uint32 *)bp->dst + bp->top * bp->pitch + bp->left;
- anim_line = this->anim_buf + ((uint32 *)bp->dst - (uint32 *)_screen.dst_ptr) + bp->top * this->anim_buf_width + bp->left;
+ uint32 *dst = (uint32 *)bp->dst + bp->top * bp->pitch + bp->left;
+ uint8 *anim = this->anim_buf + ((uint32 *)bp->dst - (uint32 *)_screen.dst_ptr) + bp->top * this->anim_buf_width + bp->left;
+
+ const byte *remap = bp->remap; // store so we don't have to access it via bp everytime
for (int y = 0; y < bp->height; y++) {
- dst = dst_line;
- dst_line += bp->pitch;
+ uint32 *dst_ln = dst + bp->pitch;
+ uint8 *anim_ln = anim + this->anim_buf_width;
- src = src_line;
- src_line += bp->sprite_width * ScaleByZoom(1, zoom);
+ const Colour *src_px_ln = (const Colour *)((const byte *)src_px + *(const uint32 *)src_px);
+ src_px++;
- anim = anim_line;
- anim_line += this->anim_buf_width;
+ const uint8 *src_n_ln = src_n + *(uint32 *)src_n;
+ src_n += 4;
+
+ uint32 *dst_end = dst + bp->skip_left;
+
+ 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 = 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;
- for (int x = 0; x < bp->width; x++) {
- if (src->a == 0) {
- /* src->r is 'misused' here to indicate how much more pixels are following with an alpha of 0 */
- int skip = UnScaleByZoom(src->r, zoom);
+ while (dst < dst_end) {
+ n = min<uint>(*src_n++, (uint)(dst_end - dst));
- dst += skip;
- anim += skip;
- x += skip - 1;
- src += ScaleByZoom(1, zoom) * skip;
+ if (src_px->a == 0) {
+ anim += n;
+ dst += n;
+ src_px++;
+ src_n++;
continue;
}
+ draw:;
+
switch (mode) {
case BM_COLOUR_REMAP:
- /* In case the m-channel is zero, do not remap this pixel in any way */
- if (src->m == 0) {
- *dst = ComposeColourRGBA(src->r, src->g, src->b, src->a, *dst);
- *anim = 0;
+ 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;
+ *anim = 0;
+ } else {
+ uint r = remap[m];
+ *anim = r;
+ if (r != 0) *dst = this->LookupColourInPalette(r);
+ }
+ anim++;
+ dst++;
+ src_px++;
+ src_n++;
+ } while (--n != 0);
} else {
- if (bp->remap[src->m] != 0) {
- *dst = ComposeColourPA(this->LookupColourInPalette(bp->remap[src->m]), src->a, *dst);
- *anim = bp->remap[src->m];
- }
+ 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 {
+ uint r = remap[m];
+ *anim = r;
+ if (r != 0) *dst = ComposeColourPANoCheck(this->LookupColourInPalette(r), src_px->a, *dst);
+ }
+ anim++;
+ dst++;
+ src_px++;
+ src_n++;
+ } while (--n != 0);
}
break;
@@ -82,21 +136,72 @@ void Blitter_32bppAnim::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomL
* we produce a result the newgrf maker didn't expect ;) */
/* Make the current color a bit more black, so it looks like this image is transparent */
- *dst = MakeTransparent(*dst, 192);
- *anim = bp->remap[*anim];
+ src_px += n;
+ src_n += n;
+
+ do {
+ *dst = MakeTransparent(*dst, 192);
+ *anim = remap[*anim];
+ anim++;
+ dst++;
+ } while (--n != 0);
break;
default:
- /* Above 217 is palette animation */
- if (src->m >= 217) *dst = ComposeColourPA(this->LookupColourInPalette(src->m), src->a, *dst);
- else *dst = ComposeColourRGBA(src->r, src->g, src->b, src->a, *dst);
- *anim = src->m;
+ if (src_px->a == 255) {
+ do {
+ /* Compiler assumes pointer aliasing, can't optimise this on its own */
+ uint m = *src_n++;
+ /* Above 217 is palette animation */
+ *anim++ = m;
+ *dst++ = (m >= 217) ? this->LookupColourInPalette(m) : *src_px;
+ src_px++;
+ } while (--n != 0);
+ } else {
+ do {
+ uint m = *src_n++;
+ *anim++ = m;
+ if (m >= 217) {
+ *dst = ComposeColourPANoCheck(this->LookupColourInPalette(m), src_px->a, *dst);
+ } else {
+ *dst = ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, *dst);
+ }
+ dst++;
+ src_px++;
+ } while (--n != 0);
+ }
break;
}
- dst++;
- anim++;
- src += ScaleByZoom(1, zoom);
}
+
+ anim = anim_ln;
+ dst = dst_ln;
+ src_px = src_px_ln;
+ src_n = src_n_ln;
+ }
+}
+
+void Blitter_32bppAnim::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom)
+{
+ 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 Draw() */
+ Blitter_32bppOptimized::Draw(bp, mode, zoom);
+ return;
+ }
+
+ if (_screen.width != this->anim_buf_width || _screen.height != this->anim_buf_height) {
+ /* The size of the screen changed; we can assume we can wipe all data from our buffer */
+ free(this->anim_buf);
+ this->anim_buf = CallocT<uint8>(_screen.width * _screen.height);
+ this->anim_buf_width = _screen.width;
+ this->anim_buf_height = _screen.height;
+ }
+
+ 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;
}
}