peter1138@6872: /* $Id$ */ peter1138@6872: peter1138@6872: /** @file 8bpp_optimized.cpp */ 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" 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@6878: const uint8 *src, *src_next; truelight@6878: uint8 *dst, *dst_line; truelight@6852: uint offset = 0; truelight@6852: truelight@6852: /* Find the offset of this zoom-level */ smatz@8095: 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 */ truelight@6878: src = (const uint8 *)bp->sprite + offset; truelight@6878: 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: uint trans, pixels; truelight@6852: for (;;) { truelight@6852: trans = *src++; truelight@6852: pixels = *src++; truelight@6852: if (trans == 0 && pixels == 0) break; truelight@6852: src += pixels; truelight@6852: } truelight@6852: } truelight@6852: truelight@6852: src_next = src; truelight@6852: truelight@6852: for (int y = 0; y < bp->height; y++) { truelight@6852: 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; truelight@6852: uint8 trans = *src++; truelight@6852: uint8 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; truelight@6852: if (pixels > width) pixels = 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: { truelight@6852: Sprite *dest_sprite; truelight@6852: byte *temp_dst; truelight@6852: uint memory = 0; truelight@6852: uint index = 0; truelight@6852: truelight@6852: /* Make memory for all zoom-levels */ smatz@8095: memory += (int)(ZOOM_LVL_END - ZOOM_LVL_BEGIN) * sizeof(uint16); 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: index += 2; truelight@6852: } truelight@6852: truelight@6852: /* We have no idea how much memory we really need, so just guess something */ truelight@6852: memory *= 5; truelight@6852: temp_dst = MallocT(memory); 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 scaled image */ truelight@6852: const SpriteLoader::CommonPixel *src; truelight@6852: truelight@6852: /* Store the index table */ truelight@6852: temp_dst[i * 2] = index & 0xFF; truelight@6852: temp_dst[i * 2 + 1] = (index >> 8) & 0xFF; truelight@6852: truelight@6852: byte *dst = &temp_dst[index]; truelight@6852: smatz@8095: for (int y = 0; y < UnScaleByZoom(sprite->height, i); y++) { truelight@6852: uint trans = 0; truelight@6852: uint pixels = 0; truelight@6852: uint last_color = 0; truelight@6852: uint count_index = 0; truelight@6855: uint rx = 0; smatz@8095: src = &sprite->data[ScaleByZoom(y, i) * sprite->width]; truelight@6852: smatz@8095: for (int x = 0; x < UnScaleByZoom(sprite->width, i); x++) { truelight@6852: uint color = 0; truelight@6852: truelight@6852: /* Get the color keeping in mind the zoom-level */ smatz@8095: for (int j = 0; j < ScaleByZoom(1, i); j++) { truelight@6860: if (src->m != 0) color = src->m; truelight@6852: src++; truelight@6855: rx++; truelight@6855: /* Because of the scaling it might happen we read outside the buffer. Avoid that. */ truelight@6855: if (rx == sprite->width) break; truelight@6852: } truelight@6852: truelight@6978: if (last_color == 0 || color == 0 || pixels == 255) { truelight@6852: if (count_index != 0) { truelight@6852: /* Write how many non-transparent bytes we get */ truelight@6852: temp_dst[count_index] = pixels; truelight@6852: pixels = 0; truelight@6852: count_index = 0; truelight@6852: } truelight@6852: /* As long as we find transparency bytes, keep counting */ truelight@6852: if (color == 0) { truelight@6852: last_color = 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; truelight@6852: dst++; index++; truelight@6852: trans = 0; truelight@6852: /* Reserve a byte for the pixel counter */ truelight@6852: count_index = index; truelight@6852: dst++; index++; truelight@6852: } truelight@6852: last_color = color; truelight@6852: pixels++; truelight@6852: *dst = color; truelight@6852: dst++; index++; truelight@6852: } truelight@6852: truelight@6852: if (count_index != 0) temp_dst[count_index] = pixels; truelight@6852: truelight@6852: /* Write line-ending */ truelight@6852: *dst = 0; dst++; index++; truelight@6852: *dst = 0; dst++; index++; truelight@6852: } truelight@6852: } truelight@6852: truelight@6852: /* Safety check, to make sure we guessed the size correctly */ truelight@6852: assert(index < memory); truelight@6852: truelight@6852: /* Allocate the exact amount of memory we need */ truelight@6856: dest_sprite = (Sprite *)allocator(sizeof(*dest_sprite) + index); 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; truelight@6852: memcpy(dest_sprite->data, temp_dst, index); rubidium@7088: free(temp_dst); truelight@6852: truelight@6852: return dest_sprite; truelight@6852: }