3
SDL2_rotozoom.c: rotozoomer, zoomer and shrinker for 32bit or 8bit surfaces
5
Copyright (C) 2012 Andreas Schiffler
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.
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:
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.
20
2. Altered source versions must be plainly marked as such, and must not be
21
misrepresented as being the original software.
23
3. This notice may not be removed or altered from any source
26
Andreas Schiffler -- aschiffler at ferzkopp dot net
37
#include "SDL_rotozoom.h"
39
/* ---- Internally used structures */
42
\brief A 32 bit RGBA pixel.
44
typedef struct tColorRGBA {
52
\brief A 8bit Y/palette pixel.
54
typedef struct tColorY {
59
\brief Returns maximum of two numbers a and b.
61
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
64
\brief Number of guard rows added to destination surfaces.
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.
73
#define GUARD_ROWS (2)
76
\brief Lower limit of absolute zoom factor or rotation degrees.
78
#define VALUE_LIMIT 0.001
81
\brief Returns colorkey info for a surface
83
Uint32 _colorkey(SDL_Surface *src)
86
SDL_GetColorKey(src, &key);
92
\brief Internal 32 bit integer-factor averaging Shrinker.
94
Shrinks 32 bit RGBA/ABGR 'src' surface to 'dst' surface.
95
Averages color and alpha values values of src pixels to calculate dst pixels.
96
Assumes src and dst surfaces are of 32 bit depth.
97
Assumes dst surface was allocated with the correct dimensions.
99
\param src The surface to shrink (input).
100
\param dst The shrunken surface (output).
101
\param factorx The horizontal shrinking ratio.
102
\param factory The vertical shrinking ratio.
104
\return 0 for success or -1 for error.
106
int _shrinkSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
108
int x, y, dx, dy, sgap, dgap, ra, ga, ba, aa;
110
tColorRGBA *sp, *osp, *oosp;
114
* Averaging integer shrink
117
/* Precalculate division factor */
118
n_average = factorx*factory;
123
sp = (tColorRGBA *) src->pixels;
124
sgap = src->pitch - src->w * 4;
126
dp = (tColorRGBA *) dst->pixels;
127
dgap = dst->pitch - dst->w * 4;
129
for (y = 0; y < dst->h; y++) {
132
for (x = 0; x < dst->w; x++) {
134
/* Trace out source box and accumulate */
137
for (dy=0; dy < factory; dy++) {
138
for (dx=0; dx < factorx; dx++) {
147
sp = (tColorRGBA *)((Uint8*)sp + (src->pitch - 4*factorx)); // next y
152
sp = (tColorRGBA *)((Uint8*)oosp + 4*factorx);
154
/* Store result in destination */
155
dp->r = ra/n_average;
156
dp->g = ga/n_average;
157
dp->b = ba/n_average;
158
dp->a = aa/n_average;
161
* Advance destination pointer
168
sp = (tColorRGBA *)((Uint8*)osp + src->pitch*factory);
171
* Advance destination pointers
173
dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
181
\brief Internal 8 bit integer-factor averaging shrinker.
183
Shrinks 8bit Y 'src' surface to 'dst' surface.
184
Averages color (brightness) values values of src pixels to calculate dst pixels.
185
Assumes src and dst surfaces are of 8 bit depth.
186
Assumes dst surface was allocated with the correct dimensions.
188
\param src The surface to shrink (input).
189
\param dst The shrunken surface (output).
190
\param factorx The horizontal shrinking ratio.
191
\param factory The vertical shrinking ratio.
193
\return 0 for success or -1 for error.
195
int _shrinkSurfaceY(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
197
int x, y, dx, dy, sgap, dgap, a;
199
Uint8 *sp, *osp, *oosp;
203
* Averaging integer shrink
206
/* Precalculate division factor */
207
n_average = factorx*factory;
212
sp = (Uint8 *) src->pixels;
213
sgap = src->pitch - src->w;
215
dp = (Uint8 *) dst->pixels;
216
dgap = dst->pitch - dst->w;
218
for (y = 0; y < dst->h; y++) {
221
for (x = 0; x < dst->w; x++) {
223
/* Trace out source box and accumulate */
226
for (dy=0; dy < factory; dy++) {
227
for (dx=0; dx < factorx; dx++) {
232
/* end src dx loop */
234
sp = (Uint8 *)((Uint8*)sp + (src->pitch - factorx));
236
/* end src dy loop */
239
sp = (Uint8 *)((Uint8*)oosp + factorx);
241
/* Store result in destination */
245
* Advance destination pointer
252
sp = (Uint8 *)((Uint8*)osp + src->pitch*factory);
255
* Advance destination pointers
257
dp = (Uint8 *)((Uint8 *)dp + dgap);
265
\brief Internal 32 bit Zoomer with optional anti-aliasing by bilinear interpolation.
267
Zooms 32 bit RGBA/ABGR 'src' surface to 'dst' surface.
268
Assumes src and dst surfaces are of 32 bit depth.
269
Assumes dst surface was allocated with the correct dimensions.
271
\param src The surface to zoom (input).
272
\param dst The zoomed surface (output).
273
\param flipx Flag indicating if the image should be horizontally flipped.
274
\param flipy Flag indicating if the image should be vertically flipped.
275
\param smooth Antialiasing flag; set to SMOOTHING_ON to enable.
277
\return 0 for success or -1 for error.
279
int _zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy, int smooth)
281
int x, y, sx, sy, ssx, ssy, *sax, *say, *csax, *csay, *salast, csx, csy, ex, ey, cx, cy, sstep, sstepx, sstepy;
282
tColorRGBA *c00, *c01, *c10, *c11;
283
tColorRGBA *sp, *csp, *dp;
284
int spixelgap, spixelw, spixelh, dgap, t1, t2;
287
* Allocate memory for row/column increments
289
if ((sax = (int *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
292
if ((say = (int *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
298
* Precalculate row increments
300
spixelw = (src->w - 1);
301
spixelh = (src->h - 1);
303
sx = (int) (65536.0 * (float) spixelw / (float) (dst->w - 1));
304
sy = (int) (65536.0 * (float) spixelh / (float) (dst->h - 1));
306
sx = (int) (65536.0 * (float) (src->w) / (float) (dst->w));
307
sy = (int) (65536.0 * (float) (src->h) / (float) (dst->h));
310
/* Maximum scaled source size */
311
ssx = (src->w << 16) - 1;
312
ssy = (src->h << 16) - 1;
314
/* Precalculate horizontal row increments */
317
for (x = 0; x <= dst->w; x++) {
322
/* Guard from overflows */
328
/* Precalculate vertical row increments */
331
for (y = 0; y <= dst->h; y++) {
336
/* Guard from overflows */
342
sp = (tColorRGBA *) src->pixels;
343
dp = (tColorRGBA *) dst->pixels;
344
dgap = dst->pitch - dst->w * 4;
345
spixelgap = src->pitch/4;
347
if (flipx) sp += spixelw;
348
if (flipy) sp += (spixelgap * spixelh);
351
* Switch between interpolating and non-interpolating code
359
for (y = 0; y < dst->h; y++) {
362
for (x = 0; x < dst->w; x++) {
364
* Setup color source pointers
366
ex = (*csax & 0xffff);
367
ey = (*csay & 0xffff);
370
sstepx = cx < spixelw;
371
sstepy = cy < spixelh;
394
* Draw and interpolate colors
396
t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
397
t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
398
dp->r = (((t2 - t1) * ey) >> 16) + t1;
399
t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff;
400
t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff;
401
dp->g = (((t2 - t1) * ey) >> 16) + t1;
402
t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff;
403
t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff;
404
dp->b = (((t2 - t1) * ey) >> 16) + t1;
405
t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff;
406
t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff;
407
dp->a = (((t2 - t1) * ey) >> 16) + t1;
409
* Advance source pointer x
413
sstep = (*csax >> 16) - (*salast >> 16);
421
* Advance destination pointer x
426
* Advance source pointer y
430
sstep = (*csay >> 16) - (*salast >> 16);
439
* Advance destination pointer y
441
dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
445
* Non-Interpolating Zoom
448
for (y = 0; y < dst->h; y++) {
451
for (x = 0; x < dst->w; x++) {
458
* Advance source pointer x
462
sstep = (*csax >> 16) - (*salast >> 16);
463
if (flipx) sstep = -sstep;
467
* Advance destination pointer x
472
* Advance source pointer y
476
sstep = (*csay >> 16) - (*salast >> 16);
478
if (flipy) sstep = -sstep;
482
* Advance destination pointer y
484
dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
499
\brief Internal 8 bit Zoomer without smoothing.
501
Zooms 8bit palette/Y 'src' surface to 'dst' surface.
502
Assumes src and dst surfaces are of 8 bit depth.
503
Assumes dst surface was allocated with the correct dimensions.
505
\param src The surface to zoom (input).
506
\param dst The zoomed surface (output).
507
\param flipx Flag indicating if the image should be horizontally flipped.
508
\param flipy Flag indicating if the image should be vertically flipped.
510
\return 0 for success or -1 for error.
512
int _zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy)
515
Uint32 *sax, *say, *csax, *csay;
517
Uint8 *sp, *dp, *csp;
521
* Allocate memory for row increments
523
if ((sax = (Uint32 *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
526
if ((say = (Uint32 *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
534
sp = csp = (Uint8 *) src->pixels;
535
dp = (Uint8 *) dst->pixels;
536
dgap = dst->pitch - dst->w;
538
if (flipx) csp += (src->w-1);
539
if (flipy) csp = ( (Uint8*)csp + src->pitch*(src->h-1) );
542
* Precalculate row increments
546
for (x = 0; x < dst->w; x++) {
549
while (csx >= dst->w) {
553
(*csax) = (*csax) * (flipx ? -1 : 1);
558
for (y = 0; y < dst->h; y++) {
561
while (csy >= dst->h) {
565
(*csay) = (*csay) * (flipy ? -1 : 1);
573
for (y = 0; y < dst->h; y++) {
576
for (x = 0; x < dst->w; x++) {
582
* Advance source pointers
587
* Advance destination pointer
592
* Advance source pointer (for row)
594
csp += ((*csay) * src->pitch);
598
* Advance destination pointers
613
\brief Internal 32 bit rotozoomer with optional anti-aliasing.
615
Rotates and zooms 32 bit RGBA/ABGR 'src' surface to 'dst' surface based on the control
616
parameters by scanning the destination surface and applying optionally anti-aliasing
617
by bilinear interpolation.
618
Assumes src and dst surfaces are of 32 bit depth.
619
Assumes dst surface was allocated with the correct dimensions.
621
\param src Source surface.
622
\param dst Destination surface.
623
\param cx Horizontal center coordinate.
624
\param cy Vertical center coordinate.
625
\param isin Integer version of sine of angle.
626
\param icos Integer version of cosine of angle.
627
\param flipx Flag indicating horizontal mirroring should be applied.
628
\param flipy Flag indicating vertical mirroring should be applied.
629
\param smooth Flag indicating anti-aliasing should be used.
631
void _transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy, int smooth)
633
int x, y, t1, t2, dx, dy, xd, yd, sdx, sdy, ax, ay, ex, ey, sw, sh;
634
tColorRGBA c00, c01, c10, c11, cswap;
641
xd = ((src->w - dst->w) << 15);
642
yd = ((src->h - dst->h) << 15);
643
ax = (cx << 16) - (icos * cx);
644
ay = (cy << 16) - (isin * cx);
647
pc = (tColorRGBA*) dst->pixels;
648
gap = dst->pitch - dst->w * 4;
651
* Switch between interpolating and non-interpolating code
654
for (y = 0; y < dst->h; y++) {
656
sdx = (ax + (isin * dy)) + xd;
657
sdy = (ay - (icos * dy)) + yd;
658
for (x = 0; x < dst->w; x++) {
661
if (flipx) dx = sw - dx;
662
if (flipy) dy = sh - dy;
663
if ((dx > -1) && (dy > -1) && (dx < (src->w-1)) && (dy < (src->h-1))) {
664
sp = (tColorRGBA *)src->pixels;;
665
sp += ((src->pitch/4) * dy);
670
sp += (src->pitch/4);
675
cswap = c00; c00=c01; c01=cswap;
676
cswap = c10; c10=c11; c11=cswap;
679
cswap = c00; c00=c10; c10=cswap;
680
cswap = c01; c01=c11; c11=cswap;
687
t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff;
688
t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff;
689
pc->r = (((t2 - t1) * ey) >> 16) + t1;
690
t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff;
691
t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff;
692
pc->g = (((t2 - t1) * ey) >> 16) + t1;
693
t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff;
694
t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff;
695
pc->b = (((t2 - t1) * ey) >> 16) + t1;
696
t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff;
697
t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff;
698
pc->a = (((t2 - t1) * ey) >> 16) + t1;
704
pc = (tColorRGBA *) ((Uint8 *) pc + gap);
707
for (y = 0; y < dst->h; y++) {
709
sdx = (ax + (isin * dy)) + xd;
710
sdy = (ay - (icos * dy)) + yd;
711
for (x = 0; x < dst->w; x++) {
712
dx = (short) (sdx >> 16);
713
dy = (short) (sdy >> 16);
714
if (flipx) dx = (src->w-1)-dx;
715
if (flipy) dy = (src->h-1)-dy;
716
if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
717
sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
725
pc = (tColorRGBA *) ((Uint8 *) pc + gap);
732
\brief Rotates and zooms 8 bit palette/Y 'src' surface to 'dst' surface without smoothing.
734
Rotates and zooms 8 bit RGBA/ABGR 'src' surface to 'dst' surface based on the control
735
parameters by scanning the destination surface.
736
Assumes src and dst surfaces are of 8 bit depth.
737
Assumes dst surface was allocated with the correct dimensions.
739
\param src Source surface.
740
\param dst Destination surface.
741
\param cx Horizontal center coordinate.
742
\param cy Vertical center coordinate.
743
\param isin Integer version of sine of angle.
744
\param icos Integer version of cosine of angle.
745
\param flipx Flag indicating horizontal mirroring should be applied.
746
\param flipy Flag indicating vertical mirroring should be applied.
748
void transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy)
750
int x, y, dx, dy, xd, yd, sdx, sdy, ax, ay, sw, sh;
757
xd = ((src->w - dst->w) << 15);
758
yd = ((src->h - dst->h) << 15);
759
ax = (cx << 16) - (icos * cx);
760
ay = (cy << 16) - (isin * cx);
763
pc = (tColorY*) dst->pixels;
764
gap = dst->pitch - dst->w;
766
* Clear surface to colorkey
768
memset(pc, (int)(_colorkey(src) & 0xff), dst->pitch * dst->h);
770
* Iterate through destination surface
772
for (y = 0; y < dst->h; y++) {
774
sdx = (ax + (isin * dy)) + xd;
775
sdy = (ay - (icos * dy)) + yd;
776
for (x = 0; x < dst->w; x++) {
777
dx = (short) (sdx >> 16);
778
dy = (short) (sdy >> 16);
779
if (flipx) dx = (src->w-1)-dx;
780
if (flipy) dy = (src->h-1)-dy;
781
if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
782
sp = (tColorY *) (src->pixels);
783
sp += (src->pitch * dy + dx);
795
\brief Rotates a 32 bit surface in increments of 90 degrees.
797
Specialized 90 degree rotator which rotates a 'src' surface in 90 degree
798
increments clockwise returning a new surface. Faster than rotozoomer since
799
not scanning or interpolation takes place. Input surface must be 32 bit.
800
(code contributed by J. Schiller, improved by C. Allport and A. Schiffler)
802
\param src Source surface to rotate.
803
\param numClockwiseTurns Number of clockwise 90 degree turns to apply to the source.
805
\returns The new, rotated surface; or NULL for surfaces with incorrect input format.
807
SDL_Surface* rotateSurface90Degrees(SDL_Surface* src, int numClockwiseTurns)
809
int row, col, newWidth, newHeight;
810
int bpp, src_ipr, dst_ipr;
815
/* Has to be a valid surface pointer and only 32-bit surfaces (for now) */
816
if (!src || src->format->BitsPerPixel != 32) { return NULL; }
818
/* normalize numClockwiseTurns */
819
while(numClockwiseTurns < 0) { numClockwiseTurns += 4; }
820
numClockwiseTurns = (numClockwiseTurns % 4);
822
/* if it's even, our new width will be the same as the source surface */
823
newWidth = (numClockwiseTurns % 2) ? (src->h) : (src->w);
824
newHeight = (numClockwiseTurns % 2) ? (src->w) : (src->h);
825
dst = SDL_CreateRGBSurface( src->flags, newWidth, newHeight, src->format->BitsPerPixel,
834
if (SDL_MUSTLOCK(dst)) {
835
SDL_LockSurface(dst);
837
if (SDL_MUSTLOCK(dst)) {
838
SDL_LockSurface(dst);
841
/* Calculate int-per-row */
842
bpp = src->format->BitsPerPixel / 8;
843
src_ipr = src->pitch / bpp;
844
dst_ipr = dst->pitch / bpp;
846
switch(numClockwiseTurns) {
847
case 0: /* Make a copy of the surface */
849
/* Unfortunately SDL_BlitSurface cannot be used to make a copy of the surface
850
since it does not preserve alpha. */
852
if (src->pitch == dst->pitch) {
853
/* If the pitch is the same for both surfaces, the memory can be copied all at once. */
854
memcpy(dst->pixels, src->pixels, (src->h * src->pitch));
858
/* If the pitch differs, copy each row separately */
859
srcBuf = (Uint32*)(src->pixels);
860
dstBuf = (Uint32*)(dst->pixels);
861
for (row = 0; row < src->h; row++) {
862
memcpy(dstBuf, srcBuf, dst->w * bpp);
870
/* rotate clockwise */
871
case 1: /* rotated 90 degrees clockwise */
873
for (row = 0; row < src->h; ++row) {
874
srcBuf = (Uint32*)(src->pixels) + (row * src_ipr);
875
dstBuf = (Uint32*)(dst->pixels) + (dst->w - row - 1);
876
for (col = 0; col < src->w; ++col) {
887
case 2: /* rotated 180 degrees clockwise */
889
for (row = 0; row < src->h; ++row) {
890
srcBuf = (Uint32*)(src->pixels) + (row * src_ipr);
891
dstBuf = (Uint32*)(dst->pixels) + ((dst->h - row - 1) * dst_ipr) + (dst->w - 1);
892
for (col = 0; col < src->w; ++col) {
903
for (row = 0; row < src->h; ++row) {
904
srcBuf = (Uint32*)(src->pixels) + (row * src_ipr);
905
dstBuf = (Uint32*)(dst->pixels) + row + ((dst->h - 1) * dst_ipr);
906
for (col = 0; col < src->w; ++col) {
917
if (SDL_MUSTLOCK(src)) {
918
SDL_UnlockSurface(src);
920
if (SDL_MUSTLOCK(dst)) {
921
SDL_UnlockSurface(dst);
929
\brief Internal target surface sizing function for rotozooms with trig result return.
931
\param width The source surface width.
932
\param height The source surface height.
933
\param angle The angle to rotate in degrees.
934
\param zoomx The horizontal scaling factor.
935
\param zoomy The vertical scaling factor.
936
\param dstwidth The calculated width of the destination surface.
937
\param dstheight The calculated height of the destination surface.
938
\param canglezoom The sine of the angle adjusted by the zoom factor.
939
\param sanglezoom The cosine of the angle adjusted by the zoom factor.
942
void _rotozoomSurfaceSizeTrig(int width, int height, double angle, double zoomx, double zoomy,
943
int *dstwidth, int *dstheight,
944
double *canglezoom, double *sanglezoom)
946
double x, y, cx, cy, sx, sy;
948
int dstwidthhalf, dstheighthalf;
951
* Determine destination width and height by rotating a centered source box
953
radangle = angle * (M_PI / 180.0);
954
*sanglezoom = sin(radangle);
955
*canglezoom = cos(radangle);
956
*sanglezoom *= zoomx;
957
*canglezoom *= zoomx;
958
x = (double)(width / 2);
959
y = (double)(height / 2);
960
cx = *canglezoom * x;
961
cy = *canglezoom * y;
962
sx = *sanglezoom * x;
963
sy = *sanglezoom * y;
965
dstwidthhalf = MAX((int)
966
ceil(MAX(MAX(MAX(fabs(cx + sy), fabs(cx - sy)), fabs(-cx + sy)), fabs(-cx - sy))), 1);
967
dstheighthalf = MAX((int)
968
ceil(MAX(MAX(MAX(fabs(sx + cy), fabs(sx - cy)), fabs(-sx + cy)), fabs(-sx - cy))), 1);
969
*dstwidth = 2 * dstwidthhalf;
970
*dstheight = 2 * dstheighthalf;
974
\brief Returns the size of the resulting target surface for a rotozoomSurfaceXY() call.
976
\param width The source surface width.
977
\param height The source surface height.
978
\param angle The angle to rotate in degrees.
979
\param zoomx The horizontal scaling factor.
980
\param zoomy The vertical scaling factor.
981
\param dstwidth The calculated width of the rotozoomed destination surface.
982
\param dstheight The calculated height of the rotozoomed destination surface.
984
void rotozoomSurfaceSizeXY(int width, int height, double angle, double zoomx, double zoomy, int *dstwidth, int *dstheight)
986
double dummy_sanglezoom, dummy_canglezoom;
988
_rotozoomSurfaceSizeTrig(width, height, angle, zoomx, zoomy, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
992
\brief Returns the size of the resulting target surface for a rotozoomSurface() call.
994
\param width The source surface width.
995
\param height The source surface height.
996
\param angle The angle to rotate in degrees.
997
\param zoom The scaling factor.
998
\param dstwidth The calculated width of the rotozoomed destination surface.
999
\param dstheight The calculated height of the rotozoomed destination surface.
1001
void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth, int *dstheight)
1003
double dummy_sanglezoom, dummy_canglezoom;
1005
_rotozoomSurfaceSizeTrig(width, height, angle, zoom, zoom, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
1009
\brief Rotates and zooms a surface and optional anti-aliasing.
1011
Rotates and zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1012
'angle' is the rotation in degrees and 'zoom' a scaling factor. If 'smooth' is set
1013
then the destination 32bit surface is anti-aliased. If the surface is not 8bit
1014
or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
1016
\param src The surface to rotozoom.
1017
\param angle The angle to rotate in degrees.
1018
\param zoom The scaling factor.
1019
\param smooth Antialiasing flag; set to SMOOTHING_ON to enable.
1021
\return The new rotozoomed surface.
1023
SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth)
1025
return rotozoomSurfaceXY(src, angle, zoom, zoom, smooth);
1029
\brief Rotates and zooms a surface with different horizontal and vertival scaling factors and optional anti-aliasing.
1031
Rotates and zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1032
'angle' is the rotation in degrees, 'zoomx and 'zoomy' scaling factors. If 'smooth' is set
1033
then the destination 32bit surface is anti-aliased. If the surface is not 8bit
1034
or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
1036
\param src The surface to rotozoom.
1037
\param angle The angle to rotate in degrees.
1038
\param zoomx The horizontal scaling factor.
1039
\param zoomy The vertical scaling factor.
1040
\param smooth Antialiasing flag; set to SMOOTHING_ON to enable.
1042
\return The new rotozoomed surface.
1044
SDL_Surface *rotozoomSurfaceXY(SDL_Surface * src, double angle, double zoomx, double zoomy, int smooth)
1046
SDL_Surface *rz_src;
1047
SDL_Surface *rz_dst;
1049
double sanglezoom, canglezoom, sanglezoominv, canglezoominv;
1050
int dstwidthhalf, dstwidth, dstheighthalf, dstheight;
1052
int i, src_converted;
1063
* Determine if source surface is 32bit or 8bit
1065
is32bit = (src->format->BitsPerPixel == 32);
1066
if ((is32bit) || (src->format->BitsPerPixel == 8)) {
1068
* Use source surface 'as is'
1074
* New source surface is 32bit with a defined RGBA ordering
1077
SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1078
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
1079
0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
1081
0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
1085
SDL_BlitSurface(src, NULL, rz_src, NULL);
1092
* Sanity check zoom factor
1094
flipx = (zoomx<0.0);
1095
if (flipx) zoomx=-zoomx;
1096
flipy = (zoomy<0.0);
1097
if (flipy) zoomy=-zoomy;
1098
if (zoomx < VALUE_LIMIT) zoomx = VALUE_LIMIT;
1099
if (zoomy < VALUE_LIMIT) zoomy = VALUE_LIMIT;
1100
zoominv = 65536.0 / (zoomx * zoomx);
1103
* Check if we have a rotozoom or just a zoom
1105
if (fabs(angle) > VALUE_LIMIT) {
1108
* Angle!=0: full rotozoom
1111
* -----------------------
1114
/* Determine target size */
1115
_rotozoomSurfaceSizeTrig(rz_src->w, rz_src->h, angle, zoomx, zoomy, &dstwidth, &dstheight, &canglezoom, &sanglezoom);
1118
* Calculate target factors from sin/cos and zoom
1120
sanglezoominv = sanglezoom;
1121
canglezoominv = canglezoom;
1122
sanglezoominv *= zoominv;
1123
canglezoominv *= zoominv;
1125
/* Calculate half size */
1126
dstwidthhalf = dstwidth / 2;
1127
dstheighthalf = dstheight / 2;
1130
* Alloc space to completely contain the rotated surface
1135
* Target surface is 32bit with source RGBA/ABGR ordering
1138
SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
1139
rz_src->format->Rmask, rz_src->format->Gmask,
1140
rz_src->format->Bmask, rz_src->format->Amask);
1143
* Target surface is 8bit
1145
rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
1152
/* Adjust for guard rows */
1153
rz_dst->h = dstheight;
1156
* Lock source surface
1158
if (SDL_MUSTLOCK(rz_src)) {
1159
SDL_LockSurface(rz_src);
1163
* Check which kind of surface we have
1167
* Call the 32bit transformation routine to do the rotation (using alpha)
1169
_transformSurfaceRGBA(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
1170
(int) (sanglezoominv), (int) (canglezoominv),
1175
* Copy palette and colorkey info
1177
for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1178
rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1180
rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1182
* Call the 8bit transformation routine to do the rotation
1184
transformSurfaceY(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
1185
(int) (sanglezoominv), (int) (canglezoominv),
1189
* Unlock source surface
1191
if (SDL_MUSTLOCK(rz_src)) {
1192
SDL_UnlockSurface(rz_src);
1198
* Angle=0: Just a zoom
1201
* --------------------
1205
* Calculate target size
1207
zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
1210
* Alloc space to completely contain the zoomed surface
1215
* Target surface is 32bit with source RGBA/ABGR ordering
1218
SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
1219
rz_src->format->Rmask, rz_src->format->Gmask,
1220
rz_src->format->Bmask, rz_src->format->Amask);
1223
* Target surface is 8bit
1225
rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
1232
/* Adjust for guard rows */
1233
rz_dst->h = dstheight;
1236
* Lock source surface
1238
if (SDL_MUSTLOCK(rz_src)) {
1239
SDL_LockSurface(rz_src);
1243
* Check which kind of surface we have
1247
* Call the 32bit transformation routine to do the zooming (using alpha)
1249
_zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
1253
* Copy palette and colorkey info
1255
for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1256
rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1258
rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1261
* Call the 8bit transformation routine to do the zooming
1263
_zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
1267
* Unlock source surface
1269
if (SDL_MUSTLOCK(rz_src)) {
1270
SDL_UnlockSurface(rz_src);
1275
* Cleanup temp surface
1277
if (src_converted) {
1278
SDL_FreeSurface(rz_src);
1282
* Return destination surface
1288
\brief Calculates the size of the target surface for a zoomSurface() call.
1290
The minimum size of the target surface is 1. The input factors can be positive or negative.
1292
\param width The width of the source surface to zoom.
1293
\param height The height of the source surface to zoom.
1294
\param zoomx The horizontal zoom factor.
1295
\param zoomy The vertical zoom factor.
1296
\param dstwidth Pointer to an integer to store the calculated width of the zoomed target surface.
1297
\param dstheight Pointer to an integer to store the calculated height of the zoomed target surface.
1299
void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight)
1302
* Make zoom factors positive
1305
flipx = (zoomx<0.0);
1306
if (flipx) zoomx = -zoomx;
1307
flipy = (zoomy<0.0);
1308
if (flipy) zoomy = -zoomy;
1311
* Sanity check zoom factors
1313
if (zoomx < VALUE_LIMIT) {
1314
zoomx = VALUE_LIMIT;
1316
if (zoomy < VALUE_LIMIT) {
1317
zoomy = VALUE_LIMIT;
1321
* Calculate target size
1323
*dstwidth = (int) floor(((double) width * zoomx) + 0.5);
1324
*dstheight = (int) floor(((double) height * zoomy) + 0.5);
1325
if (*dstwidth < 1) {
1328
if (*dstheight < 1) {
1334
\brief Zoom a surface by independent horizontal and vertical factors with optional smoothing.
1336
Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1337
'zoomx' and 'zoomy' are scaling factors for width and height. If 'smooth' is on
1338
then the destination 32bit surface is anti-aliased. If the surface is not 8bit
1339
or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
1340
If zoom factors are negative, the image is flipped on the axes.
1342
\param src The surface to zoom.
1343
\param zoomx The horizontal zoom factor.
1344
\param zoomy The vertical zoom factor.
1345
\param smooth Antialiasing flag; set to SMOOTHING_ON to enable.
1347
\return The new, zoomed surface.
1349
SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth)
1351
SDL_Surface *rz_src;
1352
SDL_Surface *rz_dst;
1353
int dstwidth, dstheight;
1355
int i, src_converted;
1365
* Determine if source surface is 32bit or 8bit
1367
is32bit = (src->format->BitsPerPixel == 32);
1368
if ((is32bit) || (src->format->BitsPerPixel == 8)) {
1370
* Use source surface 'as is'
1376
* New source surface is 32bit with a defined RGBA ordering
1379
SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1380
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
1381
0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
1383
0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
1386
if (rz_src == NULL) {
1389
SDL_BlitSurface(src, NULL, rz_src, NULL);
1394
flipx = (zoomx<0.0);
1395
if (flipx) zoomx = -zoomx;
1396
flipy = (zoomy<0.0);
1397
if (flipy) zoomy = -zoomy;
1399
/* Get size if target */
1400
zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
1403
* Alloc space to completely contain the zoomed surface
1408
* Target surface is 32bit with source RGBA/ABGR ordering
1411
SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
1412
rz_src->format->Rmask, rz_src->format->Gmask,
1413
rz_src->format->Bmask, rz_src->format->Amask);
1416
* Target surface is 8bit
1418
rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
1422
if (rz_dst == NULL) {
1424
* Cleanup temp surface
1426
if (src_converted) {
1427
SDL_FreeSurface(rz_src);
1432
/* Adjust for guard rows */
1433
rz_dst->h = dstheight;
1436
* Lock source surface
1438
if (SDL_MUSTLOCK(rz_src)) {
1439
SDL_LockSurface(rz_src);
1443
* Check which kind of surface we have
1447
* Call the 32bit transformation routine to do the zooming (using alpha)
1449
_zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
1452
* Copy palette and colorkey info
1454
for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1455
rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1457
rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1459
* Call the 8bit transformation routine to do the zooming
1461
_zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
1464
* Unlock source surface
1466
if (SDL_MUSTLOCK(rz_src)) {
1467
SDL_UnlockSurface(rz_src);
1471
* Cleanup temp surface
1473
if (src_converted) {
1474
SDL_FreeSurface(rz_src);
1478
* Return destination surface
1484
\brief Shrink a surface by an integer ratio using averaging.
1486
Shrinks a 32bit or 8bit 'src' surface to a newly created 'dst' surface.
1487
'factorx' and 'factory' are the shrinking ratios (i.e. 2=1/2 the size,
1488
3=1/3 the size, etc.) The destination surface is antialiased by averaging
1489
the source box RGBA or Y information. If the surface is not 8bit
1490
or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
1491
The input surface is not modified. The output surface is newly allocated.
1493
\param src The surface to shrink.
1494
\param factorx The horizontal shrinking ratio.
1495
\param factory The vertical shrinking ratio.
1497
\return The new, shrunken surface.
1500
SDL_Surface *shrinkSurface(SDL_Surface *src, int factorx, int factory)
1503
SDL_Surface *rz_src;
1504
SDL_Surface *rz_dst = NULL;
1505
int dstwidth, dstheight;
1507
int i, src_converted;
1518
* Determine if source surface is 32bit or 8bit
1520
is32bit = (src->format->BitsPerPixel == 32);
1521
if ((is32bit) || (src->format->BitsPerPixel == 8)) {
1523
* Use source surface 'as is'
1529
* New source surface is 32bit with a defined RGBA ordering
1531
rz_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1532
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
1533
0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
1535
0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
1540
goto exitShrinkSurface;
1543
SDL_BlitSurface(src, NULL, rz_src, NULL);
1551
if (SDL_MUSTLOCK(rz_src)) {
1552
if (SDL_LockSurface(rz_src) < 0) {
1554
goto exitShrinkSurface;
1558
/* Get size for target */
1559
dstwidth=rz_src->w/factorx;
1560
while (dstwidth*factorx>rz_src->w) { dstwidth--; }
1561
dstheight=rz_src->h/factory;
1562
while (dstheight*factory>rz_src->h) { dstheight--; }
1565
* Alloc space to completely contain the shrunken surface
1566
* (with added guard rows)
1570
* Target surface is 32bit with source RGBA/ABGR ordering
1573
SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
1574
rz_src->format->Rmask, rz_src->format->Gmask,
1575
rz_src->format->Bmask, rz_src->format->Amask);
1578
* Target surface is 8bit
1580
rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
1584
if (rz_dst == NULL) {
1586
goto exitShrinkSurface;
1589
/* Adjust for guard rows */
1590
rz_dst->h = dstheight;
1593
* Check which kind of surface we have
1597
* Call the 32bit transformation routine to do the shrinking (using alpha)
1599
result = _shrinkSurfaceRGBA(rz_src, rz_dst, factorx, factory);
1600
if ((result!=0) || (rz_dst==NULL)) {
1602
goto exitShrinkSurface;
1606
* Copy palette and colorkey info
1608
for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1609
rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1611
rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1613
* Call the 8bit transformation routine to do the shrinking
1615
result = _shrinkSurfaceY(rz_src, rz_dst, factorx, factory);
1618
goto exitShrinkSurface;
1625
* Unlock source surface
1627
if (SDL_MUSTLOCK(rz_src)) {
1628
SDL_UnlockSurface(rz_src);
1632
* Cleanup temp surface
1634
if (src_converted==1) {
1635
SDL_FreeSurface(rz_src);
1639
/* Check error state; maybe need to cleanup destination */
1642
SDL_FreeSurface(rz_dst);
1648
* Return destination surface