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