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