00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
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
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
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
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
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
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;
00326
00327 int y_src = 0;
00328 int y_src_next = 0;
00329 int y_step = 0;
00330 int h_src = src->h;
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;
00341
00342 int x_src = 0;
00343 int x_src_next = 0;
00344 int x_step = 0;
00345 int w_src = src->w;
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
00359
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
00406 surface scale_surface(const surface &surf, int w, int h, bool optimize)
00407 {
00408
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
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
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
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;
00481 pix[1] = *(src_word + dx);
00482 pix[2] = *(src_word + dy);
00483 pix[3] = *(src_word + dx + dy);
00484
00485 bilin[0] = n*w;
00486 bilin[1] = n*e;
00487 bilin[2] = s*w;
00488 bilin[3] = s*e;
00489
00490
00491
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
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
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
00586
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
00698
00699
00700
00701
00702
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
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
00741
00742 if (alpha < 255/4)
00743 *beg = (alpha*4) << 24;
00744 else
00745 *beg = 0xFF000000;
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){
00775
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
00927
00928
00929
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
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
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
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;
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;
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
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078
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
01105
01106
01107
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
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
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
01495
01496
01497
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
01541 surface rotate_180_surface(const surface &surf, bool optimize)
01542 {
01543 if ( surf == NULL )
01544 return NULL;
01545
01546
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 {
01555 surface_lock lock(nsurf);
01556 Uint32* const pixels = lock.pixels();
01557
01558
01559
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
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
01583 surface rotate_90_surface(const surface &surf, bool clockwise, bool optimize)
01584 {
01585 if ( surf == NULL )
01586 return NULL;
01587
01588
01589 surface dst(create_neutral_surface(surf->h, surf->w));
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 {
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
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
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
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
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
01770
01771
01772
01773
01774
01775
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
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
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
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
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
01822
01823
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
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
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
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
01947
01948
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
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