00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "global.hpp"
00019
00020 #include "config.hpp"
00021 #include "log.hpp"
00022 #include "sdl_utils.hpp"
00023 #include "util.hpp"
00024 #include "video.hpp"
00025
00026 #include <algorithm>
00027 #include <string.h>
00028 #include <cassert>
00029 #include <cmath>
00030 #include <iostream>
00031 #include <map>
00032
00033 SDL_Color int_to_color(const Uint32 rgb) {
00034 SDL_Color to_return = {
00035 (0x00FF0000 & rgb)>>16,
00036 (0x0000FF00 & rgb)>>8,
00037 (0x000000FF & rgb), 0
00038 };
00039 return to_return;
00040 }
00041
00042 Uint32 color_to_int(const SDL_Color& color) {
00043 Uint32 to_return = color.r;
00044 to_return = (to_return << 8) & color.g;
00045 to_return = (to_return << 8) & color.b;
00046 return to_return;
00047 }
00048
00049 SDLKey sdl_keysym_from_name(std::string const &keyname)
00050 {
00051 static bool initialized = false;
00052 typedef std::map<std::string const, SDLKey> keysym_map_t;
00053 static keysym_map_t keysym_map;
00054
00055 if (!initialized) {
00056 for(SDLKey i = SDLK_FIRST; i < SDLK_LAST; i = SDLKey(int(i) + 1)) {
00057 std::string name = SDL_GetKeyName(i);
00058 if (!name.empty())
00059 keysym_map[name] = i;
00060 }
00061 initialized = true;
00062 }
00063
00064 keysym_map_t::const_iterator it = keysym_map.find(keyname);
00065 if (it != keysym_map.end())
00066 return it->second;
00067 else
00068 return SDLK_UNKNOWN;
00069 }
00070
00071 bool point_in_rect(int x, int y, const SDL_Rect& rect)
00072 {
00073 return x >= rect.x && y >= rect.y && x < rect.x + rect.w && y < rect.y + rect.h;
00074 }
00075
00076 bool rects_overlap(const SDL_Rect& rect1, const SDL_Rect& rect2)
00077 {
00078 return (rect1.x < rect2.x+rect2.w && rect2.x < rect1.x+rect1.w &&
00079 rect1.y < rect2.y+rect2.h && rect2.y < rect1.y+rect1.h);
00080 }
00081
00082 SDL_Rect intersect_rects(SDL_Rect const &rect1, SDL_Rect const &rect2)
00083 {
00084 SDL_Rect res;
00085 res.x = maximum<int>(rect1.x, rect2.x);
00086 res.y = maximum<int>(rect1.y, rect2.y);
00087 res.w = maximum<int>(minimum<int>(rect1.x + rect1.w, rect2.x + rect2.w) - res.x, 0);
00088 res.h = maximum<int>(minimum<int>(rect1.y + rect1.h, rect2.y + rect2.h) - res.y, 0);
00089 return res;
00090 }
00091
00092
00093
00094
00095 SDL_Rect create_rect(const int x, const int y, const int w, const int h)
00096 {
00097 SDL_Rect rect = { x, y, w, h };
00098 return rect;
00099 }
00100
00101 bool operator<(const surface& a, const surface& b)
00102 {
00103 return a.get() < b.get();
00104 }
00105
00106 static SDL_PixelFormat& get_neutral_pixel_format()
00107 {
00108 static bool first_time = true;
00109 static SDL_PixelFormat format;
00110
00111 if(first_time) {
00112 first_time = false;
00113 surface surf(SDL_CreateRGBSurface(SDL_SWSURFACE,1,1,32,0xFF0000,0xFF00,0xFF,0xFF000000));
00114 format = *surf->format;
00115 format.palette = NULL;
00116 }
00117
00118 return format;
00119 }
00120
00121 surface make_neutral_surface(surface const &surf)
00122 {
00123 if(surf == NULL) {
00124 std::cerr << "null neutral surface...\n";
00125 return NULL;
00126 }
00127
00128 surface const result = SDL_ConvertSurface(surf,&get_neutral_pixel_format(),SDL_SWSURFACE);
00129 if(result != NULL) {
00130 SDL_SetAlpha(result,SDL_SRCALPHA,SDL_ALPHA_OPAQUE);
00131 }
00132
00133 return result;
00134 }
00135
00136
00137 surface create_optimized_surface(surface const &surf)
00138 {
00139 if(surf == NULL)
00140 return NULL;
00141
00142 surface const result = display_format_alpha(surf);
00143 if(result == surf) {
00144 std::cerr << "resulting surface is the same as the source!!!\n";
00145 } else if(result == NULL) {
00146 return surf;
00147 }
00148
00149 SDL_SetAlpha(result,SDL_SRCALPHA|SDL_RLEACCEL,SDL_ALPHA_OPAQUE);
00150
00151 return result;
00152 }
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168 surface stretch_surface_horizontal(
00169 const surface& surf, const unsigned w, const bool optimize)
00170 {
00171
00172 assert(SDL_ALPHA_TRANSPARENT==0);
00173
00174 if(surf == NULL)
00175 return NULL;
00176
00177 if(w == surf->w) {
00178 return surf;
00179 }
00180 assert(w > 0);
00181
00182 surface dst(SDL_CreateRGBSurface(SDL_SWSURFACE,
00183 w, surf->h, 32, 0xFF0000, 0xFF00, 0xFF, 0xFF000000));
00184
00185 surface src(make_neutral_surface(surf));
00186
00187
00188 if(src == NULL || dst == NULL) {
00189 std::cerr << "Could not create surface to scale onto\n";
00190 return NULL;
00191 }
00192
00193 {
00194
00195 surface_lock src_lock(src);
00196 surface_lock dst_lock(dst);
00197
00198 Uint32* const src_pixels = reinterpret_cast<Uint32*>(src_lock.pixels());
00199 Uint32* dst_pixels = reinterpret_cast<Uint32*>(dst_lock.pixels());
00200
00201 for(unsigned y = 0; y < src->h; ++y) {
00202 const Uint32 pixel = src_pixels [y * src->w];
00203 for(unsigned x = 0; x < w; ++x) {
00204
00205 *dst_pixels++ = pixel;
00206
00207 }
00208 }
00209 }
00210
00211 return optimize ? create_optimized_surface(dst) : dst;
00212 }
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228 surface stretch_surface_vertical(
00229 const surface& surf, const unsigned h, const bool optimize)
00230 {
00231
00232 assert(SDL_ALPHA_TRANSPARENT==0);
00233
00234 if(surf == NULL)
00235 return NULL;
00236
00237 if(h == surf->h) {
00238 return surf;
00239 }
00240 assert(h > 0);
00241
00242 surface dst(SDL_CreateRGBSurface(SDL_SWSURFACE,
00243 surf->w, h, 32, 0xFF0000, 0xFF00, 0xFF, 0xFF000000));
00244
00245 surface src(make_neutral_surface(surf));
00246
00247
00248 if(src == NULL || dst == NULL) {
00249 std::cerr << "Could not create surface to scale onto\n";
00250 return NULL;
00251 }
00252
00253 {
00254
00255 surface_lock src_lock(src);
00256 surface_lock dst_lock(dst);
00257
00258 Uint32* const src_pixels = reinterpret_cast<Uint32*>(src_lock.pixels());
00259 Uint32* dst_pixels = reinterpret_cast<Uint32*>(dst_lock.pixels());
00260
00261 for(unsigned y = 0; y < h; ++y) {
00262 for(unsigned x = 0; x < src->w; ++x) {
00263
00264 *dst_pixels++ = src_pixels[x];
00265 }
00266 }
00267 }
00268
00269 return optimize ? create_optimized_surface(dst) : dst;
00270 }
00271
00272
00273 surface scale_surface(surface const &surf, int w, int h, bool optimize)
00274 {
00275
00276 assert(SDL_ALPHA_TRANSPARENT==0);
00277
00278 if(surf == NULL)
00279 return NULL;
00280
00281 if(w == surf->w && h == surf->h) {
00282 return surf;
00283 }
00284 assert(w >= 0);
00285 assert(h >= 0);
00286
00287 surface dst(SDL_CreateRGBSurface(SDL_SWSURFACE,w,h,32,0xFF0000,0xFF00,0xFF,0xFF000000));
00288
00289 if (w == 0 || h ==0) {
00290 std::cerr << "Create an empty image\n";
00291 return create_optimized_surface(dst);
00292 }
00293
00294 surface src(make_neutral_surface(surf));
00295
00296
00297 if(src == NULL || dst == NULL) {
00298 std::cerr << "Could not create surface to scale onto\n";
00299 return NULL;
00300 }
00301
00302 const fixed_t xratio = fxpdiv(surf->w,w);
00303 const fixed_t yratio = fxpdiv(surf->h,h);
00304
00305 {
00306 surface_lock src_lock(src);
00307 surface_lock dst_lock(dst);
00308
00309 Uint32* const src_pixels = reinterpret_cast<Uint32*>(src_lock.pixels());
00310 Uint32* const dst_pixels = reinterpret_cast<Uint32*>(dst_lock.pixels());
00311
00312 fixed_t ysrc = ftofxp(0.0);
00313 for(int ydst = 0; ydst != h; ++ydst, ysrc += yratio) {
00314 fixed_t xsrc = ftofxp(0.0);
00315 for(int xdst = 0; xdst != w; ++xdst, xsrc += xratio) {
00316 const int xsrcint = fxptoi(xsrc);
00317 const int ysrcint = fxptoi(ysrc);
00318
00319 Uint32* const src_word = src_pixels + ysrcint*src->w + xsrcint;
00320 Uint32* const dst_word = dst_pixels + ydst*dst->w + xdst;
00321 const int dx = (xsrcint + 1 < src->w) ? 1 : 0;
00322 const int dy = (ysrcint + 1 < src->h) ? src->w : 0;
00323
00324 Uint8 r,g,b,a;
00325 Uint32 rr,gg,bb,aa;
00326 Uint16 avg_r, avg_g, avg_b, avg_a;
00327 Uint32 pix[4], bilin[4];
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341 const fixed_t e = 0x000000FF & xsrc;
00342 const fixed_t s = 0x000000FF & ysrc;
00343 const fixed_t n = 0xFF - s;
00344 const fixed_t w = 0xFF - e;
00345
00346 pix[0] = *src_word;
00347 pix[1] = *(src_word + dx);
00348 pix[2] = *(src_word + dy);
00349 pix[3] = *(src_word + dx + dy);
00350
00351 bilin[0] = n*w;
00352 bilin[1] = n*e;
00353 bilin[2] = s*w;
00354 bilin[3] = s*e;
00355
00356
00357
00358
00359 int count = 0;
00360 avg_r = avg_g = avg_b = avg_a = 0;
00361 int loc;
00362 for (loc=0; loc<4; loc++) {
00363 a = pix[loc] >> 24;
00364 r = pix[loc] >> 16;
00365 g = pix[loc] >> 8;
00366 b = pix[loc] >> 0;
00367 if (a != 0) {
00368 avg_r += r;
00369 avg_g += g;
00370 avg_b += b;
00371 avg_a += a;
00372 count++;
00373 }
00374 }
00375 if (count>0) {
00376 avg_r /= count;
00377 avg_b /= count;
00378 avg_g /= count;
00379 avg_a /= count;
00380 }
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404 rr = gg = bb = aa = 0;
00405 for (loc=0; loc<4; loc++) {
00406 a = pix[loc] >> 24;
00407 r = pix[loc] >> 16;
00408 g = pix[loc] >> 8;
00409 b = pix[loc] >> 0;
00410 if (a == 0) {
00411 r = avg_r;
00412 g = avg_g;
00413 b = avg_b;
00414 }
00415 rr += r * bilin[loc];
00416 gg += g * bilin[loc];
00417 bb += b * bilin[loc];
00418 aa += a * bilin[loc];
00419 }
00420 r = rr >> 16;
00421 g = gg >> 16;
00422 b = bb >> 16;
00423 a = aa >> 16;
00424 a = (a < avg_a/2) ? 0 : avg_a;
00425 *dst_word = (a << 24) + (r << 16) + (g << 8) + b;
00426 }
00427 }
00428 }
00429
00430 return optimize ? create_optimized_surface(dst) : dst;
00431 }
00432
00433 surface scale_surface_blended(surface const &surf, int w, int h, bool optimize)
00434 {
00435 if(surf== NULL)
00436 return NULL;
00437
00438 if(w == surf->w && h == surf->h) {
00439 return surf;
00440 }
00441 assert(w >= 0);
00442 assert(h >= 0);
00443
00444 surface dst(SDL_CreateRGBSurface(SDL_SWSURFACE,w,h,32,0xFF0000,0xFF00,0xFF,0xFF000000));
00445
00446 if (w == 0 || h ==0) {
00447 std::cerr << "Create an empty image\n";
00448 return create_optimized_surface(dst);
00449 }
00450
00451 surface src(make_neutral_surface(surf));
00452
00453 if(src == NULL || dst == NULL) {
00454 std::cerr << "Could not create surface to scale onto\n";
00455 return NULL;
00456 }
00457
00458 const double xratio = static_cast<double>(surf->w)/
00459 static_cast<double>(w);
00460 const double yratio = static_cast<double>(surf->h)/
00461 static_cast<double>(h);
00462
00463 {
00464 surface_lock src_lock(src);
00465 surface_lock dst_lock(dst);
00466
00467 Uint32* const src_pixels = reinterpret_cast<Uint32*>(src_lock.pixels());
00468 Uint32* const dst_pixels = reinterpret_cast<Uint32*>(dst_lock.pixels());
00469
00470 double ysrc = 0.0;
00471 for(int ydst = 0; ydst != h; ++ydst, ysrc += yratio) {
00472 double xsrc = 0.0;
00473 for(int xdst = 0; xdst != w; ++xdst, xsrc += xratio) {
00474 double red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0;
00475
00476 double summation = 0.0;
00477
00478
00479
00480 for(double xloc = xsrc; xloc < xsrc+xratio; xloc += 1.0) {
00481 const double xsize = minimum<double>(std::floor(xloc+1.0)-xloc,xsrc+xratio-xloc);
00482 for(double yloc = ysrc; yloc < ysrc+yratio; yloc += 1.0) {
00483 const int xsrcint = maximum<int>(0,minimum<int>(src->w-1,static_cast<int>(xsrc)));
00484 const int ysrcint = maximum<int>(0,minimum<int>(src->h-1,static_cast<int>(ysrc)));
00485
00486 const double ysize = minimum<double>(std::floor(yloc+1.0)-yloc,ysrc+yratio-yloc);
00487
00488 Uint8 r,g,b,a;
00489
00490 SDL_GetRGBA(src_pixels[ysrcint*src->w + xsrcint],src->format,&r,&g,&b,&a);
00491 const double value = xsize*ysize*double(a)/255.0;
00492 summation += value;
00493
00494 red += r*value;
00495 green += g*value;
00496 blue += b*value;
00497 alpha += a*value;
00498 }
00499 }
00500
00501 if(summation == 0.0)
00502 summation = 1.0;
00503
00504 red /= summation;
00505 green /= summation;
00506 blue /= summation;
00507 alpha /= summation;
00508
00509 dst_pixels[ydst*dst->w + xdst] = SDL_MapRGBA(dst->format,Uint8(red),Uint8(green),Uint8(blue),Uint8(alpha));
00510 }
00511 }
00512 }
00513
00514 return optimize ? create_optimized_surface(dst) : dst;
00515 }
00516
00517 surface adjust_surface_colour(surface const &surf, int red, int green, int blue, bool optimize)
00518 {
00519 if((red == 0 && green == 0 && blue == 0) || surf == NULL)
00520 return create_optimized_surface(surf);
00521
00522 surface nsurf(make_neutral_surface(surf));
00523
00524 if(nsurf == NULL) {
00525 std::cerr << "failed to make neutral surface\n";
00526 return NULL;
00527 }
00528
00529 {
00530 surface_lock lock(nsurf);
00531 Uint32* beg = lock.pixels();
00532 Uint32* end = beg + nsurf->w*surf->h;
00533
00534 while(beg != end) {
00535 Uint8 alpha = (*beg) >> 24;
00536
00537 if(alpha) {
00538 Uint8 r, g, b;
00539 r = (*beg) >> 16;
00540 g = (*beg) >> 8;
00541 b = (*beg) >> 0;
00542
00543 r = maximum<int>(0,minimum<int>(255,int(r)+red));
00544 g = maximum<int>(0,minimum<int>(255,int(g)+green));
00545 b = maximum<int>(0,minimum<int>(255,int(b)+blue));
00546
00547 *beg = (alpha << 24) + (r << 16) + (g << 8) + b;
00548 }
00549
00550 ++beg;
00551 }
00552 }
00553
00554 return optimize ? create_optimized_surface(nsurf) : nsurf;
00555 }
00556
00557 surface greyscale_image(surface const &surf, bool optimize)
00558 {
00559 if(surf == NULL)
00560 return NULL;
00561
00562 surface nsurf(make_neutral_surface(surf));
00563 if(nsurf == NULL) {
00564 std::cerr << "failed to make neutral surface\n";
00565 return NULL;
00566 }
00567
00568 {
00569 surface_lock lock(nsurf);
00570 Uint32* beg = lock.pixels();
00571 Uint32* end = beg + nsurf->w*surf->h;
00572
00573 while(beg != end) {
00574 Uint8 alpha = (*beg) >> 24;
00575
00576 if(alpha) {
00577 Uint8 r, g, b;
00578 r = (*beg) >> 16;
00579 g = (*beg) >> 8;
00580 b = (*beg);
00581
00582
00583
00584
00585
00586
00587 const Uint8 avg = static_cast<Uint8>((
00588 77 * static_cast<Uint16>(r) +
00589 150 * static_cast<Uint16>(g) +
00590 29 * static_cast<Uint16>(b) ) / 256);
00591
00592 *beg = (alpha << 24) | (avg << 16) | (avg << 8) | avg;
00593 }
00594
00595 ++beg;
00596 }
00597 }
00598
00599 return optimize ? create_optimized_surface(nsurf) : nsurf;
00600 }
00601
00602 surface darken_image(surface const &surf, bool optimize)
00603 {
00604 if(surf == NULL)
00605 return NULL;
00606
00607 surface nsurf(make_neutral_surface(surf));
00608 if(nsurf == NULL) {
00609 std::cerr << "failed to make neutral surface\n";
00610 return NULL;
00611 }
00612
00613 {
00614 surface_lock lock(nsurf);
00615 Uint32* beg = lock.pixels();
00616 Uint32* end = beg + nsurf->w*surf->h;
00617
00618 while(beg != end) {
00619 Uint8 alpha = (*beg) >> 24;
00620
00621 if(alpha) {
00622 Uint8 r, g, b;
00623 r = (*beg) >> 16;
00624 g = (*beg) >> 8;
00625 b = (*beg);
00626
00627
00628
00629
00630
00631
00632
00633 const Uint8 avg = static_cast<Uint8>((
00634 77 * static_cast<Uint16>(r) +
00635 150 * static_cast<Uint16>(g) +
00636 29 * static_cast<Uint16>(b) ) / 256);
00637
00638 r = ((avg * 196) >> 8);
00639 g = ((avg * 171) >> 8);
00640 b = ((avg * 184) >> 8);
00641
00642 *beg = (alpha << 24) | (r << 16) | (g << 8) | b;
00643 }
00644
00645 ++beg;
00646 }
00647 }
00648
00649 return optimize ? create_optimized_surface(nsurf) : nsurf;
00650 }
00651
00652 surface recolor_image(surface surf, const std::map<Uint32, Uint32>& map_rgb, bool optimize){
00653 if(map_rgb.size()){
00654 if(surf == NULL)
00655 return NULL;
00656
00657 surface nsurf(make_neutral_surface(surf));
00658 if(nsurf == NULL) {
00659 std::cerr << "failed to make neutral surface\n";
00660 return NULL;
00661 }
00662
00663 surface_lock lock(nsurf);
00664 Uint32* beg = lock.pixels();
00665 Uint32* end = beg + nsurf->w*surf->h;
00666
00667 std::map<Uint32, Uint32>::const_iterator map_rgb_end = map_rgb.end();
00668
00669 while(beg != end) {
00670 Uint8 alpha = (*beg) >> 24;
00671
00672 if(alpha){
00673
00674 Uint32 oldrgb = (*beg) & 0x00FFFFFF;
00675 std::map<Uint32, Uint32>::const_iterator i = map_rgb.find(oldrgb);
00676 if(i != map_rgb.end()){
00677 *beg = (alpha << 24) + i->second;
00678 }
00679 }
00680 ++beg;
00681 }
00682
00683 return optimize ? create_optimized_surface(nsurf) : nsurf;
00684 }
00685 return surf;
00686 }
00687
00688 surface brighten_image(surface const &surf, fixed_t amount, bool optimize)
00689 {
00690 if(surf == NULL) {
00691 return NULL;
00692 }
00693
00694 surface nsurf(make_neutral_surface(surf));
00695
00696 if(nsurf == NULL) {
00697 std::cerr << "could not make neutral surface...\n";
00698 return NULL;
00699 }
00700
00701 {
00702 surface_lock lock(nsurf);
00703 Uint32* beg = lock.pixels();
00704 Uint32* end = beg + nsurf->w*surf->h;
00705
00706 if (amount < 0) amount = 0;
00707 while(beg != end) {
00708 Uint8 alpha = (*beg) >> 24;
00709
00710 if(alpha) {
00711 Uint8 r, g, b;
00712 r = (*beg) >> 16;
00713 g = (*beg) >> 8;
00714 b = (*beg);
00715
00716 r = minimum<unsigned>(unsigned(fxpmult(r, amount)),255);
00717 g = minimum<unsigned>(unsigned(fxpmult(g, amount)),255);
00718 b = minimum<unsigned>(unsigned(fxpmult(b, amount)),255);
00719
00720 *beg = (alpha << 24) + (r << 16) + (g << 8) + b;
00721 }
00722
00723 ++beg;
00724 }
00725 }
00726
00727 return optimize ? create_optimized_surface(nsurf) : nsurf;
00728 }
00729
00730 surface adjust_surface_alpha(surface const &surf, fixed_t amount, bool optimize)
00731 {
00732 if(surf== NULL) {
00733 return NULL;
00734 }
00735
00736 surface nsurf(make_neutral_surface(surf));
00737
00738 if(nsurf == NULL) {
00739 std::cerr << "could not make neutral surface...\n";
00740 return NULL;
00741 }
00742
00743 {
00744 surface_lock lock(nsurf);
00745 Uint32* beg = lock.pixels();
00746 Uint32* end = beg + nsurf->w*surf->h;
00747
00748 if (amount < 0) amount = 0;
00749 while(beg != end) {
00750 Uint8 alpha = (*beg) >> 24;
00751
00752 if(alpha) {
00753 Uint8 r, g, b;
00754 r = (*beg) >> 16;
00755 g = (*beg) >> 8;
00756 b = (*beg);
00757
00758 alpha = minimum<unsigned>(unsigned(fxpmult(alpha,amount)),255);
00759 *beg = (alpha << 24) + (r << 16) + (g << 8) + b;
00760 }
00761
00762 ++beg;
00763 }
00764 }
00765
00766 return optimize ? create_optimized_surface(nsurf) : nsurf;
00767 }
00768
00769 surface adjust_surface_alpha_add(surface const &surf, int amount, bool optimize)
00770 {
00771 if(surf== NULL) {
00772 return NULL;
00773 }
00774
00775 surface nsurf(make_neutral_surface(surf));
00776
00777 if(nsurf == NULL) {
00778 std::cerr << "could not make neutral surface...\n";
00779 return NULL;
00780 }
00781
00782 {
00783 surface_lock lock(nsurf);
00784 Uint32* beg = lock.pixels();
00785 Uint32* end = beg + nsurf->w*surf->h;
00786
00787 while(beg != end) {
00788 Uint8 alpha = (*beg) >> 24;
00789
00790 if(alpha) {
00791 Uint8 r, g, b;
00792 r = (*beg) >> 16;
00793 g = (*beg) >> 8;
00794 b = (*beg);
00795
00796 alpha = Uint8(maximum<int>(0,minimum<int>(255,int(alpha) + amount)));
00797 *beg = (alpha << 24) + (r << 16) + (g << 8) + b;
00798 }
00799
00800 ++beg;
00801 }
00802 }
00803
00804 return optimize ? create_optimized_surface(nsurf) : nsurf;
00805 }
00806
00807
00808 surface mask_surface(surface const &surf, surface const &mask)
00809 {
00810 if(surf == NULL) {
00811 return NULL;
00812 }
00813
00814 surface nsurf = make_neutral_surface(surf);
00815 surface nmask(make_neutral_surface(mask));
00816
00817 if(nsurf == NULL || nmask == NULL) {
00818 std::cerr << "could not make neutral surface...\n";
00819 return NULL;
00820 }
00821 if (nsurf->w != nmask->w) {
00822
00823
00824
00825
00826 std::cerr << "Detected an image with bad dimensions :" << nsurf->w << "x" << nsurf->h << "\n";
00827 std::cerr << "It will not be masked, please use :"<< nmask->w << "x" << nmask->h << "\n";
00828 return nsurf;
00829 }
00830
00831 {
00832 surface_lock lock(nsurf);
00833 surface_lock mlock(nmask);
00834
00835 Uint32* beg = lock.pixels();
00836 Uint32* end = beg + nsurf->w*surf->h;
00837 Uint32* mbeg = mlock.pixels();
00838 Uint32* mend = mbeg + nmask->w*nmask->h;
00839
00840 while(beg != end && mbeg != mend) {
00841 Uint8 alpha = (*beg) >> 24;
00842
00843 if(alpha) {
00844 Uint8 r, g, b;
00845 r = (*beg) >> 16;
00846 g = (*beg) >> 8;
00847 b = (*beg);
00848
00849 Uint8 malpha = (*mbeg) >> 24;
00850 if (alpha > malpha) alpha = malpha;
00851
00852 *beg = (alpha << 24) + (r << 16) + (g << 8) + b;
00853 }
00854
00855 ++beg;
00856 ++mbeg;
00857 }
00858 }
00859
00860 return nsurf;
00861
00862 }
00863
00864
00865 surface blur_surface(surface const &surf, int depth, bool optimize)
00866 {
00867 if(surf == NULL) {
00868 return NULL;
00869 }
00870
00871 surface res = make_neutral_surface(surf);
00872
00873 if(res == NULL) {
00874 std::cerr << "could not make neutral surface...\n";
00875 return NULL;
00876 }
00877
00878 const int max_blur = 256;
00879 if(depth > max_blur) {
00880 depth = max_blur;
00881 }
00882
00883 Uint32 queue[max_blur];
00884 const Uint32* end_queue = queue + max_blur;
00885
00886 const Uint32 ff = 0xff;
00887
00888 surface_lock lock(res);
00889 int x, y;
00890 for(y = 0; y < res->h; ++y) {
00891 const Uint32* front = &queue[0];
00892 Uint32* back = &queue[0];
00893 Uint32 red = 0, green = 0, blue = 0, avg = 0;
00894 Uint32* p = lock.pixels() + y*res->w;
00895 for(x = 0; x <= depth && x < res->w; ++x, ++p) {
00896 red += ((*p) >> 16)&0xFF;
00897 green += ((*p) >> 8)&0xFF;
00898 blue += (*p)&0xFF;
00899 ++avg;
00900 *back++ = *p;
00901 if(back == end_queue) {
00902 back = &queue[0];
00903 }
00904 }
00905
00906 p = lock.pixels() + y*res->w;
00907 for(x = 0; x < res->w; ++x, ++p) {
00908 *p = 0xFF000000 | (minimum(red/avg,ff) << 16) | (minimum(green/avg,ff) << 8) | minimum(blue/avg,ff);
00909 if(x >= depth) {
00910 red -= ((*front) >> 16)&0xFF;
00911 green -= ((*front) >> 8)&0xFF;
00912 blue -= *front&0xFF;
00913 --avg;
00914 ++front;
00915 if(front == end_queue) {
00916 front = &queue[0];
00917 }
00918 }
00919
00920 if(x + depth+1 < res->w) {
00921 Uint32* q = p + depth+1;
00922 red += ((*q) >> 16)&0xFF;
00923 green += ((*q) >> 8)&0xFF;
00924 blue += (*q)&0xFF;
00925 ++avg;
00926 *back++ = *q;
00927 if(back == end_queue) {
00928 back = &queue[0];
00929 }
00930 }
00931 }
00932 }
00933
00934 for(x = 0; x < res->w; ++x) {
00935 const Uint32* front = &queue[0];
00936 Uint32* back = &queue[0];
00937 Uint32 red = 0, green = 0, blue = 0, avg = 0;
00938 Uint32* p = lock.pixels() + x;
00939 for(y = 0; y <= depth && y < res->h; ++y, p += res->w) {
00940 red += ((*p) >> 16)&0xFF;
00941 green += ((*p) >> 8)&0xFF;
00942 blue += *p&0xFF;
00943 ++avg;
00944 *back++ = *p;
00945 if(back == end_queue) {
00946 back = &queue[0];
00947 }
00948 }
00949
00950 p = lock.pixels() + x;
00951 for(y = 0; y < res->h; ++y, p += res->w) {
00952 *p = 0xFF000000 | (minimum(red/avg,ff) << 16) | (minimum(green/avg,ff) << 8) | minimum(blue/avg,ff);
00953 if(y >= depth) {
00954 red -= ((*front) >> 16)&0xFF;
00955 green -= ((*front) >> 8)&0xFF;
00956 blue -= *front&0xFF;
00957 --avg;
00958 ++front;
00959 if(front == end_queue) {
00960 front = &queue[0];
00961 }
00962 }
00963
00964 if(y + depth+1 < res->h) {
00965 Uint32* q = p + (depth+1)*res->w;
00966 red += ((*q) >> 16)&0xFF;
00967 green += ((*q) >> 8)&0xFF;
00968 blue += (*q)&0xFF;
00969 ++avg;
00970 *back++ = *q;
00971 if(back == end_queue) {
00972 back = &queue[0];
00973 }
00974 }
00975 }
00976 }
00977
00978 return optimize ? create_optimized_surface(res) : res;
00979 }
00980
00981
00982
00983
00984 surface blur_alpha_surface(surface const &surf, int depth, bool optimize)
00985 {
00986 if(surf == NULL) {
00987 return NULL;
00988 }
00989
00990 surface res = make_neutral_surface(surf);
00991
00992 if(res == NULL) {
00993 std::cerr << "could not make neutral surface...\n";
00994 return NULL;
00995 }
00996
00997 const int max_blur = 256;
00998 if(depth > max_blur) {
00999 depth = max_blur;
01000 }
01001
01002 Uint32 queue[max_blur];
01003 const Uint32* end_queue = queue + max_blur;
01004
01005 const Uint32 ff = 0xff;
01006
01007 surface_lock lock(res);
01008 int x, y;
01009 for(y = 0; y < res->h; ++y) {
01010 const Uint32* front = &queue[0];
01011 Uint32* back = &queue[0];
01012 Uint32 alpha=0, red = 0, green = 0, blue = 0, avg = 0;
01013 Uint32* p = lock.pixels() + y*res->w;
01014 for(x = 0; x <= depth && x < res->w; ++x, ++p) {
01015 alpha += ((*p) >> 24)&0xFF;
01016 red += ((*p) >> 16)&0xFF;
01017 green += ((*p) >> 8)&0xFF;
01018 blue += (*p)&0xFF;
01019 ++avg;
01020 *back++ = *p;
01021 if(back == end_queue) {
01022 back = &queue[0];
01023 }
01024 }
01025
01026 p = lock.pixels() + y*res->w;
01027 for(x = 0; x < res->w; ++x, ++p) {
01028 *p = (minimum(alpha/avg,ff) << 24) | (minimum(red/avg,ff) << 16) | (minimum(green/avg,ff) << 8) | minimum(blue/avg,ff);
01029 if(x >= depth) {
01030 alpha -= ((*front) >> 24)&0xFF;
01031 red -= ((*front) >> 16)&0xFF;
01032 green -= ((*front) >> 8)&0xFF;
01033 blue -= *front&0xFF;
01034 --avg;
01035 ++front;
01036 if(front == end_queue) {
01037 front = &queue[0];
01038 }
01039 }
01040
01041 if(x + depth+1 < res->w) {
01042 Uint32* q = p + depth+1;
01043 alpha += ((*q) >> 24)&0xFF;
01044 red += ((*q) >> 16)&0xFF;
01045 green += ((*q) >> 8)&0xFF;
01046 blue += (*q)&0xFF;
01047 ++avg;
01048 *back++ = *q;
01049 if(back == end_queue) {
01050 back = &queue[0];
01051 }
01052 }
01053 }
01054 }
01055
01056 for(x = 0; x < res->w; ++x) {
01057 const Uint32* front = &queue[0];
01058 Uint32* back = &queue[0];
01059 Uint32 alpha=0, red = 0, green = 0, blue = 0, avg = 0;
01060 Uint32* p = lock.pixels() + x;
01061 for(y = 0; y <= depth && y < res->h; ++y, p += res->w) {
01062 alpha += ((*p) >> 24)&0xFF;
01063 red += ((*p) >> 16)&0xFF;
01064 green += ((*p) >> 8)&0xFF;
01065 blue += *p&0xFF;
01066 ++avg;
01067 *back++ = *p;
01068 if(back == end_queue) {
01069 back = &queue[0];
01070 }
01071 }
01072
01073 p = lock.pixels() + x;
01074 for(y = 0; y < res->h; ++y, p += res->w) {
01075 *p = (minimum(alpha/avg,ff) << 24) | (minimum(red/avg,ff) << 16) | (minimum(green/avg,ff) << 8) | minimum(blue/avg,ff);
01076 if(y >= depth) {
01077 alpha -= ((*front) >> 24)&0xFF;
01078 red -= ((*front) >> 16)&0xFF;
01079 green -= ((*front) >> 8)&0xFF;
01080 blue -= *front&0xFF;
01081 --avg;
01082 ++front;
01083 if(front == end_queue) {
01084 front = &queue[0];
01085 }
01086 }
01087
01088 if(y + depth+1 < res->h) {
01089 Uint32* q = p + (depth+1)*res->w;
01090 alpha += ((*q) >> 24)&0xFF;
01091 red += ((*q) >> 16)&0xFF;
01092 green += ((*q) >> 8)&0xFF;
01093 blue += (*q)&0xFF;
01094 ++avg;
01095 *back++ = *q;
01096 if(back == end_queue) {
01097 back = &queue[0];
01098 }
01099 }
01100 }
01101 }
01102
01103 return optimize ? create_optimized_surface(res) : res;
01104 }
01105
01106
01107 surface cut_surface(surface const &surf, SDL_Rect const &r)
01108 {
01109 surface res = create_compatible_surface(surf, r.w, r.h);
01110
01111 size_t sbpp = surf->format->BytesPerPixel;
01112 size_t spitch = surf->pitch;
01113 size_t rbpp = res->format->BytesPerPixel;
01114 size_t rpitch = res->pitch;
01115
01116
01117 SDL_Rect src_rect = r;
01118 SDL_Rect dst_rect = { 0, 0, r.w, r.h };
01119
01120 if (src_rect.x < 0) {
01121 if (src_rect.x + src_rect.w <= 0)
01122 return res;
01123 dst_rect.x -= src_rect.x;
01124 dst_rect.w += src_rect.x;
01125 src_rect.w += src_rect.x;
01126 src_rect.x = 0;
01127 }
01128 if (src_rect.y < 0) {
01129 if (src_rect.y + src_rect.h <= 0)
01130 return res;
01131 dst_rect.y -= src_rect.y;
01132 dst_rect.h += src_rect.y;
01133 src_rect.h += src_rect.y;
01134 src_rect.y = 0;
01135 }
01136
01137 if(src_rect.x >= surf->w || src_rect.y >= surf->h)
01138 return res;
01139
01140 surface_lock slock(surf);
01141 surface_lock rlock(res);
01142
01143 Uint8* src = reinterpret_cast<Uint8 *>(slock.pixels());
01144 Uint8* dest = reinterpret_cast<Uint8 *>(rlock.pixels());
01145
01146 for(int y = 0; y < src_rect.h && (src_rect.y + y) < surf->h; ++y) {
01147 Uint8* line_src = src + (src_rect.y + y) * spitch + src_rect.x * sbpp;
01148 Uint8* line_dest = dest + (dst_rect.y + y) * rpitch + dst_rect.x * rbpp;
01149 size_t size = src_rect.w + src_rect.x <= surf->w ? src_rect.w : surf->w - src_rect.x;
01150
01151 assert(rpitch >= src_rect.w * rbpp);
01152 memcpy(line_dest, line_src, size * rbpp);
01153 }
01154
01155 return res;
01156 }
01157
01158 surface blend_surface(surface const &surf, double amount, Uint32 colour, bool optimize)
01159 {
01160 if(surf== NULL) {
01161 return NULL;
01162 }
01163
01164 surface nsurf(make_neutral_surface(surf));
01165
01166 if(nsurf == NULL) {
01167 std::cerr << "could not make neutral surface...\n";
01168 return NULL;
01169 }
01170
01171 {
01172 surface_lock lock(nsurf);
01173 Uint32* beg = lock.pixels();
01174 Uint32* end = beg + nsurf->w*surf->h;
01175
01176 Uint8 red, green, blue, alpha;
01177 SDL_GetRGBA(colour,nsurf->format,&red,&green,&blue,&alpha);
01178
01179 red = Uint8(red * amount);
01180 green = Uint8(green * amount);
01181 blue = Uint8(blue * amount);
01182
01183 amount = 1.0 - amount;
01184
01185 while(beg != end) {
01186 Uint8 r, g, b, a;
01187 a = (*beg) >> 24;
01188 r = (*beg) >> 16;
01189 g = (*beg) >> 8;
01190 b = (*beg);
01191
01192 r = Uint8(r * amount) + red;
01193 g = Uint8(g * amount) + green;
01194 b = Uint8(b * amount) + blue;
01195
01196 *beg = (a << 24) | (r << 16) | (g << 8) | b;
01197
01198 ++beg;
01199 }
01200 }
01201
01202 return optimize ? create_optimized_surface(nsurf) : nsurf;
01203 }
01204
01205 surface flip_surface(surface const &surf, bool optimize)
01206 {
01207 if(surf == NULL) {
01208 return NULL;
01209 }
01210
01211 surface nsurf(make_neutral_surface(surf));
01212
01213 if(nsurf == NULL) {
01214 std::cerr << "could not make neutral surface...\n";
01215 return NULL;
01216 }
01217
01218 {
01219 surface_lock lock(nsurf);
01220 Uint32* const pixels = lock.pixels();
01221
01222 for(int y = 0; y != nsurf->h; ++y) {
01223 for(int x = 0; x != nsurf->w/2; ++x) {
01224 const int index1 = y*nsurf->w + x;
01225 const int index2 = (y+1)*nsurf->w - x - 1;
01226 std::swap(pixels[index1],pixels[index2]);
01227 }
01228 }
01229 }
01230
01231 return optimize ? create_optimized_surface(nsurf) : nsurf;
01232 }
01233
01234 surface flop_surface(surface const &surf, bool optimize)
01235 {
01236 if(surf == NULL) {
01237 return NULL;
01238 }
01239
01240 surface nsurf(make_neutral_surface(surf));
01241
01242 if(nsurf == NULL) {
01243 std::cerr << "could not make neutral surface...\n";
01244 return NULL;
01245 }
01246
01247 {
01248 surface_lock lock(nsurf);
01249 Uint32* const pixels = lock.pixels();
01250
01251 for(int x = 0; x != nsurf->w; ++x) {
01252 for(int y = 0; y != nsurf->h/2; ++y) {
01253 const int index1 = y*nsurf->w + x;
01254 const int index2 = (nsurf->h-y-1)*surf->w + x;
01255 std::swap(pixels[index1],pixels[index2]);
01256 }
01257 }
01258 }
01259
01260 return optimize ? create_optimized_surface(nsurf) : nsurf;
01261 }
01262
01263
01264 surface create_compatible_surface(surface const &surf, int width, int height)
01265 {
01266 if(surf == NULL)
01267 return NULL;
01268
01269 if(width == -1)
01270 width = surf->w;
01271
01272 if(height == -1)
01273 height = surf->h;
01274
01275 return SDL_CreateRGBSurface(SDL_SWSURFACE,width,height,surf->format->BitsPerPixel,
01276 surf->format->Rmask,surf->format->Gmask,surf->format->Bmask,surf->format->Amask);
01277 }
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291 void blit_surface(const surface& src,
01292 const SDL_Rect* srcrect, surface& dst, const SDL_Rect* dstrect)
01293 {
01294 assert(src);
01295 assert(dst);
01296 assert((src->flags & SDL_RLEACCEL) == 0);
01297 assert((dst->flags & SDL_RLEACCEL) == 0);
01298
01299
01300 SDL_Rect dst_rect = { 0, 0, dst->w, dst->h };
01301 if(dstrect) {
01302 dst_rect.x = dstrect->x;
01303 dst_rect.w -= dstrect->x;
01304
01305 dst_rect.y = dstrect->y;
01306 dst_rect.h -= dstrect->y;
01307
01308 }
01309
01310 SDL_Rect src_rect = { 0, 0, src->w, src->h };
01311 if(srcrect && srcrect->w && srcrect->h) {
01312 src_rect.x = srcrect->x;
01313 src_rect.y = srcrect->y;
01314
01315 src_rect.w = srcrect->w;
01316 src_rect.h = srcrect->h;
01317
01318 if (src_rect.x < 0) {
01319 if (src_rect.x + src_rect.w <= 0 || src_rect.x + dst_rect.w <= 0 )
01320 return;
01321 dst_rect.x -= src_rect.x;
01322 dst_rect.w += src_rect.x;
01323 src_rect.w += src_rect.x;
01324 src_rect.x = 0;
01325 }
01326 if (src_rect.y < 0) {
01327 if (src_rect.y + src_rect.h <= 0 || src_rect.y + dst_rect.h <= 0 )
01328 return;
01329 dst_rect.y -= src_rect.y;
01330 dst_rect.h += src_rect.y;
01331 src_rect.h += src_rect.y;
01332 src_rect.y = 0;
01333 }
01334 if (src_rect.x + src_rect.w > src->w) {
01335 if (src_rect.x >= src->w)
01336 return;
01337 src_rect.w = src->w - src_rect.x;
01338 }
01339 if (src_rect.y + src_rect.h > src->h) {
01340 if (src_rect.y >= src->h)
01341 return;
01342 src_rect.h = src->h - src_rect.y;
01343 }
01344 }
01345
01346 assert(dst_rect.x >= 0);
01347 assert(dst_rect.y >= 0);
01348
01349
01350 const unsigned width = minimum(src_rect.w, dst_rect.w);
01351 const unsigned height = minimum(src_rect.h, dst_rect.h);
01352
01353
01354
01355
01356
01357
01358
01359
01360 {
01361
01362 surface_lock src_lock(src);
01363 surface_lock dst_lock(dst);
01364
01365 Uint32* const src_pixels = reinterpret_cast<Uint32*>(src_lock.pixels());
01366 Uint32* dst_pixels = reinterpret_cast<Uint32*>(dst_lock.pixels());
01367
01368 for(unsigned y = 0; y < height; ++y) {
01369 for(unsigned x = 0; x < width; ++x) {
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379 const Uint32 src_pixel = src_pixels[(y + src_rect.y) * src->w + (x + src_rect.x)];
01380 const Uint8 src_a = (src_pixel & 0xFF000000) >> 24;
01381
01382 if(!src_a) {
01383
01384 continue;
01385 }
01386
01387 const ptrdiff_t dst_offset = (y + dst_rect.y) * dst->w + (x + dst_rect.x);
01388 if(src_a == 255) {
01389
01390 dst_pixels[dst_offset] = src_pixel;
01391 continue;
01392 }
01393
01394 const Uint32 dst_pixel = dst_pixels[dst_offset];
01395 Uint8 dst_a = (dst_pixel & 0xFF000000) >> 24;
01396
01397 if(!dst_a) {
01398
01399 dst_pixels[dst_offset] = src_pixel;
01400 continue;
01401 }
01402
01403 const Uint8 src_r = (src_pixel & 0x00FF0000) >> 16;
01404 const Uint8 src_g = (src_pixel & 0x0000FF00) >> 8;
01405 const Uint8 src_b = src_pixel & 0x000000FF;
01406
01407 Uint8 dst_r = (dst_pixel & 0x00FF0000) >> 16;
01408 Uint8 dst_g = (dst_pixel & 0x0000FF00) >> 8;
01409 Uint8 dst_b = dst_pixel & 0x000000FF;
01410
01411 if(dst_a == 255) {
01412
01413
01414 dst_r = (((src_r - dst_r) * src_a) >> 8 ) + dst_r;
01415 dst_g = (((src_g - dst_g) * src_a) >> 8 ) + dst_g;
01416 dst_b = (((src_b - dst_b) * src_a) >> 8 ) + dst_b;
01417
01418 } else {
01419
01420
01421
01422
01423 const unsigned tmp_a = 255 - src_a;
01424
01425 const unsigned tmp_r = 1 + (src_r * src_a) + (dst_r * tmp_a);
01426 dst_r = (tmp_r + (tmp_r >> 8)) >> 8;
01427
01428 const unsigned tmp_g = 1 + (src_g * src_a) + (dst_g * tmp_a);
01429 dst_g = (tmp_g + (tmp_g >> 8)) >> 8;
01430
01431 const unsigned tmp_b = 1 + (src_b * src_a) + (dst_b * tmp_a);
01432 dst_b = (tmp_b + (tmp_b >> 8)) >> 8;
01433
01434 dst_a += (((255 - dst_a) * src_a) >> 8);
01435 }
01436
01437 dst_pixels[dst_offset] = (dst_a << 24) | (dst_r << 16) | (dst_g << 8) | (dst_b);
01438
01439 }
01440 }
01441 }
01442 }
01443
01444
01445
01446 void fill_rect_alpha(SDL_Rect &rect, Uint32 colour, Uint8 alpha, surface const &target)
01447 {
01448 if(alpha == SDL_ALPHA_OPAQUE) {
01449 SDL_FillRect(target,&rect,colour);
01450 return;
01451 } else if(alpha == SDL_ALPHA_TRANSPARENT) {
01452 return;
01453 }
01454
01455 surface tmp(create_compatible_surface(target,rect.w,rect.h));
01456 if(tmp == NULL) {
01457 return;
01458 }
01459
01460 SDL_Rect r = {0,0,rect.w,rect.h};
01461 SDL_FillRect(tmp,&r,colour);
01462 SDL_SetAlpha(tmp,SDL_SRCALPHA,alpha);
01463 SDL_BlitSurface(tmp,NULL,target,&rect);
01464 }
01465
01466 surface get_surface_portion(surface const &src, SDL_Rect &area)
01467 {
01468
01469 if(area.x >= src->w || area.y >= src->h || area.x + area.w < 0 || area.y + area.h < 0) {
01470
01471 return NULL;
01472 }
01473
01474 if(area.x + area.w > src->w) {
01475 area.w = src->w - area.x;
01476 }
01477 if(area.y + area.h > src->h) {
01478 area.h = src->h - area.y;
01479 }
01480
01481 surface const dst = create_compatible_surface(src,area.w,area.h);
01482 if(dst == NULL) {
01483 std::cerr << "Could not create a new surface in get_surface_portion()\n";
01484 return NULL;
01485 }
01486
01487 SDL_BlitSurface(src,&area,dst, NULL);
01488
01489 return dst;
01490 }
01491
01492 namespace {
01493
01494 struct not_alpha
01495 {
01496 not_alpha() {}
01497
01498
01499 bool operator()(Uint32 pixel) const {
01500 Uint8 alpha = pixel >> 24;
01501 return alpha != 0x00;
01502 }
01503 };
01504
01505 }
01506
01507 SDL_Rect get_non_transparent_portion(surface const &surf)
01508 {
01509 SDL_Rect res = {0,0,0,0};
01510 const surface nsurf(make_neutral_surface(surf));
01511 if(nsurf == NULL) {
01512 std::cerr << "failed to make neutral surface\n";
01513 return res;
01514 }
01515
01516 const not_alpha calc;
01517
01518 surface_lock lock(nsurf);
01519 const Uint32* const pixels = lock.pixels();
01520
01521 int n;
01522 for(n = 0; n != nsurf->h; ++n) {
01523 const Uint32* const start_row = pixels + n*nsurf->w;
01524 const Uint32* const end_row = start_row + nsurf->w;
01525
01526 if(std::find_if(start_row,end_row,calc) != end_row)
01527 break;
01528 }
01529
01530 res.y = n;
01531
01532 for(n = 0; n != nsurf->h-res.y; ++n) {
01533 const Uint32* const start_row = pixels + (nsurf->h-n-1)*surf->w;
01534 const Uint32* const end_row = start_row + nsurf->w;
01535
01536 if(std::find_if(start_row,end_row,calc) != end_row)
01537 break;
01538 }
01539
01540
01541
01542
01543 res.h = nsurf->h - res.y - n;
01544
01545 for(n = 0; n != nsurf->w; ++n) {
01546 int y;
01547 for(y = 0; y != nsurf->h; ++y) {
01548 const Uint32 pixel = pixels[y*nsurf->w + n];
01549 if(calc(pixel))
01550 break;
01551 }
01552
01553 if(y != nsurf->h)
01554 break;
01555 }
01556
01557 res.x = n;
01558
01559 for(n = 0; n != nsurf->w-res.x; ++n) {
01560 int y;
01561 for(y = 0; y != nsurf->h; ++y) {
01562 const Uint32 pixel = pixels[y*nsurf->w + surf->w - n - 1];
01563 if(calc(pixel))
01564 break;
01565 }
01566
01567 if(y != nsurf->h)
01568 break;
01569 }
01570
01571 res.w = nsurf->w - res.x - n;
01572
01573 return res;
01574 }
01575
01576 bool operator==(const SDL_Rect& a, const SDL_Rect& b)
01577 {
01578 return a.x == b.x && a.y == b.y && a.w == b.w && a.h == b.h;
01579 }
01580
01581 bool operator!=(const SDL_Rect& a, const SDL_Rect& b)
01582 {
01583 return !operator==(a,b);
01584 }
01585
01586 bool operator==(const SDL_Color& a, const SDL_Color& b) {
01587 return a.r == b.r && a.g == b.g && a.b == b.b;
01588 }
01589
01590 bool operator!=(const SDL_Color& a, const SDL_Color& b) {
01591 return !operator==(a,b);
01592 }
01593
01594 SDL_Color inverse(const SDL_Color& colour) {
01595 SDL_Color inverse;
01596 inverse.r = 255 - colour.r;
01597 inverse.g = 255 - colour.g;
01598 inverse.b = 255 - colour.b;
01599 inverse.unused = 0;
01600 return inverse;
01601 }
01602
01603 void pixel_data::read(const config& cfg) {
01604 const std::string& red = cfg["red"];
01605 const std::string& green = cfg["green"];
01606 const std::string& blue = cfg["blue"];
01607
01608 if (red.empty())
01609 r = 0;
01610 else
01611 r = atoi(red.c_str());
01612
01613 if (green.empty())
01614 g = 0;
01615 else
01616 g = atoi(green.c_str());
01617
01618 if (blue.empty())
01619 b = 0;
01620 else
01621 b = atoi(blue.c_str());
01622 }
01623
01624 surface_restorer::surface_restorer() : target_(NULL), rect_(empty_rect), surface_(NULL)
01625 {
01626 }
01627
01628 surface_restorer::surface_restorer(CVideo* target, const SDL_Rect& rect)
01629 : target_(target), rect_(rect), surface_(NULL)
01630 {
01631 update();
01632 }
01633
01634 surface_restorer::~surface_restorer()
01635 {
01636 restore();
01637 }
01638
01639 void surface_restorer::restore(SDL_Rect const &dst) const
01640 {
01641 if (surface_.null())
01642 return;
01643 SDL_Rect dst2 = intersect_rects(dst, rect_);
01644 if (dst2.w == 0 || dst2.h == 0)
01645 return;
01646 SDL_Rect src = dst2;
01647 src.x -= rect_.x;
01648 src.y -= rect_.y;
01649 SDL_BlitSurface(surface_, &src, target_->getSurface(), &dst2);
01650 update_rect(dst2);
01651 }
01652
01653 void surface_restorer::restore() const
01654 {
01655 if (surface_.null())
01656 return;
01657 SDL_Rect dst = rect_;
01658 SDL_BlitSurface(surface_, NULL, target_->getSurface(), &dst);
01659 update_rect(rect_);
01660 }
01661
01662 void surface_restorer::update()
01663 {
01664 if(rect_.w == 0 || rect_.h == 0)
01665 surface_.assign(NULL);
01666 else
01667 surface_.assign(::get_surface_portion(target_->getSurface(),rect_));
01668 }
01669
01670 void surface_restorer::cancel()
01671 {
01672 surface_.assign(NULL);
01673 }
01674
01675 void draw_rectangle(int x, int y, int w, int h, Uint32 colour,surface target)
01676 {
01677
01678 SDL_Rect top = {x,y,w,1};
01679 SDL_Rect bot = {x,y+h-1,w,1};
01680 SDL_Rect left = {x,y,1,h};
01681 SDL_Rect right = {x+w-1,y,1,h};
01682
01683 SDL_FillRect(target,&top,colour);
01684 SDL_FillRect(target,&bot,colour);
01685 SDL_FillRect(target,&left,colour);
01686 SDL_FillRect(target,&right,colour);
01687 }
01688
01689 void draw_solid_tinted_rectangle(int x, int y, int w, int h,
01690 int r, int g, int b,
01691 double alpha, surface target)
01692 {
01693
01694 SDL_Rect rect = {x,y,w,h};
01695 fill_rect_alpha(rect,SDL_MapRGB(target->format,r,g,b),Uint8(alpha*255),target);
01696 }
01697
01698 void draw_centered_on_background(surface surf, const SDL_Rect& rect, const SDL_Color& color, surface target)
01699 {
01700 clip_rect_setter clip_setter(target, rect);
01701
01702 Uint32 col = SDL_MapRGBA(target->format, color.r, color.g, color.b, color.unused);
01703
01704 SDL_Rect r = rect;
01705 SDL_FillRect(target, &r, col);
01706
01707 if (surf != NULL) {
01708 r.x = rect.x + (rect.w-surf->w)/2;
01709 r.y = rect.y + (rect.h-surf->h)/2;
01710 SDL_BlitSurface(surf, NULL, target, &r);
01711 }
01712 update_rect(rect);
01713 }