peter1138@6872: /* $Id$ */ peter1138@6872: rubidium@9111: /** @file 8bpp_optimized.cpp Implementation of the optimized 8 bpp blitter. */ peter1138@6872: truelight@6852: #include "../stdafx.h" rubidium@8123: #include "../zoom_func.h" truelight@6852: #include "../debug.h" rubidium@8130: #include "../core/alloc_func.hpp" smatz@9437: #include "../core/math_func.hpp" truelight@6852: #include "8bpp_optimized.hpp" truelight@6852: truelight@6852: static FBlitter_8bppOptimized iFBlitter_8bppOptimized; truelight@6852: truelight@6852: void Blitter_8bppOptimized::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) truelight@6852: { truelight@6852: /* Find the offset of this zoom-level */ smatz@9437: uint offset = ((const uint8 *)bp->sprite)[(int)(zoom - ZOOM_LVL_BEGIN) * 2] | ((const byte *)bp->sprite)[(int)(zoom - ZOOM_LVL_BEGIN) * 2 + 1] << 8; truelight@6852: truelight@6852: /* Find where to start reading in the source sprite */ smatz@9437: const uint8 *src = (const uint8 *)bp->sprite + offset; smatz@9437: uint8 *dst_line = (uint8 *)bp->dst + bp->top * bp->pitch + bp->left; truelight@6852: truelight@6852: /* Skip over the top lines in the source image */ truelight@6852: for (int y = 0; y < bp->skip_top; y++) { truelight@6852: for (;;) { smatz@9437: uint trans = *src++; smatz@9437: uint pixels = *src++; truelight@6852: if (trans == 0 && pixels == 0) break; truelight@6852: src += pixels; truelight@6852: } truelight@6852: } truelight@6852: smatz@9437: const uint8 *src_next = src; truelight@6852: truelight@6852: for (int y = 0; y < bp->height; y++) { smatz@9437: uint8 *dst = dst_line; truelight@6852: dst_line += bp->pitch; truelight@6852: truelight@6852: uint skip_left = bp->skip_left; truelight@6852: int width = bp->width; truelight@6852: truelight@6852: for (;;) { truelight@6852: src = src_next; smatz@9437: uint trans = *src++; smatz@9437: uint pixels = *src++; truelight@6852: src_next = src + pixels; truelight@6852: if (trans == 0 && pixels == 0) break; truelight@6852: if (width <= 0) continue; truelight@6852: truelight@6852: if (skip_left != 0) { truelight@6852: if (skip_left < trans) { truelight@6852: trans -= skip_left; truelight@6852: skip_left = 0; truelight@6852: } else { truelight@6852: skip_left -= trans; truelight@6852: trans = 0; truelight@6852: } truelight@6852: if (skip_left < pixels) { truelight@6852: src += skip_left; truelight@6852: pixels -= skip_left; truelight@6852: skip_left = 0; truelight@6852: } else { truelight@6852: src += pixels; truelight@6852: skip_left -= pixels; truelight@6852: pixels = 0; truelight@6852: } truelight@6852: } truelight@6852: if (skip_left != 0) continue; truelight@6852: truelight@6852: /* Skip transparent pixels */ truelight@6852: dst += trans; truelight@6852: width -= trans; truelight@6852: if (width <= 0) continue; smatz@9437: pixels = min(pixels, (uint)width); truelight@6852: width -= pixels; truelight@6852: truelight@6852: switch (mode) { truelight@6852: case BM_COLOUR_REMAP: truelight@6852: for (uint x = 0; x < pixels; x++) { truelight@6852: if (bp->remap[*src] != 0) *dst = bp->remap[*src]; truelight@6852: dst++; src++; truelight@6852: } truelight@6852: break; truelight@6852: truelight@6852: case BM_TRANSPARENT: truelight@6852: for (uint x = 0; x < pixels; x++) { truelight@6852: *dst = bp->remap[*dst]; truelight@6852: dst++; src++; truelight@6852: } truelight@6852: break; truelight@6852: truelight@6852: default: truelight@6852: memcpy(dst, src, pixels); truelight@6852: dst += pixels; src += pixels; truelight@6852: break; truelight@6852: } truelight@6852: } truelight@6852: } truelight@6852: } truelight@6852: truelight@6856: Sprite *Blitter_8bppOptimized::Encode(SpriteLoader::Sprite *sprite, Blitter::AllocatorProc *allocator) truelight@6852: { smatz@9437: /* Make memory for all zoom-levels */ smatz@9437: uint memory = (int)(ZOOM_LVL_END - ZOOM_LVL_BEGIN) * sizeof(uint16); truelight@6852: smatz@8095: for (ZoomLevel i = ZOOM_LVL_BEGIN; i < ZOOM_LVL_END; i++) { smatz@8095: memory += UnScaleByZoom(sprite->height, i) * UnScaleByZoom(sprite->width, i); truelight@6852: } truelight@6852: truelight@6852: /* We have no idea how much memory we really need, so just guess something */ truelight@6852: memory *= 5; smatz@9437: byte *temp_dst = MallocT(memory); smatz@9437: byte *dst = &temp_dst[(ZOOM_LVL_END - ZOOM_LVL_BEGIN) * 2]; truelight@6852: truelight@6852: /* Make the sprites per zoom-level */ smatz@8095: for (ZoomLevel i = ZOOM_LVL_BEGIN; i < ZOOM_LVL_END; i++) { truelight@6852: /* Store the index table */ smatz@9437: uint index = dst - temp_dst; truelight@6852: temp_dst[i * 2] = index & 0xFF; truelight@6852: temp_dst[i * 2 + 1] = (index >> 8) & 0xFF; truelight@6852: smatz@9437: /* cache values, because compiler can't cache it */ smatz@9437: int scaled_height = UnScaleByZoom(sprite->height, i); smatz@9437: int scaled_width = UnScaleByZoom(sprite->width, i); smatz@9437: int scaled_1 = ScaleByZoom(1, i); truelight@6852: smatz@9437: for (int y = 0; y < scaled_height; y++) { truelight@6852: uint trans = 0; truelight@6852: uint pixels = 0; smatz@9437: uint last_colour = 0; smatz@9437: byte *count_dst = NULL; truelight@6852: smatz@9437: /* Store the scaled image */ smatz@9437: const SpriteLoader::CommonPixel *src = &sprite->data[ScaleByZoom(y, i) * sprite->width]; smatz@9437: const SpriteLoader::CommonPixel *src_end = &src[sprite->width]; smatz@9437: smatz@9437: for (int x = 0; x < scaled_width; x++) { smatz@9437: uint colour = 0; truelight@6852: truelight@6852: /* Get the color keeping in mind the zoom-level */ smatz@9437: for (int j = 0; j < scaled_1; j++) { smatz@9437: if (src->m != 0) colour = src->m; truelight@6855: /* Because of the scaling it might happen we read outside the buffer. Avoid that. */ smatz@9437: if (++src == src_end) break; truelight@6852: } truelight@6852: smatz@9437: if (last_colour == 0 || colour == 0 || pixels == 255) { smatz@9437: if (count_dst != NULL) { truelight@6852: /* Write how many non-transparent bytes we get */ smatz@9437: *count_dst = pixels; truelight@6852: pixels = 0; smatz@9437: count_dst = NULL; truelight@6852: } truelight@6852: /* As long as we find transparency bytes, keep counting */ smatz@9437: if (colour == 0) { smatz@9437: last_colour = 0; truelight@6852: trans++; truelight@6852: continue; truelight@6852: } truelight@6852: /* No longer transparency, so write the amount of transparent bytes */ truelight@6852: *dst = trans; smatz@9437: dst++; truelight@6852: trans = 0; truelight@6852: /* Reserve a byte for the pixel counter */ smatz@9437: count_dst = dst; smatz@9437: dst++; truelight@6852: } smatz@9437: last_colour = colour; truelight@6852: pixels++; smatz@9437: *dst = colour; smatz@9437: dst++; truelight@6852: } truelight@6852: smatz@9437: if (count_dst != NULL) *count_dst = pixels; truelight@6852: truelight@6852: /* Write line-ending */ smatz@9437: *dst = 0; dst++; smatz@9437: *dst = 0; dst++; truelight@6852: } truelight@6852: } truelight@6852: smatz@9437: uint size = dst - temp_dst; smatz@9437: truelight@6852: /* Safety check, to make sure we guessed the size correctly */ smatz@9437: assert(size < memory); truelight@6852: truelight@6852: /* Allocate the exact amount of memory we need */ smatz@9437: Sprite *dest_sprite = (Sprite *)allocator(sizeof(*dest_sprite) + size); truelight@6852: truelight@6852: dest_sprite->height = sprite->height; truelight@6852: dest_sprite->width = sprite->width; truelight@6852: dest_sprite->x_offs = sprite->x_offs; truelight@6852: dest_sprite->y_offs = sprite->y_offs; smatz@9437: memcpy(dest_sprite->data, temp_dst, size); rubidium@7088: free(temp_dst); truelight@6852: truelight@6852: return dest_sprite; truelight@6852: }