- Main Page
- Data Structures
- Files

- File List
- Globals

# SDL_rotozoom.c

Go to the documentation of this file.

    00001 /*
    00002
    00003 SDL_rotozoom.c - rotozoomer, zoomer and shrinker for 32bit or 8bit surfaces
    00004
    00005 LGPL (c) A. Schiffler
    00006
    00007 */
    00008
    00009 #ifdef WIN32
    00010 #include <windows.h>
    00011 #endif
    00012
    00013 #include <stdlib.h>
    00014 #include <string.h>
    00015
    00016 #include "SDL_rotozoom.h"
    00017
    00018 /* ---- Internally used structures */
    00019
    00023 typedef struct tColorRGBA {
    00024         Uint8 r;
    00025         Uint8 g;
    00026         Uint8 b;
    00027         Uint8 a;
    00028 } tColorRGBA;
    00029
    00033 typedef struct tColorY {
    00034         Uint8 y;
    00035 } tColorY;
    00036
    00040 #define MAX(a,b)    (((a) > (b)) ? (a) : (b))
    00041
    00052 #define GUARD_ROWS (2)
    00053
    00057 #define VALUE_LIMIT     0.001
    00058
    00062 Uint32 _colorkey(SDL_Surface *src)
    00063 {
    00064         Uint32 key = 0;
    00065 #if (SDL_MINOR_VERSION == 3)
    00066         SDL_GetColorKey(src, &key);
    00067 #else
    00068         if (src)
    00069         {
    00070                 key = src->format->colorkey;
    00071         }
    00072 #endif
    00073         return key;
    00074 }
    00075
    00076
    00092 int _shrinkSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
    00093 {
    00094         int x, y, dx, dy, sgap, dgap, ra, ga, ba, aa;
    00095         int n_average;
    00096         tColorRGBA *sp, *osp, *oosp;
    00097         tColorRGBA *dp;
    00098
    00099         /*
    00100         * Averaging integer shrink
    00101         */
    00102
    00103         /* Precalculate division factor */
    00104         n_average = factorx*factory;
    00105
    00106         /*
    00107         * Scan destination
    00108         */
    00109         sp = (tColorRGBA *) src->pixels;
    00110         sgap = src->pitch - src->w * 4;
    00111
    00112         dp = (tColorRGBA *) dst->pixels;
    00113         dgap = dst->pitch - dst->w * 4;
    00114
    00115         for (y = 0; y < dst->h; y++) {
    00116
    00117                 osp=sp;
    00118                 for (x = 0; x < dst->w; x++) {
    00119
    00120                         /* Trace out source box and accumulate */
    00121                         oosp=sp;
    00122                         ra=ga=ba=aa=0;
    00123                         for (dy=0; dy < factory; dy++) {
    00124                                 for (dx=0; dx < factorx; dx++) {
    00125                                         ra += sp->r;
    00126                                         ga += sp->g;
    00127                                         ba += sp->b;
    00128                                         aa += sp->a;
    00129
    00130                                         sp++;
    00131                                 }
    00132                                 /* src dx loop */
    00133                                 sp = (tColorRGBA *)((Uint8*)sp + (src->pitch - 4*factorx)); // next y
    00134                         }
    00135                         /* src dy loop */
    00136
    00137                         /* next box-x */
    00138                         sp = (tColorRGBA *)((Uint8*)oosp + 4*factorx);
    00139
    00140                         /* Store result in destination */
    00141                         dp->r = ra/n_average;
    00142                         dp->g = ga/n_average;
    00143                         dp->b = ba/n_average;
    00144                         dp->a = aa/n_average;
    00145
    00146                         /*
    00147                         * Advance destination pointer
    00148                         */
    00149                         dp++;
    00150                 }
    00151                 /* dst x loop */
    00152
    00153                 /* next box-y */
    00154                 sp = (tColorRGBA *)((Uint8*)osp + src->pitch*factory);
    00155
    00156                 /*
    00157                 * Advance destination pointers
    00158                 */
    00159                 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
    00160         }
    00161         /* dst y loop */
    00162
    00163         return (0);
    00164 }
    00165
    00181 int _shrinkSurfaceY(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
    00182 {
    00183         int x, y, dx, dy, sgap, dgap, a;
    00184         int n_average;
    00185         Uint8 *sp, *osp, *oosp;
    00186         Uint8 *dp;
    00187
    00188         /*
    00189         * Averaging integer shrink
    00190         */
    00191
    00192         /* Precalculate division factor */
    00193         n_average = factorx*factory;
    00194
    00195         /*
    00196         * Scan destination
    00197         */
    00198         sp = (Uint8 *) src->pixels;
    00199         sgap = src->pitch - src->w;
    00200
    00201         dp = (Uint8 *) dst->pixels;
    00202         dgap = dst->pitch - dst->w;
    00203
    00204         for (y = 0; y < dst->h; y++) {
    00205
    00206                 osp=sp;
    00207                 for (x = 0; x < dst->w; x++) {
    00208
    00209                         /* Trace out source box and accumulate */
    00210                         oosp=sp;
    00211                         a=0;
    00212                         for (dy=0; dy < factory; dy++) {
    00213                                 for (dx=0; dx < factorx; dx++) {
    00214                                         a += (*sp);
    00215                                         /* next x */
    00216                                         sp++;
    00217                                 }
    00218                                 /* end src dx loop */
    00219                                 /* next y */
    00220                                 sp = (Uint8 *)((Uint8*)sp + (src->pitch - factorx));
    00221                         }
    00222                         /* end src dy loop */
    00223
    00224                         /* next box-x */
    00225                         sp = (Uint8 *)((Uint8*)oosp + factorx);
    00226
    00227                         /* Store result in destination */
    00228                         *dp = a/n_average;
    00229
    00230                         /*
    00231                         * Advance destination pointer
    00232                         */
    00233                         dp++;
    00234                 }
    00235                 /* end dst x loop */
    00236
    00237                 /* next box-y */
    00238                 sp = (Uint8 *)((Uint8*)osp + src->pitch*factory);
    00239
    00240                 /*
    00241                 * Advance destination pointers
    00242                 */
    00243                 dp = (Uint8 *)((Uint8 *)dp + dgap);
    00244         }
    00245         /* end dst y loop */
    00246
    00247         return (0);
    00248 }
    00249
    00265 int _zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy, int smooth)
    00266 {
    00267         int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy, ex, ey, t1, t2, sstep, lx, ly;
    00268         tColorRGBA *c00, *c01, *c10, *c11, *cswap;
    00269         tColorRGBA *sp, *csp, *dp;
    00270         int dgap;
    00271
    00272         /*
    00273         * Variable setup
    00274         */
    00275         if (smooth) {
    00276                 /*
    00277                 * For interpolation: assume source dimension is one pixel
    00278                 * smaller to avoid overflow on right and bottom edge.
    00279                 */
    00280                 sx = (int) (65536.0 * (float) (src->w - 1) / (float) dst->w);
    00281                 sy = (int) (65536.0 * (float) (src->h - 1) / (float) dst->h);
    00282         } else {
    00283                 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
    00284                 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
    00285         }
    00286
    00287         /*
    00288         * Allocate memory for row increments
    00289         */
    00290         if ((sax = (int *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
    00291                 return (-1);
    00292         }
    00293         if ((say = (int *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
    00294                 free(sax);
    00295                 return (-1);
    00296         }
    00297
    00298         /*
    00299         * Precalculate row increments
    00300         */
    00301         sp = csp = (tColorRGBA *) src->pixels;
    00302         dp = (tColorRGBA *) dst->pixels;
    00303
    00304         if (flipx) csp += (src->w-1);
    00305         if (flipy) csp += ((src->pitch/4)*(src->h-1));
    00306
    00307         csx = 0;
    00308         csax = sax;
    00309         for (x = 0; x <= dst->w; x++) {
    00310                 *csax = csx;
    00311                 csax++;
    00312                 csx &= 0xffff;
    00313                 csx += sx;
    00314         }
    00315         csy = 0;
    00316         csay = say;
    00317         for (y = 0; y <= dst->h; y++) {
    00318                 *csay = csy;
    00319                 csay++;
    00320                 csy &= 0xffff;
    00321                 csy += sy;
    00322         }
    00323
    00324         dgap = dst->pitch - dst->w * 4;
    00325
    00326         /*
    00327         * Switch between interpolating and non-interpolating code
    00328         */
    00329         if (smooth) {
    00330
    00331                 /*
    00332                 * Interpolating Zoom
    00333                 */
    00334
    00335                 /*
    00336                 * Scan destination
    00337                 */
    00338                 csay = say;
    00339                 ly = 0;
    00340                 for (y = 0; y < dst->h; y++) {
    00341                         /*
    00342                         * Setup color source pointers
    00343                         */
    00344                         c00 = csp;
    00345                         c01 = csp;
    00346                         c01++;
    00347                         c10 = csp;
    00348                         c10 += src->pitch/4;
    00349                         c11 = c10;
    00350                         c11++;
    00351                         if (flipx) {
    00352                                 cswap = c00; c00=c01; c01=cswap;
    00353                                 cswap = c10; c10=c11; c11=cswap;
    00354                         }
    00355                         if (flipy) {
    00356                                 cswap = c00; c00=c10; c10=cswap;
    00357                                 cswap = c01; c01=c11; c11=cswap;
    00358                         }
    00359
    00360                         csax = sax;
    00361                         lx = 0;
    00362                         for (x = 0; x < dst->w; x++) {
    00363                                 /*
    00364                                 * Draw and interpolate colors
    00365                                 */
    00366                                 ex = (*csax & 0xffff);
    00367                                 ey = (*csay & 0xffff);
    00368                                 t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
    00369                                 t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
    00370                                 dp->r = (((t2 - t1) * ey) >> 16) + t1;
    00371                                 t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff;
    00372                                 t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff;
    00373                                 dp->g = (((t2 - t1) * ey) >> 16) + t1;
    00374                                 t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff;
    00375                                 t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff;
    00376                                 dp->b = (((t2 - t1) * ey) >> 16) + t1;
    00377                                 t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff;
    00378                                 t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff;
    00379                                 dp->a = (((t2 - t1) * ey) >> 16) + t1;
    00380
    00381                                 /*
    00382                                 * Advance source pointers
    00383                                 */
    00384                                 csax++;
    00385                                 if (*csax > 0)
    00386                                 {
    00387                                         sstep = (*csax >> 16);
    00388                                         lx += sstep;
    00389                                         if (flipx) sstep = -sstep;
    00390                                         if (lx <= src->w)
    00391                                         {
    00392                                                 c00 += sstep;
    00393                                                 c01 += sstep;
    00394                                                 c10 += sstep;
    00395                                                 c11 += sstep;
    00396                                         }
    00397                                 }
    00398
    00399                                 /*
    00400                                 * Advance destination pointer
    00401                                 */
    00402                                 dp++;
    00403                         }
    00404
    00405                         /*
    00406                         * Advance source pointer
    00407                         */
    00408                         csay++;
    00409                         if (*csay > 0)
    00410                         {
    00411                                 sstep = (*csay >> 16);
    00412                                 ly += sstep;
    00413                                 if (flipy) sstep = -sstep;
    00414                                 if (ly < src->h)
    00415                                 {
    00416                                         csp += (sstep * (src->pitch/4));
    00417                                 }
    00418                         }
    00419
    00420                         /*
    00421                         * Advance destination pointers
    00422                         */
    00423                         dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
    00424                 }
    00425         } else {
    00426
    00427                 /*
    00428                 * Non-Interpolating Zoom
    00429                 */
    00430                 csay = say;
    00431                 for (y = 0; y < dst->h; y++) {
    00432                         sp = csp;
    00433                         csax = sax;
    00434                         for (x = 0; x < dst->w; x++) {
    00435                                 /*
    00436                                 * Draw
    00437                                 */
    00438                                 *dp = *sp;
    00439                                 /*
    00440                                 * Advance source pointers
    00441                                 */
    00442                                 csax++;
    00443                                 if (*csax > 0)
    00444                                 {
    00445                                         sstep = (*csax >> 16);
    00446                                         if (flipx) sstep = -sstep;
    00447                                         sp += sstep;
    00448                                 }
    00449                                 /*
    00450                                 * Advance destination pointer
    00451                                 */
    00452                                 dp++;
    00453                         }
    00454                         /*
    00455                         * Advance source pointer
    00456                         */
    00457                         csay++;
    00458                         if (*csay > 0)
    00459                         {
    00460                                 sstep = (*csay >> 16) * (src->pitch/4);
    00461                                 if (flipy) sstep = -sstep;
    00462                                 csp += sstep;
    00463                         }
    00464
    00465                         /*
    00466                         * Advance destination pointers
    00467                         */
    00468                         dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
    00469                 }
    00470         }
    00471
    00472         /*
    00473         * Remove temp arrays
    00474         */
    00475         free(sax);
    00476         free(say);
    00477
    00478         return (0);
    00479 }
    00480
    00496 int _zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy)
    00497 {
    00498         int x, y;
    00499         Uint32 *sax, *say, *csax, *csay;
    00500         int csx, csy;
    00501         Uint8 *sp, *dp, *csp;
    00502         int dgap;
    00503
    00504         /*
    00505         * Allocate memory for row increments
    00506         */
    00507         if ((sax = (Uint32 *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
    00508                 return (-1);
    00509         }
    00510         if ((say = (Uint32 *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
    00511                 free(sax);
    00512                 return (-1);
    00513         }
    00514
    00515         /*
    00516         * Pointer setup
    00517         */
    00518         sp = csp = (Uint8 *) src->pixels;
    00519         dp = (Uint8 *) dst->pixels;
    00520         dgap = dst->pitch - dst->w;
    00521
    00522         if (flipx) csp += (src->w-1);
    00523         if (flipy) csp  = ( (Uint8*)csp + src->pitch*(src->h-1) );
    00524
    00525         /*
    00526         * Precalculate row increments
    00527         */
    00528         csx = 0;
    00529         csax = sax;
    00530         for (x = 0; x < dst->w; x++) {
    00531                 csx += src->w;
    00532                 *csax = 0;
    00533                 while (csx >= dst->w) {
    00534                         csx -= dst->w;
    00535                         (*csax)++;
    00536                 }
    00537                 csax++;
    00538         }
    00539         csy = 0;
    00540         csay = say;
    00541         for (y = 0; y < dst->h; y++) {
    00542                 csy += src->h;
    00543                 *csay = 0;
    00544                 while (csy >= dst->h) {
    00545                         csy -= dst->h;
    00546                         (*csay)++;
    00547                 }
    00548                 csay++;
    00549         }
    00550
    00551         /*
    00552         * Draw
    00553         */
    00554         csay = say;
    00555         for (y = 0; y < dst->h; y++) {
    00556                 csax = sax;
    00557                 sp = csp;
    00558                 for (x = 0; x < dst->w; x++) {
    00559                         /*
    00560                         * Draw
    00561                         */
    00562                         *dp = *sp;
    00563                         /*
    00564                         * Advance source pointers
    00565                         */
    00566                         sp += (*csax) * (flipx ? -1 : 1);
    00567                         csax++;
    00568                         /*
    00569                         * Advance destination pointer
    00570                         */
    00571                         dp++;
    00572                 }
    00573                 /*
    00574                 * Advance source pointer (for row)
    00575                 */
    00576                 csp += ((*csay) * src->pitch) * (flipy ? -1 : 1);
    00577                 csay++;
    00578
    00579                 /*
    00580                 * Advance destination pointers
    00581                 */
    00582                 dp += dgap;
    00583         }
    00584
    00585         /*
    00586         * Remove temp arrays
    00587         */
    00588         free(sax);
    00589         free(say);
    00590
    00591         return (0);
    00592 }
    00593
    00613 void _transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy, int smooth)
    00614 {
    00615         int x, y, t1, t2, dx, dy, xd, yd, sdx, sdy, ax, ay, ex, ey, sw, sh;
    00616         tColorRGBA c00, c01, c10, c11, cswap;
    00617         tColorRGBA *pc, *sp;
    00618         int gap;
    00619
    00620         /*
    00621         * Variable setup
    00622         */
    00623         xd = ((src->w - dst->w) << 15);
    00624         yd = ((src->h - dst->h) << 15);
    00625         ax = (cx << 16) - (icos * cx);
    00626         ay = (cy << 16) - (isin * cx);
    00627         sw = src->w - 1;
    00628         sh = src->h - 1;
    00629         pc = (tColorRGBA*) dst->pixels;
    00630         gap = dst->pitch - dst->w * 4;
    00631
    00632         /*
    00633         * Switch between interpolating and non-interpolating code
    00634         */
    00635         if (smooth) {
    00636                 for (y = 0; y < dst->h; y++) {
    00637                         dy = cy - y;
    00638                         sdx = (ax + (isin * dy)) + xd;
    00639                         sdy = (ay - (icos * dy)) + yd;
    00640                         for (x = 0; x < dst->w; x++) {
    00641                                 dx = (sdx >> 16);
    00642                                 dy = (sdy >> 16);
    00643                                 if (flipx) dx = sw - dx;
    00644                                 if (flipy) dy = sh - dy;
    00645                                 if ((dx > -1) && (dy > -1) && (dx < (src->w-1)) && (dy < (src->h-1))) {
    00646                                         sp = (tColorRGBA *)src->pixels;;
    00647                                         sp += ((src->pitch/4) * dy);
    00648                                         sp += dx;
    00649                                         c00 = *sp;
    00650                                         sp += 1;
    00651                                         c01 = *sp;
    00652                                         sp += (src->pitch/4);
    00653                                         c11 = *sp;
    00654                                         sp -= 1;
    00655                                         c10 = *sp;
    00656                                         if (flipx) {
    00657                                                 cswap = c00; c00=c01; c01=cswap;
    00658                                                 cswap = c10; c10=c11; c11=cswap;
    00659                                         }
    00660                                         if (flipy) {
    00661                                                 cswap = c00; c00=c10; c10=cswap;
    00662                                                 cswap = c01; c01=c11; c11=cswap;
    00663                                         }
    00664                                         /*
    00665                                         * Interpolate colors
    00666                                         */
    00667                                         ex = (sdx & 0xffff);
    00668                                         ey = (sdy & 0xffff);
    00669                                         t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff;
    00670                                         t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff;
    00671                                         pc->r = (((t2 - t1) * ey) >> 16) + t1;
    00672                                         t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff;
    00673                                         t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff;
    00674                                         pc->g = (((t2 - t1) * ey) >> 16) + t1;
    00675                                         t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff;
    00676                                         t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff;
    00677                                         pc->b = (((t2 - t1) * ey) >> 16) + t1;
    00678                                         t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff;
    00679                                         t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff;
    00680                                         pc->a = (((t2 - t1) * ey) >> 16) + t1;
    00681                                 }
    00682                                 sdx += icos;
    00683                                 sdy += isin;
    00684                                 pc++;
    00685                         }
    00686                         pc = (tColorRGBA *) ((Uint8 *) pc + gap);
    00687                 }
    00688         } else {
    00689                 for (y = 0; y < dst->h; y++) {
    00690                         dy = cy - y;
    00691                         sdx = (ax + (isin * dy)) + xd;
    00692                         sdy = (ay - (icos * dy)) + yd;
    00693                         for (x = 0; x < dst->w; x++) {
    00694                                 dx = (short) (sdx >> 16);
    00695                                 dy = (short) (sdy >> 16);
    00696                                 if (flipx) dx = (src->w-1)-dx;
    00697                                 if (flipy) dy = (src->h-1)-dy;
    00698                                 if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
    00699                                         sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
    00700                                         sp += dx;
    00701                                         *pc = *sp;
    00702                                 }
    00703                                 sdx += icos;
    00704                                 sdy += isin;
    00705                                 pc++;
    00706                         }
    00707                         pc = (tColorRGBA *) ((Uint8 *) pc + gap);
    00708                 }
    00709         }
    00710 }
    00711
    00730 void transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy)
    00731 {
    00732         int x, y, dx, dy, xd, yd, sdx, sdy, ax, ay, sw, sh;
    00733         tColorY *pc, *sp;
    00734         int gap;
    00735
    00736         /*
    00737         * Variable setup
    00738         */
    00739         xd = ((src->w - dst->w) << 15);
    00740         yd = ((src->h - dst->h) << 15);
    00741         ax = (cx << 16) - (icos * cx);
    00742         ay = (cy << 16) - (isin * cx);
    00743         sw = src->w - 1;
    00744         sh = src->h - 1;
    00745         pc = (tColorY*) dst->pixels;
    00746         gap = dst->pitch - dst->w;
    00747         /*
    00748         * Clear surface to colorkey
    00749         */
    00750         memset(pc, (unsigned char) (_colorkey(src) & 0xff), dst->pitch * dst->h);
    00751         /*
    00752         * Iterate through destination surface
    00753         */
    00754         for (y = 0; y < dst->h; y++) {
    00755                 dy = cy - y;
    00756                 sdx = (ax + (isin * dy)) + xd;
    00757                 sdy = (ay - (icos * dy)) + yd;
    00758                 for (x = 0; x < dst->w; x++) {
    00759                         dx = (short) (sdx >> 16);
    00760                         dy = (short) (sdy >> 16);
    00761                         if (flipx) dx = (src->w-1)-dx;
    00762                         if (flipy) dy = (src->h-1)-dy;
    00763                         if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
    00764                                 sp = (tColorY *) (src->pixels);
    00765                                 sp += (src->pitch * dy + dx);
    00766                                 *pc = *sp;
    00767                         }
    00768                         sdx += icos;
    00769                         sdy += isin;
    00770                         pc++;
    00771                 }
    00772                 pc += gap;
    00773         }
    00774 }
    00775
    00789 SDL_Surface* rotateSurface90Degrees(SDL_Surface* src, int numClockwiseTurns)
    00790 {
    00791         int row, col, newWidth, newHeight;
    00792         int bpp, src_ipr, dst_ipr;
    00793         SDL_Surface* dst;
    00794         Uint32* srcBuf;
    00795         Uint32* dstBuf;
    00796
    00797         /* Has to be a valid surface pointer and only 32-bit surfaces (for now) */
    00798         if (!src || src->format->BitsPerPixel != 32) { return NULL; }
    00799
    00800         /* normalize numClockwiseTurns */
    00801         while(numClockwiseTurns < 0) { numClockwiseTurns += 4; }
    00802         numClockwiseTurns = (numClockwiseTurns % 4);
    00803
    00804         /* if it's even, our new width will be the same as the source surface */
    00805         newWidth = (numClockwiseTurns % 2) ? (src->h) : (src->w);
    00806         newHeight = (numClockwiseTurns % 2) ? (src->w) : (src->h);
    00807         dst = SDL_CreateRGBSurface( src->flags, newWidth, newHeight, src->format->BitsPerPixel,
    00808                 src->format->Rmask,
    00809                 src->format->Gmask,
    00810                 src->format->Bmask,
    00811                 src->format->Amask);
    00812         if(!dst) {
    00813                 return NULL;
    00814         }
    00815
    00816         if (SDL_MUSTLOCK(dst)) {
    00817                 SDL_LockSurface(dst);
    00818         }
    00819         if (SDL_MUSTLOCK(dst)) {
    00820                 SDL_LockSurface(dst);
    00821         }
    00822
    00823         /* Calculate int-per-row */
    00824         bpp = src->format->BitsPerPixel / 8;
    00825         src_ipr = src->pitch / bpp;
    00826         dst_ipr = dst->pitch / bpp;
    00827
    00828         switch(numClockwiseTurns) {
    00829                 case 0: /* Make a copy of the surface */
    00830                         {
    00831                                 /* Unfortunately SDL_BlitSurface cannot be used to make a copy of the surface
    00832                                    since it does not preserve alpha. */
    00833
    00834                                 if (src->pitch == dst->pitch) {
    00835                                         /* If the pitch is the same for both surfaces, the memory can be copied all at once. */
    00836                                         memcpy(dst->pixels, src->pixels, (src->h * src->pitch));
    00837                                 }
    00838                                 else
    00839                                 {
    00840                                         /* If the pitch differs, copy each row separately */
    00841                                         srcBuf = (Uint32*)(src->pixels);
    00842                                         dstBuf = (Uint32*)(dst->pixels);
    00843                                         for (row = 0; row < src->h; row++) {
    00844                                                 memcpy(dstBuf, srcBuf, dst->w * bpp);
    00845                                                 srcBuf += src_ipr;
    00846                                                 dstBuf += dst_ipr;
    00847                                         } /* end for(col) */
    00848                                 } /* end for(row) */
    00849                         }
    00850                         break;
    00851
    00852                         /* rotate clockwise */
    00853                 case 1: /* rotated 90 degrees clockwise */
    00854                  {
    00855                          for (row = 0; row < src->h; ++row) {
    00856                                  srcBuf = (Uint32*)(src->pixels) + (row * src_ipr);
    00857                                  dstBuf = (Uint32*)(dst->pixels) + (dst->w - row - 1);
    00858                                  for (col = 0; col < src->w; ++col) {
    00859                                          *dstBuf = *srcBuf;
    00860                                          ++srcBuf;
    00861                                          dstBuf += dst_ipr;
    00862                                  }
    00863                                  /* end for(col) */
    00864                          }
    00865                          /* end for(row) */
    00866                  }
    00867                  break;
    00868
    00869                 case 2: /* rotated 180 degrees clockwise */
    00870                  {
    00871                          for (row = 0; row < src->h; ++row) {
    00872                                  srcBuf = (Uint32*)(src->pixels) + (row * src_ipr);
    00873                                  dstBuf = (Uint32*)(dst->pixels) + ((dst->h - row - 1) * dst_ipr) + (dst->w - 1);
    00874                                  for (col = 0; col < src->w; ++col) {
    00875                                          *dstBuf = *srcBuf;
    00876                                          ++srcBuf;
    00877                                          --dstBuf;
    00878                                  }
    00879                          }
    00880                  }
    00881                  break;
    00882
    00883                 case 3:
    00884                  {
    00885                          for (row = 0; row < src->h; ++row) {
    00886                                  srcBuf = (Uint32*)(src->pixels) + (row * src_ipr);
    00887                                  dstBuf = (Uint32*)(dst->pixels) + row + ((dst->h - 1) * dst_ipr);
    00888                                  for (col = 0; col < src->w; ++col) {
    00889                                          *dstBuf = *srcBuf;
    00890                                          ++srcBuf;
    00891                                          dstBuf -= dst_ipr;
    00892                                  }
    00893                          }
    00894                  }
    00895                  break;
    00896         }
    00897         /* end switch */
    00898
    00899         if (SDL_MUSTLOCK(src)) {
    00900                 SDL_UnlockSurface(src);
    00901         }
    00902         if (SDL_MUSTLOCK(dst)) {
    00903                 SDL_UnlockSurface(dst);
    00904         }
    00905
    00906         return dst;
    00907 }
    00908
    00909
    00924 void _rotozoomSurfaceSizeTrig(int width, int height, double angle, double zoomx, double zoomy,
    00925                                                           int *dstwidth, int *dstheight,
    00926                                                           double *canglezoom, double *sanglezoom)
    00927 {
    00928         double x, y, cx, cy, sx, sy;
    00929         double radangle;
    00930         int dstwidthhalf, dstheighthalf;
    00931
    00932         /*
    00933         * Determine destination width and height by rotating a centered source box
    00934         */
    00935         radangle = angle * (M_PI / 180.0);
    00936         *sanglezoom = sin(radangle);
    00937         *canglezoom = cos(radangle);
    00938         *sanglezoom *= zoomx;
    00939         *canglezoom *= zoomx;
    00940         x = width / 2;
    00941         y = height / 2;
    00942         cx = *canglezoom * x;
    00943         cy = *canglezoom * y;
    00944         sx = *sanglezoom * x;
    00945         sy = *sanglezoom * y;
    00946
    00947         dstwidthhalf = MAX((int)
    00948                 ceil(MAX(MAX(MAX(fabs(cx + sy), fabs(cx - sy)), fabs(-cx + sy)), fabs(-cx - sy))), 1);
    00949         dstheighthalf = MAX((int)
    00950                 ceil(MAX(MAX(MAX(fabs(sx + cy), fabs(sx - cy)), fabs(-sx + cy)), fabs(-sx - cy))), 1);
    00951         *dstwidth = 2 * dstwidthhalf;
    00952         *dstheight = 2 * dstheighthalf;
    00953 }
    00954
    00966 void rotozoomSurfaceSizeXY(int width, int height, double angle, double zoomx, double zoomy, int *dstwidth, int *dstheight)
    00967 {
    00968         double dummy_sanglezoom, dummy_canglezoom;
    00969
    00970         _rotozoomSurfaceSizeTrig(width, height, angle, zoomx, zoomy, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
    00971 }
    00972
    00983 void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth, int *dstheight)
    00984 {
    00985         double dummy_sanglezoom, dummy_canglezoom;
    00986
    00987         _rotozoomSurfaceSizeTrig(width, height, angle, zoom, zoom, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
    00988 }
    00989
    01005 SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth)
    01006 {
    01007         return rotozoomSurfaceXY(src, angle, zoom, zoom, smooth);
    01008 }
    01009
    01026 SDL_Surface *rotozoomSurfaceXY(SDL_Surface * src, double angle, double zoomx, double zoomy, int smooth)
    01027 {
    01028         SDL_Surface *rz_src;
    01029         SDL_Surface *rz_dst;
    01030         double zoominv;
    01031         double sanglezoom, canglezoom, sanglezoominv, canglezoominv;
    01032         int dstwidthhalf, dstwidth, dstheighthalf, dstheight;
    01033         int is32bit;
    01034         int i, src_converted;
    01035         int flipx,flipy;
    01036         Uint8 r,g,b;
    01037         Uint32 colorkey = 0;
    01038         int colorKeyAvailable = 0;
    01039
    01040         /*
    01041         * Sanity check
    01042         */
    01043         if (src == NULL)
    01044                 return (NULL);
    01045
    01046         if (src->flags & SDL_SRCCOLORKEY)
    01047         {
    01048                 colorkey = _colorkey(src);
    01049                 SDL_GetRGB(colorkey, src->format, &r, &g, &b);
    01050                 colorKeyAvailable = 1;
    01051         }
    01052         /*
    01053         * Determine if source surface is 32bit or 8bit
    01054         */
    01055         is32bit = (src->format->BitsPerPixel == 32);
    01056         if ((is32bit) || (src->format->BitsPerPixel == 8)) {
    01057                 /*
    01058                 * Use source surface 'as is'
    01059                 */
    01060                 rz_src = src;
    01061                 src_converted = 0;
    01062         } else {
    01063                 /*
    01064                 * New source surface is 32bit with a defined RGBA ordering
    01065                 */
    01066                 rz_src =
    01067                         SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
    01068 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
    01069                         0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
    01070 #else
    01071                         0xff000000,  0x00ff0000, 0x0000ff00, 0x000000ff
    01072 #endif
    01073                         );
    01074                 if(colorKeyAvailable)
    01075                         SDL_SetColorKey(src, 0, 0);
    01076
    01077                 SDL_BlitSurface(src, NULL, rz_src, NULL);
    01078
    01079                 if(colorKeyAvailable)
    01080                         SDL_SetColorKey(src, SDL_SRCCOLORKEY, colorkey);
    01081                 src_converted = 1;
    01082                 is32bit = 1;
    01083         }
    01084
    01085         /*
    01086         * Sanity check zoom factor
    01087         */
    01088         flipx = (zoomx<0.0);
    01089         if (flipx) zoomx=-zoomx;
    01090         flipy = (zoomy<0.0);
    01091         if (flipy) zoomy=-zoomy;
    01092         if (zoomx < VALUE_LIMIT) zoomx = VALUE_LIMIT;
    01093         if (zoomy < VALUE_LIMIT) zoomy = VALUE_LIMIT;
    01094         zoominv = 65536.0 / (zoomx * zoomx);
    01095
    01096         /*
    01097         * Check if we have a rotozoom or just a zoom
    01098         */
    01099         if (fabs(angle) > VALUE_LIMIT) {
    01100
    01101                 /*
    01102                 * Angle!=0: full rotozoom
    01103                 */
    01104                 /*
    01105                 * -----------------------
    01106                 */
    01107
    01108                 /* Determine target size */
    01109                 _rotozoomSurfaceSizeTrig(rz_src->w, rz_src->h, angle, zoomx, zoomy, &dstwidth, &dstheight, &canglezoom, &sanglezoom);
    01110
    01111                 /*
    01112                 * Calculate target factors from sin/cos and zoom
    01113                 */
    01114                 sanglezoominv = sanglezoom;
    01115                 canglezoominv = canglezoom;
    01116                 sanglezoominv *= zoominv;
    01117                 canglezoominv *= zoominv;
    01118
    01119                 /* Calculate half size */
    01120                 dstwidthhalf = dstwidth / 2;
    01121                 dstheighthalf = dstheight / 2;
    01122
    01123                 /*
    01124                 * Alloc space to completely contain the rotated surface
    01125                 */
    01126                 rz_dst = NULL;
    01127                 if (is32bit) {
    01128                         /*
    01129                         * Target surface is 32bit with source RGBA/ABGR ordering
    01130                         */
    01131                         rz_dst =
    01132                                 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
    01133                                 rz_src->format->Rmask, rz_src->format->Gmask,
    01134                                 rz_src->format->Bmask, rz_src->format->Amask);
    01135                 } else {
    01136                         /*
    01137                         * Target surface is 8bit
    01138                         */
    01139                         rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
    01140                 }
    01141
    01142                 /* Check target */
    01143                 if (rz_dst == NULL)
    01144                         return NULL;
    01145
    01146                 /* Adjust for guard rows */
    01147                 rz_dst->h = dstheight;
    01148
    01149                 if (colorKeyAvailable == 1){
    01150                         colorkey = SDL_MapRGB(rz_dst->format, r, g, b);
    01151
    01152                         SDL_FillRect(rz_dst, NULL, colorkey );
    01153                 }
    01154
    01155                 /*
    01156                 * Lock source surface
    01157                 */
    01158                 if (SDL_MUSTLOCK(rz_src)) {
    01159                         SDL_LockSurface(rz_src);
    01160                 }
    01161
    01162                 /*
    01163                 * Check which kind of surface we have
    01164                 */
    01165                 if (is32bit) {
    01166                         /*
    01167                         * Call the 32bit transformation routine to do the rotation (using alpha)
    01168                         */
    01169                         _transformSurfaceRGBA(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
    01170                                 (int) (sanglezoominv), (int) (canglezoominv),
    01171                                 flipx, flipy,
    01172                                 smooth);
    01173                         /*
    01174                         * Turn on source-alpha support
    01175                         */
    01176                         SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
    01177                         SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
    01178                 } else {
    01179                         /*
    01180                         * Copy palette and colorkey info
    01181                         */
    01182                         for (i = 0; i < rz_src->format->palette->ncolors; i++) {
    01183                                 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
    01184                         }
    01185                         rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
    01186                         /*
    01187                         * Call the 8bit transformation routine to do the rotation
    01188                         */
    01189                         transformSurfaceY(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
    01190                                 (int) (sanglezoominv), (int) (canglezoominv),
    01191                                 flipx, flipy);
    01192                         SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
    01193                 }
    01194                 /*
    01195                 * Unlock source surface
    01196                 */
    01197                 if (SDL_MUSTLOCK(rz_src)) {
    01198                         SDL_UnlockSurface(rz_src);
    01199                 }
    01200
    01201         } else {
    01202
    01203                 /*
    01204                 * Angle=0: Just a zoom
    01205                 */
    01206                 /*
    01207                 * --------------------
    01208                 */
    01209
    01210                 /*
    01211                 * Calculate target size
    01212                 */
    01213                 zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
    01214
    01215                 /*
    01216                 * Alloc space to completely contain the zoomed surface
    01217                 */
    01218                 rz_dst = NULL;
    01219                 if (is32bit) {
    01220                         /*
    01221                         * Target surface is 32bit with source RGBA/ABGR ordering
    01222                         */
    01223                         rz_dst =
    01224                                 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
    01225                                 rz_src->format->Rmask, rz_src->format->Gmask,
    01226                                 rz_src->format->Bmask, rz_src->format->Amask);
    01227                 } else {
    01228                         /*
    01229                         * Target surface is 8bit
    01230                         */
    01231                         rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
    01232                 }
    01233
    01234                 /* Check target */
    01235                 if (rz_dst == NULL)
    01236                         return NULL;
    01237
    01238                 /* Adjust for guard rows */
    01239                 rz_dst->h = dstheight;
    01240
    01241                 if (colorKeyAvailable == 1){
    01242                         colorkey = SDL_MapRGB(rz_dst->format, r, g, b);
    01243
    01244                         SDL_FillRect(rz_dst, NULL, colorkey );
    01245                 }
    01246
    01247                 /*
    01248                 * Lock source surface
    01249                 */
    01250                 if (SDL_MUSTLOCK(rz_src)) {
    01251                         SDL_LockSurface(rz_src);
    01252                 }
    01253
    01254                 /*
    01255                 * Check which kind of surface we have
    01256                 */
    01257                 if (is32bit) {
    01258                         /*
    01259                         * Call the 32bit transformation routine to do the zooming (using alpha)
    01260                         */
    01261                         _zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
    01262
    01263                         /*
    01264                         * Turn on source-alpha support
    01265                         */
    01266                         SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
    01267                         SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
    01268                 } else {
    01269                         /*
    01270                         * Copy palette and colorkey info
    01271                         */
    01272                         for (i = 0; i < rz_src->format->palette->ncolors; i++) {
    01273                                 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
    01274                         }
    01275                         rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
    01276
    01277                         /*
    01278                         * Call the 8bit transformation routine to do the zooming
    01279                         */
    01280                         _zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
    01281                         SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
    01282                 }
    01283
    01284                 /*
    01285                 * Unlock source surface
    01286                 */
    01287                 if (SDL_MUSTLOCK(rz_src)) {
    01288                         SDL_UnlockSurface(rz_src);
    01289                 }
    01290         }
    01291
    01292         /*
    01293         * Cleanup temp surface
    01294         */
    01295         if (src_converted) {
    01296                 SDL_FreeSurface(rz_src);
    01297         }
    01298
    01299         /*
    01300         * Return destination surface
    01301         */
    01302         return (rz_dst);
    01303 }
    01304
    01317 void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight)
    01318 {
    01319         /*
    01320         * Make zoom factors positive
    01321         */
    01322         int flipx, flipy;
    01323         flipx = (zoomx<0.0);
    01324         if (flipx) zoomx = -zoomx;
    01325         flipy = (zoomy<0.0);
    01326         if (flipy) zoomy = -zoomy;
    01327
    01328         /*
    01329         * Sanity check zoom factors
    01330         */
    01331         if (zoomx < VALUE_LIMIT) {
    01332                 zoomx = VALUE_LIMIT;
    01333         }
    01334         if (zoomy < VALUE_LIMIT) {
    01335                 zoomy = VALUE_LIMIT;
    01336         }
    01337
    01338         /*
    01339         * Calculate target size
    01340         */
    01341         *dstwidth = (int) ((double) width * zoomx);
    01342         *dstheight = (int) ((double) height * zoomy);
    01343         if (*dstwidth < 1) {
    01344                 *dstwidth = 1;
    01345         }
    01346         if (*dstheight < 1) {
    01347                 *dstheight = 1;
    01348         }
    01349 }
    01350
    01367 SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth)
    01368 {
    01369         SDL_Surface *rz_src;
    01370         SDL_Surface *rz_dst;
    01371         int dstwidth, dstheight;
    01372         int is32bit;
    01373         int i, src_converted;
    01374         int flipx, flipy;
    01375
    01376         /*
    01377         * Sanity check
    01378         */
    01379         if (src == NULL)
    01380                 return (NULL);
    01381
    01382         /*
    01383         * Determine if source surface is 32bit or 8bit
    01384         */
    01385         is32bit = (src->format->BitsPerPixel == 32);
    01386         if ((is32bit) || (src->format->BitsPerPixel == 8)) {
    01387                 /*
    01388                 * Use source surface 'as is'
    01389                 */
    01390                 rz_src = src;
    01391                 src_converted = 0;
    01392         } else {
    01393                 /*
    01394                 * New source surface is 32bit with a defined RGBA ordering
    01395                 */
    01396                 rz_src =
    01397                         SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
    01398 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
    01399                         0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
    01400 #else
    01401                         0xff000000,  0x00ff0000, 0x0000ff00, 0x000000ff
    01402 #endif
    01403                         );
    01404                 SDL_BlitSurface(src, NULL, rz_src, NULL);
    01405                 src_converted = 1;
    01406                 is32bit = 1;
    01407         }
    01408
    01409         flipx = (zoomx<0.0);
    01410         if (flipx) zoomx = -zoomx;
    01411         flipy = (zoomy<0.0);
    01412         if (flipy) zoomy = -zoomy;
    01413
    01414         /* Get size if target */
    01415         zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
    01416
    01417         /*
    01418         * Alloc space to completely contain the zoomed surface
    01419         */
    01420         rz_dst = NULL;
    01421         if (is32bit) {
    01422                 /*
    01423                 * Target surface is 32bit with source RGBA/ABGR ordering
    01424                 */
    01425                 rz_dst =
    01426                         SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
    01427                         rz_src->format->Rmask, rz_src->format->Gmask,
    01428                         rz_src->format->Bmask, rz_src->format->Amask);
    01429         } else {
    01430                 /*
    01431                 * Target surface is 8bit
    01432                 */
    01433                 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
    01434         }
    01435
    01436         /* Check target */
    01437         if (rz_dst == NULL)
    01438                 return NULL;
    01439
    01440         /* Adjust for guard rows */
    01441         rz_dst->h = dstheight;
    01442
    01443         /*
    01444         * Lock source surface
    01445         */
    01446         if (SDL_MUSTLOCK(rz_src)) {
    01447                 SDL_LockSurface(rz_src);
    01448         }
    01449
    01450         /*
    01451         * Check which kind of surface we have
    01452         */
    01453         if (is32bit) {
    01454                 /*
    01455                 * Call the 32bit transformation routine to do the zooming (using alpha)
    01456                 */
    01457                 _zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
    01458                 /*
    01459                 * Turn on source-alpha support
    01460                 */
    01461                 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
    01462         } else {
    01463                 /*
    01464                 * Copy palette and colorkey info
    01465                 */
    01466                 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
    01467                         rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
    01468                 }
    01469                 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
    01470                 /*
    01471                 * Call the 8bit transformation routine to do the zooming
    01472                 */
    01473                 _zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
    01474                 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
    01475         }
    01476         /*
    01477         * Unlock source surface
    01478         */
    01479         if (SDL_MUSTLOCK(rz_src)) {
    01480                 SDL_UnlockSurface(rz_src);
    01481         }
    01482
    01483         /*
    01484         * Cleanup temp surface
    01485         */
    01486         if (src_converted) {
    01487                 SDL_FreeSurface(rz_src);
    01488         }
    01489
    01490         /*
    01491         * Return destination surface
    01492         */
    01493         return (rz_dst);
    01494 }
    01495
    01512 SDL_Surface *shrinkSurface(SDL_Surface *src, int factorx, int factory)
    01513 {
    01514         SDL_Surface *rz_src;
    01515         SDL_Surface *rz_dst;
    01516         int dstwidth, dstheight;
    01517         int is32bit;
    01518         int i, src_converted;
    01519
    01520         /*
    01521         * Sanity check
    01522         */
    01523         if (src == NULL)
    01524                 return (NULL);
    01525
    01526         /*
    01527         * Determine if source surface is 32bit or 8bit
    01528         */
    01529         is32bit = (src->format->BitsPerPixel == 32);
    01530         if ((is32bit) || (src->format->BitsPerPixel == 8)) {
    01531                 /*
    01532                 * Use source surface 'as is'
    01533                 */
    01534                 rz_src = src;
    01535                 src_converted = 0;
    01536         } else {
    01537                 /*
    01538                 * New source surface is 32bit with a defined RGBA ordering
    01539                 */
    01540                 rz_src =
    01541                         SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
    01542 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
    01543                         0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
    01544 #else
    01545                         0xff000000,  0x00ff0000, 0x0000ff00, 0x000000ff
    01546 #endif
    01547                         );
    01548                 SDL_BlitSurface(src, NULL, rz_src, NULL);
    01549                 src_converted = 1;
    01550                 is32bit = 1;
    01551         }
    01552
    01553         /* Get size for target */
    01554         dstwidth=rz_src->w/factorx;
    01555         while (dstwidth*factorx>rz_src->w) { dstwidth--; }
    01556         dstheight=rz_src->h/factory;
    01557         while (dstheight*factory>rz_src->h) { dstheight--; }
    01558
    01559         /*
    01560         * Alloc space to completely contain the shrunken surface
    01561         * (with added guard rows)
    01562         */
    01563         rz_dst = NULL;
    01564         if (is32bit) {
    01565                 /*
    01566                 * Target surface is 32bit with source RGBA/ABGR ordering
    01567                 */
    01568                 rz_dst =
    01569                         SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
    01570                         rz_src->format->Rmask, rz_src->format->Gmask,
    01571                         rz_src->format->Bmask, rz_src->format->Amask);
    01572         } else {
    01573                 /*
    01574                 * Target surface is 8bit
    01575                 */
    01576                 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
    01577         }
    01578
    01579         /* Check target */
    01580         if (rz_dst == NULL)
    01581                 return NULL;
    01582
    01583         /* Adjust for guard rows */
    01584         rz_dst->h = dstheight;
    01585
    01586         /*
    01587         * Lock source surface
    01588         */
    01589         if (SDL_MUSTLOCK(rz_src)) {
    01590                 SDL_LockSurface(rz_src);
    01591         }
    01592
    01593         /*
    01594         * Check which kind of surface we have
    01595         */
    01596         if (is32bit) {
    01597                 /*
    01598                 * Call the 32bit transformation routine to do the shrinking (using alpha)
    01599                 */
    01600                 _shrinkSurfaceRGBA(rz_src, rz_dst, factorx, factory);
    01601                 /*
    01602                 * Turn on source-alpha support
    01603                 */
    01604                 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
    01605         } else {
    01606                 /*
    01607                 * Copy palette and colorkey info
    01608                 */
    01609                 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
    01610                         rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
    01611                 }
    01612                 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
    01613                 /*
    01614                 * Call the 8bit transformation routine to do the shrinking
    01615                 */
    01616                 _shrinkSurfaceY(rz_src, rz_dst, factorx, factory);
    01617                 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
    01618         }
    01619
    01620         /*
    01621         * Unlock source surface
    01622         */
    01623         if (SDL_MUSTLOCK(rz_src)) {
    01624                 SDL_UnlockSurface(rz_src);
    01625         }
    01626
    01627         /*
    01628         * Cleanup temp surface
    01629         */
    01630         if (src_converted) {
    01631                 SDL_FreeSurface(rz_src);
    01632         }
    01633
    01634         /*
    01635         * Return destination surface
    01636         */
    01637         return (rz_dst);
    01638 }