SDL3_gfx 1.0.0
Graphics primitives and surface functions for SDL3
C:/Users/ADMIN/Documents/GitHub/SDL3_gfx/SDL3_rotozoom.c
Go to the documentation of this file.
1/*
2
3SDL3_rotozoom.c: rotozoomer, zoomer and shrinker for 32bit or 8bit surfaces
4
5Copyright (C) 2012-2014 Andreas Schiffler
6
7This software is provided 'as-is', without any express or implied
8warranty. In no event will the authors be held liable for any damages
9arising from the use of this software.
10
11Permission is granted to anyone to use this software for any purpose,
12including commercial applications, and to alter it and redistribute it
13freely, subject to the following restrictions:
14
151. The origin of this software must not be misrepresented; you must not
16claim that you wrote the original software. If you use this software
17in a product, an acknowledgment in the product documentation would be
18appreciated but is not required.
19
202. Altered source versions must be plainly marked as such, and must not be
21misrepresented as being the original software.
22
233. This notice may not be removed or altered from any source
24distribution.
25
26Andreas 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 "SDL3_rotozoom.h"
38
42#define MAX(a,b) (((a) > (b)) ? (a) : (b))
43
54#define GUARD_ROWS (2)
55
59#define VALUE_LIMIT 0.001
60
64Uint32 _colorkey(SDL_Surface *src)
65{
66 Uint32 key = 0;
67 SDL_GetSurfaceColorKey(src, &key);
68 return key;
69}
70
71
87int _shrinkSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
88{
89 int x, y, dx, dy, dgap, ra, ga, ba, aa;
90 int n_average;
91 SDL_Color *sp, *osp, *oosp;
92 SDL_Color *dp;
93
94 /*
95 * Averaging integer shrink
96 */
97
98 /* Precalculate division factor */
99 n_average = factorx*factory;
100
101 /*
102 * Scan destination
103 */
104 sp = (SDL_Color *) src->pixels;
105
106 dp = (SDL_Color *) dst->pixels;
107 dgap = dst->pitch - dst->w * 4;
108
109 for (y = 0; y < dst->h; y++) {
110
111 osp=sp;
112 for (x = 0; x < dst->w; x++) {
113
114 /* Trace out source box and accumulate */
115 oosp=sp;
116 ra=ga=ba=aa=0;
117 for (dy=0; dy < factory; dy++) {
118 for (dx=0; dx < factorx; dx++) {
119 ra += sp->r;
120 ga += sp->g;
121 ba += sp->b;
122 aa += sp->a;
123
124 sp++;
125 }
126 /* src dx loop */
127 sp = (SDL_Color *)((Uint8*)sp + (src->pitch - 4*factorx)); // next y
128 }
129 /* src dy loop */
130
131 /* next box-x */
132 sp = (SDL_Color *)((Uint8*)oosp + 4*factorx);
133
134 /* Store result in destination */
135 dp->r = ra/n_average;
136 dp->g = ga/n_average;
137 dp->b = ba/n_average;
138 dp->a = aa/n_average;
139
140 /*
141 * Advance destination pointer
142 */
143 dp++;
144 }
145 /* dst x loop */
146
147 /* next box-y */
148 sp = (SDL_Color *)((Uint8*)osp + src->pitch*factory);
149
150 /*
151 * Advance destination pointers
152 */
153 dp = (SDL_Color *) ((Uint8 *) dp + dgap);
154 }
155 /* dst y loop */
156
157 return (0);
158}
159
175int _shrinkSurfaceY(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
176{
177 int x, y, dx, dy, dgap, a;
178 int n_average;
179 Uint8 *sp, *osp, *oosp;
180 Uint8 *dp;
181
182 /*
183 * Averaging integer shrink
184 */
185
186 /* Precalculate division factor */
187 n_average = factorx*factory;
188
189 /*
190 * Scan destination
191 */
192 sp = (Uint8 *) src->pixels;
193
194 dp = (Uint8 *) dst->pixels;
195 dgap = dst->pitch - dst->w;
196
197 for (y = 0; y < dst->h; y++) {
198
199 osp=sp;
200 for (x = 0; x < dst->w; x++) {
201
202 /* Trace out source box and accumulate */
203 oosp=sp;
204 a=0;
205 for (dy=0; dy < factory; dy++) {
206 for (dx=0; dx < factorx; dx++) {
207 a += (*sp);
208 /* next x */
209 sp++;
210 }
211 /* end src dx loop */
212 /* next y */
213 sp = (Uint8 *)((Uint8*)sp + (src->pitch - factorx));
214 }
215 /* end src dy loop */
216
217 /* next box-x */
218 sp = (Uint8 *)((Uint8*)oosp + factorx);
219
220 /* Store result in destination */
221 *dp = a/n_average;
222
223 /*
224 * Advance destination pointer
225 */
226 dp++;
227 }
228 /* end dst x loop */
229
230 /* next box-y */
231 sp = (Uint8 *)((Uint8*)osp + src->pitch*factory);
232
233 /*
234 * Advance destination pointers
235 */
236 dp = (Uint8 *)((Uint8 *)dp + dgap);
237 }
238 /* end dst y loop */
239
240 return (0);
241}
242
258int _zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy, int smooth)
259{
260 int x, y, sx, sy, ssx, ssy, *sax, *say, *csax, *csay, *salast, csx, csy, ex, ey, cx, cy, sstep, sstepx, sstepy;
261 SDL_Color *c00, *c01, *c10, *c11;
262 SDL_Color *sp, *csp, *dp;
263 int spixelgap, spixelw, spixelh, dgap, t1, t2;
264
265 /*
266 * Allocate memory for row/column increments
267 */
268 if ((sax = (int *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
269 return (-1);
270 }
271 if ((say = (int *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
272 free(sax);
273 return (-1);
274 }
275
276 /*
277 * Precalculate row increments
278 */
279 spixelw = (src->w - 1);
280 spixelh = (src->h - 1);
281 if (smooth) {
282 sx = (int) (65536.0 * (float) spixelw / (float) (dst->w - 1));
283 sy = (int) (65536.0 * (float) spixelh / (float) (dst->h - 1));
284 } else {
285 sx = (int) (65536.0 * (float) (src->w) / (float) (dst->w));
286 sy = (int) (65536.0 * (float) (src->h) / (float) (dst->h));
287 }
288
289 /* Maximum scaled source size */
290 ssx = (src->w << 16) - 1;
291 ssy = (src->h << 16) - 1;
292
293 /* Precalculate horizontal row increments */
294 csx = 0;
295 csax = sax;
296 for (x = 0; x <= dst->w; x++) {
297 *csax = csx;
298 csax++;
299 csx += sx;
300
301 /* Guard from overflows */
302 if (csx > ssx) {
303 csx = ssx;
304 }
305 }
306
307 /* Precalculate vertical row increments */
308 csy = 0;
309 csay = say;
310 for (y = 0; y <= dst->h; y++) {
311 *csay = csy;
312 csay++;
313 csy += sy;
314
315 /* Guard from overflows */
316 if (csy > ssy) {
317 csy = ssy;
318 }
319 }
320
321 sp = (SDL_Color *) src->pixels;
322 dp = (SDL_Color *) dst->pixels;
323 dgap = dst->pitch - dst->w * 4;
324 spixelgap = src->pitch/4;
325
326 if (flipx) sp += spixelw;
327 if (flipy) sp += (spixelgap * spixelh);
328
329 /*
330 * Switch between interpolating and non-interpolating code
331 */
332 if (smooth) {
333
334 /*
335 * Interpolating Zoom
336 */
337 csay = say;
338 for (y = 0; y < dst->h; y++) {
339 csp = sp;
340 csax = sax;
341 for (x = 0; x < dst->w; x++) {
342 /*
343 * Setup color source pointers
344 */
345 ex = (*csax & 0xffff);
346 ey = (*csay & 0xffff);
347 cx = (*csax >> 16);
348 cy = (*csay >> 16);
349 sstepx = cx < spixelw;
350 sstepy = cy < spixelh;
351 c00 = sp;
352 c01 = sp;
353 c10 = sp;
354 if (sstepy) {
355 if (flipy) {
356 c10 -= spixelgap;
357 } else {
358 c10 += spixelgap;
359 }
360 }
361 c11 = c10;
362 if (sstepx) {
363 if (flipx) {
364 c01--;
365 c11--;
366 } else {
367 c01++;
368 c11++;
369 }
370 }
371
372 /*
373 * Draw and interpolate colors
374 */
375 t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
376 t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
377 dp->r = (((t2 - t1) * ey) >> 16) + t1;
378 t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff;
379 t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff;
380 dp->g = (((t2 - t1) * ey) >> 16) + t1;
381 t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff;
382 t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff;
383 dp->b = (((t2 - t1) * ey) >> 16) + t1;
384 t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff;
385 t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff;
386 dp->a = (((t2 - t1) * ey) >> 16) + t1;
387 /*
388 * Advance source pointer x
389 */
390 salast = csax;
391 csax++;
392 sstep = (*csax >> 16) - (*salast >> 16);
393 if (flipx) {
394 sp -= sstep;
395 } else {
396 sp += sstep;
397 }
398
399 /*
400 * Advance destination pointer x
401 */
402 dp++;
403 }
404 /*
405 * Advance source pointer y
406 */
407 salast = csay;
408 csay++;
409 sstep = (*csay >> 16) - (*salast >> 16);
410 sstep *= spixelgap;
411 if (flipy) {
412 sp = csp - sstep;
413 } else {
414 sp = csp + sstep;
415 }
416
417 /*
418 * Advance destination pointer y
419 */
420 dp = (SDL_Color *) ((Uint8 *) dp + dgap);
421 }
422 } else {
423 /*
424 * Non-Interpolating Zoom
425 */
426 csay = say;
427 for (y = 0; y < dst->h; y++) {
428 csp = sp;
429 csax = sax;
430 for (x = 0; x < dst->w; x++) {
431 /*
432 * Draw
433 */
434 *dp = *sp;
435
436 /*
437 * Advance source pointer x
438 */
439 salast = csax;
440 csax++;
441 sstep = (*csax >> 16) - (*salast >> 16);
442 if (flipx) sstep = -sstep;
443 sp += sstep;
444
445 /*
446 * Advance destination pointer x
447 */
448 dp++;
449 }
450 /*
451 * Advance source pointer y
452 */
453 salast = csay;
454 csay++;
455 sstep = (*csay >> 16) - (*salast >> 16);
456 sstep *= spixelgap;
457 if (flipy) sstep = -sstep;
458 sp = csp + sstep;
459
460 /*
461 * Advance destination pointer y
462 */
463 dp = (SDL_Color *) ((Uint8 *) dp + dgap);
464 }
465 }
466
467 /*
468 * Remove temp arrays
469 */
470 free(sax);
471 free(say);
472
473 return (0);
474}
475
491int _zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy)
492{
493 int x, y;
494 Uint32 *sax, *say, *csax, *csay;
495 int csx, csy;
496 Uint8 *sp, *dp, *csp;
497 int dgap;
498
499 /*
500 * Allocate memory for row increments
501 */
502 if ((sax = (Uint32 *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
503 return (-1);
504 }
505 if ((say = (Uint32 *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
506 free(sax);
507 return (-1);
508 }
509
510 /*
511 * Pointer setup
512 */
513 sp = csp = (Uint8 *) src->pixels;
514 dp = (Uint8 *) dst->pixels;
515 dgap = dst->pitch - dst->w;
516
517 if (flipx) csp += (src->w-1);
518 if (flipy) csp = ( (Uint8*)csp + src->pitch*(src->h-1) );
519
520 /*
521 * Precalculate row increments
522 */
523 csx = 0;
524 csax = sax;
525 for (x = 0; x < dst->w; x++) {
526 csx += src->w;
527 *csax = 0;
528 while (csx >= dst->w) {
529 csx -= dst->w;
530 (*csax)++;
531 }
532 (*csax) = (*csax) * (flipx ? -1 : 1);
533 csax++;
534 }
535 csy = 0;
536 csay = say;
537 for (y = 0; y < dst->h; y++) {
538 csy += src->h;
539 *csay = 0;
540 while (csy >= dst->h) {
541 csy -= dst->h;
542 (*csay)++;
543 }
544 (*csay) = (*csay) * (flipy ? -1 : 1);
545 csay++;
546 }
547
548 /*
549 * Draw
550 */
551 csay = say;
552 for (y = 0; y < dst->h; y++) {
553 csax = sax;
554 sp = csp;
555 for (x = 0; x < dst->w; x++) {
556 /*
557 * Draw
558 */
559 *dp = *sp;
560 /*
561 * Advance source pointers
562 */
563 sp += (*csax);
564 csax++;
565 /*
566 * Advance destination pointer
567 */
568 dp++;
569 }
570 /*
571 * Advance source pointer (for row)
572 */
573 csp += ((*csay) * src->pitch);
574 csay++;
575
576 /*
577 * Advance destination pointers
578 */
579 dp += dgap;
580 }
581
582 /*
583 * Remove temp arrays
584 */
585 free(sax);
586 free(say);
587
588 return (0);
589}
590
610void _transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy, int smooth)
611{
612 int x, y, t1, t2, dx, dy, xd, yd, sdx, sdy, ax, ay, ex, ey, sw, sh;
613 SDL_Color c00, c01, c10, c11, cswap;
614 SDL_Color *pc, *sp;
615 int gap;
616
617 /*
618 * Variable setup
619 */
620 xd = ((src->w - dst->w) << 15);
621 yd = ((src->h - dst->h) << 15);
622 ax = (cx << 16) - (icos * cx);
623 ay = (cy << 16) - (isin * cx);
624 sw = src->w - 1;
625 sh = src->h - 1;
626 pc = (SDL_Color *) dst->pixels;
627 gap = dst->pitch - dst->w * 4;
628
629 /*
630 * Switch between interpolating and non-interpolating code
631 */
632 if (smooth) {
633 for (y = 0; y < dst->h; y++) {
634 dy = cy - y;
635 sdx = (ax + (isin * dy)) + xd;
636 sdy = (ay - (icos * dy)) + yd;
637 for (x = 0; x < dst->w; x++) {
638 dx = (sdx >> 16);
639 dy = (sdy >> 16);
640 if (flipx) dx = sw - dx;
641 if (flipy) dy = sh - dy;
642 if ((dx > -1) && (dy > -1) && (dx < (src->w-1)) && (dy < (src->h-1))) {
643 sp = (SDL_Color *)src->pixels;;
644 sp += ((src->pitch/4) * dy);
645 sp += dx;
646 c00 = *sp;
647 sp += 1;
648 c01 = *sp;
649 sp += (src->pitch/4);
650 c11 = *sp;
651 sp -= 1;
652 c10 = *sp;
653 if (flipx) {
654 cswap = c00; c00=c01; c01=cswap;
655 cswap = c10; c10=c11; c11=cswap;
656 }
657 if (flipy) {
658 cswap = c00; c00=c10; c10=cswap;
659 cswap = c01; c01=c11; c11=cswap;
660 }
661 /*
662 * Interpolate colors
663 */
664 ex = (sdx & 0xffff);
665 ey = (sdy & 0xffff);
666 t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff;
667 t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff;
668 pc->r = (((t2 - t1) * ey) >> 16) + t1;
669 t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff;
670 t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff;
671 pc->g = (((t2 - t1) * ey) >> 16) + t1;
672 t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff;
673 t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff;
674 pc->b = (((t2 - t1) * ey) >> 16) + t1;
675 t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff;
676 t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff;
677 pc->a = (((t2 - t1) * ey) >> 16) + t1;
678 }
679 sdx += icos;
680 sdy += isin;
681 pc++;
682 }
683 pc = (SDL_Color *) ((Uint8 *) pc + gap);
684 }
685 } else {
686 for (y = 0; y < dst->h; y++) {
687 dy = cy - y;
688 sdx = (ax + (isin * dy)) + xd;
689 sdy = (ay - (icos * dy)) + yd;
690 for (x = 0; x < dst->w; x++) {
691 dx = (short) (sdx >> 16);
692 dy = (short) (sdy >> 16);
693 if (flipx) dx = (src->w-1)-dx;
694 if (flipy) dy = (src->h-1)-dy;
695 if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
696 sp = (SDL_Color *) ((Uint8 *) src->pixels + src->pitch * dy);
697 sp += dx;
698 *pc = *sp;
699 }
700 sdx += icos;
701 sdy += isin;
702 pc++;
703 }
704 pc = (SDL_Color *) ((Uint8 *) pc + gap);
705 }
706 }
707}
708
727void transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy)
728{
729 int x, y, dx, dy, xd, yd, sdx, sdy, ax, ay;
730 Uint8 *pc, *sp;
731 int gap;
732
733 /*
734 * Variable setup
735 */
736 xd = ((src->w - dst->w) << 15);
737 yd = ((src->h - dst->h) << 15);
738 ax = (cx << 16) - (icos * cx);
739 ay = (cy << 16) - (isin * cx);
740 pc = (Uint8 *) dst->pixels;
741 gap = dst->pitch - dst->w;
742 /*
743 * Clear surface to colorkey
744 */
745 memset(pc, (int)(_colorkey(src) & 0xff), dst->pitch * dst->h);
746 /*
747 * Iterate through destination surface
748 */
749 for (y = 0; y < dst->h; y++) {
750 dy = cy - y;
751 sdx = (ax + (isin * dy)) + xd;
752 sdy = (ay - (icos * dy)) + yd;
753 for (x = 0; x < dst->w; x++) {
754 dx = (short) (sdx >> 16);
755 dy = (short) (sdy >> 16);
756 if (flipx) dx = (src->w-1)-dx;
757 if (flipy) dy = (src->h-1)-dy;
758 if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
759 sp = (Uint8 *) (src->pixels);
760 sp += (src->pitch * dy + dx);
761 *pc = *sp;
762 }
763 sdx += icos;
764 sdy += isin;
765 pc++;
766 }
767 pc += gap;
768 }
769}
770
784SDL_Surface* rotateSurface90Degrees(SDL_Surface* src, int numClockwiseTurns)
785{
786 int row, col, newWidth, newHeight;
787 int bpp, bpr;
788 SDL_Surface* dst;
789 Uint8* srcBuf;
790 Uint8* dstBuf;
791 int normalizedClockwiseTurns;
792 const SDL_PixelFormatDetails* details;
793
794 /* Has to be a valid surface pointer and be a Nbit surface where n is divisible by 8 */
795 if (!src ||
796 !src->format) {
797 SDL_SetError("NULL source surface or source surface format");
798 return NULL;
799 }
800
801 details = SDL_GetPixelFormatDetails(src->format);
802 if ((details->bits_per_pixel % 8) != 0) {
803 SDL_SetError("Invalid source surface bit depth");
804 return NULL;
805 }
806
807 /* normalize numClockwiseTurns */
808 normalizedClockwiseTurns = (numClockwiseTurns % 4);
809 if (normalizedClockwiseTurns < 0) {
810 normalizedClockwiseTurns += 4;
811 }
812
813 /* If turns are even, our new width/height will be the same as the source surface */
814 if (normalizedClockwiseTurns % 2) {
815 newWidth = src->h;
816 newHeight = src->w;
817 } else {
818 newWidth = src->w;
819 newHeight = src->h;
820 }
821
822 dst = SDL_CreateSurface(newWidth, newHeight, src->format);
823 if(!dst) {
824 SDL_SetError("Could not create destination surface");
825 return NULL;
826 }
827
828 if (SDL_MUSTLOCK(src)) {
829 SDL_LockSurface(src);
830 }
831 if (SDL_MUSTLOCK(dst)) {
832 SDL_LockSurface(dst);
833 }
834
835 /* Calculate byte-per-pixel */
836 bpp = details->bits_per_pixel / 8;
837
838 switch(normalizedClockwiseTurns) {
839 case 0: /* Make a copy of the surface */
840 {
841 /* Unfortunately SDL_BlitSurface cannot be used to make a copy of the surface
842 since it does not preserve alpha. */
843
844 if (src->pitch == dst->pitch) {
845 /* If the pitch is the same for both surfaces, the memory can be copied all at once. */
846 memcpy(dst->pixels, src->pixels, (src->h * src->pitch));
847 }
848 else
849 {
850 /* If the pitch differs, copy each row separately */
851 srcBuf = (Uint8*)(src->pixels);
852 dstBuf = (Uint8*)(dst->pixels);
853 bpr = src->w * bpp;
854 for (row = 0; row < src->h; row++) {
855 memcpy(dstBuf, srcBuf, bpr);
856 srcBuf += src->pitch;
857 dstBuf += dst->pitch;
858 }
859 }
860 }
861 break;
862
863 /* rotate clockwise */
864 case 1: /* rotated 90 degrees clockwise */
865 {
866 for (row = 0; row < src->h; ++row) {
867 srcBuf = (Uint8*)(src->pixels) + (row * src->pitch);
868 dstBuf = (Uint8*)(dst->pixels) + (dst->w - row - 1) * bpp;
869 for (col = 0; col < src->w; ++col) {
870 memcpy (dstBuf, srcBuf, bpp);
871 srcBuf += bpp;
872 dstBuf += dst->pitch;
873 }
874 }
875 }
876 break;
877
878 case 2: /* rotated 180 degrees clockwise */
879 {
880 for (row = 0; row < src->h; ++row) {
881 srcBuf = (Uint8*)(src->pixels) + (row * src->pitch);
882 dstBuf = (Uint8*)(dst->pixels) + ((dst->h - row - 1) * dst->pitch) + (dst->w - 1) * bpp;
883 for (col = 0; col < src->w; ++col) {
884 memcpy (dstBuf, srcBuf, bpp);
885 srcBuf += bpp;
886 dstBuf -= bpp;
887 }
888 }
889 }
890 break;
891
892 case 3: /* rotated 270 degrees clockwise */
893 {
894 for (row = 0; row < src->h; ++row) {
895 srcBuf = (Uint8*)(src->pixels) + (row * src->pitch);
896 dstBuf = (Uint8*)(dst->pixels) + (row * bpp) + ((dst->h - 1) * dst->pitch);
897 for (col = 0; col < src->w; ++col) {
898 memcpy (dstBuf, srcBuf, bpp);
899 srcBuf += bpp;
900 dstBuf -= dst->pitch;
901 }
902 }
903 }
904 break;
905 }
906 /* end switch */
907
908 if (SDL_MUSTLOCK(src)) {
909 SDL_UnlockSurface(src);
910 }
911 if (SDL_MUSTLOCK(dst)) {
912 SDL_UnlockSurface(dst);
913 }
914
915 return dst;
916}
917
918
933void _rotozoomSurfaceSizeTrig(int width, int height, double angle, double zoomx, double zoomy,
934 int *dstwidth, int *dstheight,
935 double *canglezoom, double *sanglezoom)
936{
937 double x, y, cx, cy, sx, sy;
938 double radangle;
939 int dstwidthhalf, dstheighthalf;
940
941 /*
942 * Determine destination width and height by rotating a centered source box
943 */
944 radangle = angle * (M_PI / 180.0);
945 *sanglezoom = sin(radangle);
946 *canglezoom = cos(radangle);
947 *sanglezoom *= zoomx;
948 *canglezoom *= zoomy;
949 x = (double)(width / 2);
950 y = (double)(height / 2);
951 cx = *canglezoom * x;
952 cy = *canglezoom * y;
953 sx = *sanglezoom * x;
954 sy = *sanglezoom * y;
955
956 dstwidthhalf = MAX((int)
957 ceil(MAX(MAX(MAX(fabs(cx + sy), fabs(cx - sy)), fabs(-cx + sy)), fabs(-cx - sy))), 1);
958 dstheighthalf = MAX((int)
959 ceil(MAX(MAX(MAX(fabs(sx + cy), fabs(sx - cy)), fabs(-sx + cy)), fabs(-sx - cy))), 1);
960 *dstwidth = 2 * dstwidthhalf;
961 *dstheight = 2 * dstheighthalf;
962}
963
975void rotozoomSurfaceSizeXY(int width, int height, double angle, double zoomx, double zoomy, int *dstwidth, int *dstheight)
976{
977 double dummy_sanglezoom, dummy_canglezoom;
978
979 _rotozoomSurfaceSizeTrig(width, height, angle, zoomx, zoomy, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
980}
981
992void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth, int *dstheight)
993{
994 double dummy_sanglezoom, dummy_canglezoom;
995
996 _rotozoomSurfaceSizeTrig(width, height, angle, zoom, zoom, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
997}
998
1014SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth)
1015{
1016 return rotozoomSurfaceXY(src, angle, zoom, zoom, smooth);
1017}
1018
1035SDL_Surface *rotozoomSurfaceXY(SDL_Surface * src, double angle, double zoomx, double zoomy, int smooth)
1036{
1037 SDL_Surface *rz_src;
1038 SDL_Surface *rz_dst;
1039 double zoominv;
1040 double sanglezoom, canglezoom, sanglezoominv, canglezoominv;
1041 int dstwidthhalf, dstwidth, dstheighthalf, dstheight;
1042 int is32bit;
1043 int i, src_converted;
1044 int flipx,flipy;
1045 const SDL_PixelFormatDetails* details;
1046 SDL_Palette* pal_dst;
1047 SDL_Palette* pal_src;
1048
1049 /*
1050 * Sanity check
1051 */
1052 if (src == NULL) {
1053 return (NULL);
1054 }
1055
1056 /*
1057 * Determine if source surface is 32bit or 8bit
1058 */
1059 details = SDL_GetPixelFormatDetails(src->format);
1060 is32bit = (details->bits_per_pixel == 32);
1061 if ((is32bit) || (details->bits_per_pixel == 8)) {
1062 /*
1063 * Use source surface 'as is'
1064 */
1065 rz_src = src;
1066 src_converted = 0;
1067 } else {
1068 /*
1069 * New source surface is 32bit with a defined RGBA ordering
1070 */
1071 rz_src =
1072 SDL_CreateSurface(src->w, src->h, SDL_PIXELFORMAT_RGBA32);
1073
1074 SDL_BlitSurface(src, NULL, rz_src, NULL);
1075
1076 src_converted = 1;
1077 is32bit = 1;
1078 }
1079
1080 /*
1081 * Sanity check zoom factor
1082 */
1083 flipx = (zoomx<0.0);
1084 if (flipx) zoomx=-zoomx;
1085 flipy = (zoomy<0.0);
1086 if (flipy) zoomy=-zoomy;
1087 if (zoomx < VALUE_LIMIT) zoomx = VALUE_LIMIT;
1088 if (zoomy < VALUE_LIMIT) zoomy = VALUE_LIMIT;
1089 zoominv = 65536.0 / (zoomx * zoomx);
1090
1091 /*
1092 * Check if we have a rotozoom or just a zoom
1093 */
1094 if (fabs(angle) > VALUE_LIMIT) {
1095
1096 /*
1097 * Angle!=0: full rotozoom
1098 */
1099 /*
1100 * -----------------------
1101 */
1102
1103 /* Determine target size */
1104 _rotozoomSurfaceSizeTrig(rz_src->w, rz_src->h, angle, zoomx, zoomy, &dstwidth, &dstheight, &canglezoom, &sanglezoom);
1105
1106 /*
1107 * Calculate target factors from sin/cos and zoom
1108 */
1109 sanglezoominv = sanglezoom;
1110 canglezoominv = canglezoom;
1111 sanglezoominv *= zoominv;
1112 canglezoominv *= zoominv;
1113
1114 /* Calculate half size */
1115 dstwidthhalf = dstwidth / 2;
1116 dstheighthalf = dstheight / 2;
1117
1118 /*
1119 * Alloc space to completely contain the rotated surface
1120 */
1121 rz_dst = NULL;
1122 if (is32bit) {
1123 /*
1124 * Target surface is 32bit with source RGBA/ABGR ordering
1125 */
1126 rz_dst =
1127 SDL_CreateSurface(dstwidth, dstheight + GUARD_ROWS, rz_src->format);
1128 } else {
1129 /*
1130 * Target surface is 8bit
1131 */
1132 rz_dst = SDL_CreateSurface(dstwidth, dstheight + GUARD_ROWS, SDL_PIXELFORMAT_INDEX8);
1133 pal_dst = SDL_CreateSurfacePalette(rz_dst);
1134 }
1135
1136 /* Check target */
1137 if (rz_dst == NULL)
1138 return NULL;
1139
1140 /* Adjust for guard rows */
1141 rz_dst->h = dstheight;
1142
1143 /*
1144 * Lock source surface
1145 */
1146 if (SDL_MUSTLOCK(rz_src)) {
1147 SDL_LockSurface(rz_src);
1148 }
1149
1150 /*
1151 * Check which kind of surface we have
1152 */
1153 if (is32bit) {
1154 /*
1155 * Call the 32bit transformation routine to do the rotation (using alpha)
1156 */
1157 _transformSurfaceRGBA(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
1158 (int) (sanglezoominv), (int) (canglezoominv),
1159 flipx, flipy,
1160 smooth);
1161 } else {
1162 /*
1163 * Copy palette and colorkey info
1164 */
1165 pal_src = SDL_GetSurfacePalette(rz_src);
1166 for (i = 0; i < pal_src->ncolors; i++) {
1167 pal_dst->colors[i] = pal_src->colors[i];
1168 }
1169 pal_dst->ncolors = pal_src->ncolors;
1170 /*
1171 * Call the 8bit transformation routine to do the rotation
1172 */
1173 transformSurfaceY(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
1174 (int) (sanglezoominv), (int) (canglezoominv),
1175 flipx, flipy);
1176 }
1177 /*
1178 * Unlock source surface
1179 */
1180 if (SDL_MUSTLOCK(rz_src)) {
1181 SDL_UnlockSurface(rz_src);
1182 }
1183
1184 } else {
1185
1186 /*
1187 * Angle=0: Just a zoom
1188 */
1189 /*
1190 * --------------------
1191 */
1192
1193 /*
1194 * Calculate target size
1195 */
1196 zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
1197
1198 /*
1199 * Alloc space to completely contain the zoomed surface
1200 */
1201 rz_dst = NULL;
1202 if (is32bit) {
1203 /*
1204 * Target surface is 32bit with source RGBA/ABGR ordering
1205 */
1206 rz_dst =
1207 SDL_CreateSurface(dstwidth, dstheight + GUARD_ROWS, rz_src->format);
1208 } else {
1209 /*
1210 * Target surface is 8bit
1211 */
1212 rz_dst = SDL_CreateSurface(dstwidth, dstheight + GUARD_ROWS, SDL_PIXELFORMAT_INDEX8);
1213 pal_dst = SDL_CreateSurfacePalette(rz_dst);
1214 }
1215
1216 /* Check target */
1217 if (rz_dst == NULL)
1218 return NULL;
1219
1220 /* Adjust for guard rows */
1221 rz_dst->h = dstheight;
1222
1223 /*
1224 * Lock source surface
1225 */
1226 if (SDL_MUSTLOCK(rz_src)) {
1227 SDL_LockSurface(rz_src);
1228 }
1229
1230 /*
1231 * Check which kind of surface we have
1232 */
1233 if (is32bit) {
1234 /*
1235 * Call the 32bit transformation routine to do the zooming (using alpha)
1236 */
1237 _zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
1238
1239 } else {
1240 /*
1241 * Copy palette and colorkey info
1242 */
1243 pal_src = SDL_GetSurfacePalette(rz_src);
1244 for (i = 0; i < pal_src->ncolors; i++) {
1245 pal_dst->colors[i] = pal_src->colors[i];
1246 }
1247 pal_dst->ncolors = pal_src->ncolors;
1248
1249 /*
1250 * Call the 8bit transformation routine to do the zooming
1251 */
1252 _zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
1253 }
1254
1255 /*
1256 * Unlock source surface
1257 */
1258 if (SDL_MUSTLOCK(rz_src)) {
1259 SDL_UnlockSurface(rz_src);
1260 }
1261 }
1262
1263 /*
1264 * Cleanup temp surface
1265 */
1266 if (src_converted) {
1267 SDL_DestroySurface(rz_src);
1268 }
1269
1270 /*
1271 * Return destination surface
1272 */
1273 return (rz_dst);
1274}
1275
1288void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight)
1289{
1290 /*
1291 * Make zoom factors positive
1292 */
1293 int flipx, flipy;
1294 flipx = (zoomx<0.0);
1295 if (flipx) zoomx = -zoomx;
1296 flipy = (zoomy<0.0);
1297 if (flipy) zoomy = -zoomy;
1298
1299 /*
1300 * Sanity check zoom factors
1301 */
1302 if (zoomx < VALUE_LIMIT) {
1303 zoomx = VALUE_LIMIT;
1304 }
1305 if (zoomy < VALUE_LIMIT) {
1306 zoomy = VALUE_LIMIT;
1307 }
1308
1309 /*
1310 * Calculate target size
1311 */
1312 *dstwidth = (int) floor(((double) width * zoomx) + 0.5);
1313 *dstheight = (int) floor(((double) height * zoomy) + 0.5);
1314 if (*dstwidth < 1) {
1315 *dstwidth = 1;
1316 }
1317 if (*dstheight < 1) {
1318 *dstheight = 1;
1319 }
1320}
1321
1338SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth)
1339{
1340 SDL_Surface *rz_src;
1341 SDL_Surface *rz_dst;
1342 int dstwidth, dstheight;
1343 int is32bit;
1344 int i, src_converted;
1345 int flipx, flipy;
1346 const SDL_PixelFormatDetails* details;
1347 SDL_Palette* pal_src;
1348 SDL_Palette* pal_dst;
1349
1350 /*
1351 * Sanity check
1352 */
1353 if (src == NULL)
1354 return (NULL);
1355
1356 /*
1357 * Determine if source surface is 32bit or 8bit
1358 */
1359 details = SDL_GetPixelFormatDetails(src->format);
1360 is32bit = (details->bits_per_pixel == 32);
1361 if ((is32bit) || (details->bits_per_pixel == 8)) {
1362 /*
1363 * Use source surface 'as is'
1364 */
1365 rz_src = src;
1366 src_converted = 0;
1367 } else {
1368 /*
1369 * New source surface is 32bit with a defined RGBA ordering
1370 */
1371 rz_src =
1372 SDL_CreateSurface(src->w, src->h, SDL_PIXELFORMAT_RGBA32);
1373 if (rz_src == NULL) {
1374 return NULL;
1375 }
1376 SDL_BlitSurface(src, NULL, rz_src, NULL);
1377 src_converted = 1;
1378 is32bit = 1;
1379 }
1380
1381 flipx = (zoomx<0.0);
1382 if (flipx) zoomx = -zoomx;
1383 flipy = (zoomy<0.0);
1384 if (flipy) zoomy = -zoomy;
1385
1386 /* Get size if target */
1387 zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
1388
1389 /*
1390 * Alloc space to completely contain the zoomed surface
1391 */
1392 rz_dst = NULL;
1393 if (is32bit) {
1394 /*
1395 * Target surface is 32bit with source RGBA/ABGR ordering
1396 */
1397 rz_dst =
1398 SDL_CreateSurface(dstwidth, dstheight + GUARD_ROWS, rz_src->format);
1399 } else {
1400 /*
1401 * Target surface is 8bit
1402 */
1403 rz_dst = SDL_CreateSurface(dstwidth, dstheight + GUARD_ROWS, SDL_PIXELFORMAT_INDEX8);
1404 pal_dst = SDL_CreateSurfacePalette(rz_dst);
1405 }
1406
1407 /* Check target */
1408 if (rz_dst == NULL) {
1409 /*
1410 * Cleanup temp surface
1411 */
1412 if (src_converted) {
1413 SDL_DestroySurface(rz_src);
1414 }
1415 return NULL;
1416 }
1417
1418 /* Adjust for guard rows */
1419 rz_dst->h = dstheight;
1420
1421 /*
1422 * Lock source surface
1423 */
1424 if (SDL_MUSTLOCK(rz_src)) {
1425 SDL_LockSurface(rz_src);
1426 }
1427
1428 /*
1429 * Check which kind of surface we have
1430 */
1431 if (is32bit) {
1432 /*
1433 * Call the 32bit transformation routine to do the zooming (using alpha)
1434 */
1435 _zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
1436 } else {
1437 /*
1438 * Copy palette and colorkey info
1439 */
1440 pal_src = SDL_GetSurfacePalette(rz_src);
1441 for (i = 0; i < pal_src->ncolors; i++) {
1442 pal_dst->colors[i] = pal_src->colors[i];
1443 }
1444 pal_dst->ncolors = pal_src->ncolors;
1445 /*
1446 * Call the 8bit transformation routine to do the zooming
1447 */
1448 _zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
1449 }
1450 /*
1451 * Unlock source surface
1452 */
1453 if (SDL_MUSTLOCK(rz_src)) {
1454 SDL_UnlockSurface(rz_src);
1455 }
1456
1457 /*
1458 * Cleanup temp surface
1459 */
1460 if (src_converted) {
1461 SDL_DestroySurface(rz_src);
1462 }
1463
1464 /*
1465 * Return destination surface
1466 */
1467 return (rz_dst);
1468}
1469
1486/*@null@*/
1487SDL_Surface *shrinkSurface(SDL_Surface *src, int factorx, int factory)
1488{
1489 int result;
1490 SDL_Surface *rz_src;
1491 SDL_Surface *rz_dst = NULL;
1492 int dstwidth, dstheight;
1493 int is32bit;
1494 int i, src_converted;
1495 int haveError = 0;
1496 const SDL_PixelFormatDetails* details;
1497 SDL_Palette* pal_src;
1498 SDL_Palette* pal_dst;
1499
1500 /*
1501 * Sanity check
1502 */
1503 if (src == NULL) {
1504 return (NULL);
1505 }
1506
1507 /*
1508 * Determine if source surface is 32bit or 8bit
1509 */
1510 details = SDL_GetPixelFormatDetails(src->format);
1511 is32bit = (details->bits_per_pixel == 32);
1512 if ((is32bit) || (details->bits_per_pixel == 8)) {
1513 /*
1514 * Use source surface 'as is'
1515 */
1516 rz_src = src;
1517 src_converted = 0;
1518 } else {
1519 /*
1520 * New source surface is 32bit with a defined RGBA ordering
1521 */
1522 rz_src = SDL_CreateSurface(src->w, src->h, SDL_PIXELFORMAT_RGBA32);
1523 if (rz_src==NULL) {
1524 haveError = 1;
1525 goto exitShrinkSurface;
1526 }
1527
1528 SDL_BlitSurface(src, NULL, rz_src, NULL);
1529 src_converted = 1;
1530 is32bit = 1;
1531 }
1532
1533 /*
1534 * Lock the surface
1535 */
1536 if (SDL_MUSTLOCK(rz_src)) {
1537 if (SDL_LockSurface(rz_src) < 0) {
1538 haveError = 1;
1539 goto exitShrinkSurface;
1540 }
1541 }
1542
1543 /* Get size for target */
1544 dstwidth=rz_src->w/factorx;
1545 while (dstwidth*factorx>rz_src->w) { dstwidth--; }
1546 dstheight=rz_src->h/factory;
1547 while (dstheight*factory>rz_src->h) { dstheight--; }
1548
1549 /*
1550 * Alloc space to completely contain the shrunken surface
1551 * (with added guard rows)
1552 */
1553 if (is32bit==1) {
1554 /*
1555 * Target surface is 32bit with source RGBA/ABGR ordering
1556 */
1557 rz_dst =
1558 SDL_CreateSurface(dstwidth, dstheight + GUARD_ROWS, rz_src->format);
1559 } else {
1560 /*
1561 * Target surface is 8bit
1562 */
1563 rz_dst = SDL_CreateSurface(dstwidth, dstheight + GUARD_ROWS, SDL_PIXELFORMAT_INDEX8);
1564 pal_dst = SDL_CreateSurfacePalette(rz_dst);
1565 }
1566
1567 /* Check target */
1568 if (rz_dst == NULL) {
1569 haveError = 1;
1570 goto exitShrinkSurface;
1571 }
1572
1573 /* Adjust for guard rows */
1574 rz_dst->h = dstheight;
1575
1576 /*
1577 * Check which kind of surface we have
1578 */
1579 if (is32bit==1) {
1580 /*
1581 * Call the 32bit transformation routine to do the shrinking (using alpha)
1582 */
1583 result = _shrinkSurfaceRGBA(rz_src, rz_dst, factorx, factory);
1584 if ((result!=0) || (rz_dst==NULL)) {
1585 haveError = 1;
1586 goto exitShrinkSurface;
1587 }
1588 } else {
1589 /*
1590 * Copy palette and colorkey info
1591 */
1592 pal_src = SDL_GetSurfacePalette(rz_src);
1593 for (i = 0; i < pal_src->ncolors; i++) {
1594 pal_dst->colors[i] = pal_src->colors[i];
1595 }
1596 pal_dst->ncolors = pal_src->ncolors;
1597 /*
1598 * Call the 8bit transformation routine to do the shrinking
1599 */
1600 result = _shrinkSurfaceY(rz_src, rz_dst, factorx, factory);
1601 if (result!=0) {
1602 haveError = 1;
1603 goto exitShrinkSurface;
1604 }
1605 }
1606
1607exitShrinkSurface:
1608 if (rz_src!=NULL) {
1609 /*
1610 * Unlock source surface
1611 */
1612 if (SDL_MUSTLOCK(rz_src)) {
1613 SDL_UnlockSurface(rz_src);
1614 }
1615
1616 /*
1617 * Cleanup temp surface
1618 */
1619 if (src_converted==1) {
1620 SDL_DestroySurface(rz_src);
1621 }
1622 }
1623
1624 /* Check error state; maybe need to cleanup destination */
1625 if (haveError==1) {
1626 if (rz_dst!=NULL) {
1627 SDL_DestroySurface(rz_dst);
1628 }
1629 rz_dst=NULL;
1630 }
1631
1632 /*
1633 * Return destination surface
1634 */
1635 return (rz_dst);
1636}
#define M_PI
SDL_Surface * rotozoomSurfaceXY(SDL_Surface *src, double angle, double zoomx, double zoomy, int smooth)
Rotates and zooms a surface with different horizontal and vertival scaling factors and optional anti-...
#define GUARD_ROWS
Number of guard rows added to destination surfaces.
void transformSurfaceY(SDL_Surface *src, SDL_Surface *dst, int cx, int cy, int isin, int icos, int flipx, int flipy)
Rotates and zooms 8 bit palette/Y 'src' surface to 'dst' surface without smoothing.
SDL_Surface * rotozoomSurface(SDL_Surface *src, double angle, double zoom, int smooth)
Rotates and zooms a surface and optional anti-aliasing.
SDL_Surface * rotateSurface90Degrees(SDL_Surface *src, int numClockwiseTurns)
Rotates a 8/16/24/32 bit surface in increments of 90 degrees.
SDL_Surface * zoomSurface(SDL_Surface *src, double zoomx, double zoomy, int smooth)
Zoom a surface by independent horizontal and vertical factors with optional smoothing.
SDL_Surface * shrinkSurface(SDL_Surface *src, int factorx, int factory)
Shrink a surface by an integer ratio using averaging.
void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight)
Calculates the size of the target surface for a zoomSurface() call.
void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth, int *dstheight)
Returns the size of the resulting target surface for a rotozoomSurface() call.
int _zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst, int flipx, int flipy, int smooth)
Internal 32 bit Zoomer with optional anti-aliasing by bilinear interpolation.
#define VALUE_LIMIT
Lower limit of absolute zoom factor or rotation degrees.
int _shrinkSurfaceY(SDL_Surface *src, SDL_Surface *dst, int factorx, int factory)
Internal 8 bit integer-factor averaging shrinker.
void _transformSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst, int cx, int cy, int isin, int icos, int flipx, int flipy, int smooth)
Internal 32 bit rotozoomer with optional anti-aliasing.
int _shrinkSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst, int factorx, int factory)
Internal 32 bit integer-factor averaging Shrinker.
int _zoomSurfaceY(SDL_Surface *src, SDL_Surface *dst, int flipx, int flipy)
Internal 8 bit Zoomer without smoothing.
void rotozoomSurfaceSizeXY(int width, int height, double angle, double zoomx, double zoomy, int *dstwidth, int *dstheight)
Returns the size of the resulting target surface for a rotozoomSurfaceXY() call.
void _rotozoomSurfaceSizeTrig(int width, int height, double angle, double zoomx, double zoomy, int *dstwidth, int *dstheight, double *canglezoom, double *sanglezoom)
Internal target surface sizing function for rotozooms with trig result return.
#define MAX(a, b)
Returns maximum of two numbers a and b.
Uint32 _colorkey(SDL_Surface *src)
Returns colorkey info for a surface.