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