src/blitter/32bpp_anim.cpp
changeset 11082 45ab75d184a0
parent 11013 71b7f7c475db
child 11083 19aff1f3244e
--- a/src/blitter/32bpp_anim.cpp	Thu Jun 26 00:40:42 2008 +0000
+++ b/src/blitter/32bpp_anim.cpp	Thu Jun 26 15:46:19 2008 +0000
@@ -15,6 +15,172 @@
 
 static FBlitter_32bppAnim iFBlitter_32bppAnim;
 
+template <BlitterMode mode>
+inline void Blitter_32bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom)
+{
+	const SpriteData *src = (const SpriteData *)bp->sprite;
+
+	const Colour *src_px = (const Colour *)(src->data + src->offset[zoom][0]);
+	const uint8  *src_n  = (const uint8  *)(src->data + src->offset[zoom][1]);
+
+	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;
+	}
+
+	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++) {
+		uint32 *dst_ln = dst + bp->pitch;
+		uint8 *anim_ln = anim + this->anim_buf_width;
+
+		const Colour *src_px_ln = (const Colour *)((const byte *)src_px + *(const uint32 *)src_px);
+		src_px++;
+
+		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;
+
+		while (dst < dst_end) {
+			n = 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:
+					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 {
+						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;
+
+				case BM_TRANSPARENT:
+					/* TODO -- We make an assumption here that the remap in fact is transparency, not some color.
+					 *  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 color a bit more black, so it looks like this image is transparent */
+					src_px += n;
+					src_n += n;
+
+					do {
+						*dst = MakeTransparent(*dst, 192);
+						*anim = remap[*anim];
+						anim++;
+						dst++;
+					} while (--n != 0);
+					break;
+
+				default:
+					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;
+			}
+		}
+
+		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) {
@@ -23,10 +189,6 @@
 		return;
 	}
 
-	const SpriteLoader::CommonPixel *src, *src_line;
-	uint32 *dst, *dst_line;
-	uint8 *anim, *anim_line;
-
 	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);
@@ -35,68 +197,11 @@
 		this->anim_buf_height = _screen.height;
 	}
 
-	/* 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;
-
-	for (int y = 0; y < bp->height; y++) {
-		dst = dst_line;
-		dst_line += bp->pitch;
-
-		src = src_line;
-		src_line += bp->sprite_width * ScaleByZoom(1, zoom);
-
-		anim = anim_line;
-		anim_line += this->anim_buf_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);
-
-				dst  += skip;
-				anim += skip;
-				x    += skip - 1;
-				src  += ScaleByZoom(1, zoom) * skip;
-				continue;
-			}
-
-			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;
-					} else {
-						if (bp->remap[src->m] != 0) {
-							*dst = ComposeColourPA(this->LookupColourInPalette(bp->remap[src->m]), src->a, *dst);
-							*anim = bp->remap[src->m];
-						}
-					}
-					break;
-
-				case BM_TRANSPARENT:
-					/* TODO -- We make an assumption here that the remap in fact is transparency, not some color.
-					 *  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 color a bit more black, so it looks like this image is transparent */
-					*dst = MakeTransparent(*dst, 192);
-					*anim = bp->remap[*anim];
-					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;
-					break;
-			}
-			dst++;
-			anim++;
-			src += ScaleByZoom(1, zoom);
-		}
+	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;
 	}
 }