sdl_utils.cpp

Go to the documentation of this file.
00001 /* $Id: sdl_utils.cpp 54113 2012-05-06 22:06:46Z jamit $ */
00002 /*
00003    Copyright (C) 2003 - 2012 by David White <dave@whitevine.net>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014 */
00015 
00016 /**
00017  *  @file
00018  *  Support-routines for the SDL-graphics-library.
00019  */
00020 
00021 #include "global.hpp"
00022 
00023 #include "sdl_utils.hpp"
00024 
00025 #include "floating_point_emulation.hpp"
00026 #include "neon.hpp"
00027 #include "video.hpp"
00028 
00029 #include <algorithm>
00030 #include <cassert>
00031 #include <cstring>
00032 #include <iostream>
00033 
00034 surface_lock::surface_lock(surface &surf) : surface_(surf), locked_(false)
00035 {
00036     if (SDL_MUSTLOCK(surface_))
00037         locked_ = SDL_LockSurface(surface_) == 0;
00038 }
00039 
00040 surface_lock::~surface_lock()
00041 {
00042     if (locked_)
00043         SDL_UnlockSurface(surface_);
00044 }
00045 
00046 const_surface_lock::const_surface_lock(const surface &surf) : surface_(surf), locked_(false)
00047 {
00048     if (SDL_MUSTLOCK(surface_))
00049         locked_ = SDL_LockSurface(surface_) == 0;
00050 }
00051 
00052 const_surface_lock::~const_surface_lock()
00053 {
00054     if (locked_)
00055         SDL_UnlockSurface(surface_);
00056 }
00057 
00058 SDL_Color int_to_color(const Uint32 rgb)
00059 {
00060     SDL_Color result;
00061     result.r = (0x00FF0000 & rgb )>> 16;
00062     result.g = (0x0000FF00 & rgb) >> 8;
00063     result.b = (0x000000FF & rgb);
00064     result.unused = 0;
00065     return result;
00066 }
00067 
00068 SDL_Color create_color(const unsigned char red
00069         , unsigned char green
00070         , unsigned char blue
00071         , unsigned char unused)
00072 {
00073     SDL_Color result;
00074     result.r = red;
00075     result.g = green;
00076     result.b = blue;
00077     result.unused = unused;
00078 
00079     return result;
00080 }
00081 
00082 SDLKey sdl_keysym_from_name(std::string const &keyname)
00083 {
00084     static bool initialized = false;
00085     typedef std::map<std::string const, SDLKey> keysym_map_t;
00086     static keysym_map_t keysym_map;
00087 
00088     if (!initialized) {
00089         for(SDLKey i = SDLK_FIRST; i < SDLK_LAST; i = SDLKey(int(i) + 1)) {
00090             std::string name = SDL_GetKeyName(i);
00091             if (!name.empty())
00092                 keysym_map[name] = i;
00093         }
00094         initialized = true;
00095     }
00096 
00097     keysym_map_t::const_iterator it = keysym_map.find(keyname);
00098     if (it != keysym_map.end())
00099         return it->second;
00100     else
00101         return SDLK_UNKNOWN;
00102 }
00103 
00104 bool point_in_rect(int x, int y, const SDL_Rect& rect)
00105 {
00106     return x >= rect.x && y >= rect.y && x < rect.x + rect.w && y < rect.y + rect.h;
00107 }
00108 
00109 bool rects_overlap(const SDL_Rect& rect1, const SDL_Rect& rect2)
00110 {
00111     return (rect1.x < rect2.x+rect2.w && rect2.x < rect1.x+rect1.w &&
00112             rect1.y < rect2.y+rect2.h && rect2.y < rect1.y+rect1.h);
00113 }
00114 
00115 SDL_Rect intersect_rects(SDL_Rect const &rect1, SDL_Rect const &rect2)
00116 {
00117     SDL_Rect res;
00118     res.x = std::max<int>(rect1.x, rect2.x);
00119     res.y = std::max<int>(rect1.y, rect2.y);
00120     int w = std::min<int>(rect1.x + rect1.w, rect2.x + rect2.w) - res.x;
00121     int h = std::min<int>(rect1.y + rect1.h, rect2.y + rect2.h) - res.y;
00122     if (w <= 0 || h <= 0) return empty_rect;
00123     res.w = w;
00124     res.h = h;
00125     return res;
00126 }
00127 
00128 SDL_Rect union_rects(SDL_Rect const &rect1, SDL_Rect const &rect2)
00129 {
00130     if (rect1.w == 0 || rect1.h == 0) return rect2;
00131     if (rect2.w == 0 || rect2.h == 0) return rect1;
00132     SDL_Rect res;
00133     res.x = std::min<int>(rect1.x, rect2.x);
00134     res.y = std::min<int>(rect1.y, rect2.y);
00135     res.w = std::max<int>(rect1.x + rect1.w, rect2.x + rect2.w) - res.x;
00136     res.h = std::max<int>(rect1.y + rect1.h, rect2.y + rect2.h) - res.y;
00137     return res;
00138 }
00139 
00140 SDL_Rect create_rect(const int x, const int y, const int w, const int h)
00141 {
00142     SDL_Rect rect;
00143     rect.x = x;
00144     rect.y = y;
00145     rect.w = w;
00146     rect.h = h;
00147     return rect;
00148 }
00149 
00150 bool operator<(const surface& a, const surface& b)
00151 {
00152     return a.get() < b.get();
00153 }
00154 
00155 bool is_neutral(const surface& surf)
00156 {
00157     return (surf->format->BytesPerPixel == 4 &&
00158         surf->format->Rmask == 0xFF0000u &&
00159         (surf->format->Amask | 0xFF000000u) == 0xFF000000u);
00160 }
00161 
00162 static SDL_PixelFormat& get_neutral_pixel_format()
00163     {
00164         static bool first_time = true;
00165         static SDL_PixelFormat format;
00166 
00167         if(first_time) {
00168             first_time = false;
00169             surface surf(SDL_CreateRGBSurface(SDL_SWSURFACE,1,1,32,0xFF0000,0xFF00,0xFF,0xFF000000));
00170             format = *surf->format;
00171             format.palette = NULL;
00172         }
00173 
00174         return format;
00175     }
00176 
00177 surface make_neutral_surface(const surface &surf)
00178 {
00179     if(surf == NULL) {
00180         std::cerr << "null neutral surface...\n";
00181         return NULL;
00182     }
00183 
00184     surface const result = SDL_ConvertSurface(surf,&get_neutral_pixel_format(),SDL_SWSURFACE);
00185     if(result != NULL) {
00186         SDL_SetAlpha(result,SDL_SRCALPHA,SDL_ALPHA_OPAQUE);
00187     }
00188 
00189     return result;
00190 }
00191 
00192 surface create_neutral_surface(int w, int h)
00193 {
00194     if (w < 0 || h < 0) {
00195         std::cerr << "error : neutral surface with negative dimensions\n";
00196         return NULL;
00197     }
00198 
00199     SDL_PixelFormat format = get_neutral_pixel_format();
00200     surface result = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h,
00201             format.BitsPerPixel,
00202             format.Rmask,
00203             format.Gmask,
00204             format.Bmask,
00205             format.Amask);
00206 
00207     return result;
00208 }
00209 
00210 surface create_optimized_surface(const surface &surf)
00211 {
00212     if(surf == NULL)
00213         return NULL;
00214 
00215     surface const result = display_format_alpha(surf);
00216     if(result == surf) {
00217         std::cerr << "resulting surface is the same as the source!!!\n";
00218     } else if(result == NULL) {
00219         return surf;
00220     }
00221 
00222     SDL_SetAlpha(result,SDL_SRCALPHA|SDL_RLEACCEL,SDL_ALPHA_OPAQUE);
00223 
00224     return result;
00225 }
00226 
00227 surface stretch_surface_horizontal(
00228         const surface& surf, const unsigned w, const bool optimize)
00229 {
00230     // Since SDL version 1.1.5 0 is transparent, before 255 was transparent.
00231     assert(SDL_ALPHA_TRANSPARENT==0);
00232 
00233     if(surf == NULL)
00234         return NULL;
00235 
00236     if(static_cast<int>(w) == surf->w) {
00237         return surf;
00238     }
00239     assert(w > 0);
00240 
00241     surface dst(create_neutral_surface(w, surf->h));
00242 
00243     surface src(make_neutral_surface(surf));
00244     // Now both surfaces are always in the "neutral" pixel format
00245 
00246     if(src == NULL || dst == NULL) {
00247         std::cerr << "Could not create surface to scale onto\n";
00248         return NULL;
00249     }
00250 
00251     {
00252         // Extra scoping used for the surface_lock.
00253         const_surface_lock src_lock(src);
00254         surface_lock dst_lock(dst);
00255 
00256         const Uint32* const src_pixels = src_lock.pixels();
00257         Uint32* dst_pixels = dst_lock.pixels();
00258 
00259         for(unsigned y = 0; y < static_cast<unsigned>(src->h); ++y) {
00260             const Uint32 pixel = src_pixels [y * src->w];
00261             for(unsigned x = 0; x < w; ++x) {
00262 
00263                 *dst_pixels++ = pixel;
00264 
00265             }
00266         }
00267     }
00268 
00269     return optimize ? create_optimized_surface(dst) : dst;
00270 }
00271 
00272 surface stretch_surface_vertical(
00273         const surface& surf, const unsigned h, const bool optimize)
00274 {
00275     // Since SDL version 1.1.5 0 is transparent, before 255 was transparent.
00276     assert(SDL_ALPHA_TRANSPARENT==0);
00277 
00278     if(surf == NULL)
00279         return NULL;
00280 
00281     if(static_cast<int>(h) == surf->h) {
00282         return surf;
00283     }
00284     assert(h > 0);
00285 
00286     surface dst(create_neutral_surface(surf->w, h));
00287 
00288     surface src(make_neutral_surface(surf));
00289     // Now both surfaces are always in the "neutral" pixel format
00290 
00291     if(src == NULL || dst == NULL) {
00292         std::cerr << "Could not create surface to scale onto\n";
00293         return NULL;
00294     }
00295 
00296     {
00297         // Extra scoping used for the surface_lock.
00298         const_surface_lock src_lock(src);
00299         surface_lock dst_lock(dst);
00300 
00301         const Uint32* const src_pixels = src_lock.pixels();
00302         Uint32* dst_pixels = dst_lock.pixels();
00303 
00304         for(unsigned y = 0; y < static_cast<unsigned>(h); ++y) {
00305           for(unsigned x = 0; x < static_cast<unsigned>(src->w); ++x) {
00306 
00307                 *dst_pixels++ = src_pixels[x];
00308             }
00309         }
00310     }
00311 
00312     return optimize ? create_optimized_surface(dst) : dst;
00313 }
00314 
00315 #ifdef PANDORA
00316 static void
00317 scale_surface_down(surface& dst, const surface& src, const int w_dst, const int h_dst)
00318 {
00319     const_surface_lock src_lock(src);
00320     surface_lock dst_lock(dst);
00321 
00322     const Uint32* const src_pixels = src_lock.pixels();
00323     Uint32* const dst_pixels = dst_lock.pixels();
00324 
00325     int y_dst = 0;       // The current y in the destination surface
00326 
00327     int y_src = 0;       // The current y in the source surface
00328     int y_src_next = 0;  // The next y in the source surface
00329     int y_step = 0;      // The y stepper
00330     int h_src = src->h;  // The height of the source surface
00331 
00332     for( ; y_dst != h_dst; ++y_dst, y_src = y_src_next) {
00333 
00334         y_step += h_src;
00335         do {
00336             ++y_src_next;
00337             y_step -= h_dst;
00338         } while(y_step >= h_dst);
00339 
00340         int x_dst = 0;       // The current x in the destination surface
00341 
00342         int x_src = 0;       // The current x in the source surface
00343         int x_src_next = 0;  // The next x in the source surface
00344         int x_step = 0;      // The x stepper
00345         int w_src = src->w;  // The width of the source surface
00346 
00347         for( ; x_dst != w_dst; ++x_dst, x_src = x_src_next) {
00348 
00349             x_step += w_src;
00350             do {
00351                 ++x_src_next;
00352                 x_step -= w_dst;
00353             } while(x_step >= w_dst);
00354 
00355             int r_sum = 0, g_sum = 0, b_sum = 0, a_sum = 0;
00356             int samples = 0;
00357 
00358             // We now have a rectangle, (xsrc,ysrc,xratio,yratio)
00359             // which we want to derive the pixel from
00360             for(int x = x_src; x < x_src_next; ++x) {
00361                 for(int y = y_src; y < y_src_next; ++y) {
00362 
00363                     ++samples;
00364 
00365                     const Uint32 pixel = src_pixels[y_src * w_src + x_src];
00366                     const Uint8 a = pixel >> 24;
00367                     if(a) {
00368                         a_sum += a;
00369                         r_sum += a * static_cast<Uint8>(pixel >> 16);
00370                         g_sum += a * static_cast<Uint8>(pixel >> 8);
00371                         b_sum += a * static_cast<Uint8>(pixel);
00372                     }
00373                 }
00374             }
00375 
00376             if(a_sum) {
00377 
00378                 const int adjustment = (a_sum | 1) >> 1;
00379                 r_sum += adjustment;
00380                 g_sum += adjustment;
00381                 b_sum += adjustment;
00382 
00383                 r_sum /= a_sum;
00384                 g_sum /= a_sum;
00385                 b_sum /= a_sum;
00386 
00387                 assert(samples == (x_src_next - x_src) * (y_src_next - y_src));
00388                 if(samples != 1) {
00389                     a_sum += (samples | 1) >> 1;
00390                     a_sum /= samples;
00391                 }
00392             }
00393 
00394             dst_pixels[y_dst * w_dst + x_dst] =
00395                       static_cast<Uint8>(a_sum) << 24
00396                     | static_cast<Uint8>(r_sum) << 16
00397                     | static_cast<Uint8>(g_sum) << 8
00398                     | static_cast<Uint8>(b_sum);
00399         }
00400     }
00401 }
00402 
00403 #endif
00404 
00405 // NOTE: Don't pass this function 0 scaling arguments.
00406 surface scale_surface(const surface &surf, int w, int h, bool optimize)
00407 {
00408     // Since SDL version 1.1.5 0 is transparent, before 255 was transparent.
00409     assert(SDL_ALPHA_TRANSPARENT==0);
00410 
00411     if(surf == NULL)
00412         return NULL;
00413 
00414     if(w == surf->w && h == surf->h) {
00415         return surf;
00416     }
00417     assert(w >= 0);
00418     assert(h >= 0);
00419 
00420     surface dst(create_neutral_surface(w,h));
00421 
00422     if (w == 0 || h ==0) {
00423         std::cerr << "Create an empty image\n";
00424         return create_optimized_surface(dst);
00425     }
00426 
00427     surface src(make_neutral_surface(surf));
00428     // Now both surfaces are always in the "neutral" pixel format
00429 
00430     if(src == NULL || dst == NULL) {
00431         std::cerr << "Could not create surface to scale onto\n";
00432         return NULL;
00433     }
00434 
00435     if (w > surf->w || h > surf->h)
00436     {
00437         const_surface_lock src_lock(src);
00438         surface_lock dst_lock(dst);
00439 
00440         const Uint32* const src_pixels = src_lock.pixels();
00441         Uint32* const dst_pixels = dst_lock.pixels();
00442 
00443         fixed_t xratio = fxpdiv(surf->w,w);
00444         fixed_t yratio = fxpdiv(surf->h,h);
00445 
00446         fixed_t ysrc = ftofxp(0.0);
00447         for(int ydst = 0; ydst != h; ++ydst, ysrc += yratio) {
00448             fixed_t xsrc = ftofxp(0.0);
00449             for(int xdst = 0; xdst != w; ++xdst, xsrc += xratio) {
00450                 const int xsrcint = fxptoi(xsrc);
00451                 const int ysrcint = fxptoi(ysrc);
00452 
00453                 const Uint32* const src_word = src_pixels + ysrcint*src->w + xsrcint;
00454                 Uint32* const dst_word = dst_pixels +    ydst*dst->w + xdst;
00455                 const int dx = (xsrcint + 1 < src->w) ? 1 : 0;
00456                 const int dy = (ysrcint + 1 < src->h) ? src->w : 0;
00457 
00458                 Uint8 r,g,b,a;
00459                 Uint32 rr,gg,bb,aa;
00460                 Uint16 avg_r, avg_g, avg_b, avg_a;
00461                 Uint32 pix[4], bilin[4];
00462 
00463                 // This next part is the fixed point
00464                 // equivalent of "take everything to
00465                 // the right of the decimal point."
00466                 // These fundamental weights decide
00467                 // the contributions from various
00468                 // input pixels. The labels assume
00469                 // that the upper left corner of the
00470                 // screen ("northeast") is 0,0 but the
00471                 // code should still be consistant if
00472                 // the graphics origin is actually
00473                 // somewhere else.
00474 
00475                 const fixed_t e = 0x000000FF & xsrc;
00476                 const fixed_t s = 0x000000FF & ysrc;
00477                 const fixed_t n = 0xFF - s;
00478                 const fixed_t w = 0xFF - e;
00479 
00480                 pix[0] = *src_word;              // northwest
00481                 pix[1] = *(src_word + dx);       // northeast
00482                 pix[2] = *(src_word + dy);       // southwest
00483                 pix[3] = *(src_word + dx + dy);  // southeast
00484 
00485                 bilin[0] = n*w;
00486                 bilin[1] = n*e;
00487                 bilin[2] = s*w;
00488                 bilin[3] = s*e;
00489 
00490                 // Scope out the neighboorhood, see
00491                 // what the pixel values are like.
00492 
00493                 int count = 0;
00494                 avg_r = avg_g = avg_b = avg_a = 0;
00495                 int loc;
00496                 for (loc=0; loc<4; loc++) {
00497                   a = pix[loc] >> 24;
00498                   r = pix[loc] >> 16;
00499                   g = pix[loc] >> 8;
00500                   b = pix[loc] >> 0;
00501                   if (a != 0) {
00502                     avg_r += r;
00503                     avg_g += g;
00504                     avg_b += b;
00505                     avg_a += a;
00506                     count++;
00507                   }
00508                 }
00509                 if (count>0) {
00510                   avg_r /= count;
00511                   avg_b /= count;
00512                   avg_g /= count;
00513                   avg_a /= count;
00514                 }
00515 
00516                 // Perform modified bilinear interpolation.
00517                 // Don't trust any color information from
00518                 // an RGBA sample when the alpha channel
00519                 // is set to fully transparent.
00520                 //
00521                 // Some of the input images are hex tiles,
00522                 // created using a hexagon shaped alpha channel
00523                 // that is either set to full-on or full-off.
00524                 //
00525                 // If intermediate alpha values are introduced
00526                 // along a hex edge, it produces a gametime artifact.
00527                 // Moving the mouse around will leave behind
00528                 // "hexagon halos" from the temporary highlighting.
00529                 // In other words, the Wesnoth rendering engine
00530                 // freaks out.
00531                 //
00532                 // The alpha thresholding step attempts
00533                 // to accommodates this limitation.
00534                 // There is a small loss of quality.
00535                 // For example, skeleton bowstrings
00536                 // are not as good as they could be.
00537 
00538                 rr = gg = bb = aa = 0;
00539                 for (loc=0; loc<4; loc++) {
00540                   a = pix[loc] >> 24;
00541                   r = pix[loc] >> 16;
00542                   g = pix[loc] >> 8;
00543                   b = pix[loc] >> 0;
00544                   if (a == 0) {
00545                     r = static_cast<Uint8>(avg_r);
00546                     g = static_cast<Uint8>(avg_g);
00547                     b = static_cast<Uint8>(avg_b);
00548                   }
00549                   rr += r * bilin[loc];
00550                   gg += g * bilin[loc];
00551                   bb += b * bilin[loc];
00552                   aa += a * bilin[loc];
00553                 }
00554                 r = rr >> 16;
00555                 g = gg >> 16;
00556                 b = bb >> 16;
00557                 a = aa >> 16;
00558                 a = (a < avg_a/2) ? 0 : avg_a;
00559                 *dst_word = (a << 24) + (r << 16) + (g << 8) + b;
00560             }
00561         }
00562     }
00563     else
00564     {
00565 #ifdef PANDORA
00566         scale_surface_down(dst, src, w, h);
00567 #else
00568         const_surface_lock src_lock(src);
00569         surface_lock dst_lock(dst);
00570 
00571         const Uint32* const src_pixels = src_lock.pixels();
00572         Uint32* const dst_pixels = dst_lock.pixels();
00573 
00574         tfloat xratio = tfloat(surf->w) / w;
00575         tfloat yratio = tfloat(surf->h) / h;
00576 
00577         tfloat ysrc;
00578         for(int ydst = 0; ydst != h; ++ydst, ysrc += yratio) {
00579             tfloat xsrc;
00580             for(int xdst = 0; xdst != w; ++xdst, xsrc += xratio) {
00581                 tfloat red, green, blue, alpha;
00582 
00583                 tfloat summation;
00584 
00585                 // We now have a rectangle, (xsrc,ysrc,xratio,yratio)
00586                 // which we want to derive the pixel from
00587                 for(tfloat xloc = xsrc; xloc < xsrc+xratio; xloc += 1) {
00588                     const tfloat xsize = std::min<tfloat>(floor(xloc + 1)-xloc,xsrc+xratio-xloc);
00589                     for(tfloat yloc = ysrc; yloc < ysrc+yratio; yloc += 1) {
00590                         const int xsrcint = std::max<int>(0,std::min<int>(src->w-1,xsrc.to_int()));
00591                         const int ysrcint = std::max<int>(0,std::min<int>(src->h-1,ysrc.to_int()));
00592 
00593                         const tfloat ysize = std::min<tfloat>(floor(yloc+1)-yloc,ysrc+yratio-yloc);
00594 
00595                         Uint8 r,g,b,a;
00596 
00597                         SDL_GetRGBA(src_pixels[ysrcint*src->w + xsrcint],src->format,&r,&g,&b,&a);
00598                         tfloat value = xsize * ysize;
00599                         summation += value;
00600                         if (!a) continue;
00601                         value *= a;
00602                         alpha += value;
00603                         red += r * value;
00604                         green += g * value;
00605                         blue += b * value;
00606                     }
00607                 }
00608 
00609                 if (alpha != 0) {
00610                     red = red / alpha + 0.5;
00611                     green = green / alpha  + 0.5;
00612                     blue = blue / alpha + 0.5;
00613                     alpha = alpha / summation + 0.5;
00614                 }
00615 
00616                 dst_pixels[ydst*dst->w + xdst] = SDL_MapRGBA(
00617                           dst->format
00618                         , red.to_int()
00619                         , green.to_int()
00620                         , blue.to_int()
00621                         , alpha.to_int());
00622             }
00623         }
00624 #endif
00625     }
00626 
00627     return optimize ? create_optimized_surface(dst) : dst;
00628 }
00629 
00630 surface adjust_surface_color(const surface &surf, int red, int green, int blue, bool optimize)
00631 {
00632     if(surf == NULL)
00633         return NULL;
00634 
00635     if((red == 0 && green == 0 && blue == 0))
00636         return optimize ? create_optimized_surface(surf) : surf;
00637 
00638     surface nsurf(make_neutral_surface(surf));
00639 
00640     if(nsurf == NULL) {
00641         std::cerr << "failed to make neutral surface\n";
00642         return NULL;
00643     }
00644 
00645     {
00646         surface_lock lock(nsurf);
00647         Uint32* beg = lock.pixels();
00648         Uint32* end = beg + nsurf->w*surf->h;
00649 
00650         while(beg != end) {
00651             Uint8 alpha = (*beg) >> 24;
00652 
00653             if(alpha) {
00654                 Uint8 r, g, b;
00655                 r = (*beg) >> 16;
00656                 g = (*beg) >> 8;
00657                 b = (*beg) >> 0;
00658 
00659                 r = std::max<int>(0,std::min<int>(255,int(r)+red));
00660                 g = std::max<int>(0,std::min<int>(255,int(g)+green));
00661                 b = std::max<int>(0,std::min<int>(255,int(b)+blue));
00662 
00663                 *beg = (alpha << 24) + (r << 16) + (g << 8) + b;
00664             }
00665 
00666             ++beg;
00667         }
00668     }
00669 
00670     return optimize ? create_optimized_surface(nsurf) : nsurf;
00671 }
00672 
00673 surface greyscale_image(const surface &surf, bool optimize)
00674 {
00675     if(surf == NULL)
00676         return NULL;
00677 
00678     surface nsurf(make_neutral_surface(surf));
00679     if(nsurf == NULL) {
00680         std::cerr << "failed to make neutral surface\n";
00681         return NULL;
00682     }
00683 
00684     {
00685         surface_lock lock(nsurf);
00686         Uint32* beg = lock.pixels();
00687         Uint32* end = beg + nsurf->w*surf->h;
00688 
00689         while(beg != end) {
00690             Uint8 alpha = (*beg) >> 24;
00691 
00692             if(alpha) {
00693                 Uint8 r, g, b;
00694                 r = (*beg) >> 16;
00695                 g = (*beg) >> 8;
00696                 b = (*beg);
00697                 //const Uint8 avg = (red+green+blue)/3;
00698 
00699                 // Use the correct formula for RGB to grayscale conversion.
00700                 // Ok, this is no big deal :)
00701                 // The correct formula being:
00702                 // gray=0.299red+0.587green+0.114blue
00703                 const Uint8 avg = static_cast<Uint8>((
00704                     77  * static_cast<Uint16>(r) +
00705                     150 * static_cast<Uint16>(g) +
00706                     29  * static_cast<Uint16>(b)  ) / 256);
00707 
00708                 *beg = (alpha << 24) | (avg << 16) | (avg << 8) | avg;
00709             }
00710 
00711             ++beg;
00712         }
00713     }
00714 
00715     return optimize ? create_optimized_surface(nsurf) : nsurf;
00716 }
00717 
00718 surface shadow_image(const surface &surf, bool optimize)
00719 {
00720     if(surf == NULL)
00721         return NULL;
00722 
00723     // we blur it, and reuse the neutral surface created by the blur function (optimized = false)
00724     surface nsurf (blur_alpha_surface(surf, 2, false));
00725 
00726     if(nsurf == NULL) {
00727         std::cerr << "failed to blur the shadow surface\n";
00728         return NULL;
00729     }
00730 
00731     {
00732         surface_lock lock(nsurf);
00733         Uint32* beg = lock.pixels();
00734         Uint32* end = beg + nsurf->w*surf->h;
00735 
00736         while(beg != end) {
00737             Uint8 alpha = (*beg) >> 24;
00738 
00739             if(alpha) {
00740                 // increase alpha and color in black (RGB=0)
00741                 // with some stupid optimization for handling maximum values
00742                 if (alpha < 255/4)
00743                     *beg = (alpha*4) << 24;
00744                 else
00745                     *beg = 0xFF000000; // we hit the maximum
00746             }
00747 
00748             ++beg;
00749         }
00750     }
00751 
00752     return optimize ? create_optimized_surface(nsurf) : nsurf;
00753 }
00754 
00755 
00756 surface recolor_image(surface surf, const std::map<Uint32, Uint32>& map_rgb, bool optimize){
00757     if(surf == NULL)
00758         return NULL;
00759 
00760     if(!map_rgb.empty()){
00761          surface nsurf(make_neutral_surface(surf));
00762          if(nsurf == NULL) {
00763             std::cerr << "failed to make neutral surface\n";
00764             return NULL;
00765          }
00766 
00767         surface_lock lock(nsurf);
00768         Uint32* beg = lock.pixels();
00769         Uint32* end = beg + nsurf->w*surf->h;
00770 
00771         while(beg != end) {
00772             Uint8 alpha = (*beg) >> 24;
00773 
00774             if(alpha){  // don't recolor invisible pixels.
00775                 // palette use only RGB channels, so remove alpha
00776                 Uint32 oldrgb = (*beg) & 0x00FFFFFF;
00777                 std::map<Uint32, Uint32>::const_iterator i = map_rgb.find(oldrgb);
00778                 if(i != map_rgb.end()){
00779                     *beg = (alpha << 24) + i->second;
00780                 }
00781             }
00782         ++beg;
00783         }
00784 
00785         return optimize ? create_optimized_surface(nsurf) : nsurf;
00786     }
00787     return surf;
00788 }
00789 
00790 surface brighten_image(const surface &surf, fixed_t amount, bool optimize)
00791 {
00792     if(surf == NULL) {
00793         return NULL;
00794     }
00795 
00796     surface nsurf(make_neutral_surface(surf));
00797 
00798     if(nsurf == NULL) {
00799         std::cerr << "could not make neutral surface...\n";
00800         return NULL;
00801     }
00802 
00803     {
00804         surface_lock lock(nsurf);
00805         Uint32* beg = lock.pixels();
00806         Uint32* end = beg + nsurf->w*surf->h;
00807 
00808         if (amount < 0) amount = 0;
00809         while(beg != end) {
00810             Uint8 alpha = (*beg) >> 24;
00811 
00812             if(alpha) {
00813                 Uint8 r, g, b;
00814                 r = (*beg) >> 16;
00815                 g = (*beg) >> 8;
00816                 b = (*beg);
00817 
00818                 r = std::min<unsigned>(unsigned(fxpmult(r, amount)),255);
00819                 g = std::min<unsigned>(unsigned(fxpmult(g, amount)),255);
00820                 b = std::min<unsigned>(unsigned(fxpmult(b, amount)),255);
00821 
00822                 *beg = (alpha << 24) + (r << 16) + (g << 8) + b;
00823             }
00824 
00825             ++beg;
00826         }
00827     }
00828 
00829     return optimize ? create_optimized_surface(nsurf) : nsurf;
00830 }
00831 
00832 surface adjust_surface_alpha(const surface &surf, fixed_t amount, bool optimize)
00833 {
00834     if(surf== NULL) {
00835         return NULL;
00836     }
00837 
00838     surface nsurf(make_neutral_surface(surf));
00839 
00840     if(nsurf == NULL) {
00841         std::cerr << "could not make neutral surface...\n";
00842         return NULL;
00843     }
00844 
00845     {
00846         surface_lock lock(nsurf);
00847         Uint32* beg = lock.pixels();
00848         Uint32* end = beg + nsurf->w*surf->h;
00849 
00850         if (amount < 0) amount = 0;
00851         while(beg != end) {
00852             Uint8 alpha = (*beg) >> 24;
00853 
00854             if(alpha) {
00855                 Uint8 r, g, b;
00856                 r = (*beg) >> 16;
00857                 g = (*beg) >> 8;
00858                 b = (*beg);
00859 
00860                 alpha = std::min<unsigned>(unsigned(fxpmult(alpha,amount)),255);
00861                 *beg = (alpha << 24) + (r << 16) + (g << 8) + b;
00862             }
00863 
00864             ++beg;
00865         }
00866     }
00867 
00868     return optimize ? create_optimized_surface(nsurf) : nsurf;
00869 }
00870 
00871 surface adjust_surface_alpha_add(const surface &surf, int amount, bool optimize)
00872 {
00873     if(surf== NULL) {
00874         return NULL;
00875     }
00876 
00877     surface nsurf(make_neutral_surface(surf));
00878 
00879     if(nsurf == NULL) {
00880         std::cerr << "could not make neutral surface...\n";
00881         return NULL;
00882     }
00883 
00884     {
00885         surface_lock lock(nsurf);
00886         Uint32* beg = lock.pixels();
00887         Uint32* end = beg + nsurf->w*surf->h;
00888 
00889         while(beg != end) {
00890             Uint8 alpha = (*beg) >> 24;
00891 
00892             if(alpha) {
00893                 Uint8 r, g, b;
00894                 r = (*beg) >> 16;
00895                 g = (*beg) >> 8;
00896                 b = (*beg);
00897 
00898                 alpha = Uint8(std::max<int>(0,std::min<int>(255,int(alpha) + amount)));
00899                 *beg = (alpha << 24) + (r << 16) + (g << 8) + b;
00900             }
00901 
00902             ++beg;
00903         }
00904     }
00905 
00906     return optimize ? create_optimized_surface(nsurf) : nsurf;
00907 }
00908 
00909 surface mask_surface(const surface &surf, const surface &mask, bool* empty_result, const std::string& filename)
00910 {
00911     if(surf == NULL) {
00912         return NULL;
00913     }
00914     if(mask == NULL) {
00915         return surf;
00916     }
00917 
00918     surface nsurf = make_neutral_surface(surf);
00919     surface nmask(make_neutral_surface(mask));
00920 
00921     if(nsurf == NULL || nmask == NULL) {
00922         std::cerr << "could not make neutral surface...\n";
00923         return NULL;
00924     }
00925     if (nsurf->w !=  nmask->w) {
00926         // we don't support efficiently different width.
00927         // (different height is not a real problem)
00928         // This function is used on all hexes and usually only for that
00929         // so better keep it simple and efficient for the normal case
00930         std::stringstream ss;
00931         ss << "Detected an image with bad dimensions: ";
00932         if(!filename.empty()) ss << filename << ": ";
00933         ss << nsurf->w << "x" << nsurf->h << "\n";
00934         std::cerr << ss.str();
00935         std::cerr << "It will not be masked, please use :"<< nmask->w << "x" << nmask->h << "\n";
00936         return nsurf;
00937     }
00938 
00939     bool empty = true;
00940     {
00941         surface_lock lock(nsurf);
00942         const_surface_lock mlock(nmask);
00943 
00944         Uint32* beg = lock.pixels();
00945         Uint32* end = beg + nsurf->w*surf->h;
00946         const Uint32* mbeg = mlock.pixels();
00947         const Uint32* mend = mbeg + nmask->w*nmask->h;
00948 
00949         while(beg != end && mbeg != mend) {
00950             Uint8 alpha = (*beg) >> 24;
00951 
00952             if(alpha) {
00953                 Uint8 r, g, b;
00954                 r = (*beg) >> 16;
00955                 g = (*beg) >> 8;
00956                 b = (*beg);
00957 
00958                 Uint8 malpha = (*mbeg) >> 24;
00959                 if (alpha > malpha) {
00960                     alpha = malpha;
00961                 }
00962                 if(alpha)
00963                     empty = false;
00964 
00965                 *beg = (alpha << 24) + (r << 16) + (g << 8) + b;
00966             }
00967 
00968             ++beg;
00969             ++mbeg;
00970         }
00971     }
00972     if(empty_result)
00973         *empty_result = empty;
00974 
00975     return nsurf;
00976     //return create_optimized_surface(nsurf);
00977 }
00978 
00979 bool in_mask_surface(const surface &surf, const surface &mask)
00980 {
00981     if(surf == NULL) {
00982         return false;
00983     }
00984     if(mask == NULL){
00985         return true;
00986     }
00987 
00988     if (surf->w != mask->w || surf->h != mask->h ) {
00989         // not same size, consider it doesn't fit
00990         return false;
00991     }
00992 
00993     surface nsurf = make_neutral_surface(surf);
00994     surface nmask(make_neutral_surface(mask));
00995 
00996     if(nsurf == NULL || nmask == NULL) {
00997         std::cerr << "could not make neutral surface...\n";
00998         return false;
00999     }
01000 
01001     {
01002         surface_lock lock(nsurf);
01003         const_surface_lock mlock(nmask);
01004 
01005         const Uint32* mbeg = mlock.pixels();
01006         const Uint32* mend = mbeg + nmask->w*nmask->h;
01007         Uint32* beg = lock.pixels();
01008         // no need for 'end', because both surfaces have same size
01009 
01010         while(mbeg != mend) {
01011             Uint8 malpha = (*mbeg) >> 24;
01012             if(malpha == 0) {
01013                 Uint8 alpha = (*beg) >> 24;
01014                 if (alpha)
01015                     return false;
01016             }
01017             ++mbeg;
01018             ++beg;
01019         }
01020     }
01021 
01022     return true;
01023 }
01024 
01025 surface submerge_alpha(const surface &surf, int depth, float alpha_base, float alpha_delta,  bool optimize)
01026 {
01027     if(surf== NULL) {
01028         return NULL;
01029     }
01030 
01031     surface nsurf(make_neutral_surface(surf));
01032 
01033     {
01034         surface_lock lock(nsurf);
01035 
01036         Uint32* beg = lock.pixels();
01037         Uint32* limit = beg + (nsurf->h-depth) * nsurf->w ;
01038         Uint32* end = beg + nsurf->w * nsurf->h;
01039         beg = limit; // directlt jump to the bottom part
01040 
01041         while(beg != end){
01042             Uint8 alpha = (*beg) >> 24;
01043 
01044             if(alpha) {
01045                 Uint8 r, g, b;
01046                 r = (*beg) >> 16;
01047                 g = (*beg) >> 8;
01048                 b = (*beg);
01049                 int d = (beg-limit)/nsurf->w;  // current depth in pixels
01050                 float a = alpha_base - d * alpha_delta;
01051                 fixed_t amount = ftofxp(a<0?0:a);
01052                 alpha = std::min<unsigned>(unsigned(fxpmult(alpha,amount)),255);
01053                 *beg = (alpha << 24) + (r << 16) + (g << 8) + b;
01054             }
01055 
01056             ++beg;
01057         }
01058 
01059 /*
01060         for(int y = submerge_height; y < nsurf->h; ++y) {
01061             Uint32* cur = beg + y * nsurf->w;
01062             Uint32* row_end = beg + (y+1) * nsurf->w;
01063             float d = y * 1.0 / depth;
01064             double a = 0.2;//std::max<double>(0, (1-d)*0.3);
01065             fixed_t amount = ftofxp(a);
01066             while(cur != row_end) {
01067                 Uint8 alpha = (*cur) >> 24;
01068 
01069                 if(alpha) {
01070                     Uint8 r, g, b;
01071                     r = (*cur) >> 16;
01072                     g = (*cur) >> 8;
01073                     b = (*cur);
01074                     alpha = std::min<unsigned>(unsigned(fxpmult(alpha,amount)),255);
01075                     *cur = (alpha << 24) + (r << 16) + (g << 8) + b;
01076                 }
01077 
01078                 ++cur;
01079             }
01080         }*/
01081 
01082     }
01083 
01084     return optimize ? create_optimized_surface(nsurf) : nsurf;
01085 
01086 }
01087 
01088 surface light_surface(const surface &surf, const surface &lightmap, bool optimize)
01089 {
01090     if(surf == NULL) {
01091         return NULL;
01092     }
01093     if(lightmap == NULL) {
01094         return surf;
01095     }
01096 
01097     surface nsurf = make_neutral_surface(surf);
01098 
01099     if(nsurf == NULL) {
01100         std::cerr << "could not make neutral surface...\n";
01101         return NULL;
01102     }
01103     if (nsurf->w != lightmap->w) {
01104         // we don't support efficiently different width.
01105         // (different height is not a real problem)
01106         // This function is used on all hexes and usually only for that
01107         // so better keep it simple and efficient for the normal case
01108         std::cerr << "Detected an image with bad dimensions :" << nsurf->w << "x" << nsurf->h << "\n";
01109         std::cerr << "It will not be lighted, please use :"<< lightmap->w << "x" << lightmap->h << "\n";
01110         return nsurf;
01111     }
01112     {
01113         surface_lock lock(nsurf);
01114         const_surface_lock llock(lightmap);
01115 
01116         Uint32* beg = lock.pixels();
01117         Uint32* end = beg + nsurf->w * nsurf->h;
01118         const Uint32* lbeg = llock.pixels();
01119         const Uint32* lend = lbeg + lightmap->w * lightmap->h;
01120 
01121         while(beg != end && lbeg != lend) {
01122             Uint8 alpha = (*beg) >> 24;
01123             if(alpha) {
01124                 Uint8 lr, lg, lb;
01125 
01126                 lr = (*lbeg) >> 16;
01127                 lg = (*lbeg) >> 8;
01128                 lb = (*lbeg);
01129 
01130                 Uint8 r, g, b;
01131                 r = (*beg) >> 16;
01132                 g = (*beg) >> 8;
01133                 b = (*beg);
01134 
01135                 int dr = (static_cast<int>(lr) - 128) * 2;
01136                 int dg = (static_cast<int>(lg) - 128) * 2;
01137                 int db = (static_cast<int>(lb) - 128) * 2;
01138                 //note that r + dr will promote r to int (needed to avoid Uint8 math)
01139                 r = std::max<int>(0,std::min<int>(255, r + dr));
01140                 g = std::max<int>(0,std::min<int>(255, g + dg));
01141                 b = std::max<int>(0,std::min<int>(255, b + db));
01142 
01143                 *beg = (alpha << 24) + (r << 16) + (g << 8) + b;
01144             }
01145             ++beg;
01146             ++lbeg;
01147         }
01148     }
01149 
01150     return optimize ? create_optimized_surface(nsurf) : nsurf;
01151 }
01152 
01153 
01154 surface blur_surface(const surface &surf, int depth, bool optimize)
01155 {
01156     if(surf == NULL) {
01157         return NULL;
01158     }
01159 
01160     surface res = make_neutral_surface(surf);
01161 
01162     if(res == NULL) {
01163         std::cerr << "could not make neutral surface...\n";
01164         return NULL;
01165     }
01166 
01167     SDL_Rect rect = create_rect(0, 0, surf->w, surf->h);
01168     blur_surface(res, rect, depth);
01169 
01170     return optimize ? create_optimized_surface(res) : res;
01171 }
01172 
01173 void blur_surface(surface& surf, SDL_Rect rect, unsigned depth)
01174 {
01175     if(surf == NULL) {
01176         return;
01177     }
01178 
01179     const unsigned max_blur = 256;
01180     if(depth > max_blur) {
01181         depth = max_blur;
01182     }
01183 
01184     Uint32 queue[max_blur];
01185     const Uint32* end_queue = queue + max_blur;
01186 
01187     const Uint32 ff = 0xff;
01188 
01189     const unsigned pixel_offset = rect.y * surf->w + rect.x;
01190 
01191     surface_lock lock(surf);
01192     for(unsigned y = 0; y < rect.h; ++y) {
01193         const Uint32* front = &queue[0];
01194         Uint32* back = &queue[0];
01195         Uint32 red = 0, green = 0, blue = 0, avg = 0;
01196         Uint32* p = lock.pixels() + pixel_offset + y * surf->w;
01197         for(unsigned x = 0; x <= depth && x < rect.w; ++x, ++p) {
01198             red += ((*p) >> 16)&0xFF;
01199             green += ((*p) >> 8)&0xFF;
01200             blue += (*p)&0xFF;
01201             ++avg;
01202             *back++ = *p;
01203             if(back == end_queue) {
01204                 back = &queue[0];
01205             }
01206         }
01207 
01208         p = lock.pixels() + pixel_offset + y * surf->w;
01209         for(unsigned x = 0; x < rect.w; ++x, ++p) {
01210             *p = 0xFF000000
01211                     | (std::min(red/avg,ff) << 16)
01212                     | (std::min(green/avg,ff) << 8)
01213                     | std::min(blue/avg,ff);
01214 
01215             if(x >= depth) {
01216                 red -= ((*front) >> 16)&0xFF;
01217                 green -= ((*front) >> 8)&0xFF;
01218                 blue -= *front&0xFF;
01219                 --avg;
01220                 ++front;
01221                 if(front == end_queue) {
01222                     front = &queue[0];
01223                 }
01224             }
01225 
01226             if(x + depth+1 < rect.w) {
01227                 Uint32* q = p + depth+1;
01228                 red += ((*q) >> 16)&0xFF;
01229                 green += ((*q) >> 8)&0xFF;
01230                 blue += (*q)&0xFF;
01231                 ++avg;
01232                 *back++ = *q;
01233                 if(back == end_queue) {
01234                     back = &queue[0];
01235                 }
01236             }
01237         }
01238     }
01239 
01240     for(unsigned x = 0; x < rect.w; ++x) {
01241         const Uint32* front = &queue[0];
01242         Uint32* back = &queue[0];
01243         Uint32 red = 0, green = 0, blue = 0, avg = 0;
01244         Uint32* p = lock.pixels() + pixel_offset + x;
01245         for(unsigned y = 0; y <= depth && y < rect.h; ++y, p += surf->w) {
01246             red += ((*p) >> 16)&0xFF;
01247             green += ((*p) >> 8)&0xFF;
01248             blue += *p&0xFF;
01249             ++avg;
01250             *back++ = *p;
01251             if(back == end_queue) {
01252                 back = &queue[0];
01253             }
01254         }
01255 
01256         p = lock.pixels() + pixel_offset + x;
01257         for(unsigned y = 0; y < rect.h; ++y, p += surf->w) {
01258             *p = 0xFF000000
01259                     | (std::min(red/avg,ff) << 16)
01260                     | (std::min(green/avg,ff) << 8)
01261                     | std::min(blue/avg,ff);
01262 
01263             if(y >= depth) {
01264                 red -= ((*front) >> 16)&0xFF;
01265                 green -= ((*front) >> 8)&0xFF;
01266                 blue -= *front&0xFF;
01267                 --avg;
01268                 ++front;
01269                 if(front == end_queue) {
01270                     front = &queue[0];
01271                 }
01272             }
01273 
01274             if(y + depth+1 < rect.h) {
01275                 Uint32* q = p + (depth+1)*surf->w;
01276                 red += ((*q) >> 16)&0xFF;
01277                 green += ((*q) >> 8)&0xFF;
01278                 blue += (*q)&0xFF;
01279                 ++avg;
01280                 *back++ = *q;
01281                 if(back == end_queue) {
01282                     back = &queue[0];
01283                 }
01284             }
01285         }
01286     }
01287 }
01288 
01289 surface blur_alpha_surface(const surface &surf, int depth, bool optimize)
01290 {
01291     if(surf == NULL) {
01292         return NULL;
01293     }
01294 
01295     surface res = make_neutral_surface(surf);
01296 
01297     if(res == NULL) {
01298         std::cerr << "could not make neutral surface...\n";
01299         return NULL;
01300     }
01301 
01302     const int max_blur = 256;
01303     if(depth > max_blur) {
01304         depth = max_blur;
01305     }
01306 
01307     Uint32 queue[max_blur];
01308     const Uint32* end_queue = queue + max_blur;
01309 
01310     const Uint32 ff = 0xff;
01311 
01312     surface_lock lock(res);
01313     int x, y;
01314     for(y = 0; y < res->h; ++y) {
01315         const Uint32* front = &queue[0];
01316         Uint32* back = &queue[0];
01317         Uint32 alpha=0, red = 0, green = 0, blue = 0, avg = 0;
01318         Uint32* p = lock.pixels() + y*res->w;
01319         for(x = 0; x <= depth && x < res->w; ++x, ++p) {
01320             alpha += ((*p) >> 24)&0xFF;
01321             red += ((*p) >> 16)&0xFF;
01322             green += ((*p) >> 8)&0xFF;
01323             blue += (*p)&0xFF;
01324             ++avg;
01325             *back++ = *p;
01326             if(back == end_queue) {
01327                 back = &queue[0];
01328             }
01329         }
01330 
01331         p = lock.pixels() + y*res->w;
01332         for(x = 0; x < res->w; ++x, ++p) {
01333             *p = (std::min(alpha/avg,ff) << 24) | (std::min(red/avg,ff) << 16) | (std::min(green/avg,ff) << 8) | std::min(blue/avg,ff);
01334             if(x >= depth) {
01335                 alpha -= ((*front) >> 24)&0xFF;
01336                 red -= ((*front) >> 16)&0xFF;
01337                 green -= ((*front) >> 8)&0xFF;
01338                 blue -= *front&0xFF;
01339                 --avg;
01340                 ++front;
01341                 if(front == end_queue) {
01342                     front = &queue[0];
01343                 }
01344             }
01345 
01346             if(x + depth+1 < res->w) {
01347                 Uint32* q = p + depth+1;
01348                 alpha += ((*q) >> 24)&0xFF;
01349                 red += ((*q) >> 16)&0xFF;
01350                 green += ((*q) >> 8)&0xFF;
01351                 blue += (*q)&0xFF;
01352                 ++avg;
01353                 *back++ = *q;
01354                 if(back == end_queue) {
01355                     back = &queue[0];
01356                 }
01357             }
01358         }
01359     }
01360 
01361     for(x = 0; x < res->w; ++x) {
01362         const Uint32* front = &queue[0];
01363         Uint32* back = &queue[0];
01364         Uint32 alpha=0, red = 0, green = 0, blue = 0, avg = 0;
01365         Uint32* p = lock.pixels() + x;
01366         for(y = 0; y <= depth && y < res->h; ++y, p += res->w) {
01367             alpha += ((*p) >> 24)&0xFF;
01368             red += ((*p) >> 16)&0xFF;
01369             green += ((*p) >> 8)&0xFF;
01370             blue += *p&0xFF;
01371             ++avg;
01372             *back++ = *p;
01373             if(back == end_queue) {
01374                 back = &queue[0];
01375             }
01376         }
01377 
01378         p = lock.pixels() + x;
01379         for(y = 0; y < res->h; ++y, p += res->w) {
01380             *p = (std::min(alpha/avg,ff) << 24) | (std::min(red/avg,ff) << 16) | (std::min(green/avg,ff) << 8) | std::min(blue/avg,ff);
01381             if(y >= depth) {
01382                 alpha -= ((*front) >> 24)&0xFF;
01383                 red -= ((*front) >> 16)&0xFF;
01384                 green -= ((*front) >> 8)&0xFF;
01385                 blue -= *front&0xFF;
01386                 --avg;
01387                 ++front;
01388                 if(front == end_queue) {
01389                     front = &queue[0];
01390                 }
01391             }
01392 
01393             if(y + depth+1 < res->h) {
01394                 Uint32* q = p + (depth+1)*res->w;
01395                 alpha += ((*q) >> 24)&0xFF;
01396                 red += ((*q) >> 16)&0xFF;
01397                 green += ((*q) >> 8)&0xFF;
01398                 blue += (*q)&0xFF;
01399                 ++avg;
01400                 *back++ = *q;
01401                 if(back == end_queue) {
01402                     back = &queue[0];
01403                 }
01404             }
01405         }
01406     }
01407 
01408     return optimize ? create_optimized_surface(res) : res;
01409 }
01410 
01411 surface cut_surface(const surface &surf, SDL_Rect const &r)
01412 {
01413     if(surf == NULL)
01414         return NULL;
01415 
01416     surface res = create_compatible_surface(surf, r.w, r.h);
01417 
01418     size_t sbpp = surf->format->BytesPerPixel;
01419     size_t spitch = surf->pitch;
01420     size_t rbpp = res->format->BytesPerPixel;
01421     size_t rpitch = res->pitch;
01422 
01423     // compute the areas to copy
01424     SDL_Rect src_rect = r;
01425     SDL_Rect dst_rect = { 0, 0, r.w, r.h };
01426 
01427     if (src_rect.x < 0) {
01428         if (src_rect.x + src_rect.w <= 0)
01429             return res;
01430         dst_rect.x -= src_rect.x;
01431         dst_rect.w += src_rect.x;
01432         src_rect.w += src_rect.x;
01433         src_rect.x = 0;
01434     }
01435     if (src_rect.y < 0) {
01436         if (src_rect.y + src_rect.h <= 0)
01437             return res;
01438         dst_rect.y -= src_rect.y;
01439         dst_rect.h += src_rect.y;
01440         src_rect.h += src_rect.y;
01441         src_rect.y = 0;
01442     }
01443 
01444     if(src_rect.x >= surf->w || src_rect.y >= surf->h)
01445         return res;
01446 
01447     const_surface_lock slock(surf);
01448     surface_lock rlock(res);
01449 
01450     const Uint8* src = reinterpret_cast<const Uint8 *>(slock.pixels());
01451     Uint8* dest = reinterpret_cast<Uint8 *>(rlock.pixels());
01452 
01453     for(int y = 0; y < src_rect.h && (src_rect.y + y) < surf->h; ++y) {
01454         const Uint8* line_src  = src  + (src_rect.y + y) * spitch + src_rect.x * sbpp;
01455         Uint8* line_dest = dest + (dst_rect.y + y) * rpitch + dst_rect.x * rbpp;
01456         size_t size = src_rect.w + src_rect.x <= surf->w ? src_rect.w : surf->w - src_rect.x;
01457 
01458         assert(rpitch >= src_rect.w * rbpp);
01459         memcpy(line_dest, line_src, size * rbpp);
01460     }
01461 
01462     return res;
01463 }
01464 surface blend_surface(
01465           const surface &surf
01466         , const double amount
01467         , const Uint32 color
01468         , const bool optimize)
01469 {
01470     if(surf== NULL) {
01471         return NULL;
01472     }
01473 
01474     surface nsurf(make_neutral_surface(surf));
01475 
01476     if(nsurf == NULL) {
01477         std::cerr << "could not make neutral surface...\n";
01478         return NULL;
01479     }
01480 
01481     {
01482         surface_lock lock(nsurf);
01483         Uint32* beg = lock.pixels();
01484         Uint32* end = beg + nsurf->w*surf->h;
01485 
01486         Uint16 ratio = amount * 256;
01487         const Uint16 red   = ratio * static_cast<Uint8>(color >> 16);
01488         const Uint16 green = ratio * static_cast<Uint8>(color >> 8);
01489         const Uint16 blue  = ratio * static_cast<Uint8>(color);
01490         ratio = 256 - ratio;
01491 
01492 #ifdef PANDORA
01493         /*
01494          * Use an optimised version of the generic algorithm. The optimised
01495          * version processes 8 pixels a time. If the number of pixels is not an
01496          * exact multiple of 8 it falls back to the generic algorithm to handle
01497          * the last pixels.
01498          */
01499         uint16x8_t vred = vdupq_n_u16(red);
01500         uint16x8_t vgreen = vdupq_n_u16(green);
01501         uint16x8_t vblue = vdupq_n_u16(blue);
01502 
01503         uint8x8_t vratio = vdup_n_u8(ratio);
01504 
01505         const int div = (nsurf->w * surf->h) / 8;
01506         for(int i = 0; i < div; ++i, beg += 8) {
01507             uint8x8x4_t rgba = vld4_u8(reinterpret_cast<Uint8*>(beg));
01508 
01509             uint16x8_t b = vmull_u8(rgba.val[0], vratio);
01510             uint16x8_t g = vmull_u8(rgba.val[1], vratio);
01511             uint16x8_t r = vmull_u8(rgba.val[2], vratio);
01512 
01513             b = vaddq_u16(b, vblue);
01514             g = vaddq_u16(g, vgreen);
01515             r = vaddq_u16(r, vred);
01516 
01517             rgba.val[0] = vshrn_n_u16(b, 8);
01518             rgba.val[1] = vshrn_n_u16(g, 8);
01519             rgba.val[2] = vshrn_n_u16(r, 8);
01520 
01521             vst4_u8(reinterpret_cast<Uint8*>(beg), rgba);
01522         }
01523 #endif
01524         while(beg != end) {
01525             Uint8 a = static_cast<Uint8>(*beg >> 24);
01526             Uint8 r = (ratio * static_cast<Uint8>(*beg >> 16) + red)   >> 8;
01527             Uint8 g = (ratio * static_cast<Uint8>(*beg >> 8)  + green) >> 8;
01528             Uint8 b = (ratio * static_cast<Uint8>(*beg)       + blue)  >> 8;
01529 
01530             *beg = (a << 24) | (r << 16) | (g << 8) | b;
01531 
01532             ++beg;
01533         }
01534     }
01535 
01536     return optimize ? create_optimized_surface(nsurf) : nsurf;
01537 }
01538 
01539 
01540 // Rotates a surface 180 degrees.
01541 surface rotate_180_surface(const surface &surf, bool optimize)
01542 {
01543     if ( surf == NULL )
01544         return NULL;
01545 
01546     // Work with a "neutral" (unoptimized) surface.
01547     surface nsurf(make_neutral_surface(surf));
01548 
01549     if ( nsurf == NULL ) {
01550         std::cerr << "could not make neutral surface...\n";
01551         return NULL;
01552     }
01553 
01554     {// Code block to limit the scope of the surface lock.
01555         surface_lock lock(nsurf);
01556         Uint32* const pixels = lock.pixels();
01557 
01558         // Swap pixels in the upper half of the image with
01559         // those in the lower half.
01560         for (int y=0; y != nsurf->h/2; ++y) {
01561             for(int x=0; x != nsurf->w; ++x) {
01562                 const int index1 = y*nsurf->w + x;
01563                 const int index2 = (nsurf->h-y)*nsurf->w - x - 1;
01564                 std::swap(pixels[index1],pixels[index2]);
01565             }
01566         }
01567 
01568         if ( is_odd(nsurf->h) ) {
01569             // The middle row still needs to be processed.
01570             for (int x=0; x != nsurf->w/2; ++x) {
01571                 const int index1 = (nsurf->h/2)*nsurf->w + x;
01572                 const int index2 = (nsurf->h/2)*nsurf->w + (nsurf->w - x - 1);
01573                 std::swap(pixels[index1],pixels[index2]);
01574             }
01575         }
01576     }
01577 
01578     return optimize ? create_optimized_surface(nsurf) : nsurf;
01579 }
01580 
01581 
01582 // Rotates a surface 90 degrees, either clockwise or counter-clockwise.
01583 surface rotate_90_surface(const surface &surf, bool clockwise, bool optimize)
01584 {
01585     if ( surf == NULL )
01586         return NULL;
01587 
01588     // Work with "neutral" (unoptimized) surfaces.
01589     surface dst(create_neutral_surface(surf->h, surf->w)); // Flipped dimensions.
01590     surface src(make_neutral_surface(surf));
01591 
01592     if ( src == NULL  ||  dst == NULL ) {
01593         std::cerr << "could not make neutral surface...\n";
01594         return NULL;
01595     }
01596 
01597     {// Code block to limit the scope of the surface locks.
01598         const_surface_lock src_lock(src);
01599         surface_lock dst_lock(dst);
01600 
01601         const Uint32* const src_pixels = src_lock.pixels();
01602         Uint32* const dst_pixels = dst_lock.pixels();
01603 
01604         // Copy the pixels.
01605         for ( int y = 0; y != src->h; ++y ) {
01606             for ( int x = 0; x != src->w; ++x ) {
01607                 const int src_index = y*src->w + x;
01608                 const int dst_index = clockwise ?
01609                                           x*dst->w + (dst->w-1-y) :
01610                                           (dst->h-1-x)*dst->w + y;
01611                 dst_pixels[dst_index] = src_pixels[src_index];
01612             }
01613         }
01614     }
01615 
01616     return optimize ? create_optimized_surface(dst) : dst;
01617 }
01618 
01619 
01620 surface flip_surface(const surface &surf, bool optimize)
01621 {
01622     if(surf == NULL) {
01623         return NULL;
01624     }
01625 
01626     surface nsurf(make_neutral_surface(surf));
01627 
01628     if(nsurf == NULL) {
01629         std::cerr << "could not make neutral surface...\n";
01630         return NULL;
01631     }
01632 
01633     {
01634         surface_lock lock(nsurf);
01635         Uint32* const pixels = lock.pixels();
01636 
01637         for(int y = 0; y != nsurf->h; ++y) {
01638             for(int x = 0; x != nsurf->w/2; ++x) {
01639                 const int index1 = y*nsurf->w + x;
01640                 const int index2 = (y+1)*nsurf->w - x - 1;
01641                 std::swap(pixels[index1],pixels[index2]);
01642             }
01643         }
01644     }
01645 
01646     return optimize ? create_optimized_surface(nsurf) : nsurf;
01647 }
01648 
01649 surface flop_surface(const surface &surf, bool optimize)
01650 {
01651     if(surf == NULL) {
01652         return NULL;
01653     }
01654 
01655     surface nsurf(make_neutral_surface(surf));
01656 
01657     if(nsurf == NULL) {
01658         std::cerr << "could not make neutral surface...\n";
01659         return NULL;
01660     }
01661 
01662     {
01663         surface_lock lock(nsurf);
01664         Uint32* const pixels = lock.pixels();
01665 
01666         for(int x = 0; x != nsurf->w; ++x) {
01667             for(int y = 0; y != nsurf->h/2; ++y) {
01668                 const int index1 = y*nsurf->w + x;
01669                 const int index2 = (nsurf->h-y-1)*surf->w + x;
01670                 std::swap(pixels[index1],pixels[index2]);
01671             }
01672         }
01673     }
01674 
01675     return optimize ? create_optimized_surface(nsurf) : nsurf;
01676 }
01677 
01678 
01679 surface create_compatible_surface(const surface &surf, int width, int height)
01680 {
01681     if(surf == NULL)
01682         return NULL;
01683 
01684     if(width == -1)
01685         width = surf->w;
01686 
01687     if(height == -1)
01688         height = surf->h;
01689 
01690     surface s = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, surf->format->BitsPerPixel,
01691         surf->format->Rmask, surf->format->Gmask, surf->format->Bmask, surf->format->Amask);
01692     if (surf->format->palette) {
01693         SDL_SetPalette(s, SDL_LOGPAL, surf->format->palette->colors, 0, surf->format->palette->ncolors);
01694     }
01695     return s;
01696 }
01697 
01698 void blit_surface(const surface& src,
01699     const SDL_Rect* srcrect, surface& dst, const SDL_Rect* dstrect)
01700 {
01701     assert(src);
01702     assert(dst);
01703 
01704     // Get the areas to blit
01705     SDL_Rect dst_rect = create_rect(0, 0, dst->w, dst->h);
01706     if(dstrect) {
01707         dst_rect.x = dstrect->x;
01708         dst_rect.w -= dstrect->x;
01709 
01710         dst_rect.y = dstrect->y;
01711         dst_rect.h -= dstrect->y;
01712 
01713     }
01714 
01715     SDL_Rect src_rect = create_rect(0, 0, src->w, src->h);
01716     if(srcrect && srcrect->w && srcrect->h) {
01717         src_rect.x = srcrect->x;
01718         src_rect.y = srcrect->y;
01719 
01720         src_rect.w = srcrect->w;
01721         src_rect.h = srcrect->h;
01722 
01723         if (src_rect.x < 0) {
01724             if (src_rect.x + src_rect.w <= 0 || src_rect.x + dst_rect.w <= 0 )
01725                 return;
01726             dst_rect.x -= src_rect.x;
01727             dst_rect.w += src_rect.x;
01728             src_rect.w += src_rect.x;
01729             src_rect.x = 0;
01730         }
01731         if (src_rect.y < 0) {
01732             if (src_rect.y + src_rect.h <= 0 || src_rect.y + dst_rect.h <= 0 )
01733                 return;
01734             dst_rect.y -= src_rect.y;
01735             dst_rect.h += src_rect.y;
01736             src_rect.h += src_rect.y;
01737             src_rect.y = 0;
01738         }
01739         if (src_rect.x + src_rect.w > src->w) {
01740             if (src_rect.x >= src->w)
01741                 return;
01742             src_rect.w = src->w - src_rect.x;
01743         }
01744         if (src_rect.y + src_rect.h > src->h) {
01745             if (src_rect.y >= src->h)
01746                 return;
01747             src_rect.h = src->h - src_rect.y;
01748         }
01749     }
01750 
01751     assert(dst_rect.x >= 0);
01752     assert(dst_rect.y >= 0);
01753 
01754     // Get the blit size limits.
01755     const unsigned width = std::min(src_rect.w, dst_rect.w);
01756     const unsigned height = std::min(src_rect.h, dst_rect.h);
01757 
01758     {
01759         // Extra scoping used for the surface_lock.
01760         const_surface_lock src_lock(src);
01761         surface_lock dst_lock(dst);
01762 
01763         const Uint32* const src_pixels = src_lock.pixels();
01764         Uint32* dst_pixels = dst_lock.pixels();
01765 
01766         for(unsigned y = 0; y < height; ++y) {
01767             for(unsigned x = 0; x < width; ++x) {
01768 
01769                 // We need to do the blitting using some optimizations
01770                 // if the src is fully transparent we can ignore this pixel
01771                 // if the src is fully opaque we can overwrite the destination with this pixel
01772                 // if the destination is fully transparent we replace us with the source
01773                 //
01774                 // We do these optimizations between the extraction of the variables
01775                 // to avoid creating variables not used (it might save us some cycles).
01776 
01777                 const int src_offset = (y + src_rect.y) * src->w + (x + src_rect.x);
01778                 assert(src_offset < src->w * src->h);
01779                 const Uint32 src_pixel = src_pixels[src_offset];
01780                 const Uint8 src_a = (src_pixel & 0xFF000000) >> 24;
01781 
01782                 if(!src_a) {
01783                     // Fully transparent source, ignore
01784                     continue;
01785                 }
01786 
01787                 const ptrdiff_t dst_offset = (y + dst_rect.y) * dst->w + (x + dst_rect.x);
01788                 assert(dst_offset < dst->w * dst->h);
01789                 if(src_a == 255) {
01790                     // Fully opaque source, copy
01791                     dst_pixels[dst_offset] = src_pixel;
01792                     continue;
01793                 }
01794 
01795                 const Uint32 dst_pixel = dst_pixels[dst_offset];
01796                 Uint8 dst_a = (dst_pixel & 0xFF000000) >> 24;
01797 
01798                 if(!dst_a) {
01799                     // Fully transparent destination, copy
01800                     dst_pixels[dst_offset] = src_pixel;
01801                     continue;
01802                 }
01803 
01804                 const Uint8 src_r = (src_pixel & 0x00FF0000) >> 16;
01805                 const Uint8 src_g = (src_pixel & 0x0000FF00) >> 8;
01806                 const Uint8 src_b = src_pixel & 0x000000FF;
01807 
01808                 Uint8 dst_r = (dst_pixel & 0x00FF0000) >> 16;
01809                 Uint8 dst_g = (dst_pixel & 0x0000FF00) >> 8;
01810                 Uint8 dst_b = dst_pixel & 0x000000FF;
01811 
01812                 if(dst_a == 255) {
01813 
01814                     // Destination fully opaque blend the source.
01815                     dst_r = (((src_r - dst_r) * src_a) >> 8 ) + dst_r;
01816                     dst_g = (((src_g - dst_g) * src_a) >> 8 ) + dst_g;
01817                     dst_b = (((src_b - dst_b) * src_a) >> 8 ) + dst_b;
01818 
01819                 } else {
01820 
01821                     // Destination and source party transparent.
01822 
01823                     // acquired the data now do the blitting
01824                     const unsigned tmp_a = 255 - src_a;
01825 
01826                     const unsigned tmp_r = 1 + (src_r * src_a) + (dst_r * tmp_a);
01827                     dst_r = (tmp_r + (tmp_r >> 8)) >> 8;
01828 
01829                     const unsigned tmp_g = 1 + (src_g * src_a) + (dst_g * tmp_a);
01830                     dst_g = (tmp_g + (tmp_g >> 8)) >> 8;
01831 
01832                     const unsigned tmp_b = 1 + (src_b * src_a) + (dst_b * tmp_a);
01833                     dst_b = (tmp_b + (tmp_b >> 8)) >> 8;
01834 
01835                     dst_a += (((255 - dst_a) * src_a) >> 8);
01836                 }
01837 
01838                 dst_pixels[dst_offset] = (dst_a << 24) | (dst_r << 16) | (dst_g << 8) | (dst_b);
01839 
01840             }
01841         }
01842     }
01843 }
01844 
01845 
01846 
01847 void fill_rect_alpha(SDL_Rect &rect, Uint32 color, Uint8 alpha, surface &target)
01848 {
01849     if(alpha == SDL_ALPHA_OPAQUE) {
01850         sdl_fill_rect(target,&rect,color);
01851         return;
01852     } else if(alpha == SDL_ALPHA_TRANSPARENT) {
01853         return;
01854     }
01855 
01856     surface tmp(create_compatible_surface(target,rect.w,rect.h));
01857     if(tmp == NULL) {
01858         return;
01859     }
01860 
01861     SDL_Rect r = {0,0,rect.w,rect.h};
01862     sdl_fill_rect(tmp,&r,color);
01863     SDL_SetAlpha(tmp,SDL_SRCALPHA,alpha);
01864     sdl_blit(tmp,NULL,target,&rect);
01865 }
01866 
01867 surface get_surface_portion(const surface &src, SDL_Rect &area, bool optimize_format)
01868 {
01869     if (src == NULL) {
01870         return NULL;
01871     }
01872 
01873     // Check if there is something in the portion
01874     if(area.x >= src->w || area.y >= src->h || area.x + area.w < 0 || area.y + area.h < 0) {
01875         return NULL;
01876     }
01877 
01878     if(area.x + area.w > src->w) {
01879         area.w = src->w - area.x;
01880     }
01881     if(area.y + area.h > src->h) {
01882         area.h = src->h - area.y;
01883     }
01884 
01885     // use same format as the source (almost always the screen)
01886     surface dst = create_compatible_surface(src, area.w, area.h);
01887 
01888     if(dst == NULL) {
01889         std::cerr << "Could not create a new surface in get_surface_portion()\n";
01890         return NULL;
01891     }
01892 
01893     sdl_blit(src, &area, dst, NULL);
01894 
01895     return optimize_format ? display_format_alpha(dst) : dst;
01896 }
01897 
01898 namespace {
01899 
01900 struct not_alpha
01901 {
01902     not_alpha() {}
01903 
01904     // we assume neutral format
01905     bool operator()(Uint32 pixel) const {
01906         Uint8 alpha = pixel >> 24;
01907         return alpha != 0x00;
01908     }
01909 };
01910 
01911 }
01912 
01913 SDL_Rect get_non_transparent_portion(const surface &surf)
01914 {
01915     SDL_Rect res = {0,0,0,0};
01916     surface nsurf(make_neutral_surface(surf));
01917     if(nsurf == NULL) {
01918         std::cerr << "failed to make neutral surface\n";
01919         return res;
01920     }
01921 
01922     const not_alpha calc;
01923 
01924     surface_lock lock(nsurf);
01925     const Uint32* const pixels = lock.pixels();
01926 
01927     int n;
01928     for(n = 0; n != nsurf->h; ++n) {
01929         const Uint32* const start_row = pixels + n*nsurf->w;
01930         const Uint32* const end_row = start_row + nsurf->w;
01931 
01932         if(std::find_if(start_row,end_row,calc) != end_row)
01933             break;
01934     }
01935 
01936     res.y = n;
01937 
01938     for(n = 0; n != nsurf->h-res.y; ++n) {
01939         const Uint32* const start_row = pixels + (nsurf->h-n-1)*surf->w;
01940         const Uint32* const end_row = start_row + nsurf->w;
01941 
01942         if(std::find_if(start_row,end_row,calc) != end_row)
01943             break;
01944     }
01945 
01946     // The height is the height of the surface,
01947     // minus the distance from the top and
01948     // the distance from the bottom.
01949     res.h = nsurf->h - res.y - n;
01950 
01951     for(n = 0; n != nsurf->w; ++n) {
01952         int y;
01953         for(y = 0; y != nsurf->h; ++y) {
01954             const Uint32 pixel = pixels[y*nsurf->w + n];
01955             if(calc(pixel))
01956                 break;
01957         }
01958 
01959         if(y != nsurf->h)
01960             break;
01961     }
01962 
01963     res.x = n;
01964 
01965     for(n = 0; n != nsurf->w-res.x; ++n) {
01966         int y;
01967         for(y = 0; y != nsurf->h; ++y) {
01968             const Uint32 pixel = pixels[y*nsurf->w + surf->w - n - 1];
01969             if(calc(pixel))
01970                 break;
01971         }
01972 
01973         if(y != nsurf->h)
01974             break;
01975     }
01976 
01977     res.w = nsurf->w - res.x - n;
01978 
01979     return res;
01980 }
01981 
01982 bool operator==(const SDL_Rect& a, const SDL_Rect& b)
01983 {
01984     return a.x == b.x && a.y == b.y && a.w == b.w && a.h == b.h;
01985 }
01986 
01987 bool operator!=(const SDL_Rect& a, const SDL_Rect& b)
01988 {
01989     return !operator==(a,b);
01990 }
01991 
01992 bool operator==(const SDL_Color& a, const SDL_Color& b) {
01993     return a.r == b.r && a.g == b.g && a.b == b.b;
01994 }
01995 
01996 bool operator!=(const SDL_Color& a, const SDL_Color& b) {
01997     return !operator==(a,b);
01998 }
01999 
02000 SDL_Color inverse(const SDL_Color& color) {
02001     SDL_Color inverse;
02002     inverse.r = 255 - color.r;
02003     inverse.g = 255 - color.g;
02004     inverse.b = 255 - color.b;
02005     inverse.unused = 0;
02006     return inverse;
02007 }
02008 
02009 surface_restorer::surface_restorer() : target_(NULL), rect_(empty_rect), surface_(NULL)
02010 {
02011 }
02012 
02013 surface_restorer::surface_restorer(CVideo* target, const SDL_Rect& rect)
02014 : target_(target), rect_(rect), surface_(NULL)
02015 {
02016     update();
02017 }
02018 
02019 surface_restorer::~surface_restorer()
02020 {
02021     restore();
02022 }
02023 
02024 void surface_restorer::restore(SDL_Rect const &dst) const
02025 {
02026     if (surface_.null())
02027         return;
02028     SDL_Rect dst2 = intersect_rects(dst, rect_);
02029     if (dst2.w == 0 || dst2.h == 0)
02030         return;
02031     SDL_Rect src = dst2;
02032     src.x -= rect_.x;
02033     src.y -= rect_.y;
02034     sdl_blit(surface_, &src, target_->getSurface(), &dst2);
02035     update_rect(dst2);
02036 }
02037 
02038 void surface_restorer::restore() const
02039 {
02040     if (surface_.null())
02041         return;
02042     SDL_Rect dst = rect_;
02043     sdl_blit(surface_, NULL, target_->getSurface(), &dst);
02044     update_rect(rect_);
02045 }
02046 
02047 void surface_restorer::update()
02048 {
02049     if(rect_.w == 0 || rect_.h == 0)
02050         surface_.assign(NULL);
02051     else
02052         surface_.assign(::get_surface_portion(target_->getSurface(),rect_));
02053 }
02054 
02055 void surface_restorer::cancel()
02056 {
02057     surface_.assign(NULL);
02058 }
02059 
02060 void draw_rectangle(int x, int y, int w, int h, Uint32 color,surface target)
02061 {
02062 
02063     SDL_Rect top = create_rect(x, y, w, 1);
02064     SDL_Rect bot = create_rect(x, y + h - 1, w, 1);
02065     SDL_Rect left = create_rect(x, y, 1, h);
02066     SDL_Rect right = create_rect(x + w - 1, y, 1, h);
02067 
02068     sdl_fill_rect(target,&top,color);
02069     sdl_fill_rect(target,&bot,color);
02070     sdl_fill_rect(target,&left,color);
02071     sdl_fill_rect(target,&right,color);
02072 }
02073 
02074 void draw_solid_tinted_rectangle(int x, int y, int w, int h,
02075                                  int r, int g, int b,
02076                                  double alpha, surface target)
02077 {
02078 
02079     SDL_Rect rect = create_rect(x, y, w, h);
02080     fill_rect_alpha(rect,SDL_MapRGB(target->format,r,g,b),Uint8(alpha*255),target);
02081 }
02082 
02083 void draw_centered_on_background(surface surf, const SDL_Rect& rect, const SDL_Color& color, surface target)
02084 {
02085     clip_rect_setter clip_setter(target, &rect);
02086 
02087     Uint32 col = SDL_MapRGBA(target->format, color.r, color.g, color.b, color.unused);
02088     //TODO: only draw background outside the image
02089     SDL_Rect r = rect;
02090     sdl_fill_rect(target, &r, col);
02091 
02092     if (surf != NULL) {
02093         r.x = rect.x + (rect.w-surf->w)/2;
02094         r.y = rect.y + (rect.h-surf->h)/2;
02095         sdl_blit(surf, NULL, target, &r);
02096     }
02097     update_rect(rect);
02098 }
02099 
02100 std::ostream& operator<<(std::ostream& s, const SDL_Rect& rect)
02101 {
02102     s << rect.x << ',' << rect.y << " x "  << rect.w << ',' << rect.h;
02103     return s;
02104 }
02105 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Fri May 25 2012 01:03:09 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs