SDL2_gfx  1.0.1
GraphicsprimitivesandsurfacefunctionsforSDL2
I:/Sources/sdl2gfx/SDL2_rotozoom.c
Go to the documentation of this file.
00001 /*  
00002 
00003 SDL2_rotozoom.c: rotozoomer, zoomer and shrinker for 32bit or 8bit surfaces
00004 
00005 Copyright (C) 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 "SDL2_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         SDL_GetColorKey(src, &key);
00087         return key;
00088 }
00089 
00090 
00106 int _shrinkSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
00107 {
00108         int x, y, dx, dy, dgap, ra, ga, ba, aa;
00109         int n_average;
00110         tColorRGBA *sp, *osp, *oosp;
00111         tColorRGBA *dp;
00112 
00113         /*
00114         * Averaging integer shrink
00115         */
00116 
00117         /* Precalculate division factor */
00118         n_average = factorx*factory;
00119 
00120         /*
00121         * Scan destination
00122         */
00123         sp = (tColorRGBA *) src->pixels;
00124         
00125         dp = (tColorRGBA *) dst->pixels;
00126         dgap = dst->pitch - dst->w * 4;
00127 
00128         for (y = 0; y < dst->h; y++) {
00129 
00130                 osp=sp;
00131                 for (x = 0; x < dst->w; x++) {
00132 
00133                         /* Trace out source box and accumulate */
00134                         oosp=sp;
00135                         ra=ga=ba=aa=0;
00136                         for (dy=0; dy < factory; dy++) {
00137                                 for (dx=0; dx < factorx; dx++) {
00138                                         ra += sp->r;
00139                                         ga += sp->g;
00140                                         ba += sp->b;
00141                                         aa += sp->a;
00142 
00143                                         sp++;
00144                                 } 
00145                                 /* src dx loop */
00146                                 sp = (tColorRGBA *)((Uint8*)sp + (src->pitch - 4*factorx)); // next y
00147                         }
00148                         /* src dy loop */
00149 
00150                         /* next box-x */
00151                         sp = (tColorRGBA *)((Uint8*)oosp + 4*factorx);
00152 
00153                         /* Store result in destination */
00154                         dp->r = ra/n_average;
00155                         dp->g = ga/n_average;
00156                         dp->b = ba/n_average;
00157                         dp->a = aa/n_average;
00158 
00159                         /*
00160                         * Advance destination pointer 
00161                         */
00162                         dp++;
00163                 } 
00164                 /* dst x loop */
00165 
00166                 /* next box-y */
00167                 sp = (tColorRGBA *)((Uint8*)osp + src->pitch*factory);
00168 
00169                 /*
00170                 * Advance destination pointers 
00171                 */
00172                 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
00173         } 
00174         /* dst y loop */
00175 
00176         return (0);
00177 }
00178 
00194 int _shrinkSurfaceY(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
00195 {
00196         int x, y, dx, dy, dgap, a;
00197         int n_average;
00198         Uint8 *sp, *osp, *oosp;
00199         Uint8 *dp;
00200 
00201         /*
00202         * Averaging integer shrink
00203         */
00204 
00205         /* Precalculate division factor */
00206         n_average = factorx*factory;
00207 
00208         /*
00209         * Scan destination
00210         */
00211         sp = (Uint8 *) src->pixels;
00212 
00213         dp = (Uint8 *) dst->pixels;
00214         dgap = dst->pitch - dst->w;
00215 
00216         for (y = 0; y < dst->h; y++) {    
00217 
00218                 osp=sp;
00219                 for (x = 0; x < dst->w; x++) {
00220 
00221                         /* Trace out source box and accumulate */
00222                         oosp=sp;
00223                         a=0;
00224                         for (dy=0; dy < factory; dy++) {
00225                                 for (dx=0; dx < factorx; dx++) {
00226                                         a += (*sp);
00227                                         /* next x */           
00228                                         sp++;
00229                                 } 
00230                                 /* end src dx loop */         
00231                                 /* next y */
00232                                 sp = (Uint8 *)((Uint8*)sp + (src->pitch - factorx)); 
00233                         } 
00234                         /* end src dy loop */
00235 
00236                         /* next box-x */
00237                         sp = (Uint8 *)((Uint8*)oosp + factorx);
00238 
00239                         /* Store result in destination */
00240                         *dp = a/n_average;
00241 
00242                         /*
00243                         * Advance destination pointer 
00244                         */
00245                         dp++;
00246                 } 
00247                 /* end dst x loop */
00248 
00249                 /* next box-y */
00250                 sp = (Uint8 *)((Uint8*)osp + src->pitch*factory);
00251 
00252                 /*
00253                 * Advance destination pointers 
00254                 */
00255                 dp = (Uint8 *)((Uint8 *)dp + dgap);
00256         } 
00257         /* end dst y loop */
00258 
00259         return (0);
00260 }
00261 
00277 int _zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy, int smooth)
00278 {
00279         int x, y, sx, sy, ssx, ssy, *sax, *say, *csax, *csay, *salast, csx, csy, ex, ey, cx, cy, sstep, sstepx, sstepy;
00280         tColorRGBA *c00, *c01, *c10, *c11;
00281         tColorRGBA *sp, *csp, *dp;
00282         int spixelgap, spixelw, spixelh, dgap, t1, t2;
00283 
00284         /*
00285         * Allocate memory for row/column increments 
00286         */
00287         if ((sax = (int *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
00288                 return (-1);
00289         }
00290         if ((say = (int *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
00291                 free(sax);
00292                 return (-1);
00293         }
00294 
00295         /*
00296         * Precalculate row increments 
00297         */
00298         spixelw = (src->w - 1);
00299         spixelh = (src->h - 1);
00300         if (smooth) {
00301                 sx = (int) (65536.0 * (float) spixelw / (float) (dst->w - 1));
00302                 sy = (int) (65536.0 * (float) spixelh / (float) (dst->h - 1));
00303         } else {
00304                 sx = (int) (65536.0 * (float) (src->w) / (float) (dst->w));
00305                 sy = (int) (65536.0 * (float) (src->h) / (float) (dst->h));
00306         }
00307 
00308         /* Maximum scaled source size */
00309         ssx = (src->w << 16) - 1;
00310         ssy = (src->h << 16) - 1;
00311 
00312         /* Precalculate horizontal row increments */
00313         csx = 0;
00314         csax = sax;
00315         for (x = 0; x <= dst->w; x++) {
00316                 *csax = csx;
00317                 csax++;
00318                 csx += sx;
00319 
00320                 /* Guard from overflows */
00321                 if (csx > ssx) { 
00322                         csx = ssx; 
00323                 }
00324         }
00325 
00326         /* Precalculate vertical row increments */
00327         csy = 0;
00328         csay = say;
00329         for (y = 0; y <= dst->h; y++) {
00330                 *csay = csy;
00331                 csay++;
00332                 csy += sy;
00333 
00334                 /* Guard from overflows */
00335                 if (csy > ssy) {
00336                         csy = ssy;
00337                 }
00338         }
00339 
00340         sp = (tColorRGBA *) src->pixels;
00341         dp = (tColorRGBA *) dst->pixels;
00342         dgap = dst->pitch - dst->w * 4;
00343         spixelgap = src->pitch/4;
00344 
00345         if (flipx) sp += spixelw;
00346         if (flipy) sp += (spixelgap * spixelh);
00347 
00348         /*
00349         * Switch between interpolating and non-interpolating code 
00350         */
00351         if (smooth) {
00352 
00353                 /*
00354                 * Interpolating Zoom 
00355                 */
00356                 csay = say;
00357                 for (y = 0; y < dst->h; y++) {
00358                         csp = sp;
00359                         csax = sax;
00360                         for (x = 0; x < dst->w; x++) {
00361                                 /*
00362                                 * Setup color source pointers 
00363                                 */
00364                                 ex = (*csax & 0xffff);
00365                                 ey = (*csay & 0xffff);
00366                                 cx = (*csax >> 16);
00367                                 cy = (*csay >> 16);
00368                                 sstepx = cx < spixelw;
00369                                 sstepy = cy < spixelh;
00370                                 c00 = sp;
00371                                 c01 = sp;
00372                                 c10 = sp;
00373                                 if (sstepy) {
00374                                         if (flipy) {
00375                                                 c10 -= spixelgap;
00376                                         } else {
00377                                                 c10 += spixelgap;
00378                                         }
00379                                 }
00380                                 c11 = c10;
00381                                 if (sstepx) {
00382                                         if (flipx) {
00383                                                 c01--;
00384                                                 c11--;
00385                                         } else {
00386                                                 c01++;
00387                                                 c11++;
00388                                         }
00389                                 }
00390 
00391                                 /*
00392                                 * Draw and interpolate colors 
00393                                 */
00394                                 t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
00395                                 t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
00396                                 dp->r = (((t2 - t1) * ey) >> 16) + t1;
00397                                 t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff;
00398                                 t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff;
00399                                 dp->g = (((t2 - t1) * ey) >> 16) + t1;
00400                                 t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff;
00401                                 t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff;
00402                                 dp->b = (((t2 - t1) * ey) >> 16) + t1;
00403                                 t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff;
00404                                 t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff;
00405                                 dp->a = (((t2 - t1) * ey) >> 16) + t1;                          
00406                                 /*
00407                                 * Advance source pointer x
00408                                 */
00409                                 salast = csax;
00410                                 csax++;                         
00411                                 sstep = (*csax >> 16) - (*salast >> 16);
00412                                 if (flipx) {
00413                                         sp -= sstep;
00414                                 } else {
00415                                         sp += sstep;
00416                                 }
00417 
00418                                 /*
00419                                 * Advance destination pointer x
00420                                 */
00421                                 dp++;
00422                         }
00423                         /*
00424                         * Advance source pointer y
00425                         */
00426                         salast = csay;
00427                         csay++;
00428                         sstep = (*csay >> 16) - (*salast >> 16);
00429                         sstep *= spixelgap;
00430                         if (flipy) { 
00431                                 sp = csp - sstep;
00432                         } else {
00433                                 sp = csp + sstep;
00434                         }
00435 
00436                         /*
00437                         * Advance destination pointer y
00438                         */
00439                         dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
00440                 }
00441         } else {
00442                 /*
00443                 * Non-Interpolating Zoom 
00444                 */              
00445                 csay = say;
00446                 for (y = 0; y < dst->h; y++) {
00447                         csp = sp;
00448                         csax = sax;
00449                         for (x = 0; x < dst->w; x++) {
00450                                 /*
00451                                 * Draw 
00452                                 */
00453                                 *dp = *sp;
00454 
00455                                 /*
00456                                 * Advance source pointer x
00457                                 */
00458                                 salast = csax;
00459                                 csax++;                         
00460                                 sstep = (*csax >> 16) - (*salast >> 16);
00461                                 if (flipx) sstep = -sstep;
00462                                 sp += sstep;
00463 
00464                                 /*
00465                                 * Advance destination pointer x
00466                                 */
00467                                 dp++;
00468                         }
00469                         /*
00470                         * Advance source pointer y
00471                         */
00472                         salast = csay;
00473                         csay++;
00474                         sstep = (*csay >> 16) - (*salast >> 16);
00475                         sstep *= spixelgap;
00476                         if (flipy) sstep = -sstep;                      
00477                         sp = csp + sstep;
00478 
00479                         /*
00480                         * Advance destination pointer y
00481                         */
00482                         dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
00483                 }
00484         }
00485 
00486         /*
00487         * Remove temp arrays 
00488         */
00489         free(sax);
00490         free(say);
00491 
00492         return (0);
00493 }
00494 
00510 int _zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy)
00511 {
00512         int x, y;
00513         Uint32 *sax, *say, *csax, *csay;
00514         int csx, csy;
00515         Uint8 *sp, *dp, *csp;
00516         int dgap;
00517 
00518         /*
00519         * Allocate memory for row increments 
00520         */
00521         if ((sax = (Uint32 *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
00522                 return (-1);
00523         }
00524         if ((say = (Uint32 *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
00525                 free(sax);
00526                 return (-1);
00527         }
00528 
00529         /*
00530         * Pointer setup 
00531         */
00532         sp = csp = (Uint8 *) src->pixels;
00533         dp = (Uint8 *) dst->pixels;
00534         dgap = dst->pitch - dst->w;
00535 
00536         if (flipx) csp += (src->w-1);
00537         if (flipy) csp  = ( (Uint8*)csp + src->pitch*(src->h-1) );
00538 
00539         /*
00540         * Precalculate row increments 
00541         */
00542         csx = 0;
00543         csax = sax;
00544         for (x = 0; x < dst->w; x++) {
00545                 csx += src->w;
00546                 *csax = 0;
00547                 while (csx >= dst->w) {
00548                         csx -= dst->w;
00549                         (*csax)++;
00550                 }
00551                 (*csax) = (*csax) * (flipx ? -1 : 1);
00552                 csax++;
00553         }
00554         csy = 0;
00555         csay = say;
00556         for (y = 0; y < dst->h; y++) {
00557                 csy += src->h;
00558                 *csay = 0;
00559                 while (csy >= dst->h) {
00560                         csy -= dst->h;
00561                         (*csay)++;
00562                 }
00563                 (*csay) = (*csay) * (flipy ? -1 : 1);
00564                 csay++;
00565         }
00566 
00567         /*
00568         * Draw 
00569         */
00570         csay = say;
00571         for (y = 0; y < dst->h; y++) {
00572                 csax = sax;
00573                 sp = csp;
00574                 for (x = 0; x < dst->w; x++) {
00575                         /*
00576                         * Draw 
00577                         */
00578                         *dp = *sp;
00579                         /*
00580                         * Advance source pointers 
00581                         */
00582                         sp += (*csax);
00583                         csax++;
00584                         /*
00585                         * Advance destination pointer 
00586                         */
00587                         dp++;
00588                 }
00589                 /*
00590                 * Advance source pointer (for row) 
00591                 */
00592                 csp += ((*csay) * src->pitch);
00593                 csay++;
00594 
00595                 /*
00596                 * Advance destination pointers 
00597                 */
00598                 dp += dgap;
00599         }
00600 
00601         /*
00602         * Remove temp arrays 
00603         */
00604         free(sax);
00605         free(say);
00606 
00607         return (0);
00608 }
00609 
00629 void _transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy, int smooth)
00630 {
00631         int x, y, t1, t2, dx, dy, xd, yd, sdx, sdy, ax, ay, ex, ey, sw, sh;
00632         tColorRGBA c00, c01, c10, c11, cswap;
00633         tColorRGBA *pc, *sp;
00634         int gap;
00635 
00636         /*
00637         * Variable setup 
00638         */
00639         xd = ((src->w - dst->w) << 15);
00640         yd = ((src->h - dst->h) << 15);
00641         ax = (cx << 16) - (icos * cx);
00642         ay = (cy << 16) - (isin * cx);
00643         sw = src->w - 1;
00644         sh = src->h - 1;
00645         pc = (tColorRGBA*) dst->pixels;
00646         gap = dst->pitch - dst->w * 4;
00647 
00648         /*
00649         * Switch between interpolating and non-interpolating code 
00650         */
00651         if (smooth) {
00652                 for (y = 0; y < dst->h; y++) {
00653                         dy = cy - y;
00654                         sdx = (ax + (isin * dy)) + xd;
00655                         sdy = (ay - (icos * dy)) + yd;
00656                         for (x = 0; x < dst->w; x++) {
00657                                 dx = (sdx >> 16);
00658                                 dy = (sdy >> 16);
00659                                 if (flipx) dx = sw - dx;
00660                                 if (flipy) dy = sh - dy;
00661                                 if ((dx > -1) && (dy > -1) && (dx < (src->w-1)) && (dy < (src->h-1))) {
00662                                         sp = (tColorRGBA *)src->pixels;;
00663                                         sp += ((src->pitch/4) * dy);
00664                                         sp += dx;
00665                                         c00 = *sp;
00666                                         sp += 1;
00667                                         c01 = *sp;
00668                                         sp += (src->pitch/4);
00669                                         c11 = *sp;
00670                                         sp -= 1;
00671                                         c10 = *sp;
00672                                         if (flipx) {
00673                                                 cswap = c00; c00=c01; c01=cswap;
00674                                                 cswap = c10; c10=c11; c11=cswap;
00675                                         }
00676                                         if (flipy) {
00677                                                 cswap = c00; c00=c10; c10=cswap;
00678                                                 cswap = c01; c01=c11; c11=cswap;
00679                                         }
00680                                         /*
00681                                         * Interpolate colors 
00682                                         */
00683                                         ex = (sdx & 0xffff);
00684                                         ey = (sdy & 0xffff);
00685                                         t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff;
00686                                         t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff;
00687                                         pc->r = (((t2 - t1) * ey) >> 16) + t1;
00688                                         t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff;
00689                                         t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff;
00690                                         pc->g = (((t2 - t1) * ey) >> 16) + t1;
00691                                         t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff;
00692                                         t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff;
00693                                         pc->b = (((t2 - t1) * ey) >> 16) + t1;
00694                                         t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff;
00695                                         t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff;
00696                                         pc->a = (((t2 - t1) * ey) >> 16) + t1;
00697                                 }
00698                                 sdx += icos;
00699                                 sdy += isin;
00700                                 pc++;
00701                         }
00702                         pc = (tColorRGBA *) ((Uint8 *) pc + gap);
00703                 }
00704         } else {
00705                 for (y = 0; y < dst->h; y++) {
00706                         dy = cy - y;
00707                         sdx = (ax + (isin * dy)) + xd;
00708                         sdy = (ay - (icos * dy)) + yd;
00709                         for (x = 0; x < dst->w; x++) {
00710                                 dx = (short) (sdx >> 16);
00711                                 dy = (short) (sdy >> 16);
00712                                 if (flipx) dx = (src->w-1)-dx;
00713                                 if (flipy) dy = (src->h-1)-dy;
00714                                 if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
00715                                         sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
00716                                         sp += dx;
00717                                         *pc = *sp;
00718                                 }
00719                                 sdx += icos;
00720                                 sdy += isin;
00721                                 pc++;
00722                         }
00723                         pc = (tColorRGBA *) ((Uint8 *) pc + gap);
00724                 }
00725         }
00726 }
00727 
00746 void transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy)
00747 {
00748         int x, y, dx, dy, xd, yd, sdx, sdy, ax, ay;
00749         tColorY *pc, *sp;
00750         int gap;
00751 
00752         /*
00753         * Variable setup 
00754         */
00755         xd = ((src->w - dst->w) << 15);
00756         yd = ((src->h - dst->h) << 15);
00757         ax = (cx << 16) - (icos * cx);
00758         ay = (cy << 16) - (isin * cx);
00759         pc = (tColorY*) dst->pixels;
00760         gap = dst->pitch - dst->w;
00761         /*
00762         * Clear surface to colorkey 
00763         */      
00764         memset(pc, (int)(_colorkey(src) & 0xff), dst->pitch * dst->h);
00765         /*
00766         * Iterate through destination surface 
00767         */
00768         for (y = 0; y < dst->h; y++) {
00769                 dy = cy - y;
00770                 sdx = (ax + (isin * dy)) + xd;
00771                 sdy = (ay - (icos * dy)) + yd;
00772                 for (x = 0; x < dst->w; x++) {
00773                         dx = (short) (sdx >> 16);
00774                         dy = (short) (sdy >> 16);
00775                         if (flipx) dx = (src->w-1)-dx;
00776                         if (flipy) dy = (src->h-1)-dy;
00777                         if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
00778                                 sp = (tColorY *) (src->pixels);
00779                                 sp += (src->pitch * dy + dx);
00780                                 *pc = *sp;
00781                         }
00782                         sdx += icos;
00783                         sdy += isin;
00784                         pc++;
00785                 }
00786                 pc += gap;
00787         }
00788 }
00789 
00803 SDL_Surface* rotateSurface90Degrees(SDL_Surface* src, int numClockwiseTurns) 
00804 {
00805         int row, col, newWidth, newHeight;
00806         int bpp, bpr;
00807         SDL_Surface* dst;
00808         Uint8* srcBuf;
00809         Uint8* dstBuf;
00810         int normalizedClockwiseTurns;
00811 
00812         /* Has to be a valid surface pointer and be a Nbit surface where n is divisible by 8 */
00813         if (!src || 
00814             !src->format) {
00815                 SDL_SetError("NULL source surface or source surface format");
00816             return NULL; 
00817         }
00818 
00819         if ((src->format->BitsPerPixel % 8) != 0) {
00820                 SDL_SetError("Invalid source surface bit depth");
00821             return NULL; 
00822         }
00823 
00824         /* normalize numClockwiseTurns */
00825         normalizedClockwiseTurns = (numClockwiseTurns % 4);
00826         if (normalizedClockwiseTurns < 0) {
00827                 normalizedClockwiseTurns += 4;
00828         }
00829 
00830         /* If turns are even, our new width/height will be the same as the source surface */
00831         if (normalizedClockwiseTurns % 2) {
00832                 newWidth = src->h;
00833                 newHeight = src->w;
00834         } else {
00835                 newWidth = src->w;
00836                 newHeight = src->h;
00837         }
00838 
00839         dst = SDL_CreateRGBSurface( src->flags, newWidth, newHeight, src->format->BitsPerPixel,
00840                 src->format->Rmask,
00841                 src->format->Gmask, 
00842                 src->format->Bmask, 
00843                 src->format->Amask);
00844         if(!dst) {
00845                 SDL_SetError("Could not create destination surface"); 
00846                 return NULL;
00847         }
00848 
00849         if (SDL_MUSTLOCK(src)) {
00850                 SDL_LockSurface(src);
00851         }
00852         if (SDL_MUSTLOCK(dst)) {
00853                 SDL_LockSurface(dst);
00854         }
00855 
00856         /* Calculate byte-per-pixel */
00857         bpp = src->format->BitsPerPixel / 8;
00858 
00859         switch(normalizedClockwiseTurns) {
00860         case 0: /* Make a copy of the surface */
00861                 {
00862                         /* Unfortunately SDL_BlitSurface cannot be used to make a copy of the surface
00863                         since it does not preserve alpha. */
00864 
00865                         if (src->pitch == dst->pitch) {
00866                                 /* If the pitch is the same for both surfaces, the memory can be copied all at once. */
00867                                 memcpy(dst->pixels, src->pixels, (src->h * src->pitch));
00868                         }
00869                         else
00870                         {
00871                                 /* If the pitch differs, copy each row separately */
00872                                 srcBuf = (Uint8*)(src->pixels);
00873                                 dstBuf = (Uint8*)(dst->pixels);
00874                                 bpr = src->w * bpp;
00875                                 for (row = 0; row < src->h; row++) {
00876                                         memcpy(dstBuf, srcBuf, bpr);
00877                                         srcBuf += src->pitch;
00878                                         dstBuf += dst->pitch;
00879                                 }
00880                         }
00881                 }
00882                 break;
00883 
00884                 /* rotate clockwise */
00885         case 1: /* rotated 90 degrees clockwise */
00886                 {
00887                         for (row = 0; row < src->h; ++row) {
00888                                 srcBuf = (Uint8*)(src->pixels) + (row * src->pitch);
00889                                 dstBuf = (Uint8*)(dst->pixels) + (dst->w - row - 1) * bpp;
00890                                 for (col = 0; col < src->w; ++col) {
00891                                         memcpy (dstBuf, srcBuf, bpp);
00892                                         srcBuf += bpp;
00893                                         dstBuf += dst->pitch;
00894                                 } 
00895                         } 
00896                 }
00897                 break;
00898 
00899         case 2: /* rotated 180 degrees clockwise */
00900                 {
00901                         for (row = 0; row < src->h; ++row) {
00902                                 srcBuf = (Uint8*)(src->pixels) + (row * src->pitch);
00903                                 dstBuf = (Uint8*)(dst->pixels) + ((dst->h - row - 1) * dst->pitch) + (dst->w - 1) * bpp;
00904                                 for (col = 0; col < src->w; ++col) {
00905                                         memcpy (dstBuf, srcBuf, bpp);
00906                                         srcBuf += bpp;
00907                                         dstBuf -= bpp;
00908                                 } 
00909                         } 
00910                 }
00911                 break;
00912 
00913         case 3: /* rotated 270 degrees clockwise */
00914                 {
00915                         for (row = 0; row < src->h; ++row) {
00916                                 srcBuf = (Uint8*)(src->pixels) + (row * src->pitch);
00917                                 dstBuf = (Uint8*)(dst->pixels) + (row * bpp) + (dst->h * dst->pitch);
00918                                 for (col = 0; col < src->w; ++col) {
00919                                         memcpy (dstBuf, srcBuf, bpp);
00920                                         srcBuf += bpp;
00921                                         dstBuf -= dst->pitch;
00922                                 } 
00923                         } 
00924                 }
00925                 break;
00926         } 
00927         /* end switch */
00928 
00929         if (SDL_MUSTLOCK(src)) {
00930                 SDL_UnlockSurface(src);
00931         }
00932         if (SDL_MUSTLOCK(dst)) {
00933                 SDL_UnlockSurface(dst);
00934         }
00935 
00936         return dst;
00937 }
00938 
00939 
00954 void _rotozoomSurfaceSizeTrig(int width, int height, double angle, double zoomx, double zoomy, 
00955         int *dstwidth, int *dstheight, 
00956         double *canglezoom, double *sanglezoom)
00957 {
00958         double x, y, cx, cy, sx, sy;
00959         double radangle;
00960         int dstwidthhalf, dstheighthalf;
00961 
00962         /*
00963         * Determine destination width and height by rotating a centered source box 
00964         */
00965         radangle = angle * (M_PI / 180.0);
00966         *sanglezoom = sin(radangle);
00967         *canglezoom = cos(radangle);
00968         *sanglezoom *= zoomx;
00969         *canglezoom *= zoomx;
00970         x = (double)(width / 2);
00971         y = (double)(height / 2);
00972         cx = *canglezoom * x;
00973         cy = *canglezoom * y;
00974         sx = *sanglezoom * x;
00975         sy = *sanglezoom * y;
00976 
00977         dstwidthhalf = MAX((int)
00978                 ceil(MAX(MAX(MAX(fabs(cx + sy), fabs(cx - sy)), fabs(-cx + sy)), fabs(-cx - sy))), 1);
00979         dstheighthalf = MAX((int)
00980                 ceil(MAX(MAX(MAX(fabs(sx + cy), fabs(sx - cy)), fabs(-sx + cy)), fabs(-sx - cy))), 1);
00981         *dstwidth = 2 * dstwidthhalf;
00982         *dstheight = 2 * dstheighthalf;
00983 }
00984 
00996 void rotozoomSurfaceSizeXY(int width, int height, double angle, double zoomx, double zoomy, int *dstwidth, int *dstheight)
00997 {
00998         double dummy_sanglezoom, dummy_canglezoom;
00999 
01000         _rotozoomSurfaceSizeTrig(width, height, angle, zoomx, zoomy, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
01001 }
01002 
01013 void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth, int *dstheight)
01014 {
01015         double dummy_sanglezoom, dummy_canglezoom;
01016 
01017         _rotozoomSurfaceSizeTrig(width, height, angle, zoom, zoom, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
01018 }
01019 
01035 SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth)
01036 {
01037         return rotozoomSurfaceXY(src, angle, zoom, zoom, smooth);
01038 }
01039 
01056 SDL_Surface *rotozoomSurfaceXY(SDL_Surface * src, double angle, double zoomx, double zoomy, int smooth)
01057 {
01058         SDL_Surface *rz_src;
01059         SDL_Surface *rz_dst;
01060         double zoominv;
01061         double sanglezoom, canglezoom, sanglezoominv, canglezoominv;
01062         int dstwidthhalf, dstwidth, dstheighthalf, dstheight;
01063         int is32bit;
01064         int i, src_converted;
01065         int flipx,flipy;
01066 
01067         /*
01068         * Sanity check 
01069         */
01070         if (src == NULL) {
01071                 return (NULL);
01072         }
01073 
01074         /*
01075         * Determine if source surface is 32bit or 8bit 
01076         */
01077         is32bit = (src->format->BitsPerPixel == 32);
01078         if ((is32bit) || (src->format->BitsPerPixel == 8)) {
01079                 /*
01080                 * Use source surface 'as is' 
01081                 */
01082                 rz_src = src;
01083                 src_converted = 0;
01084         } else {
01085                 /*
01086                 * New source surface is 32bit with a defined RGBA ordering 
01087                 */
01088                 rz_src =
01089                         SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, 
01090 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
01091                         0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
01092 #else
01093                         0xff000000,  0x00ff0000, 0x0000ff00, 0x000000ff
01094 #endif
01095                         );
01096 
01097                 SDL_BlitSurface(src, NULL, rz_src, NULL);
01098 
01099                 src_converted = 1;
01100                 is32bit = 1;
01101         }
01102 
01103         /*
01104         * Sanity check zoom factor 
01105         */
01106         flipx = (zoomx<0.0);
01107         if (flipx) zoomx=-zoomx;
01108         flipy = (zoomy<0.0);
01109         if (flipy) zoomy=-zoomy;
01110         if (zoomx < VALUE_LIMIT) zoomx = VALUE_LIMIT;
01111         if (zoomy < VALUE_LIMIT) zoomy = VALUE_LIMIT;
01112         zoominv = 65536.0 / (zoomx * zoomx);
01113 
01114         /*
01115         * Check if we have a rotozoom or just a zoom 
01116         */
01117         if (fabs(angle) > VALUE_LIMIT) {
01118 
01119                 /*
01120                 * Angle!=0: full rotozoom 
01121                 */
01122                 /*
01123                 * ----------------------- 
01124                 */
01125 
01126                 /* Determine target size */
01127                 _rotozoomSurfaceSizeTrig(rz_src->w, rz_src->h, angle, zoomx, zoomy, &dstwidth, &dstheight, &canglezoom, &sanglezoom);
01128 
01129                 /*
01130                 * Calculate target factors from sin/cos and zoom 
01131                 */
01132                 sanglezoominv = sanglezoom;
01133                 canglezoominv = canglezoom;
01134                 sanglezoominv *= zoominv;
01135                 canglezoominv *= zoominv;
01136 
01137                 /* Calculate half size */
01138                 dstwidthhalf = dstwidth / 2;
01139                 dstheighthalf = dstheight / 2;
01140 
01141                 /*
01142                 * Alloc space to completely contain the rotated surface 
01143                 */
01144                 rz_dst = NULL;
01145                 if (is32bit) {
01146                         /*
01147                         * Target surface is 32bit with source RGBA/ABGR ordering 
01148                         */
01149                         rz_dst =
01150                                 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
01151                                 rz_src->format->Rmask, rz_src->format->Gmask,
01152                                 rz_src->format->Bmask, rz_src->format->Amask);
01153                 } else {
01154                         /*
01155                         * Target surface is 8bit 
01156                         */
01157                         rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
01158                 }
01159 
01160                 /* Check target */
01161                 if (rz_dst == NULL)
01162                         return NULL;
01163 
01164                 /* Adjust for guard rows */
01165                 rz_dst->h = dstheight;
01166 
01167                 /*
01168                 * Lock source surface 
01169                 */
01170                 if (SDL_MUSTLOCK(rz_src)) {
01171                         SDL_LockSurface(rz_src);
01172                 }
01173 
01174                 /*
01175                 * Check which kind of surface we have 
01176                 */
01177                 if (is32bit) {
01178                         /*
01179                         * Call the 32bit transformation routine to do the rotation (using alpha) 
01180                         */
01181                         _transformSurfaceRGBA(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
01182                                 (int) (sanglezoominv), (int) (canglezoominv), 
01183                                 flipx, flipy,
01184                                 smooth);
01185                 } else {
01186                         /*
01187                         * Copy palette and colorkey info 
01188                         */
01189                         for (i = 0; i < rz_src->format->palette->ncolors; i++) {
01190                                 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
01191                         }
01192                         rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
01193                         /*
01194                         * Call the 8bit transformation routine to do the rotation 
01195                         */
01196                         transformSurfaceY(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
01197                                 (int) (sanglezoominv), (int) (canglezoominv),
01198                                 flipx, flipy);
01199                 }
01200                 /*
01201                 * Unlock source surface 
01202                 */
01203                 if (SDL_MUSTLOCK(rz_src)) {
01204                         SDL_UnlockSurface(rz_src);
01205                 }
01206 
01207         } else {
01208 
01209                 /*
01210                 * Angle=0: Just a zoom 
01211                 */
01212                 /*
01213                 * -------------------- 
01214                 */
01215 
01216                 /*
01217                 * Calculate target size
01218                 */
01219                 zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
01220 
01221                 /*
01222                 * Alloc space to completely contain the zoomed surface 
01223                 */
01224                 rz_dst = NULL;
01225                 if (is32bit) {
01226                         /*
01227                         * Target surface is 32bit with source RGBA/ABGR ordering 
01228                         */
01229                         rz_dst =
01230                                 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
01231                                 rz_src->format->Rmask, rz_src->format->Gmask,
01232                                 rz_src->format->Bmask, rz_src->format->Amask);
01233                 } else {
01234                         /*
01235                         * Target surface is 8bit 
01236                         */
01237                         rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
01238                 }
01239 
01240                 /* Check target */
01241                 if (rz_dst == NULL)
01242                         return NULL;
01243 
01244                 /* Adjust for guard rows */
01245                 rz_dst->h = dstheight;
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                 } else {
01264                         /*
01265                         * Copy palette and colorkey info 
01266                         */
01267                         for (i = 0; i < rz_src->format->palette->ncolors; i++) {
01268                                 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
01269                         }
01270                         rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
01271 
01272                         /*
01273                         * Call the 8bit transformation routine to do the zooming 
01274                         */
01275                         _zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
01276                 }
01277 
01278                 /*
01279                 * Unlock source surface 
01280                 */
01281                 if (SDL_MUSTLOCK(rz_src)) {
01282                         SDL_UnlockSurface(rz_src);
01283                 }
01284         }
01285 
01286         /*
01287         * Cleanup temp surface 
01288         */
01289         if (src_converted) {
01290                 SDL_FreeSurface(rz_src);
01291         }
01292 
01293         /*
01294         * Return destination surface 
01295         */
01296         return (rz_dst);
01297 }
01298 
01311 void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight)
01312 {
01313         /*
01314         * Make zoom factors positive 
01315         */
01316         int flipx, flipy;
01317         flipx = (zoomx<0.0);
01318         if (flipx) zoomx = -zoomx;
01319         flipy = (zoomy<0.0);
01320         if (flipy) zoomy = -zoomy;
01321 
01322         /*
01323         * Sanity check zoom factors 
01324         */
01325         if (zoomx < VALUE_LIMIT) {
01326                 zoomx = VALUE_LIMIT;
01327         }
01328         if (zoomy < VALUE_LIMIT) {
01329                 zoomy = VALUE_LIMIT;
01330         }
01331 
01332         /*
01333         * Calculate target size 
01334         */
01335         *dstwidth = (int) floor(((double) width * zoomx) + 0.5);
01336         *dstheight = (int) floor(((double) height * zoomy) + 0.5);
01337         if (*dstwidth < 1) {
01338                 *dstwidth = 1;
01339         }
01340         if (*dstheight < 1) {
01341                 *dstheight = 1;
01342         }
01343 }
01344 
01361 SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth)
01362 {
01363         SDL_Surface *rz_src;
01364         SDL_Surface *rz_dst;
01365         int dstwidth, dstheight;
01366         int is32bit;
01367         int i, src_converted;
01368         int flipx, flipy;
01369 
01370         /*
01371         * Sanity check 
01372         */
01373         if (src == NULL)
01374                 return (NULL);
01375 
01376         /*
01377         * Determine if source surface is 32bit or 8bit 
01378         */
01379         is32bit = (src->format->BitsPerPixel == 32);
01380         if ((is32bit) || (src->format->BitsPerPixel == 8)) {
01381                 /*
01382                 * Use source surface 'as is' 
01383                 */
01384                 rz_src = src;
01385                 src_converted = 0;
01386         } else {
01387                 /*
01388                 * New source surface is 32bit with a defined RGBA ordering 
01389                 */
01390                 rz_src =
01391                         SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, 
01392 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
01393                         0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
01394 #else
01395                         0xff000000,  0x00ff0000, 0x0000ff00, 0x000000ff
01396 #endif
01397                         );
01398                 if (rz_src == NULL) {
01399                         return NULL;
01400                 }
01401                 SDL_BlitSurface(src, NULL, rz_src, NULL);
01402                 src_converted = 1;
01403                 is32bit = 1;
01404         }
01405 
01406         flipx = (zoomx<0.0);
01407         if (flipx) zoomx = -zoomx;
01408         flipy = (zoomy<0.0);
01409         if (flipy) zoomy = -zoomy;
01410 
01411         /* Get size if target */
01412         zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
01413 
01414         /*
01415         * Alloc space to completely contain the zoomed surface 
01416         */
01417         rz_dst = NULL;
01418         if (is32bit) {
01419                 /*
01420                 * Target surface is 32bit with source RGBA/ABGR ordering 
01421                 */
01422                 rz_dst =
01423                         SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
01424                         rz_src->format->Rmask, rz_src->format->Gmask,
01425                         rz_src->format->Bmask, rz_src->format->Amask);
01426         } else {
01427                 /*
01428                 * Target surface is 8bit 
01429                 */
01430                 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
01431         }
01432 
01433         /* Check target */
01434         if (rz_dst == NULL) {
01435                 /*
01436                 * Cleanup temp surface 
01437                 */
01438                 if (src_converted) {
01439                         SDL_FreeSurface(rz_src);
01440                 }               
01441                 return NULL;
01442         }
01443 
01444         /* Adjust for guard rows */
01445         rz_dst->h = dstheight;
01446 
01447         /*
01448         * Lock source surface 
01449         */
01450         if (SDL_MUSTLOCK(rz_src)) {
01451                 SDL_LockSurface(rz_src);
01452         }
01453 
01454         /*
01455         * Check which kind of surface we have 
01456         */
01457         if (is32bit) {
01458                 /*
01459                 * Call the 32bit transformation routine to do the zooming (using alpha) 
01460                 */
01461                 _zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
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         }
01475         /*
01476         * Unlock source surface 
01477         */
01478         if (SDL_MUSTLOCK(rz_src)) {
01479                 SDL_UnlockSurface(rz_src);
01480         }
01481 
01482         /*
01483         * Cleanup temp surface 
01484         */
01485         if (src_converted) {
01486                 SDL_FreeSurface(rz_src);
01487         }
01488 
01489         /*
01490         * Return destination surface 
01491         */
01492         return (rz_dst);
01493 }
01494 
01511 /*@null@*/ 
01512 SDL_Surface *shrinkSurface(SDL_Surface *src, int factorx, int factory)
01513 {
01514         int result;
01515         SDL_Surface *rz_src;
01516         SDL_Surface *rz_dst = NULL;
01517         int dstwidth, dstheight;
01518         int is32bit;
01519         int i, src_converted;
01520         int haveError = 0;
01521 
01522         /*
01523         * Sanity check 
01524         */
01525         if (src == NULL) {
01526                 return (NULL);
01527         }
01528 
01529         /*
01530         * Determine if source surface is 32bit or 8bit 
01531         */
01532         is32bit = (src->format->BitsPerPixel == 32);
01533         if ((is32bit) || (src->format->BitsPerPixel == 8)) {
01534                 /*
01535                 * Use source surface 'as is' 
01536                 */
01537                 rz_src = src;
01538                 src_converted = 0;
01539         } else {
01540                 /*
01541                 * New source surface is 32bit with a defined RGBA ordering 
01542                 */
01543                 rz_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, 
01544 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
01545                         0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
01546 #else
01547                         0xff000000,  0x00ff0000, 0x0000ff00, 0x000000ff
01548 #endif
01549                         );
01550                 if (rz_src==NULL) {
01551                         haveError = 1;
01552                         goto exitShrinkSurface;
01553                 }
01554 
01555                 SDL_BlitSurface(src, NULL, rz_src, NULL);
01556                 src_converted = 1;
01557                 is32bit = 1;
01558         }
01559 
01560         /*
01561         * Lock the surface 
01562         */
01563         if (SDL_MUSTLOCK(rz_src)) {
01564                 if (SDL_LockSurface(rz_src) < 0) {
01565                         haveError = 1;
01566                         goto exitShrinkSurface;
01567                 }
01568         }
01569 
01570         /* Get size for target */
01571         dstwidth=rz_src->w/factorx;
01572         while (dstwidth*factorx>rz_src->w) { dstwidth--; }
01573         dstheight=rz_src->h/factory;
01574         while (dstheight*factory>rz_src->h) { dstheight--; }
01575 
01576         /*
01577         * Alloc space to completely contain the shrunken surface
01578         * (with added guard rows)
01579         */
01580         if (is32bit==1) {
01581                 /*
01582                 * Target surface is 32bit with source RGBA/ABGR ordering 
01583                 */
01584                 rz_dst =
01585                         SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
01586                         rz_src->format->Rmask, rz_src->format->Gmask,
01587                         rz_src->format->Bmask, rz_src->format->Amask);
01588         } else {
01589                 /*
01590                 * Target surface is 8bit 
01591                 */
01592                 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
01593         }
01594 
01595         /* Check target */
01596         if (rz_dst == NULL) {
01597                 haveError = 1;
01598                 goto exitShrinkSurface;
01599         }
01600 
01601         /* Adjust for guard rows */
01602         rz_dst->h = dstheight;
01603 
01604         /*
01605         * Check which kind of surface we have 
01606         */
01607         if (is32bit==1) {
01608                 /*
01609                 * Call the 32bit transformation routine to do the shrinking (using alpha) 
01610                 */
01611                 result = _shrinkSurfaceRGBA(rz_src, rz_dst, factorx, factory);          
01612                 if ((result!=0) || (rz_dst==NULL)) {
01613                         haveError = 1;
01614                         goto exitShrinkSurface;
01615                 }
01616         } else {
01617                 /*
01618                 * Copy palette and colorkey info 
01619                 */
01620                 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
01621                         rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
01622                 }
01623                 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
01624                 /*
01625                 * Call the 8bit transformation routine to do the shrinking 
01626                 */
01627                 result = _shrinkSurfaceY(rz_src, rz_dst, factorx, factory);
01628                 if (result!=0) {
01629                         haveError = 1;
01630                         goto exitShrinkSurface;
01631                 }
01632         }
01633 
01634 exitShrinkSurface:
01635         if (rz_src!=NULL) {
01636                 /*
01637                 * Unlock source surface 
01638                 */
01639                 if (SDL_MUSTLOCK(rz_src)) {
01640                         SDL_UnlockSurface(rz_src);
01641                 }
01642 
01643                 /*
01644                 * Cleanup temp surface 
01645                 */
01646                 if (src_converted==1) {
01647                         SDL_FreeSurface(rz_src);
01648                 }
01649         }
01650 
01651         /* Check error state; maybe need to cleanup destination */
01652         if (haveError==1) {
01653                 if (rz_dst!=NULL) {
01654                         SDL_FreeSurface(rz_dst);
01655                 }
01656                 rz_dst=NULL;
01657         } 
01658 
01659         /*
01660         * Return destination surface 
01661         */
01662         return (rz_dst);
01663 }