SDL2_gfx
1.0.0
GraphicsprimitivesandsurfacefunctionsforSDL2
|
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; 00807 SDL_Surface* dst; 00808 Uint8* srcBuf; 00809 Uint8* dstBuf; 00810 00811 /* Has to be a valid surface pointer and be a 8/16/24/32-bit surface */ 00812 if (!src || !src->format || 00813 !(src->format->BitsPerPixel == 8) || 00814 (src->format->BitsPerPixel == 16) || 00815 (src->format->BitsPerPixel == 24) || 00816 (src->format->BitsPerPixel == 32)) { return NULL; } 00817 00818 /* normalize numClockwiseTurns */ 00819 while(numClockwiseTurns < 0) { numClockwiseTurns += 4; } 00820 numClockwiseTurns = (numClockwiseTurns % 4); 00821 00822 /* if it's even, our new width will be the same as the source surface */ 00823 newWidth = (numClockwiseTurns % 2) ? (src->h) : (src->w); 00824 newHeight = (numClockwiseTurns % 2) ? (src->w) : (src->h); 00825 dst = SDL_CreateRGBSurface( src->flags, newWidth, newHeight, src->format->BitsPerPixel, 00826 src->format->Rmask, 00827 src->format->Gmask, 00828 src->format->Bmask, 00829 src->format->Amask); 00830 if(!dst) { 00831 return NULL; 00832 } 00833 00834 if (SDL_MUSTLOCK(src)) { 00835 SDL_LockSurface(src); 00836 } 00837 if (SDL_MUSTLOCK(dst)) { 00838 SDL_LockSurface(dst); 00839 } 00840 00841 /* Calculate byte-per-pixel */ 00842 bpp = src->format->BitsPerPixel / 8; 00843 00844 switch(numClockwiseTurns) { 00845 case 0: /* Make a copy of the surface */ 00846 { 00847 /* Unfortunately SDL_BlitSurface cannot be used to make a copy of the surface 00848 since it does not preserve alpha. */ 00849 00850 if (src->pitch == dst->pitch) { 00851 /* If the pitch is the same for both surfaces, the memory can be copied all at once. */ 00852 memcpy(dst->pixels, src->pixels, (src->h * src->pitch)); 00853 } 00854 else 00855 { 00856 /* If the pitch differs, copy each row separately */ 00857 srcBuf = (Uint8*)(src->pixels); 00858 dstBuf = (Uint8*)(dst->pixels); 00859 for (row = 0; row < src->h; row++) { 00860 memcpy(dstBuf, srcBuf, dst->w * bpp); 00861 srcBuf += src->pitch; 00862 dstBuf += dst->pitch; 00863 } /* end for(col) */ 00864 } /* end for(row) */ 00865 } 00866 break; 00867 00868 /* rotate clockwise */ 00869 case 1: /* rotated 90 degrees clockwise */ 00870 { 00871 for (row = 0; row < src->h; ++row) { 00872 srcBuf = (Uint8*)(src->pixels) + (row * src->pitch); 00873 dstBuf = (Uint8*)(dst->pixels) + (dst->w - row - 1) * bpp; 00874 for (col = 0; col < src->w; ++col) { 00875 memcpy (dstBuf, srcBuf, bpp); 00876 srcBuf += bpp; 00877 dstBuf += dst->pitch; 00878 } 00879 } 00880 } 00881 break; 00882 00883 case 2: /* rotated 180 degrees clockwise */ 00884 { 00885 for (row = 0; row < src->h; ++row) { 00886 srcBuf = (Uint8*)(src->pixels) + (row * src->pitch); 00887 dstBuf = (Uint8*)(dst->pixels) + ((dst->h - row - 1) * dst->pitch) + (dst->w - 1) * bpp; 00888 for (col = 0; col < src->w; ++col) { 00889 memcpy (dstBuf, srcBuf, bpp); 00890 srcBuf += bpp; 00891 dstBuf -= bpp; 00892 } 00893 } 00894 } 00895 break; 00896 00897 case 3: /* rotated 270 degrees clockwise */ 00898 { 00899 for (row = 0; row < src->h; ++row) { 00900 srcBuf = (Uint8*)(src->pixels) + (row * src->pitch); 00901 dstBuf = (Uint8*)(dst->pixels) + row + ((dst->h - 1) * dst->pitch); 00902 for (col = 0; col < src->w; ++col) { 00903 *dstBuf = *srcBuf; 00904 srcBuf += bpp; 00905 dstBuf -= dst->pitch; 00906 } 00907 } 00908 } 00909 break; 00910 } 00911 /* end switch */ 00912 00913 if (SDL_MUSTLOCK(src)) { 00914 SDL_UnlockSurface(src); 00915 } 00916 if (SDL_MUSTLOCK(dst)) { 00917 SDL_UnlockSurface(dst); 00918 } 00919 00920 return dst; 00921 } 00922 00923 00938 void _rotozoomSurfaceSizeTrig(int width, int height, double angle, double zoomx, double zoomy, 00939 int *dstwidth, int *dstheight, 00940 double *canglezoom, double *sanglezoom) 00941 { 00942 double x, y, cx, cy, sx, sy; 00943 double radangle; 00944 int dstwidthhalf, dstheighthalf; 00945 00946 /* 00947 * Determine destination width and height by rotating a centered source box 00948 */ 00949 radangle = angle * (M_PI / 180.0); 00950 *sanglezoom = sin(radangle); 00951 *canglezoom = cos(radangle); 00952 *sanglezoom *= zoomx; 00953 *canglezoom *= zoomx; 00954 x = (double)(width / 2); 00955 y = (double)(height / 2); 00956 cx = *canglezoom * x; 00957 cy = *canglezoom * y; 00958 sx = *sanglezoom * x; 00959 sy = *sanglezoom * y; 00960 00961 dstwidthhalf = MAX((int) 00962 ceil(MAX(MAX(MAX(fabs(cx + sy), fabs(cx - sy)), fabs(-cx + sy)), fabs(-cx - sy))), 1); 00963 dstheighthalf = MAX((int) 00964 ceil(MAX(MAX(MAX(fabs(sx + cy), fabs(sx - cy)), fabs(-sx + cy)), fabs(-sx - cy))), 1); 00965 *dstwidth = 2 * dstwidthhalf; 00966 *dstheight = 2 * dstheighthalf; 00967 } 00968 00980 void rotozoomSurfaceSizeXY(int width, int height, double angle, double zoomx, double zoomy, int *dstwidth, int *dstheight) 00981 { 00982 double dummy_sanglezoom, dummy_canglezoom; 00983 00984 _rotozoomSurfaceSizeTrig(width, height, angle, zoomx, zoomy, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom); 00985 } 00986 00997 void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth, int *dstheight) 00998 { 00999 double dummy_sanglezoom, dummy_canglezoom; 01000 01001 _rotozoomSurfaceSizeTrig(width, height, angle, zoom, zoom, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom); 01002 } 01003 01019 SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth) 01020 { 01021 return rotozoomSurfaceXY(src, angle, zoom, zoom, smooth); 01022 } 01023 01040 SDL_Surface *rotozoomSurfaceXY(SDL_Surface * src, double angle, double zoomx, double zoomy, int smooth) 01041 { 01042 SDL_Surface *rz_src; 01043 SDL_Surface *rz_dst; 01044 double zoominv; 01045 double sanglezoom, canglezoom, sanglezoominv, canglezoominv; 01046 int dstwidthhalf, dstwidth, dstheighthalf, dstheight; 01047 int is32bit; 01048 int i, src_converted; 01049 int flipx,flipy; 01050 01051 /* 01052 * Sanity check 01053 */ 01054 if (src == NULL) { 01055 return (NULL); 01056 } 01057 01058 /* 01059 * Determine if source surface is 32bit or 8bit 01060 */ 01061 is32bit = (src->format->BitsPerPixel == 32); 01062 if ((is32bit) || (src->format->BitsPerPixel == 8)) { 01063 /* 01064 * Use source surface 'as is' 01065 */ 01066 rz_src = src; 01067 src_converted = 0; 01068 } else { 01069 /* 01070 * New source surface is 32bit with a defined RGBA ordering 01071 */ 01072 rz_src = 01073 SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, 01074 #if SDL_BYTEORDER == SDL_LIL_ENDIAN 01075 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 01076 #else 01077 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff 01078 #endif 01079 ); 01080 01081 SDL_BlitSurface(src, NULL, rz_src, NULL); 01082 01083 src_converted = 1; 01084 is32bit = 1; 01085 } 01086 01087 /* 01088 * Sanity check zoom factor 01089 */ 01090 flipx = (zoomx<0.0); 01091 if (flipx) zoomx=-zoomx; 01092 flipy = (zoomy<0.0); 01093 if (flipy) zoomy=-zoomy; 01094 if (zoomx < VALUE_LIMIT) zoomx = VALUE_LIMIT; 01095 if (zoomy < VALUE_LIMIT) zoomy = VALUE_LIMIT; 01096 zoominv = 65536.0 / (zoomx * zoomx); 01097 01098 /* 01099 * Check if we have a rotozoom or just a zoom 01100 */ 01101 if (fabs(angle) > VALUE_LIMIT) { 01102 01103 /* 01104 * Angle!=0: full rotozoom 01105 */ 01106 /* 01107 * ----------------------- 01108 */ 01109 01110 /* Determine target size */ 01111 _rotozoomSurfaceSizeTrig(rz_src->w, rz_src->h, angle, zoomx, zoomy, &dstwidth, &dstheight, &canglezoom, &sanglezoom); 01112 01113 /* 01114 * Calculate target factors from sin/cos and zoom 01115 */ 01116 sanglezoominv = sanglezoom; 01117 canglezoominv = canglezoom; 01118 sanglezoominv *= zoominv; 01119 canglezoominv *= zoominv; 01120 01121 /* Calculate half size */ 01122 dstwidthhalf = dstwidth / 2; 01123 dstheighthalf = dstheight / 2; 01124 01125 /* 01126 * Alloc space to completely contain the rotated surface 01127 */ 01128 rz_dst = NULL; 01129 if (is32bit) { 01130 /* 01131 * Target surface is 32bit with source RGBA/ABGR ordering 01132 */ 01133 rz_dst = 01134 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32, 01135 rz_src->format->Rmask, rz_src->format->Gmask, 01136 rz_src->format->Bmask, rz_src->format->Amask); 01137 } else { 01138 /* 01139 * Target surface is 8bit 01140 */ 01141 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0); 01142 } 01143 01144 /* Check target */ 01145 if (rz_dst == NULL) 01146 return NULL; 01147 01148 /* Adjust for guard rows */ 01149 rz_dst->h = dstheight; 01150 01151 /* 01152 * Lock source surface 01153 */ 01154 if (SDL_MUSTLOCK(rz_src)) { 01155 SDL_LockSurface(rz_src); 01156 } 01157 01158 /* 01159 * Check which kind of surface we have 01160 */ 01161 if (is32bit) { 01162 /* 01163 * Call the 32bit transformation routine to do the rotation (using alpha) 01164 */ 01165 _transformSurfaceRGBA(rz_src, rz_dst, dstwidthhalf, dstheighthalf, 01166 (int) (sanglezoominv), (int) (canglezoominv), 01167 flipx, flipy, 01168 smooth); 01169 } else { 01170 /* 01171 * Copy palette and colorkey info 01172 */ 01173 for (i = 0; i < rz_src->format->palette->ncolors; i++) { 01174 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i]; 01175 } 01176 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors; 01177 /* 01178 * Call the 8bit transformation routine to do the rotation 01179 */ 01180 transformSurfaceY(rz_src, rz_dst, dstwidthhalf, dstheighthalf, 01181 (int) (sanglezoominv), (int) (canglezoominv), 01182 flipx, flipy); 01183 } 01184 /* 01185 * Unlock source surface 01186 */ 01187 if (SDL_MUSTLOCK(rz_src)) { 01188 SDL_UnlockSurface(rz_src); 01189 } 01190 01191 } else { 01192 01193 /* 01194 * Angle=0: Just a zoom 01195 */ 01196 /* 01197 * -------------------- 01198 */ 01199 01200 /* 01201 * Calculate target size 01202 */ 01203 zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight); 01204 01205 /* 01206 * Alloc space to completely contain the zoomed surface 01207 */ 01208 rz_dst = NULL; 01209 if (is32bit) { 01210 /* 01211 * Target surface is 32bit with source RGBA/ABGR ordering 01212 */ 01213 rz_dst = 01214 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32, 01215 rz_src->format->Rmask, rz_src->format->Gmask, 01216 rz_src->format->Bmask, rz_src->format->Amask); 01217 } else { 01218 /* 01219 * Target surface is 8bit 01220 */ 01221 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0); 01222 } 01223 01224 /* Check target */ 01225 if (rz_dst == NULL) 01226 return NULL; 01227 01228 /* Adjust for guard rows */ 01229 rz_dst->h = dstheight; 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 } else { 01248 /* 01249 * Copy palette and colorkey info 01250 */ 01251 for (i = 0; i < rz_src->format->palette->ncolors; i++) { 01252 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i]; 01253 } 01254 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors; 01255 01256 /* 01257 * Call the 8bit transformation routine to do the zooming 01258 */ 01259 _zoomSurfaceY(rz_src, rz_dst, flipx, flipy); 01260 } 01261 01262 /* 01263 * Unlock source surface 01264 */ 01265 if (SDL_MUSTLOCK(rz_src)) { 01266 SDL_UnlockSurface(rz_src); 01267 } 01268 } 01269 01270 /* 01271 * Cleanup temp surface 01272 */ 01273 if (src_converted) { 01274 SDL_FreeSurface(rz_src); 01275 } 01276 01277 /* 01278 * Return destination surface 01279 */ 01280 return (rz_dst); 01281 } 01282 01295 void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight) 01296 { 01297 /* 01298 * Make zoom factors positive 01299 */ 01300 int flipx, flipy; 01301 flipx = (zoomx<0.0); 01302 if (flipx) zoomx = -zoomx; 01303 flipy = (zoomy<0.0); 01304 if (flipy) zoomy = -zoomy; 01305 01306 /* 01307 * Sanity check zoom factors 01308 */ 01309 if (zoomx < VALUE_LIMIT) { 01310 zoomx = VALUE_LIMIT; 01311 } 01312 if (zoomy < VALUE_LIMIT) { 01313 zoomy = VALUE_LIMIT; 01314 } 01315 01316 /* 01317 * Calculate target size 01318 */ 01319 *dstwidth = (int) floor(((double) width * zoomx) + 0.5); 01320 *dstheight = (int) floor(((double) height * zoomy) + 0.5); 01321 if (*dstwidth < 1) { 01322 *dstwidth = 1; 01323 } 01324 if (*dstheight < 1) { 01325 *dstheight = 1; 01326 } 01327 } 01328 01345 SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth) 01346 { 01347 SDL_Surface *rz_src; 01348 SDL_Surface *rz_dst; 01349 int dstwidth, dstheight; 01350 int is32bit; 01351 int i, src_converted; 01352 int flipx, flipy; 01353 01354 /* 01355 * Sanity check 01356 */ 01357 if (src == NULL) 01358 return (NULL); 01359 01360 /* 01361 * Determine if source surface is 32bit or 8bit 01362 */ 01363 is32bit = (src->format->BitsPerPixel == 32); 01364 if ((is32bit) || (src->format->BitsPerPixel == 8)) { 01365 /* 01366 * Use source surface 'as is' 01367 */ 01368 rz_src = src; 01369 src_converted = 0; 01370 } else { 01371 /* 01372 * New source surface is 32bit with a defined RGBA ordering 01373 */ 01374 rz_src = 01375 SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, 01376 #if SDL_BYTEORDER == SDL_LIL_ENDIAN 01377 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 01378 #else 01379 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff 01380 #endif 01381 ); 01382 if (rz_src == NULL) { 01383 return NULL; 01384 } 01385 SDL_BlitSurface(src, NULL, rz_src, NULL); 01386 src_converted = 1; 01387 is32bit = 1; 01388 } 01389 01390 flipx = (zoomx<0.0); 01391 if (flipx) zoomx = -zoomx; 01392 flipy = (zoomy<0.0); 01393 if (flipy) zoomy = -zoomy; 01394 01395 /* Get size if target */ 01396 zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight); 01397 01398 /* 01399 * Alloc space to completely contain the zoomed surface 01400 */ 01401 rz_dst = NULL; 01402 if (is32bit) { 01403 /* 01404 * Target surface is 32bit with source RGBA/ABGR ordering 01405 */ 01406 rz_dst = 01407 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32, 01408 rz_src->format->Rmask, rz_src->format->Gmask, 01409 rz_src->format->Bmask, rz_src->format->Amask); 01410 } else { 01411 /* 01412 * Target surface is 8bit 01413 */ 01414 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0); 01415 } 01416 01417 /* Check target */ 01418 if (rz_dst == NULL) { 01419 /* 01420 * Cleanup temp surface 01421 */ 01422 if (src_converted) { 01423 SDL_FreeSurface(rz_src); 01424 } 01425 return NULL; 01426 } 01427 01428 /* Adjust for guard rows */ 01429 rz_dst->h = dstheight; 01430 01431 /* 01432 * Lock source surface 01433 */ 01434 if (SDL_MUSTLOCK(rz_src)) { 01435 SDL_LockSurface(rz_src); 01436 } 01437 01438 /* 01439 * Check which kind of surface we have 01440 */ 01441 if (is32bit) { 01442 /* 01443 * Call the 32bit transformation routine to do the zooming (using alpha) 01444 */ 01445 _zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth); 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 } 01459 /* 01460 * Unlock source surface 01461 */ 01462 if (SDL_MUSTLOCK(rz_src)) { 01463 SDL_UnlockSurface(rz_src); 01464 } 01465 01466 /* 01467 * Cleanup temp surface 01468 */ 01469 if (src_converted) { 01470 SDL_FreeSurface(rz_src); 01471 } 01472 01473 /* 01474 * Return destination surface 01475 */ 01476 return (rz_dst); 01477 } 01478 01495 /*@null@*/ 01496 SDL_Surface *shrinkSurface(SDL_Surface *src, int factorx, int factory) 01497 { 01498 int result; 01499 SDL_Surface *rz_src; 01500 SDL_Surface *rz_dst = NULL; 01501 int dstwidth, dstheight; 01502 int is32bit; 01503 int i, src_converted; 01504 int haveError = 0; 01505 01506 /* 01507 * Sanity check 01508 */ 01509 if (src == NULL) { 01510 return (NULL); 01511 } 01512 01513 /* 01514 * Determine if source surface is 32bit or 8bit 01515 */ 01516 is32bit = (src->format->BitsPerPixel == 32); 01517 if ((is32bit) || (src->format->BitsPerPixel == 8)) { 01518 /* 01519 * Use source surface 'as is' 01520 */ 01521 rz_src = src; 01522 src_converted = 0; 01523 } else { 01524 /* 01525 * New source surface is 32bit with a defined RGBA ordering 01526 */ 01527 rz_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, 01528 #if SDL_BYTEORDER == SDL_LIL_ENDIAN 01529 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 01530 #else 01531 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff 01532 #endif 01533 ); 01534 if (rz_src==NULL) { 01535 haveError = 1; 01536 goto exitShrinkSurface; 01537 } 01538 01539 SDL_BlitSurface(src, NULL, rz_src, NULL); 01540 src_converted = 1; 01541 is32bit = 1; 01542 } 01543 01544 /* 01545 * Lock the surface 01546 */ 01547 if (SDL_MUSTLOCK(rz_src)) { 01548 if (SDL_LockSurface(rz_src) < 0) { 01549 haveError = 1; 01550 goto exitShrinkSurface; 01551 } 01552 } 01553 01554 /* Get size for target */ 01555 dstwidth=rz_src->w/factorx; 01556 while (dstwidth*factorx>rz_src->w) { dstwidth--; } 01557 dstheight=rz_src->h/factory; 01558 while (dstheight*factory>rz_src->h) { dstheight--; } 01559 01560 /* 01561 * Alloc space to completely contain the shrunken surface 01562 * (with added guard rows) 01563 */ 01564 if (is32bit==1) { 01565 /* 01566 * Target surface is 32bit with source RGBA/ABGR ordering 01567 */ 01568 rz_dst = 01569 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32, 01570 rz_src->format->Rmask, rz_src->format->Gmask, 01571 rz_src->format->Bmask, rz_src->format->Amask); 01572 } else { 01573 /* 01574 * Target surface is 8bit 01575 */ 01576 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0); 01577 } 01578 01579 /* Check target */ 01580 if (rz_dst == NULL) { 01581 haveError = 1; 01582 goto exitShrinkSurface; 01583 } 01584 01585 /* Adjust for guard rows */ 01586 rz_dst->h = dstheight; 01587 01588 /* 01589 * Check which kind of surface we have 01590 */ 01591 if (is32bit==1) { 01592 /* 01593 * Call the 32bit transformation routine to do the shrinking (using alpha) 01594 */ 01595 result = _shrinkSurfaceRGBA(rz_src, rz_dst, factorx, factory); 01596 if ((result!=0) || (rz_dst==NULL)) { 01597 haveError = 1; 01598 goto exitShrinkSurface; 01599 } 01600 } else { 01601 /* 01602 * Copy palette and colorkey info 01603 */ 01604 for (i = 0; i < rz_src->format->palette->ncolors; i++) { 01605 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i]; 01606 } 01607 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors; 01608 /* 01609 * Call the 8bit transformation routine to do the shrinking 01610 */ 01611 result = _shrinkSurfaceY(rz_src, rz_dst, factorx, factory); 01612 if (result!=0) { 01613 haveError = 1; 01614 goto exitShrinkSurface; 01615 } 01616 } 01617 01618 exitShrinkSurface: 01619 if (rz_src!=NULL) { 01620 /* 01621 * Unlock source surface 01622 */ 01623 if (SDL_MUSTLOCK(rz_src)) { 01624 SDL_UnlockSurface(rz_src); 01625 } 01626 01627 /* 01628 * Cleanup temp surface 01629 */ 01630 if (src_converted==1) { 01631 SDL_FreeSurface(rz_src); 01632 } 01633 } 01634 01635 /* Check error state; maybe need to cleanup destination */ 01636 if (haveError==1) { 01637 if (rz_dst!=NULL) { 01638 SDL_FreeSurface(rz_dst); 01639 } 01640 rz_dst=NULL; 01641 } 01642 01643 /* 01644 * Return destination surface 01645 */ 01646 return (rz_dst); 01647 }