2 * Derived from: SDL_rotozoom, LGPL (c) A. Schiffler from the SDL_gfx library.
3 * Modifications by Hyunjun Son(hj79.son@samsung.com)
5 * This work is licensed under the terms of the GNU GPL version 2.
6 * See the COPYING file in the top-level directory.
17 #include "sdl_rotate.h"
21 /* ---- Internally used structures */
24 \brief A 32 bit RGBA pixel.
26 typedef struct tColorRGBA {
34 \brief A 8bit Y/palette pixel.
36 typedef struct tColorY {
41 \brief Returns maximum of two numbers a and b.
43 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
46 \brief Number of guard rows added to destination surfaces.
48 This is a simple but effective workaround for observed issues.
49 These rows allocate extra memory and are then hidden from the surface.
50 Rows are added to the end of destination surfaces when they are allocated.
51 This catches any potential overflows which seem to happen with
52 just the right src image dimensions and scale/rotation and can lead
53 to a situation where the program can segfault.
55 #define GUARD_ROWS (0)
58 \brief Lower limit of absolute zoom factor or rotation degrees.
60 #define VALUE_LIMIT 0.001
62 Uint32 _colorkey(SDL_Surface *src);
63 int _shrinkSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory);
64 int _shrinkSurfaceY(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory);
65 int _zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy, int smooth);
66 int _zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy);
67 void _transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy, int smooth);
68 void transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy);
69 void _rotozoomSurfaceSizeTrig(int width, int height, double angle, double zoomx, double zoomy,
70 int *dstwidth, int *dstheight,
71 double *canglezoom, double *sanglezoom);
74 \brief Returns colorkey info for a surface
76 Uint32 _colorkey(SDL_Surface *src)
79 #if (SDL_MINOR_VERSION == 3)
80 SDL_GetColorKey(src, &key);
84 key = src->format->colorkey;
92 \brief Internal 32 bit integer-factor averaging Shrinker.
94 Shrinks 32 bit RGBA/ABGR 'src' surface to 'dst' surface.
95 Averages color and alpha values values of src pixels to calculate dst pixels.
96 Assumes src and dst surfaces are of 32 bit depth.
97 Assumes dst surface was allocated with the correct dimensions.
99 \param src The surface to shrink (input).
100 \param dst The shrunken surface (output).
101 \param factorx The horizontal shrinking ratio.
102 \param factory The vertical shrinking ratio.
104 \return 0 for success or -1 for error.
106 int _shrinkSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
108 int x, y, dx, dy, sgap, dgap, ra, ga, ba, aa;
110 tColorRGBA *sp, *osp, *oosp;
114 * Averaging integer shrink
117 /* Precalculate division factor */
118 n_average = factorx*factory;
123 sp = (tColorRGBA *) src->pixels;
124 sgap = src->pitch - src->w * 4;
126 dp = (tColorRGBA *) dst->pixels;
127 dgap = dst->pitch - dst->w * 4;
129 for (y = 0; y < dst->h; y++) {
132 for (x = 0; x < dst->w; x++) {
134 /* Trace out source box and accumulate */
137 for (dy=0; dy < factory; dy++) {
138 for (dx=0; dx < factorx; dx++) {
147 sp = (tColorRGBA *)((Uint8*)sp + (src->pitch - 4*factorx)); // next y
152 sp = (tColorRGBA *)((Uint8*)oosp + 4*factorx);
154 /* Store result in destination */
155 dp->r = ra/n_average;
156 dp->g = ga/n_average;
157 dp->b = ba/n_average;
158 dp->a = aa/n_average;
161 * Advance destination pointer
168 sp = (tColorRGBA *)((Uint8*)osp + src->pitch*factory);
171 * Advance destination pointers
173 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
181 \brief Internal 8 bit integer-factor averaging shrinker.
183 Shrinks 8bit Y 'src' surface to 'dst' surface.
184 Averages color (brightness) values values of src pixels to calculate dst pixels.
185 Assumes src and dst surfaces are of 8 bit depth.
186 Assumes dst surface was allocated with the correct dimensions.
188 \param src The surface to shrink (input).
189 \param dst The shrunken surface (output).
190 \param factorx The horizontal shrinking ratio.
191 \param factory The vertical shrinking ratio.
193 \return 0 for success or -1 for error.
195 int _shrinkSurfaceY(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
197 int x, y, dx, dy, sgap, dgap, a;
199 Uint8 *sp, *osp, *oosp;
203 * Averaging integer shrink
206 /* Precalculate division factor */
207 n_average = factorx*factory;
212 sp = (Uint8 *) src->pixels;
213 sgap = src->pitch - src->w;
215 dp = (Uint8 *) dst->pixels;
216 dgap = dst->pitch - dst->w;
218 for (y = 0; y < dst->h; y++) {
221 for (x = 0; x < dst->w; x++) {
223 /* Trace out source box and accumulate */
226 for (dy=0; dy < factory; dy++) {
227 for (dx=0; dx < factorx; dx++) {
232 /* end src dx loop */
234 sp = (Uint8 *)((Uint8*)sp + (src->pitch - factorx));
236 /* end src dy loop */
239 sp = (Uint8 *)((Uint8*)oosp + factorx);
241 /* Store result in destination */
245 * Advance destination pointer
252 sp = (Uint8 *)((Uint8*)osp + src->pitch*factory);
255 * Advance destination pointers
257 dp = (Uint8 *)((Uint8 *)dp + dgap);
265 \brief Internal 32 bit Zoomer with optional anti-aliasing by bilinear interpolation.
267 Zooms 32 bit RGBA/ABGR 'src' surface to 'dst' surface.
268 Assumes src and dst surfaces are of 32 bit depth.
269 Assumes dst surface was allocated with the correct dimensions.
271 \param src The surface to zoom (input).
272 \param dst The zoomed surface (output).
273 \param flipx Flag indicating if the image should be horizontally flipped.
274 \param flipy Flag indicating if the image should be vertically flipped.
275 \param smooth Antialiasing flag; set to SMOOTHING_ON to enable.
277 \return 0 for success or -1 for error.
279 int _zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy, int smooth)
281 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy, ex, ey, t1, t2, sstep, lx, ly;
282 tColorRGBA *c00, *c01, *c10, *c11, *cswap;
283 tColorRGBA *sp, *csp, *dp;
291 * For interpolation: assume source dimension is one pixel
294 * smaller to avoid overflow on right and bottom edge.
296 sx = (int) (65536.0 * (float) (src->w - 1) / (float) dst->w);
297 sy = (int) (65536.0 * (float) (src->h - 1) / (float) dst->h);
299 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
300 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
304 * Allocate memory for row increments
306 if ((sax = (int *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
309 if ((say = (int *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
315 * Precalculate row increments
317 sp = csp = (tColorRGBA *) src->pixels;
318 dp = (tColorRGBA *) dst->pixels;
320 if (flipx) csp += (src->w-1);
321 if (flipy) csp += (src->pitch*(src->h-1));
325 for (x = 0; x <= dst->w; x++) {
333 for (y = 0; y <= dst->h; y++) {
340 dgap = dst->pitch - dst->w * 4;
343 * Switch between interpolating and non-interpolating code
356 for (y = 0; y < dst->h; y++) {
358 * Setup color source pointers
363 c10 = (tColorRGBA *) ((Uint8 *) csp + src->pitch);
368 cswap = c00; c00=c01; c01=cswap;
369 cswap = c10; c10=c11; c11=cswap;
372 cswap = c00; c00=c10; c10=cswap;
373 cswap = c01; c01=c11; c11=cswap;
376 for (x = 0; x < dst->w; x++) {
380 ex = (*csax & 0xffff);
381 ey = (*csay & 0xffff);
382 t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
383 t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
384 dp->r = (((t2 - t1) * ey) >> 16) + t1;
385 t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff;
386 t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff;
387 dp->g = (((t2 - t1) * ey) >> 16) + t1;
388 t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff;
389 t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff;
390 dp->b = (((t2 - t1) * ey) >> 16) + t1;
391 t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff;
392 t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff;
393 dp->a = (((t2 - t1) * ey) >> 16) + t1;
396 * Advance source pointers
399 sstep = (*csax >> 16);
401 if (lx >= src->w) sstep = 0;
402 if (flipx) sstep = -sstep;
408 * Advance destination pointer
413 * Advance source pointer
416 sstep = (*csay >> 16);
418 if (ly >= src->h) sstep = 0;
420 if (flipy) sstep = -sstep;
421 csp = (tColorRGBA *) ((Uint8 *) csp + sstep);
424 * Advance destination pointers
426 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
431 * Non-Interpolating Zoom
435 for (y = 0; y < dst->h; y++) {
438 for (x = 0; x < dst->w; x++) {
444 * Advance source pointers
447 sstep = (*csax >> 16);
448 if (flipx) sstep = -sstep;
451 * Advance destination pointer
456 * Advance source pointer
459 sstep = (*csay >> 16) * src->pitch;
460 if (flipy) sstep = -sstep;
461 csp = (tColorRGBA *) ((Uint8 *) csp + sstep);
464 * Advance destination pointers
466 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
481 \brief Internal 8 bit Zoomer without smoothing.
483 Zooms 8bit palette/Y 'src' surface to 'dst' surface.
484 Assumes src and dst surfaces are of 8 bit depth.
485 Assumes dst surface was allocated with the correct dimensions.
487 \param src The surface to zoom (input).
488 \param dst The zoomed surface (output).
489 \param flipx Flag indicating if the image should be horizontally flipped.
490 \param flipy Flag indicating if the image should be vertically flipped.
492 \return 0 for success or -1 for error.
494 int _zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy)
497 Uint32 *sax, *say, *csax, *csay;
499 Uint8 *sp, *dp, *csp;
503 * Allocate memory for row increments
505 if ((sax = (Uint32 *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
508 if ((say = (Uint32 *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
516 sp = csp = (Uint8 *) src->pixels;
517 dp = (Uint8 *) dst->pixels;
518 dgap = dst->pitch - dst->w;
520 if (flipx) csp += (src->w-1);
521 if (flipy) csp = ( (Uint8*)csp + src->pitch*(src->h-1) );
524 * Precalculate row increments
528 for (x = 0; x < dst->w; x++) {
531 while (csx >= dst->w) {
539 for (y = 0; y < dst->h; y++) {
542 while (csy >= dst->h) {
553 for (y = 0; y < dst->h; y++) {
556 for (x = 0; x < dst->w; x++) {
562 * Advance source pointers
564 sp += (*csax) * (flipx ? -1 : 1);
567 * Advance destination pointer
572 * Advance source pointer (for row)
574 csp += ((*csay) * src->pitch) * (flipy ? -1 : 1);
578 * Advance destination pointers
593 \brief Internal 32 bit rotozoomer with optional anti-aliasing.
595 Rotates and zooms 32 bit RGBA/ABGR 'src' surface to 'dst' surface based on the control
596 parameters by scanning the destination surface and applying optionally anti-aliasing
597 by bilinear interpolation.
598 Assumes src and dst surfaces are of 32 bit depth.
599 Assumes dst surface was allocated with the correct dimensions.
601 \param src Source surface.
602 \param dst Destination surface.
603 \param cx Horizontal center coordinate.
604 \param cy Vertical center coordinate.
605 \param isin Integer version of sine of angle.
606 \param icos Integer version of cosine of angle.
607 \param flipx Flag indicating horizontal mirroring should be applied.
608 \param flipy Flag indicating vertical mirroring should be applied.
609 \param smooth Flag indicating anti-aliasing should be used.
611 void _transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy, int smooth)
613 int x, y, t1, t2, dx, dy, xd, yd, sdx, sdy, ax, ay, ex, ey, sw, sh;
614 tColorRGBA c00, c01, c10, c11, cswap;
621 xd = ((src->w - dst->w) << 15);
622 yd = ((src->h - dst->h) << 15);
623 ax = (cx << 16) - (icos * cx);
624 ay = (cy << 16) - (isin * cx);
627 pc = (tColorRGBA*) dst->pixels;
628 gap = dst->pitch - dst->w * 4;
631 * Switch between interpolating and non-interpolating code
634 for (y = 0; y < dst->h; y++) {
636 sdx = (ax + (isin * dy)) + xd;
637 sdy = (ay - (icos * dy)) + yd;
638 for (x = 0; x < dst->w; x++) {
641 if ((dx > -1) && (dy > -1) && (dx < src->w) && (dy < src->h)) {
642 if (flipx) dx = sw - dx;
643 if (flipy) dy = sh - dy;
644 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
649 sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
654 cswap = c00; c00=c01; c01=cswap;
655 cswap = c10; c10=c11; c11=cswap;
658 cswap = c00; c00=c10; c10=cswap;
659 cswap = c01; c01=c11; c11=cswap;
666 t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff;
667 t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff;
668 pc->r = (((t2 - t1) * ey) >> 16) + t1;
669 t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff;
670 t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff;
671 pc->g = (((t2 - t1) * ey) >> 16) + t1;
672 t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff;
673 t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff;
674 pc->b = (((t2 - t1) * ey) >> 16) + t1;
675 t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff;
676 t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff;
677 pc->a = (((t2 - t1) * ey) >> 16) + t1;
683 pc = (tColorRGBA *) ((Uint8 *) pc + gap);
686 for (y = 0; y < dst->h; y++) {
688 sdx = (ax + (isin * dy)) + xd;
689 sdy = (ay - (icos * dy)) + yd;
690 for (x = 0; x < dst->w; x++) {
691 dx = (short) (sdx >> 16);
692 dy = (short) (sdy >> 16);
693 if (flipx) dx = (src->w-1)-dx;
694 if (flipy) dy = (src->h-1)-dy;
695 if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
696 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
704 pc = (tColorRGBA *) ((Uint8 *) pc + gap);
711 \brief Rotates and zooms 8 bit palette/Y 'src' surface to 'dst' surface without smoothing.
713 Rotates and zooms 8 bit RGBA/ABGR 'src' surface to 'dst' surface based on the control
714 parameters by scanning the destination surface.
715 Assumes src and dst surfaces are of 8 bit depth.
716 Assumes dst surface was allocated with the correct dimensions.
718 \param src Source surface.
719 \param dst Destination surface.
720 \param cx Horizontal center coordinate.
721 \param cy Vertical center coordinate.
722 \param isin Integer version of sine of angle.
723 \param icos Integer version of cosine of angle.
724 \param flipx Flag indicating horizontal mirroring should be applied.
725 \param flipy Flag indicating vertical mirroring should be applied.
727 void transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy)
729 int x, y, dx, dy, xd, yd, sdx, sdy, ax, ay, sw, sh;
736 xd = ((src->w - dst->w) << 15);
737 yd = ((src->h - dst->h) << 15);
738 ax = (cx << 16) - (icos * cx);
739 ay = (cy << 16) - (isin * cx);
742 pc = (tColorY*) dst->pixels;
743 gap = dst->pitch - dst->w;
745 * Clear surface to colorkey
747 memset(pc, (unsigned char) (_colorkey(src) & 0xff), dst->pitch * dst->h);
749 * Iterate through destination surface
751 for (y = 0; y < dst->h; y++) {
753 sdx = (ax + (isin * dy)) + xd;
754 sdy = (ay - (icos * dy)) + yd;
755 for (x = 0; x < dst->w; x++) {
756 dx = (short) (sdx >> 16);
757 dy = (short) (sdy >> 16);
758 if (flipx) dx = (src->w-1)-dx;
759 if (flipy) dy = (src->h-1)-dy;
760 if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
761 sp = (tColorY *) (src->pixels);
762 sp += (src->pitch * dy + dx);
775 \brief Rotates a 32 bit surface in increments of 90 degrees.
777 Specialized 90 degree rotator which rotates a 'src' surface in 90 degree
778 increments clockwise returning a new surface. Faster than rotozoomer since
779 not scanning or interpolation takes place. Input surface must be 32 bit.
780 (code contributed by J. Schiller, improved by C. Allport and A. Schiffler)
782 \param src Source surface to rotate.
783 \param numClockwiseTurns Number of clockwise 90 degree turns to apply to the source.
785 \returns The new, rotated surface; or NULL for surfaces with incorrect input format.
787 SDL_Surface* rotateSurface90Degrees(SDL_Surface* src, int numClockwiseTurns)
789 int row, col, newWidth, newHeight;
790 int bpp, src_ipr, dst_ipr;
795 /* Has to be a valid surface pointer and only 32-bit surfaces (for now) */
796 if (!src || src->format->BitsPerPixel != 32) { return NULL; }
798 /* normalize numClockwiseTurns */
799 while(numClockwiseTurns < 0) { numClockwiseTurns += 4; }
800 numClockwiseTurns = (numClockwiseTurns % 4);
802 /* if it's even, our new width will be the same as the source surface */
803 newWidth = (numClockwiseTurns % 2) ? (src->h) : (src->w);
804 newHeight = (numClockwiseTurns % 2) ? (src->w) : (src->h);
805 dst = SDL_CreateRGBSurface( src->flags, newWidth, newHeight, src->format->BitsPerPixel,
814 if (SDL_MUSTLOCK(dst)) {
815 SDL_LockSurface(dst);
817 if (SDL_MUSTLOCK(dst)) {
818 SDL_LockSurface(dst);
821 /* Calculate int-per-row */
822 bpp = src->format->BitsPerPixel / 8;
823 src_ipr = src->pitch / bpp;
824 dst_ipr = dst->pitch / bpp;
826 switch(numClockwiseTurns) {
827 case 0: /* Make a copy of the surface */
829 /* Unfortunately SDL_BlitSurface cannot be used to make a copy of the surface
830 since it does not preserve alpha. */
832 if (src->pitch == dst->pitch) {
833 /* If the pitch is the same for both surfaces, the memory can be copied all at once. */
834 memcpy(dst->pixels, src->pixels, (src->h * src->pitch));
838 /* If the pitch differs, copy each row separately */
839 srcBuf = (Uint32*)(src->pixels);
840 dstBuf = (Uint32*)(dst->pixels);
841 for (row = 0; row < src->h; row++) {
842 memcpy(dstBuf, srcBuf, dst->w * bpp);
850 /* rotate clockwise */
851 case 1: /* rotated 90 degrees clockwise */
853 for (row = 0; row < src->h; ++row) {
854 srcBuf = (Uint32*)(src->pixels) + (row * src_ipr);
855 dstBuf = (Uint32*)(dst->pixels) + (dst->w - row - 1);
856 for (col = 0; col < src->w; ++col) {
867 case 2: /* rotated 180 degrees clockwise */
869 for (row = 0; row < src->h; ++row) {
870 srcBuf = (Uint32*)(src->pixels) + (row * src_ipr);
871 dstBuf = (Uint32*)(dst->pixels) + ((dst->h - row - 1) * dst_ipr) + (dst->w - 1);
872 for (col = 0; col < src->w; ++col) {
883 for (row = 0; row < src->h; ++row) {
884 srcBuf = (Uint32*)(src->pixels) + (row * src_ipr);
885 dstBuf = (Uint32*)(dst->pixels) + row + ((dst->h - 1) * dst_ipr);
886 for (col = 0; col < src->w; ++col) {
897 if (SDL_MUSTLOCK(src)) {
898 SDL_UnlockSurface(src);
900 if (SDL_MUSTLOCK(dst)) {
901 SDL_UnlockSurface(dst);
910 \brief Internal target surface sizing function for rotozooms with trig result return.
912 \param width The source surface width.
913 \param height The source surface height.
914 \param angle The angle to rotate in degrees.
915 \param zoomx The horizontal scaling factor.
916 \param zoomy The vertical scaling factor.
917 \param dstwidth The calculated width of the destination surface.
918 \param dstheight The calculated height of the destination surface.
919 \param canglezoom The sine of the angle adjusted by the zoom factor.
920 \param sanglezoom The cosine of the angle adjusted by the zoom factor.
923 void _rotozoomSurfaceSizeTrig(int width, int height, double angle, double zoomx, double zoomy,
924 int *dstwidth, int *dstheight,
925 double *canglezoom, double *sanglezoom)
927 double x, y, cx, cy, sx, sy;
929 int dstwidthhalf, dstheighthalf;
932 * Determine destination width and height by rotating a centered source box
934 radangle = angle * (M_PI / 180.0);
935 *sanglezoom = sin(radangle);
936 *canglezoom = cos(radangle);
937 *sanglezoom *= zoomx;
938 *canglezoom *= zoomx;
941 cx = *canglezoom * x;
942 cy = *canglezoom * y;
943 sx = *sanglezoom * x;
944 sy = *sanglezoom * y;
946 dstwidthhalf = MAX((int)
947 ceil(MAX(MAX(MAX(fabs(cx + sy), fabs(cx - sy)), fabs(-cx + sy)), fabs(-cx - sy))), 1);
948 dstheighthalf = MAX((int)
949 ceil(MAX(MAX(MAX(fabs(sx + cy), fabs(sx - cy)), fabs(-sx + cy)), fabs(-sx - cy))), 1);
950 *dstwidth = 2 * dstwidthhalf;
951 *dstheight = 2 * dstheighthalf;
955 \brief Returns the size of the resulting target surface for a rotozoomSurfaceXY() call.
957 \param width The source surface width.
958 \param height The source surface height.
959 \param angle The angle to rotate in degrees.
960 \param zoomx The horizontal scaling factor.
961 \param zoomy The vertical scaling factor.
962 \param dstwidth The calculated width of the rotozoomed destination surface.
963 \param dstheight The calculated height of the rotozoomed destination surface.
965 void rotozoomSurfaceSizeXY(int width, int height, double angle, double zoomx, double zoomy, int *dstwidth, int *dstheight)
967 double dummy_sanglezoom, dummy_canglezoom;
969 _rotozoomSurfaceSizeTrig(width, height, angle, zoomx, zoomy, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
973 \brief Returns the size of the resulting target surface for a rotozoomSurface() call.
975 \param width The source surface width.
976 \param height The source surface height.
977 \param angle The angle to rotate in degrees.
978 \param zoom The scaling factor.
979 \param dstwidth The calculated width of the rotozoomed destination surface.
980 \param dstheight The calculated height of the rotozoomed destination surface.
982 void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth, int *dstheight)
984 double dummy_sanglezoom, dummy_canglezoom;
986 _rotozoomSurfaceSizeTrig(width, height, angle, zoom, zoom, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
990 \brief Rotates and zooms a surface and optional anti-aliasing.
992 Rotates and zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
993 'angle' is the rotation in degrees and 'zoom' a scaling factor. If 'smooth' is set
994 then the destination 32bit surface is anti-aliased. If the surface is not 8bit
995 or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
997 \param src The surface to rotozoom.
998 \param angle The angle to rotate in degrees.
999 \param zoom The scaling factor.
1000 \param smooth Antialiasing flag; set to SMOOTHING_ON to enable.
1002 \return The new rotozoomed surface.
1004 SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth)
1006 return rotozoomSurfaceXY(src, angle, zoom, zoom, smooth);
1010 \brief Rotates and zooms a surface with different horizontal and vertival scaling factors and optional anti-aliasing.
1012 Rotates and zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1013 'angle' is the rotation in degrees, 'zoomx and 'zoomy' scaling factors. If 'smooth' is set
1014 then the destination 32bit surface is anti-aliased. If the surface is not 8bit
1015 or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
1017 \param src The surface to rotozoom.
1018 \param angle The angle to rotate in degrees.
1019 \param zoomx The horizontal scaling factor.
1020 \param zoomy The vertical scaling factor.
1021 \param smooth Antialiasing flag; set to SMOOTHING_ON to enable.
1023 \return The new rotozoomed surface.
1025 SDL_Surface *rotozoomSurfaceXY(SDL_Surface * src, double angle, double zoomx, double zoomy, int smooth)
1027 SDL_Surface *rz_src;
1028 SDL_Surface *rz_dst;
1030 double sanglezoom, canglezoom, sanglezoominv, canglezoominv;
1031 int dstwidthhalf, dstwidth, dstheighthalf, dstheight;
1033 int i, src_converted;
1036 Uint32 colorkey = 0;
1037 int colorKeyAvailable = 0;
1045 if (src->flags & SDL_SRCCOLORKEY)
1047 colorkey = _colorkey(src);
1048 SDL_GetRGB(colorkey, src->format, &r, &g, &b);
1049 colorKeyAvailable = 1;
1052 * Determine if source surface is 32bit or 8bit
1054 is32bit = (src->format->BitsPerPixel == 32);
1055 if ((is32bit) || (src->format->BitsPerPixel == 8)) {
1057 * Use source surface 'as is'
1063 * New source surface is 32bit with a defined RGBA ordering
1066 SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1067 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
1068 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
1070 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
1073 if(colorKeyAvailable)
1074 SDL_SetColorKey(src, 0, 0);
1076 SDL_BlitSurface(src, NULL, rz_src, NULL);
1078 if(colorKeyAvailable)
1079 SDL_SetColorKey(src, SDL_SRCCOLORKEY, colorkey);
1085 * Sanity check zoom factor
1087 flipx = (zoomx<0.0);
1088 if (flipx) zoomx=-zoomx;
1089 flipy = (zoomy<0.0);
1090 if (flipy) zoomy=-zoomy;
1091 if (zoomx < VALUE_LIMIT) zoomx = VALUE_LIMIT;
1092 if (zoomy < VALUE_LIMIT) zoomy = VALUE_LIMIT;
1093 zoominv = 65536.0 / (zoomx * zoomx);
1096 * Check if we have a rotozoom or just a zoom
1098 if (fabs(angle) > VALUE_LIMIT) {
1101 * Angle!=0: full rotozoom
1104 * -----------------------
1107 /* Determine target size */
1108 _rotozoomSurfaceSizeTrig(rz_src->w, rz_src->h, angle, zoomx, zoomy, &dstwidth, &dstheight, &canglezoom, &sanglezoom);
1111 * Calculate target factors from sin/cos and zoom
1113 sanglezoominv = sanglezoom;
1114 canglezoominv = canglezoom;
1115 sanglezoominv *= zoominv;
1116 canglezoominv *= zoominv;
1118 /* Calculate half size */
1119 dstwidthhalf = dstwidth / 2;
1120 dstheighthalf = dstheight / 2;
1123 * Alloc space to completely contain the rotated surface
1128 * Target surface is 32bit with source RGBA/ABGR ordering
1131 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
1132 rz_src->format->Rmask, rz_src->format->Gmask,
1133 rz_src->format->Bmask, rz_src->format->Amask);
1136 * Target surface is 8bit
1138 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
1141 if (colorKeyAvailable == 1){
1142 colorkey = SDL_MapRGB(rz_dst->format, r, g, b);
1144 SDL_FillRect(rz_dst, NULL, colorkey );
1148 * Lock source surface
1150 if (SDL_MUSTLOCK(rz_src)) {
1151 SDL_LockSurface(rz_src);
1155 * Check which kind of surface we have
1159 * Call the 32bit transformation routine to do the rotation (using alpha)
1161 _transformSurfaceRGBA(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
1162 (int) (sanglezoominv), (int) (canglezoominv),
1166 * Turn on source-alpha support
1168 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1169 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
1172 * Copy palette and colorkey info
1174 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1175 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1177 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1179 * Call the 8bit transformation routine to do the rotation
1181 transformSurfaceY(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
1182 (int) (sanglezoominv), (int) (canglezoominv),
1184 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
1187 * Unlock source surface
1189 if (SDL_MUSTLOCK(rz_src)) {
1190 SDL_UnlockSurface(rz_src);
1196 * Angle=0: Just a zoom
1199 * --------------------
1203 * Calculate target size
1205 zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
1208 * Alloc space to completely contain the zoomed surface
1213 * Target surface is 32bit with source RGBA/ABGR ordering
1216 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
1217 rz_src->format->Rmask, rz_src->format->Gmask,
1218 rz_src->format->Bmask, rz_src->format->Amask);
1221 * Target surface is 8bit
1223 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
1226 if (colorKeyAvailable == 1){
1227 colorkey = SDL_MapRGB(rz_dst->format, r, g, b);
1229 SDL_FillRect(rz_dst, NULL, colorkey );
1233 * Lock source surface
1235 if (SDL_MUSTLOCK(rz_src)) {
1236 SDL_LockSurface(rz_src);
1240 * Check which kind of surface we have
1244 * Call the 32bit transformation routine to do the zooming (using alpha)
1246 _zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
1248 * Turn on source-alpha support
1250 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1251 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
1254 * Copy palette and colorkey info
1256 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1257 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1259 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1261 * Call the 8bit transformation routine to do the zooming
1263 _zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
1264 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
1267 * Unlock source surface
1269 if (SDL_MUSTLOCK(rz_src)) {
1270 SDL_UnlockSurface(rz_src);
1275 * Cleanup temp surface
1277 if (src_converted) {
1278 SDL_FreeSurface(rz_src);
1282 * Return destination surface
1284 rz_dst->h -= GUARD_ROWS;
1289 \brief Calculates the size of the target surface for a zoomSurface() call.
1291 The minimum size of the target surface is 1. The input factors can be positive or negative.
1293 \param width The width of the source surface to zoom.
1294 \param height The height of the source surface to zoom.
1295 \param zoomx The horizontal zoom factor.
1296 \param zoomy The vertical zoom factor.
1297 \param dstwidth Pointer to an integer to store the calculated width of the zoomed target surface.
1298 \param dstheight Pointer to an integer to store the calculated height of the zoomed target surface.
1300 void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight)
1303 * Make zoom factors positive
1306 flipx = (zoomx<0.0);
1307 if (flipx) zoomx = -zoomx;
1308 flipy = (zoomy<0.0);
1309 if (flipy) zoomy = -zoomy;
1312 * Sanity check zoom factors
1314 if (zoomx < VALUE_LIMIT) {
1315 zoomx = VALUE_LIMIT;
1317 if (zoomy < VALUE_LIMIT) {
1318 zoomy = VALUE_LIMIT;
1322 * Calculate target size
1324 *dstwidth = (int) ((double) width * zoomx);
1325 *dstheight = (int) ((double) height * zoomy);
1326 if (*dstwidth < 1) {
1329 if (*dstheight < 1) {
1335 \brief Zoom a surface by independent horizontal and vertical factors with optional smoothing.
1337 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1338 'zoomx' and 'zoomy' are scaling factors for width and height. If 'smooth' is on
1339 then the destination 32bit surface is anti-aliased. If the surface is not 8bit
1340 or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
1341 If zoom factors are negative, the image is flipped on the axes.
1343 \param src The surface to zoom.
1344 \param zoomx The horizontal zoom factor.
1345 \param zoomy The vertical zoom factor.
1346 \param smooth Antialiasing flag; set to SMOOTHING_ON to enable.
1348 \return The new, zoomed surface.
1350 SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth)
1352 SDL_Surface *rz_src;
1353 SDL_Surface *rz_dst;
1354 int dstwidth, dstheight;
1356 int i, src_converted;
1366 * Determine if source surface is 32bit or 8bit
1368 is32bit = (src->format->BitsPerPixel == 32);
1369 if ((is32bit) || (src->format->BitsPerPixel == 8)) {
1371 * Use source surface 'as is'
1377 * New source surface is 32bit with a defined RGBA ordering
1380 SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1381 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
1382 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
1384 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
1387 SDL_BlitSurface(src, NULL, rz_src, NULL);
1392 flipx = (zoomx<0.0);
1393 if (flipx) zoomx = -zoomx;
1394 flipy = (zoomy<0.0);
1395 if (flipy) zoomy = -zoomy;
1397 /* Get size if target */
1398 zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
1401 * Alloc space to completely contain the zoomed surface
1406 * Target surface is 32bit with source RGBA/ABGR ordering
1409 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
1410 rz_src->format->Rmask, rz_src->format->Gmask,
1411 rz_src->format->Bmask, rz_src->format->Amask);
1414 * Target surface is 8bit
1416 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
1420 * Lock source surface
1422 if (SDL_MUSTLOCK(rz_src)) {
1423 SDL_LockSurface(rz_src);
1427 * Check which kind of surface we have
1431 * Call the 32bit transformation routine to do the zooming (using alpha)
1433 _zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
1435 * Turn on source-alpha support
1437 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1440 * Copy palette and colorkey info
1442 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1443 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1445 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1447 * Call the 8bit transformation routine to do the zooming
1449 _zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
1450 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
1453 * Unlock source surface
1455 if (SDL_MUSTLOCK(rz_src)) {
1456 SDL_UnlockSurface(rz_src);
1460 * Cleanup temp surface
1462 if (src_converted) {
1463 SDL_FreeSurface(rz_src);
1467 * Return destination surface
1469 rz_dst->h -= GUARD_ROWS;
1474 \brief Shrink a surface by an integer ratio using averaging.
1476 Shrinks a 32bit or 8bit 'src' surface to a newly created 'dst' surface.
1477 'factorx' and 'factory' are the shrinking ratios (i.e. 2=1/2 the size,
1478 3=1/3 the size, etc.) The destination surface is antialiased by averaging
1479 the source box RGBA or Y information. If the surface is not 8bit
1480 or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
1481 The input surface is not modified. The output surface is newly allocated.
1483 \param src The surface to shrink.
1484 \param factorx The horizontal shrinking ratio.
1485 \param factory The vertical shrinking ratio.
1487 \return The new, shrunken surface.
1489 SDL_Surface *shrinkSurface(SDL_Surface *src, int factorx, int factory)
1491 SDL_Surface *rz_src;
1492 SDL_Surface *rz_dst;
1493 int dstwidth, dstheight;
1495 int i, src_converted;
1504 * Determine if source surface is 32bit or 8bit
1506 is32bit = (src->format->BitsPerPixel == 32);
1507 if ((is32bit) || (src->format->BitsPerPixel == 8)) {
1509 * Use source surface 'as is'
1515 * New source surface is 32bit with a defined RGBA ordering
1518 SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1519 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
1520 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
1522 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
1525 SDL_BlitSurface(src, NULL, rz_src, NULL);
1530 /* Get size for target */
1531 dstwidth=rz_src->w/factorx;
1532 while (dstwidth*factorx>rz_src->w) { dstwidth--; }
1533 dstheight=rz_src->h/factory;
1534 while (dstheight*factory>rz_src->h) { dstheight--; }
1537 * Alloc space to completely contain the shrunken surface
1538 * (with added guard rows)
1543 * Target surface is 32bit with source RGBA/ABGR ordering
1546 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
1547 rz_src->format->Rmask, rz_src->format->Gmask,
1548 rz_src->format->Bmask, rz_src->format->Amask);
1551 * Target surface is 8bit
1553 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
1557 * Lock source surface
1559 if (SDL_MUSTLOCK(rz_src)) {
1560 SDL_LockSurface(rz_src);
1564 * Check which kind of surface we have
1568 * Call the 32bit transformation routine to do the shrinking (using alpha)
1570 _shrinkSurfaceRGBA(rz_src, rz_dst, factorx, factory);
1572 * Turn on source-alpha support
1574 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1577 * Copy palette and colorkey info
1579 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1580 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1582 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1584 * Call the 8bit transformation routine to do the shrinking
1586 _shrinkSurfaceY(rz_src, rz_dst, factorx, factory);
1587 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
1591 * Unlock source surface
1593 if (SDL_MUSTLOCK(rz_src)) {
1594 SDL_UnlockSurface(rz_src);
1598 * Cleanup temp surface
1600 if (src_converted) {
1601 SDL_FreeSurface(rz_src);
1605 * Return destination surface
1607 rz_dst->h -= GUARD_ROWS;