update source for tizen_2.1
[sdk/emulator/qemu.git] / tizen / src / SDL_gfx / SDL_rotozoom.c
1 /*  
2
3 SDL_rotozoom.c: rotozoomer, zoomer and shrinker for 32bit or 8bit surfaces
4
5 Copyright (C) 2001-2012  Andreas Schiffler
6
7 This software is provided 'as-is', without any express or implied
8 warranty. In no event will the authors be held liable for any damages
9 arising from the use of this software.
10
11 Permission is granted to anyone to use this software for any purpose,
12 including commercial applications, and to alter it and redistribute it
13 freely, subject to the following restrictions:
14
15 1. The origin of this software must not be misrepresented; you must not
16 claim that you wrote the original software. If you use this software
17 in a product, an acknowledgment in the product documentation would be
18 appreciated but is not required.
19
20 2. Altered source versions must be plainly marked as such, and must not be
21 misrepresented as being the original software.
22
23 3. This notice may not be removed or altered from any source
24 distribution.
25
26 Andreas Schiffler -- aschiffler at ferzkopp dot net
27
28 */
29
30 #ifdef WIN32
31 #include <windows.h>
32 #endif
33
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include "SDL_rotozoom.h"
38
39 /* ---- Internally used structures */
40
41 /*!
42 \brief A 32 bit RGBA pixel.
43 */
44 typedef struct tColorRGBA {
45         Uint8 r;
46         Uint8 g;
47         Uint8 b;
48         Uint8 a;
49 } tColorRGBA;
50
51 /*!
52 \brief A 8bit Y/palette pixel.
53 */
54 typedef struct tColorY {
55         Uint8 y;
56 } tColorY;
57
58 /*! 
59 \brief Returns maximum of two numbers a and b.
60 */
61 #define MAX(a,b)    (((a) > (b)) ? (a) : (b))
62
63 /*! 
64 \brief Number of guard rows added to destination surfaces.
65
66 This is a simple but effective workaround for observed issues.
67 These rows allocate extra memory and are then hidden from the surface.
68 Rows are added to the end of destination surfaces when they are allocated. 
69 This catches any potential overflows which seem to happen with 
70 just the right src image dimensions and scale/rotation and can lead
71 to a situation where the program can segfault.
72 */
73 #define GUARD_ROWS (2)
74
75 /*!
76 \brief Lower limit of absolute zoom factor or rotation degrees.
77 */
78 #define VALUE_LIMIT     0.001
79
80 /*!
81 \brief Returns colorkey info for a surface
82 */
83 static Uint32 _colorkey(SDL_Surface *src)
84 {
85         Uint32 key = 0; 
86 #if (SDL_MINOR_VERSION == 3)
87         SDL_GetColorKey(src, &key);
88 #else
89         if (src) 
90         {
91                 key = src->format->colorkey;
92         }
93 #endif
94         return key;
95 }
96
97
98 /*! 
99 \brief Internal 32 bit integer-factor averaging Shrinker.
100
101 Shrinks 32 bit RGBA/ABGR 'src' surface to 'dst' surface.
102 Averages color and alpha values values of src pixels to calculate dst pixels.
103 Assumes src and dst surfaces are of 32 bit depth.
104 Assumes dst surface was allocated with the correct dimensions.
105
106 \param src The surface to shrink (input).
107 \param dst The shrunken surface (output).
108 \param factorx The horizontal shrinking ratio.
109 \param factory The vertical shrinking ratio.
110
111 \return 0 for success or -1 for error.
112 */
113 static int _shrinkSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
114 {
115         int x, y, dx, dy, sgap, dgap, ra, ga, ba, aa;
116         int n_average;
117         tColorRGBA *sp, *osp, *oosp;
118         tColorRGBA *dp;
119
120         /*
121         * Averaging integer shrink
122         */
123
124         /* Precalculate division factor */
125         n_average = factorx*factory;
126
127         /*
128         * Scan destination
129         */
130         sp = (tColorRGBA *) src->pixels;
131         sgap = src->pitch - src->w * 4;
132
133         dp = (tColorRGBA *) dst->pixels;
134         dgap = dst->pitch - dst->w * 4;
135
136         for (y = 0; y < dst->h; y++) {
137
138                 osp=sp;
139                 for (x = 0; x < dst->w; x++) {
140
141                         /* Trace out source box and accumulate */
142                         oosp=sp;
143                         ra=ga=ba=aa=0;
144                         for (dy=0; dy < factory; dy++) {
145                                 for (dx=0; dx < factorx; dx++) {
146                                         ra += sp->r;
147                                         ga += sp->g;
148                                         ba += sp->b;
149                                         aa += sp->a;
150
151                                         sp++;
152                                 } 
153                                 /* src dx loop */
154                                 sp = (tColorRGBA *)((Uint8*)sp + (src->pitch - 4*factorx)); // next y
155                         }
156                         /* src dy loop */
157
158                         /* next box-x */
159                         sp = (tColorRGBA *)((Uint8*)oosp + 4*factorx);
160
161                         /* Store result in destination */
162                         dp->r = ra/n_average;
163                         dp->g = ga/n_average;
164                         dp->b = ba/n_average;
165                         dp->a = aa/n_average;
166
167                         /*
168                         * Advance destination pointer 
169                         */
170                         dp++;
171                 } 
172                 /* dst x loop */
173
174                 /* next box-y */
175                 sp = (tColorRGBA *)((Uint8*)osp + src->pitch*factory);
176
177                 /*
178                 * Advance destination pointers 
179                 */
180                 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
181         } 
182         /* dst y loop */
183
184         return (0);
185 }
186
187 /*! 
188 \brief Internal 8 bit integer-factor averaging shrinker.
189
190 Shrinks 8bit Y 'src' surface to 'dst' surface.
191 Averages color (brightness) values values of src pixels to calculate dst pixels.
192 Assumes src and dst surfaces are of 8 bit depth.
193 Assumes dst surface was allocated with the correct dimensions.
194
195 \param src The surface to shrink (input).
196 \param dst The shrunken surface (output).
197 \param factorx The horizontal shrinking ratio.
198 \param factory The vertical shrinking ratio.
199
200 \return 0 for success or -1 for error.
201 */
202 static int _shrinkSurfaceY(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
203 {
204         int x, y, dx, dy, sgap, dgap, a;
205         int n_average;
206         Uint8 *sp, *osp, *oosp;
207         Uint8 *dp;
208
209         /*
210         * Averaging integer shrink
211         */
212
213         /* Precalculate division factor */
214         n_average = factorx*factory;
215
216         /*
217         * Scan destination
218         */
219         sp = (Uint8 *) src->pixels;
220         sgap = src->pitch - src->w;
221
222         dp = (Uint8 *) dst->pixels;
223         dgap = dst->pitch - dst->w;
224
225         for (y = 0; y < dst->h; y++) {    
226
227                 osp=sp;
228                 for (x = 0; x < dst->w; x++) {
229
230                         /* Trace out source box and accumulate */
231                         oosp=sp;
232                         a=0;
233                         for (dy=0; dy < factory; dy++) {
234                                 for (dx=0; dx < factorx; dx++) {
235                                         a += (*sp);
236                                         /* next x */           
237                                         sp++;
238                                 } 
239                                 /* end src dx loop */         
240                                 /* next y */
241                                 sp = (Uint8 *)((Uint8*)sp + (src->pitch - factorx)); 
242                         } 
243                         /* end src dy loop */
244
245                         /* next box-x */
246                         sp = (Uint8 *)((Uint8*)oosp + factorx);
247
248                         /* Store result in destination */
249                         *dp = a/n_average;
250
251                         /*
252                         * Advance destination pointer 
253                         */
254                         dp++;
255                 } 
256                 /* end dst x loop */
257
258                 /* next box-y */
259                 sp = (Uint8 *)((Uint8*)osp + src->pitch*factory);
260
261                 /*
262                 * Advance destination pointers 
263                 */
264                 dp = (Uint8 *)((Uint8 *)dp + dgap);
265         } 
266         /* end dst y loop */
267
268         return (0);
269 }
270
271 /*! 
272 \brief Internal 32 bit Zoomer with optional anti-aliasing by bilinear interpolation.
273
274 Zooms 32 bit RGBA/ABGR 'src' surface to 'dst' surface.
275 Assumes src and dst surfaces are of 32 bit depth.
276 Assumes dst surface was allocated with the correct dimensions.
277
278 \param src The surface to zoom (input).
279 \param dst The zoomed surface (output).
280 \param flipx Flag indicating if the image should be horizontally flipped.
281 \param flipy Flag indicating if the image should be vertically flipped.
282 \param smooth Antialiasing flag; set to SMOOTHING_ON to enable.
283
284 \return 0 for success or -1 for error.
285 */
286 static int _zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy, int smooth)
287 {
288         int x, y, sx, sy, ssx, ssy, *sax, *say, *csax, *csay, *salast, csx, csy, ex, ey, cx, cy, sstep, sstepx, sstepy;
289         tColorRGBA *c00, *c01, *c10, *c11;
290         tColorRGBA *sp, *csp, *dp;
291         int spixelgap, spixelw, spixelh, dgap, t1, t2;
292
293         /*
294         * Allocate memory for row/column increments 
295         */
296         if ((sax = (int *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
297                 return (-1);
298         }
299         if ((say = (int *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
300                 free(sax);
301                 return (-1);
302         }
303
304         /*
305         * Precalculate row increments 
306         */
307         spixelw = (src->w - 1);
308         spixelh = (src->h - 1);
309         if (smooth) {
310                 sx = (int) (65536.0 * (float) spixelw / (float) (dst->w - 1));
311                 sy = (int) (65536.0 * (float) spixelh / (float) (dst->h - 1));
312         } else {
313                 sx = (int) (65536.0 * (float) (src->w) / (float) (dst->w));
314                 sy = (int) (65536.0 * (float) (src->h) / (float) (dst->h));
315         }
316
317         /* Maximum scaled source size */
318         ssx = (src->w << 16) - 1;
319         ssy = (src->h << 16) - 1;
320
321         /* Precalculate horizontal row increments */
322         csx = 0;
323         csax = sax;
324         for (x = 0; x <= dst->w; x++) {
325                 *csax = csx;
326                 csax++;
327                 csx += sx;
328
329                 /* Guard from overflows */
330                 if (csx > ssx) { 
331                         csx = ssx; 
332                 }
333         }
334
335         /* Precalculate vertical row increments */
336         csy = 0;
337         csay = say;
338         for (y = 0; y <= dst->h; y++) {
339                 *csay = csy;
340                 csay++;
341                 csy += sy;
342
343                 /* Guard from overflows */
344                 if (csy > ssy) {
345                         csy = ssy;
346                 }
347         }
348
349         sp = (tColorRGBA *) src->pixels;
350         dp = (tColorRGBA *) dst->pixels;
351         dgap = dst->pitch - dst->w * 4;
352         spixelgap = src->pitch/4;
353
354         if (flipx) sp += spixelw;
355         if (flipy) sp += (spixelgap * spixelh);
356
357         /*
358         * Switch between interpolating and non-interpolating code 
359         */
360         if (smooth) {
361
362                 /*
363                 * Interpolating Zoom 
364                 */
365                 csay = say;
366                 for (y = 0; y < dst->h; y++) {
367                         csp = sp;
368                         csax = sax;
369                         for (x = 0; x < dst->w; x++) {
370                                 /*
371                                 * Setup color source pointers 
372                                 */
373                                 ex = (*csax & 0xffff);
374                                 ey = (*csay & 0xffff);
375                                 cx = (*csax >> 16);
376                                 cy = (*csay >> 16);
377                                 sstepx = cx < spixelw;
378                                 sstepy = cy < spixelh;
379                                 c00 = sp;
380                                 c01 = sp;
381                                 c10 = sp;
382                                 if (sstepy) {
383                                         if (flipy) {
384                                                 c10 -= spixelgap;
385                                         } else {
386                                                 c10 += spixelgap;
387                                         }
388                                 }
389                                 c11 = c10;
390                                 if (sstepx) {
391                                         if (flipx) {
392                                                 c01--;
393                                                 c11--;
394                                         } else {
395                                                 c01++;
396                                                 c11++;
397                                         }
398                                 }
399
400                                 /*
401                                 * Draw and interpolate colors 
402                                 */
403                                 t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
404                                 t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
405                                 dp->r = (((t2 - t1) * ey) >> 16) + t1;
406                                 t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff;
407                                 t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff;
408                                 dp->g = (((t2 - t1) * ey) >> 16) + t1;
409                                 t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff;
410                                 t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff;
411                                 dp->b = (((t2 - t1) * ey) >> 16) + t1;
412                                 t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff;
413                                 t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff;
414                                 dp->a = (((t2 - t1) * ey) >> 16) + t1;                          
415                                 /*
416                                 * Advance source pointer x
417                                 */
418                                 salast = csax;
419                                 csax++;                         
420                                 sstep = (*csax >> 16) - (*salast >> 16);
421                                 if (flipx) {
422                                         sp -= sstep;
423                                 } else {
424                                         sp += sstep;
425                                 }
426
427                                 /*
428                                 * Advance destination pointer x
429                                 */
430                                 dp++;
431                         }
432                         /*
433                         * Advance source pointer y
434                         */
435                         salast = csay;
436                         csay++;
437                         sstep = (*csay >> 16) - (*salast >> 16);
438                         sstep *= spixelgap;
439                         if (flipy) { 
440                                 sp = csp - sstep;
441                         } else {
442                                 sp = csp + sstep;
443                         }
444
445                         /*
446                         * Advance destination pointer y
447                         */
448                         dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
449                 }
450         } else {
451                 /*
452                 * Non-Interpolating Zoom 
453                 */              
454                 csay = say;
455                 for (y = 0; y < dst->h; y++) {
456                         csp = sp;
457                         csax = sax;
458                         for (x = 0; x < dst->w; x++) {
459                                 /*
460                                 * Draw 
461                                 */
462                                 *dp = *sp;
463
464                                 /*
465                                 * Advance source pointer x
466                                 */
467                                 salast = csax;
468                                 csax++;                         
469                                 sstep = (*csax >> 16) - (*salast >> 16);
470                                 if (flipx) sstep = -sstep;
471                                 sp += sstep;
472
473                                 /*
474                                 * Advance destination pointer x
475                                 */
476                                 dp++;
477                         }
478                         /*
479                         * Advance source pointer y
480                         */
481                         salast = csay;
482                         csay++;
483                         sstep = (*csay >> 16) - (*salast >> 16);
484                         sstep *= spixelgap;
485                         if (flipy) sstep = -sstep;                      
486                         sp = csp + sstep;
487
488                         /*
489                         * Advance destination pointer y
490                         */
491                         dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
492                 }
493         }
494
495         /*
496         * Remove temp arrays 
497         */
498         free(sax);
499         free(say);
500
501         return (0);
502 }
503
504 /*! 
505
506 \brief Internal 8 bit Zoomer without smoothing.
507
508 Zooms 8bit palette/Y 'src' surface to 'dst' surface.
509 Assumes src and dst surfaces are of 8 bit depth.
510 Assumes dst surface was allocated with the correct dimensions.
511
512 \param src The surface to zoom (input).
513 \param dst The zoomed surface (output).
514 \param flipx Flag indicating if the image should be horizontally flipped.
515 \param flipy Flag indicating if the image should be vertically flipped.
516
517 \return 0 for success or -1 for error.
518 */
519 static int _zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy)
520 {
521         int x, y;
522         Uint32 *sax, *say, *csax, *csay;
523         int csx, csy;
524         Uint8 *sp, *dp, *csp;
525         int dgap;
526
527         /*
528         * Allocate memory for row increments 
529         */
530         if ((sax = (Uint32 *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
531                 return (-1);
532         }
533         if ((say = (Uint32 *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
534                 free(sax);
535                 return (-1);
536         }
537
538         /*
539         * Pointer setup 
540         */
541         sp = csp = (Uint8 *) src->pixels;
542         dp = (Uint8 *) dst->pixels;
543         dgap = dst->pitch - dst->w;
544
545         if (flipx) csp += (src->w-1);
546         if (flipy) csp  = ( (Uint8*)csp + src->pitch*(src->h-1) );
547
548         /*
549         * Precalculate row increments 
550         */
551         csx = 0;
552         csax = sax;
553         for (x = 0; x < dst->w; x++) {
554                 csx += src->w;
555                 *csax = 0;
556                 while (csx >= dst->w) {
557                         csx -= dst->w;
558                         (*csax)++;
559                 }
560                 (*csax) = (*csax) * (flipx ? -1 : 1);
561                 csax++;
562         }
563         csy = 0;
564         csay = say;
565         for (y = 0; y < dst->h; y++) {
566                 csy += src->h;
567                 *csay = 0;
568                 while (csy >= dst->h) {
569                         csy -= dst->h;
570                         (*csay)++;
571                 }
572                 (*csay) = (*csay) * (flipy ? -1 : 1);
573                 csay++;
574         }
575
576         /*
577         * Draw 
578         */
579         csay = say;
580         for (y = 0; y < dst->h; y++) {
581                 csax = sax;
582                 sp = csp;
583                 for (x = 0; x < dst->w; x++) {
584                         /*
585                         * Draw 
586                         */
587                         *dp = *sp;
588                         /*
589                         * Advance source pointers 
590                         */
591                         sp += (*csax);
592                         csax++;
593                         /*
594                         * Advance destination pointer 
595                         */
596                         dp++;
597                 }
598                 /*
599                 * Advance source pointer (for row) 
600                 */
601                 csp += ((*csay) * src->pitch);
602                 csay++;
603
604                 /*
605                 * Advance destination pointers 
606                 */
607                 dp += dgap;
608         }
609
610         /*
611         * Remove temp arrays 
612         */
613         free(sax);
614         free(say);
615
616         return (0);
617 }
618
619 /*! 
620 \brief Internal 32 bit rotozoomer with optional anti-aliasing.
621
622 Rotates and zooms 32 bit RGBA/ABGR 'src' surface to 'dst' surface based on the control 
623 parameters by scanning the destination surface and applying optionally anti-aliasing
624 by bilinear interpolation.
625 Assumes src and dst surfaces are of 32 bit depth.
626 Assumes dst surface was allocated with the correct dimensions.
627
628 \param src Source surface.
629 \param dst Destination surface.
630 \param cx Horizontal center coordinate.
631 \param cy Vertical center coordinate.
632 \param isin Integer version of sine of angle.
633 \param icos Integer version of cosine of angle.
634 \param flipx Flag indicating horizontal mirroring should be applied.
635 \param flipy Flag indicating vertical mirroring should be applied.
636 \param smooth Flag indicating anti-aliasing should be used.
637 */
638 static void _transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy, int smooth)
639 {
640         int x, y, t1, t2, dx, dy, xd, yd, sdx, sdy, ax, ay, ex, ey, sw, sh;
641         tColorRGBA c00, c01, c10, c11, cswap;
642         tColorRGBA *pc, *sp;
643         int gap;
644
645         /*
646         * Variable setup 
647         */
648         xd = ((src->w - dst->w) << 15);
649         yd = ((src->h - dst->h) << 15);
650         ax = (cx << 16) - (icos * cx);
651         ay = (cy << 16) - (isin * cx);
652         sw = src->w - 1;
653         sh = src->h - 1;
654         pc = (tColorRGBA*) dst->pixels;
655         gap = dst->pitch - dst->w * 4;
656
657         /*
658         * Switch between interpolating and non-interpolating code 
659         */
660         if (smooth) {
661                 for (y = 0; y < dst->h; y++) {
662                         dy = cy - y;
663                         sdx = (ax + (isin * dy)) + xd;
664                         sdy = (ay - (icos * dy)) + yd;
665                         for (x = 0; x < dst->w; x++) {
666                                 dx = (sdx >> 16);
667                                 dy = (sdy >> 16);
668                                 if (flipx) dx = sw - dx;
669                                 if (flipy) dy = sh - dy;
670                                 if ((dx > -1) && (dy > -1) && (dx < (src->w-1)) && (dy < (src->h-1))) {
671                                         sp = (tColorRGBA *)src->pixels;;
672                                         sp += ((src->pitch/4) * dy);
673                                         sp += dx;
674                                         c00 = *sp;
675                                         sp += 1;
676                                         c01 = *sp;
677                                         sp += (src->pitch/4);
678                                         c11 = *sp;
679                                         sp -= 1;
680                                         c10 = *sp;
681                                         if (flipx) {
682                                                 cswap = c00; c00=c01; c01=cswap;
683                                                 cswap = c10; c10=c11; c11=cswap;
684                                         }
685                                         if (flipy) {
686                                                 cswap = c00; c00=c10; c10=cswap;
687                                                 cswap = c01; c01=c11; c11=cswap;
688                                         }
689                                         /*
690                                         * Interpolate colors 
691                                         */
692                                         ex = (sdx & 0xffff);
693                                         ey = (sdy & 0xffff);
694                                         t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff;
695                                         t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff;
696                                         pc->r = (((t2 - t1) * ey) >> 16) + t1;
697                                         t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff;
698                                         t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff;
699                                         pc->g = (((t2 - t1) * ey) >> 16) + t1;
700                                         t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff;
701                                         t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff;
702                                         pc->b = (((t2 - t1) * ey) >> 16) + t1;
703                                         t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff;
704                                         t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff;
705                                         pc->a = (((t2 - t1) * ey) >> 16) + t1;
706                                 }
707                                 sdx += icos;
708                                 sdy += isin;
709                                 pc++;
710                         }
711                         pc = (tColorRGBA *) ((Uint8 *) pc + gap);
712                 }
713         } else {
714                 for (y = 0; y < dst->h; y++) {
715                         dy = cy - y;
716                         sdx = (ax + (isin * dy)) + xd;
717                         sdy = (ay - (icos * dy)) + yd;
718                         for (x = 0; x < dst->w; x++) {
719                                 dx = (short) (sdx >> 16);
720                                 dy = (short) (sdy >> 16);
721                                 if (flipx) dx = (src->w-1)-dx;
722                                 if (flipy) dy = (src->h-1)-dy;
723                                 if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
724                                         sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
725                                         sp += dx;
726                                         *pc = *sp;
727                                 }
728                                 sdx += icos;
729                                 sdy += isin;
730                                 pc++;
731                         }
732                         pc = (tColorRGBA *) ((Uint8 *) pc + gap);
733                 }
734         }
735 }
736
737 /*!
738
739 \brief Rotates and zooms 8 bit palette/Y 'src' surface to 'dst' surface without smoothing.
740
741 Rotates and zooms 8 bit RGBA/ABGR 'src' surface to 'dst' surface based on the control 
742 parameters by scanning the destination surface.
743 Assumes src and dst surfaces are of 8 bit depth.
744 Assumes dst surface was allocated with the correct dimensions.
745
746 \param src Source surface.
747 \param dst Destination surface.
748 \param cx Horizontal center coordinate.
749 \param cy Vertical center coordinate.
750 \param isin Integer version of sine of angle.
751 \param icos Integer version of cosine of angle.
752 \param flipx Flag indicating horizontal mirroring should be applied.
753 \param flipy Flag indicating vertical mirroring should be applied.
754 */
755 static void transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy)
756 {
757         int x, y, dx, dy, xd, yd, sdx, sdy, ax, ay, sw, sh;
758         tColorY *pc, *sp;
759         int gap;
760
761         /*
762         * Variable setup 
763         */
764         xd = ((src->w - dst->w) << 15);
765         yd = ((src->h - dst->h) << 15);
766         ax = (cx << 16) - (icos * cx);
767         ay = (cy << 16) - (isin * cx);
768         sw = src->w - 1;
769         sh = src->h - 1;
770         pc = (tColorY*) dst->pixels;
771         gap = dst->pitch - dst->w;
772         /*
773         * Clear surface to colorkey 
774         */      
775         memset(pc, (int)(_colorkey(src) & 0xff), dst->pitch * dst->h);
776         /*
777         * Iterate through destination surface 
778         */
779         for (y = 0; y < dst->h; y++) {
780                 dy = cy - y;
781                 sdx = (ax + (isin * dy)) + xd;
782                 sdy = (ay - (icos * dy)) + yd;
783                 for (x = 0; x < dst->w; x++) {
784                         dx = (short) (sdx >> 16);
785                         dy = (short) (sdy >> 16);
786                         if (flipx) dx = (src->w-1)-dx;
787                         if (flipy) dy = (src->h-1)-dy;
788                         if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
789                                 sp = (tColorY *) (src->pixels);
790                                 sp += (src->pitch * dy + dx);
791                                 *pc = *sp;
792                         }
793                         sdx += icos;
794                         sdy += isin;
795                         pc++;
796                 }
797                 pc += gap;
798         }
799 }
800
801 /*!
802 \brief Rotates a 32 bit surface in increments of 90 degrees.
803
804 Specialized 90 degree rotator which rotates a 'src' surface in 90 degree 
805 increments clockwise returning a new surface. Faster than rotozoomer since
806 not scanning or interpolation takes place. Input surface must be 32 bit.
807 (code contributed by J. Schiller, improved by C. Allport and A. Schiffler)
808
809 \param src Source surface to rotate.
810 \param numClockwiseTurns Number of clockwise 90 degree turns to apply to the source.
811
812 \returns The new, rotated surface; or NULL for surfaces with incorrect input format.
813 */
814 SDL_Surface* rotateSurface90Degrees(SDL_Surface* src, int numClockwiseTurns) 
815 {
816         int row, col, newWidth, newHeight;
817         int bpp, src_ipr, dst_ipr;
818         SDL_Surface* dst;
819         Uint32* srcBuf;
820         Uint32* dstBuf;
821
822         /* Has to be a valid surface pointer and only 32-bit surfaces (for now) */
823         if (!src || src->format->BitsPerPixel != 32) { return NULL; }
824
825         /* normalize numClockwiseTurns */
826         while(numClockwiseTurns < 0) { numClockwiseTurns += 4; }
827         numClockwiseTurns = (numClockwiseTurns % 4);
828
829         /* if it's even, our new width will be the same as the source surface */
830         newWidth = (numClockwiseTurns % 2) ? (src->h) : (src->w);
831         newHeight = (numClockwiseTurns % 2) ? (src->w) : (src->h);
832         dst = SDL_CreateRGBSurface( src->flags, newWidth, newHeight, src->format->BitsPerPixel,
833                 src->format->Rmask,
834                 src->format->Gmask, 
835                 src->format->Bmask, 
836                 src->format->Amask);
837         if(!dst) {
838                 return NULL;
839         }
840
841         if (SDL_MUSTLOCK(dst)) {
842                 SDL_LockSurface(dst);
843         }
844         if (SDL_MUSTLOCK(dst)) {
845                 SDL_LockSurface(dst);
846         }
847
848         /* Calculate int-per-row */
849         bpp = src->format->BitsPerPixel / 8;
850         src_ipr = src->pitch / bpp;
851         dst_ipr = dst->pitch / bpp;
852
853         switch(numClockwiseTurns) {
854         case 0: /* Make a copy of the surface */
855                 {
856                         /* Unfortunately SDL_BlitSurface cannot be used to make a copy of the surface
857                         since it does not preserve alpha. */
858
859                         if (src->pitch == dst->pitch) {
860                                 /* If the pitch is the same for both surfaces, the memory can be copied all at once. */
861                                 memcpy(dst->pixels, src->pixels, (src->h * src->pitch));
862                         }
863                         else
864                         {
865                                 /* If the pitch differs, copy each row separately */
866                                 srcBuf = (Uint32*)(src->pixels); 
867                                 dstBuf = (Uint32*)(dst->pixels);
868                                 for (row = 0; row < src->h; row++) {
869                                         memcpy(dstBuf, srcBuf, dst->w * bpp);
870                                         srcBuf += src_ipr;
871                                         dstBuf += dst_ipr;
872                                 } /* end for(col) */
873                         } /* end for(row) */
874                 }
875                 break;
876
877                 /* rotate clockwise */
878         case 1: /* rotated 90 degrees clockwise */
879                 {
880                         for (row = 0; row < src->h; ++row) {
881                                 srcBuf = (Uint32*)(src->pixels) + (row * src_ipr);
882                                 dstBuf = (Uint32*)(dst->pixels) + (dst->w - row - 1);
883                                 for (col = 0; col < src->w; ++col) {
884                                         *dstBuf = *srcBuf;
885                                         ++srcBuf;
886                                         dstBuf += dst_ipr;
887                                 } 
888                                 /* end for(col) */
889                         } 
890                         /* end for(row) */
891                 }
892                 break;
893
894         case 2: /* rotated 180 degrees clockwise */
895                 {
896                         for (row = 0; row < src->h; ++row) {
897                                 srcBuf = (Uint32*)(src->pixels) + (row * src_ipr);
898                                 dstBuf = (Uint32*)(dst->pixels) + ((dst->h - row - 1) * dst_ipr) + (dst->w - 1);
899                                 for (col = 0; col < src->w; ++col) {
900                                         *dstBuf = *srcBuf;
901                                         ++srcBuf;
902                                         --dstBuf;
903                                 } 
904                         } 
905                 }
906                 break;
907
908         case 3:
909                 {
910                         for (row = 0; row < src->h; ++row) {
911                                 srcBuf = (Uint32*)(src->pixels) + (row * src_ipr);
912                                 dstBuf = (Uint32*)(dst->pixels) + row + ((dst->h - 1) * dst_ipr);
913                                 for (col = 0; col < src->w; ++col) {
914                                         *dstBuf = *srcBuf;
915                                         ++srcBuf;
916                                         dstBuf -= dst_ipr;
917                                 } 
918                         } 
919                 }
920                 break;
921         } 
922         /* end switch */
923
924         if (SDL_MUSTLOCK(src)) {
925                 SDL_UnlockSurface(src);
926         }
927         if (SDL_MUSTLOCK(dst)) {
928                 SDL_UnlockSurface(dst);
929         }
930
931         return dst;
932 }
933
934
935 /*!
936 \brief Internal target surface sizing function for rotozooms with trig result return. 
937
938 \param width The source surface width.
939 \param height The source surface height.
940 \param angle The angle to rotate in degrees.
941 \param zoomx The horizontal scaling factor.
942 \param zoomy The vertical scaling factor.
943 \param dstwidth The calculated width of the destination surface.
944 \param dstheight The calculated height of the destination surface.
945 \param canglezoom The sine of the angle adjusted by the zoom factor.
946 \param sanglezoom The cosine of the angle adjusted by the zoom factor.
947
948 */
949 static void _rotozoomSurfaceSizeTrig(int width, int height, double angle, double zoomx, double zoomy, 
950         int *dstwidth, int *dstheight, 
951         double *canglezoom, double *sanglezoom)
952 {
953         double x, y, cx, cy, sx, sy;
954         double radangle;
955         int dstwidthhalf, dstheighthalf;
956
957         /*
958         * Determine destination width and height by rotating a centered source box 
959         */
960         radangle = angle * (M_PI / 180.0);
961         *sanglezoom = sin(radangle);
962         *canglezoom = cos(radangle);
963         *sanglezoom *= zoomx;
964         *canglezoom *= zoomx;
965         x = (double)(width / 2);
966         y = (double)(height / 2);
967         cx = *canglezoom * x;
968         cy = *canglezoom * y;
969         sx = *sanglezoom * x;
970         sy = *sanglezoom * y;
971
972         dstwidthhalf = MAX((int)
973                 ceil(MAX(MAX(MAX(fabs(cx + sy), fabs(cx - sy)), fabs(-cx + sy)), fabs(-cx - sy))), 1);
974         dstheighthalf = MAX((int)
975                 ceil(MAX(MAX(MAX(fabs(sx + cy), fabs(sx - cy)), fabs(-sx + cy)), fabs(-sx - cy))), 1);
976         *dstwidth = 2 * dstwidthhalf;
977         *dstheight = 2 * dstheighthalf;
978 }
979
980 /*! 
981 \brief Returns the size of the resulting target surface for a rotozoomSurfaceXY() call. 
982
983 \param width The source surface width.
984 \param height The source surface height.
985 \param angle The angle to rotate in degrees.
986 \param zoomx The horizontal scaling factor.
987 \param zoomy The vertical scaling factor.
988 \param dstwidth The calculated width of the rotozoomed destination surface.
989 \param dstheight The calculated height of the rotozoomed destination surface.
990 */
991 void rotozoomSurfaceSizeXY(int width, int height, double angle, double zoomx, double zoomy, int *dstwidth, int *dstheight)
992 {
993         double dummy_sanglezoom, dummy_canglezoom;
994
995         _rotozoomSurfaceSizeTrig(width, height, angle, zoomx, zoomy, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
996 }
997
998 /*! 
999 \brief Returns the size of the resulting target surface for a rotozoomSurface() call. 
1000
1001 \param width The source surface width.
1002 \param height The source surface height.
1003 \param angle The angle to rotate in degrees.
1004 \param zoom The scaling factor.
1005 \param dstwidth The calculated width of the rotozoomed destination surface.
1006 \param dstheight The calculated height of the rotozoomed destination surface.
1007 */
1008 void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth, int *dstheight)
1009 {
1010         double dummy_sanglezoom, dummy_canglezoom;
1011
1012         _rotozoomSurfaceSizeTrig(width, height, angle, zoom, zoom, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
1013 }
1014
1015 /*!
1016 \brief Rotates and zooms a surface and optional anti-aliasing. 
1017
1018 Rotates and zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1019 'angle' is the rotation in degrees and 'zoom' a scaling factor. If 'smooth' is set
1020 then the destination 32bit surface is anti-aliased. If the surface is not 8bit
1021 or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
1022
1023 \param src The surface to rotozoom.
1024 \param angle The angle to rotate in degrees.
1025 \param zoom The scaling factor.
1026 \param smooth Antialiasing flag; set to SMOOTHING_ON to enable.
1027
1028 \return The new rotozoomed surface.
1029 */
1030 SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth)
1031 {
1032         return rotozoomSurfaceXY(src, angle, zoom, zoom, smooth);
1033 }
1034
1035 /*!
1036 \brief Rotates and zooms a surface with different horizontal and vertival scaling factors and optional anti-aliasing. 
1037
1038 Rotates and zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1039 'angle' is the rotation in degrees, 'zoomx and 'zoomy' scaling factors. If 'smooth' is set
1040 then the destination 32bit surface is anti-aliased. If the surface is not 8bit
1041 or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
1042
1043 \param src The surface to rotozoom.
1044 \param angle The angle to rotate in degrees.
1045 \param zoomx The horizontal scaling factor.
1046 \param zoomy The vertical scaling factor.
1047 \param smooth Antialiasing flag; set to SMOOTHING_ON to enable.
1048
1049 \return The new rotozoomed surface.
1050 */
1051 SDL_Surface *rotozoomSurfaceXY(SDL_Surface * src, double angle, double zoomx, double zoomy, int smooth)
1052 {
1053         SDL_Surface *rz_src;
1054         SDL_Surface *rz_dst;
1055         double zoominv;
1056         double sanglezoom, canglezoom, sanglezoominv, canglezoominv;
1057         int dstwidthhalf, dstwidth, dstheighthalf, dstheight;
1058         int is32bit;
1059         int i, src_converted;
1060         int flipx,flipy;
1061         Uint8 r,g,b;
1062         Uint32 colorkey = 0;
1063         int colorKeyAvailable = 0;
1064
1065         /*
1066         * Sanity check 
1067         */
1068         if (src == NULL)
1069                 return (NULL);
1070
1071         if (src->flags & SDL_SRCCOLORKEY)
1072         {
1073                 colorkey = _colorkey(src);
1074                 SDL_GetRGB(colorkey, src->format, &r, &g, &b);
1075                 colorKeyAvailable = 1;
1076         }
1077         /*
1078         * Determine if source surface is 32bit or 8bit 
1079         */
1080         is32bit = (src->format->BitsPerPixel == 32);
1081         if ((is32bit) || (src->format->BitsPerPixel == 8)) {
1082                 /*
1083                 * Use source surface 'as is' 
1084                 */
1085                 rz_src = src;
1086                 src_converted = 0;
1087         } else {
1088                 /*
1089                 * New source surface is 32bit with a defined RGBA ordering 
1090                 */
1091                 rz_src =
1092                         SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, 
1093 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
1094                         0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
1095 #else
1096                         0xff000000,  0x00ff0000, 0x0000ff00, 0x000000ff
1097 #endif
1098                         );
1099                 if(colorKeyAvailable)
1100                         SDL_SetColorKey(src, 0, 0);
1101
1102                 SDL_BlitSurface(src, NULL, rz_src, NULL);
1103
1104                 if(colorKeyAvailable)
1105                         SDL_SetColorKey(src, SDL_SRCCOLORKEY, colorkey);
1106                 src_converted = 1;
1107                 is32bit = 1;
1108         }
1109
1110         /*
1111         * Sanity check zoom factor 
1112         */
1113         flipx = (zoomx<0.0);
1114         if (flipx) zoomx=-zoomx;
1115         flipy = (zoomy<0.0);
1116         if (flipy) zoomy=-zoomy;
1117         if (zoomx < VALUE_LIMIT) zoomx = VALUE_LIMIT;
1118         if (zoomy < VALUE_LIMIT) zoomy = VALUE_LIMIT;
1119         zoominv = 65536.0 / (zoomx * zoomx);
1120
1121         /*
1122         * Check if we have a rotozoom or just a zoom 
1123         */
1124         if (fabs(angle) > VALUE_LIMIT) {
1125
1126                 /*
1127                 * Angle!=0: full rotozoom 
1128                 */
1129                 /*
1130                 * ----------------------- 
1131                 */
1132
1133                 /* Determine target size */
1134                 _rotozoomSurfaceSizeTrig(rz_src->w, rz_src->h, angle, zoomx, zoomy, &dstwidth, &dstheight, &canglezoom, &sanglezoom);
1135
1136                 /*
1137                 * Calculate target factors from sin/cos and zoom 
1138                 */
1139                 sanglezoominv = sanglezoom;
1140                 canglezoominv = canglezoom;
1141                 sanglezoominv *= zoominv;
1142                 canglezoominv *= zoominv;
1143
1144                 /* Calculate half size */
1145                 dstwidthhalf = dstwidth / 2;
1146                 dstheighthalf = dstheight / 2;
1147
1148                 /*
1149                 * Alloc space to completely contain the rotated surface 
1150                 */
1151                 rz_dst = NULL;
1152                 if (is32bit) {
1153                         /*
1154                         * Target surface is 32bit with source RGBA/ABGR ordering 
1155                         */
1156                         rz_dst =
1157                                 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
1158                                 rz_src->format->Rmask, rz_src->format->Gmask,
1159                                 rz_src->format->Bmask, rz_src->format->Amask);
1160                 } else {
1161                         /*
1162                         * Target surface is 8bit 
1163                         */
1164                         rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
1165                 }
1166
1167                 /* Check target */
1168                 if (rz_dst == NULL)
1169                         return NULL;
1170
1171                 /* Adjust for guard rows */
1172                 rz_dst->h = dstheight;
1173
1174                 if (colorKeyAvailable == 1){
1175                         colorkey = SDL_MapRGB(rz_dst->format, r, g, b);
1176
1177                         SDL_FillRect(rz_dst, NULL, colorkey );
1178                 }
1179
1180                 /*
1181                 * Lock source surface 
1182                 */
1183                 if (SDL_MUSTLOCK(rz_src)) {
1184                         SDL_LockSurface(rz_src);
1185                 }
1186
1187                 /*
1188                 * Check which kind of surface we have 
1189                 */
1190                 if (is32bit) {
1191                         /*
1192                         * Call the 32bit transformation routine to do the rotation (using alpha) 
1193                         */
1194                         _transformSurfaceRGBA(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
1195                                 (int) (sanglezoominv), (int) (canglezoominv), 
1196                                 flipx, flipy,
1197                                 smooth);
1198                         /*
1199                         * Turn on source-alpha support 
1200                         */
1201                         SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1202                         SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
1203                 } else {
1204                         /*
1205                         * Copy palette and colorkey info 
1206                         */
1207                         for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1208                                 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1209                         }
1210                         rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1211                         /*
1212                         * Call the 8bit transformation routine to do the rotation 
1213                         */
1214                         transformSurfaceY(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
1215                                 (int) (sanglezoominv), (int) (canglezoominv),
1216                                 flipx, flipy);
1217                         SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
1218                 }
1219                 /*
1220                 * Unlock source surface 
1221                 */
1222                 if (SDL_MUSTLOCK(rz_src)) {
1223                         SDL_UnlockSurface(rz_src);
1224                 }
1225
1226         } else {
1227
1228                 /*
1229                 * Angle=0: Just a zoom 
1230                 */
1231                 /*
1232                 * -------------------- 
1233                 */
1234
1235                 /*
1236                 * Calculate target size
1237                 */
1238                 zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
1239
1240                 /*
1241                 * Alloc space to completely contain the zoomed surface 
1242                 */
1243                 rz_dst = NULL;
1244                 if (is32bit) {
1245                         /*
1246                         * Target surface is 32bit with source RGBA/ABGR ordering 
1247                         */
1248                         rz_dst =
1249                                 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
1250                                 rz_src->format->Rmask, rz_src->format->Gmask,
1251                                 rz_src->format->Bmask, rz_src->format->Amask);
1252                 } else {
1253                         /*
1254                         * Target surface is 8bit 
1255                         */
1256                         rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
1257                 }
1258
1259                 /* Check target */
1260                 if (rz_dst == NULL)
1261                         return NULL;
1262
1263                 /* Adjust for guard rows */
1264                 rz_dst->h = dstheight;
1265
1266                 if (colorKeyAvailable == 1){
1267                         colorkey = SDL_MapRGB(rz_dst->format, r, g, b);
1268
1269                         SDL_FillRect(rz_dst, NULL, colorkey );
1270                 }
1271
1272                 /*
1273                 * Lock source surface 
1274                 */
1275                 if (SDL_MUSTLOCK(rz_src)) {
1276                         SDL_LockSurface(rz_src);
1277                 }
1278
1279                 /*
1280                 * Check which kind of surface we have 
1281                 */
1282                 if (is32bit) {
1283                         /*
1284                         * Call the 32bit transformation routine to do the zooming (using alpha) 
1285                         */
1286                         _zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
1287
1288                         /*
1289                         * Turn on source-alpha support 
1290                         */
1291                         SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1292                         SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
1293                 } else {
1294                         /*
1295                         * Copy palette and colorkey info 
1296                         */
1297                         for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1298                                 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1299                         }
1300                         rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1301
1302                         /*
1303                         * Call the 8bit transformation routine to do the zooming 
1304                         */
1305                         _zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
1306                         SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
1307                 }
1308
1309                 /*
1310                 * Unlock source surface 
1311                 */
1312                 if (SDL_MUSTLOCK(rz_src)) {
1313                         SDL_UnlockSurface(rz_src);
1314                 }
1315         }
1316
1317         /*
1318         * Cleanup temp surface 
1319         */
1320         if (src_converted) {
1321                 SDL_FreeSurface(rz_src);
1322         }
1323
1324         /*
1325         * Return destination surface 
1326         */
1327         return (rz_dst);
1328 }
1329
1330 /*!
1331 \brief Calculates the size of the target surface for a zoomSurface() call.
1332
1333 The minimum size of the target surface is 1. The input factors can be positive or negative.
1334
1335 \param width The width of the source surface to zoom.
1336 \param height The height of the source surface to zoom.
1337 \param zoomx The horizontal zoom factor.
1338 \param zoomy The vertical zoom factor.
1339 \param dstwidth Pointer to an integer to store the calculated width of the zoomed target surface.
1340 \param dstheight Pointer to an integer to store the calculated height of the zoomed target surface.
1341 */
1342 void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight)
1343 {
1344         /*
1345         * Make zoom factors positive 
1346         */
1347         int flipx, flipy;
1348         flipx = (zoomx<0.0);
1349         if (flipx) zoomx = -zoomx;
1350         flipy = (zoomy<0.0);
1351         if (flipy) zoomy = -zoomy;
1352
1353         /*
1354         * Sanity check zoom factors 
1355         */
1356         if (zoomx < VALUE_LIMIT) {
1357                 zoomx = VALUE_LIMIT;
1358         }
1359         if (zoomy < VALUE_LIMIT) {
1360                 zoomy = VALUE_LIMIT;
1361         }
1362
1363         /*
1364         * Calculate target size 
1365         */
1366         *dstwidth = (int) floor(((double) width * zoomx) + 0.5);
1367         *dstheight = (int) floor(((double) height * zoomy) + 0.5);
1368         if (*dstwidth < 1) {
1369                 *dstwidth = 1;
1370         }
1371         if (*dstheight < 1) {
1372                 *dstheight = 1;
1373         }
1374 }
1375
1376 /*! 
1377 \brief Zoom a surface by independent horizontal and vertical factors with optional smoothing.
1378
1379 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1380 'zoomx' and 'zoomy' are scaling factors for width and height. If 'smooth' is on
1381 then the destination 32bit surface is anti-aliased. If the surface is not 8bit
1382 or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
1383 If zoom factors are negative, the image is flipped on the axes.
1384
1385 \param src The surface to zoom.
1386 \param zoomx The horizontal zoom factor.
1387 \param zoomy The vertical zoom factor.
1388 \param smooth Antialiasing flag; set to SMOOTHING_ON to enable.
1389
1390 \return The new, zoomed surface.
1391 */
1392 SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth)
1393 {
1394         SDL_Surface *rz_src;
1395         SDL_Surface *rz_dst;
1396         int dstwidth, dstheight;
1397         int is32bit;
1398         int i, src_converted;
1399         int flipx, flipy;
1400
1401         /*
1402         * Sanity check 
1403         */
1404         if (src == NULL)
1405                 return (NULL);
1406
1407         /*
1408         * Determine if source surface is 32bit or 8bit 
1409         */
1410         is32bit = (src->format->BitsPerPixel == 32);
1411         if ((is32bit) || (src->format->BitsPerPixel == 8)) {
1412                 /*
1413                 * Use source surface 'as is' 
1414                 */
1415                 rz_src = src;
1416                 src_converted = 0;
1417         } else {
1418                 /*
1419                 * New source surface is 32bit with a defined RGBA ordering 
1420                 */
1421                 rz_src =
1422                         SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, 
1423 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
1424                         0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
1425 #else
1426                         0xff000000,  0x00ff0000, 0x0000ff00, 0x000000ff
1427 #endif
1428                         );
1429                 if (rz_src == NULL) {
1430                         return NULL;
1431                 }
1432                 SDL_BlitSurface(src, NULL, rz_src, NULL);
1433                 src_converted = 1;
1434                 is32bit = 1;
1435         }
1436
1437         flipx = (zoomx<0.0);
1438         if (flipx) zoomx = -zoomx;
1439         flipy = (zoomy<0.0);
1440         if (flipy) zoomy = -zoomy;
1441
1442         /* Get size if target */
1443         zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
1444
1445         /*
1446         * Alloc space to completely contain the zoomed surface 
1447         */
1448         rz_dst = NULL;
1449         if (is32bit) {
1450                 /*
1451                 * Target surface is 32bit with source RGBA/ABGR ordering 
1452                 */
1453                 rz_dst =
1454                         SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
1455                         rz_src->format->Rmask, rz_src->format->Gmask,
1456                         rz_src->format->Bmask, rz_src->format->Amask);
1457         } else {
1458                 /*
1459                 * Target surface is 8bit 
1460                 */
1461                 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
1462         }
1463
1464         /* Check target */
1465         if (rz_dst == NULL) {
1466                 /*
1467                 * Cleanup temp surface 
1468                 */
1469                 if (src_converted) {
1470                         SDL_FreeSurface(rz_src);
1471                 }               
1472                 return NULL;
1473         }
1474
1475         /* Adjust for guard rows */
1476         rz_dst->h = dstheight;
1477
1478         /*
1479         * Lock source surface 
1480         */
1481         if (SDL_MUSTLOCK(rz_src)) {
1482                 SDL_LockSurface(rz_src);
1483         }
1484
1485         /*
1486         * Check which kind of surface we have 
1487         */
1488         if (is32bit) {
1489                 /*
1490                 * Call the 32bit transformation routine to do the zooming (using alpha) 
1491                 */
1492                 _zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
1493                 /*
1494                 * Turn on source-alpha support 
1495                 */
1496                 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1497         } else {
1498                 /*
1499                 * Copy palette and colorkey info 
1500                 */
1501                 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1502                         rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1503                 }
1504                 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1505                 /*
1506                 * Call the 8bit transformation routine to do the zooming 
1507                 */
1508                 _zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
1509                 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
1510         }
1511         /*
1512         * Unlock source surface 
1513         */
1514         if (SDL_MUSTLOCK(rz_src)) {
1515                 SDL_UnlockSurface(rz_src);
1516         }
1517
1518         /*
1519         * Cleanup temp surface 
1520         */
1521         if (src_converted) {
1522                 SDL_FreeSurface(rz_src);
1523         }
1524
1525         /*
1526         * Return destination surface 
1527         */
1528         return (rz_dst);
1529 }
1530
1531 /*! 
1532 \brief Shrink a surface by an integer ratio using averaging.
1533
1534 Shrinks a 32bit or 8bit 'src' surface to a newly created 'dst' surface.
1535 'factorx' and 'factory' are the shrinking ratios (i.e. 2=1/2 the size,
1536 3=1/3 the size, etc.) The destination surface is antialiased by averaging
1537 the source box RGBA or Y information. If the surface is not 8bit
1538 or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
1539 The input surface is not modified. The output surface is newly allocated.
1540
1541 \param src The surface to shrink.
1542 \param factorx The horizontal shrinking ratio.
1543 \param factory The vertical shrinking ratio.
1544
1545 \return The new, shrunken surface.
1546 */
1547 /*@null@*/ 
1548 SDL_Surface *shrinkSurface(SDL_Surface *src, int factorx, int factory)
1549 {
1550         int result;
1551         SDL_Surface *rz_src;
1552         SDL_Surface *rz_dst = NULL;
1553         int dstwidth, dstheight;
1554         int is32bit;
1555         int i, src_converted;
1556         int haveError = 0;
1557
1558         /*
1559         * Sanity check 
1560         */
1561         if (src == NULL) {
1562                 return (NULL);
1563         }
1564
1565         /*
1566         * Determine if source surface is 32bit or 8bit 
1567         */
1568         is32bit = (src->format->BitsPerPixel == 32);
1569         if ((is32bit) || (src->format->BitsPerPixel == 8)) {
1570                 /*
1571                 * Use source surface 'as is' 
1572                 */
1573                 rz_src = src;
1574                 src_converted = 0;
1575         } else {
1576                 /*
1577                 * New source surface is 32bit with a defined RGBA ordering 
1578                 */
1579                 rz_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, 
1580 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
1581                         0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
1582 #else
1583                         0xff000000,  0x00ff0000, 0x0000ff00, 0x000000ff
1584 #endif
1585                         );
1586                 if (rz_src==NULL) {
1587                         haveError = 1;
1588                         goto exitShrinkSurface;
1589                 }
1590
1591                 SDL_BlitSurface(src, NULL, rz_src, NULL);
1592                 src_converted = 1;
1593                 is32bit = 1;
1594         }
1595
1596         /*
1597         * Lock the surface 
1598         */
1599         if (SDL_MUSTLOCK(rz_src)) {
1600                 if (SDL_LockSurface(rz_src) < 0) {
1601                         haveError = 1;
1602                         goto exitShrinkSurface;
1603                 }
1604         }
1605
1606         /* Get size for target */
1607         dstwidth=rz_src->w/factorx;
1608         while (dstwidth*factorx>rz_src->w) { dstwidth--; }
1609         dstheight=rz_src->h/factory;
1610         while (dstheight*factory>rz_src->h) { dstheight--; }
1611
1612         /*
1613         * Alloc space to completely contain the shrunken surface
1614         * (with added guard rows)
1615         */
1616         if (is32bit==1) {
1617                 /*
1618                 * Target surface is 32bit with source RGBA/ABGR ordering 
1619                 */
1620                 rz_dst =
1621                         SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
1622                         rz_src->format->Rmask, rz_src->format->Gmask,
1623                         rz_src->format->Bmask, rz_src->format->Amask);
1624         } else {
1625                 /*
1626                 * Target surface is 8bit 
1627                 */
1628                 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
1629         }
1630
1631         /* Check target */
1632         if (rz_dst == NULL) {
1633                 haveError = 1;
1634                 goto exitShrinkSurface;
1635         }
1636
1637         /* Adjust for guard rows */
1638         rz_dst->h = dstheight;
1639
1640         /*
1641         * Check which kind of surface we have 
1642         */
1643         if (is32bit==1) {
1644                 /*
1645                 * Call the 32bit transformation routine to do the shrinking (using alpha) 
1646                 */
1647                 result = _shrinkSurfaceRGBA(rz_src, rz_dst, factorx, factory);          
1648                 if ((result!=0) || (rz_dst==NULL)) {
1649                         haveError = 1;
1650                         goto exitShrinkSurface;
1651                 }
1652
1653                 /*
1654                 * Turn on source-alpha support 
1655                 */
1656                 result = SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1657                 if (result!=0) {
1658                         haveError = 1;
1659                         goto exitShrinkSurface;
1660                 }
1661         } else {
1662                 /*
1663                 * Copy palette and colorkey info 
1664                 */
1665                 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1666                         rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1667                 }
1668                 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1669                 /*
1670                 * Call the 8bit transformation routine to do the shrinking 
1671                 */
1672                 result = _shrinkSurfaceY(rz_src, rz_dst, factorx, factory);
1673                 if (result!=0) {
1674                         haveError = 1;
1675                         goto exitShrinkSurface;
1676                 }
1677
1678                 /*
1679                 * Set colorkey on target
1680                 */
1681                 result = SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
1682                 if (result!=0) {
1683                         haveError = 1;
1684                         goto exitShrinkSurface;
1685                 }               
1686         }
1687
1688 exitShrinkSurface:
1689         if (rz_src!=NULL) {
1690                 /*
1691                 * Unlock source surface 
1692                 */
1693                 if (SDL_MUSTLOCK(rz_src)) {
1694                         SDL_UnlockSurface(rz_src);
1695                 }
1696
1697                 /*
1698                 * Cleanup temp surface 
1699                 */
1700                 if (src_converted==1) {
1701                         SDL_FreeSurface(rz_src);
1702                 }
1703         }
1704
1705         /* Check error state; maybe need to cleanup destination */
1706         if (haveError==1) {
1707                 if (rz_dst!=NULL) {
1708                         SDL_FreeSurface(rz_dst);
1709                 }
1710                 rz_dst=NULL;
1711         } 
1712
1713         /*
1714         * Return destination surface 
1715         */
1716         return (rz_dst);
1717 }