# 32bpp_optimized.cpp

Go to the documentation of this file.

    00001 /* $Id$ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
    00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
    00008  */
    00009
    00012 #include "../stdafx.h"
    00013 #include "../core/alloc_func.hpp"
    00014 #include "../zoom_func.h"
    00015 #include "../core/math_func.hpp"
    00016 #include "32bpp_optimized.hpp"
    00017
    00018 static const int MAX_PALETTE_TABLES = 50;
    00019
    00020 struct RecolourTable {
    00021   SpriteID   id;
    00022   Colour     tables[256];
    00023 } _rgb_palettes[MAX_PALETTE_TABLES] = {{0,{{0}}}};
    00024
    00025 Colour _rgb_stringremap[3] = {{0}};
    00026
    00027 static FBlitter_32bppOptimized iFBlitter_32bppOptimized;
    00028
    00036 template <BlitterMode mode>
    00037 inline void Blitter_32bppOptimized::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom)
    00038 {
    00039   const SpriteData *src = (const SpriteData *)bp->sprite;
    00040
    00041   /* src_px : each line begins with uint32 n = 'number of bytes in this line',
    00042    *          then n times is the Colour struct for this line */
    00043   zoom = ZOOM_LVL_BEGIN;
    00044   const Colour *src_px = (const Colour *)(src->data + src->offset[zoom][0]);
    00045   /* src_n  : each line begins with uint32 n = 'number of bytes in this line',
    00046    *          then interleaved stream of 'm' and 'n' channels. 'm' is remap,
    00047    *          'n' is number of bytes with the same alpha channel class */
    00048   const uint8  *src_n  = (const uint8  *)(src->data + src->offset[zoom][1]);
    00049
    00050   /* skip upper lines in src_px and src_n */
    00051   for (uint i = bp->skip_top; i != 0; i--) {
    00052     src_px = (const Colour *)((const byte *)src_px + *(const uint32 *)src_px);
    00053     src_n += *(uint32 *)src_n;
    00054   }
    00055
    00056   /* skip lines in dst */
    00057   uint32 *dst = (uint32 *)bp->dst + bp->top * bp->pitch + bp->left;
    00058
    00059   /* store so we don't have to access it via bp everytime (compiler assumes pointer aliasing) */
    00060   const Colour *remap = (const Colour *)bp->remap;
    00061   for (int y = 0; y < bp->height; y++) {
    00062     /* next dst line begins here */
    00063     uint32 *dst_ln = dst + bp->pitch;
    00064
    00065     /* next src line begins here */
    00066     const Colour *src_px_ln = (const Colour *)((const byte *)src_px + *(const uint32 *)src_px);
    00067     src_px++;
    00068
    00069     /* next src_n line begins here */
    00070     const uint8 *src_n_ln = src_n + *(uint32 *)src_n;
    00071     src_n += 4;
    00072
    00073     /* we will end this line when we reach this point */
    00074     uint32 *dst_end = dst + bp->skip_left;
    00075
    00076     /* number of pixels with the same aplha channel class */
    00077     uint n;
    00078
    00079     while (dst < dst_end) {
    00080       n = *src_n++;
    00081
    00082       if (src_px->a == 0) {
    00083         dst += n;
    00084         src_px ++;
    00085         src_n++;
    00086       } else {
    00087         if (dst + n > dst_end) {
    00088           uint d = dst_end - dst;
    00089           src_px += d;
    00090           src_n += d;
    00091
    00092           dst = dst_end - bp->skip_left;
    00093           dst_end = dst + bp->width;
    00094
    00095           n = min<uint>(n - d, (uint)bp->width);
    00096           goto draw;
    00097         }
    00098         dst += n;
    00099         src_px += n;
    00100         src_n += n;
    00101       }
    00102     }
    00103
    00104     dst -= bp->skip_left;
    00105     dst_end -= bp->skip_left;
    00106
    00107     dst_end += bp->width;
    00108
    00109     while (dst < dst_end) {
    00110       n = min<uint>(*src_n++, (uint)(dst_end - dst));
    00111
    00112       if (src_px->a == 0) {
    00113         dst += n;
    00114         src_px++;
    00115         src_n++;
    00116         continue;
    00117       }
    00118
    00119       draw:;
    00120
    00121       switch (mode) {
    00122         case BM_COLOUR_REMAP:
    00123           do {
    00124             uint m = *src_n;
    00125             /* In case the m-channel is zero, do not remap this pixel in any way */
    00126             if (m == 0) {
    00127               if (src_px->a == 255) {
    00128                 *dst = src_px->data;
    00129               } else {
    00130                 *dst = ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, *dst);
    00131               }
    00132             } else {
    00133               Colour r = remap[m];
    00134               if (r.a != 0) {
    00135                 uint src_col = ComposeColour(src_px->a, src_px->r, src_px->g, src_px->b);
    00136                 uint comp_col = ComposeColourBlend(r.data, src_col);
    00137                 *dst = ComposeColourPA(comp_col, src_px->a, *dst);
    00138               }
    00139             }
    00140             dst++;
    00141             src_px++;
    00142             src_n++;
    00143           } while (--n != 0);
    00144           break;
    00145         case BM_COLOUR_OPAQUE:
    00146           do {
    00147             uint m = *src_n;
    00148             /* In case the m-channel is zero, do not remap this pixel in any way */
    00149             if (m == 0) {
    00150               *dst = ComposeColourRGBA(src_px->r, src_px->g, src_px->b, src_px->a, *dst);
    00151             } else {
    00152               Colour r = remap[m];
    00153               if (r.a != 0) {
    00154                 *dst = ComposeColourPA(r.data, src_px->a, *dst);
    00155               }
    00156             }
    00157             dst++;
    00158             src_px++;
    00159             src_n++;
    00160           } while (--n != 0);
    00161           break;
    00162         case BM_TRANSPARENT:
    00163           do {
    00164             uint m = *src_n;
    00165             if (m == 0) {
    00166               *dst = ComposeColourRGBA(src_px->r, src_px->g, src_px->b, src_px->a / 2, *dst);
    00167             } else {
    00168               if (remap){
    00169                 Colour r = remap[m];
    00170                 if (r.a != 0) *dst = ComposeColourPA(r.data, src_px->a / 2, *dst);
    00171               }
    00172               else {
    00173                 *dst = ComposeColourRGBA(src_px->r, src_px->g, src_px->b, src_px->a / 2, *dst);
    00174               }
    00175             }
    00176
    00177             dst++;
    00178             src_px++;
    00179             src_n++;
    00180           /* TODO -- We make an assumption here that the remap in fact is transparency, not some colour.
    00181            *  This is never a problem with the code we produce, but newgrfs can make it fail... or at least:
    00182            *  we produce a result the newgrf maker didn't expect ;) */
    00183           } while (--n != 0);
    00184           break;
    00185         case BM_SHADOW:
    00186           /* Make the current colour a bit more black */
    00187           src_n += n;
    00188           if (src_px->a == 255) {
    00189             src_px += n;
    00190             do {
    00191               *dst = MakeTransparent(*dst, 3, 4);
    00192               dst++;
    00193             } while (--n != 0);
    00194           } else {
    00195             do {
    00196               *dst = MakeTransparent(*dst, (256 * 4 - src_px->a), 256 * 4);
    00197               dst++;
    00198               src_px++;
    00199             } while (--n != 0);
    00200           }
    00201
    00202           break;
    00203         default:
    00204           if (src_px->a == 255) {
    00205             /* faster than memcpy(), n is usually low */
    00206             src_n += n;
    00207             do {
    00208               *dst = src_px->data;
    00209               dst++;
    00210               src_px++;
    00211             } while (--n != 0);
    00212           } else {
    00213             src_n += n;
    00214             do {
    00215               *dst = ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, *dst);
    00216               dst++;
    00217               src_px++;
    00218             } while (--n != 0);
    00219           }
    00220           break;
    00221       }
    00222     }
    00223     dst = dst_ln;
    00224     src_px = src_px_ln;
    00225     src_n  = src_n_ln;
    00226   }
    00227 }
    00228
    00236 void Blitter_32bppOptimized::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom)
    00237 {
    00238     switch (mode) {
    00239     default: NOT_REACHED();
    00240     case BM_NORMAL:        Draw<BM_NORMAL>       (bp, zoom); return;
    00241     case BM_COLOUR_REMAP:  Draw<BM_COLOUR_REMAP> (bp, zoom); return;
    00242     case BM_COLOUR_OPAQUE: Draw<BM_COLOUR_OPAQUE>(bp, zoom); return;
    00243     case BM_TRANSPARENT:   Draw<BM_TRANSPARENT>  (bp, zoom); return;
    00244     case BM_SHADOW:        Draw<BM_SHADOW>       (bp, zoom); return;
    00245   }
    00246 }
    00247
    00255 static const SpriteLoader::Sprite *ResizeSprite(const SpriteLoader::Sprite *sprite_src, ZoomLevel zoom)
    00256 {
    00257   return sprite_src;
    00258 }
    00259
    00260 Sprite *Blitter_32bppOptimized::Encode(SpriteLoader::Sprite *sprite, AllocatorProc *allocator)
    00261 {
    00262   /* streams of pixels (a, r, g, b channels)
    00263    *
    00264    * stored in separated stream so data are always aligned on 4B boundary */
    00265   Colour *dst_px_orig[ZOOM_LVL_COUNT];
    00266
    00267   /* interleaved stream of 'm' channel and 'n' channel
    00268    * 'n' is number if following pixels with the same alpha channel class
    00269    * there are 3 classes: 0, 255, others
    00270    *
    00271    * it has to be stored in one stream so fewer registers are used -
    00272    * x86 has problems with register allocation even with this solution */
    00273   uint8  *dst_n_orig[ZOOM_LVL_COUNT];
    00274
    00275   /* lengths of streams */
    00276   uint32 lengths[ZOOM_LVL_COUNT][2];
    00277
    00278   for (ZoomLevel z = ZOOM_LVL_BEGIN; z <= ZOOM_LVL_BEGIN; z++) {
    00279     const SpriteLoader::Sprite *src_orig = ResizeSprite(sprite, z);
    00280
    00281     uint size = src_orig->height * src_orig->width;
    00282
    00283     dst_px_orig[z] = CallocT<Colour>(size + src_orig->height * 2);
    00284     dst_n_orig[z]  = CallocT<uint8>(size * 2 + src_orig->height * 4 * 2);
    00285
    00286     uint32 *dst_px_ln = (uint32 *)dst_px_orig[z];
    00287     uint32 *dst_n_ln  = (uint32 *)dst_n_orig[z];
    00288
    00289     const SpriteLoader::CommonPixel *src = (const SpriteLoader::CommonPixel *)src_orig->data;
    00290
    00291     for (uint y = src_orig->height; y > 0; y--) {
    00292       Colour *dst_px = (Colour *)(dst_px_ln + 1);
    00293       uint8 *dst_n = (uint8 *)(dst_n_ln + 1);
    00294
    00295       uint8 *dst_len = dst_n++;
    00296
    00297       uint last = 3;
    00298       int len = 0;
    00299
    00300       for (uint x = src_orig->width; x > 0; x--) {
    00301         uint8 a = src->a;
    00302         uint t = a > 0 && a < 255 ? 1 : a;
    00303
    00304         if (last != t || len == 255) {
    00305           if (last != 3) {
    00306             *dst_len = len;
    00307             dst_len = dst_n++;
    00308           }
    00309           len = 0;
    00310         }
    00311
    00312         last = t;
    00313         len++;
    00314
    00315         if (a != 0) {
    00316           dst_px->a = a;
    00317           *dst_n = src->m;
    00318
    00319           dst_px->r = src->r;
    00320           dst_px->g = src->g;
    00321           dst_px->b = src->b;
    00322
    00323           dst_px++;
    00324           dst_n++;
    00325         } else if (len == 1) {
    00326           dst_px++;
    00327           *dst_n = src->m;
    00328           dst_n++;
    00329         }
    00330
    00331         src++;
    00332       }
    00333
    00334       if (last != 3) {
    00335         *dst_len = len;
    00336       }
    00337
    00338       dst_px = (Colour *)AlignPtr(dst_px, 4);
    00339       dst_n  = (uint8 *)AlignPtr(dst_n, 4);
    00340
    00341       *dst_px_ln = (uint8 *)dst_px - (uint8 *)dst_px_ln;
    00342       *dst_n_ln  = (uint8 *)dst_n  - (uint8 *)dst_n_ln;
    00343
    00344       dst_px_ln = (uint32 *)dst_px;
    00345       dst_n_ln =  (uint32 *)dst_n;
    00346     }
    00347
    00348     lengths[z][0] = (byte *)dst_px_ln - (byte *)dst_px_orig[z]; // all are aligned to 4B boundary
    00349     lengths[z][1] = (byte *)dst_n_ln  - (byte *)dst_n_orig[z];
    00350
    00351   }
    00352
    00353   uint len = 0; // total length of data
    00354   for (ZoomLevel z = ZOOM_LVL_BEGIN; z <= ZOOM_LVL_BEGIN; z++) {
    00355     len += lengths[z][0] + lengths[z][1];
    00356   }
    00357
    00358   Sprite *dest_sprite = (Sprite *)allocator(sizeof(*dest_sprite) + sizeof(SpriteData) + len);
    00359
    00360   dest_sprite->height = sprite->height;
    00361   dest_sprite->width  = sprite->width;
    00362   dest_sprite->x_offs = sprite->x_offs;
    00363   dest_sprite->y_offs = sprite->y_offs;
    00364
    00365   SpriteData *dst = (SpriteData *)dest_sprite->data;
    00366
    00367   ZoomLevel z = ZOOM_LVL_BEGIN;
    00368   dst->offset[z][0] = 0;
    00369   dst->offset[z][1] = lengths[z][0] + dst->offset[z][0];
    00370
    00371   memcpy(dst->data + dst->offset[z][0], dst_px_orig[z], lengths[z][0]);
    00372   memcpy(dst->data + dst->offset[z][1], dst_n_orig[z],  lengths[z][1]);
    00373
    00374   free(dst_px_orig[z]);
    00375   free(dst_n_orig[z]);
    00376
    00377   return dest_sprite;
    00378 }
    00379
    00380 void Blitter_32bppOptimized::RescaleSpriteHalfSize(const SpriteLoader::Sprite *src_sprite,
    00381                                       SpriteLoader::Sprite *dest_sprite,
    00382                                       bool                 prevent_alpha_bleeding)
    00383 {
    00384   SpriteLoader::CommonPixel *dst;
    00385   SpriteLoader::CommonPixel *src;
    00386   int width, height;
    00387   int x, y;
    00388   bool  extra_px_x = false;
    00389   bool  extra_px_y = false;
    00390
    00391   SpriteLoader::CommonPixel clr;
    00392
    00393   width = (src_sprite->width + 1) / 2;
    00394   height = (src_sprite->height + 1) / 2;
    00395
    00396   /* src sprite width is odd, just copy last pixel iso taking average */
    00397   if (src_sprite->width & 1) {
    00398     extra_px_x = true;
    00399   }
    00400   /* src sprite height is odd, just copy last pixel iso taking average */
    00401   if (src_sprite->height & 1) {
    00402     extra_px_y = true;
    00403   }
    00404
    00405
    00406   dest_sprite->data = CallocT<SpriteLoader::CommonPixel>(height * width);
    00407   dst = (SpriteLoader::CommonPixel *)dest_sprite->data;
    00408   src = (SpriteLoader::CommonPixel *)src_sprite->data;
    00409
    00410   dest_sprite->width = width ;
    00411   dest_sprite->height = height;
    00412
    00413   dest_sprite->x_offs = src_sprite->x_offs / 2;
    00414   dest_sprite->y_offs = src_sprite->y_offs / 2;
    00415
    00416   for (y = 0; y < height + (extra_px_y ? -1 : 0); y++) {
    00417     for (x = 0; x < width + (extra_px_x ? -1 : 0); x++) {
    00418         uint ma = 0;
    00419         uint a = 0;
    00420         uint r = 0;
    00421         uint g = 0;
    00422         uint b = 0;
    00423         uint i;
    00424         uint j;
    00425
    00426         for (i = 0; i < 2; i++) {
    00427           for (j = 0; j < 2; j++) {
    00428             uint ca;
    00429             uint cr;
    00430             uint cg;
    00431             uint cb;
    00432
    00433             clr = src[((2 * y + i ) * src_sprite->width) + (2 * x + j )];
    00434             ca = clr.a;
    00435             cr = clr.r;
    00436             cg = clr.g;
    00437             cb = clr.b;
    00438
    00439             a += ca;
    00440             r += ca * cr;
    00441             g += ca * cg;
    00442             b += ca * cb;
    00443             if (prevent_alpha_bleeding) {
    00444               if (ca > ma) ma = ca;
    00445             } else {
    00446               ma += ca;
    00447             }
    00448           }
    00449         }
    00450
    00451         if (a == 0) {
    00452           dst[y * width + x].r = 0;
    00453           dst[y * width + x].g = 0;
    00454           dst[y * width + x].b = 0;
    00455           dst[y * width + x].a = 0;
    00456           dst[y * width + x].m = 0;
    00457         } else {
    00458           r /= a;
    00459           g /= a;
    00460           b /= a;
    00461           if (prevent_alpha_bleeding) {
    00462             a = ma;
    00463           } else {
    00464             a /= 4;
    00465           }
    00466           dst[y * width + x].r = r;
    00467           dst[y * width + x].g = g;
    00468           dst[y * width + x].b = b;
    00469           dst[y * width + x].a = a;
    00470           dst[y * width + x].m = clr.m;
    00471         }
    00472     }
    00473     if (extra_px_x) {
    00474       clr = src[((2 * y ) * src_sprite->width) + (2 * x)];
    00475       dst[y * width + x] = clr;
    00476     }
    00477   }
    00478
    00479 }
    00480 /*
    00481 void Blitter_32bppOptimized::RescaleSpriteDoubleSizePrev(const SpriteLoader::Sprite *src_sprite,
    00482                                         SpriteLoader::Sprite *dest_sprite)
    00483 {
    00484   int width, height;
    00485   SpriteLoader::CommonPixel *dst;
    00486   SpriteLoader::CommonPixel *src;
    00487
    00488   width = src_sprite->width * 2;
    00489   height = src_sprite->height * 2;
    00490
    00491   dest_sprite->data = CallocT<SpriteLoader::CommonPixel>(height * width);
    00492   dst = (SpriteLoader::CommonPixel *)dest_sprite->data;
    00493   src = (SpriteLoader::CommonPixel *)src_sprite->data;
    00494
    00495   dest_sprite->width = width;
    00496   dest_sprite->height = height;
    00497   dest_sprite->x_offs = src_sprite->x_offs * 2;
    00498   dest_sprite->y_offs = src_sprite->y_offs * 2;
    00499
    00500   uint dst_y = 0;
    00501   uint src_y_idx = 0;
    00502   for (int y = 0; y < src_sprite->height - 1; y++) {
    00503      int x;
    00504
    00505     uint dst_x = 0;
    00506     for (x = 0; x < src_sprite->width - 1; x++) {
    00507       dst[dst_y + dst_x] = src[src_y_idx + x];
    00508       dst_x++;
    00509       dst[dst_y + dst_x].r = (src[src_y_idx + x + 1].r + src[src_y_idx + x].r) / 2;
    00510       dst[dst_y + dst_x].g = (src[src_y_idx + x + 1].g + src[src_y_idx + x].g) / 2;
    00511       dst[dst_y + dst_x].b = (src[src_y_idx + x + 1].b + src[src_y_idx + x].b) / 2;
    00512       dst[dst_y + dst_x].a = (src[src_y_idx + x + 1].a + src[src_y_idx + x].a) / 2;
    00513       dst[dst_y + dst_x].m =  src[src_y_idx + x].m;
    00514       dst_x--;
    00515       dst_y += width;
    00516       dst[dst_y + dst_x].r = (src[src_y_idx + x].r + src[src_y_idx + src_sprite->width + x].r) / 2;
    00517       dst[dst_y + dst_x].g = (src[src_y_idx + x].g + src[src_y_idx + src_sprite->width + x].g) / 2;
    00518       dst[dst_y + dst_x].b = (src[src_y_idx + x].b + src[src_y_idx + src_sprite->width + x].b) / 2;
    00519       dst[dst_y + dst_x].a = (src[src_y_idx + x].a + src[src_y_idx + src_sprite->width + x].a) / 2;
    00520       dst[dst_y + dst_x].m =  src[src_y_idx + x].m;
    00521       dst_x++;
    00522       dst[dst_y + dst_x].r = (src[src_y_idx + x].r + src[src_y_idx + src_sprite->width + x].r +
    00523                               src[src_y_idx + x + 1].r + src[src_y_idx + src_sprite->width + x + 1].r ) / 4;
    00524       dst[dst_y + dst_x].g = (src[src_y_idx + x].g + src[src_y_idx + src_sprite->width + x].g +
    00525                               src[src_y_idx + x + 1].g + src[src_y_idx + src_sprite->width + x + 1].g ) / 4;
    00526       dst[dst_y + dst_x].b = (src[src_y_idx + x].b + src[src_y_idx + src_sprite->width + x].b +
    00527                               src[src_y_idx + x + 1].b + src[src_y_idx + src_sprite->width + x + 1].b ) / 4;
    00528       dst[dst_y + dst_x].a = (src[src_y_idx + x].a + src[src_y_idx + src_sprite->width + x].a +
    00529                               src[src_y_idx + x + 1].a + src[src_y_idx + src_sprite->width + x + 1].a ) / 4;
    00530       dst[dst_y + dst_x].m =  src[src_y_idx + x].m;
    00531       dst_y -= width;
    00532       dst_x++;
    00533     }
    00534
    00535      last pixels in row cannot be interpolated */
    00536 /*     dst[dst_y + dst_x] = src[src_y_idx + x];
    00537     dst_x++;
    00538     dst[dst_y + dst_x] = src[src_y_idx + x];
    00539     dst_x--;
    00540     dst_y += width;
    00541     dst[dst_y + dst_x].r = (src[src_y_idx + x].r + src[src_y_idx + src_sprite->width + x].r) / 2;
    00542     dst[dst_y + dst_x].g = (src[src_y_idx + x].g + src[src_y_idx + src_sprite->width + x].g) / 2;
    00543     dst[dst_y + dst_x].b = (src[src_y_idx + x].b + src[src_y_idx + src_sprite->width + x].b) / 2;
    00544     dst[dst_y + dst_x].a = (src[src_y_idx + x].a + src[src_y_idx + src_sprite->width + x].a) / 2;
    00545     dst[dst_y + dst_x].m =  src[src_y_idx + x].m;
    00546     dst_x++;
    00547     dst[dst_y + dst_x].r = (src[src_y_idx + x].r + src[src_y_idx + src_sprite->width + x].r) / 2;
    00548     dst[dst_y + dst_x].g = (src[src_y_idx + x].g + src[src_y_idx + src_sprite->width + x].g) / 2;
    00549     dst[dst_y + dst_x].b = (src[src_y_idx + x].b + src[src_y_idx + src_sprite->width + x].b) / 2;
    00550     dst[dst_y + dst_x].a = (src[src_y_idx + x].a + src[src_y_idx + src_sprite->width + x].a) / 2;
    00551     dst[dst_y + dst_x].m =  src[src_y_idx + x].m;
    00552
    00553     dst_y += width;
    00554     src_y_idx += src_sprite->width;
    00555   }
    00556    last row can not be interpolated */
    00557 /* uint dst_x = 0;
    00558   for (int x = 0; x < src_sprite->width - 1; x++) {
    00559     dst[dst_y + dst_x] = src[src_y_idx + x];
    00560     dst_x++;
    00561     dst[dst_y + dst_x].r = (src[src_y_idx + x + 1].r + src[src_y_idx + x].r) / 2;
    00562     dst[dst_y + dst_x].g = (src[src_y_idx + x + 1].g + src[src_y_idx + x].g) / 2;
    00563     dst[dst_y + dst_x].b = (src[src_y_idx + x + 1].b + src[src_y_idx + x].b) / 2;
    00564     dst[dst_y + dst_x].a = (src[src_y_idx + x + 1].a + src[src_y_idx + x].a) / 2;
    00565     dst[dst_y + dst_x].m =  src[src_y_idx + x].m;
    00566     dst_x--;
    00567     dst_y += width;
    00568     dst[dst_y + dst_x] = src[src_y_idx + x];
    00569     dst_x++;
    00570     dst[dst_y + dst_x].r = (src[src_y_idx + x + 1].r + src[src_y_idx + x].r) / 2;
    00571     dst[dst_y + dst_x].g = (src[src_y_idx + x + 1].g + src[src_y_idx + x].g) / 2;
    00572     dst[dst_y + dst_x].b = (src[src_y_idx + x + 1].b + src[src_y_idx + x].b) / 2;
    00573     dst[dst_y + dst_x].a = (src[src_y_idx + x + 1].a + src[src_y_idx + x].a) / 2;
    00574     dst[dst_y + dst_x].m =  src[src_y_idx + x].m;
    00575     dst_y -= width;
    00576     dst_x++;
    00577   }
    00578 }
    00579
    00580 */
    00581
    00582 void Blitter_32bppOptimized::RescaleSpriteDoubleSize(const SpriteLoader::Sprite *src_sprite,
    00583                                         SpriteLoader::Sprite *dest_sprite)
    00584 {
    00585   int width, height;
    00586   SpriteLoader::CommonPixel *dst;
    00587   SpriteLoader::CommonPixel *src;
    00588
    00589   width = src_sprite->width * 2;
    00590   height = src_sprite->height * 2;
    00591
    00592   dest_sprite->data = CallocT<SpriteLoader::CommonPixel>(height * width);
    00593   dst = (SpriteLoader::CommonPixel *)dest_sprite->data;
    00594   src = (SpriteLoader::CommonPixel *)src_sprite->data;
    00595
    00596   dest_sprite->width = width;
    00597   dest_sprite->height = height;
    00598   dest_sprite->x_offs = src_sprite->x_offs * 2;
    00599   dest_sprite->y_offs = src_sprite->y_offs * 2;
    00600   SpriteLoader::CommonPixel B, D, E, H, F;
    00601   SpriteLoader::CommonPixel E0, E1, E2, E3;
    00602   uint dst_y = 0;
    00603   uint src_y_idx = 0;
    00604   for (int y = 0; y < src_sprite->height ; y++) {
    00605     int x;
    00606
    00607     uint dst_x = 0;
    00608     for (x = 0; x < src_sprite->width - 1; x++) {
    00609       E = src[src_y_idx + x];
    00610       if (src_y_idx) {
    00611         B = src[src_y_idx + x - src_sprite->width];
    00612       } else {
    00613         B = src[src_y_idx + x];
    00614       }
    00615       if (x) {
    00616         D = src[src_y_idx + x - 1];
    00617       } else {
    00618         D = src[src_y_idx + x ];
    00619       }
    00620       if (x < src_sprite->width - 1){
    00621         F = src[src_y_idx + x + 1];
    00622       } else {
    00623         F = src[src_y_idx + x ];
    00624       }
    00625       if (y < src_sprite->height - 1){
    00626         H = src[src_y_idx + x + src_sprite->width];
    00627       } else {
    00628         H = src[src_y_idx + x];
    00629       }
    00630       if ((B.r != H.r && D.r != F.r) ||
    00631         (B.g != H.g && D.g != F.g) ||
    00632         (B.b != H.b && D.b != F.b) ||
    00633         (B.a != H.a && D.a != F.a))
    00634        {
    00635         if ((D.r == B.r) &&
    00636           (D.g == B.g) &&
    00637           (D.b == B.b) &&
    00638           (D.a == B.a)) {
    00639           E0 = D;
    00640         } else {
    00641           E0 = E;
    00642         }
    00643         if ((B.r == F.r) &&
    00644           (B.g == F.g) &&
    00645           (B.b == F.b) &&
    00646           (B.a == F.a)) {
    00647           E1 = F;
    00648         } else {
    00649           E1 = E;
    00650         }
    00651         if ((D.r == H.r) &&
    00652           (D.g == H.g) &&
    00653           (D.b == H.b) &&
    00654           (D.a == H.a)) {
    00655           E2 = D;
    00656         } else {
    00657           E2 = E;
    00658         }
    00659         if ((H.r == F.r) &&
    00660           (H.g == F.g) &&
    00661           (H.b == F.b) &&
    00662           (H.a == F.a)) {
    00663           E3 = F;
    00664         } else {
    00665           E3 = E;
    00666         }
    00667       } else {
    00668         E0 = E;
    00669         E1 = E;
    00670         E2 = E;
    00671         E3 = E;
    00672       }
    00673       dst[dst_y + dst_x] = E0;
    00674       dst_x++;
    00675       dst[dst_y + dst_x] = E1;
    00676       dst_x--;
    00677       dst_y += width;
    00678       dst[dst_y + dst_x] = E2;
    00679       dst_x++;
    00680       dst[dst_y + dst_x] = E3;
    00681       dst_y -= width;
    00682       dst_x++;
    00683     }
    00684
    00685     dst_y += width;
    00686 dst_y += width;
    00687     src_y_idx += src_sprite->width;
    00688   }
    00689 }
    00690
    00691 void Blitter_32bppOptimized::FillRGBFromPalette(SpriteLoader::Sprite *sprite)
    00692 {
    00693   SpriteLoader::CommonPixel *spr = sprite->data;
    00694
    00695   for (uint y = 0; y < sprite->height; y++) {
    00696     uint y_idx  = y * sprite->width;
    00697     for (uint x = 0; x < sprite->width; x++) {
    00698       if (spr[y_idx + x].a == 0) {
    00699         spr[y_idx + x].r = 0;
    00700         spr[y_idx + x].g = 0;
    00701         spr[y_idx + x].b = 0;
    00702         spr[y_idx + x].m = 0;
    00703       } else {
    00704         if (spr[y_idx + x].m != 0) {
    00705           /* Pre-convert the mapping channel to a RGB value */
    00706           uint color = this->LookupColourInPalette(spr[y_idx + x].m);
    00707           spr[y_idx + x].r = GB(color, 16, 8);
    00708           spr[y_idx + x].g = GB(color, 8,  8);
    00709           spr[y_idx + x].b = GB(color, 0,  8);
    00710         }
    00711       }
    00712     }
    00713   }
    00714 }
    00715
    00716 byte *Blitter_32bppOptimized::FillRGBPalette(SpriteID id, byte *remap_data)
    00717 {
    00718   for (int idx = 0; (idx < MAX_PALETTE_TABLES); idx++) {
    00719     if ((id == _rgb_palettes[idx].id) || (_rgb_palettes[idx].id == 0)) {
    00720       _rgb_palettes[idx].id = id;
    00721       for (int col_idx = 0; col_idx < 256; col_idx++) {
    00722         _rgb_palettes[idx].tables[col_idx].data = this->LookupColourInPalette(remap_data[col_idx + 1]);
    00723       }
    00724       return (byte *)&(_rgb_palettes[idx].tables[0]);
    00725     }
    00726   }
    00727   error("No more rgb palette tables available");
    00728   return NULL;
    00729 }
    00730