Atrinik Client 2.5
toolkit/SDL_rotozoom.c
00001 /*
00002 
00003 SDL_rotozoom.c - rotozoomer, zoomer and shrinker for 32bit or 8bit surfaces
00004 
00005 LGPL (c) A. Schiffler
00006 
00007 */
00008 
00009 #include <global.h>
00010 
00011 /* ---- Internally used structures */
00012 
00016 typedef struct tColorRGBA {
00017     Uint8 r;
00018     Uint8 g;
00019     Uint8 b;
00020     Uint8 a;
00021 } tColorRGBA;
00022 
00026 typedef struct tColorY {
00027     Uint8 y;
00028 } tColorY;
00029 
00040 #define GUARD_ROWS (2)
00041 
00045 #define VALUE_LIMIT 0.001
00046 
00050 Uint32 _colorkey(SDL_Surface *src)
00051 {
00052     Uint32 key = 0;
00053 #if (SDL_MINOR_VERSION == 3)
00054     SDL_GetColorKey(src, &key);
00055 #else
00056     if (src)
00057     {
00058         key = src->format->colorkey;
00059     }
00060 #endif
00061     return key;
00062 }
00063 
00064 
00080 int _shrinkSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
00081 {
00082     int x, y, dx, dy, dgap, ra, ga, ba, aa;
00083     int n_average;
00084     tColorRGBA *sp, *osp, *oosp;
00085     tColorRGBA *dp;
00086 
00087     /*
00088     * Averaging integer shrink
00089     */
00090 
00091     /* Precalculate division factor */
00092     n_average = factorx*factory;
00093 
00094     /*
00095     * Scan destination
00096     */
00097     sp = (tColorRGBA *) src->pixels;
00098 
00099     dp = (tColorRGBA *) dst->pixels;
00100     dgap = dst->pitch - dst->w * 4;
00101 
00102     for (y = 0; y < dst->h; y++) {
00103 
00104         osp=sp;
00105         for (x = 0; x < dst->w; x++) {
00106 
00107             /* Trace out source box and accumulate */
00108             oosp=sp;
00109             ra=ga=ba=aa=0;
00110             for (dy=0; dy < factory; dy++) {
00111                 for (dx=0; dx < factorx; dx++) {
00112                     ra += sp->r;
00113                     ga += sp->g;
00114                     ba += sp->b;
00115                     aa += sp->a;
00116 
00117                     sp++;
00118                 }
00119                 /* src dx loop */
00120                 sp = (tColorRGBA *)((Uint8*)sp + (src->pitch - 4*factorx)); /* next y */
00121             }
00122             /* src dy loop */
00123 
00124             /* next box-x */
00125             sp = (tColorRGBA *)((Uint8*)oosp + 4*factorx);
00126 
00127             /* Store result in destination */
00128             dp->r = ra/n_average;
00129             dp->g = ga/n_average;
00130             dp->b = ba/n_average;
00131             dp->a = aa/n_average;
00132 
00133             /*
00134             * Advance destination pointer
00135             */
00136             dp++;
00137         }
00138         /* dst x loop */
00139 
00140         /* next box-y */
00141         sp = (tColorRGBA *)((Uint8*)osp + src->pitch*factory);
00142 
00143         /*
00144         * Advance destination pointers
00145         */
00146         dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
00147     }
00148     /* dst y loop */
00149 
00150     return (0);
00151 }
00152 
00168 int _shrinkSurfaceY(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
00169 {
00170     int x, y, dx, dy, dgap, a;
00171     int n_average;
00172     Uint8 *sp, *osp, *oosp;
00173     Uint8 *dp;
00174 
00175     /*
00176     * Averaging integer shrink
00177     */
00178 
00179     /* Precalculate division factor */
00180     n_average = factorx*factory;
00181 
00182     /*
00183     * Scan destination
00184     */
00185     sp = (Uint8 *) src->pixels;
00186 
00187     dp = (Uint8 *) dst->pixels;
00188     dgap = dst->pitch - dst->w;
00189 
00190     for (y = 0; y < dst->h; y++) {
00191 
00192         osp=sp;
00193         for (x = 0; x < dst->w; x++) {
00194 
00195             /* Trace out source box and accumulate */
00196             oosp=sp;
00197             a=0;
00198             for (dy=0; dy < factory; dy++) {
00199                 for (dx=0; dx < factorx; dx++) {
00200                     a += (*sp);
00201                     /* next x */
00202                     sp++;
00203                 }
00204                 /* end src dx loop */
00205                 /* next y */
00206                 sp = (Uint8 *)((Uint8*)sp + (src->pitch - factorx));
00207             }
00208             /* end src dy loop */
00209 
00210             /* next box-x */
00211             sp = (Uint8 *)((Uint8*)oosp + factorx);
00212 
00213             /* Store result in destination */
00214             *dp = a/n_average;
00215 
00216             /*
00217             * Advance destination pointer
00218             */
00219             dp++;
00220         }
00221         /* end dst x loop */
00222 
00223         /* next box-y */
00224         sp = (Uint8 *)((Uint8*)osp + src->pitch*factory);
00225 
00226         /*
00227         * Advance destination pointers
00228         */
00229         dp = (Uint8 *)((Uint8 *)dp + dgap);
00230     }
00231     /* end dst y loop */
00232 
00233     return (0);
00234 }
00235 
00251 int _zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy, int smooth)
00252 {
00253     int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy, ex, ey, t1, t2, sstep, lx, ly;
00254     tColorRGBA *c00, *c01, *c10, *c11, *cswap;
00255     tColorRGBA *sp, *csp, *dp;
00256     int dgap;
00257 
00258     /*
00259     * Variable setup
00260     */
00261     if (smooth) {
00262         /*
00263         * For interpolation: assume source dimension is one pixel
00264         * smaller to avoid overflow on right and bottom edge.
00265         */
00266         sx = (int) (65536.0 * (float) (src->w - 1) / (float) dst->w);
00267         sy = (int) (65536.0 * (float) (src->h - 1) / (float) dst->h);
00268     } else {
00269         sx = (int) (65536.0 * (float) src->w / (float) dst->w);
00270         sy = (int) (65536.0 * (float) src->h / (float) dst->h);
00271     }
00272 
00273     /*
00274     * Allocate memory for row increments
00275     */
00276     if ((sax = (int *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
00277         return (-1);
00278     }
00279     if ((say = (int *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
00280         free(sax);
00281         return (-1);
00282     }
00283 
00284     /*
00285     * Precalculate row increments
00286     */
00287     sp = csp = (tColorRGBA *) src->pixels;
00288     dp = (tColorRGBA *) dst->pixels;
00289 
00290     if (flipx) csp += (src->w-1);
00291     if (flipy) csp += ((src->pitch/4)*(src->h-1));
00292 
00293     csx = 0;
00294     csax = sax;
00295     for (x = 0; x <= dst->w; x++) {
00296         *csax = csx;
00297         csax++;
00298         csx &= 0xffff;
00299         csx += sx;
00300     }
00301     csy = 0;
00302     csay = say;
00303     for (y = 0; y <= dst->h; y++) {
00304         *csay = csy;
00305         csay++;
00306         csy &= 0xffff;
00307         csy += sy;
00308     }
00309 
00310     dgap = dst->pitch - dst->w * 4;
00311 
00312     /*
00313     * Switch between interpolating and non-interpolating code
00314     */
00315     if (smooth) {
00316 
00317         /*
00318         * Interpolating Zoom
00319         */
00320 
00321         /*
00322         * Scan destination
00323         */
00324         csay = say;
00325         ly = 0;
00326         for (y = 0; y < dst->h; y++) {
00327             /*
00328             * Setup color source pointers
00329             */
00330             c00 = csp;
00331             c01 = csp;
00332             c01++;
00333             c10 = csp;
00334             c10 += src->pitch/4;
00335             c11 = c10;
00336             c11++;
00337             if (flipx) {
00338                 cswap = c00; c00=c01; c01=cswap;
00339                 cswap = c10; c10=c11; c11=cswap;
00340             }
00341             if (flipy) {
00342                 cswap = c00; c00=c10; c10=cswap;
00343                 cswap = c01; c01=c11; c11=cswap;
00344             }
00345 
00346             csax = sax;
00347             lx = 0;
00348             for (x = 0; x < dst->w; x++) {
00349                 /*
00350                 * Draw and interpolate colors
00351                 */
00352                 ex = (*csax & 0xffff);
00353                 ey = (*csay & 0xffff);
00354                 t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
00355                 t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
00356                 dp->r = (((t2 - t1) * ey) >> 16) + t1;
00357                 t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff;
00358                 t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff;
00359                 dp->g = (((t2 - t1) * ey) >> 16) + t1;
00360                 t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff;
00361                 t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff;
00362                 dp->b = (((t2 - t1) * ey) >> 16) + t1;
00363                 t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff;
00364                 t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff;
00365                 dp->a = (((t2 - t1) * ey) >> 16) + t1;
00366 
00367                 /*
00368                 * Advance source pointers
00369                 */
00370                 csax++;
00371                 if (*csax > 0)
00372                 {
00373                     sstep = (*csax >> 16);
00374                     lx += sstep;
00375                     if (flipx) sstep = -sstep;
00376                     if (lx <= src->w)
00377                     {
00378                         c00 += sstep;
00379                         c01 += sstep;
00380                         c10 += sstep;
00381                         c11 += sstep;
00382                     }
00383                 }
00384 
00385                 /*
00386                 * Advance destination pointer
00387                 */
00388                 dp++;
00389             }
00390 
00391             /*
00392             * Advance source pointer
00393             */
00394             csay++;
00395             if (*csay > 0)
00396             {
00397                 sstep = (*csay >> 16);
00398                 ly += sstep;
00399                 if (flipy) sstep = -sstep;
00400                 if (ly < src->h)
00401                 {
00402                     csp += (sstep * (src->pitch/4));
00403                 }
00404             }
00405 
00406             /*
00407             * Advance destination pointers
00408             */
00409             dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
00410         }
00411     } else {
00412 
00413         /*
00414         * Non-Interpolating Zoom
00415         */
00416         csay = say;
00417         for (y = 0; y < dst->h; y++) {
00418             sp = csp;
00419             csax = sax;
00420             for (x = 0; x < dst->w; x++) {
00421                 /*
00422                 * Draw
00423                 */
00424                 *dp = *sp;
00425                 /*
00426                 * Advance source pointers
00427                 */
00428                 csax++;
00429                 if (*csax > 0)
00430                 {
00431                     sstep = (*csax >> 16);
00432                     if (flipx) sstep = -sstep;
00433                     sp += sstep;
00434                 }
00435                 /*
00436                 * Advance destination pointer
00437                 */
00438                 dp++;
00439             }
00440             /*
00441             * Advance source pointer
00442             */
00443             csay++;
00444             if (*csay > 0)
00445             {
00446                 sstep = (*csay >> 16) * (src->pitch/4);
00447                 if (flipy) sstep = -sstep;
00448                 csp += sstep;
00449             }
00450 
00451             /*
00452             * Advance destination pointers
00453             */
00454             dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
00455         }
00456     }
00457 
00458     /*
00459     * Remove temp arrays
00460     */
00461     free(sax);
00462     free(say);
00463 
00464     return (0);
00465 }
00466 
00482 int _zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy)
00483 {
00484     int x, y;
00485     Uint32 *sax, *say, *csax, *csay;
00486     int csx, csy;
00487     Uint8 *sp, *dp, *csp;
00488     int dgap;
00489 
00490     /*
00491     * Allocate memory for row increments
00492     */
00493     if ((sax = (Uint32 *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
00494         return (-1);
00495     }
00496     if ((say = (Uint32 *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
00497         free(sax);
00498         return (-1);
00499     }
00500 
00501     /*
00502     * Pointer setup
00503     */
00504     sp = csp = (Uint8 *) src->pixels;
00505     dp = (Uint8 *) dst->pixels;
00506     dgap = dst->pitch - dst->w;
00507 
00508     if (flipx) csp += (src->w-1);
00509     if (flipy) csp  = ( (Uint8*)csp + src->pitch*(src->h-1) );
00510 
00511     /*
00512     * Precalculate row increments
00513     */
00514     csx = 0;
00515     csax = sax;
00516     for (x = 0; x < dst->w; x++) {
00517         csx += src->w;
00518         *csax = 0;
00519         while (csx >= dst->w) {
00520             csx -= dst->w;
00521             (*csax)++;
00522         }
00523         csax++;
00524     }
00525     csy = 0;
00526     csay = say;
00527     for (y = 0; y < dst->h; y++) {
00528         csy += src->h;
00529         *csay = 0;
00530         while (csy >= dst->h) {
00531             csy -= dst->h;
00532             (*csay)++;
00533         }
00534         csay++;
00535     }
00536 
00537     /*
00538     * Draw
00539     */
00540     csay = say;
00541     for (y = 0; y < dst->h; y++) {
00542         csax = sax;
00543         sp = csp;
00544         for (x = 0; x < dst->w; x++) {
00545             /*
00546             * Draw
00547             */
00548             *dp = *sp;
00549             /*
00550             * Advance source pointers
00551             */
00552             sp += (*csax) * (flipx ? -1 : 1);
00553             csax++;
00554             /*
00555             * Advance destination pointer
00556             */
00557             dp++;
00558         }
00559         /*
00560         * Advance source pointer (for row)
00561         */
00562         csp += ((*csay) * src->pitch) * (flipy ? -1 : 1);
00563         csay++;
00564 
00565         /*
00566         * Advance destination pointers
00567         */
00568         dp += dgap;
00569     }
00570 
00571     /*
00572     * Remove temp arrays
00573     */
00574     free(sax);
00575     free(say);
00576 
00577     return (0);
00578 }
00579 
00599 void _transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy, int smooth)
00600 {
00601     int x, y, t1, t2, dx, dy, xd, yd, sdx, sdy, ax, ay, ex, ey, sw, sh;
00602     tColorRGBA c00, c01, c10, c11, cswap;
00603     tColorRGBA *pc, *sp;
00604     int gap;
00605 
00606     /*
00607     * Variable setup
00608     */
00609     xd = ((src->w - dst->w) << 15);
00610     yd = ((src->h - dst->h) << 15);
00611     ax = (cx << 16) - (icos * cx);
00612     ay = (cy << 16) - (isin * cx);
00613     sw = src->w - 1;
00614     sh = src->h - 1;
00615     pc = (tColorRGBA*) dst->pixels;
00616     gap = dst->pitch - dst->w * 4;
00617 
00618     /*
00619     * Switch between interpolating and non-interpolating code
00620     */
00621     if (smooth) {
00622         for (y = 0; y < dst->h; y++) {
00623             dy = cy - y;
00624             sdx = (ax + (isin * dy)) + xd;
00625             sdy = (ay - (icos * dy)) + yd;
00626             for (x = 0; x < dst->w; x++) {
00627                 dx = (sdx >> 16);
00628                 dy = (sdy >> 16);
00629                 if (flipx) dx = sw - dx;
00630                 if (flipy) dy = sh - dy;
00631                 if ((dx > -1) && (dy > -1) && (dx < (src->w-1)) && (dy < (src->h-1))) {
00632                     sp = (tColorRGBA *)src->pixels;;
00633                     sp += ((src->pitch/4) * dy);
00634                     sp += dx;
00635                     c00 = *sp;
00636                     sp += 1;
00637                     c01 = *sp;
00638                     sp += (src->pitch/4);
00639                     c11 = *sp;
00640                     sp -= 1;
00641                     c10 = *sp;
00642                     if (flipx) {
00643                         cswap = c00; c00=c01; c01=cswap;
00644                         cswap = c10; c10=c11; c11=cswap;
00645                     }
00646                     if (flipy) {
00647                         cswap = c00; c00=c10; c10=cswap;
00648                         cswap = c01; c01=c11; c11=cswap;
00649                     }
00650                     /*
00651                     * Interpolate colors
00652                     */
00653                     ex = (sdx & 0xffff);
00654                     ey = (sdy & 0xffff);
00655                     t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff;
00656                     t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff;
00657                     pc->r = (((t2 - t1) * ey) >> 16) + t1;
00658                     t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff;
00659                     t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff;
00660                     pc->g = (((t2 - t1) * ey) >> 16) + t1;
00661                     t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff;
00662                     t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff;
00663                     pc->b = (((t2 - t1) * ey) >> 16) + t1;
00664                     t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff;
00665                     t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff;
00666                     pc->a = (((t2 - t1) * ey) >> 16) + t1;
00667                 }
00668                 sdx += icos;
00669                 sdy += isin;
00670                 pc++;
00671             }
00672             pc = (tColorRGBA *) ((Uint8 *) pc + gap);
00673         }
00674     } else {
00675         for (y = 0; y < dst->h; y++) {
00676             dy = cy - y;
00677             sdx = (ax + (isin * dy)) + xd;
00678             sdy = (ay - (icos * dy)) + yd;
00679             for (x = 0; x < dst->w; x++) {
00680                 dx = (short) (sdx >> 16);
00681                 dy = (short) (sdy >> 16);
00682                 if (flipx) dx = (src->w-1)-dx;
00683                 if (flipy) dy = (src->h-1)-dy;
00684                 if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
00685                     sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
00686                     sp += dx;
00687                     *pc = *sp;
00688                 }
00689                 sdx += icos;
00690                 sdy += isin;
00691                 pc++;
00692             }
00693             pc = (tColorRGBA *) ((Uint8 *) pc + gap);
00694         }
00695     }
00696 }
00697 
00716 void transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy)
00717 {
00718     int x, y, dx, dy, xd, yd, sdx, sdy, ax, ay;
00719     tColorY *pc, *sp;
00720     int gap;
00721 
00722     /*
00723     * Variable setup
00724     */
00725     xd = ((src->w - dst->w) << 15);
00726     yd = ((src->h - dst->h) << 15);
00727     ax = (cx << 16) - (icos * cx);
00728     ay = (cy << 16) - (isin * cx);
00729     pc = (tColorY*) dst->pixels;
00730     gap = dst->pitch - dst->w;
00731     /*
00732     * Clear surface to colorkey
00733     */
00734     memset(pc, (unsigned char) (_colorkey(src) & 0xff), dst->pitch * dst->h);
00735     /*
00736     * Iterate through destination surface
00737     */
00738     for (y = 0; y < dst->h; y++) {
00739         dy = cy - y;
00740         sdx = (ax + (isin * dy)) + xd;
00741         sdy = (ay - (icos * dy)) + yd;
00742         for (x = 0; x < dst->w; x++) {
00743             dx = (short) (sdx >> 16);
00744             dy = (short) (sdy >> 16);
00745             if (flipx) dx = (src->w-1)-dx;
00746             if (flipy) dy = (src->h-1)-dy;
00747             if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
00748                 sp = (tColorY *) (src->pixels);
00749                 sp += (src->pitch * dy + dx);
00750                 *pc = *sp;
00751             }
00752             sdx += icos;
00753             sdy += isin;
00754             pc++;
00755         }
00756         pc += gap;
00757     }
00758 }
00759 
00773 SDL_Surface* rotateSurface90Degrees(SDL_Surface* src, int numClockwiseTurns)
00774 {
00775     int row, col, newWidth, newHeight;
00776     int bpp, src_ipr, dst_ipr;
00777     SDL_Surface* dst;
00778     Uint32* srcBuf;
00779     Uint32* dstBuf;
00780 
00781     /* Has to be a valid surface pointer and only 32-bit surfaces (for now) */
00782     if (!src || src->format->BitsPerPixel != 32) { return NULL; }
00783 
00784     /* normalize numClockwiseTurns */
00785     while(numClockwiseTurns < 0) { numClockwiseTurns += 4; }
00786     numClockwiseTurns = (numClockwiseTurns % 4);
00787 
00788     /* if it's even, our new width will be the same as the source surface */
00789     newWidth = (numClockwiseTurns % 2) ? (src->h) : (src->w);
00790     newHeight = (numClockwiseTurns % 2) ? (src->w) : (src->h);
00791     dst = SDL_CreateRGBSurface( src->flags, newWidth, newHeight, src->format->BitsPerPixel,
00792         src->format->Rmask,
00793         src->format->Gmask,
00794         src->format->Bmask,
00795         src->format->Amask);
00796     if(!dst) {
00797         return NULL;
00798     }
00799 
00800     if (SDL_MUSTLOCK(dst)) {
00801         SDL_LockSurface(dst);
00802     }
00803     if (SDL_MUSTLOCK(dst)) {
00804         SDL_LockSurface(dst);
00805     }
00806 
00807     /* Calculate int-per-row */
00808     bpp = src->format->BitsPerPixel / 8;
00809     src_ipr = src->pitch / bpp;
00810     dst_ipr = dst->pitch / bpp;
00811 
00812     switch(numClockwiseTurns) {
00813         case 0: /* Make a copy of the surface */
00814             {
00815                 /* Unfortunately SDL_BlitSurface cannot be used to make a copy of the surface
00816                    since it does not preserve alpha. */
00817 
00818                 if (src->pitch == dst->pitch) {
00819                     /* If the pitch is the same for both surfaces, the memory can be copied all at once. */
00820                     memcpy(dst->pixels, src->pixels, (src->h * src->pitch));
00821                 }
00822                 else
00823                 {
00824                     /* If the pitch differs, copy each row separately */
00825                     srcBuf = (Uint32*)(src->pixels);
00826                     dstBuf = (Uint32*)(dst->pixels);
00827                     for (row = 0; row < src->h; row++) {
00828                         memcpy(dstBuf, srcBuf, dst->w * bpp);
00829                         srcBuf += src_ipr;
00830                         dstBuf += dst_ipr;
00831                     } /* end for(col) */
00832                 } /* end for(row) */
00833             }
00834             break;
00835 
00836             /* rotate clockwise */
00837         case 1: /* rotated 90 degrees clockwise */
00838          {
00839              for (row = 0; row < src->h; ++row) {
00840                  srcBuf = (Uint32*)(src->pixels) + (row * src_ipr);
00841                  dstBuf = (Uint32*)(dst->pixels) + (dst->w - row - 1);
00842                  for (col = 0; col < src->w; ++col) {
00843                      *dstBuf = *srcBuf;
00844                      ++srcBuf;
00845                      dstBuf += dst_ipr;
00846                  }
00847                  /* end for(col) */
00848              }
00849              /* end for(row) */
00850          }
00851          break;
00852 
00853         case 2: /* rotated 180 degrees clockwise */
00854          {
00855              for (row = 0; row < src->h; ++row) {
00856                  srcBuf = (Uint32*)(src->pixels) + (row * src_ipr);
00857                  dstBuf = (Uint32*)(dst->pixels) + ((dst->h - row - 1) * dst_ipr) + (dst->w - 1);
00858                  for (col = 0; col < src->w; ++col) {
00859                      *dstBuf = *srcBuf;
00860                      ++srcBuf;
00861                      --dstBuf;
00862                  }
00863              }
00864          }
00865          break;
00866 
00867         case 3:
00868          {
00869              for (row = 0; row < src->h; ++row) {
00870                  srcBuf = (Uint32*)(src->pixels) + (row * src_ipr);
00871                  dstBuf = (Uint32*)(dst->pixels) + row + ((dst->h - 1) * dst_ipr);
00872                  for (col = 0; col < src->w; ++col) {
00873                      *dstBuf = *srcBuf;
00874                      ++srcBuf;
00875                      dstBuf -= dst_ipr;
00876                  }
00877              }
00878          }
00879          break;
00880     }
00881     /* end switch */
00882 
00883     if (SDL_MUSTLOCK(src)) {
00884         SDL_UnlockSurface(src);
00885     }
00886     if (SDL_MUSTLOCK(dst)) {
00887         SDL_UnlockSurface(dst);
00888     }
00889 
00890     return dst;
00891 }
00892 
00893 
00908 void _rotozoomSurfaceSizeTrig(int width, int height, double angle, double zoomx, double zoomy,
00909                               int *dstwidth, int *dstheight,
00910                               double *canglezoom, double *sanglezoom)
00911 {
00912     double x, y, cx, cy, sx, sy;
00913     double radangle;
00914     double dstwidthhalf, dstheighthalf;
00915 
00916     (void) zoomy;
00917 
00918     /*
00919     * Determine destination width and height by rotating a centered source box
00920     */
00921     radangle = angle * (M_PI / 180.0);
00922     *sanglezoom = sin(radangle);
00923     *canglezoom = cos(radangle);
00924     *sanglezoom *= zoomx;
00925     *canglezoom *= zoomx;
00926     x = width / 2;
00927     y = height / 2;
00928     cx = *canglezoom * x;
00929     cy = *canglezoom * y;
00930     sx = *sanglezoom * x;
00931     sy = *sanglezoom * y;
00932 
00933     dstwidthhalf = MAX(ceil(MAX(MAX(MAX(fabs(cx + sy), fabs(cx - sy)), fabs(-cx + sy)), fabs(-cx - sy))), 1);
00934     dstheighthalf = MAX(ceil(MAX(MAX(MAX(fabs(sx + cy), fabs(sx - cy)), fabs(-sx + cy)), fabs(-sx - cy))), 1);
00935     *dstwidth = (int) (dstwidthhalf * 2.0);
00936     *dstheight = (int) (dstheighthalf * 2.0);
00937 }
00938 
00950 void rotozoomSurfaceSizeXY(int width, int height, double angle, double zoomx, double zoomy, int *dstwidth, int *dstheight)
00951 {
00952     double dummy_sanglezoom, dummy_canglezoom;
00953 
00954     _rotozoomSurfaceSizeTrig(width, height, angle, zoomx, zoomy, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
00955 }
00956 
00967 void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth, int *dstheight)
00968 {
00969     double dummy_sanglezoom, dummy_canglezoom;
00970 
00971     _rotozoomSurfaceSizeTrig(width, height, angle, zoom, zoom, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
00972 }
00973 
00989 SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth)
00990 {
00991     return rotozoomSurfaceXY(src, angle, zoom, zoom, smooth);
00992 }
00993 
01010 SDL_Surface *rotozoomSurfaceXY(SDL_Surface * src, double angle, double zoomx, double zoomy, int smooth)
01011 {
01012     SDL_Surface *rz_src;
01013     SDL_Surface *rz_dst;
01014     double zoominv;
01015     double sanglezoom, canglezoom, sanglezoominv, canglezoominv;
01016     int dstwidthhalf, dstwidth, dstheighthalf, dstheight;
01017     int is32bit;
01018     int i, src_converted;
01019     int flipx,flipy;
01020     Uint8 r,g,b;
01021     Uint32 colorkey = 0;
01022     int colorKeyAvailable = 0;
01023 
01024     /*
01025     * Sanity check
01026     */
01027     if (src == NULL)
01028         return (NULL);
01029 
01030     if (src->flags & SDL_SRCCOLORKEY)
01031     {
01032         colorkey = _colorkey(src);
01033         SDL_GetRGB(colorkey, src->format, &r, &g, &b);
01034         colorKeyAvailable = 1;
01035     }
01036     /*
01037     * Determine if source surface is 32bit or 8bit
01038     */
01039     is32bit = (src->format->BitsPerPixel == 32);
01040     if ((is32bit) || (src->format->BitsPerPixel == 8)) {
01041         /*
01042         * Use source surface 'as is'
01043         */
01044         rz_src = src;
01045         src_converted = 0;
01046     } else {
01047         /*
01048         * New source surface is 32bit with a defined RGBA ordering
01049         */
01050         rz_src =
01051             SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
01052 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
01053             0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
01054 #else
01055             0xff000000,  0x00ff0000, 0x0000ff00, 0x000000ff
01056 #endif
01057             );
01058         if(colorKeyAvailable)
01059             SDL_SetColorKey(src, 0, 0);
01060 
01061         SDL_BlitSurface(src, NULL, rz_src, NULL);
01062 
01063         if(colorKeyAvailable)
01064             SDL_SetColorKey(src, SDL_SRCCOLORKEY, colorkey);
01065         src_converted = 1;
01066         is32bit = 1;
01067     }
01068 
01069     /*
01070     * Sanity check zoom factor
01071     */
01072     flipx = (zoomx<0.0);
01073     if (flipx) zoomx=-zoomx;
01074     flipy = (zoomy<0.0);
01075     if (flipy) zoomy=-zoomy;
01076     if (zoomx < VALUE_LIMIT) zoomx = VALUE_LIMIT;
01077     if (zoomy < VALUE_LIMIT) zoomy = VALUE_LIMIT;
01078     zoominv = 65536.0 / (zoomx * zoomx);
01079 
01080     /*
01081     * Check if we have a rotozoom or just a zoom
01082     */
01083     if (fabs(angle) > VALUE_LIMIT) {
01084 
01085         /*
01086         * Angle!=0: full rotozoom
01087         */
01088         /*
01089         * -----------------------
01090         */
01091 
01092         /* Determine target size */
01093         _rotozoomSurfaceSizeTrig(rz_src->w, rz_src->h, angle, zoomx, zoomy, &dstwidth, &dstheight, &canglezoom, &sanglezoom);
01094 
01095         /*
01096         * Calculate target factors from sin/cos and zoom
01097         */
01098         sanglezoominv = sanglezoom;
01099         canglezoominv = canglezoom;
01100         sanglezoominv *= zoominv;
01101         canglezoominv *= zoominv;
01102 
01103         /* Calculate half size */
01104         dstwidthhalf = dstwidth / 2;
01105         dstheighthalf = dstheight / 2;
01106 
01107         /*
01108         * Alloc space to completely contain the rotated surface
01109         */
01110         rz_dst = NULL;
01111         if (is32bit) {
01112             /*
01113             * Target surface is 32bit with source RGBA/ABGR ordering
01114             */
01115             rz_dst =
01116                 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
01117                 rz_src->format->Rmask, rz_src->format->Gmask,
01118                 rz_src->format->Bmask, rz_src->format->Amask);
01119         } else {
01120             /*
01121             * Target surface is 8bit
01122             */
01123             rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
01124         }
01125 
01126         /* Check target */
01127         if (rz_dst == NULL)
01128             return NULL;
01129 
01130         /* Adjust for guard rows */
01131         rz_dst->h = dstheight;
01132 
01133         if (colorKeyAvailable == 1){
01134             colorkey = SDL_MapRGB(rz_dst->format, r, g, b);
01135 
01136             SDL_FillRect(rz_dst, NULL, colorkey );
01137         }
01138 
01139         /*
01140         * Lock source surface
01141         */
01142         if (SDL_MUSTLOCK(rz_src)) {
01143             SDL_LockSurface(rz_src);
01144         }
01145 
01146         /*
01147         * Check which kind of surface we have
01148         */
01149         if (is32bit) {
01150             /*
01151             * Call the 32bit transformation routine to do the rotation (using alpha)
01152             */
01153             _transformSurfaceRGBA(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
01154                 (int) (sanglezoominv), (int) (canglezoominv),
01155                 flipx, flipy,
01156                 smooth);
01157             /*
01158             * Turn on source-alpha support
01159             */
01160             SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
01161             SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
01162         } else {
01163             /*
01164             * Copy palette and colorkey info
01165             */
01166             for (i = 0; i < rz_src->format->palette->ncolors; i++) {
01167                 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
01168             }
01169             rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
01170             /*
01171             * Call the 8bit transformation routine to do the rotation
01172             */
01173             transformSurfaceY(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
01174                 (int) (sanglezoominv), (int) (canglezoominv),
01175                 flipx, flipy);
01176             SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
01177         }
01178         /*
01179         * Unlock source surface
01180         */
01181         if (SDL_MUSTLOCK(rz_src)) {
01182             SDL_UnlockSurface(rz_src);
01183         }
01184 
01185     } else {
01186 
01187         /*
01188         * Angle=0: Just a zoom
01189         */
01190         /*
01191         * --------------------
01192         */
01193 
01194         /*
01195         * Calculate target size
01196         */
01197         zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
01198 
01199         /*
01200         * Alloc space to completely contain the zoomed surface
01201         */
01202         rz_dst = NULL;
01203         if (is32bit) {
01204             /*
01205             * Target surface is 32bit with source RGBA/ABGR ordering
01206             */
01207             rz_dst =
01208                 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
01209                 rz_src->format->Rmask, rz_src->format->Gmask,
01210                 rz_src->format->Bmask, rz_src->format->Amask);
01211         } else {
01212             /*
01213             * Target surface is 8bit
01214             */
01215             rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
01216         }
01217 
01218         /* Check target */
01219         if (rz_dst == NULL)
01220             return NULL;
01221 
01222         /* Adjust for guard rows */
01223         rz_dst->h = dstheight;
01224 
01225         if (colorKeyAvailable == 1){
01226             colorkey = SDL_MapRGB(rz_dst->format, r, g, b);
01227 
01228             SDL_FillRect(rz_dst, NULL, colorkey );
01229         }
01230 
01231         /*
01232         * Lock source surface
01233         */
01234         if (SDL_MUSTLOCK(rz_src)) {
01235             SDL_LockSurface(rz_src);
01236         }
01237 
01238         /*
01239         * Check which kind of surface we have
01240         */
01241         if (is32bit) {
01242             /*
01243             * Call the 32bit transformation routine to do the zooming (using alpha)
01244             */
01245             _zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
01246 
01247             /*
01248             * Turn on source-alpha support
01249             */
01250             SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
01251             SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
01252         } else {
01253             /*
01254             * Copy palette and colorkey info
01255             */
01256             for (i = 0; i < rz_src->format->palette->ncolors; i++) {
01257                 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
01258             }
01259             rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
01260 
01261             /*
01262             * Call the 8bit transformation routine to do the zooming
01263             */
01264             _zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
01265             SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
01266         }
01267 
01268         /*
01269         * Unlock source surface
01270         */
01271         if (SDL_MUSTLOCK(rz_src)) {
01272             SDL_UnlockSurface(rz_src);
01273         }
01274     }
01275 
01276     /*
01277     * Cleanup temp surface
01278     */
01279     if (src_converted) {
01280         SDL_FreeSurface(rz_src);
01281     }
01282 
01283     /*
01284     * Return destination surface
01285     */
01286     return (rz_dst);
01287 }
01288 
01301 void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight)
01302 {
01303     /*
01304     * Make zoom factors positive
01305     */
01306     int flipx, flipy;
01307     flipx = (zoomx<0.0);
01308     if (flipx) zoomx = -zoomx;
01309     flipy = (zoomy<0.0);
01310     if (flipy) zoomy = -zoomy;
01311 
01312     /*
01313     * Sanity check zoom factors
01314     */
01315     if (zoomx < VALUE_LIMIT) {
01316         zoomx = VALUE_LIMIT;
01317     }
01318     if (zoomy < VALUE_LIMIT) {
01319         zoomy = VALUE_LIMIT;
01320     }
01321 
01322     /*
01323     * Calculate target size
01324     */
01325     *dstwidth = (int) ((double) width * zoomx);
01326     *dstheight = (int) ((double) height * zoomy);
01327     if (*dstwidth < 1) {
01328         *dstwidth = 1;
01329     }
01330     if (*dstheight < 1) {
01331         *dstheight = 1;
01332     }
01333 }
01334 
01351 SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth)
01352 {
01353     SDL_Surface *rz_src;
01354     SDL_Surface *rz_dst;
01355     int dstwidth, dstheight;
01356     int is32bit;
01357     int i, src_converted;
01358     int flipx, flipy;
01359 
01360     /*
01361     * Sanity check
01362     */
01363     if (src == NULL)
01364         return (NULL);
01365 
01366     /*
01367     * Determine if source surface is 32bit or 8bit
01368     */
01369     is32bit = (src->format->BitsPerPixel == 32);
01370     if ((is32bit) || (src->format->BitsPerPixel == 8)) {
01371         /*
01372         * Use source surface 'as is'
01373         */
01374         rz_src = src;
01375         src_converted = 0;
01376     } else {
01377         /*
01378         * New source surface is 32bit with a defined RGBA ordering
01379         */
01380         rz_src =
01381             SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
01382 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
01383             0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
01384 #else
01385             0xff000000,  0x00ff0000, 0x0000ff00, 0x000000ff
01386 #endif
01387             );
01388         SDL_BlitSurface(src, NULL, rz_src, NULL);
01389         src_converted = 1;
01390         is32bit = 1;
01391     }
01392 
01393     flipx = (zoomx<0.0);
01394     if (flipx) zoomx = -zoomx;
01395     flipy = (zoomy<0.0);
01396     if (flipy) zoomy = -zoomy;
01397 
01398     /* Get size if target */
01399     zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
01400 
01401     /*
01402     * Alloc space to completely contain the zoomed surface
01403     */
01404     rz_dst = NULL;
01405     if (is32bit) {
01406         /*
01407         * Target surface is 32bit with source RGBA/ABGR ordering
01408         */
01409         rz_dst =
01410             SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
01411             rz_src->format->Rmask, rz_src->format->Gmask,
01412             rz_src->format->Bmask, rz_src->format->Amask);
01413     } else {
01414         /*
01415         * Target surface is 8bit
01416         */
01417         rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
01418     }
01419 
01420     /* Check target */
01421     if (rz_dst == NULL)
01422         return NULL;
01423 
01424     /* Adjust for guard rows */
01425     rz_dst->h = dstheight;
01426 
01427     /*
01428     * Lock source surface
01429     */
01430     if (SDL_MUSTLOCK(rz_src)) {
01431         SDL_LockSurface(rz_src);
01432     }
01433 
01434     /*
01435     * Check which kind of surface we have
01436     */
01437     if (is32bit) {
01438         /*
01439         * Call the 32bit transformation routine to do the zooming (using alpha)
01440         */
01441         _zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
01442         /*
01443         * Turn on source-alpha support
01444         */
01445         SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
01446     } else {
01447         /*
01448         * Copy palette and colorkey info
01449         */
01450         for (i = 0; i < rz_src->format->palette->ncolors; i++) {
01451             rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
01452         }
01453         rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
01454         /*
01455         * Call the 8bit transformation routine to do the zooming
01456         */
01457         _zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
01458         SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
01459     }
01460     /*
01461     * Unlock source surface
01462     */
01463     if (SDL_MUSTLOCK(rz_src)) {
01464         SDL_UnlockSurface(rz_src);
01465     }
01466 
01467     /*
01468     * Cleanup temp surface
01469     */
01470     if (src_converted) {
01471         SDL_FreeSurface(rz_src);
01472     }
01473 
01474     /*
01475     * Return destination surface
01476     */
01477     return (rz_dst);
01478 }
01479 
01496 SDL_Surface *shrinkSurface(SDL_Surface *src, int factorx, int factory)
01497 {
01498     SDL_Surface *rz_src;
01499     SDL_Surface *rz_dst;
01500     int dstwidth, dstheight;
01501     int is32bit;
01502     int i, src_converted;
01503 
01504     /*
01505     * Sanity check
01506     */
01507     if (src == NULL)
01508         return (NULL);
01509 
01510     /*
01511     * Determine if source surface is 32bit or 8bit
01512     */
01513     is32bit = (src->format->BitsPerPixel == 32);
01514     if ((is32bit) || (src->format->BitsPerPixel == 8)) {
01515         /*
01516         * Use source surface 'as is'
01517         */
01518         rz_src = src;
01519         src_converted = 0;
01520     } else {
01521         /*
01522         * New source surface is 32bit with a defined RGBA ordering
01523         */
01524         rz_src =
01525             SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
01526 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
01527             0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
01528 #else
01529             0xff000000,  0x00ff0000, 0x0000ff00, 0x000000ff
01530 #endif
01531             );
01532         SDL_BlitSurface(src, NULL, rz_src, NULL);
01533         src_converted = 1;
01534         is32bit = 1;
01535     }
01536 
01537     /* Get size for target */
01538     dstwidth=rz_src->w/factorx;
01539     while (dstwidth*factorx>rz_src->w) { dstwidth--; }
01540     dstheight=rz_src->h/factory;
01541     while (dstheight*factory>rz_src->h) { dstheight--; }
01542 
01543     /*
01544     * Alloc space to completely contain the shrunken surface
01545     * (with added guard rows)
01546     */
01547     rz_dst = NULL;
01548     if (is32bit) {
01549         /*
01550         * Target surface is 32bit with source RGBA/ABGR ordering
01551         */
01552         rz_dst =
01553             SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
01554             rz_src->format->Rmask, rz_src->format->Gmask,
01555             rz_src->format->Bmask, rz_src->format->Amask);
01556     } else {
01557         /*
01558         * Target surface is 8bit
01559         */
01560         rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
01561     }
01562 
01563     /* Check target */
01564     if (rz_dst == NULL)
01565         return NULL;
01566 
01567     /* Adjust for guard rows */
01568     rz_dst->h = dstheight;
01569 
01570     /*
01571     * Lock source surface
01572     */
01573     if (SDL_MUSTLOCK(rz_src)) {
01574         SDL_LockSurface(rz_src);
01575     }
01576 
01577     /*
01578     * Check which kind of surface we have
01579     */
01580     if (is32bit) {
01581         /*
01582         * Call the 32bit transformation routine to do the shrinking (using alpha)
01583         */
01584         _shrinkSurfaceRGBA(rz_src, rz_dst, factorx, factory);
01585         /*
01586         * Turn on source-alpha support
01587         */
01588         SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
01589     } else {
01590         /*
01591         * Copy palette and colorkey info
01592         */
01593         for (i = 0; i < rz_src->format->palette->ncolors; i++) {
01594             rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
01595         }
01596         rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
01597         /*
01598         * Call the 8bit transformation routine to do the shrinking
01599         */
01600         _shrinkSurfaceY(rz_src, rz_dst, factorx, factory);
01601         SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
01602     }
01603 
01604     /*
01605     * Unlock source surface
01606     */
01607     if (SDL_MUSTLOCK(rz_src)) {
01608         SDL_UnlockSurface(rz_src);
01609     }
01610 
01611     /*
01612     * Cleanup temp surface
01613     */
01614     if (src_converted) {
01615         SDL_FreeSurface(rz_src);
01616     }
01617 
01618     /*
01619     * Return destination surface
01620     */
01621     return (rz_dst);
01622 }