/** * Compose a colour based on RGBA values and the current pixel value. * Handles fully transparent and solid pixels in a special (faster) way. */ static inline uint32 ComposeColourRGBA(uint r, uint g, uint b, uint a, uint32 current) { if (a == 0) return current; if (a >= 255) return ComposeColour(0xFF, r, g, b); return ComposeColourRGBANoCheck(r, g, b, a, current); }
/** * Compose a colour based on Pixel value, alpha value, and the current pixel value. */ static inline uint32 ComposeColourPANoCheck(uint32 colour, uint a, uint32 current) { uint r = GB(colour, 16, 8); uint g = GB(colour, 8, 8); uint b = GB(colour, 0, 8); return ComposeColourRGBANoCheck(r, g, b, a, current); }
/** * Compose a colour based on Pixel value, alpha value, and the current pixel value. */ static inline Colour ComposeColourPANoCheck(Colour colour, uint a, Colour current) { uint r = colour.r; uint g = colour.g; uint b = colour.b; return ComposeColourRGBANoCheck(r, g, b, a, current); }
inline void Blitter_32bppOptimized::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 uint8 *src_n = (const uint8 *)(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 += *(uint32 *)src_n; } /* skip lines in dst */ uint32 *dst = (uint32 *)bp->dst + 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 */ uint32 *dst_ln = dst + 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 uint8 *src_n_ln = src_n + *(uint32 *)src_n; src_n += 4; /* we will end this line when we reach this point */ uint32 *dst_end = dst + bp->skip_left; /* number of pixels with the same aplha channel class */ uint n; while (dst < dst_end) { n = *src_n++; if (src_px->a == 0) { dst += n; src_px ++; src_n++; } 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) { 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->data; } else { uint r = remap[m]; if (r != 0) *dst = this->LookupColourInPalette(r); } 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 { uint r = remap[m]; if (r != 0) *dst = ComposeColourPANoCheck(this->LookupColourInPalette(r), src_px->a, *dst); } 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 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 { *dst = MakeTransparent(*dst, 3, 4); dst++; } while (--n != 0); } else { do { *dst = MakeTransparent(*dst, (256 * 4 - src_px->a), 256 * 4); dst++; src_px++; } while (--n != 0); } break; default: if (src_px->a == 255) { /* faster than memcpy(), n is usually low */ src_n += n; do { *dst = src_px->data; dst++; src_px++; } while (--n != 0); } else { src_n += n; do { *dst = ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, *dst); dst++; src_px++; } while (--n != 0); } break; } } dst = dst_ln; src_px = src_px_ln; src_n = src_n_ln; } }
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 uint16 *src_n = (const uint16 *)(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 uint16 *)((const byte *)src_n + *(const uint32 *)src_n); } Colour *dst = (Colour *)bp->dst + bp->top * bp->pitch + bp->left; uint16 *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++) { Colour *dst_ln = dst + bp->pitch; uint16 *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 uint16 *src_n_ln = (const uint16 *)((const byte *)src_n + *(const uint32 *)src_n); src_n += 2; Colour *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->data; *anim = 0; } else { uint r = remap[GB(m, 0, 8)]; *anim = r | (m & 0xFF00); if (r != 0) *dst = this->AdjustBrightness(this->LookupColourInPalette(r), 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 { uint r = remap[GB(m, 0, 8)]; *anim = 0; if (r != 0) *dst = ComposeColourPANoCheck(this->AdjustBrightness(this->LookupColourInPalette(r), GB(m, 8, 8)), 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 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 { *dst = MakeTransparent(*dst, 3, 4); *anim = 0; anim++; dst++; } while (--n != 0); } else { do { *dst = MakeTransparent(*dst, (256 * 4 - src_px->a), 256 * 4); *anim = 0; anim++; dst++; src_px++; } while (--n != 0); } break; default: if (src_px->a == 255) { do { /* Compiler assumes pointer aliasing, can't optimise this on its own */ uint m = GB(*src_n, 0, 8); /* Above PALETTE_ANIM_START is palette animation */ *anim++ = *src_n; *dst++ = (m >= PALETTE_ANIM_START) ? this->AdjustBrightness(this->LookupColourInPalette(m), GB(*src_n, 8, 8)) : src_px->data; src_px++; src_n++; } while (--n != 0); } else { do { uint m = GB(*src_n, 0, 8); *anim++ = 0; if (m >= PALETTE_ANIM_START) { *dst = ComposeColourPANoCheck(this->AdjustBrightness(this->LookupColourInPalette(m), GB(*src_n, 8, 8)), src_px->a, *dst); } else { *dst = ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, *dst); } dst++; src_px++; src_n++; } while (--n != 0); } break; } } anim = anim_ln; dst = dst_ln; src_px = src_px_ln; src_n = src_n_ln; } }