32bpp_anim.cpp

Go to the documentation of this file.
00001 /* $Id: 32bpp_anim.cpp 15428 2009-02-09 02:57:15Z rubidium $ */
00002 
00005 #include "../stdafx.h"
00006 #include "../core/alloc_func.hpp"
00007 #include "../core/math_func.hpp"
00008 #include "../gfx_func.h"
00009 #include "../video/video_driver.hpp"
00010 #include "32bpp_anim.hpp"
00011 
00012 #include "../table/sprites.h"
00013 
00014 static FBlitter_32bppAnim iFBlitter_32bppAnim;
00015 
00016 template <BlitterMode mode>
00017 inline void Blitter_32bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom)
00018 {
00019   const SpriteData *src = (const SpriteData *)bp->sprite;
00020 
00021   const Colour *src_px = (const Colour *)(src->data + src->offset[zoom][0]);
00022   const uint8  *src_n  = (const uint8  *)(src->data + src->offset[zoom][1]);
00023 
00024   for (uint i = bp->skip_top; i != 0; i--) {
00025     src_px = (const Colour *)((const byte *)src_px + *(const uint32 *)src_px);
00026     src_n += *(const uint32 *)src_n;
00027   }
00028 
00029   uint32 *dst = (uint32 *)bp->dst + bp->top * bp->pitch + bp->left;
00030   uint8 *anim = this->anim_buf + ((uint32 *)bp->dst - (uint32 *)_screen.dst_ptr) + bp->top * this->anim_buf_width + bp->left;
00031 
00032   const byte *remap = bp->remap; // store so we don't have to access it via bp everytime
00033 
00034   for (int y = 0; y < bp->height; y++) {
00035     uint32 *dst_ln = dst + bp->pitch;
00036     uint8 *anim_ln = anim + this->anim_buf_width;
00037 
00038     const Colour *src_px_ln = (const Colour *)((const byte *)src_px + *(const uint32 *)src_px);
00039     src_px++;
00040 
00041     const uint8 *src_n_ln = src_n + *(uint32 *)src_n;
00042     src_n += 4;
00043 
00044     uint32 *dst_end = dst + bp->skip_left;
00045 
00046     uint n;
00047 
00048     while (dst < dst_end) {
00049       n = *src_n++;
00050 
00051       if (src_px->a == 0) {
00052         dst += n;
00053         src_px ++;
00054         src_n++;
00055 
00056         if (dst > dst_end) anim += dst - dst_end;
00057       } else {
00058         if (dst + n > dst_end) {
00059           uint d = dst_end - dst;
00060           src_px += d;
00061           src_n += d;
00062 
00063           dst = dst_end - bp->skip_left;
00064           dst_end = dst + bp->width;
00065 
00066           n = min<uint>(n - d, (uint)bp->width);
00067           goto draw;
00068         }
00069         dst += n;
00070         src_px += n;
00071         src_n += n;
00072       }
00073     }
00074 
00075     dst -= bp->skip_left;
00076     dst_end -= bp->skip_left;
00077 
00078     dst_end += bp->width;
00079 
00080     while (dst < dst_end) {
00081       n = min<uint>(*src_n++, (uint)(dst_end - dst));
00082 
00083       if (src_px->a == 0) {
00084         anim += n;
00085         dst += n;
00086         src_px++;
00087         src_n++;
00088         continue;
00089       }
00090 
00091       draw:;
00092 
00093       switch (mode) {
00094         case BM_COLOUR_REMAP:
00095           if (src_px->a == 255) {
00096             do {
00097               uint m = *src_n;
00098               /* In case the m-channel is zero, do not remap this pixel in any way */
00099               if (m == 0) {
00100                 *dst = *src_px;
00101                 *anim = 0;
00102               } else {
00103                 uint r = remap[m];
00104                 *anim = r;
00105                 if (r != 0) *dst = this->LookupColourInPalette(r);
00106               }
00107               anim++;
00108               dst++;
00109               src_px++;
00110               src_n++;
00111             } while (--n != 0);
00112           } else {
00113             do {
00114               uint m = *src_n;
00115               if (m == 0) {
00116                 *dst = ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, *dst);
00117                 *anim = 0;
00118               } else {
00119                 uint r = remap[m];
00120                 *anim = r;
00121                 if (r != 0) *dst = ComposeColourPANoCheck(this->LookupColourInPalette(r), src_px->a, *dst);
00122               }
00123               anim++;
00124               dst++;
00125               src_px++;
00126               src_n++;
00127             } while (--n != 0);
00128           }
00129           break;
00130 
00131         case BM_TRANSPARENT:
00132           /* TODO -- We make an assumption here that the remap in fact is transparency, not some colour.
00133            *  This is never a problem with the code we produce, but newgrfs can make it fail... or at least:
00134            *  we produce a result the newgrf maker didn't expect ;) */
00135 
00136           /* Make the current colour a bit more black, so it looks like this image is transparent */
00137           src_n += n;
00138           if (src_px->a == 255) {
00139             src_px += n;
00140             do {
00141               *dst = MakeTransparent(*dst, 3, 4);
00142               *anim = remap[*anim];
00143               anim++;
00144               dst++;
00145             } while (--n != 0);
00146           } else {
00147             do {
00148               *dst = MakeTransparent(*dst, (256 * 4 - src_px->a), 256 * 4);
00149               *anim = remap[*anim];
00150               anim++;
00151               dst++;
00152               src_px++;
00153             } while (--n != 0);
00154           }
00155           break;
00156 
00157         default:
00158           if (src_px->a == 255) {
00159             do {
00160               /* Compiler assumes pointer aliasing, can't optimise this on its own */
00161               uint m = *src_n++;
00162               /* Above 217 (PALETTE_ANIM_SIZE_START) is palette animation */
00163               *anim++ = m;
00164               *dst++ = (m >= PALETTE_ANIM_SIZE_START) ? this->LookupColourInPalette(m) : *src_px;
00165               src_px++;
00166             } while (--n != 0);
00167           } else {
00168             do {
00169               uint m = *src_n++;
00170               *anim++ = m;
00171               if (m >= PALETTE_ANIM_SIZE_START) {
00172                 *dst = ComposeColourPANoCheck(this->LookupColourInPalette(m), src_px->a, *dst);
00173               } else {
00174                 *dst = ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, *dst);
00175               }
00176               dst++;
00177               src_px++;
00178             } while (--n != 0);
00179           }
00180           break;
00181       }
00182     }
00183 
00184     anim = anim_ln;
00185     dst = dst_ln;
00186     src_px = src_px_ln;
00187     src_n  = src_n_ln;
00188   }
00189 }
00190 
00191 void Blitter_32bppAnim::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom)
00192 {
00193   if (_screen_disable_anim) {
00194     /* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent Draw() */
00195     Blitter_32bppOptimized::Draw(bp, mode, zoom);
00196     return;
00197   }
00198 
00199   if (_screen.width != this->anim_buf_width || _screen.height != this->anim_buf_height) {
00200     /* The size of the screen changed; we can assume we can wipe all data from our buffer */
00201     free(this->anim_buf);
00202     this->anim_buf = CallocT<uint8>(_screen.width * _screen.height);
00203     this->anim_buf_width = _screen.width;
00204     this->anim_buf_height = _screen.height;
00205   }
00206 
00207   switch (mode) {
00208     default: NOT_REACHED();
00209     case BM_NORMAL:       Draw<BM_NORMAL>      (bp, zoom); return;
00210     case BM_COLOUR_REMAP: Draw<BM_COLOUR_REMAP>(bp, zoom); return;
00211     case BM_TRANSPARENT:  Draw<BM_TRANSPARENT> (bp, zoom); return;
00212   }
00213 }
00214 
00215 void Blitter_32bppAnim::DrawColourMappingRect(void *dst, int width, int height, int pal)
00216 {
00217   if (_screen_disable_anim) {
00218     /* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent DrawColourMappingRect() */
00219     Blitter_32bppOptimized::DrawColourMappingRect(dst, width, height, pal);
00220     return;
00221   }
00222 
00223   uint32 *udst = (uint32 *)dst;
00224   uint8 *anim;
00225 
00226   anim = this->anim_buf + ((uint32 *)dst - (uint32 *)_screen.dst_ptr);
00227 
00228   if (pal == PALETTE_TO_TRANSPARENT) {
00229     do {
00230       for (int i = 0; i != width; i++) {
00231         *udst = MakeTransparent(*udst, 154);
00232         *anim = 0;
00233         udst++;
00234         anim++;
00235       }
00236       udst = udst - width + _screen.pitch;
00237       anim = anim - width + this->anim_buf_width;
00238     } while (--height);
00239     return;
00240   }
00241   if (pal == PALETTE_TO_STRUCT_GREY) {
00242     do {
00243       for (int i = 0; i != width; i++) {
00244         *udst = MakeGrey(*udst);
00245         *anim = 0;
00246         udst++;
00247         anim++;
00248       }
00249       udst = udst - width + _screen.pitch;
00250       anim = anim - width + this->anim_buf_width;
00251     } while (--height);
00252     return;
00253   }
00254 
00255   DEBUG(misc, 0, "32bpp blitter doesn't know how to draw this colour table ('%d')", pal);
00256 }
00257 
00258 void Blitter_32bppAnim::SetPixel(void *video, int x, int y, uint8 colour)
00259 {
00260   *((uint32 *)video + x + y * _screen.pitch) = LookupColourInPalette(colour);
00261 
00262   /* Set the colour in the anim-buffer too, if we are rendering to the screen */
00263   if (_screen_disable_anim) return;
00264   this->anim_buf[((uint32 *)video - (uint32 *)_screen.dst_ptr) + x + y * this->anim_buf_width] = colour;
00265 }
00266 
00267 void Blitter_32bppAnim::SetPixelIfEmpty(void *video, int x, int y, uint8 colour)
00268 {
00269   uint32 *dst = (uint32 *)video + x + y * _screen.pitch;
00270   if (*dst == 0) {
00271     *dst = LookupColourInPalette(colour);
00272     /* Set the colour in the anim-buffer too, if we are rendering to the screen */
00273     if (_screen_disable_anim) return;
00274     this->anim_buf[((uint32 *)video - (uint32 *)_screen.dst_ptr) + x + y * this->anim_buf_width] = colour;
00275   }
00276 }
00277 
00278 void Blitter_32bppAnim::DrawRect(void *video, int width, int height, uint8 colour)
00279 {
00280   if (_screen_disable_anim) {
00281     /* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent DrawRect() */
00282     Blitter_32bppOptimized::DrawRect(video, width, height, colour);
00283     return;
00284   }
00285 
00286   uint32 colour32 = LookupColourInPalette(colour);
00287   uint8 *anim_line;
00288 
00289   anim_line = ((uint32 *)video - (uint32 *)_screen.dst_ptr) + this->anim_buf;
00290 
00291   do {
00292     uint32 *dst = (uint32 *)video;
00293     uint8 *anim = anim_line;
00294 
00295     for (int i = width; i > 0; i--) {
00296       *dst = colour32;
00297       /* Set the colour in the anim-buffer too */
00298       *anim = colour;
00299       dst++;
00300       anim++;
00301     }
00302     video = (uint32 *)video + _screen.pitch;
00303     anim_line += this->anim_buf_width;
00304   } while (--height);
00305 }
00306 
00307 void Blitter_32bppAnim::CopyFromBuffer(void *video, const void *src, int width, int height)
00308 {
00309   assert(!_screen_disable_anim);
00310   assert(video >= _screen.dst_ptr && video <= (uint32 *)_screen.dst_ptr + _screen.width + _screen.height * _screen.pitch);
00311   uint32 *dst = (uint32 *)video;
00312   uint32 *usrc = (uint32 *)src;
00313   uint8 *anim_line;
00314 
00315   anim_line = ((uint32 *)video - (uint32 *)_screen.dst_ptr) + this->anim_buf;
00316 
00317   for (; height > 0; height--) {
00318     memcpy(dst, usrc, width * sizeof(uint32));
00319     usrc += width;
00320     dst += _screen.pitch;
00321     /* Copy back the anim-buffer */
00322     memcpy(anim_line, usrc, width * sizeof(uint8));
00323     usrc = (uint32 *)((uint8 *)usrc + width);
00324     anim_line += this->anim_buf_width;
00325   }
00326 
00327   /* We update the palette (or the pixels that do animation) immediatly, to avoid graphical glitches */
00328   this->PaletteAnimate(PALETTE_ANIM_SIZE_START, (_use_palette == PAL_DOS) ? PALETTE_ANIM_SIZE_DOS : PALETTE_ANIM_SIZE_WIN);
00329 }
00330 
00331 void Blitter_32bppAnim::CopyToBuffer(const void *video, void *dst, int width, int height)
00332 {
00333   assert(!_screen_disable_anim);
00334   assert(video >= _screen.dst_ptr && video <= (uint32 *)_screen.dst_ptr + _screen.width + _screen.height * _screen.pitch);
00335   uint32 *udst = (uint32 *)dst;
00336   uint32 *src = (uint32 *)video;
00337   uint8 *anim_line;
00338 
00339   if (this->anim_buf == NULL) return;
00340 
00341   anim_line = ((uint32 *)video - (uint32 *)_screen.dst_ptr) + this->anim_buf;
00342 
00343   for (; height > 0; height--) {
00344     memcpy(udst, src, width * sizeof(uint32));
00345     src += _screen.pitch;
00346     udst += width;
00347     /* Copy the anim-buffer */
00348     memcpy(udst, anim_line, width * sizeof(uint8));
00349     udst = (uint32 *)((uint8 *)udst + width);
00350     anim_line += this->anim_buf_width;
00351   }
00352 }
00353 
00354 void Blitter_32bppAnim::ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y)
00355 {
00356   assert(!_screen_disable_anim);
00357   assert(video >= _screen.dst_ptr && video <= (uint32 *)_screen.dst_ptr + _screen.width + _screen.height * _screen.pitch);
00358   uint8 *dst, *src;
00359 
00360   /* We need to scroll the anim-buffer too */
00361   if (scroll_y > 0) {
00362     dst = this->anim_buf + left + (top + height - 1) * this->anim_buf_width;
00363     src = dst - scroll_y * this->anim_buf_width;
00364 
00365     /* Adjust left & width */
00366     if (scroll_x >= 0) dst += scroll_x;
00367     else               src -= scroll_x;
00368 
00369     uint tw = width + (scroll_x >= 0 ? -scroll_x : scroll_x);
00370     uint th = height - scroll_y;
00371     for (; th > 0; th--) {
00372       memcpy(dst, src, tw * sizeof(uint8));
00373       src -= this->anim_buf_width;
00374       dst -= this->anim_buf_width;
00375     }
00376   } else {
00377     /* Calculate pointers */
00378     dst = this->anim_buf + left + top * this->anim_buf_width;
00379     src = dst - scroll_y * this->anim_buf_width;
00380 
00381     /* Adjust left & width */
00382     if (scroll_x >= 0) dst += scroll_x;
00383     else               src -= scroll_x;
00384 
00385     /* the y-displacement may be 0 therefore we have to use memmove,
00386      * because source and destination may overlap */
00387     uint tw = width + (scroll_x >= 0 ? -scroll_x : scroll_x);
00388     uint th = height + scroll_y;
00389     for (; th > 0; th--) {
00390       memmove(dst, src, tw * sizeof(uint8));
00391       src += this->anim_buf_width;
00392       dst += this->anim_buf_width;
00393     }
00394   }
00395 
00396   Blitter_32bppBase::ScrollBuffer(video, left, top, width, height, scroll_x, scroll_y);
00397 }
00398 
00399 int Blitter_32bppAnim::BufferSize(int width, int height)
00400 {
00401   return width * height * (sizeof(uint32) + sizeof(uint8));
00402 }
00403 
00404 void Blitter_32bppAnim::PaletteAnimate(uint start, uint count)
00405 {
00406   assert(!_screen_disable_anim);
00407 
00408   /* Never repaint the transparency pixel */
00409   if (start == 0) {
00410     start++;
00411     count--;
00412   }
00413 
00414   const uint8 *anim = this->anim_buf;
00415   uint32 *dst = (uint32 *)_screen.dst_ptr;
00416 
00417   /* Let's walk the anim buffer and try to find the pixels */
00418   for (int y = this->anim_buf_height; y != 0 ; y--) {
00419     for (int x = this->anim_buf_width; x != 0 ; x--) {
00420       uint colour = *anim;
00421       if (IsInsideBS(colour, start, count)) {
00422         /* Update this pixel */
00423         *dst = LookupColourInPalette(colour);
00424       }
00425       dst++;
00426       anim++;
00427     }
00428     dst += _screen.pitch - this->anim_buf_width;
00429   }
00430 
00431   /* Make sure the backend redraws the whole screen */
00432   _video_driver->MakeDirty(0, 0, _screen.width, _screen.height);
00433 }
00434 
00435 Blitter::PaletteAnimation Blitter_32bppAnim::UsePaletteAnimation()
00436 {
00437   return Blitter::PALETTE_ANIMATION_BLITTER;
00438 }

Generated on Mon Feb 16 23:12:05 2009 for openttd by  doxygen 1.5.6