1 /* SDL_rotozoom.c
2 
3 
4    The SDL_rotozoom sources were copied from the SDL_gfx library and
5    are relicensed, only for the purposes of TuxMath, to GPL.  Original
6    license was GNU Lesser Public License, Version 2 (or later).
7    Thanks to Andreas Schiffler.
8 
9    SDL_gfx website: http://www.ferzkopp.net/Software/SDL_gfx-2.0/
10 
11    Slight modification and relicensing for tuxmath:
12    Copyright (C) 2008, 2009, 2010.
13 Authors: David Bruce, Tim Holy, Brendan Luchen.
14 email: <tuxmath-devel@lists.sourceforge.net>
15 
16 
17 
18 SDL_rotozoom.c is part of "Tux, of Math Command", a.k.a. "tuxmath".
19 
20 Tuxmath is free software: you can redistribute it and/or modify
21 it under the terms of the GNU General Public License as published by
22 the Free Software Foundation; either version 3 of the License, or
23 (at your option) any later version.
24 
25 Tuxmath is distributed in the hope that it will be useful,
26 but WITHOUT ANY WARRANTY; without even the implied warranty of
27 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28 GNU General Public License for more details.
29 
30 You should have received a copy of the GNU General Public License
31 along with this program.  If not, see <http://www.gnu.org/licenses/>.
32 */
33 
34 
35 
36 #ifdef WIN32
37 #include <windows.h>
38 #endif
39 
40 #include <stdlib.h>
41 #include <string.h>
42 
43 #include "SDL_rotozoom.h"
44 
45 #define MAX(a,b)    (((a) > (b)) ? (a) : (b))
46 
47 
48 /*
49 
50    32bit integer-factor averaging Shrinker
51 
52    Shrinks 32bit RGBA/ABGR 'src' surface to 'dst' surface.
53 
54 */
55 
shrinkSurfaceRGBA(SDL_Surface * src,SDL_Surface * dst,int factorx,int factory)56 int shrinkSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
57 {
58     int x, y, dx, dy, sgap, dgap, ra, ga, ba, aa;
59     int n_average;
60     tColorRGBA *sp, *osp, *oosp;
61     tColorRGBA *dp;
62 
63     /*
64      * Averaging integer shrink
65      */
66 
67     /* Precalculate division factor */
68     n_average = factorx*factory;
69 
70     /*
71      * Scan destination
72      */
73     sp = (tColorRGBA *) src->pixels;
74     sgap = src->pitch - src->w * 4;
75 
76     dp = (tColorRGBA *) dst->pixels;
77     dgap = dst->pitch - dst->w * 4;
78 
79     for (y = 0; y < dst->h; y++) {
80 
81 	osp=sp;
82 	for (x = 0; x < dst->w; x++) {
83 
84 	    /* Trace out source box and accumulate */
85 	    oosp=sp;
86 	    ra=ga=ba=aa=0;
87 	    for (dy=0; dy < factory; dy++) {
88 		for (dx=0; dx < factorx; dx++) {
89 		    ra += sp->r;
90 		    ga += sp->g;
91 		    ba += sp->b;
92 		    aa += sp->a;
93 
94 		    sp++;
95 		} // src dx loop
96 		sp = (tColorRGBA *)((Uint8*)sp + (src->pitch - 4*factorx)); // next y
97 	    } // src dy loop
98 
99 	    // next box-x
100 	    sp = (tColorRGBA *)((Uint8*)oosp + 4*factorx);
101 
102 	    /* Store result in destination */
103 	    dp->r = ra/n_average;
104 	    dp->g = ga/n_average;
105 	    dp->b = ba/n_average;
106 	    dp->a = aa/n_average;
107 
108 	    /*
109 	     * Advance destination pointer
110 	     */
111 	    dp++;
112 	} // dst x loop
113 
114 	// next box-y
115 	sp = (tColorRGBA *)((Uint8*)osp + src->pitch*factory);
116 
117 	/*
118 	 * Advance destination pointers
119 	 */
120 	dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
121     } // dst y loop
122 
123     return (0);
124 }
125 
126 /*
127 
128    8bit integer-factor averaging Shrinker
129 
130    Shrinks 8bit Y 'src' surface to 'dst' surface.
131 
132 */
133 
shrinkSurfaceY(SDL_Surface * src,SDL_Surface * dst,int factorx,int factory)134 int shrinkSurfaceY(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
135 {
136     int x, y, dx, dy, sgap, dgap, a;
137     int n_average;
138     Uint8 *sp, *osp, *oosp;
139     Uint8 *dp;
140 
141     /*
142      * Averaging integer shrink
143      */
144 
145     /* Precalculate division factor */
146     n_average = factorx*factory;
147 
148     /*
149      * Scan destination
150      */
151     sp = (Uint8 *) src->pixels;
152     sgap = src->pitch - src->w;
153 
154     dp = (Uint8 *) dst->pixels;
155     dgap = dst->pitch - dst->w;
156 
157     for (y = 0; y < dst->h; y++) {
158 
159 	osp=sp;
160 	for (x = 0; x < dst->w; x++) {
161 
162 	    /* Trace out source box and accumulate */
163 	    oosp=sp;
164 	    a=0;
165 	    for (dy=0; dy < factory; dy++) {
166 		for (dx=0; dx < factorx; dx++) {
167 		    a += (*sp);
168 		    sp++; // next x
169 		} // src dx loop
170 		sp = (Uint8 *)((Uint8*)sp + (src->pitch - factorx)); // next y
171 	    } // src dy loop
172 
173 	    // next box-x
174 	    sp = (Uint8 *)((Uint8*)oosp + factorx);
175 
176 	    /* Store result in destination */
177 	    *dp = a/n_average;
178 
179 	    /*
180 	     * Advance destination pointer
181 	     */
182 	    dp++;
183 	} // dst x loop
184 
185 	// next box-y
186 	sp = (Uint8 *)((Uint8*)osp + src->pitch*factory);
187 
188 	/*
189 	 * Advance destination pointers
190 	 */
191 	dp = (Uint8 *)((Uint8 *)dp + dgap);
192     } // dst y loop
193 
194     return (0);
195 }
196 
197 /*
198 
199    32bit Zoomer with optional anti-aliasing by bilinear interpolation.
200 
201    Zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
202 
203 */
204 
zoomSurfaceRGBA(SDL_Surface * src,SDL_Surface * dst,int flipx,int flipy,int smooth)205 int zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy, int smooth)
206 {
207     int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy, ex, ey, t1, t2, sstep;
208     tColorRGBA *c00, *c01, *c10, *c11;
209     tColorRGBA *sp, *csp, *dp;
210     int dgap;
211 
212     /*
213      * Variable setup
214      */
215     if (smooth) {
216 	/*
217 	 * For interpolation: assume source dimension is one pixel
218 	 */
219 	/*
220 	 * smaller to avoid overflow on right and bottom edge.
221 	 */
222 	sx = (int) (65536.0 * (float) (src->w - 1) / (float) dst->w);
223 	sy = (int) (65536.0 * (float) (src->h - 1) / (float) dst->h);
224     } else {
225 	sx = (int) (65536.0 * (float) src->w / (float) dst->w);
226 	sy = (int) (65536.0 * (float) src->h / (float) dst->h);
227     }
228 
229     /*
230      * Allocate memory for row increments
231      */
232     if ((sax = (int *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
233 	return (-1);
234     }
235     if ((say = (int *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
236 	free(sax);
237 	return (-1);
238     }
239 
240     /*
241      * Precalculate row increments
242      */
243     sp = csp = (tColorRGBA *) src->pixels;
244     dp = (tColorRGBA *) dst->pixels;
245 
246     if (flipx) csp += (src->w-1);
247     if (flipy) csp  = (tColorRGBA*)( (Uint8*)csp + src->pitch*(src->h-1) );
248 
249     csx = 0;
250     csax = sax;
251     for (x = 0; x <= dst->w; x++) {
252 	*csax = csx;
253 	csax++;
254 	csx &= 0xffff;
255 	csx += sx;
256     }
257     csy = 0;
258     csay = say;
259     for (y = 0; y <= dst->h; y++) {
260 	*csay = csy;
261 	csay++;
262 	csy &= 0xffff;
263 	csy += sy;
264     }
265 
266     dgap = dst->pitch - dst->w * 4;
267 
268     /*
269      * Switch between interpolating and non-interpolating code
270      */
271     if (smooth) {
272 
273 	/*
274 	 * Interpolating Zoom
275 	 */
276 
277 	/*
278 	 * Scan destination
279 	 */
280 	csay = say;
281 	for (y = 0; y < dst->h; y++) {
282 	    /*
283 	     * Setup color source pointers
284 	     */
285 	    c00 = csp;
286 	    c01 = csp;
287 	    c01++;
288 	    c10 = (tColorRGBA *) ((Uint8 *) csp + src->pitch);
289 	    c11 = c10;
290 	    c11++;
291 	    csax = sax;
292 	    for (x = 0; x < dst->w; x++) {
293 
294 		/*
295 		 * Interpolate colors
296 		 */
297 		ex = (*csax & 0xffff);
298 		ey = (*csay & 0xffff);
299 		t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
300 		t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
301 		dp->r = (((t2 - t1) * ey) >> 16) + t1;
302 		t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff;
303 		t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff;
304 		dp->g = (((t2 - t1) * ey) >> 16) + t1;
305 		t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff;
306 		t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff;
307 		dp->b = (((t2 - t1) * ey) >> 16) + t1;
308 		t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff;
309 		t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff;
310 		dp->a = (((t2 - t1) * ey) >> 16) + t1;
311 
312 		/*
313 		 * Advance source pointers
314 		 */
315 		csax++;
316 		sstep = (*csax >> 16);
317 		c00 += sstep;
318 		c01 += sstep;
319 		c10 += sstep;
320 		c11 += sstep;
321 		/*
322 		 * Advance destination pointer
323 		 */
324 		dp++;
325 	    }
326 	    /*
327 	     * Advance source pointer
328 	     */
329 	    csay++;
330 	    csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
331 	    /*
332 	     * Advance destination pointers
333 	     */
334 	    dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
335 	}
336 
337     } else {
338 
339 	/*
340 	 * Non-Interpolating Zoom
341 	 */
342 
343 	csay = say;
344 	for (y = 0; y < dst->h; y++) {
345 	    sp = csp;
346 	    csax = sax;
347 	    for (x = 0; x < dst->w; x++) {
348 		/*
349 		 * Draw
350 		 */
351 		*dp = *sp;
352 		/*
353 		 * Advance source pointers
354 		 */
355 		csax++;
356 		sstep = (*csax >> 16);
357 		if (flipx) sstep = -sstep;
358 		sp += sstep;
359 		/*
360 		 * Advance destination pointer
361 		 */
362 		dp++;
363 	    }
364 	    /*
365 	     * Advance source pointer
366 	     */
367 	    csay++;
368 	    sstep = (*csay >> 16) * src->pitch;
369 	    if (flipy) sstep = -sstep;
370 	    csp = (tColorRGBA *) ((Uint8 *) csp + sstep);
371 
372 	    /*
373 	     * Advance destination pointers
374 	     */
375 	    dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
376 	}
377 
378     }
379 
380     /*
381      * Remove temp arrays
382      */
383     free(sax);
384     free(say);
385 
386     return (0);
387 }
388 
389 /*
390 
391    8bit Zoomer without smoothing.
392 
393    Zoomes 8bit palette/Y 'src' surface to 'dst' surface.
394 
395 */
396 
zoomSurfaceY(SDL_Surface * src,SDL_Surface * dst,int flipx,int flipy)397 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy)
398 {
399     Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
400     Uint8 *sp, *dp, *csp;
401     int dgap;
402 
403     /*
404      * Variable setup
405      */
406     sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
407     sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
408 
409     /*
410      * Allocate memory for row increments
411      */
412     if ((sax = (Uint32 *) malloc(dst->w * sizeof(Uint32))) == NULL) {
413 	return (-1);
414     }
415     if ((say = (Uint32 *) malloc(dst->h * sizeof(Uint32))) == NULL) {
416 	if (sax != NULL) {
417 	    free(sax);
418 	}
419 	return (-1);
420     }
421 
422     /*
423      * Precalculate row increments
424      */
425     csx = 0;
426     csax = sax;
427     for (x = 0; x < dst->w; x++) {
428 	csx += sx;
429 	*csax = (csx >> 16);
430 	csx &= 0xffff;
431 	csax++;
432     }
433     csy = 0;
434     csay = say;
435     for (y = 0; y < dst->h; y++) {
436 	csy += sy;
437 	*csay = (csy >> 16);
438 	csy &= 0xffff;
439 	csay++;
440     }
441 
442     csx = 0;
443     csax = sax;
444     for (x = 0; x < dst->w; x++) {
445 	csx += (*csax);
446 	csax++;
447     }
448     csy = 0;
449     csay = say;
450     for (y = 0; y < dst->h; y++) {
451 	csy += (*csay);
452 	csay++;
453     }
454 
455     /*
456      * Pointer setup
457      */
458     sp = csp = (Uint8 *) src->pixels;
459     dp = (Uint8 *) dst->pixels;
460     dgap = dst->pitch - dst->w;
461 
462     /*
463      * Draw
464      */
465     csay = say;
466     for (y = 0; y < dst->h; y++) {
467 	csax = sax;
468 	sp = csp;
469 	for (x = 0; x < dst->w; x++) {
470 	    /*
471 	     * Draw
472 	     */
473 	    *dp = *sp;
474 	    /*
475 	     * Advance source pointers
476 	     */
477 	    sp += (*csax);
478 	    csax++;
479 	    /*
480 	     * Advance destination pointer
481 	     */
482 	    dp++;
483 	}
484 	/*
485 	 * Advance source pointer (for row)
486 	 */
487 	csp += ((*csay) * src->pitch);
488 	csay++;
489 	/*
490 	 * Advance destination pointers
491 	 */
492 	dp += dgap;
493     }
494 
495     /*
496      * Remove temp arrays
497      */
498     free(sax);
499     free(say);
500 
501     return (0);
502 }
503 
504 /*
505 
506    32bit Rotozoomer with optional anti-aliasing by bilinear interpolation.
507 
508    Rotates and zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
509 
510 */
511 
transformSurfaceRGBA(SDL_Surface * src,SDL_Surface * dst,int cx,int cy,int isin,int icos,int flipx,int flipy,int smooth)512 void transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy, int smooth)
513 {
514     int x, y, t1, t2, dx, dy, xd, yd, sdx, sdy, ax, ay, ex, ey, sw, sh;
515     tColorRGBA c00, c01, c10, c11;
516     tColorRGBA *pc, *sp;
517     int gap;
518 
519     c00.r = c00.g = c00.b = c00.a = 0;
520     c01.r = c01.g = c01.b = c01.a = 0;
521     c10.r = c10.g = c10.b = c10.a = 0;
522     c11.r = c11.g = c11.b = c11.a = 0;
523     /*
524      * Variable setup
525      */
526     xd = ((src->w - dst->w) << 15);
527     yd = ((src->h - dst->h) << 15);
528     ax = (cx << 16) - (icos * cx);
529     ay = (cy << 16) - (isin * cx);
530     sw = src->w - 1;
531     sh = src->h - 1;
532     pc = dst->pixels;
533     gap = dst->pitch - dst->w * 4;
534 
535     /*
536      * Switch between interpolating and non-interpolating code
537      */
538     if (smooth) {
539 	for (y = 0; y < dst->h; y++) {
540 	    dy = cy - y;
541 	    sdx = (ax + (isin * dy)) + xd;
542 	    sdy = (ay - (icos * dy)) + yd;
543 	    for (x = 0; x < dst->w; x++) {
544 		dx = (sdx >> 16);
545 		dy = (sdy >> 16);
546 		if ((dx >= -1) && (dy >= -1) && (dx < src->w) && (dy < src->h)) {
547 		    if ((dx >= 0) && (dy >= 0) && (dx < sw) && (dy < sh)) {
548 			sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
549 			sp += dx;
550 			c00 = *sp;
551 			sp += 1;
552 			c01 = *sp;
553 			sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
554 			sp -= 1;
555 			c10 = *sp;
556 			sp += 1;
557 			c11 = *sp;
558 		    } else if ((dx == sw) && (dy == sh)) {
559 			sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
560 			sp += dx;
561 			c00 = *sp;
562 			c01 = *sp;
563 			c10 = *sp;
564 			c11 = *sp;
565 		    } else if ((dx == -1) && (dy == -1)) {
566 			sp = (tColorRGBA *) (src->pixels);
567 			c00 = *sp;
568 			c01 = *sp;
569 			c10 = *sp;
570 			c11 = *sp;
571 		    } else if ((dx == -1) && (dy == sh)) {
572 			sp = (tColorRGBA *) (src->pixels);
573 			sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
574 			c00 = *sp;
575 			c01 = *sp;
576 			c10 = *sp;
577 			c11 = *sp;
578 		    } else if ((dx == sw) && (dy == -1)) {
579 			sp = (tColorRGBA *) (src->pixels);
580 			sp += dx;
581 			c00 = *sp;
582 			c01 = *sp;
583 			c10 = *sp;
584 			c11 = *sp;
585 		    } else if (dx == -1) {
586 			sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
587 			c00 = *sp;
588 			c01 = *sp;
589 			c10 = *sp;
590 			sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
591 			c11 = *sp;
592 		    } else if (dy == -1) {
593 			sp = (tColorRGBA *) (src->pixels);
594 			sp += dx;
595 			c00 = *sp;
596 			c01 = *sp;
597 			c10 = *sp;
598 			sp += 1;
599 			c11 = *sp;
600 		    } else if (dx == sw) {
601 			sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
602 			sp += dx;
603 			c00 = *sp;
604 			c01 = *sp;
605 			sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
606 			c10 = *sp;
607 			c11 = *sp;
608 		    } else if (dy == sh) {
609 			sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
610 			sp += dx;
611 			c00 = *sp;
612 			sp += 1;
613 			c01 = *sp;
614 			c10 = *sp;
615 			c11 = *sp;
616 		    }
617 		    /*
618 		     * Interpolate colors
619 		     */
620 		    ex = (sdx & 0xffff);
621 		    ey = (sdy & 0xffff);
622 		    t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff;
623 		    t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff;
624 		    pc->r = (((t2 - t1) * ey) >> 16) + t1;
625 		    t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff;
626 		    t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff;
627 		    pc->g = (((t2 - t1) * ey) >> 16) + t1;
628 		    t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff;
629 		    t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff;
630 		    pc->b = (((t2 - t1) * ey) >> 16) + t1;
631 		    t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff;
632 		    t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff;
633 		    pc->a = (((t2 - t1) * ey) >> 16) + t1;
634 		}
635 		sdx += icos;
636 		sdy += isin;
637 		pc++;
638 	    }
639 	    pc = (tColorRGBA *) ((Uint8 *) pc + gap);
640 	}
641     } else {
642 	for (y = 0; y < dst->h; y++) {
643 	    dy = cy - y;
644 	    sdx = (ax + (isin * dy)) + xd;
645 	    sdy = (ay - (icos * dy)) + yd;
646 	    for (x = 0; x < dst->w; x++) {
647 		dx = (short) (sdx >> 16);
648 		dy = (short) (sdy >> 16);
649 		if (flipx) dx = (src->w-1)-dx;
650 		if (flipy) dy = (src->h-1)-dy;
651 		if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
652 		    sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
653 		    sp += dx;
654 		    *pc = *sp;
655 		}
656 		sdx += icos;
657 		sdy += isin;
658 		pc++;
659 	    }
660 	    pc = (tColorRGBA *) ((Uint8 *) pc + gap);
661 	}
662     }
663 }
664 
665 /*
666 
667    8bit Rotozoomer without smoothing
668 
669    Rotates and zoomes 8bit palette/Y 'src' surface to 'dst' surface.
670 
671 */
672 
transformSurfaceY(SDL_Surface * src,SDL_Surface * dst,int cx,int cy,int isin,int icos)673 void transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos)
674 {
675     int x, y, dx, dy, xd, yd, sdx, sdy, ax, ay, sw, sh;
676     tColorY *pc, *sp;
677     int gap;
678 
679     /*
680      * Variable setup
681      */
682     xd = ((src->w - dst->w) << 15);
683     yd = ((src->h - dst->h) << 15);
684     ax = (cx << 16) - (icos * cx);
685     ay = (cy << 16) - (isin * cx);
686     sw = src->w - 1;
687     sh = src->h - 1;
688     pc = dst->pixels;
689     gap = dst->pitch - dst->w;
690     /*
691      * Clear surface to colorkey
692      */
693     memset(pc, (unsigned char) (src->format->colorkey & 0xff), dst->pitch * dst->h);
694     /*
695      * Iterate through destination surface
696      */
697     for (y = 0; y < dst->h; y++) {
698 	dy = cy - y;
699 	sdx = (ax + (isin * dy)) + xd;
700 	sdy = (ay - (icos * dy)) + yd;
701 	for (x = 0; x < dst->w; x++) {
702 	    dx = (short) (sdx >> 16);
703 	    dy = (short) (sdy >> 16);
704 	    if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
705 		sp = (tColorY *) (src->pixels);
706 		sp += (src->pitch * dy + dx);
707 		*pc = *sp;
708 	    }
709 	    sdx += icos;
710 	    sdy += isin;
711 	    pc++;
712 	}
713 	pc += gap;
714     }
715 }
716 
717 
718 /*
719 
720    32bit specialized 90degree rotator
721 
722    Rotates and zooms 'src' surface to 'dst' surface in 90degree increments.
723 
724    (contributed by Jeff Schiller)
725 
726 */
rotateSurface90Degrees(SDL_Surface * pSurf,int numClockwiseTurns)727 SDL_Surface* rotateSurface90Degrees(SDL_Surface* pSurf, int numClockwiseTurns)
728 {
729     int row, col;
730 
731     // Has to be a valid surface pointer and only 32-bit surfaces (for now)
732     if (!pSurf || pSurf->format->BitsPerPixel != 32) { return NULL; }
733 
734     // normalize numClockwiseTurns
735     while(numClockwiseTurns < 0) { numClockwiseTurns += 4; }
736     numClockwiseTurns = (numClockwiseTurns % 4);
737 
738     // if it's even, our new width will be the same as the source surface
739     int newWidth = (numClockwiseTurns % 2) ? (pSurf->h) : (pSurf->w);
740     int newHeight = (numClockwiseTurns % 2) ? (pSurf->w) : (pSurf->h);
741     SDL_Surface* pSurfOut = SDL_CreateRGBSurface( pSurf->flags, newWidth, newHeight, pSurf->format->BitsPerPixel,
742 	    pSurf->format->Rmask,
743 	    pSurf->format->Gmask,
744 	    pSurf->format->Bmask,
745 	    pSurf->format->Amask);
746     if(!pSurfOut) {
747 	return NULL;
748     }
749 
750     if(numClockwiseTurns != 0) {
751 	SDL_LockSurface(pSurf);
752 	SDL_LockSurface(pSurfOut);
753 	switch(numClockwiseTurns) {
754 	    // rotate clockwise
755 	    case 1: // rotated 90 degrees clockwise
756 		{
757 		    Uint32* srcBuf = NULL;
758 		    Uint32* dstBuf = NULL;
759 
760 		    for (row = 0; row < pSurf->h; ++row) {
761 			srcBuf = (Uint32*)(pSurf->pixels) + (row*pSurf->pitch/4);
762 			dstBuf = (Uint32*)(pSurfOut->pixels) + (pSurfOut->w - row - 1);
763 			for (col = 0; col < pSurf->w; ++col) {
764 			    *dstBuf = *srcBuf;
765 			    ++srcBuf;
766 			    dstBuf += pSurfOut->pitch/4;
767 			} // for(col)
768 		    } // for(row)
769 		}
770 		break;
771 
772 	    case 2: // rotated 180 degrees clockwise
773 		{
774 		    Uint32* srcBuf = NULL;
775 		    Uint32* dstBuf = NULL;
776 
777 		    for(row = 0; row < pSurf->h; ++row) {
778 			srcBuf = (Uint32*)(pSurf->pixels) + (row*pSurf->pitch/4);
779 			dstBuf = (Uint32*)(pSurfOut->pixels) + ((pSurfOut->h - row - 1)*pSurfOut->pitch/4) + (pSurfOut->w - 1);
780 			for(col = 0; col < pSurf->w; ++col) {
781 			    *dstBuf = *srcBuf;
782 			    ++srcBuf;
783 			    --dstBuf;
784 			} // for(col)
785 		    } // for(row)
786 		}
787 		break;
788 
789 	    case 3:
790 		{
791 		    Uint32* srcBuf = NULL;
792 		    Uint32* dstBuf = NULL;
793 
794 		    for(row = 0; row < pSurf->h; ++row) {
795 			srcBuf = (Uint32*)(pSurf->pixels) + (row*pSurf->pitch/4);
796 			dstBuf = (Uint32*)(pSurfOut->pixels) + row + ((pSurfOut->h - 1)*pSurfOut->pitch/4);
797 			for(col = 0; col < pSurf->w; ++col) {
798 			    *dstBuf = *srcBuf;
799 			    ++srcBuf;
800 			    dstBuf -= pSurfOut->pitch/4;
801 			} // for(col)
802 		    } // for(row)
803 		}
804 		break;
805 	} // switch
806 
807 	SDL_UnlockSurface(pSurf);
808 	SDL_UnlockSurface(pSurfOut);
809     } // if numClockwiseTurns > 0
810     else {
811 	// simply copy surface to output
812 	if(SDL_BlitSurface(pSurf, NULL, pSurfOut, NULL)) {
813 	    return NULL;
814 	}
815     }
816     return pSurfOut;
817 }
818 
819 /*
820 
821    rotozoomSurface()
822 
823    Rotates and zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
824    'angle' is the rotation in degrees. 'zoom' a scaling factor. If 'smooth' is 1
825    then the destination 32bit surface is anti-aliased. If the surface is not 8bit
826    or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
827 
828 */
829 
830 #define VALUE_LIMIT	0.001
831 
832 
833 /* Local rotozoom-size function with trig result return */
834 
rotozoomSurfaceSizeTrig(int width,int height,double angle,double zoomx,double zoomy,int * dstwidth,int * dstheight,double * canglezoom,double * sanglezoom)835 void rotozoomSurfaceSizeTrig(int width, int height, double angle, double zoomx, double zoomy, int *dstwidth, int *dstheight,
836 	double *canglezoom, double *sanglezoom)
837 {
838     double x, y, cx, cy, sx, sy;
839     double radangle;
840     int dstwidthhalf, dstheighthalf;
841 
842     /*
843      * Determine destination width and height by rotating a centered source box
844      */
845     radangle = angle * (M_PI / 180.0);
846     *sanglezoom = sin(radangle);
847     *canglezoom = cos(radangle);
848     *sanglezoom *= zoomx;
849     *canglezoom *= zoomx;
850     x = width / 2;
851     y = height / 2;
852     cx = *canglezoom * x;
853     cy = *canglezoom * y;
854     sx = *sanglezoom * x;
855     sy = *sanglezoom * y;
856 
857     dstwidthhalf = MAX((int)
858 	    ceil(MAX(MAX(MAX(fabs(cx + sy), fabs(cx - sy)), fabs(-cx + sy)), fabs(-cx - sy))), 1);
859     dstheighthalf = MAX((int)
860 	    ceil(MAX(MAX(MAX(fabs(sx + cy), fabs(sx - cy)), fabs(-sx + cy)), fabs(-sx - cy))), 1);
861     *dstwidth = 2 * dstwidthhalf;
862     *dstheight = 2 * dstheighthalf;
863 }
864 
865 
866 /* Publically available rotozoom-size function */
867 
rotozoomSurfaceSizeXY(int width,int height,double angle,double zoomx,double zoomy,int * dstwidth,int * dstheight)868 void rotozoomSurfaceSizeXY(int width, int height, double angle, double zoomx, double zoomy, int *dstwidth, int *dstheight)
869 {
870     double dummy_sanglezoom, dummy_canglezoom;
871 
872     rotozoomSurfaceSizeTrig(width, height, angle, zoomx, zoomy, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
873 }
874 
875 /* Publically available rotozoom-size function */
876 
rotozoomSurfaceSize(int width,int height,double angle,double zoom,int * dstwidth,int * dstheight)877 void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth, int *dstheight)
878 {
879     double dummy_sanglezoom, dummy_canglezoom;
880 
881     rotozoomSurfaceSizeTrig(width, height, angle, zoom, zoom, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
882 }
883 
884 /* Publically available rotozoom function */
885 
rotozoomSurface(SDL_Surface * src,double angle,double zoom,int smooth)886 SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth)
887 {
888     return rotozoomSurfaceXY(src, angle, zoom, zoom, smooth);
889 }
890 
891 /* Publically available rotozoom function */
892 
rotozoomSurfaceXY(SDL_Surface * src,double angle,double zoomx,double zoomy,int smooth)893 SDL_Surface *rotozoomSurfaceXY(SDL_Surface * src, double angle, double zoomx, double zoomy, int smooth)
894 {
895     SDL_Surface *rz_src;
896     SDL_Surface *rz_dst;
897     double zoominv;
898     double sanglezoom, canglezoom, sanglezoominv, canglezoominv;
899     int dstwidthhalf, dstwidth, dstheighthalf, dstheight;
900     int is32bit;
901     int i, src_converted;
902     int flipx,flipy;
903 
904     /*
905      * Sanity check
906      */
907     if (src == NULL)
908 	return (NULL);
909 
910     /*
911      * Determine if source surface is 32bit or 8bit
912      */
913     is32bit = (src->format->BitsPerPixel == 32);
914     if ((is32bit) || (src->format->BitsPerPixel == 8)) {
915 	/*
916 	 * Use source surface 'as is'
917 	 */
918 	rz_src = src;
919 	src_converted = 0;
920     } else {
921 	/*
922 	 * New source surface is 32bit with a defined RGBA ordering
923 	 */
924 	rz_src =
925 	    SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
926 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
927 		    0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
928 #else
929 		    0xff000000,  0x00ff0000, 0x0000ff00, 0x000000ff
930 #endif
931 		    );
932 	SDL_BlitSurface(src, NULL, rz_src, NULL);
933 	src_converted = 1;
934 	is32bit = 1;
935     }
936 
937     /*
938      * Sanity check zoom factor
939      */
940     flipx = (zoomx<0);
941     if (flipx) zoomx=-zoomx;
942     flipy = (zoomy<0);
943     if (flipy) zoomy=-zoomy;
944     if (zoomx < VALUE_LIMIT) zoomx = VALUE_LIMIT;
945     if (zoomy < VALUE_LIMIT) zoomy = VALUE_LIMIT;
946     zoominv = 65536.0 / (zoomx * zoomx);
947 
948     /*
949      * Check if we have a rotozoom or just a zoom
950      */
951     if (fabs(angle) > VALUE_LIMIT) {
952 
953 	/*
954 	 * Angle!=0: full rotozoom
955 	 */
956 	/*
957 	 * -----------------------
958 	 */
959 
960 	/* Determine target size */
961 	rotozoomSurfaceSizeTrig(rz_src->w, rz_src->h, angle, zoomx, zoomy, &dstwidth, &dstheight, &canglezoom, &sanglezoom);
962 
963 	/*
964 	 * Calculate target factors from sin/cos and zoom
965 	 */
966 	sanglezoominv = sanglezoom;
967 	canglezoominv = canglezoom;
968 	sanglezoominv *= zoominv;
969 	canglezoominv *= zoominv;
970 
971 	/* Calculate half size */
972 	dstwidthhalf = dstwidth / 2;
973 	dstheighthalf = dstheight / 2;
974 
975 	/*
976 	 * Alloc space to completely contain the rotated surface
977 	 */
978 	rz_dst = NULL;
979 	if (is32bit) {
980 	    /*
981 	     * Target surface is 32bit with source RGBA/ABGR ordering
982 	     */
983 	    rz_dst =
984 		SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
985 			rz_src->format->Rmask, rz_src->format->Gmask,
986 			rz_src->format->Bmask, rz_src->format->Amask);
987 	} else {
988 	    /*
989 	     * Target surface is 8bit
990 	     */
991 	    rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
992 	}
993 
994 	/*
995 	 * Lock source surface
996 	 */
997 	SDL_LockSurface(rz_src);
998 	/*
999 	 * Check which kind of surface we have
1000 	 */
1001 	if (is32bit) {
1002 	    /*
1003 	     * Call the 32bit transformation routine to do the rotation (using alpha)
1004 	     */
1005 	    transformSurfaceRGBA(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
1006 		    (int) (sanglezoominv), (int) (canglezoominv),
1007 		    flipx, flipy,
1008 		    smooth);
1009 	    /*
1010 	     * Turn on source-alpha support
1011 	     */
1012 	    SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1013 	} else {
1014 	    /*
1015 	     * Copy palette and colorkey info
1016 	     */
1017 	    for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1018 		rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1019 	    }
1020 	    rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1021 	    /*
1022 	     * Call the 8bit transformation routine to do the rotation
1023 	     */
1024 	    transformSurfaceY(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
1025 		    (int) (sanglezoominv), (int) (canglezoominv));
1026 	    SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
1027 	}
1028 	/*
1029 	 * Unlock source surface
1030 	 */
1031 	SDL_UnlockSurface(rz_src);
1032 
1033     } else {
1034 
1035 	/*
1036 	 * Angle=0: Just a zoom
1037 	 */
1038 	/*
1039 	 * --------------------
1040 	 */
1041 
1042 	/*
1043 	 * Calculate target size
1044 	 */
1045 	zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
1046 
1047 	/*
1048 	 * Alloc space to completely contain the zoomed surface
1049 	 */
1050 	rz_dst = NULL;
1051 	if (is32bit) {
1052 	    /*
1053 	     * Target surface is 32bit with source RGBA/ABGR ordering
1054 	     */
1055 	    rz_dst =
1056 		SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
1057 			rz_src->format->Rmask, rz_src->format->Gmask,
1058 			rz_src->format->Bmask, rz_src->format->Amask);
1059 	} else {
1060 	    /*
1061 	     * Target surface is 8bit
1062 	     */
1063 	    rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
1064 	}
1065 
1066 	/*
1067 	 * Lock source surface
1068 	 */
1069 	SDL_LockSurface(rz_src);
1070 	/*
1071 	 * Check which kind of surface we have
1072 	 */
1073 	if (is32bit) {
1074 	    /*
1075 	     * Call the 32bit transformation routine to do the zooming (using alpha)
1076 	     */
1077 	    zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
1078 	    /*
1079 	     * Turn on source-alpha support
1080 	     */
1081 	    SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1082 	} else {
1083 	    /*
1084 	     * Copy palette and colorkey info
1085 	     */
1086 	    for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1087 		rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1088 	    }
1089 	    rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1090 	    /*
1091 	     * Call the 8bit transformation routine to do the zooming
1092 	     */
1093 	    zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
1094 	    SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
1095 	}
1096 	/*
1097 	 * Unlock source surface
1098 	 */
1099 	SDL_UnlockSurface(rz_src);
1100     }
1101 
1102     /*
1103      * Cleanup temp surface
1104      */
1105     if (src_converted) {
1106 	SDL_FreeSurface(rz_src);
1107     }
1108 
1109     /*
1110      * Return destination surface
1111      */
1112     return (rz_dst);
1113 }
1114 
1115 /*
1116 
1117    zoomSurface()
1118 
1119    Zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1120    'zoomx' and 'zoomy' are scaling factors for width and height. If 'smooth' is 1
1121    then the destination 32bit surface is anti-aliased. If the surface is not 8bit
1122    or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
1123 
1124 */
1125 
1126 #define VALUE_LIMIT	0.001
1127 
zoomSurfaceSize(int width,int height,double zoomx,double zoomy,int * dstwidth,int * dstheight)1128 void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight)
1129 {
1130     /*
1131      * Sanity check zoom factors
1132      */
1133     if (zoomx < VALUE_LIMIT) {
1134 	zoomx = VALUE_LIMIT;
1135     }
1136     if (zoomy < VALUE_LIMIT) {
1137 	zoomy = VALUE_LIMIT;
1138     }
1139 
1140     /*
1141      * Calculate target size
1142      */
1143     *dstwidth = (int) ((double) width * zoomx);
1144     *dstheight = (int) ((double) height * zoomy);
1145     if (*dstwidth < 1) {
1146 	*dstwidth = 1;
1147     }
1148     if (*dstheight < 1) {
1149 	*dstheight = 1;
1150     }
1151 }
1152 
zoomSurface(SDL_Surface * src,double zoomx,double zoomy,int smooth)1153 SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth)
1154 {
1155     SDL_Surface *rz_src;
1156     SDL_Surface *rz_dst;
1157     int dstwidth, dstheight;
1158     int is32bit;
1159     int i, src_converted;
1160     int flipx, flipy;
1161 
1162     /*
1163      * Sanity check
1164      */
1165     if (src == NULL)
1166 	return (NULL);
1167 
1168     /*
1169      * Determine if source surface is 32bit or 8bit
1170      */
1171     is32bit = (src->format->BitsPerPixel == 32);
1172     if ((is32bit) || (src->format->BitsPerPixel == 8)) {
1173 	/*
1174 	 * Use source surface 'as is'
1175 	 */
1176 	rz_src = src;
1177 	src_converted = 0;
1178     } else {
1179 	/*
1180 	 * New source surface is 32bit with a defined RGBA ordering
1181 	 */
1182 	rz_src =
1183 	    SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1184 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
1185 		    0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
1186 #else
1187 		    0xff000000,  0x00ff0000, 0x0000ff00, 0x000000ff
1188 #endif
1189 		    );
1190 	SDL_BlitSurface(src, NULL, rz_src, NULL);
1191 	src_converted = 1;
1192 	is32bit = 1;
1193     }
1194 
1195     flipx = (zoomx<0);
1196     if (flipx) zoomx = -zoomx;
1197     flipy = (zoomy<0);
1198     if (flipy) zoomy = -zoomy;
1199 
1200     /* Get size if target */
1201     zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
1202 
1203     /*
1204      * Alloc space to completely contain the zoomed surface
1205      */
1206     rz_dst = NULL;
1207     if (is32bit) {
1208 	/*
1209 	 * Target surface is 32bit with source RGBA/ABGR ordering
1210 	 */
1211 	rz_dst =
1212 	    SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
1213 		    rz_src->format->Rmask, rz_src->format->Gmask,
1214 		    rz_src->format->Bmask, rz_src->format->Amask);
1215     } else {
1216 	/*
1217 	 * Target surface is 8bit
1218 	 */
1219 	rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
1220     }
1221 
1222     /*
1223      * Lock source surface
1224      */
1225     SDL_LockSurface(rz_src);
1226     /*
1227      * Check which kind of surface we have
1228      */
1229     if (is32bit) {
1230 	/*
1231 	 * Call the 32bit transformation routine to do the zooming (using alpha)
1232 	 */
1233 	zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
1234 	/*
1235 	 * Turn on source-alpha support
1236 	 */
1237 	SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1238     } else {
1239 	/*
1240 	 * Copy palette and colorkey info
1241 	 */
1242 	for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1243 	    rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1244 	}
1245 	rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1246 	/*
1247 	 * Call the 8bit transformation routine to do the zooming
1248 	 */
1249 	zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
1250 	SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
1251     }
1252     /*
1253      * Unlock source surface
1254      */
1255     SDL_UnlockSurface(rz_src);
1256 
1257     /*
1258      * Cleanup temp surface
1259      */
1260     if (src_converted) {
1261 	SDL_FreeSurface(rz_src);
1262     }
1263 
1264     /*
1265      * Return destination surface
1266      */
1267     return (rz_dst);
1268 }
1269 
shrinkSurface(SDL_Surface * src,int factorx,int factory)1270 SDL_Surface *shrinkSurface(SDL_Surface * src, int factorx, int factory)
1271 {
1272     SDL_Surface *rz_src;
1273     SDL_Surface *rz_dst;
1274     int dstwidth, dstheight;
1275     int is32bit;
1276     int i, src_converted;
1277 
1278     /*
1279      * Sanity check
1280      */
1281     if (src == NULL)
1282 	return (NULL);
1283 
1284     /*
1285      * Determine if source surface is 32bit or 8bit
1286      */
1287     is32bit = (src->format->BitsPerPixel == 32);
1288     if ((is32bit) || (src->format->BitsPerPixel == 8)) {
1289 	/*
1290 	 * Use source surface 'as is'
1291 	 */
1292 	rz_src = src;
1293 	src_converted = 0;
1294     } else {
1295 	/*
1296 	 * New source surface is 32bit with a defined RGBA ordering
1297 	 */
1298 	rz_src =
1299 	    SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1300 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
1301 		    0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
1302 #else
1303 		    0xff000000,  0x00ff0000, 0x0000ff00, 0x000000ff
1304 #endif
1305 		    );
1306 	SDL_BlitSurface(src, NULL, rz_src, NULL);
1307 	src_converted = 1;
1308 	is32bit = 1;
1309     }
1310 
1311     /* Get size for target */
1312     dstwidth=rz_src->w/factorx;
1313     while (dstwidth*factorx>rz_src->w) { dstwidth--; }
1314     dstheight=rz_src->h/factory;
1315     while (dstheight*factory>rz_src->h) { dstheight--; }
1316 
1317     /*
1318      * Alloc space to completely contain the shrunken surface
1319      */
1320     rz_dst = NULL;
1321     if (is32bit) {
1322 	/*
1323 	 * Target surface is 32bit with source RGBA/ABGR ordering
1324 	 */
1325 	rz_dst =
1326 	    SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
1327 		    rz_src->format->Rmask, rz_src->format->Gmask,
1328 		    rz_src->format->Bmask, rz_src->format->Amask);
1329     } else {
1330 	/*
1331 	 * Target surface is 8bit
1332 	 */
1333 	rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
1334     }
1335 
1336     /*
1337      * Lock source surface
1338      */
1339     SDL_LockSurface(rz_src);
1340     /*
1341      * Check which kind of surface we have
1342      */
1343     if (is32bit) {
1344 	/*
1345 	 * Call the 32bit transformation routine to do the shrinking (using alpha)
1346 	 */
1347 	shrinkSurfaceRGBA(rz_src, rz_dst, factorx, factory);
1348 	/*
1349 	 * Turn on source-alpha support
1350 	 */
1351 	SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1352     } else {
1353 	/*
1354 	 * Copy palette and colorkey info
1355 	 */
1356 	for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1357 	    rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1358 	}
1359 	rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1360 	/*
1361 	 * Call the 8bit transformation routine to do the shrinking
1362 	 */
1363 	shrinkSurfaceY(rz_src, rz_dst, factorx, factory);
1364 	SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
1365     }
1366     /*
1367      * Unlock source surface
1368      */
1369     SDL_UnlockSurface(rz_src);
1370 
1371     /*
1372      * Cleanup temp surface
1373      */
1374     if (src_converted) {
1375 	SDL_FreeSurface(rz_src);
1376     }
1377 
1378     /*
1379      * Return destination surface
1380      */
1381     return (rz_dst);
1382 }
1383