1 /*
2 
3   rotozoom.c - rotozoomer for 32bit or 8bit surfaces
4   LGPL (c) A. Schiffler
5 
6   Note by sc2 developers:
7   Taken from SDL_gfx library and modified, original code can be downloaded
8   from http://www.ferzkopp.net/Software/SDL_gfx-2.0/
9 
10 */
11 
12 #include <stdlib.h>
13 #include <string.h>
14 #include "sdl_common.h"
15 #include "libs/memlib.h"
16 #include "port.h"
17 #include "rotozoom.h"
18 
19 #define MAX(a,b)    (((a) > (b)) ? (a) : (b))
20 
21 
22 
23 /*
24 
25  32bit Zoomer with optional anti-aliasing by bilinear interpolation.
26 
27  Zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
28 
29 */
30 
zoomSurfaceRGBA(SDL_Surface * src,SDL_Surface * dst,int smooth)31 int zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int smooth)
32 {
33     int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy, ex, ey, t1, t2, sstep;
34     tColorRGBA *c00, *c01, *c10, *c11;
35     tColorRGBA *sp, *csp, *dp;
36     int sgap, dgap;
37 
38     /*
39      * Variable setup
40      */
41     if (smooth) {
42 	/*
43 	 * For interpolation: assume source dimension is one pixel
44 	 */
45 	/*
46 	 * smaller to avoid overflow on right and bottom edge.
47 	 */
48 	sx = (int) (65536.0 * (float) (src->w - 1) / (float) dst->w);
49 	sy = (int) (65536.0 * (float) (src->h - 1) / (float) dst->h);
50     } else {
51 	sx = (int) (65536.0 * (float) src->w / (float) dst->w);
52 	sy = (int) (65536.0 * (float) src->h / (float) dst->h);
53     }
54 
55     /*
56      * Allocate memory for row increments
57      */
58 
59 #ifndef __SYMBIAN32__
60     if ((sax = (int *) alloca((dst->w + 1) * sizeof(Uint32))) == NULL)
61 		return (-1);
62     if ((say = (int *) alloca((dst->h + 1) * sizeof(Uint32))) == NULL)
63 		return (-1);
64 #else
65     if ((sax = (int *) HMalloc((dst->w + 1) * sizeof(Uint32))) == NULL)
66 		return (-1);
67     if ((say = (int *) HMalloc((dst->h + 1) * sizeof(Uint32))) == NULL)
68     {
69     	HFree(sax);
70 		return (-1);
71 	}
72 #endif
73 
74 
75     /*
76      * Precalculate row increments
77      */
78     csx = 0;
79     csax = sax;
80     for (x = 0; x <= dst->w; x++) {
81 	*csax = csx;
82 	csax++;
83 	csx &= 0xffff;
84 	csx += sx;
85     }
86     csy = 0;
87     csay = say;
88     for (y = 0; y <= dst->h; y++) {
89 	*csay = csy;
90 	csay++;
91 	csy &= 0xffff;
92 	csy += sy;
93     }
94 
95     /*
96      * Pointer setup
97      */
98     sp = csp = (tColorRGBA *) src->pixels;
99     dp = (tColorRGBA *) dst->pixels;
100     sgap = src->pitch - src->w * 4;
101     dgap = dst->pitch - dst->w * 4;
102 
103     /*
104      * Switch between interpolating and non-interpolating code
105      */
106     if (smooth) {
107 
108 	/*
109 	 * Interpolating Zoom
110 	 */
111 
112 	/*
113 	 * Scan destination
114 	 */
115 	csay = say;
116 	for (y = 0; y < dst->h; y++) {
117 	    /*
118 	     * Setup color source pointers
119 	     */
120 	    c00 = csp;
121 	    c01 = csp;
122 	    c01++;
123 	    c10 = (tColorRGBA *) ((Uint8 *) csp + src->pitch);
124 	    c11 = c10;
125 	    c11++;
126 	    csax = sax;
127 	    for (x = 0; x < dst->w; x++) {
128 
129 		/*
130 		 * Interpolate colors
131 		 */
132 		ex = (*csax & 0xffff);
133 		ey = (*csay & 0xffff);
134 		t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
135 		t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
136 		dp->r = (((t2 - t1) * ey) >> 16) + t1;
137 		t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff;
138 		t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff;
139 		dp->g = (((t2 - t1) * ey) >> 16) + t1;
140 		t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff;
141 		t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff;
142 		dp->b = (((t2 - t1) * ey) >> 16) + t1;
143 		t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff;
144 		t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff;
145 		dp->a = (((t2 - t1) * ey) >> 16) + t1;
146 
147 		/*
148 		 * Advance source pointers
149 		 */
150 		csax++;
151 		sstep = (*csax >> 16);
152 		c00 += sstep;
153 		c01 += sstep;
154 		c10 += sstep;
155 		c11 += sstep;
156 		/*
157 		 * Advance destination pointer
158 		 */
159 		dp++;
160 	    }
161 	    /*
162 	     * Advance source pointer
163 	     */
164 	    csay++;
165 	    csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
166 	    /*
167 	     * Advance destination pointers
168 	     */
169 	    dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
170 	}
171 
172     } else {
173 
174 	/*
175 	 * Non-Interpolating Zoom
176 	 */
177 
178 	csay = say;
179 	for (y = 0; y < dst->h; y++) {
180 	    sp = csp;
181 	    csax = sax;
182 	    for (x = 0; x < dst->w; x++) {
183 		/*
184 		 * Draw
185 		 */
186 		*dp = *sp;
187 		/*
188 		 * Advance source pointers
189 		 */
190 		csax++;
191 		sp += (*csax >> 16);
192 		/*
193 		 * Advance destination pointer
194 		 */
195 		dp++;
196 	    }
197 	    /*
198 	     * Advance source pointer
199 	     */
200 	    csay++;
201 	    csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
202 	    /*
203 	     * Advance destination pointers
204 	     */
205 	    dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
206 	}
207 
208     }
209 
210 #ifdef __SYMBIAN32__
211 	HFree(sax);
212 	HFree(say);
213 #endif
214 
215     return (0);
216 }
217 
218 /*
219 
220  8bit Zoomer without smoothing.
221 
222  Zoomes 8bit palette/Y 'src' surface to 'dst' surface.
223 
224 */
225 
226 static
zoomSurfaceY(SDL_Surface * src,SDL_Surface * dst)227 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
228 {
229     Uint32 sx, sy, *sax, *say, *csax, *csay, csx, csy;
230 	int x, y;
231     Uint8 *sp, *dp, *csp;
232     int dgap;
233 
234     /*
235      * Variable setup
236      */
237     sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
238     sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
239 
240     /*
241      * Allocate memory for row increments
242      */
243 #ifndef __SYMBIAN32__
244     if ((sax = (Uint32 *) alloca(dst->w * sizeof(Uint32))) == NULL)
245 		return (-1);
246     if ((say = (Uint32 *) alloca(dst->h * sizeof(Uint32))) == NULL)
247 		return (-1);
248 #else
249     if ((sax = (Uint32 *) HMalloc(dst->w * sizeof(Uint32))) == NULL)
250 		return (-1);
251     if ((say = (Uint32 *) HMalloc(dst->h * sizeof(Uint32))) == NULL)
252     {
253     	HFree(sax);
254 		return (-1);
255 	}
256 #endif
257 
258     /*
259      * Precalculate row increments
260      */
261     csx = 0;
262     csax = sax;
263     for (x = 0; x < dst->w; x++) {
264 	csx += sx;
265 	*csax = (csx >> 16);
266 	csx &= 0xffff;
267 	csax++;
268     }
269     csy = 0;
270     csay = say;
271     for (y = 0; y < dst->h; y++) {
272 	csy += sy;
273 	*csay = (csy >> 16);
274 	csy &= 0xffff;
275 	csay++;
276     }
277 
278     csx = 0;
279     csax = sax;
280     for (x = 0; x < dst->w; x++) {
281 	csx += (*csax);
282 	csax++;
283     }
284     csy = 0;
285     csay = say;
286     for (y = 0; y < dst->h; y++) {
287 	csy += (*csay);
288 	csay++;
289     }
290 
291     /*
292      * Pointer setup
293      */
294     sp = csp = (Uint8 *) src->pixels;
295     dp = (Uint8 *) dst->pixels;
296     dgap = dst->pitch - dst->w;
297 
298     /*
299      * Draw
300      */
301     csay = say;
302     for (y = 0; y < dst->h; y++) {
303 	csax = sax;
304 	sp = csp;
305 	for (x = 0; x < dst->w; x++) {
306 	    /*
307 	     * Draw
308 	     */
309 	    *dp = *sp;
310 	    /*
311 	     * Advance source pointers
312 	     */
313 	    sp += (*csax);
314 	    csax++;
315 	    /*
316 	     * Advance destination pointer
317 	     */
318 	    dp++;
319 	}
320 	/*
321 	 * Advance source pointer (for row)
322 	 */
323 	csp += ((*csay) * src->pitch);
324 	csay++;
325 	/*
326 	 * Advance destination pointers
327 	 */
328 	dp += dgap;
329     }
330 
331 #ifdef __SYMBIAN32__
332 	HFree(sax);
333 	HFree(say);
334 #endif
335 
336     return (0);
337 }
338 
339 /*
340 
341  32bit Rotozoomer with optional anti-aliasing by bilinear interpolation.
342 
343  Rotates and zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
344 
345 */
346 
347 static
transformSurfaceRGBA(SDL_Surface * src,SDL_Surface * dst,int cx,int cy,int isin,int icos,int smooth)348 void transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int smooth)
349 {
350     int x, y, t1, t2, dx, dy, xd, yd, sdx, sdy, ax, ay, ex, ey, sw, sh;
351     tColorRGBA c00, c01, c10, c11;
352     tColorRGBA *pc, *sp;
353     int gap;
354 
355     /*
356      * Variable setup
357      */
358     xd = ((src->w - dst->w) << 15);
359     yd = ((src->h - dst->h) << 15);
360     ax = (cx << 16) - (icos * cx);
361     ay = (cy << 16) - (isin * cx);
362     sw = src->w - 1;
363     sh = src->h - 1;
364     pc = dst->pixels;
365     gap = dst->pitch - dst->w * 4;
366 
367     /*
368      * Switch between interpolating and non-interpolating code
369      */
370     if (smooth) {
371 	for (y = 0; y < dst->h; y++) {
372 	    dy = cy - y;
373 	    sdx = (ax + (isin * dy)) + xd;
374 	    sdy = (ay - (icos * dy)) + yd;
375 	    for (x = 0; x < dst->w; x++) {
376 		dx = (sdx >> 16);
377 		dy = (sdy >> 16);
378 		if ((dx >= -1) && (dy >= -1) && (dx < src->w) && (dy < src->h)) {
379 		    if ((dx >= 0) && (dy >= 0) && (dx < sw) && (dy < sh)) {
380 			sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
381 			sp += dx;
382 			c00 = *sp;
383 			sp += 1;
384 			c01 = *sp;
385 			sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
386 			sp -= 1;
387 			c10 = *sp;
388 			sp += 1;
389 			c11 = *sp;
390 		    } else if ((dx == sw) && (dy == sh)) {
391 			sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
392 			sp += dx;
393 			c00 = *sp;
394 			c01 = *sp;
395 			c10 = *sp;
396 			c11 = *sp;
397 		    } else if ((dx == -1) && (dy == -1)) {
398 			sp = (tColorRGBA *) (src->pixels);
399 			c00 = *sp;
400 			c01 = *sp;
401 			c10 = *sp;
402 			c11 = *sp;
403 		    } else if ((dx == -1) && (dy == sh)) {
404 			sp = (tColorRGBA *) (src->pixels);
405 			sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
406 			c00 = *sp;
407 			c01 = *sp;
408 			c10 = *sp;
409 			c11 = *sp;
410 		    } else if ((dx == sw) && (dy == -1)) {
411 			sp = (tColorRGBA *) (src->pixels);
412 			sp += dx;
413 			c00 = *sp;
414 			c01 = *sp;
415 			c10 = *sp;
416 			c11 = *sp;
417 		    } else if (dx == -1) {
418 			sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
419 			c00 = *sp;
420 			c01 = *sp;
421 			c10 = *sp;
422 			sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
423 			c11 = *sp;
424 		    } else if (dy == -1) {
425 			sp = (tColorRGBA *) (src->pixels);
426 			sp += dx;
427 			c00 = *sp;
428 			c01 = *sp;
429 			c10 = *sp;
430 			sp += 1;
431 			c11 = *sp;
432 		    } else if (dx == sw) {
433 			sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
434 			sp += dx;
435 			c00 = *sp;
436 			c01 = *sp;
437 			sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
438 			c10 = *sp;
439 			c11 = *sp;
440 		    } else if (dy == sh) {
441 			sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
442 			sp += dx;
443 			c00 = *sp;
444 			sp += 1;
445 			c01 = *sp;
446 			c10 = *sp;
447 			c11 = *sp;
448 		    }
449 		    /*
450 		     * Interpolate colors
451 		     */
452 		    ex = (sdx & 0xffff);
453 		    ey = (sdy & 0xffff);
454 		    t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff;
455 		    t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff;
456 		    pc->r = (((t2 - t1) * ey) >> 16) + t1;
457 		    t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff;
458 		    t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff;
459 		    pc->g = (((t2 - t1) * ey) >> 16) + t1;
460 		    t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff;
461 		    t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff;
462 		    pc->b = (((t2 - t1) * ey) >> 16) + t1;
463 		    t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff;
464 		    t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff;
465 		    pc->a = (((t2 - t1) * ey) >> 16) + t1;
466 		}
467 		sdx += icos;
468 		sdy += isin;
469 		pc++;
470 	    }
471 	    pc = (tColorRGBA *) ((Uint8 *) pc + gap);
472 	}
473     } else {
474 	for (y = 0; y < dst->h; y++) {
475 	    dy = cy - y;
476 	    sdx = (ax + (isin * dy)) + xd;
477 	    sdy = (ay - (icos * dy)) + yd;
478 	    for (x = 0; x < dst->w; x++) {
479 		dx = (short) (sdx >> 16);
480 		dy = (short) (sdy >> 16);
481 		if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
482 		    sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
483 		    sp += dx;
484 		    *pc = *sp;
485 		}
486 		sdx += icos;
487 		sdy += isin;
488 		pc++;
489 	    }
490 	    pc = (tColorRGBA *) ((Uint8 *) pc + gap);
491 	}
492     }
493 }
494 
495 /*
496 
497  8bit Rotozoomer without smoothing
498 
499  Rotates and zoomes 8bit palette/Y 'src' surface to 'dst' surface.
500 
501 */
502 
503 static
transformSurfaceY(SDL_Surface * src,SDL_Surface * dst,int cx,int cy,int isin,int icos)504 void transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos)
505 {
506     int x, y, dx, dy, xd, yd, sdx, sdy, ax, ay, sw, sh;
507     tColorY *pc, *sp;
508     int gap;
509     Uint32 colorkey = 0;
510 
511     /*
512      * Variable setup
513      */
514     xd = ((src->w - dst->w) << 15);
515     yd = ((src->h - dst->h) << 15);
516     ax = (cx << 16) - (icos * cx);
517     ay = (cy << 16) - (isin * cx);
518     sw = src->w - 1;
519     sh = src->h - 1;
520     pc = dst->pixels;
521     gap = dst->pitch - dst->w;
522     /*
523      * Clear surface to colorkey
524      */
525     TFB_GetColorKey (src, &colorkey);
526     memset(pc, (unsigned char) (colorkey & 0xff), dst->pitch * dst->h);
527     /*
528      * Iterate through destination surface
529      */
530     for (y = 0; y < dst->h; y++) {
531 	dy = cy - y;
532 	sdx = (ax + (isin * dy)) + xd;
533 	sdy = (ay - (icos * dy)) + yd;
534 	for (x = 0; x < dst->w; x++) {
535 	    dx = (short) (sdx >> 16);
536 	    dy = (short) (sdy >> 16);
537 	    if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
538 		sp = (tColorY *) (src->pixels);
539 		sp += (src->pitch * dy + dx);
540 		*pc = *sp;
541 	    }
542 	    sdx += icos;
543 	    sdy += isin;
544 	    pc++;
545 	}
546 	pc += gap;
547     }
548 }
549 
550 /*
551 
552  rotozoomSurface()
553 
554  Rotates and zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
555  'angle' is the rotation in degrees. 'zoom' a scaling factor. If 'smooth' is 1
556  then the destination 32bit surface is anti-aliased. If the surface is not 8bit
557  or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
558 
559 */
560 
561 #define VALUE_LIMIT	0.001
562 
563 
564 /* Local rotozoom-size function with trig result return */
565 
566 static
rotozoomSurfaceSizeTrig(int width,int height,double angle,double zoom,int * dstwidth,int * dstheight,double * canglezoom,double * sanglezoom)567 void rotozoomSurfaceSizeTrig(int width, int height, double angle, double zoom, int *dstwidth, int *dstheight,
568 			     double *canglezoom, double *sanglezoom)
569 {
570     double x, y, cx, cy, sx, sy;
571     double radangle;
572     int dstwidthhalf, dstheighthalf;
573 
574     /*
575      * Determine destination width and height by rotating a centered source box
576      */
577     radangle = angle * (M_PI / 180.0);
578     *sanglezoom = sin(radangle);
579     *canglezoom = cos(radangle);
580     *sanglezoom *= zoom;
581     *canglezoom *= zoom;
582     x = width / 2;
583     y = height / 2;
584     cx = *canglezoom * x;
585     cy = *canglezoom * y;
586     sx = *sanglezoom * x;
587     sy = *sanglezoom * y;
588     dstwidthhalf = MAX(ceil(fabs(cx) + fabs(sy)), 1);
589     dstheighthalf = MAX(ceil(fabs(sx) + fabs(cy)), 1);
590     *dstwidth = 2 * dstwidthhalf;
591     *dstheight = 2 * dstheighthalf;
592 }
593 
594 
595 /* Publically available rotozoom-size function */
596 
rotozoomSurfaceSize(int width,int height,double angle,double zoom,int * dstwidth,int * dstheight)597 void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth, int *dstheight)
598 {
599     double dummy_sanglezoom, dummy_canglezoom;
600 
601     rotozoomSurfaceSizeTrig(width, height, angle, zoom, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
602 }
603 
604 
605 /* Publically available rotozoom function */
606 
rotozoomSurface(SDL_Surface * src,double angle,double zoom,int smooth)607 SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth)
608 {
609     SDL_Surface *rz_src;
610     SDL_Surface *rz_dst;
611     double zoominv;
612     double sanglezoom, canglezoom, sanglezoominv, canglezoominv;
613     int dstwidthhalf, dstwidth, dstheighthalf, dstheight;
614     int is32bit;
615     int i, src_converted;
616 
617     /*
618      * Sanity check
619      */
620     if (src == NULL)
621 	return (NULL);
622 
623     /*
624      * Determine if source surface is 32bit or 8bit
625      */
626     is32bit = (src->format->BitsPerPixel == 32);
627     if ((is32bit) || (src->format->BitsPerPixel == 8)) {
628 	/*
629 	 * Use source surface 'as is'
630 	 */
631 	rz_src = src;
632 	src_converted = 0;
633     } else {
634 	/*
635 	 * New source surface is 32bit with a defined RGBA ordering
636 	 */
637 	rz_src =
638 	    SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
639 	SDL_BlitSurface(src, NULL, rz_src, NULL);
640 	src_converted = 1;
641 	is32bit = 1;
642     }
643 
644     /*
645      * Sanity check zoom factor
646      */
647     if (zoom < VALUE_LIMIT) {
648 	zoom = VALUE_LIMIT;
649     }
650     zoominv = 65536.0 / (zoom * zoom);
651 
652     /*
653      * Check if we have a rotozoom or just a zoom
654      */
655     if (fabs(angle) > VALUE_LIMIT) {
656 
657 	/*
658 	 * Angle!=0: full rotozoom
659 	 */
660 	/*
661 	 * -----------------------
662 	 */
663 
664 	/* Determine target size */
665 	rotozoomSurfaceSizeTrig(rz_src->w, rz_src->h, angle, zoom, &dstwidth, &dstheight, &canglezoom, &sanglezoom);
666 
667 	/*
668 	 * Calculate target factors from sin/cos and zoom
669 	 */
670 	sanglezoominv = sanglezoom;
671 	canglezoominv = canglezoom;
672 	sanglezoominv *= zoominv;
673 	canglezoominv *= zoominv;
674 
675 	/* Calculate half size */
676 	dstwidthhalf = dstwidth / 2;
677 	dstheighthalf = dstheight / 2;
678 
679 	/*
680 	 * Alloc space to completely contain the rotated surface
681 	 */
682 	rz_dst = NULL;
683 	if (is32bit) {
684 	    /*
685 	     * Target surface is 32bit with source RGBA/ABGR ordering
686 	     */
687 	    rz_dst =
688 		SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
689 				     rz_src->format->Rmask, rz_src->format->Gmask,
690 				     rz_src->format->Bmask, rz_src->format->Amask);
691 	} else {
692 	    /*
693 	     * Target surface is 8bit
694 	     */
695 	    rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
696 	}
697 
698 	/*
699 	 * Lock source surface
700 	 */
701 	SDL_LockSurface(rz_src);
702 	/*
703 	 * Check which kind of surface we have
704 	 */
705 	if (is32bit) {
706 	    /*
707 	     * Call the 32bit transformation routine to do the rotation (using alpha)
708 	     */
709 	    transformSurfaceRGBA(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
710 				 (int) (sanglezoominv), (int) (canglezoominv), smooth);
711 	    /*
712 	     * Turn on source-alpha support
713 	     */
714 	    TFB_SetSurfaceAlphaMod (rz_dst, 255);
715 	} else {
716 	    /*
717 	     * Copy palette and colorkey info
718 	     */
719 	    Uint32 srckey = 0;
720 	    TFB_GetColorKey (rz_src, &srckey);
721 	    for (i = 0; i < rz_src->format->palette->ncolors; i++) {
722 		rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
723 	    }
724 	    rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
725 	    /*
726 	     * Call the 8bit transformation routine to do the rotation
727 	     */
728 	    transformSurfaceY(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
729 			      (int) (sanglezoominv), (int) (canglezoominv));
730 	    TFB_SetColorKey(rz_dst, srckey, 1);
731 	}
732 	/*
733 	 * Unlock source surface
734 	 */
735 	SDL_UnlockSurface(rz_src);
736 
737     } else {
738 
739 	/*
740 	 * Angle=0: Just a zoom
741 	 */
742 	/*
743 	 * --------------------
744 	 */
745 
746 	/*
747 	 * Calculate target size
748 	 */
749 	zoomSurfaceSize(rz_src->w, rz_src->h, zoom, zoom, &dstwidth, &dstheight);
750 
751 	/*
752 	 * Alloc space to completely contain the zoomed surface
753 	 */
754 	rz_dst = NULL;
755 	if (is32bit) {
756 	    /*
757 	     * Target surface is 32bit with source RGBA/ABGR ordering
758 	     */
759 	    rz_dst =
760 		SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
761 				     rz_src->format->Rmask, rz_src->format->Gmask,
762 				     rz_src->format->Bmask, rz_src->format->Amask);
763 	} else {
764 	    /*
765 	     * Target surface is 8bit
766 	     */
767 	    rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
768 	}
769 
770 	/*
771 	 * Lock source surface
772 	 */
773 	SDL_LockSurface(rz_src);
774 	/*
775 	 * Check which kind of surface we have
776 	 */
777 	if (is32bit) {
778 	    /*
779 	     * Call the 32bit transformation routine to do the zooming (using alpha)
780 	     */
781 	    zoomSurfaceRGBA(rz_src, rz_dst, smooth);
782 	    /*
783 	     * Turn on source-alpha support
784 	     */
785 	    TFB_SetSurfaceAlphaMod (rz_dst, 255);
786 	} else {
787 	    /*
788 	     * Copy palette and colorkey info
789 	     */
790 	    Uint32 srckey = 0;
791 	    TFB_GetColorKey (rz_src, &srckey);
792 	    for (i = 0; i < rz_src->format->palette->ncolors; i++) {
793 		rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
794 	    }
795 	    rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
796 	    /*
797 	     * Call the 8bit transformation routine to do the zooming
798 	     */
799 	    zoomSurfaceY(rz_src, rz_dst);
800 	    TFB_SetColorKey(rz_dst, srckey, 1);
801 	}
802 	/*
803 	 * Unlock source surface
804 	 */
805 	SDL_UnlockSurface(rz_src);
806     }
807 
808     /*
809      * Cleanup temp surface
810      */
811     if (src_converted) {
812 	SDL_FreeSurface(rz_src);
813     }
814 
815     /*
816      * Return destination surface
817      */
818     return (rz_dst);
819 }
820 
821 /* Publically available rotate function */
822 
rotateSurface(SDL_Surface * src,SDL_Surface * dst,double angle,int smooth)823 int rotateSurface(SDL_Surface *src, SDL_Surface *dst, double angle, int smooth)
824 {
825     double zoominv;
826     double sanglezoom, canglezoom, sanglezoominv, canglezoominv;
827     int dstwidthhalf, dstwidth, dstheighthalf, dstheight;
828     int is32bit;
829     int i;
830 
831     /* Sanity check */
832     if (!src || !dst)
833 		return -1;
834     if (src->format->BitsPerPixel != dst->format->BitsPerPixel)
835 		return -1;
836 
837     /* Determine if source surface is 32bit or 8bit */
838     is32bit = (src->format->BitsPerPixel == 32);
839 
840     zoominv = 65536.0;
841 
842     /* Check if we have to rotate anything */
843     if (fabs(angle) <= VALUE_LIMIT)
844 	{
845 		SDL_BlitSurface(src, NULL, dst, NULL);
846 		return 0;
847 	}
848 
849 	/* Determine target size */
850 	rotozoomSurfaceSizeTrig(src->w, src->h, angle, 1, &dstwidth, &dstheight, &canglezoom, &sanglezoom);
851 
852 	/*
853 	 * Calculate target factors from sin/cos and zoom
854 	 */
855 	sanglezoominv = sanglezoom;
856 	canglezoominv = canglezoom;
857 	sanglezoominv *= zoominv;
858 	canglezoominv *= zoominv;
859 
860 	/* Calculate half size */
861 	dstwidthhalf = dstwidth / 2;
862 	dstheighthalf = dstheight / 2;
863 
864 	/* Check if the rotated surface will fit destination */
865 	if (dst->w < dstwidth || dst->h < dstheight)
866 		return -1;
867 
868 	/* Lock source surface */
869 	SDL_LockSurface(src);
870 	SDL_LockSurface(dst);
871 	/* Check which kind of surface we have */
872 	if (is32bit)
873 	{	/* Call the 32bit transformation routine to do the rotation (using alpha) */
874 	    transformSurfaceRGBA(src, dst, dstwidthhalf, dstheighthalf,
875 				 (int) (sanglezoominv), (int) (canglezoominv), smooth);
876 	}
877 	else
878 	{
879 	    /* Copy palette info */
880 	    for (i = 0; i < src->format->palette->ncolors; i++)
881 			dst->format->palette->colors[i] = src->format->palette->colors[i];
882 	    dst->format->palette->ncolors = src->format->palette->ncolors;
883 	    /* Call the 8bit transformation routine to do the rotation */
884 	    transformSurfaceY(src, dst, dstwidthhalf, dstheighthalf,
885 			      (int) (sanglezoominv), (int) (canglezoominv));
886 	}
887 	/* Unlock source surface */
888 	SDL_UnlockSurface(dst);
889 	SDL_UnlockSurface(src);
890 
891     return 0;
892 }
893 
894 /*
895 
896  zoomSurface()
897 
898  Zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
899  'zoomx' and 'zoomy' are scaling factors for width and height. If 'smooth' is 1
900  then the destination 32bit surface is anti-aliased. If the surface is not 8bit
901  or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
902 
903 */
904 
905 #define VALUE_LIMIT	0.001
906 
zoomSurfaceSize(int width,int height,double zoomx,double zoomy,int * dstwidth,int * dstheight)907 void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight)
908 {
909     /*
910      * Sanity check zoom factors
911      */
912     if (zoomx < VALUE_LIMIT) {
913 	zoomx = VALUE_LIMIT;
914     }
915     if (zoomy < VALUE_LIMIT) {
916 	zoomy = VALUE_LIMIT;
917     }
918 
919     /*
920      * Calculate target size
921      */
922     *dstwidth = (int) ((double) width * zoomx);
923     *dstheight = (int) ((double) height * zoomy);
924     if (*dstwidth < 1) {
925 	*dstwidth = 1;
926     }
927     if (*dstheight < 1) {
928 	*dstheight = 1;
929     }
930 }
931 
zoomSurface(SDL_Surface * src,double zoomx,double zoomy,int smooth)932 SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth)
933 {
934     SDL_Surface *rz_src;
935     SDL_Surface *rz_dst;
936     int dstwidth, dstheight;
937     int is32bit;
938     int i, src_converted;
939 
940     /*
941      * Sanity check
942      */
943     if (src == NULL)
944 	return (NULL);
945 
946     /*
947      * Determine if source surface is 32bit or 8bit
948      */
949     is32bit = (src->format->BitsPerPixel == 32);
950     if ((is32bit) || (src->format->BitsPerPixel == 8)) {
951 	/*
952 	 * Use source surface 'as is'
953 	 */
954 	rz_src = src;
955 	src_converted = 0;
956     } else {
957 	/*
958 	 * New source surface is 32bit with a defined RGBA ordering
959 	 */
960 	rz_src =
961 	    SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
962 	SDL_BlitSurface(src, NULL, rz_src, NULL);
963 	src_converted = 1;
964 	is32bit = 1;
965     }
966 
967     /* Get size if target */
968     zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
969 
970     /*
971      * Alloc space to completely contain the zoomed surface
972      */
973     rz_dst = NULL;
974     if (is32bit) {
975 	/*
976 	 * Target surface is 32bit with source RGBA/ABGR ordering
977 	 */
978 	rz_dst =
979 	    SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
980 				 rz_src->format->Rmask, rz_src->format->Gmask,
981 				 rz_src->format->Bmask, rz_src->format->Amask);
982     } else {
983 	/*
984 	 * Target surface is 8bit
985 	 */
986 	rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
987     }
988 
989     /*
990      * Lock source surface
991      */
992     SDL_LockSurface(rz_src);
993     /*
994      * Check which kind of surface we have
995      */
996     if (is32bit) {
997 	/*
998 	 * Call the 32bit transformation routine to do the zooming (using alpha)
999 	 */
1000 	zoomSurfaceRGBA(rz_src, rz_dst, smooth);
1001 	/*
1002 	 * Turn on source-alpha support
1003 	 */
1004 	TFB_SetSurfaceAlphaMod (rz_dst, 255);
1005     } else {
1006 	/*
1007 	 * Copy palette and colorkey info
1008 	 */
1009 	Uint32 srckey = 0;
1010 	TFB_GetColorKey (rz_src, &srckey);
1011 	for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1012 	    rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1013 	}
1014 	rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1015 	/*
1016 	 * Call the 8bit transformation routine to do the zooming
1017 	 */
1018 	zoomSurfaceY(rz_src, rz_dst);
1019 	TFB_SetColorKey(rz_dst, srckey, 0);
1020     }
1021     /*
1022      * Unlock source surface
1023      */
1024     SDL_UnlockSurface(rz_src);
1025 
1026     /*
1027      * Cleanup temp surface
1028      */
1029     if (src_converted) {
1030 	SDL_FreeSurface(rz_src);
1031     }
1032 
1033     /*
1034      * Return destination surface
1035      */
1036     return (rz_dst);
1037 }
1038 
1039