Initialize
[sdk/emulator/qemu.git] / ui / sdl_rotate.c
1 /*
2  * Derived from: SDL_rotozoom,  LGPL (c) A. Schiffler from the SDL_gfx library.
3  * Modifications by Hyunjun Son(hj79.son@samsung.com)
4  *
5  * This work is licensed under the terms of the GNU GPL version 2.
6  * See the COPYING file in the top-level directory.
7  *
8  */
9
10 #ifdef WIN32
11 #include <windows.h>
12 #endif
13
14 #include <stdlib.h>
15 #include <string.h>
16
17 #include "sdl_rotate.h"
18
19 #if 1
20
21 /* ---- Internally used structures */
22
23 /*!
24 \brief A 32 bit RGBA pixel.
25 */
26 typedef struct tColorRGBA {
27         Uint8 r;
28         Uint8 g;
29         Uint8 b;
30         Uint8 a;
31 } tColorRGBA;
32
33 /*!
34 \brief A 8bit Y/palette pixel.
35 */
36 typedef struct tColorY {
37         Uint8 y;
38 } tColorY;
39
40 /*!
41 \brief Returns maximum of two numbers a and b.
42 */
43 #define MAX(a,b)    (((a) > (b)) ? (a) : (b))
44
45 /*!
46 \brief Number of guard rows added to destination surfaces.
47
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.
54 */
55 #define GUARD_ROWS (0)
56
57 /*!
58 \brief Lower limit of absolute zoom factor or rotation degrees.
59 */
60 #define VALUE_LIMIT     0.001
61
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);
72
73 /*!
74 \brief Returns colorkey info for a surface
75 */
76 Uint32 _colorkey(SDL_Surface *src)
77 {
78         Uint32 key = 0;
79 #if (SDL_MINOR_VERSION == 3)
80         SDL_GetColorKey(src, &key);
81 #else
82         if (src)
83         {
84                 key = src->format->colorkey;
85         }
86 #endif
87         return key;
88 }
89
90
91 /*!
92 \brief Internal 32 bit integer-factor averaging Shrinker.
93
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.
98
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.
103
104 \return 0 for success or -1 for error.
105 */
106 int _shrinkSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
107 {
108         int x, y, dx, dy, sgap, dgap, ra, ga, ba, aa;
109         int n_average;
110         tColorRGBA *sp, *osp, *oosp;
111         tColorRGBA *dp;
112
113         /*
114         * Averaging integer shrink
115         */
116
117         /* Precalculate division factor */
118         n_average = factorx*factory;
119
120         /*
121         * Scan destination
122         */
123         sp = (tColorRGBA *) src->pixels;
124         sgap = src->pitch - src->w * 4;
125
126         dp = (tColorRGBA *) dst->pixels;
127         dgap = dst->pitch - dst->w * 4;
128
129         for (y = 0; y < dst->h; y++) {
130
131                 osp=sp;
132                 for (x = 0; x < dst->w; x++) {
133
134                         /* Trace out source box and accumulate */
135                         oosp=sp;
136                         ra=ga=ba=aa=0;
137                         for (dy=0; dy < factory; dy++) {
138                                 for (dx=0; dx < factorx; dx++) {
139                                         ra += sp->r;
140                                         ga += sp->g;
141                                         ba += sp->b;
142                                         aa += sp->a;
143
144                                         sp++;
145                                 }
146                                 /* src dx loop */
147                                 sp = (tColorRGBA *)((Uint8*)sp + (src->pitch - 4*factorx)); // next y
148                         }
149                         /* src dy loop */
150
151                         /* next box-x */
152                         sp = (tColorRGBA *)((Uint8*)oosp + 4*factorx);
153
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;
159
160                         /*
161                         * Advance destination pointer
162                         */
163                         dp++;
164                 }
165                 /* dst x loop */
166
167                 /* next box-y */
168                 sp = (tColorRGBA *)((Uint8*)osp + src->pitch*factory);
169
170                 /*
171                 * Advance destination pointers
172                 */
173                 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
174         }
175         /* dst y loop */
176
177         return (0);
178 }
179
180 /*!
181 \brief Internal 8 bit integer-factor averaging shrinker.
182
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.
187
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.
192
193 \return 0 for success or -1 for error.
194 */
195 int _shrinkSurfaceY(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
196 {
197         int x, y, dx, dy, sgap, dgap, a;
198         int n_average;
199         Uint8 *sp, *osp, *oosp;
200         Uint8 *dp;
201
202         /*
203         * Averaging integer shrink
204         */
205
206         /* Precalculate division factor */
207         n_average = factorx*factory;
208
209         /*
210         * Scan destination
211         */
212         sp = (Uint8 *) src->pixels;
213         sgap = src->pitch - src->w;
214
215         dp = (Uint8 *) dst->pixels;
216         dgap = dst->pitch - dst->w;
217
218         for (y = 0; y < dst->h; y++) {
219
220                 osp=sp;
221                 for (x = 0; x < dst->w; x++) {
222
223                         /* Trace out source box and accumulate */
224                         oosp=sp;
225                         a=0;
226                         for (dy=0; dy < factory; dy++) {
227                                 for (dx=0; dx < factorx; dx++) {
228                                         a += (*sp);
229                                         /* next x */
230                                         sp++;
231                                 }
232                                 /* end src dx loop */
233                                 /* next y */
234                                 sp = (Uint8 *)((Uint8*)sp + (src->pitch - factorx));
235                         }
236                         /* end src dy loop */
237
238                         /* next box-x */
239                         sp = (Uint8 *)((Uint8*)oosp + factorx);
240
241                         /* Store result in destination */
242                         *dp = a/n_average;
243
244                         /*
245                         * Advance destination pointer
246                         */
247                         dp++;
248                 }
249                 /* end dst x loop */
250
251                 /* next box-y */
252                 sp = (Uint8 *)((Uint8*)osp + src->pitch*factory);
253
254                 /*
255                 * Advance destination pointers
256                 */
257                 dp = (Uint8 *)((Uint8 *)dp + dgap);
258         }
259         /* end dst y loop */
260
261         return (0);
262 }
263
264 /*!
265 \brief Internal 32 bit Zoomer with optional anti-aliasing by bilinear interpolation.
266
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.
270
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.
276
277 \return 0 for success or -1 for error.
278 */
279 int _zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy, int smooth)
280 {
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;
284         int dgap;
285
286         /*
287         * Variable setup
288         */
289         if (smooth) {
290                 /*
291                 * For interpolation: assume source dimension is one pixel
292                 */
293                 /*
294                 * smaller to avoid overflow on right and bottom edge.
295                 */
296                 sx = (int) (65536.0 * (float) (src->w - 1) / (float) dst->w);
297                 sy = (int) (65536.0 * (float) (src->h - 1) / (float) dst->h);
298         } else {
299                 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
300                 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
301         }
302
303         /*
304         * Allocate memory for row increments
305         */
306         if ((sax = (int *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
307                 return (-1);
308         }
309         if ((say = (int *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
310                 free(sax);
311                 return (-1);
312         }
313
314         /*
315         * Precalculate row increments
316         */
317         sp = csp = (tColorRGBA *) src->pixels;
318         dp = (tColorRGBA *) dst->pixels;
319
320         if (flipx) csp += (src->w-1);
321         if (flipy) csp += (src->pitch*(src->h-1));
322
323         csx = 0;
324         csax = sax;
325         for (x = 0; x <= dst->w; x++) {
326                 *csax = csx;
327                 csax++;
328                 csx &= 0xffff;
329                 csx += sx;
330         }
331         csy = 0;
332         csay = say;
333         for (y = 0; y <= dst->h; y++) {
334                 *csay = csy;
335                 csay++;
336                 csy &= 0xffff;
337                 csy += sy;
338         }
339
340         dgap = dst->pitch - dst->w * 4;
341
342         /*
343         * Switch between interpolating and non-interpolating code
344         */
345         if (smooth) {
346
347                 /*
348                 * Interpolating Zoom
349                 */
350
351                 /*
352                 * Scan destination
353                 */
354                 ly = 0;
355                 csay = say;
356                 for (y = 0; y < dst->h; y++) {
357                         /*
358                         * Setup color source pointers
359                         */
360                         c00 = csp;      
361                         c01 = csp;
362                         c01++;  
363                         c10 = (tColorRGBA *) ((Uint8 *) csp + src->pitch);
364                         c11 = c10;
365                         c11++;
366                         csax = sax;
367                         if (flipx) {
368                                 cswap = c00; c00=c01; c01=cswap;
369                                 cswap = c10; c10=c11; c11=cswap;
370                         }
371                         if (flipy) {
372                                 cswap = c00; c00=c10; c10=cswap;
373                                 cswap = c01; c01=c11; c11=cswap;
374                         }
375                         lx = 0;
376                         for (x = 0; x < dst->w; x++) {
377                                 /*
378                                 * Interpolate colors
379                                 */
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;
394
395                                 /*
396                                 * Advance source pointers
397                                 */
398                                 csax++;
399                                 sstep = (*csax >> 16);
400                                 lx += sstep;
401                                 if (lx >= src->w) sstep = 0;
402                                 if (flipx) sstep = -sstep;
403                                 c00 += sstep;
404                                 c01 += sstep;
405                                 c10 += sstep;
406                                 c11 += sstep;
407                                 /*
408                                 * Advance destination pointer
409                                 */
410                                 dp++;
411                         }
412                         /*
413                         * Advance source pointer
414                         */
415                         csay++;
416                         sstep = (*csay >> 16);
417                         ly += sstep;
418                         if (ly >= src->h) sstep = 0;
419                         sstep *= src->pitch;
420                         if (flipy) sstep = -sstep;
421                         csp = (tColorRGBA *) ((Uint8 *) csp + sstep);
422
423                         /*
424                         * Advance destination pointers
425                         */
426                         dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
427                 }
428         } else {
429
430                 /*
431                 * Non-Interpolating Zoom
432                 */
433
434                 csay = say;
435                 for (y = 0; y < dst->h; y++) {
436                         sp = csp;
437                         csax = sax;
438                         for (x = 0; x < dst->w; x++) {
439                                 /*
440                                 * Draw
441                                 */
442                                 *dp = *sp;
443                                 /*
444                                 * Advance source pointers
445                                 */
446                                 csax++;
447                                 sstep = (*csax >> 16);
448                                 if (flipx) sstep = -sstep;
449                                 sp += sstep;
450                                 /*
451                                 * Advance destination pointer
452                                 */
453                                 dp++;
454                         }
455                         /*
456                         * Advance source pointer
457                         */
458                         csay++;
459                         sstep = (*csay >> 16) * src->pitch;
460                         if (flipy) sstep = -sstep;
461                         csp = (tColorRGBA *) ((Uint8 *) csp + sstep);
462
463                         /*
464                         * Advance destination pointers
465                         */
466                         dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
467                 }
468         }
469
470         /*
471         * Remove temp arrays
472         */
473         free(sax);
474         free(say);
475
476         return (0);
477 }
478
479 /*!
480
481 \brief Internal 8 bit Zoomer without smoothing.
482
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.
486
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.
491
492 \return 0 for success or -1 for error.
493 */
494 int _zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy)
495 {
496         int x, y;
497         Uint32 *sax, *say, *csax, *csay;
498         int csx, csy;
499         Uint8 *sp, *dp, *csp;
500         int dgap;
501
502         /*
503         * Allocate memory for row increments
504         */
505         if ((sax = (Uint32 *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
506                 return (-1);
507         }
508         if ((say = (Uint32 *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
509                 free(sax);
510                 return (-1);
511         }
512
513         /*
514         * Pointer setup
515         */
516         sp = csp = (Uint8 *) src->pixels;
517         dp = (Uint8 *) dst->pixels;
518         dgap = dst->pitch - dst->w;
519
520         if (flipx) csp += (src->w-1);
521         if (flipy) csp  = ( (Uint8*)csp + src->pitch*(src->h-1) );
522
523         /*
524         * Precalculate row increments
525         */
526         csx = 0;
527         csax = sax;
528         for (x = 0; x < dst->w; x++) {
529                 csx += src->w;
530                 *csax = 0;
531                 while (csx >= dst->w) {
532                         csx -= dst->w;
533                         (*csax)++;
534                 }
535                 csax++;
536         }
537         csy = 0;
538         csay = say;
539         for (y = 0; y < dst->h; y++) {
540                 csy += src->h;
541                 *csay = 0;
542                 while (csy >= dst->h) {
543                         csy -= dst->h;
544                         (*csay)++;
545                 }
546                 csay++;
547         }
548
549         /*
550         * Draw
551         */
552         csay = say;
553         for (y = 0; y < dst->h; y++) {
554                 csax = sax;
555                 sp = csp;
556                 for (x = 0; x < dst->w; x++) {
557                         /*
558                         * Draw
559                         */
560                         *dp = *sp;
561                         /*
562                         * Advance source pointers
563                         */
564                         sp += (*csax) * (flipx ? -1 : 1);
565                         csax++;
566                         /*
567                         * Advance destination pointer
568                         */
569                         dp++;
570                 }
571                 /*
572                 * Advance source pointer (for row)
573                 */
574                 csp += ((*csay) * src->pitch) * (flipy ? -1 : 1);
575                 csay++;
576
577                 /*
578                 * Advance destination pointers
579                 */
580                 dp += dgap;
581         }
582
583         /*
584         * Remove temp arrays
585         */
586         free(sax);
587         free(say);
588
589         return (0);
590 }
591
592 /*!
593 \brief Internal 32 bit rotozoomer with optional anti-aliasing.
594
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.
600
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.
610 */
611 void _transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy, int smooth)
612 {
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;
615         tColorRGBA *pc, *sp;
616         int gap;
617
618         /*
619         * Variable setup
620         */
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);
625         sw = src->w - 1;
626         sh = src->h - 1;
627         pc = (tColorRGBA*) dst->pixels;
628         gap = dst->pitch - dst->w * 4;
629
630         /*
631         * Switch between interpolating and non-interpolating code
632         */
633         if (smooth) {
634                 for (y = 0; y < dst->h; y++) {
635                         dy = cy - y;
636                         sdx = (ax + (isin * dy)) + xd;
637                         sdy = (ay - (icos * dy)) + yd;
638                         for (x = 0; x < dst->w; x++) {
639                                 dx = (sdx >> 16);
640                                 dy = (sdy >> 16);
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);
645                                         sp += dx;
646                                         c00 = *sp;
647                                         sp += 1;
648                                         c01 = *sp;
649                                         sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
650                                         c11 = *sp;
651                                         sp -= 1;
652                                         c10 = *sp;
653                                         if (flipx) {
654                                                 cswap = c00; c00=c01; c01=cswap;
655                                                 cswap = c10; c10=c11; c11=cswap;
656                                         }
657                                         if (flipy) {
658                                                 cswap = c00; c00=c10; c10=cswap;
659                                                 cswap = c01; c01=c11; c11=cswap;
660                                         }
661                                         /*
662                                         * Interpolate colors
663                                         */
664                                         ex = (sdx & 0xffff);
665                                         ey = (sdy & 0xffff);
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;
678                                 }
679                                 sdx += icos;
680                                 sdy += isin;
681                                 pc++;
682                         }
683                         pc = (tColorRGBA *) ((Uint8 *) pc + gap);
684                 }
685         } else {
686                 for (y = 0; y < dst->h; y++) {
687                         dy = cy - 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);
697                                         sp += dx;
698                                         *pc = *sp;
699                                 }
700                                 sdx += icos;
701                                 sdy += isin;
702                                 pc++;
703                         }
704                         pc = (tColorRGBA *) ((Uint8 *) pc + gap);
705                 }
706         }
707 }
708
709 /*!
710
711 \brief Rotates and zooms 8 bit palette/Y 'src' surface to 'dst' surface without smoothing.
712
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.
717
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.
726 */
727 void transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy)
728 {
729         int x, y, dx, dy, xd, yd, sdx, sdy, ax, ay, sw, sh;
730         tColorY *pc, *sp;
731         int gap;
732
733         /*
734         * Variable setup
735         */
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);
740         sw = src->w - 1;
741         sh = src->h - 1;
742         pc = (tColorY*) dst->pixels;
743         gap = dst->pitch - dst->w;
744         /*
745         * Clear surface to colorkey
746         */      
747         memset(pc, (unsigned char) (_colorkey(src) & 0xff), dst->pitch * dst->h);
748         /*
749         * Iterate through destination surface
750         */
751         for (y = 0; y < dst->h; y++) {
752                 dy = cy - 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);
763                                 *pc = *sp;
764                         }
765                         sdx += icos;
766                         sdy += isin;
767                         pc++;
768                 }
769                 pc += gap;
770         }
771 }
772 #endif
773
774 /*!
775 \brief Rotates a 32 bit surface in increments of 90 degrees.
776
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)
781
782 \param src Source surface to rotate.
783 \param numClockwiseTurns Number of clockwise 90 degree turns to apply to the source.
784
785 \returns The new, rotated surface; or NULL for surfaces with incorrect input format.
786 */
787 SDL_Surface* rotateSurface90Degrees(SDL_Surface* src, int numClockwiseTurns)
788 {
789         int row, col, newWidth, newHeight;
790         int bpp, src_ipr, dst_ipr;
791         SDL_Surface* dst;
792         Uint32* srcBuf;
793         Uint32* dstBuf;
794
795         /* Has to be a valid surface pointer and only 32-bit surfaces (for now) */
796         if (!src || src->format->BitsPerPixel != 32) { return NULL; }
797
798         /* normalize numClockwiseTurns */
799         while(numClockwiseTurns < 0) { numClockwiseTurns += 4; }
800         numClockwiseTurns = (numClockwiseTurns % 4);
801
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,
806                 src->format->Rmask,
807                 src->format->Gmask,
808                 src->format->Bmask,
809                 src->format->Amask);
810         if(!dst) {
811                 return NULL;
812         }
813
814         if (SDL_MUSTLOCK(dst)) {
815                 SDL_LockSurface(dst);
816         }
817         if (SDL_MUSTLOCK(dst)) {
818                 SDL_LockSurface(dst);
819         }
820
821         /* Calculate int-per-row */
822         bpp = src->format->BitsPerPixel / 8;
823         src_ipr = src->pitch / bpp;
824         dst_ipr = dst->pitch / bpp;
825
826         switch(numClockwiseTurns) {
827                 case 0: /* Make a copy of the surface */
828                         {
829                                 /* Unfortunately SDL_BlitSurface cannot be used to make a copy of the surface
830                                    since it does not preserve alpha. */
831
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));
835                                 }
836                                 else
837                                 {
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);
843                                                 srcBuf += src_ipr;
844                                                 dstBuf += dst_ipr;
845                                         } /* end for(col) */
846                                 } /* end for(row) */
847                         }
848                         break;
849
850                         /* rotate clockwise */
851                 case 1: /* rotated 90 degrees clockwise */
852                  {
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) {
857                                          *dstBuf = *srcBuf;
858                                          ++srcBuf;
859                                          dstBuf += dst_ipr;
860                                  }
861                                  /* end for(col) */
862                          }
863                          /* end for(row) */
864                  }
865                  break;
866
867                 case 2: /* rotated 180 degrees clockwise */
868                  {
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) {
873                                          *dstBuf = *srcBuf;
874                                          ++srcBuf;
875                                          --dstBuf;
876                                  }
877                          }
878                  }
879                  break;
880
881                 case 3:
882                  {
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) {
887                                          *dstBuf = *srcBuf;
888                                          ++srcBuf;
889                                          dstBuf -= dst_ipr;
890                                  }
891                          }
892                  }
893                  break;
894         }
895         /* end switch */
896
897         if (SDL_MUSTLOCK(src)) {
898                 SDL_UnlockSurface(src);
899         }
900         if (SDL_MUSTLOCK(dst)) {
901                 SDL_UnlockSurface(dst);
902         }
903
904         return dst;
905 }
906
907
908 #if 1
909 /*!
910 \brief Internal target surface sizing function for rotozooms with trig result return.
911
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.
921
922 */
923 void _rotozoomSurfaceSizeTrig(int width, int height, double angle, double zoomx, double zoomy,
924                                                           int *dstwidth, int *dstheight,
925                                                           double *canglezoom, double *sanglezoom)
926 {
927         double x, y, cx, cy, sx, sy;
928         double radangle;
929         int dstwidthhalf, dstheighthalf;
930
931         /*
932         * Determine destination width and height by rotating a centered source box
933         */
934         radangle = angle * (M_PI / 180.0);
935         *sanglezoom = sin(radangle);
936         *canglezoom = cos(radangle);
937         *sanglezoom *= zoomx;
938         *canglezoom *= zoomx;
939         x = width / 2;
940         y = height / 2;
941         cx = *canglezoom * x;
942         cy = *canglezoom * y;
943         sx = *sanglezoom * x;
944         sy = *sanglezoom * y;
945
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;
952 }
953
954 /*!
955 \brief Returns the size of the resulting target surface for a rotozoomSurfaceXY() call.
956
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.
964 */
965 void rotozoomSurfaceSizeXY(int width, int height, double angle, double zoomx, double zoomy, int *dstwidth, int *dstheight)
966 {
967         double dummy_sanglezoom, dummy_canglezoom;
968
969         _rotozoomSurfaceSizeTrig(width, height, angle, zoomx, zoomy, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
970 }
971
972 /*!
973 \brief Returns the size of the resulting target surface for a rotozoomSurface() call.
974
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.
981 */
982 void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth, int *dstheight)
983 {
984         double dummy_sanglezoom, dummy_canglezoom;
985
986         _rotozoomSurfaceSizeTrig(width, height, angle, zoom, zoom, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
987 }
988
989 /*!
990 \brief Rotates and zooms a surface and optional anti-aliasing.
991
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.
996
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.
1001
1002 \return The new rotozoomed surface.
1003 */
1004 SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth)
1005 {
1006         return rotozoomSurfaceXY(src, angle, zoom, zoom, smooth);
1007 }
1008
1009 /*!
1010 \brief Rotates and zooms a surface with different horizontal and vertival scaling factors and optional anti-aliasing.
1011
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.
1016
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.
1022
1023 \return The new rotozoomed surface.
1024 */
1025 SDL_Surface *rotozoomSurfaceXY(SDL_Surface * src, double angle, double zoomx, double zoomy, int smooth)
1026 {
1027         SDL_Surface *rz_src;
1028         SDL_Surface *rz_dst;
1029         double zoominv;
1030         double sanglezoom, canglezoom, sanglezoominv, canglezoominv;
1031         int dstwidthhalf, dstwidth, dstheighthalf, dstheight;
1032         int is32bit;
1033         int i, src_converted;
1034         int flipx,flipy;
1035         Uint8 r,g,b;
1036         Uint32 colorkey = 0;
1037         int colorKeyAvailable = 0;
1038
1039         /*
1040         * Sanity check
1041         */
1042         if (src == NULL)
1043                 return (NULL);
1044
1045         if (src->flags & SDL_SRCCOLORKEY)
1046         {
1047                 colorkey = _colorkey(src);
1048                 SDL_GetRGB(colorkey, src->format, &r, &g, &b);
1049                 colorKeyAvailable = 1;
1050         }
1051         /*
1052         * Determine if source surface is 32bit or 8bit
1053         */
1054         is32bit = (src->format->BitsPerPixel == 32);
1055         if ((is32bit) || (src->format->BitsPerPixel == 8)) {
1056                 /*
1057                 * Use source surface 'as is'
1058                 */
1059                 rz_src = src;
1060                 src_converted = 0;
1061         } else {
1062                 /*
1063                 * New source surface is 32bit with a defined RGBA ordering
1064                 */
1065                 rz_src =
1066                         SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1067 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
1068                         0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
1069 #else
1070                         0xff000000,  0x00ff0000, 0x0000ff00, 0x000000ff
1071 #endif
1072                         );
1073                 if(colorKeyAvailable)
1074                         SDL_SetColorKey(src, 0, 0);
1075
1076                 SDL_BlitSurface(src, NULL, rz_src, NULL);
1077
1078                 if(colorKeyAvailable)
1079                         SDL_SetColorKey(src, SDL_SRCCOLORKEY, colorkey);
1080                 src_converted = 1;
1081                 is32bit = 1;
1082         }
1083
1084         /*
1085         * Sanity check zoom factor
1086         */
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);
1094
1095         /*
1096         * Check if we have a rotozoom or just a zoom
1097         */
1098         if (fabs(angle) > VALUE_LIMIT) {
1099
1100                 /*
1101                 * Angle!=0: full rotozoom
1102                 */
1103                 /*
1104                 * -----------------------
1105                 */
1106
1107                 /* Determine target size */
1108                 _rotozoomSurfaceSizeTrig(rz_src->w, rz_src->h, angle, zoomx, zoomy, &dstwidth, &dstheight, &canglezoom, &sanglezoom);
1109
1110                 /*
1111                 * Calculate target factors from sin/cos and zoom
1112                 */
1113                 sanglezoominv = sanglezoom;
1114                 canglezoominv = canglezoom;
1115                 sanglezoominv *= zoominv;
1116                 canglezoominv *= zoominv;
1117
1118                 /* Calculate half size */
1119                 dstwidthhalf = dstwidth / 2;
1120                 dstheighthalf = dstheight / 2;
1121
1122                 /*
1123                 * Alloc space to completely contain the rotated surface
1124                 */
1125                 rz_dst = NULL;
1126                 if (is32bit) {
1127                         /*
1128                         * Target surface is 32bit with source RGBA/ABGR ordering
1129                         */
1130                         rz_dst =
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);
1134                 } else {
1135                         /*
1136                         * Target surface is 8bit
1137                         */
1138                         rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
1139                 }
1140
1141                 if (colorKeyAvailable == 1){
1142                         colorkey = SDL_MapRGB(rz_dst->format, r, g, b);
1143
1144                         SDL_FillRect(rz_dst, NULL, colorkey );
1145                 }
1146
1147                 /*
1148                 * Lock source surface
1149                 */
1150                 if (SDL_MUSTLOCK(rz_src)) {
1151                         SDL_LockSurface(rz_src);
1152                 }
1153
1154                 /*
1155                 * Check which kind of surface we have
1156                 */
1157                 if (is32bit) {
1158                         /*
1159                         * Call the 32bit transformation routine to do the rotation (using alpha)
1160                         */
1161                         _transformSurfaceRGBA(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
1162                                 (int) (sanglezoominv), (int) (canglezoominv),
1163                                 flipx, flipy,
1164                                 smooth);
1165                         /*
1166                         * Turn on source-alpha support
1167                         */
1168                         SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1169                         SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
1170                 } else {
1171                         /*
1172                         * Copy palette and colorkey info
1173                         */
1174                         for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1175                                 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1176                         }
1177                         rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1178                         /*
1179                         * Call the 8bit transformation routine to do the rotation
1180                         */
1181                         transformSurfaceY(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
1182                                 (int) (sanglezoominv), (int) (canglezoominv),
1183                                 flipx, flipy);
1184                         SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
1185                 }
1186                 /*
1187                 * Unlock source surface
1188                 */
1189                 if (SDL_MUSTLOCK(rz_src)) {
1190                         SDL_UnlockSurface(rz_src);
1191                 }
1192
1193         } else {
1194
1195                 /*
1196                 * Angle=0: Just a zoom
1197                 */
1198                 /*
1199                 * --------------------
1200                 */
1201
1202                 /*
1203                 * Calculate target size
1204                 */
1205                 zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
1206
1207                 /*
1208                 * Alloc space to completely contain the zoomed surface
1209                 */
1210                 rz_dst = NULL;
1211                 if (is32bit) {
1212                         /*
1213                         * Target surface is 32bit with source RGBA/ABGR ordering
1214                         */
1215                         rz_dst =
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);
1219                 } else {
1220                         /*
1221                         * Target surface is 8bit
1222                         */
1223                         rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
1224                 }
1225
1226                 if (colorKeyAvailable == 1){
1227                         colorkey = SDL_MapRGB(rz_dst->format, r, g, b);
1228
1229                         SDL_FillRect(rz_dst, NULL, colorkey );
1230                 }
1231
1232                 /*
1233                 * Lock source surface
1234                 */
1235                 if (SDL_MUSTLOCK(rz_src)) {
1236                         SDL_LockSurface(rz_src);
1237                 }
1238
1239                 /*
1240                 * Check which kind of surface we have
1241                 */
1242                 if (is32bit) {
1243                         /*
1244                         * Call the 32bit transformation routine to do the zooming (using alpha)
1245                         */
1246                         _zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
1247                         /*
1248                         * Turn on source-alpha support
1249                         */
1250                         SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1251                         SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
1252                 } else {
1253                         /*
1254                         * Copy palette and colorkey info
1255                         */
1256                         for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1257                                 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1258                         }
1259                         rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1260                         /*
1261                         * Call the 8bit transformation routine to do the zooming
1262                         */
1263                         _zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
1264                         SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
1265                 }
1266                 /*
1267                 * Unlock source surface
1268                 */
1269                 if (SDL_MUSTLOCK(rz_src)) {
1270                         SDL_UnlockSurface(rz_src);
1271                 }
1272         }
1273
1274         /*
1275         * Cleanup temp surface
1276         */
1277         if (src_converted) {
1278                 SDL_FreeSurface(rz_src);
1279         }
1280
1281         /*
1282         * Return destination surface
1283         */
1284         rz_dst->h -= GUARD_ROWS;
1285         return (rz_dst);
1286 }
1287
1288 /*!
1289 \brief Calculates the size of the target surface for a zoomSurface() call.
1290
1291 The minimum size of the target surface is 1. The input factors can be positive or negative.
1292
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.
1299 */
1300 void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight)
1301 {
1302         /*
1303         * Make zoom factors positive
1304         */
1305         int flipx, flipy;
1306         flipx = (zoomx<0.0);
1307         if (flipx) zoomx = -zoomx;
1308         flipy = (zoomy<0.0);
1309         if (flipy) zoomy = -zoomy;
1310
1311         /*
1312         * Sanity check zoom factors
1313         */
1314         if (zoomx < VALUE_LIMIT) {
1315                 zoomx = VALUE_LIMIT;
1316         }
1317         if (zoomy < VALUE_LIMIT) {
1318                 zoomy = VALUE_LIMIT;
1319         }
1320
1321         /*
1322         * Calculate target size
1323         */
1324         *dstwidth = (int) ((double) width * zoomx);
1325         *dstheight = (int) ((double) height * zoomy);
1326         if (*dstwidth < 1) {
1327                 *dstwidth = 1;
1328         }
1329         if (*dstheight < 1) {
1330                 *dstheight = 1;
1331         }
1332 }
1333
1334 /*!
1335 \brief Zoom a surface by independent horizontal and vertical factors with optional smoothing.
1336
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.
1342
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.
1347
1348 \return The new, zoomed surface.
1349 */
1350 SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth)
1351 {
1352         SDL_Surface *rz_src;
1353         SDL_Surface *rz_dst;
1354         int dstwidth, dstheight;
1355         int is32bit;
1356         int i, src_converted;
1357         int flipx, flipy;
1358
1359         /*
1360         * Sanity check
1361         */
1362         if (src == NULL)
1363                 return (NULL);
1364
1365         /*
1366         * Determine if source surface is 32bit or 8bit
1367         */
1368         is32bit = (src->format->BitsPerPixel == 32);
1369         if ((is32bit) || (src->format->BitsPerPixel == 8)) {
1370                 /*
1371                 * Use source surface 'as is'
1372                 */
1373                 rz_src = src;
1374                 src_converted = 0;
1375         } else {
1376                 /*
1377                 * New source surface is 32bit with a defined RGBA ordering
1378                 */
1379                 rz_src =
1380                         SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1381 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
1382                         0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
1383 #else
1384                         0xff000000,  0x00ff0000, 0x0000ff00, 0x000000ff
1385 #endif
1386                         );
1387                 SDL_BlitSurface(src, NULL, rz_src, NULL);
1388                 src_converted = 1;
1389                 is32bit = 1;
1390         }
1391
1392         flipx = (zoomx<0.0);
1393         if (flipx) zoomx = -zoomx;
1394         flipy = (zoomy<0.0);
1395         if (flipy) zoomy = -zoomy;
1396
1397         /* Get size if target */
1398         zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
1399
1400         /*
1401         * Alloc space to completely contain the zoomed surface
1402         */
1403         rz_dst = NULL;
1404         if (is32bit) {
1405                 /*
1406                 * Target surface is 32bit with source RGBA/ABGR ordering
1407                 */
1408                 rz_dst =
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);
1412         } else {
1413                 /*
1414                 * Target surface is 8bit
1415                 */
1416                 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
1417         }
1418
1419         /*
1420         * Lock source surface
1421         */
1422         if (SDL_MUSTLOCK(rz_src)) {
1423                 SDL_LockSurface(rz_src);
1424         }
1425
1426         /*
1427         * Check which kind of surface we have
1428         */
1429         if (is32bit) {
1430                 /*
1431                 * Call the 32bit transformation routine to do the zooming (using alpha)
1432                 */
1433                 _zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
1434                 /*
1435                 * Turn on source-alpha support
1436                 */
1437                 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1438         } else {
1439                 /*
1440                 * Copy palette and colorkey info
1441                 */
1442                 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1443                         rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1444                 }
1445                 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1446                 /*
1447                 * Call the 8bit transformation routine to do the zooming
1448                 */
1449                 _zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
1450                 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
1451         }
1452         /*
1453         * Unlock source surface
1454         */
1455         if (SDL_MUSTLOCK(rz_src)) {
1456                 SDL_UnlockSurface(rz_src);
1457         }
1458
1459         /*
1460         * Cleanup temp surface
1461         */
1462         if (src_converted) {
1463                 SDL_FreeSurface(rz_src);
1464         }
1465
1466         /*
1467         * Return destination surface
1468         */
1469         rz_dst->h -= GUARD_ROWS;
1470         return (rz_dst);
1471 }
1472
1473 /*!
1474 \brief Shrink a surface by an integer ratio using averaging.
1475
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.
1482
1483 \param src The surface to shrink.
1484 \param factorx The horizontal shrinking ratio.
1485 \param factory The vertical shrinking ratio.
1486
1487 \return The new, shrunken surface.
1488 */
1489 SDL_Surface *shrinkSurface(SDL_Surface *src, int factorx, int factory)
1490 {
1491         SDL_Surface *rz_src;
1492         SDL_Surface *rz_dst;
1493         int dstwidth, dstheight;
1494         int is32bit;
1495         int i, src_converted;
1496
1497         /*
1498         * Sanity check
1499         */
1500         if (src == NULL)
1501                 return (NULL);
1502
1503         /*
1504         * Determine if source surface is 32bit or 8bit
1505         */
1506         is32bit = (src->format->BitsPerPixel == 32);
1507         if ((is32bit) || (src->format->BitsPerPixel == 8)) {
1508                 /*
1509                 * Use source surface 'as is'
1510                 */
1511                 rz_src = src;
1512                 src_converted = 0;
1513         } else {
1514                 /*
1515                 * New source surface is 32bit with a defined RGBA ordering
1516                 */
1517                 rz_src =
1518                         SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1519 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
1520                         0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
1521 #else
1522                         0xff000000,  0x00ff0000, 0x0000ff00, 0x000000ff
1523 #endif
1524                         );
1525                 SDL_BlitSurface(src, NULL, rz_src, NULL);
1526                 src_converted = 1;
1527                 is32bit = 1;
1528         }
1529
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--; }
1535
1536         /*
1537         * Alloc space to completely contain the shrunken surface
1538         * (with added guard rows)
1539         */
1540         rz_dst = NULL;
1541         if (is32bit) {
1542                 /*
1543                 * Target surface is 32bit with source RGBA/ABGR ordering
1544                 */
1545                 rz_dst =
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);
1549         } else {
1550                 /*
1551                 * Target surface is 8bit
1552                 */
1553                 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
1554         }
1555
1556         /*
1557         * Lock source surface
1558         */
1559         if (SDL_MUSTLOCK(rz_src)) {
1560                 SDL_LockSurface(rz_src);
1561         }
1562
1563         /*
1564         * Check which kind of surface we have
1565         */
1566         if (is32bit) {
1567                 /*
1568                 * Call the 32bit transformation routine to do the shrinking (using alpha)
1569                 */
1570                 _shrinkSurfaceRGBA(rz_src, rz_dst, factorx, factory);
1571                 /*
1572                 * Turn on source-alpha support
1573                 */
1574                 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1575         } else {
1576                 /*
1577                 * Copy palette and colorkey info
1578                 */
1579                 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1580                         rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1581                 }
1582                 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1583                 /*
1584                 * Call the 8bit transformation routine to do the shrinking
1585                 */
1586                 _shrinkSurfaceY(rz_src, rz_dst, factorx, factory);
1587                 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
1588         }
1589
1590         /*
1591         * Unlock source surface
1592         */
1593         if (SDL_MUSTLOCK(rz_src)) {
1594                 SDL_UnlockSurface(rz_src);
1595         }
1596
1597         /*
1598         * Cleanup temp surface
1599         */
1600         if (src_converted) {
1601                 SDL_FreeSurface(rz_src);
1602         }
1603
1604         /*
1605         * Return destination surface
1606         */
1607         rz_dst->h -= GUARD_ROWS;
1608         return (rz_dst);
1609 }
1610 #endif