SDL_gfx  2.0.25
I:/Sources/sdlgfx/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 Copyright (C) 2001-2012  Andreas Schiffler
00006 
00007 This software is provided 'as-is', without any express or implied
00008 warranty. In no event will the authors be held liable for any damages
00009 arising from the use of this software.
00010 
00011 Permission is granted to anyone to use this software for any purpose,
00012 including commercial applications, and to alter it and redistribute it
00013 freely, subject to the following restrictions:
00014 
00015 1. The origin of this software must not be misrepresented; you must not
00016 claim that you wrote the original software. If you use this software
00017 in a product, an acknowledgment in the product documentation would be
00018 appreciated but is not required.
00019 
00020 2. Altered source versions must be plainly marked as such, and must not be
00021 misrepresented as being the original software.
00022 
00023 3. This notice may not be removed or altered from any source
00024 distribution.
00025 
00026 Andreas Schiffler -- aschiffler at ferzkopp dot net
00027 
00028 */
00029 
00030 #ifdef WIN32
00031 #include <windows.h>
00032 #endif
00033 
00034 #include <stdlib.h>
00035 #include <string.h>
00036 
00037 #include "SDL_rotozoom.h"
00038 
00039 /* ---- Internally used structures */
00040 
00044 typedef struct tColorRGBA {
00045         Uint8 r;
00046         Uint8 g;
00047         Uint8 b;
00048         Uint8 a;
00049 } tColorRGBA;
00050 
00054 typedef struct tColorY {
00055         Uint8 y;
00056 } tColorY;
00057 
00061 #define MAX(a,b)    (((a) > (b)) ? (a) : (b))
00062 
00073 #define GUARD_ROWS (2)
00074 
00078 #define VALUE_LIMIT     0.001
00079 
00083 Uint32 _colorkey(SDL_Surface *src)
00084 {
00085         Uint32 key = 0; 
00086 #if (SDL_MINOR_VERSION == 3)
00087         SDL_GetColorKey(src, &key);
00088 #else
00089         if (src) 
00090         {
00091                 key = src->format->colorkey;
00092         }
00093 #endif
00094         return key;
00095 }
00096 
00097 
00113 int _shrinkSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
00114 {
00115         int x, y, dx, dy, sgap, dgap, ra, ga, ba, aa;
00116         int n_average;
00117         tColorRGBA *sp, *osp, *oosp;
00118         tColorRGBA *dp;
00119 
00120         /*
00121         * Averaging integer shrink
00122         */
00123 
00124         /* Precalculate division factor */
00125         n_average = factorx*factory;
00126 
00127         /*
00128         * Scan destination
00129         */
00130         sp = (tColorRGBA *) src->pixels;
00131         sgap = src->pitch - src->w * 4;
00132 
00133         dp = (tColorRGBA *) dst->pixels;
00134         dgap = dst->pitch - dst->w * 4;
00135 
00136         for (y = 0; y < dst->h; y++) {
00137 
00138                 osp=sp;
00139                 for (x = 0; x < dst->w; x++) {
00140 
00141                         /* Trace out source box and accumulate */
00142                         oosp=sp;
00143                         ra=ga=ba=aa=0;
00144                         for (dy=0; dy < factory; dy++) {
00145                                 for (dx=0; dx < factorx; dx++) {
00146                                         ra += sp->r;
00147                                         ga += sp->g;
00148                                         ba += sp->b;
00149                                         aa += sp->a;
00150 
00151                                         sp++;
00152                                 } 
00153                                 /* src dx loop */
00154                                 sp = (tColorRGBA *)((Uint8*)sp + (src->pitch - 4*factorx)); // next y
00155                         }
00156                         /* src dy loop */
00157 
00158                         /* next box-x */
00159                         sp = (tColorRGBA *)((Uint8*)oosp + 4*factorx);
00160 
00161                         /* Store result in destination */
00162                         dp->r = ra/n_average;
00163                         dp->g = ga/n_average;
00164                         dp->b = ba/n_average;
00165                         dp->a = aa/n_average;
00166 
00167                         /*
00168                         * Advance destination pointer 
00169                         */
00170                         dp++;
00171                 } 
00172                 /* dst x loop */
00173 
00174                 /* next box-y */
00175                 sp = (tColorRGBA *)((Uint8*)osp + src->pitch*factory);
00176 
00177                 /*
00178                 * Advance destination pointers 
00179                 */
00180                 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
00181         } 
00182         /* dst y loop */
00183 
00184         return (0);
00185 }
00186 
00202 int _shrinkSurfaceY(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
00203 {
00204         int x, y, dx, dy, sgap, dgap, a;
00205         int n_average;
00206         Uint8 *sp, *osp, *oosp;
00207         Uint8 *dp;
00208 
00209         /*
00210         * Averaging integer shrink
00211         */
00212 
00213         /* Precalculate division factor */
00214         n_average = factorx*factory;
00215 
00216         /*
00217         * Scan destination
00218         */
00219         sp = (Uint8 *) src->pixels;
00220         sgap = src->pitch - src->w;
00221 
00222         dp = (Uint8 *) dst->pixels;
00223         dgap = dst->pitch - dst->w;
00224 
00225         for (y = 0; y < dst->h; y++) {    
00226 
00227                 osp=sp;
00228                 for (x = 0; x < dst->w; x++) {
00229 
00230                         /* Trace out source box and accumulate */
00231                         oosp=sp;
00232                         a=0;
00233                         for (dy=0; dy < factory; dy++) {
00234                                 for (dx=0; dx < factorx; dx++) {
00235                                         a += (*sp);
00236                                         /* next x */           
00237                                         sp++;
00238                                 } 
00239                                 /* end src dx loop */         
00240                                 /* next y */
00241                                 sp = (Uint8 *)((Uint8*)sp + (src->pitch - factorx)); 
00242                         } 
00243                         /* end src dy loop */
00244 
00245                         /* next box-x */
00246                         sp = (Uint8 *)((Uint8*)oosp + factorx);
00247 
00248                         /* Store result in destination */
00249                         *dp = a/n_average;
00250 
00251                         /*
00252                         * Advance destination pointer 
00253                         */
00254                         dp++;
00255                 } 
00256                 /* end dst x loop */
00257 
00258                 /* next box-y */
00259                 sp = (Uint8 *)((Uint8*)osp + src->pitch*factory);
00260 
00261                 /*
00262                 * Advance destination pointers 
00263                 */
00264                 dp = (Uint8 *)((Uint8 *)dp + dgap);
00265         } 
00266         /* end dst y loop */
00267 
00268         return (0);
00269 }
00270 
00286 int _zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy, int smooth)
00287 {
00288         int x, y, sx, sy, ssx, ssy, *sax, *say, *csax, *csay, *salast, csx, csy, ex, ey, cx, cy, sstep, sstepx, sstepy;
00289         tColorRGBA *c00, *c01, *c10, *c11;
00290         tColorRGBA *sp, *csp, *dp;
00291         int spixelgap, spixelw, spixelh, dgap, t1, t2;
00292 
00293         /*
00294         * Allocate memory for row/column increments 
00295         */
00296         if ((sax = (int *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
00297                 return (-1);
00298         }
00299         if ((say = (int *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
00300                 free(sax);
00301                 return (-1);
00302         }
00303 
00304         /*
00305         * Precalculate row increments 
00306         */
00307         spixelw = (src->w - 1);
00308         spixelh = (src->h - 1);
00309         if (smooth) {
00310                 sx = (int) (65536.0 * (float) spixelw / (float) (dst->w - 1));
00311                 sy = (int) (65536.0 * (float) spixelh / (float) (dst->h - 1));
00312         } else {
00313                 sx = (int) (65536.0 * (float) (src->w) / (float) (dst->w));
00314                 sy = (int) (65536.0 * (float) (src->h) / (float) (dst->h));
00315         }
00316 
00317         /* Maximum scaled source size */
00318         ssx = (src->w << 16) - 1;
00319         ssy = (src->h << 16) - 1;
00320 
00321         /* Precalculate horizontal row increments */
00322         csx = 0;
00323         csax = sax;
00324         for (x = 0; x <= dst->w; x++) {
00325                 *csax = csx;
00326                 csax++;
00327                 csx += sx;
00328 
00329                 /* Guard from overflows */
00330                 if (csx > ssx) { 
00331                         csx = ssx; 
00332                 }
00333         }
00334 
00335         /* Precalculate vertical row increments */
00336         csy = 0;
00337         csay = say;
00338         for (y = 0; y <= dst->h; y++) {
00339                 *csay = csy;
00340                 csay++;
00341                 csy += sy;
00342 
00343                 /* Guard from overflows */
00344                 if (csy > ssy) {
00345                         csy = ssy;
00346                 }
00347         }
00348 
00349         sp = (tColorRGBA *) src->pixels;
00350         dp = (tColorRGBA *) dst->pixels;
00351         dgap = dst->pitch - dst->w * 4;
00352         spixelgap = src->pitch/4;
00353 
00354         if (flipx) sp += spixelw;
00355         if (flipy) sp += (spixelgap * spixelh);
00356 
00357         /*
00358         * Switch between interpolating and non-interpolating code 
00359         */
00360         if (smooth) {
00361 
00362                 /*
00363                 * Interpolating Zoom 
00364                 */
00365                 csay = say;
00366                 for (y = 0; y < dst->h; y++) {
00367                         csp = sp;
00368                         csax = sax;
00369                         for (x = 0; x < dst->w; x++) {
00370                                 /*
00371                                 * Setup color source pointers 
00372                                 */
00373                                 ex = (*csax & 0xffff);
00374                                 ey = (*csay & 0xffff);
00375                                 cx = (*csax >> 16);
00376                                 cy = (*csay >> 16);
00377                                 sstepx = cx < spixelw;
00378                                 sstepy = cy < spixelh;
00379                                 c00 = sp;
00380                                 c01 = sp;
00381                                 c10 = sp;
00382                                 if (sstepy) {
00383                                         if (flipy) {
00384                                                 c10 -= spixelgap;
00385                                         } else {
00386                                                 c10 += spixelgap;
00387                                         }
00388                                 }
00389                                 c11 = c10;
00390                                 if (sstepx) {
00391                                         if (flipx) {
00392                                                 c01--;
00393                                                 c11--;
00394                                         } else {
00395                                                 c01++;
00396                                                 c11++;
00397                                         }
00398                                 }
00399 
00400                                 /*
00401                                 * Draw and interpolate colors 
00402                                 */
00403                                 t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
00404                                 t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
00405                                 dp->r = (((t2 - t1) * ey) >> 16) + t1;
00406                                 t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff;
00407                                 t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff;
00408                                 dp->g = (((t2 - t1) * ey) >> 16) + t1;
00409                                 t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff;
00410                                 t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff;
00411                                 dp->b = (((t2 - t1) * ey) >> 16) + t1;
00412                                 t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff;
00413                                 t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff;
00414                                 dp->a = (((t2 - t1) * ey) >> 16) + t1;                          
00415                                 /*
00416                                 * Advance source pointer x
00417                                 */
00418                                 salast = csax;
00419                                 csax++;                         
00420                                 sstep = (*csax >> 16) - (*salast >> 16);
00421                                 if (flipx) {
00422                                         sp -= sstep;
00423                                 } else {
00424                                         sp += sstep;
00425                                 }
00426 
00427                                 /*
00428                                 * Advance destination pointer x
00429                                 */
00430                                 dp++;
00431                         }
00432                         /*
00433                         * Advance source pointer y
00434                         */
00435                         salast = csay;
00436                         csay++;
00437                         sstep = (*csay >> 16) - (*salast >> 16);
00438                         sstep *= spixelgap;
00439                         if (flipy) { 
00440                                 sp = csp - sstep;
00441                         } else {
00442                                 sp = csp + sstep;
00443                         }
00444 
00445                         /*
00446                         * Advance destination pointer y
00447                         */
00448                         dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
00449                 }
00450         } else {
00451                 /*
00452                 * Non-Interpolating Zoom 
00453                 */              
00454                 csay = say;
00455                 for (y = 0; y < dst->h; y++) {
00456                         csp = sp;
00457                         csax = sax;
00458                         for (x = 0; x < dst->w; x++) {
00459                                 /*
00460                                 * Draw 
00461                                 */
00462                                 *dp = *sp;
00463 
00464                                 /*
00465                                 * Advance source pointer x
00466                                 */
00467                                 salast = csax;
00468                                 csax++;                         
00469                                 sstep = (*csax >> 16) - (*salast >> 16);
00470                                 if (flipx) sstep = -sstep;
00471                                 sp += sstep;
00472 
00473                                 /*
00474                                 * Advance destination pointer x
00475                                 */
00476                                 dp++;
00477                         }
00478                         /*
00479                         * Advance source pointer y
00480                         */
00481                         salast = csay;
00482                         csay++;
00483                         sstep = (*csay >> 16) - (*salast >> 16);
00484                         sstep *= spixelgap;
00485                         if (flipy) sstep = -sstep;                      
00486                         sp = csp + sstep;
00487 
00488                         /*
00489                         * Advance destination pointer y
00490                         */
00491                         dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
00492                 }
00493         }
00494 
00495         /*
00496         * Remove temp arrays 
00497         */
00498         free(sax);
00499         free(say);
00500 
00501         return (0);
00502 }
00503 
00519 int _zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy)
00520 {
00521         int x, y;
00522         Uint32 *sax, *say, *csax, *csay;
00523         int csx, csy;
00524         Uint8 *sp, *dp, *csp;
00525         int dgap;
00526 
00527         /*
00528         * Allocate memory for row increments 
00529         */
00530         if ((sax = (Uint32 *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
00531                 return (-1);
00532         }
00533         if ((say = (Uint32 *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
00534                 free(sax);
00535                 return (-1);
00536         }
00537 
00538         /*
00539         * Pointer setup 
00540         */
00541         sp = csp = (Uint8 *) src->pixels;
00542         dp = (Uint8 *) dst->pixels;
00543         dgap = dst->pitch - dst->w;
00544 
00545         if (flipx) csp += (src->w-1);
00546         if (flipy) csp  = ( (Uint8*)csp + src->pitch*(src->h-1) );
00547 
00548         /*
00549         * Precalculate row increments 
00550         */
00551         csx = 0;
00552         csax = sax;
00553         for (x = 0; x < dst->w; x++) {
00554                 csx += src->w;
00555                 *csax = 0;
00556                 while (csx >= dst->w) {
00557                         csx -= dst->w;
00558                         (*csax)++;
00559                 }
00560                 (*csax) = (*csax) * (flipx ? -1 : 1);
00561                 csax++;
00562         }
00563         csy = 0;
00564         csay = say;
00565         for (y = 0; y < dst->h; y++) {
00566                 csy += src->h;
00567                 *csay = 0;
00568                 while (csy >= dst->h) {
00569                         csy -= dst->h;
00570                         (*csay)++;
00571                 }
00572                 (*csay) = (*csay) * (flipy ? -1 : 1);
00573                 csay++;
00574         }
00575 
00576         /*
00577         * Draw 
00578         */
00579         csay = say;
00580         for (y = 0; y < dst->h; y++) {
00581                 csax = sax;
00582                 sp = csp;
00583                 for (x = 0; x < dst->w; x++) {
00584                         /*
00585                         * Draw 
00586                         */
00587                         *dp = *sp;
00588                         /*
00589                         * Advance source pointers 
00590                         */
00591                         sp += (*csax);
00592                         csax++;
00593                         /*
00594                         * Advance destination pointer 
00595                         */
00596                         dp++;
00597                 }
00598                 /*
00599                 * Advance source pointer (for row) 
00600                 */
00601                 csp += ((*csay) * src->pitch);
00602                 csay++;
00603 
00604                 /*
00605                 * Advance destination pointers 
00606                 */
00607                 dp += dgap;
00608         }
00609 
00610         /*
00611         * Remove temp arrays 
00612         */
00613         free(sax);
00614         free(say);
00615 
00616         return (0);
00617 }
00618 
00638 void _transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy, int smooth)
00639 {
00640         int x, y, t1, t2, dx, dy, xd, yd, sdx, sdy, ax, ay, ex, ey, sw, sh;
00641         tColorRGBA c00, c01, c10, c11, cswap;
00642         tColorRGBA *pc, *sp;
00643         int gap;
00644 
00645         /*
00646         * Variable setup 
00647         */
00648         xd = ((src->w - dst->w) << 15);
00649         yd = ((src->h - dst->h) << 15);
00650         ax = (cx << 16) - (icos * cx);
00651         ay = (cy << 16) - (isin * cx);
00652         sw = src->w - 1;
00653         sh = src->h - 1;
00654         pc = (tColorRGBA*) dst->pixels;
00655         gap = dst->pitch - dst->w * 4;
00656 
00657         /*
00658         * Switch between interpolating and non-interpolating code 
00659         */
00660         if (smooth) {
00661                 for (y = 0; y < dst->h; y++) {
00662                         dy = cy - y;
00663                         sdx = (ax + (isin * dy)) + xd;
00664                         sdy = (ay - (icos * dy)) + yd;
00665                         for (x = 0; x < dst->w; x++) {
00666                                 dx = (sdx >> 16);
00667                                 dy = (sdy >> 16);
00668                                 if (flipx) dx = sw - dx;
00669                                 if (flipy) dy = sh - dy;
00670                                 if ((dx > -1) && (dy > -1) && (dx < (src->w-1)) && (dy < (src->h-1))) {
00671                                         sp = (tColorRGBA *)src->pixels;;
00672                                         sp += ((src->pitch/4) * dy);
00673                                         sp += dx;
00674                                         c00 = *sp;
00675                                         sp += 1;
00676                                         c01 = *sp;
00677                                         sp += (src->pitch/4);
00678                                         c11 = *sp;
00679                                         sp -= 1;
00680                                         c10 = *sp;
00681                                         if (flipx) {
00682                                                 cswap = c00; c00=c01; c01=cswap;
00683                                                 cswap = c10; c10=c11; c11=cswap;
00684                                         }
00685                                         if (flipy) {
00686                                                 cswap = c00; c00=c10; c10=cswap;
00687                                                 cswap = c01; c01=c11; c11=cswap;
00688                                         }
00689                                         /*
00690                                         * Interpolate colors 
00691                                         */
00692                                         ex = (sdx & 0xffff);
00693                                         ey = (sdy & 0xffff);
00694                                         t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff;
00695                                         t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff;
00696                                         pc->r = (((t2 - t1) * ey) >> 16) + t1;
00697                                         t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff;
00698                                         t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff;
00699                                         pc->g = (((t2 - t1) * ey) >> 16) + t1;
00700                                         t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff;
00701                                         t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff;
00702                                         pc->b = (((t2 - t1) * ey) >> 16) + t1;
00703                                         t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff;
00704                                         t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff;
00705                                         pc->a = (((t2 - t1) * ey) >> 16) + t1;
00706                                 }
00707                                 sdx += icos;
00708                                 sdy += isin;
00709                                 pc++;
00710                         }
00711                         pc = (tColorRGBA *) ((Uint8 *) pc + gap);
00712                 }
00713         } else {
00714                 for (y = 0; y < dst->h; y++) {
00715                         dy = cy - y;
00716                         sdx = (ax + (isin * dy)) + xd;
00717                         sdy = (ay - (icos * dy)) + yd;
00718                         for (x = 0; x < dst->w; x++) {
00719                                 dx = (short) (sdx >> 16);
00720                                 dy = (short) (sdy >> 16);
00721                                 if (flipx) dx = (src->w-1)-dx;
00722                                 if (flipy) dy = (src->h-1)-dy;
00723                                 if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
00724                                         sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
00725                                         sp += dx;
00726                                         *pc = *sp;
00727                                 }
00728                                 sdx += icos;
00729                                 sdy += isin;
00730                                 pc++;
00731                         }
00732                         pc = (tColorRGBA *) ((Uint8 *) pc + gap);
00733                 }
00734         }
00735 }
00736 
00755 void transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy)
00756 {
00757         int x, y, dx, dy, xd, yd, sdx, sdy, ax, ay, sw, sh;
00758         tColorY *pc, *sp;
00759         int gap;
00760 
00761         /*
00762         * Variable setup 
00763         */
00764         xd = ((src->w - dst->w) << 15);
00765         yd = ((src->h - dst->h) << 15);
00766         ax = (cx << 16) - (icos * cx);
00767         ay = (cy << 16) - (isin * cx);
00768         sw = src->w - 1;
00769         sh = src->h - 1;
00770         pc = (tColorY*) dst->pixels;
00771         gap = dst->pitch - dst->w;
00772         /*
00773         * Clear surface to colorkey 
00774         */      
00775         memset(pc, (int)(_colorkey(src) & 0xff), dst->pitch * dst->h);
00776         /*
00777         * Iterate through destination surface 
00778         */
00779         for (y = 0; y < dst->h; y++) {
00780                 dy = cy - y;
00781                 sdx = (ax + (isin * dy)) + xd;
00782                 sdy = (ay - (icos * dy)) + yd;
00783                 for (x = 0; x < dst->w; x++) {
00784                         dx = (short) (sdx >> 16);
00785                         dy = (short) (sdy >> 16);
00786                         if (flipx) dx = (src->w-1)-dx;
00787                         if (flipy) dy = (src->h-1)-dy;
00788                         if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
00789                                 sp = (tColorY *) (src->pixels);
00790                                 sp += (src->pitch * dy + dx);
00791                                 *pc = *sp;
00792                         }
00793                         sdx += icos;
00794                         sdy += isin;
00795                         pc++;
00796                 }
00797                 pc += gap;
00798         }
00799 }
00800 
00814 SDL_Surface* rotateSurface90Degrees(SDL_Surface* src, int numClockwiseTurns) 
00815 {
00816         int row, col, newWidth, newHeight;
00817         int bpp, src_ipr, dst_ipr;
00818         SDL_Surface* dst;
00819         Uint32* srcBuf;
00820         Uint32* dstBuf;
00821 
00822         /* Has to be a valid surface pointer and only 32-bit surfaces (for now) */
00823         if (!src || src->format->BitsPerPixel != 32) { return NULL; }
00824 
00825         /* normalize numClockwiseTurns */
00826         while(numClockwiseTurns < 0) { numClockwiseTurns += 4; }
00827         numClockwiseTurns = (numClockwiseTurns % 4);
00828 
00829         /* if it's even, our new width will be the same as the source surface */
00830         newWidth = (numClockwiseTurns % 2) ? (src->h) : (src->w);
00831         newHeight = (numClockwiseTurns % 2) ? (src->w) : (src->h);
00832         dst = SDL_CreateRGBSurface( src->flags, newWidth, newHeight, src->format->BitsPerPixel,
00833                 src->format->Rmask,
00834                 src->format->Gmask, 
00835                 src->format->Bmask, 
00836                 src->format->Amask);
00837         if(!dst) {
00838                 return NULL;
00839         }
00840 
00841         if (SDL_MUSTLOCK(dst)) {
00842                 SDL_LockSurface(dst);
00843         }
00844         if (SDL_MUSTLOCK(dst)) {
00845                 SDL_LockSurface(dst);
00846         }
00847 
00848         /* Calculate int-per-row */
00849         bpp = src->format->BitsPerPixel / 8;
00850         src_ipr = src->pitch / bpp;
00851         dst_ipr = dst->pitch / bpp;
00852 
00853         switch(numClockwiseTurns) {
00854         case 0: /* Make a copy of the surface */
00855                 {
00856                         /* Unfortunately SDL_BlitSurface cannot be used to make a copy of the surface
00857                         since it does not preserve alpha. */
00858 
00859                         if (src->pitch == dst->pitch) {
00860                                 /* If the pitch is the same for both surfaces, the memory can be copied all at once. */
00861                                 memcpy(dst->pixels, src->pixels, (src->h * src->pitch));
00862                         }
00863                         else
00864                         {
00865                                 /* If the pitch differs, copy each row separately */
00866                                 srcBuf = (Uint32*)(src->pixels); 
00867                                 dstBuf = (Uint32*)(dst->pixels);
00868                                 for (row = 0; row < src->h; row++) {
00869                                         memcpy(dstBuf, srcBuf, dst->w * bpp);
00870                                         srcBuf += src_ipr;
00871                                         dstBuf += dst_ipr;
00872                                 } /* end for(col) */
00873                         } /* end for(row) */
00874                 }
00875                 break;
00876 
00877                 /* rotate clockwise */
00878         case 1: /* rotated 90 degrees clockwise */
00879                 {
00880                         for (row = 0; row < src->h; ++row) {
00881                                 srcBuf = (Uint32*)(src->pixels) + (row * src_ipr);
00882                                 dstBuf = (Uint32*)(dst->pixels) + (dst->w - row - 1);
00883                                 for (col = 0; col < src->w; ++col) {
00884                                         *dstBuf = *srcBuf;
00885                                         ++srcBuf;
00886                                         dstBuf += dst_ipr;
00887                                 } 
00888                                 /* end for(col) */
00889                         } 
00890                         /* end for(row) */
00891                 }
00892                 break;
00893 
00894         case 2: /* rotated 180 degrees clockwise */
00895                 {
00896                         for (row = 0; row < src->h; ++row) {
00897                                 srcBuf = (Uint32*)(src->pixels) + (row * src_ipr);
00898                                 dstBuf = (Uint32*)(dst->pixels) + ((dst->h - row - 1) * dst_ipr) + (dst->w - 1);
00899                                 for (col = 0; col < src->w; ++col) {
00900                                         *dstBuf = *srcBuf;
00901                                         ++srcBuf;
00902                                         --dstBuf;
00903                                 } 
00904                         } 
00905                 }
00906                 break;
00907 
00908         case 3:
00909                 {
00910                         for (row = 0; row < src->h; ++row) {
00911                                 srcBuf = (Uint32*)(src->pixels) + (row * src_ipr);
00912                                 dstBuf = (Uint32*)(dst->pixels) + row + ((dst->h - 1) * dst_ipr);
00913                                 for (col = 0; col < src->w; ++col) {
00914                                         *dstBuf = *srcBuf;
00915                                         ++srcBuf;
00916                                         dstBuf -= dst_ipr;
00917                                 } 
00918                         } 
00919                 }
00920                 break;
00921         } 
00922         /* end switch */
00923 
00924         if (SDL_MUSTLOCK(src)) {
00925                 SDL_UnlockSurface(src);
00926         }
00927         if (SDL_MUSTLOCK(dst)) {
00928                 SDL_UnlockSurface(dst);
00929         }
00930 
00931         return dst;
00932 }
00933 
00934 
00949 void _rotozoomSurfaceSizeTrig(int width, int height, double angle, double zoomx, double zoomy, 
00950         int *dstwidth, int *dstheight, 
00951         double *canglezoom, double *sanglezoom)
00952 {
00953         double x, y, cx, cy, sx, sy;
00954         double radangle;
00955         int dstwidthhalf, dstheighthalf;
00956 
00957         /*
00958         * Determine destination width and height by rotating a centered source box 
00959         */
00960         radangle = angle * (M_PI / 180.0);
00961         *sanglezoom = sin(radangle);
00962         *canglezoom = cos(radangle);
00963         *sanglezoom *= zoomx;
00964         *canglezoom *= zoomx;
00965         x = (double)(width / 2);
00966         y = (double)(height / 2);
00967         cx = *canglezoom * x;
00968         cy = *canglezoom * y;
00969         sx = *sanglezoom * x;
00970         sy = *sanglezoom * y;
00971 
00972         dstwidthhalf = MAX((int)
00973                 ceil(MAX(MAX(MAX(fabs(cx + sy), fabs(cx - sy)), fabs(-cx + sy)), fabs(-cx - sy))), 1);
00974         dstheighthalf = MAX((int)
00975                 ceil(MAX(MAX(MAX(fabs(sx + cy), fabs(sx - cy)), fabs(-sx + cy)), fabs(-sx - cy))), 1);
00976         *dstwidth = 2 * dstwidthhalf;
00977         *dstheight = 2 * dstheighthalf;
00978 }
00979 
00991 void rotozoomSurfaceSizeXY(int width, int height, double angle, double zoomx, double zoomy, int *dstwidth, int *dstheight)
00992 {
00993         double dummy_sanglezoom, dummy_canglezoom;
00994 
00995         _rotozoomSurfaceSizeTrig(width, height, angle, zoomx, zoomy, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
00996 }
00997 
01008 void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth, int *dstheight)
01009 {
01010         double dummy_sanglezoom, dummy_canglezoom;
01011 
01012         _rotozoomSurfaceSizeTrig(width, height, angle, zoom, zoom, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
01013 }
01014 
01030 SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth)
01031 {
01032         return rotozoomSurfaceXY(src, angle, zoom, zoom, smooth);
01033 }
01034 
01051 SDL_Surface *rotozoomSurfaceXY(SDL_Surface * src, double angle, double zoomx, double zoomy, int smooth)
01052 {
01053         SDL_Surface *rz_src;
01054         SDL_Surface *rz_dst;
01055         double zoominv;
01056         double sanglezoom, canglezoom, sanglezoominv, canglezoominv;
01057         int dstwidthhalf, dstwidth, dstheighthalf, dstheight;
01058         int is32bit;
01059         int i, src_converted;
01060         int flipx,flipy;
01061         Uint8 r,g,b;
01062         Uint32 colorkey = 0;
01063         int colorKeyAvailable = 0;
01064 
01065         /*
01066         * Sanity check 
01067         */
01068         if (src == NULL)
01069                 return (NULL);
01070 
01071         if (src->flags & SDL_SRCCOLORKEY)
01072         {
01073                 colorkey = _colorkey(src);
01074                 SDL_GetRGB(colorkey, src->format, &r, &g, &b);
01075                 colorKeyAvailable = 1;
01076         }
01077         /*
01078         * Determine if source surface is 32bit or 8bit 
01079         */
01080         is32bit = (src->format->BitsPerPixel == 32);
01081         if ((is32bit) || (src->format->BitsPerPixel == 8)) {
01082                 /*
01083                 * Use source surface 'as is' 
01084                 */
01085                 rz_src = src;
01086                 src_converted = 0;
01087         } else {
01088                 /*
01089                 * New source surface is 32bit with a defined RGBA ordering 
01090                 */
01091                 rz_src =
01092                         SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, 
01093 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
01094                         0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
01095 #else
01096                         0xff000000,  0x00ff0000, 0x0000ff00, 0x000000ff
01097 #endif
01098                         );
01099                 if(colorKeyAvailable)
01100                         SDL_SetColorKey(src, 0, 0);
01101 
01102                 SDL_BlitSurface(src, NULL, rz_src, NULL);
01103 
01104                 if(colorKeyAvailable)
01105                         SDL_SetColorKey(src, SDL_SRCCOLORKEY, colorkey);
01106                 src_converted = 1;
01107                 is32bit = 1;
01108         }
01109 
01110         /*
01111         * Sanity check zoom factor 
01112         */
01113         flipx = (zoomx<0.0);
01114         if (flipx) zoomx=-zoomx;
01115         flipy = (zoomy<0.0);
01116         if (flipy) zoomy=-zoomy;
01117         if (zoomx < VALUE_LIMIT) zoomx = VALUE_LIMIT;
01118         if (zoomy < VALUE_LIMIT) zoomy = VALUE_LIMIT;
01119         zoominv = 65536.0 / (zoomx * zoomx);
01120 
01121         /*
01122         * Check if we have a rotozoom or just a zoom 
01123         */
01124         if (fabs(angle) > VALUE_LIMIT) {
01125 
01126                 /*
01127                 * Angle!=0: full rotozoom 
01128                 */
01129                 /*
01130                 * ----------------------- 
01131                 */
01132 
01133                 /* Determine target size */
01134                 _rotozoomSurfaceSizeTrig(rz_src->w, rz_src->h, angle, zoomx, zoomy, &dstwidth, &dstheight, &canglezoom, &sanglezoom);
01135 
01136                 /*
01137                 * Calculate target factors from sin/cos and zoom 
01138                 */
01139                 sanglezoominv = sanglezoom;
01140                 canglezoominv = canglezoom;
01141                 sanglezoominv *= zoominv;
01142                 canglezoominv *= zoominv;
01143 
01144                 /* Calculate half size */
01145                 dstwidthhalf = dstwidth / 2;
01146                 dstheighthalf = dstheight / 2;
01147 
01148                 /*
01149                 * Alloc space to completely contain the rotated surface 
01150                 */
01151                 rz_dst = NULL;
01152                 if (is32bit) {
01153                         /*
01154                         * Target surface is 32bit with source RGBA/ABGR ordering 
01155                         */
01156                         rz_dst =
01157                                 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
01158                                 rz_src->format->Rmask, rz_src->format->Gmask,
01159                                 rz_src->format->Bmask, rz_src->format->Amask);
01160                 } else {
01161                         /*
01162                         * Target surface is 8bit 
01163                         */
01164                         rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
01165                 }
01166 
01167                 /* Check target */
01168                 if (rz_dst == NULL)
01169                         return NULL;
01170 
01171                 /* Adjust for guard rows */
01172                 rz_dst->h = dstheight;
01173 
01174                 if (colorKeyAvailable == 1){
01175                         colorkey = SDL_MapRGB(rz_dst->format, r, g, b);
01176 
01177                         SDL_FillRect(rz_dst, NULL, colorkey );
01178                 }
01179 
01180                 /*
01181                 * Lock source surface 
01182                 */
01183                 if (SDL_MUSTLOCK(rz_src)) {
01184                         SDL_LockSurface(rz_src);
01185                 }
01186 
01187                 /*
01188                 * Check which kind of surface we have 
01189                 */
01190                 if (is32bit) {
01191                         /*
01192                         * Call the 32bit transformation routine to do the rotation (using alpha) 
01193                         */
01194                         _transformSurfaceRGBA(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
01195                                 (int) (sanglezoominv), (int) (canglezoominv), 
01196                                 flipx, flipy,
01197                                 smooth);
01198                         /*
01199                         * Turn on source-alpha support 
01200                         */
01201                         SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
01202                         SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
01203                 } else {
01204                         /*
01205                         * Copy palette and colorkey info 
01206                         */
01207                         for (i = 0; i < rz_src->format->palette->ncolors; i++) {
01208                                 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
01209                         }
01210                         rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
01211                         /*
01212                         * Call the 8bit transformation routine to do the rotation 
01213                         */
01214                         transformSurfaceY(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
01215                                 (int) (sanglezoominv), (int) (canglezoominv),
01216                                 flipx, flipy);
01217                         SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
01218                 }
01219                 /*
01220                 * Unlock source surface 
01221                 */
01222                 if (SDL_MUSTLOCK(rz_src)) {
01223                         SDL_UnlockSurface(rz_src);
01224                 }
01225 
01226         } else {
01227 
01228                 /*
01229                 * Angle=0: Just a zoom 
01230                 */
01231                 /*
01232                 * -------------------- 
01233                 */
01234 
01235                 /*
01236                 * Calculate target size
01237                 */
01238                 zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
01239 
01240                 /*
01241                 * Alloc space to completely contain the zoomed surface 
01242                 */
01243                 rz_dst = NULL;
01244                 if (is32bit) {
01245                         /*
01246                         * Target surface is 32bit with source RGBA/ABGR ordering 
01247                         */
01248                         rz_dst =
01249                                 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
01250                                 rz_src->format->Rmask, rz_src->format->Gmask,
01251                                 rz_src->format->Bmask, rz_src->format->Amask);
01252                 } else {
01253                         /*
01254                         * Target surface is 8bit 
01255                         */
01256                         rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
01257                 }
01258 
01259                 /* Check target */
01260                 if (rz_dst == NULL)
01261                         return NULL;
01262 
01263                 /* Adjust for guard rows */
01264                 rz_dst->h = dstheight;
01265 
01266                 if (colorKeyAvailable == 1){
01267                         colorkey = SDL_MapRGB(rz_dst->format, r, g, b);
01268 
01269                         SDL_FillRect(rz_dst, NULL, colorkey );
01270                 }
01271 
01272                 /*
01273                 * Lock source surface 
01274                 */
01275                 if (SDL_MUSTLOCK(rz_src)) {
01276                         SDL_LockSurface(rz_src);
01277                 }
01278 
01279                 /*
01280                 * Check which kind of surface we have 
01281                 */
01282                 if (is32bit) {
01283                         /*
01284                         * Call the 32bit transformation routine to do the zooming (using alpha) 
01285                         */
01286                         _zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
01287 
01288                         /*
01289                         * Turn on source-alpha support 
01290                         */
01291                         SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
01292                         SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
01293                 } else {
01294                         /*
01295                         * Copy palette and colorkey info 
01296                         */
01297                         for (i = 0; i < rz_src->format->palette->ncolors; i++) {
01298                                 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
01299                         }
01300                         rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
01301 
01302                         /*
01303                         * Call the 8bit transformation routine to do the zooming 
01304                         */
01305                         _zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
01306                         SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
01307                 }
01308 
01309                 /*
01310                 * Unlock source surface 
01311                 */
01312                 if (SDL_MUSTLOCK(rz_src)) {
01313                         SDL_UnlockSurface(rz_src);
01314                 }
01315         }
01316 
01317         /*
01318         * Cleanup temp surface 
01319         */
01320         if (src_converted) {
01321                 SDL_FreeSurface(rz_src);
01322         }
01323 
01324         /*
01325         * Return destination surface 
01326         */
01327         return (rz_dst);
01328 }
01329 
01342 void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight)
01343 {
01344         /*
01345         * Make zoom factors positive 
01346         */
01347         int flipx, flipy;
01348         flipx = (zoomx<0.0);
01349         if (flipx) zoomx = -zoomx;
01350         flipy = (zoomy<0.0);
01351         if (flipy) zoomy = -zoomy;
01352 
01353         /*
01354         * Sanity check zoom factors 
01355         */
01356         if (zoomx < VALUE_LIMIT) {
01357                 zoomx = VALUE_LIMIT;
01358         }
01359         if (zoomy < VALUE_LIMIT) {
01360                 zoomy = VALUE_LIMIT;
01361         }
01362 
01363         /*
01364         * Calculate target size 
01365         */
01366         *dstwidth = (int) floor(((double) width * zoomx) + 0.5);
01367         *dstheight = (int) floor(((double) height * zoomy) + 0.5);
01368         if (*dstwidth < 1) {
01369                 *dstwidth = 1;
01370         }
01371         if (*dstheight < 1) {
01372                 *dstheight = 1;
01373         }
01374 }
01375 
01392 SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth)
01393 {
01394         SDL_Surface *rz_src;
01395         SDL_Surface *rz_dst;
01396         int dstwidth, dstheight;
01397         int is32bit;
01398         int i, src_converted;
01399         int flipx, flipy;
01400 
01401         /*
01402         * Sanity check 
01403         */
01404         if (src == NULL)
01405                 return (NULL);
01406 
01407         /*
01408         * Determine if source surface is 32bit or 8bit 
01409         */
01410         is32bit = (src->format->BitsPerPixel == 32);
01411         if ((is32bit) || (src->format->BitsPerPixel == 8)) {
01412                 /*
01413                 * Use source surface 'as is' 
01414                 */
01415                 rz_src = src;
01416                 src_converted = 0;
01417         } else {
01418                 /*
01419                 * New source surface is 32bit with a defined RGBA ordering 
01420                 */
01421                 rz_src =
01422                         SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, 
01423 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
01424                         0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
01425 #else
01426                         0xff000000,  0x00ff0000, 0x0000ff00, 0x000000ff
01427 #endif
01428                         );
01429                 if (rz_src == NULL) {
01430                         return NULL;
01431                 }
01432                 SDL_BlitSurface(src, NULL, rz_src, NULL);
01433                 src_converted = 1;
01434                 is32bit = 1;
01435         }
01436 
01437         flipx = (zoomx<0.0);
01438         if (flipx) zoomx = -zoomx;
01439         flipy = (zoomy<0.0);
01440         if (flipy) zoomy = -zoomy;
01441 
01442         /* Get size if target */
01443         zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
01444 
01445         /*
01446         * Alloc space to completely contain the zoomed surface 
01447         */
01448         rz_dst = NULL;
01449         if (is32bit) {
01450                 /*
01451                 * Target surface is 32bit with source RGBA/ABGR ordering 
01452                 */
01453                 rz_dst =
01454                         SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
01455                         rz_src->format->Rmask, rz_src->format->Gmask,
01456                         rz_src->format->Bmask, rz_src->format->Amask);
01457         } else {
01458                 /*
01459                 * Target surface is 8bit 
01460                 */
01461                 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
01462         }
01463 
01464         /* Check target */
01465         if (rz_dst == NULL) {
01466                 /*
01467                 * Cleanup temp surface 
01468                 */
01469                 if (src_converted) {
01470                         SDL_FreeSurface(rz_src);
01471                 }               
01472                 return NULL;
01473         }
01474 
01475         /* Adjust for guard rows */
01476         rz_dst->h = dstheight;
01477 
01478         /*
01479         * Lock source surface 
01480         */
01481         if (SDL_MUSTLOCK(rz_src)) {
01482                 SDL_LockSurface(rz_src);
01483         }
01484 
01485         /*
01486         * Check which kind of surface we have 
01487         */
01488         if (is32bit) {
01489                 /*
01490                 * Call the 32bit transformation routine to do the zooming (using alpha) 
01491                 */
01492                 _zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
01493                 /*
01494                 * Turn on source-alpha support 
01495                 */
01496                 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
01497         } else {
01498                 /*
01499                 * Copy palette and colorkey info 
01500                 */
01501                 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
01502                         rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
01503                 }
01504                 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
01505                 /*
01506                 * Call the 8bit transformation routine to do the zooming 
01507                 */
01508                 _zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
01509                 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
01510         }
01511         /*
01512         * Unlock source surface 
01513         */
01514         if (SDL_MUSTLOCK(rz_src)) {
01515                 SDL_UnlockSurface(rz_src);
01516         }
01517 
01518         /*
01519         * Cleanup temp surface 
01520         */
01521         if (src_converted) {
01522                 SDL_FreeSurface(rz_src);
01523         }
01524 
01525         /*
01526         * Return destination surface 
01527         */
01528         return (rz_dst);
01529 }
01530 
01547 /*@null@*/ 
01548 SDL_Surface *shrinkSurface(SDL_Surface *src, int factorx, int factory)
01549 {
01550         int result;
01551         SDL_Surface *rz_src;
01552         SDL_Surface *rz_dst = NULL;
01553         int dstwidth, dstheight;
01554         int is32bit;
01555         int i, src_converted;
01556         int haveError = 0;
01557 
01558         /*
01559         * Sanity check 
01560         */
01561         if (src == NULL) {
01562                 return (NULL);
01563         }
01564 
01565         /*
01566         * Determine if source surface is 32bit or 8bit 
01567         */
01568         is32bit = (src->format->BitsPerPixel == 32);
01569         if ((is32bit) || (src->format->BitsPerPixel == 8)) {
01570                 /*
01571                 * Use source surface 'as is' 
01572                 */
01573                 rz_src = src;
01574                 src_converted = 0;
01575         } else {
01576                 /*
01577                 * New source surface is 32bit with a defined RGBA ordering 
01578                 */
01579                 rz_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, 
01580 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
01581                         0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
01582 #else
01583                         0xff000000,  0x00ff0000, 0x0000ff00, 0x000000ff
01584 #endif
01585                         );
01586                 if (rz_src==NULL) {
01587                         haveError = 1;
01588                         goto exitShrinkSurface;
01589                 }
01590 
01591                 SDL_BlitSurface(src, NULL, rz_src, NULL);
01592                 src_converted = 1;
01593                 is32bit = 1;
01594         }
01595 
01596         /*
01597         * Lock the surface 
01598         */
01599         if (SDL_MUSTLOCK(rz_src)) {
01600                 if (SDL_LockSurface(rz_src) < 0) {
01601                         haveError = 1;
01602                         goto exitShrinkSurface;
01603                 }
01604         }
01605 
01606         /* Get size for target */
01607         dstwidth=rz_src->w/factorx;
01608         while (dstwidth*factorx>rz_src->w) { dstwidth--; }
01609         dstheight=rz_src->h/factory;
01610         while (dstheight*factory>rz_src->h) { dstheight--; }
01611 
01612         /*
01613         * Alloc space to completely contain the shrunken surface
01614         * (with added guard rows)
01615         */
01616         if (is32bit==1) {
01617                 /*
01618                 * Target surface is 32bit with source RGBA/ABGR ordering 
01619                 */
01620                 rz_dst =
01621                         SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
01622                         rz_src->format->Rmask, rz_src->format->Gmask,
01623                         rz_src->format->Bmask, rz_src->format->Amask);
01624         } else {
01625                 /*
01626                 * Target surface is 8bit 
01627                 */
01628                 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
01629         }
01630 
01631         /* Check target */
01632         if (rz_dst == NULL) {
01633                 haveError = 1;
01634                 goto exitShrinkSurface;
01635         }
01636 
01637         /* Adjust for guard rows */
01638         rz_dst->h = dstheight;
01639 
01640         /*
01641         * Check which kind of surface we have 
01642         */
01643         if (is32bit==1) {
01644                 /*
01645                 * Call the 32bit transformation routine to do the shrinking (using alpha) 
01646                 */
01647                 result = _shrinkSurfaceRGBA(rz_src, rz_dst, factorx, factory);          
01648                 if ((result!=0) || (rz_dst==NULL)) {
01649                         haveError = 1;
01650                         goto exitShrinkSurface;
01651                 }
01652 
01653                 /*
01654                 * Turn on source-alpha support 
01655                 */
01656                 result = SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
01657                 if (result!=0) {
01658                         haveError = 1;
01659                         goto exitShrinkSurface;
01660                 }
01661         } else {
01662                 /*
01663                 * Copy palette and colorkey info 
01664                 */
01665                 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
01666                         rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
01667                 }
01668                 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
01669                 /*
01670                 * Call the 8bit transformation routine to do the shrinking 
01671                 */
01672                 result = _shrinkSurfaceY(rz_src, rz_dst, factorx, factory);
01673                 if (result!=0) {
01674                         haveError = 1;
01675                         goto exitShrinkSurface;
01676                 }
01677 
01678                 /*
01679                 * Set colorkey on target
01680                 */
01681                 result = SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
01682                 if (result!=0) {
01683                         haveError = 1;
01684                         goto exitShrinkSurface;
01685                 }               
01686         }
01687 
01688 exitShrinkSurface:
01689         if (rz_src!=NULL) {
01690                 /*
01691                 * Unlock source surface 
01692                 */
01693                 if (SDL_MUSTLOCK(rz_src)) {
01694                         SDL_UnlockSurface(rz_src);
01695                 }
01696 
01697                 /*
01698                 * Cleanup temp surface 
01699                 */
01700                 if (src_converted==1) {
01701                         SDL_FreeSurface(rz_src);
01702                 }
01703         }
01704 
01705         /* Check error state; maybe need to cleanup destination */
01706         if (haveError==1) {
01707                 if (rz_dst!=NULL) {
01708                         SDL_FreeSurface(rz_dst);
01709                 }
01710                 rz_dst=NULL;
01711         } 
01712 
01713         /*
01714         * Return destination surface 
01715         */
01716         return (rz_dst);
01717 }