8bpp_optimized.cpp

Go to the documentation of this file.
00001 /* $Id: 8bpp_optimized.cpp 11691 2007-12-25 09:48:53Z rubidium $ */
00002 
00005 #include "../stdafx.h"
00006 #include "../zoom_func.h"
00007 #include "../debug.h"
00008 #include "../core/alloc_func.hpp"
00009 #include "8bpp_optimized.hpp"
00010 
00011 static FBlitter_8bppOptimized iFBlitter_8bppOptimized;
00012 
00013 void Blitter_8bppOptimized::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom)
00014 {
00015   const uint8 *src, *src_next;
00016   uint8 *dst, *dst_line;
00017   uint offset = 0;
00018 
00019   /* Find the offset of this zoom-level */
00020   offset = ((const uint8 *)bp->sprite)[(int)(zoom - ZOOM_LVL_BEGIN) * 2] | ((const byte *)bp->sprite)[(int)(zoom - ZOOM_LVL_BEGIN) * 2 + 1] << 8;
00021 
00022   /* Find where to start reading in the source sprite */
00023   src = (const uint8 *)bp->sprite + offset;
00024   dst_line = (uint8 *)bp->dst + bp->top * bp->pitch + bp->left;
00025 
00026   /* Skip over the top lines in the source image */
00027   for (int y = 0; y < bp->skip_top; y++) {
00028     uint trans, pixels;
00029     for (;;) {
00030       trans = *src++;
00031       pixels = *src++;
00032       if (trans == 0 && pixels == 0) break;
00033       src += pixels;
00034     }
00035   }
00036 
00037   src_next = src;
00038 
00039   for (int y = 0; y < bp->height; y++) {
00040     dst = dst_line;
00041     dst_line += bp->pitch;
00042 
00043     uint skip_left = bp->skip_left;
00044     int width = bp->width;
00045 
00046     for (;;) {
00047       src = src_next;
00048       uint8 trans = *src++;
00049       uint8 pixels = *src++;
00050       src_next = src + pixels;
00051       if (trans == 0 && pixels == 0) break;
00052       if (width <= 0) continue;
00053 
00054       if (skip_left != 0) {
00055         if (skip_left < trans) {
00056           trans -= skip_left;
00057           skip_left = 0;
00058         } else {
00059           skip_left -= trans;
00060           trans = 0;
00061         }
00062         if (skip_left < pixels) {
00063           src += skip_left;
00064           pixels -= skip_left;
00065           skip_left = 0;
00066         } else {
00067           src += pixels;
00068           skip_left -= pixels;
00069           pixels = 0;
00070         }
00071       }
00072       if (skip_left != 0) continue;
00073 
00074       /* Skip transparent pixels */
00075       dst += trans;
00076       width -= trans;
00077       if (width <= 0) continue;
00078       if (pixels > width) pixels = width;
00079       width -= pixels;
00080 
00081       switch (mode) {
00082         case BM_COLOUR_REMAP:
00083           for (uint x = 0; x < pixels; x++) {
00084             if (bp->remap[*src] != 0) *dst = bp->remap[*src];
00085             dst++; src++;
00086           }
00087           break;
00088 
00089         case BM_TRANSPARENT:
00090           for (uint x = 0; x < pixels; x++) {
00091             *dst = bp->remap[*dst];
00092             dst++; src++;
00093           }
00094           break;
00095 
00096         default:
00097           memcpy(dst, src, pixels);
00098           dst += pixels; src += pixels;
00099           break;
00100       }
00101     }
00102   }
00103 }
00104 
00105 Sprite *Blitter_8bppOptimized::Encode(SpriteLoader::Sprite *sprite, Blitter::AllocatorProc *allocator)
00106 {
00107   Sprite *dest_sprite;
00108   byte *temp_dst;
00109   uint memory = 0;
00110   uint index = 0;
00111 
00112   /* Make memory for all zoom-levels */
00113   memory += (int)(ZOOM_LVL_END - ZOOM_LVL_BEGIN) * sizeof(uint16);
00114   for (ZoomLevel i = ZOOM_LVL_BEGIN; i < ZOOM_LVL_END; i++) {
00115     memory += UnScaleByZoom(sprite->height, i) * UnScaleByZoom(sprite->width, i);
00116     index += 2;
00117   }
00118 
00119   /* We have no idea how much memory we really need, so just guess something */
00120   memory *= 5;
00121   temp_dst = MallocT<byte>(memory);
00122 
00123   /* Make the sprites per zoom-level */
00124   for (ZoomLevel i = ZOOM_LVL_BEGIN; i < ZOOM_LVL_END; i++) {
00125     /* Store the scaled image */
00126     const SpriteLoader::CommonPixel *src;
00127 
00128     /* Store the index table */
00129     temp_dst[i * 2] = index & 0xFF;
00130     temp_dst[i * 2 + 1] = (index >> 8) & 0xFF;
00131 
00132     byte *dst = &temp_dst[index];
00133 
00134     for (int y = 0; y < UnScaleByZoom(sprite->height, i); y++) {
00135       uint trans = 0;
00136       uint pixels = 0;
00137       uint last_color = 0;
00138       uint count_index = 0;
00139       uint rx = 0;
00140       src = &sprite->data[ScaleByZoom(y, i) * sprite->width];
00141 
00142       for (int x = 0; x < UnScaleByZoom(sprite->width, i); x++) {
00143         uint color = 0;
00144 
00145         /* Get the color keeping in mind the zoom-level */
00146         for (int j = 0; j < ScaleByZoom(1, i); j++) {
00147           if (src->m != 0) color = src->m;
00148           src++;
00149           rx++;
00150           /* Because of the scaling it might happen we read outside the buffer. Avoid that. */
00151           if (rx == sprite->width) break;
00152         }
00153 
00154         if (last_color == 0 || color == 0 || pixels == 255) {
00155           if (count_index != 0) {
00156             /* Write how many non-transparent bytes we get */
00157             temp_dst[count_index] = pixels;
00158             pixels = 0;
00159             count_index = 0;
00160           }
00161           /* As long as we find transparency bytes, keep counting */
00162           if (color == 0) {
00163             last_color = 0;
00164             trans++;
00165             continue;
00166           }
00167           /* No longer transparency, so write the amount of transparent bytes */
00168           *dst = trans;
00169           dst++; index++;
00170           trans = 0;
00171           /* Reserve a byte for the pixel counter */
00172           count_index = index;
00173           dst++; index++;
00174         }
00175         last_color = color;
00176         pixels++;
00177         *dst = color;
00178         dst++; index++;
00179       }
00180 
00181       if (count_index != 0) temp_dst[count_index] = pixels;
00182 
00183       /* Write line-ending */
00184       *dst = 0; dst++; index++;
00185       *dst = 0; dst++; index++;
00186     }
00187   }
00188 
00189   /* Safety check, to make sure we guessed the size correctly */
00190   assert(index < memory);
00191 
00192   /* Allocate the exact amount of memory we need */
00193   dest_sprite = (Sprite *)allocator(sizeof(*dest_sprite) + index);
00194 
00195   dest_sprite->height = sprite->height;
00196   dest_sprite->width  = sprite->width;
00197   dest_sprite->x_offs = sprite->x_offs;
00198   dest_sprite->y_offs = sprite->y_offs;
00199   memcpy(dest_sprite->data, temp_dst, index);
00200   free(temp_dst);
00201 
00202   return dest_sprite;
00203 }

Generated on Wed Oct 1 17:03:20 2008 for openttd by  doxygen 1.5.6