SDL  2.0
SDL_rotate.c
Go to the documentation of this file.
1 /*
2 
3 SDL_rotate.c: rotates 32bit or 8bit surfaces
4 
5 Shamelessly stolen from SDL_gfx by Andreas Schiffler. Original copyright follows:
6 
7 Copyright (C) 2001-2011 Andreas Schiffler
8 
9 This software is provided 'as-is', without any express or implied
10 warranty. In no event will the authors be held liable for any damages
11 arising from the use of this software.
12 
13 Permission is granted to anyone to use this software for any purpose,
14 including commercial applications, and to alter it and redistribute it
15 freely, subject to the following restrictions:
16 
17  1. The origin of this software must not be misrepresented; you must not
18  claim that you wrote the original software. If you use this software
19  in a product, an acknowledgment in the product documentation would be
20  appreciated but is not required.
21 
22  2. Altered source versions must be plainly marked as such, and must not be
23  misrepresented as being the original software.
24 
25  3. This notice may not be removed or altered from any source
26  distribution.
27 
28 Andreas Schiffler -- aschiffler at ferzkopp dot net
29 
30 */
31 #include "../../SDL_internal.h"
32 
33 #if defined(__WIN32__)
34 #include "../../core/windows/SDL_windows.h"
35 #endif
36 
37 #include <stdlib.h>
38 #include <string.h>
39 
40 #include "SDL.h"
41 #include "SDL_rotate.h"
42 
43 /* ---- Internally used structures */
44 
45 /* !
46 \brief A 32 bit RGBA pixel.
47 */
48 typedef struct tColorRGBA {
53 } tColorRGBA;
54 
55 /* !
56 \brief A 8bit Y/palette pixel.
57 */
58 typedef struct tColorY {
60 } tColorY;
61 
62 /* !
63 \brief Returns maximum of two numbers a and b.
64 */
65 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
66 
67 /* !
68 \brief Number of guard rows added to destination surfaces.
69 
70 This is a simple but effective workaround for observed issues.
71 These rows allocate extra memory and are then hidden from the surface.
72 Rows are added to the end of destination surfaces when they are allocated.
73 This catches any potential overflows which seem to happen with
74 just the right src image dimensions and scale/rotation and can lead
75 to a situation where the program can segfault.
76 */
77 #define GUARD_ROWS (2)
78 
79 /* !
80 \brief Lower limit of absolute zoom factor or rotation degrees.
81 */
82 #define VALUE_LIMIT 0.001
83 
84 /* !
85 \brief Returns colorkey info for a surface
86 */
87 static Uint32
89 {
90  Uint32 key = 0;
91  SDL_GetColorKey(src, &key);
92  return key;
93 }
94 
95 
96 /* !
97 \brief Internal target surface sizing function for rotations with trig result return.
98 
99 \param width The source surface width.
100 \param height The source surface height.
101 \param angle The angle to rotate in degrees.
102 \param dstwidth The calculated width of the destination surface.
103 \param dstheight The calculated height of the destination surface.
104 \param cangle The sine of the angle
105 \param sangle The cosine of the angle
106 
107 */
108 void
110  int *dstwidth, int *dstheight,
111  double *cangle, double *sangle)
112 {
113  double x, y, cx, cy, sx, sy;
114  double radangle;
115  int dstwidthhalf, dstheighthalf;
116 
117  /*
118  * Determine destination width and height by rotating a centered source box
119  */
120  radangle = angle * (M_PI / 180.0);
121  *sangle = SDL_sin(radangle);
122  *cangle = SDL_cos(radangle);
123  x = (double)(width / 2);
124  y = (double)(height / 2);
125  cx = *cangle * x;
126  cy = *cangle * y;
127  sx = *sangle * x;
128  sy = *sangle * y;
129 
130  dstwidthhalf = MAX((int)
131  SDL_ceil(MAX(MAX(MAX(SDL_fabs(cx + sy), SDL_fabs(cx - sy)), SDL_fabs(-cx + sy)), SDL_fabs(-cx - sy))), 1);
132  dstheighthalf = MAX((int)
133  SDL_ceil(MAX(MAX(MAX(SDL_fabs(sx + cy), SDL_fabs(sx - cy)), SDL_fabs(-sx + cy)), SDL_fabs(-sx - cy))), 1);
134  *dstwidth = 2 * dstwidthhalf;
135  *dstheight = 2 * dstheighthalf;
136 }
137 
138 
139 /* !
140 \brief Internal 32 bit rotozoomer with optional anti-aliasing.
141 
142 Rotates and zooms 32 bit RGBA/ABGR 'src' surface to 'dst' surface based on the control
143 parameters by scanning the destination surface and applying optionally anti-aliasing
144 by bilinear interpolation.
145 Assumes src and dst surfaces are of 32 bit depth.
146 Assumes dst surface was allocated with the correct dimensions.
147 
148 \param src Source surface.
149 \param dst Destination surface.
150 \param cx Horizontal center coordinate.
151 \param cy Vertical center coordinate.
152 \param isin Integer version of sine of angle.
153 \param icos Integer version of cosine of angle.
154 \param flipx Flag indicating horizontal mirroring should be applied.
155 \param flipy Flag indicating vertical mirroring should be applied.
156 \param smooth Flag indicating anti-aliasing should be used.
157 */
158 static void
159 _transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy, int smooth)
160 {
161  int x, y, t1, t2, dx, dy, xd, yd, sdx, sdy, ax, ay, ex, ey, sw, sh;
162  tColorRGBA c00, c01, c10, c11, cswap;
163  tColorRGBA *pc, *sp;
164  int gap;
165 
166  /*
167  * Variable setup
168  */
169  xd = ((src->w - dst->w) << 15);
170  yd = ((src->h - dst->h) << 15);
171  ax = (cx << 16) - (icos * cx);
172  ay = (cy << 16) - (isin * cx);
173  sw = src->w - 1;
174  sh = src->h - 1;
175  pc = (tColorRGBA*) dst->pixels;
176  gap = dst->pitch - dst->w * 4;
177 
178  /*
179  * Switch between interpolating and non-interpolating code
180  */
181  if (smooth) {
182  for (y = 0; y < dst->h; y++) {
183  dy = cy - y;
184  sdx = (ax + (isin * dy)) + xd;
185  sdy = (ay - (icos * dy)) + yd;
186  for (x = 0; x < dst->w; x++) {
187  dx = (sdx >> 16);
188  dy = (sdy >> 16);
189  if (flipx) dx = sw - dx;
190  if (flipy) dy = sh - dy;
191  if ((unsigned)dx < (unsigned)sw && (unsigned)dy < (unsigned)sh) {
192  sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy) + dx;
193  c00 = *sp;
194  sp += 1;
195  c01 = *sp;
196  sp += (src->pitch/4);
197  c11 = *sp;
198  sp -= 1;
199  c10 = *sp;
200  if (flipx) {
201  cswap = c00; c00=c01; c01=cswap;
202  cswap = c10; c10=c11; c11=cswap;
203  }
204  if (flipy) {
205  cswap = c00; c00=c10; c10=cswap;
206  cswap = c01; c01=c11; c11=cswap;
207  }
208  /*
209  * Interpolate colors
210  */
211  ex = (sdx & 0xffff);
212  ey = (sdy & 0xffff);
213  t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff;
214  t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff;
215  pc->r = (((t2 - t1) * ey) >> 16) + t1;
216  t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff;
217  t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff;
218  pc->g = (((t2 - t1) * ey) >> 16) + t1;
219  t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff;
220  t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff;
221  pc->b = (((t2 - t1) * ey) >> 16) + t1;
222  t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff;
223  t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff;
224  pc->a = (((t2 - t1) * ey) >> 16) + t1;
225  }
226  sdx += icos;
227  sdy += isin;
228  pc++;
229  }
230  pc = (tColorRGBA *) ((Uint8 *) pc + gap);
231  }
232  } else {
233  for (y = 0; y < dst->h; y++) {
234  dy = cy - y;
235  sdx = (ax + (isin * dy)) + xd;
236  sdy = (ay - (icos * dy)) + yd;
237  for (x = 0; x < dst->w; x++) {
238  dx = (sdx >> 16);
239  dy = (sdy >> 16);
240  if ((unsigned)dx < (unsigned)src->w && (unsigned)dy < (unsigned)src->h) {
241  if(flipx) dx = sw - dx;
242  if(flipy) dy = sh - dy;
243  *pc = *((tColorRGBA *)((Uint8 *)src->pixels + src->pitch * dy) + dx);
244  }
245  sdx += icos;
246  sdy += isin;
247  pc++;
248  }
249  pc = (tColorRGBA *) ((Uint8 *) pc + gap);
250  }
251  }
252 }
253 
254 /* !
255 
256 \brief Rotates and zooms 8 bit palette/Y 'src' surface to 'dst' surface without smoothing.
257 
258 Rotates and zooms 8 bit RGBA/ABGR 'src' surface to 'dst' surface based on the control
259 parameters by scanning the destination surface.
260 Assumes src and dst surfaces are of 8 bit depth.
261 Assumes dst surface was allocated with the correct dimensions.
262 
263 \param src Source surface.
264 \param dst Destination surface.
265 \param cx Horizontal center coordinate.
266 \param cy Vertical center coordinate.
267 \param isin Integer version of sine of angle.
268 \param icos Integer version of cosine of angle.
269 \param flipx Flag indicating horizontal mirroring should be applied.
270 \param flipy Flag indicating vertical mirroring should be applied.
271 */
272 static void
273 transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy)
274 {
275  int x, y, dx, dy, xd, yd, sdx, sdy, ax, ay;
276  tColorY *pc;
277  int gap;
278 
279  /*
280  * Variable setup
281  */
282  xd = ((src->w - dst->w) << 15);
283  yd = ((src->h - dst->h) << 15);
284  ax = (cx << 16) - (icos * cx);
285  ay = (cy << 16) - (isin * cx);
286  pc = (tColorY*) dst->pixels;
287  gap = dst->pitch - dst->w;
288  /*
289  * Clear surface to colorkey
290  */
291  SDL_memset(pc, (int)(_colorkey(src) & 0xff), dst->pitch * dst->h);
292  /*
293  * Iterate through destination surface
294  */
295  for (y = 0; y < dst->h; y++) {
296  dy = cy - y;
297  sdx = (ax + (isin * dy)) + xd;
298  sdy = (ay - (icos * dy)) + yd;
299  for (x = 0; x < dst->w; x++) {
300  dx = (sdx >> 16);
301  dy = (sdy >> 16);
302  if ((unsigned)dx < (unsigned)src->w && (unsigned)dy < (unsigned)src->h) {
303  if (flipx) dx = (src->w-1)-dx;
304  if (flipy) dy = (src->h-1)-dy;
305  *pc = *((tColorY *)src->pixels + src->pitch * dy + dx);
306  }
307  sdx += icos;
308  sdy += isin;
309  pc++;
310  }
311  pc += gap;
312  }
313 }
314 
315 
316 /* !
317 \brief Rotates and zooms a surface with different horizontal and vertival scaling factors and optional anti-aliasing.
318 
319 Rotates a 32bit or 8bit 'src' surface to newly created 'dst' surface.
320 'angle' is the rotation in degrees, 'centerx' and 'centery' the rotation center. If 'smooth' is set
321 then the destination 32bit surface is anti-aliased. If the surface is not 8bit
322 or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
323 
324 \param src The surface to rotozoom.
325 \param angle The angle to rotate in degrees.
326 \param centerx The horizontal coordinate of the center of rotation
327 \param zoomy The vertical coordinate of the center of rotation
328 \param smooth Antialiasing flag; set to SMOOTHING_ON to enable.
329 \param flipx Set to 1 to flip the image horizontally
330 \param flipy Set to 1 to flip the image vertically
331 \param dstwidth The destination surface width
332 \param dstheight The destination surface height
333 \param cangle The angle cosine
334 \param sangle The angle sine
335 \return The new rotated surface.
336 
337 */
338 
339 SDL_Surface *
340 SDLgfx_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery, int smooth, int flipx, int flipy, int dstwidth, int dstheight, double cangle, double sangle)
341 {
342  SDL_Surface *rz_src;
343  SDL_Surface *rz_dst;
344  int is32bit;
345  int i;
346  Uint8 r,g,b;
347  Uint32 colorkey = 0;
348  int colorKeyAvailable = 0;
349  double sangleinv, cangleinv;
350 
351  /*
352  * Sanity check
353  */
354  if (src == NULL)
355  return (NULL);
356 
357  if (src->flags & SDL_TRUE/* SDL_SRCCOLORKEY */)
358  {
359  colorkey = _colorkey(src);
360  SDL_GetRGB(colorkey, src->format, &r, &g, &b);
361  colorKeyAvailable = 1;
362  }
363  /*
364  * Determine if source surface is 32bit or 8bit
365  */
366  is32bit = (src->format->BitsPerPixel == 32);
367  if ((is32bit) || (src->format->BitsPerPixel == 8)) {
368  /*
369  * Use source surface 'as is'
370  */
371  rz_src = src;
372  } else {
375  0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
376 #else
377  0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
378 #endif
379  );
380  rz_src = SDL_ConvertSurfaceFormat(src, format, src->flags);
381  is32bit = 1;
382  }
383 
384 
385  /* Determine target size */
386  /* _rotozoomSurfaceSizeTrig(rz_src->w, rz_src->h, angle, &dstwidth, &dstheight, &cangle, &sangle); */
387 
388  /*
389  * Calculate target factors from sin/cos and zoom
390  */
391  sangleinv = sangle*65536.0;
392  cangleinv = cangle*65536.0;
393 
394  /*
395  * Alloc space to completely contain the rotated surface
396  */
397  rz_dst = NULL;
398  if (is32bit) {
399  /*
400  * Target surface is 32bit with source RGBA/ABGR ordering
401  */
402  rz_dst =
403  SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
404  rz_src->format->Rmask, rz_src->format->Gmask,
405  rz_src->format->Bmask, rz_src->format->Amask);
406  } else {
407  /*
408  * Target surface is 8bit
409  */
410  rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
411  }
412 
413  /* Check target */
414  if (rz_dst == NULL)
415  return NULL;
416 
417  /* Adjust for guard rows */
418  rz_dst->h = dstheight;
419 
420  if (colorKeyAvailable == 1){
421  colorkey = SDL_MapRGB(rz_dst->format, r, g, b);
422 
423  SDL_FillRect(rz_dst, NULL, colorkey );
424  }
425 
426  /*
427  * Lock source surface
428  */
429  if (SDL_MUSTLOCK(rz_src)) {
430  SDL_LockSurface(rz_src);
431  }
432 
433  /*
434  * Check which kind of surface we have
435  */
436  if (is32bit) {
437  /*
438  * Call the 32bit transformation routine to do the rotation (using alpha)
439  */
440  _transformSurfaceRGBA(rz_src, rz_dst, centerx, centery,
441  (int) (sangleinv), (int) (cangleinv),
442  flipx, flipy,
443  smooth);
444  /*
445  * Turn on source-alpha support
446  */
447  /* SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255); */
448  SDL_SetColorKey(rz_dst, /* SDL_SRCCOLORKEY */ SDL_TRUE | SDL_RLEACCEL, _colorkey(rz_src));
449  } else {
450  /*
451  * Copy palette and colorkey info
452  */
453  for (i = 0; i < rz_src->format->palette->ncolors; i++) {
454  rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
455  }
456  rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
457  /*
458  * Call the 8bit transformation routine to do the rotation
459  */
460  transformSurfaceY(rz_src, rz_dst, centerx, centery,
461  (int) (sangleinv), (int) (cangleinv),
462  flipx, flipy);
463  SDL_SetColorKey(rz_dst, /* SDL_SRCCOLORKEY */ SDL_TRUE | SDL_RLEACCEL, _colorkey(rz_src));
464  }
465 
466  /* copy alpha mod, color mod, and blend mode */
467  {
469  Uint8 alphaMod, cr, cg, cb;
470  SDL_GetSurfaceAlphaMod(src, &alphaMod);
471  SDL_GetSurfaceBlendMode(src, &blendMode);
472  SDL_GetSurfaceColorMod(src, &cr, &cg, &cb);
473  SDL_SetSurfaceAlphaMod(rz_dst, alphaMod);
474  SDL_SetSurfaceBlendMode(rz_dst, blendMode);
475  SDL_SetSurfaceColorMod(rz_dst, cr, cg, cb);
476  }
477 
478  /*
479  * Unlock source surface
480  */
481  if (SDL_MUSTLOCK(rz_src)) {
482  SDL_UnlockSurface(rz_src);
483  }
484 
485  /*
486  * Cleanup temp surface
487  */
488  if (rz_src != src) {
489  SDL_FreeSurface(rz_src);
490  }
491 
492  /*
493  * Return destination surface
494  */
495  return (rz_dst);
496 }
#define SDL_GetRGB
GLenum GLenum dst
#define SDL_ConvertSurfaceFormat
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1565
#define SDL_UnlockSurface
#define SDL_ceil
Uint8 y
Definition: SDL_rotate.c:59
GLint GLint GLsizei width
Definition: SDL_opengl.h:1565
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:155
#define SDL_SWSURFACE
Definition: SDL_surface.h:52
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1567
SDL_BlendMode
The blend mode used in SDL_RenderCopy() and drawing operations.
Definition: SDL_blendmode.h:40
#define SDL_MasksToPixelFormatEnum
#define SDL_fabs
#define GUARD_ROWS
Definition: SDL_rotate.c:77
A collection of pixels used in software blitting.
Definition: SDL_surface.h:69
#define SDL_LIL_ENDIAN
Definition: SDL_endian.h:37
Uint8 a
Definition: SDL_rotate.c:52
GLint GLint GLsizei GLsizei height
Definition: SDL_opengl.h:1565
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t1
Uint32 flags
Definition: SDL_surface.h:71
#define SDL_GetSurfaceBlendMode
static SDL_BlendMode blendMode
Definition: testdraw2.c:34
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1567
void * pixels
Definition: SDL_surface.h:75
#define SDL_GetColorKey
#define SDL_FreeSurface
#define SDL_SetSurfaceColorMod
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:139
Uint8 BitsPerPixel
Definition: SDL_pixels.h:303
#define SDL_cos
static void transformSurfaceY(SDL_Surface *src, SDL_Surface *dst, int cx, int cy, int isin, int icos, int flipx, int flipy)
Definition: SDL_rotate.c:273
#define SDL_SetColorKey
#define SDL_GetSurfaceAlphaMod
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:42
#define NULL
Definition: begin_code.h:143
SDL_Color * colors
Definition: SDL_pixels.h:291
SDL_PixelFormat * format
Definition: SDL_surface.h:72
Uint8 r
Definition: SDL_rotate.c:49
#define SDL_LockSurface
#define M_PI
Definition: SDL_stdinc.h:436
#define SDL_CreateRGBSurface
#define SDL_GetSurfaceColorMod
#define SDL_MUSTLOCK(S)
Definition: SDL_surface.h:61
#define SDL_SetSurfaceBlendMode
#define SDL_FillRect
#define SDL_MapRGB
GLfloat angle
static Uint32 _colorkey(SDL_Surface *src)
Definition: SDL_rotate.c:88
#define MAX(a, b)
Definition: SDL_rotate.c:65
SDL_Palette * palette
Definition: SDL_pixels.h:302
SDL_Surface * SDLgfx_rotateSurface(SDL_Surface *src, double angle, int centerx, int centery, int smooth, int flipx, int flipy, int dstwidth, int dstheight, double cangle, double sangle)
Definition: SDL_rotate.c:340
GLenum src
#define SDL_BYTEORDER
void SDLgfx_rotozoomSurfaceSizeTrig(int width, int height, double angle, int *dstwidth, int *dstheight, double *cangle, double *sangle)
Definition: SDL_rotate.c:109
Uint8 b
Definition: SDL_rotate.c:51
#define SDL_SetSurfaceAlphaMod
Uint8 g
Definition: SDL_rotate.c:50
#define SDL_memset
#define SDL_RLEACCEL
Definition: SDL_surface.h:54
static void _transformSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst, int cx, int cy, int isin, int icos, int flipx, int flipy, int smooth)
Definition: SDL_rotate.c:159
#define SDL_sin