diff options
Diffstat (limited to 'src/blitter/8bpp_optimized.cpp')
-rw-r--r-- | src/blitter/8bpp_optimized.cpp | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/src/blitter/8bpp_optimized.cpp b/src/blitter/8bpp_optimized.cpp new file mode 100644 index 000000000..00c427441 --- /dev/null +++ b/src/blitter/8bpp_optimized.cpp @@ -0,0 +1,199 @@ +#include "../stdafx.h" +#include "../zoom.hpp" +#include "../gfx.h" +#include "../debug.h" +#include "8bpp_optimized.hpp" + +static FBlitter_8bppOptimized iFBlitter_8bppOptimized; + +extern void* AllocSprite(size_t); + +void Blitter_8bppOptimized::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) +{ + const byte *src, *src_next; + Pixel8 *dst, *dst_line; + uint offset = 0; + + /* Find the offset of this zoom-level */ + offset = ((const byte *)bp->sprite)[(int)zoom * 2] | ((const byte *)bp->sprite)[(int)zoom * 2 + 1] << 8; + + /* Find where to start reading in the source sprite */ + src = (const byte *)bp->sprite + offset; + dst_line = (Pixel8 *)bp->dst + bp->top * bp->pitch + bp->left; + + /* Skip over the top lines in the source image */ + for (int y = 0; y < bp->skip_top; y++) { + uint trans, pixels; + for (;;) { + trans = *src++; + pixels = *src++; + if (trans == 0 && pixels == 0) break; + src += pixels; + } + } + + src_next = src; + + for (int y = 0; y < bp->height; y++) { + dst = dst_line; + dst_line += bp->pitch; + + uint skip_left = bp->skip_left; + int width = bp->width; + + for (;;) { + src = src_next; + uint8 trans = *src++; + uint8 pixels = *src++; + src_next = src + pixels; + if (trans == 0 && pixels == 0) break; + if (width <= 0) continue; + + if (skip_left != 0) { + if (skip_left < trans) { + trans -= skip_left; + skip_left = 0; + } else { + skip_left -= trans; + trans = 0; + } + if (skip_left < pixels) { + src += skip_left; + pixels -= skip_left; + skip_left = 0; + } else { + src += pixels; + skip_left -= pixels; + pixels = 0; + } + } + if (skip_left != 0) continue; + + /* Skip transparent pixels */ + dst += trans; + width -= trans; + if (width <= 0) continue; + if (pixels > width) pixels = width; + width -= pixels; + + switch (mode) { + case BM_COLOUR_REMAP: + for (uint x = 0; x < pixels; x++) { + if (bp->remap[*src] != 0) *dst = bp->remap[*src]; + dst++; src++; + } + break; + + case BM_TRANSPARENT: + for (uint x = 0; x < pixels; x++) { + *dst = bp->remap[*dst]; + dst++; src++; + } + break; + + default: + memcpy(dst, src, pixels); + dst += pixels; src += pixels; + break; + } + } + } +} + +Sprite *Blitter_8bppOptimized::Encode(SpriteLoader::Sprite *sprite) +{ + Sprite *dest_sprite; + byte *temp_dst; + uint memory = 0; + uint index = 0; + + /* Make memory for all zoom-levels */ + memory += (int)ZOOM_LVL_END * sizeof(uint16); + for (int i = 0; i < (int)ZOOM_LVL_END; i++) { + memory += UnScaleByZoom(sprite->height, (ZoomLevel)i) * UnScaleByZoom(sprite->width, (ZoomLevel)i); + index += 2; + } + + /* We have no idea how much memory we really need, so just guess something */ + memory *= 5; + temp_dst = MallocT<byte>(memory); + + /* Make the sprites per zoom-level */ + for (int i = 0; i < (int)ZOOM_LVL_END; i++) { + /* Store the scaled image */ + const SpriteLoader::CommonPixel *src; + + /* Store the index table */ + temp_dst[i * 2] = index & 0xFF; + temp_dst[i * 2 + 1] = (index >> 8) & 0xFF; + + byte *dst = &temp_dst[index]; + + for (int y = 0; y < UnScaleByZoom(sprite->height, (ZoomLevel)i); y++) { + uint trans = 0; + uint pixels = 0; + uint last_color = 0; + uint count_index = 0; + src = &sprite->data[ScaleByZoom(y, (ZoomLevel)i) * sprite->width]; + + for (int x = 0; x < UnScaleByZoom(sprite->width, (ZoomLevel)i); x++) { + uint color = 0; + int count = 0; + + /* Get the color keeping in mind the zoom-level */ + for (int j = 0; j < ScaleByZoom(1, (ZoomLevel)i); j++) { + if (src->m != 0) { color = src->m; count++; } + src++; + } + /* If more than 12.5% of the pixels are non-transparent, make thisone non-transparent too */ + if (count < ScaleByZoom(1, (ZoomLevel)i) / 8) color = 0; + + if (last_color == 0 || color == 0) { + if (count_index != 0) { + /* Write how many non-transparent bytes we get */ + temp_dst[count_index] = pixels; + pixels = 0; + count_index = 0; + } + /* As long as we find transparency bytes, keep counting */ + if (color == 0) { + last_color = 0; + trans++; + continue; + } + /* No longer transparency, so write the amount of transparent bytes */ + *dst = trans; + dst++; index++; + trans = 0; + /* Reserve a byte for the pixel counter */ + count_index = index; + dst++; index++; + } + last_color = color; + pixels++; + *dst = color; + dst++; index++; + } + + if (count_index != 0) temp_dst[count_index] = pixels; + + /* Write line-ending */ + *dst = 0; dst++; index++; + *dst = 0; dst++; index++; + } + } + + /* Safety check, to make sure we guessed the size correctly */ + assert(index < memory); + + /* Allocate the exact amount of memory we need */ + dest_sprite = (Sprite *)AllocSprite(sizeof(*dest_sprite) + index); + + dest_sprite->height = sprite->height; + dest_sprite->width = sprite->width; + dest_sprite->x_offs = sprite->x_offs; + dest_sprite->y_offs = sprite->y_offs; + memcpy(dest_sprite->data, temp_dst, index); + + return dest_sprite; +} |