SDL2_gfx
1.0.1
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, 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 }