Don't delete ChangeLog when cleaning
[tennix.git] / SDL_rotozoom.c
blobbaff64d3cbaabaf0752085649ff6ba7867ee1d5e
1 /*
3 SDL_rotozoom.c - rotozoomer for 32bit or 8bit surfaces
5 LGPL (c) A. Schiffler
7 */
9 #include <stdlib.h>
10 #include <string.h>
12 #include "SDL_rotozoom.h"
14 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
17 /*
19 32bit integer-factor averaging Shrinker
21 Shrinks 32bit RGBA/ABGR 'src' surface to 'dst' surface.
25 int shrinkSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
27 int x, y, dx, dy, sgap, dgap, ra, ga, ba, aa;
28 int n_average;
29 tColorRGBA *sp, *osp, *oosp;
30 tColorRGBA *dp;
33 * Averaging integer shrink
36 /* Precalculate division factor */
37 n_average = factorx*factory;
40 * Scan destination
42 sp = (tColorRGBA *) src->pixels;
43 sgap = src->pitch - src->w * 4;
45 dp = (tColorRGBA *) dst->pixels;
46 dgap = dst->pitch - dst->w * 4;
48 for (y = 0; y < dst->h; y++) {
50 osp=sp;
51 for (x = 0; x < dst->w; x++) {
53 /* Trace out source box and accumulate */
54 oosp=sp;
55 ra=ga=ba=aa=0;
56 for (dy=0; dy < factory; dy++) {
57 for (dx=0; dx < factorx; dx++) {
58 ra += sp->r;
59 ga += sp->g;
60 ba += sp->b;
61 aa += sp->a;
63 sp++;
65 sp = (tColorRGBA *)((Uint8*)sp + (src->pitch - 4*factorx));
69 sp = (tColorRGBA *)((Uint8*)oosp + 4*factorx);
71 /* Store result in destination */
72 dp->r = ra/n_average;
73 dp->g = ga/n_average;
74 dp->b = ba/n_average;
75 dp->a = aa/n_average;
78 * Advance destination pointer
80 dp++;
84 sp = (tColorRGBA *)((Uint8*)osp + src->pitch*factory);
87 * Advance destination pointers
89 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
92 return (0);
95 /*
97 8bit integer-factor averaging Shrinker
99 Shrinks 8bit Y 'src' surface to 'dst' surface.
103 int shrinkSurfaceY(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
105 int x, y, dx, dy, sgap, dgap, a;
106 int n_average;
107 Uint8 *sp, *osp, *oosp;
108 Uint8 *dp;
111 * Averaging integer shrink
114 /* Precalculate division factor */
115 n_average = factorx*factory;
118 * Scan destination
120 sp = (Uint8 *) src->pixels;
121 sgap = src->pitch - src->w;
123 dp = (Uint8 *) dst->pixels;
124 dgap = dst->pitch - dst->w;
126 for (y = 0; y < dst->h; y++) {
128 osp=sp;
129 for (x = 0; x < dst->w; x++) {
131 /* Trace out source box and accumulate */
132 oosp=sp;
133 a=0;
134 for (dy=0; dy < factory; dy++) {
135 for (dx=0; dx < factorx; dx++) {
136 a += (*sp);
137 sp++;
139 sp = (Uint8 *)((Uint8*)sp + (src->pitch - factorx));
143 sp = (Uint8 *)((Uint8*)oosp + factorx);
145 /* Store result in destination */
146 *dp = a/n_average;
149 * Advance destination pointer
151 dp++;
155 sp = (Uint8 *)((Uint8*)osp + src->pitch*factory);
158 * Advance destination pointers
160 dp = (Uint8 *)((Uint8 *)dp + dgap);
163 return (0);
168 32bit Zoomer with optional anti-aliasing by bilinear interpolation.
170 Zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
174 int zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy, int smooth)
176 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy, ex, ey, t1, t2, sstep;
177 tColorRGBA *c00, *c01, *c10, *c11;
178 tColorRGBA *sp, *csp, *dp;
179 int dgap;
182 * Variable setup
184 if (smooth) {
186 * For interpolation: assume source dimension is one pixel
189 * smaller to avoid overflow on right and bottom edge.
191 sx = (int) (65536.0 * (float) (src->w - 1) / (float) dst->w);
192 sy = (int) (65536.0 * (float) (src->h - 1) / (float) dst->h);
193 } else {
194 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
195 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
199 * Allocate memory for row increments
201 if ((sax = (int *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
202 return (-1);
204 if ((say = (int *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
205 free(sax);
206 return (-1);
210 * Precalculate row increments
212 sp = csp = (tColorRGBA *) src->pixels;
213 dp = (tColorRGBA *) dst->pixels;
215 if (flipx) csp += (src->w-1);
216 if (flipy) csp = (tColorRGBA*)( (Uint8*)csp + src->pitch*(src->h-1) );
218 csx = 0;
219 csax = sax;
220 for (x = 0; x <= dst->w; x++) {
221 *csax = csx;
222 csax++;
223 csx &= 0xffff;
224 csx += sx;
226 csy = 0;
227 csay = say;
228 for (y = 0; y <= dst->h; y++) {
229 *csay = csy;
230 csay++;
231 csy &= 0xffff;
232 csy += sy;
235 dgap = dst->pitch - dst->w * 4;
238 * Switch between interpolating and non-interpolating code
240 if (smooth) {
243 * Interpolating Zoom
247 * Scan destination
249 csay = say;
250 for (y = 0; y < dst->h; y++) {
252 * Setup color source pointers
254 c00 = csp;
255 c01 = csp;
256 c01++;
257 c10 = (tColorRGBA *) ((Uint8 *) csp + src->pitch);
258 c11 = c10;
259 c11++;
260 csax = sax;
261 for (x = 0; x < dst->w; x++) {
264 * Interpolate colors
266 ex = (*csax & 0xffff);
267 ey = (*csay & 0xffff);
268 t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
269 t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
270 dp->r = (((t2 - t1) * ey) >> 16) + t1;
271 t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff;
272 t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff;
273 dp->g = (((t2 - t1) * ey) >> 16) + t1;
274 t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff;
275 t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff;
276 dp->b = (((t2 - t1) * ey) >> 16) + t1;
277 t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff;
278 t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff;
279 dp->a = (((t2 - t1) * ey) >> 16) + t1;
282 * Advance source pointers
284 csax++;
285 sstep = (*csax >> 16);
286 c00 += sstep;
287 c01 += sstep;
288 c10 += sstep;
289 c11 += sstep;
291 * Advance destination pointer
293 dp++;
296 * Advance source pointer
298 csay++;
299 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
301 * Advance destination pointers
303 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
306 } else {
309 * Non-Interpolating Zoom
312 csay = say;
313 for (y = 0; y < dst->h; y++) {
314 sp = csp;
315 csax = sax;
316 for (x = 0; x < dst->w; x++) {
318 * Draw
320 *dp = *sp;
322 * Advance source pointers
324 csax++;
325 sstep = (*csax >> 16);
326 if (flipx) sstep = -sstep;
327 sp += sstep;
329 * Advance destination pointer
331 dp++;
334 * Advance source pointer
336 csay++;
337 sstep = (*csay >> 16) * src->pitch;
338 if (flipy) sstep = -sstep;
339 csp = (tColorRGBA *) ((Uint8 *) csp + sstep);
342 * Advance destination pointers
344 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
350 * Remove temp arrays
352 free(sax);
353 free(say);
355 return (0);
360 8bit Zoomer without smoothing.
362 Zoomes 8bit palette/Y 'src' surface to 'dst' surface.
366 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy)
368 (void)flipx;
369 (void)flipy;
371 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
372 Uint8 *sp, *dp, *csp;
373 int dgap;
376 * Variable setup
378 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
379 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
382 * Allocate memory for row increments
384 if ((sax = (Uint32 *) malloc(dst->w * sizeof(Uint32))) == NULL) {
385 return (-1);
387 if ((say = (Uint32 *) malloc(dst->h * sizeof(Uint32))) == NULL) {
388 if (sax != NULL) {
389 free(sax);
391 return (-1);
395 * Precalculate row increments
397 csx = 0;
398 csax = sax;
399 for (x = 0; x < (Uint32)dst->w; x++) {
400 csx += sx;
401 *csax = (csx >> 16);
402 csx &= 0xffff;
403 csax++;
405 csy = 0;
406 csay = say;
407 for (y = 0; y < (Uint32)dst->h; y++) {
408 csy += sy;
409 *csay = (csy >> 16);
410 csy &= 0xffff;
411 csay++;
414 csx = 0;
415 csax = sax;
416 for (x = 0; x < (Uint32)dst->w; x++) {
417 csx += (*csax);
418 csax++;
420 csy = 0;
421 csay = say;
422 for (y = 0; y < (Uint32)dst->h; y++) {
423 csy += (*csay);
424 csay++;
428 * Pointer setup
430 sp = csp = (Uint8 *) src->pixels;
431 dp = (Uint8 *) dst->pixels;
432 dgap = dst->pitch - dst->w;
435 * Draw
437 csay = say;
438 for (y = 0; y < (Uint32)dst->h; y++) {
439 csax = sax;
440 sp = csp;
441 for (x = 0; x < (Uint32)dst->w; x++) {
443 * Draw
445 *dp = *sp;
447 * Advance source pointers
449 sp += (*csax);
450 csax++;
452 * Advance destination pointer
454 dp++;
457 * Advance source pointer (for row)
459 csp += ((*csay) * src->pitch);
460 csay++;
462 * Advance destination pointers
464 dp += dgap;
468 * Remove temp arrays
470 free(sax);
471 free(say);
473 return (0);
478 32bit Rotozoomer with optional anti-aliasing by bilinear interpolation.
480 Rotates and zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
484 void transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy, int smooth)
486 int x, y, t1, t2, dx, dy, xd, yd, sdx, sdy, ax, ay, ex, ey, sw, sh;
487 tColorRGBA c00, c01, c10, c11;
488 tColorRGBA *pc, *sp;
489 int gap;
492 * Variable setup
494 xd = ((src->w - dst->w) << 15);
495 yd = ((src->h - dst->h) << 15);
496 ax = (cx << 16) - (icos * cx);
497 ay = (cy << 16) - (isin * cx);
498 sw = src->w - 1;
499 sh = src->h - 1;
500 pc = (tColorRGBA*)dst->pixels;
501 gap = dst->pitch - dst->w * 4;
504 * Switch between interpolating and non-interpolating code
506 if (smooth) {
507 for (y = 0; y < dst->h; y++) {
508 dy = cy - y;
509 sdx = (ax + (isin * dy)) + xd;
510 sdy = (ay - (icos * dy)) + yd;
511 for (x = 0; x < dst->w; x++) {
512 dx = (sdx >> 16);
513 dy = (sdy >> 16);
514 if ((dx >= -1) && (dy >= -1) && (dx < src->w) && (dy < src->h)) {
515 if ((dx >= 0) && (dy >= 0) && (dx < sw) && (dy < sh)) {
516 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
517 sp += dx;
518 c00 = *sp;
519 sp += 1;
520 c01 = *sp;
521 sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
522 sp -= 1;
523 c10 = *sp;
524 sp += 1;
525 c11 = *sp;
526 } else if ((dx == sw) && (dy == sh)) {
527 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
528 sp += dx;
529 c00 = *sp;
530 c01 = *sp;
531 c10 = *sp;
532 c11 = *sp;
533 } else if ((dx == -1) && (dy == -1)) {
534 sp = (tColorRGBA *) (src->pixels);
535 c00 = *sp;
536 c01 = *sp;
537 c10 = *sp;
538 c11 = *sp;
539 } else if ((dx == -1) && (dy == sh)) {
540 sp = (tColorRGBA *) (src->pixels);
541 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
542 c00 = *sp;
543 c01 = *sp;
544 c10 = *sp;
545 c11 = *sp;
546 } else if ((dx == sw) && (dy == -1)) {
547 sp = (tColorRGBA *) (src->pixels);
548 sp += dx;
549 c00 = *sp;
550 c01 = *sp;
551 c10 = *sp;
552 c11 = *sp;
553 } else if (dx == -1) {
554 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
555 c00 = *sp;
556 c01 = *sp;
557 c10 = *sp;
558 sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
559 c11 = *sp;
560 } else if (dy == -1) {
561 sp = (tColorRGBA *) (src->pixels);
562 sp += dx;
563 c00 = *sp;
564 c01 = *sp;
565 c10 = *sp;
566 sp += 1;
567 c11 = *sp;
568 } else if (dx == sw) {
569 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
570 sp += dx;
571 c00 = *sp;
572 c01 = *sp;
573 sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
574 c10 = *sp;
575 c11 = *sp;
576 } else if (dy == sh) {
577 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
578 sp += dx;
579 c00 = *sp;
580 sp += 1;
581 c01 = *sp;
582 c10 = *sp;
583 c11 = *sp;
586 * Interpolate colors
588 ex = (sdx & 0xffff);
589 ey = (sdy & 0xffff);
590 t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff;
591 t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff;
592 pc->r = (((t2 - t1) * ey) >> 16) + t1;
593 t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff;
594 t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff;
595 pc->g = (((t2 - t1) * ey) >> 16) + t1;
596 t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff;
597 t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff;
598 pc->b = (((t2 - t1) * ey) >> 16) + t1;
599 t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff;
600 t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff;
601 pc->a = (((t2 - t1) * ey) >> 16) + t1;
603 sdx += icos;
604 sdy += isin;
605 pc++;
607 pc = (tColorRGBA *) ((Uint8 *) pc + gap);
609 } else {
610 for (y = 0; y < dst->h; y++) {
611 dy = cy - y;
612 sdx = (ax + (isin * dy)) + xd;
613 sdy = (ay - (icos * dy)) + yd;
614 for (x = 0; x < dst->w; x++) {
615 dx = (short) (sdx >> 16);
616 dy = (short) (sdy >> 16);
617 if (flipx) dx = (src->w-1)-dx;
618 if (flipy) dy = (src->h-1)-dy;
619 if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
620 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
621 sp += dx;
622 *pc = *sp;
624 sdx += icos;
625 sdy += isin;
626 pc++;
628 pc = (tColorRGBA *) ((Uint8 *) pc + gap);
635 8bit Rotozoomer without smoothing
637 Rotates and zoomes 8bit palette/Y 'src' surface to 'dst' surface.
641 void transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos)
643 int x, y, dx, dy, xd, yd, sdx, sdy, ax, ay, sw, sh;
644 tColorY *pc, *sp;
645 int gap;
648 * Variable setup
650 xd = ((src->w - dst->w) << 15);
651 yd = ((src->h - dst->h) << 15);
652 ax = (cx << 16) - (icos * cx);
653 ay = (cy << 16) - (isin * cx);
654 sw = src->w - 1;
655 sh = src->h - 1;
656 pc = (tColorY*)dst->pixels;
657 gap = dst->pitch - dst->w;
659 * Clear surface to colorkey
661 memset(pc, (unsigned char) (src->format->colorkey & 0xff), dst->pitch * dst->h);
663 * Iterate through destination surface
665 for (y = 0; y < dst->h; y++) {
666 dy = cy - y;
667 sdx = (ax + (isin * dy)) + xd;
668 sdy = (ay - (icos * dy)) + yd;
669 for (x = 0; x < dst->w; x++) {
670 dx = (short) (sdx >> 16);
671 dy = (short) (sdy >> 16);
672 if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
673 sp = (tColorY *) (src->pixels);
674 sp += (src->pitch * dy + dx);
675 *pc = *sp;
677 sdx += icos;
678 sdy += isin;
679 pc++;
681 pc += gap;
688 32bit specialized 90degree rotator
690 Rotates and zooms 'src' surface to 'dst' surface in 90degree increments.
692 (contributed by Jeff Schiller)
695 SDL_Surface* rotateSurface90Degrees(SDL_Surface* pSurf, int numClockwiseTurns)
697 int row, col, newWidth, newHeight;
698 SDL_Surface* pSurfOut;
701 if (!pSurf || pSurf->format->BitsPerPixel != 32) { return NULL; }
704 while(numClockwiseTurns < 0) { numClockwiseTurns += 4; }
705 numClockwiseTurns = (numClockwiseTurns % 4);
708 newWidth = (numClockwiseTurns % 2) ? (pSurf->h) : (pSurf->w);
709 newHeight = (numClockwiseTurns % 2) ? (pSurf->w) : (pSurf->h);
710 pSurfOut = SDL_CreateRGBSurface( pSurf->flags, newWidth, newHeight, pSurf->format->BitsPerPixel,
711 pSurf->format->Rmask,
712 pSurf->format->Gmask,
713 pSurf->format->Bmask,
714 pSurf->format->Amask);
715 if(!pSurfOut) {
716 return NULL;
719 if(numClockwiseTurns != 0) {
720 SDL_LockSurface(pSurf);
721 SDL_LockSurface(pSurfOut);
722 switch(numClockwiseTurns) {
724 case 1:
726 Uint32* srcBuf = NULL;
727 Uint32* dstBuf = NULL;
729 for (row = 0; row < pSurf->h; ++row) {
730 srcBuf = (Uint32*)(pSurf->pixels) + (row*pSurf->pitch/4);
731 dstBuf = (Uint32*)(pSurfOut->pixels) + (pSurfOut->w - row - 1);
732 for (col = 0; col < pSurf->w; ++col) {
733 *dstBuf = *srcBuf;
734 ++srcBuf;
735 dstBuf += pSurfOut->pitch/4;
739 break;
741 case 2:
743 Uint32* srcBuf = NULL;
744 Uint32* dstBuf = NULL;
746 for(row = 0; row < pSurf->h; ++row) {
747 srcBuf = (Uint32*)(pSurf->pixels) + (row*pSurf->pitch/4);
748 dstBuf = (Uint32*)(pSurfOut->pixels) + ((pSurfOut->h - row - 1)*pSurfOut->pitch/4) + (pSurfOut->w - 1);
749 for(col = 0; col < pSurf->w; ++col) {
750 *dstBuf = *srcBuf;
751 ++srcBuf;
752 --dstBuf;
756 break;
758 case 3:
760 Uint32* srcBuf = NULL;
761 Uint32* dstBuf = NULL;
763 for(row = 0; row < pSurf->h; ++row) {
764 srcBuf = (Uint32*)(pSurf->pixels) + (row*pSurf->pitch/4);
765 dstBuf = (Uint32*)(pSurfOut->pixels) + row + ((pSurfOut->h - 1)*pSurfOut->pitch/4);
766 for(col = 0; col < pSurf->w; ++col) {
767 *dstBuf = *srcBuf;
768 ++srcBuf;
769 dstBuf -= pSurfOut->pitch/4;
773 break;
776 SDL_UnlockSurface(pSurf);
777 SDL_UnlockSurface(pSurfOut);
779 else {
780 /* simply copy surface to output */
781 if(SDL_BlitSurface(pSurf, NULL, pSurfOut, NULL)) {
782 return NULL;
785 return pSurfOut;
790 rotozoomSurface()
792 Rotates and zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
793 'angle' is the rotation in degrees. 'zoom' a scaling factor. If 'smooth' is 1
794 then the destination 32bit surface is anti-aliased. If the surface is not 8bit
795 or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
799 #define VALUE_LIMIT 0.001
802 /* Local rotozoom-size function with trig result return */
804 void rotozoomSurfaceSizeTrig(int width, int height, double angle, double zoomx, double zoomy, int *dstwidth, int *dstheight,
805 double *canglezoom, double *sanglezoom)
807 (void)zoomy;
809 double x, y, cx, cy, sx, sy;
810 double radangle;
811 int dstwidthhalf, dstheighthalf;
814 * Determine destination width and height by rotating a centered source box
816 radangle = angle * (M_PI / 180.0);
817 *sanglezoom = sin(radangle);
818 *canglezoom = cos(radangle);
819 *sanglezoom *= zoomx;
820 *canglezoom *= zoomx;
821 x = width / 2;
822 y = height / 2;
823 cx = *canglezoom * x;
824 cy = *canglezoom * y;
825 sx = *sanglezoom * x;
826 sy = *sanglezoom * y;
828 dstwidthhalf = MAX((int)
829 ceil(MAX(MAX(MAX(fabs(cx + sy), fabs(cx - sy)), fabs(-cx + sy)), fabs(-cx - sy))), 1);
830 dstheighthalf = MAX((int)
831 ceil(MAX(MAX(MAX(fabs(sx + cy), fabs(sx - cy)), fabs(-sx + cy)), fabs(-sx - cy))), 1);
832 *dstwidth = 2 * dstwidthhalf;
833 *dstheight = 2 * dstheighthalf;
837 /* Publically available rotozoom-size function */
839 void rotozoomSurfaceSizeXY(int width, int height, double angle, double zoomx, double zoomy, int *dstwidth, int *dstheight)
841 double dummy_sanglezoom, dummy_canglezoom;
843 rotozoomSurfaceSizeTrig(width, height, angle, zoomx, zoomy, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
846 /* Publically available rotozoom-size function */
848 void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth, int *dstheight)
850 double dummy_sanglezoom, dummy_canglezoom;
852 rotozoomSurfaceSizeTrig(width, height, angle, zoom, zoom, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
855 /* Publically available rotozoom function */
857 SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth)
859 return rotozoomSurfaceXY(src, angle, zoom, zoom, smooth);
862 /* Publically available rotozoom function */
864 SDL_Surface *rotozoomSurfaceXY(SDL_Surface * src, double angle, double zoomx, double zoomy, int smooth)
866 SDL_Surface *rz_src;
867 SDL_Surface *rz_dst;
868 double zoominv;
869 double sanglezoom, canglezoom, sanglezoominv, canglezoominv;
870 int dstwidthhalf, dstwidth, dstheighthalf, dstheight;
871 int is32bit;
872 int i, src_converted;
873 int flipx,flipy;
874 Uint8 r,g,b;
875 Uint32 colorkey;
876 int colorKeyAvailable = 0;
879 * Sanity check
881 if (src == NULL)
882 return (NULL);
884 if( src->flags & SDL_SRCCOLORKEY )
886 colorkey = src->format->colorkey;
887 SDL_GetRGB(colorkey, src->format, &r, &g, &b);
888 colorKeyAvailable = 1;
891 * Determine if source surface is 32bit or 8bit
893 is32bit = (src->format->BitsPerPixel == 32);
894 if ((is32bit) || (src->format->BitsPerPixel == 8)) {
896 * Use source surface 'as is'
898 rz_src = src;
899 src_converted = 0;
900 } else {
902 * New source surface is 32bit with a defined RGBA ordering
904 rz_src =
905 SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
906 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
907 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
908 #else
909 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
910 #endif
912 if(colorKeyAvailable)
913 SDL_SetColorKey(src, 0, 0);
915 SDL_BlitSurface(src, NULL, rz_src, NULL);
917 if(colorKeyAvailable)
918 SDL_SetColorKey(src, SDL_SRCCOLORKEY, colorkey);
919 src_converted = 1;
920 is32bit = 1;
924 * Sanity check zoom factor
926 flipx = (zoomx<0);
927 if (flipx) zoomx=-zoomx;
928 flipy = (zoomy<0);
929 if (flipy) zoomy=-zoomy;
930 if (zoomx < VALUE_LIMIT) zoomx = VALUE_LIMIT;
931 if (zoomy < VALUE_LIMIT) zoomy = VALUE_LIMIT;
932 zoominv = 65536.0 / (zoomx * zoomx);
935 * Check if we have a rotozoom or just a zoom
937 if (fabs(angle) > VALUE_LIMIT) {
940 * Angle!=0: full rotozoom
943 * -----------------------
946 /* Determine target size */
947 rotozoomSurfaceSizeTrig(rz_src->w, rz_src->h, angle, zoomx, zoomy, &dstwidth, &dstheight, &canglezoom, &sanglezoom);
950 * Calculate target factors from sin/cos and zoom
952 sanglezoominv = sanglezoom;
953 canglezoominv = canglezoom;
954 sanglezoominv *= zoominv;
955 canglezoominv *= zoominv;
957 /* Calculate half size */
958 dstwidthhalf = dstwidth / 2;
959 dstheighthalf = dstheight / 2;
962 * Alloc space to completely contain the rotated surface
964 rz_dst = NULL;
965 if (is32bit) {
967 * Target surface is 32bit with source RGBA/ABGR ordering
969 rz_dst =
970 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
971 rz_src->format->Rmask, rz_src->format->Gmask,
972 rz_src->format->Bmask, rz_src->format->Amask);
973 } else {
975 * Target surface is 8bit
977 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
980 if (colorKeyAvailable == 1){
981 colorkey = SDL_MapRGB(rz_dst->format, r, g, b);
983 SDL_FillRect(rz_dst, NULL, colorkey );
987 * Lock source surface
989 SDL_LockSurface(rz_src);
991 * Check which kind of surface we have
993 if (is32bit) {
995 * Call the 32bit transformation routine to do the rotation (using alpha)
997 transformSurfaceRGBA(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
998 (int) (sanglezoominv), (int) (canglezoominv),
999 flipx, flipy,
1000 smooth);
1002 * Turn on source-alpha support
1004 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1005 } else {
1007 * Copy palette and colorkey info
1009 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1010 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1012 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1014 * Call the 8bit transformation routine to do the rotation
1016 transformSurfaceY(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
1017 (int) (sanglezoominv), (int) (canglezoominv));
1018 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
1021 * Unlock source surface
1023 SDL_UnlockSurface(rz_src);
1025 } else {
1028 * Angle=0: Just a zoom
1031 * --------------------
1035 * Calculate target size
1037 zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
1040 * Alloc space to completely contain the zoomed surface
1042 rz_dst = NULL;
1043 if (is32bit) {
1045 * Target surface is 32bit with source RGBA/ABGR ordering
1047 rz_dst =
1048 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
1049 rz_src->format->Rmask, rz_src->format->Gmask,
1050 rz_src->format->Bmask, rz_src->format->Amask);
1051 } else {
1053 * Target surface is 8bit
1055 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
1058 if (colorKeyAvailable == 1){
1059 colorkey = SDL_MapRGB(rz_dst->format, r, g, b);
1061 SDL_FillRect(rz_dst, NULL, colorkey );
1065 * Lock source surface
1067 SDL_LockSurface(rz_src);
1069 * Check which kind of surface we have
1071 if (is32bit) {
1073 * Call the 32bit transformation routine to do the zooming (using alpha)
1075 zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
1077 * Turn on source-alpha support
1079 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1080 } else {
1082 * Copy palette and colorkey info
1084 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1085 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1087 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1089 * Call the 8bit transformation routine to do the zooming
1091 zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
1092 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
1095 * Unlock source surface
1097 SDL_UnlockSurface(rz_src);
1101 * Cleanup temp surface
1103 if (src_converted) {
1104 SDL_FreeSurface(rz_src);
1108 * Return destination surface
1110 return (rz_dst);
1115 zoomSurface()
1117 Zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1118 'zoomx' and 'zoomy' are scaling factors for width and height. If 'smooth' is 1
1119 then the destination 32bit surface is anti-aliased. If the surface is not 8bit
1120 or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
1124 #define VALUE_LIMIT 0.001
1126 void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight)
1129 * Sanity check zoom factors
1131 if (zoomx < VALUE_LIMIT) {
1132 zoomx = VALUE_LIMIT;
1134 if (zoomy < VALUE_LIMIT) {
1135 zoomy = VALUE_LIMIT;
1139 * Calculate target size
1141 *dstwidth = (int) ((double) width * zoomx);
1142 *dstheight = (int) ((double) height * zoomy);
1143 if (*dstwidth < 1) {
1144 *dstwidth = 1;
1146 if (*dstheight < 1) {
1147 *dstheight = 1;
1151 SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth)
1153 SDL_Surface *rz_src;
1154 SDL_Surface *rz_dst;
1155 int dstwidth, dstheight;
1156 int is32bit;
1157 int i, src_converted;
1158 int flipx, flipy;
1161 * Sanity check
1163 if (src == NULL)
1164 return (NULL);
1167 * Determine if source surface is 32bit or 8bit
1169 is32bit = (src->format->BitsPerPixel == 32);
1170 if ((is32bit) || (src->format->BitsPerPixel == 8)) {
1172 * Use source surface 'as is'
1174 rz_src = src;
1175 src_converted = 0;
1176 } else {
1178 * New source surface is 32bit with a defined RGBA ordering
1180 rz_src =
1181 SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1182 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
1183 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
1184 #else
1185 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
1186 #endif
1188 SDL_BlitSurface(src, NULL, rz_src, NULL);
1189 src_converted = 1;
1190 is32bit = 1;
1193 flipx = (zoomx<0);
1194 if (flipx) zoomx = -zoomx;
1195 flipy = (zoomy<0);
1196 if (flipy) zoomy = -zoomy;
1198 /* Get size if target */
1199 zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
1202 * Alloc space to completely contain the zoomed surface
1204 rz_dst = NULL;
1205 if (is32bit) {
1207 * Target surface is 32bit with source RGBA/ABGR ordering
1209 rz_dst =
1210 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
1211 rz_src->format->Rmask, rz_src->format->Gmask,
1212 rz_src->format->Bmask, rz_src->format->Amask);
1213 } else {
1215 * Target surface is 8bit
1217 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
1221 * Lock source surface
1223 SDL_LockSurface(rz_src);
1225 * Check which kind of surface we have
1227 if (is32bit) {
1229 * Call the 32bit transformation routine to do the zooming (using alpha)
1231 zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
1233 * Turn on source-alpha support
1235 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1236 } else {
1238 * Copy palette and colorkey info
1240 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1241 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1243 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1245 * Call the 8bit transformation routine to do the zooming
1247 zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
1248 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
1251 * Unlock source surface
1253 SDL_UnlockSurface(rz_src);
1256 * Cleanup temp surface
1258 if (src_converted) {
1259 SDL_FreeSurface(rz_src);
1263 * Return destination surface
1265 return (rz_dst);
1268 SDL_Surface *shrinkSurface(SDL_Surface * src, int factorx, int factory)
1270 SDL_Surface *rz_src;
1271 SDL_Surface *rz_dst;
1272 int dstwidth, dstheight;
1273 int is32bit;
1274 int i, src_converted;
1277 * Sanity check
1279 if (src == NULL)
1280 return (NULL);
1283 * Determine if source surface is 32bit or 8bit
1285 is32bit = (src->format->BitsPerPixel == 32);
1286 if ((is32bit) || (src->format->BitsPerPixel == 8)) {
1288 * Use source surface 'as is'
1290 rz_src = src;
1291 src_converted = 0;
1292 } else {
1294 * New source surface is 32bit with a defined RGBA ordering
1296 rz_src =
1297 SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1298 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
1299 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
1300 #else
1301 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
1302 #endif
1304 SDL_BlitSurface(src, NULL, rz_src, NULL);
1305 src_converted = 1;
1306 is32bit = 1;
1309 /* Get size for target */
1310 dstwidth=rz_src->w/factorx;
1311 while (dstwidth*factorx>rz_src->w) { dstwidth--; }
1312 dstheight=rz_src->h/factory;
1313 while (dstheight*factory>rz_src->h) { dstheight--; }
1316 * Alloc space to completely contain the shrunken surface
1318 rz_dst = NULL;
1319 if (is32bit) {
1321 * Target surface is 32bit with source RGBA/ABGR ordering
1323 rz_dst =
1324 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
1325 rz_src->format->Rmask, rz_src->format->Gmask,
1326 rz_src->format->Bmask, rz_src->format->Amask);
1327 } else {
1329 * Target surface is 8bit
1331 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
1335 * Lock source surface
1337 SDL_LockSurface(rz_src);
1339 * Check which kind of surface we have
1341 if (is32bit) {
1343 * Call the 32bit transformation routine to do the shrinking (using alpha)
1345 shrinkSurfaceRGBA(rz_src, rz_dst, factorx, factory);
1347 * Turn on source-alpha support
1349 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1350 } else {
1352 * Copy palette and colorkey info
1354 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1355 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1357 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1359 * Call the 8bit transformation routine to do the shrinking
1361 shrinkSurfaceY(rz_src, rz_dst, factorx, factory);
1362 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
1365 * Unlock source surface
1367 SDL_UnlockSurface(rz_src);
1370 * Cleanup temp surface
1372 if (src_converted) {
1373 SDL_FreeSurface(rz_src);
1377 * Return destination surface
1379 return (rz_dst);