zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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_config.h"
32 
33 #ifdef WIN32
34 #include <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 {
49  Uint8 r;
50  Uint8 g;
51  Uint8 b;
52  Uint8 a;
53 } tColorRGBA;
54 
55 /* !
56 \brief A 8bit Y/palette pixel.
57 */
58 typedef struct tColorY {
59  Uint8 y;
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 */
88 {
89  Uint32 key = 0;
90  SDL_GetColorKey(src, &key);
91  return key;
92 }
93 
94 
95 /* !
96 \brief Internal target surface sizing function for rotations with trig result return.
97 
98 \param width The source surface width.
99 \param height The source surface height.
100 \param angle The angle to rotate in degrees.
101 \param dstwidth The calculated width of the destination surface.
102 \param dstheight The calculated height of the destination surface.
103 \param cangle The sine of the angle
104 \param sangle The cosine of the angle
105 
106 */
108  int *dstwidth, int *dstheight,
109  double *cangle, double *sangle)
110 {
111  double x, y, cx, cy, sx, sy;
112  double radangle;
113  int dstwidthhalf, dstheighthalf;
114 
115  /*
116  * Determine destination width and height by rotating a centered source box
117  */
118  radangle = angle * (M_PI / 180.0);
119  *sangle = SDL_sin(radangle);
120  *cangle = SDL_cos(radangle);
121  x = (double)(width / 2);
122  y = (double)(height / 2);
123  cx = *cangle * x;
124  cy = *cangle * y;
125  sx = *sangle * x;
126  sy = *sangle * y;
127 
128  dstwidthhalf = MAX((int)
129  SDL_ceil(MAX(MAX(MAX(SDL_fabs(cx + sy), SDL_fabs(cx - sy)), SDL_fabs(-cx + sy)), SDL_fabs(-cx - sy))), 1);
130  dstheighthalf = MAX((int)
131  SDL_ceil(MAX(MAX(MAX(SDL_fabs(sx + cy), SDL_fabs(sx - cy)), SDL_fabs(-sx + cy)), SDL_fabs(-sx - cy))), 1);
132  *dstwidth = 2 * dstwidthhalf;
133  *dstheight = 2 * dstheighthalf;
134 }
135 
136 
137 /* !
138 \brief Internal 32 bit rotozoomer with optional anti-aliasing.
139 
140 Rotates and zooms 32 bit RGBA/ABGR 'src' surface to 'dst' surface based on the control
141 parameters by scanning the destination surface and applying optionally anti-aliasing
142 by bilinear interpolation.
143 Assumes src and dst surfaces are of 32 bit depth.
144 Assumes dst surface was allocated with the correct dimensions.
145 
146 \param src Source surface.
147 \param dst Destination surface.
148 \param cx Horizontal center coordinate.
149 \param cy Vertical center coordinate.
150 \param isin Integer version of sine of angle.
151 \param icos Integer version of cosine of angle.
152 \param flipx Flag indicating horizontal mirroring should be applied.
153 \param flipy Flag indicating vertical mirroring should be applied.
154 \param smooth Flag indicating anti-aliasing should be used.
155 */
156 void _transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy, int smooth)
157 {
158  int x, y, t1, t2, dx, dy, xd, yd, sdx, sdy, ax, ay, ex, ey, sw, sh;
159  tColorRGBA c00, c01, c10, c11, cswap;
160  tColorRGBA *pc, *sp;
161  int gap;
162 
163  /*
164  * Variable setup
165  */
166  xd = ((src->w - dst->w) << 15);
167  yd = ((src->h - dst->h) << 15);
168  ax = (cx << 16) - (icos * cx);
169  ay = (cy << 16) - (isin * cx);
170  sw = src->w - 1;
171  sh = src->h - 1;
172  pc = (tColorRGBA*) dst->pixels;
173  gap = dst->pitch - dst->w * 4;
174 
175  /*
176  * Switch between interpolating and non-interpolating code
177  */
178  if (smooth) {
179  for (y = 0; y < dst->h; y++) {
180  dy = cy - y;
181  sdx = (ax + (isin * dy)) + xd;
182  sdy = (ay - (icos * dy)) + yd;
183  for (x = 0; x < dst->w; x++) {
184  dx = (sdx >> 16);
185  dy = (sdy >> 16);
186  if (flipx) dx = sw - dx;
187  if (flipy) dy = sh - dy;
188  if ((dx > -1) && (dy > -1) && (dx < (src->w-1)) && (dy < (src->h-1))) {
189  sp = (tColorRGBA *)src->pixels;;
190  sp += ((src->pitch/4) * dy);
191  sp += dx;
192  c00 = *sp;
193  sp += 1;
194  c01 = *sp;
195  sp += (src->pitch/4);
196  c11 = *sp;
197  sp -= 1;
198  c10 = *sp;
199  if (flipx) {
200  cswap = c00; c00=c01; c01=cswap;
201  cswap = c10; c10=c11; c11=cswap;
202  }
203  if (flipy) {
204  cswap = c00; c00=c10; c10=cswap;
205  cswap = c01; c01=c11; c11=cswap;
206  }
207  /*
208  * Interpolate colors
209  */
210  ex = (sdx & 0xffff);
211  ey = (sdy & 0xffff);
212  t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff;
213  t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff;
214  pc->r = (((t2 - t1) * ey) >> 16) + t1;
215  t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff;
216  t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff;
217  pc->g = (((t2 - t1) * ey) >> 16) + t1;
218  t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff;
219  t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff;
220  pc->b = (((t2 - t1) * ey) >> 16) + t1;
221  t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff;
222  t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff;
223  pc->a = (((t2 - t1) * ey) >> 16) + t1;
224  }
225  sdx += icos;
226  sdy += isin;
227  pc++;
228  }
229  pc = (tColorRGBA *) ((Uint8 *) pc + gap);
230  }
231  } else {
232  for (y = 0; y < dst->h; y++) {
233  dy = cy - y;
234  sdx = (ax + (isin * dy)) + xd;
235  sdy = (ay - (icos * dy)) + yd;
236  for (x = 0; x < dst->w; x++) {
237  dx = (short) (sdx >> 16);
238  dy = (short) (sdy >> 16);
239  if (flipx) dx = (src->w-1)-dx;
240  if (flipy) dy = (src->h-1)-dy;
241  if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
242  sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
243  sp += dx;
244  *pc = *sp;
245  }
246  sdx += icos;
247  sdy += isin;
248  pc++;
249  }
250  pc = (tColorRGBA *) ((Uint8 *) pc + gap);
251  }
252  }
253 }
254 
255 /* !
256 
257 \brief Rotates and zooms 8 bit palette/Y 'src' surface to 'dst' surface without smoothing.
258 
259 Rotates and zooms 8 bit RGBA/ABGR 'src' surface to 'dst' surface based on the control
260 parameters by scanning the destination surface.
261 Assumes src and dst surfaces are of 8 bit depth.
262 Assumes dst surface was allocated with the correct dimensions.
263 
264 \param src Source surface.
265 \param dst Destination surface.
266 \param cx Horizontal center coordinate.
267 \param cy Vertical center coordinate.
268 \param isin Integer version of sine of angle.
269 \param icos Integer version of cosine of angle.
270 \param flipx Flag indicating horizontal mirroring should be applied.
271 \param flipy Flag indicating vertical mirroring should be applied.
272 */
273 void 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, *sp;
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 = (short) (sdx >> 16);
301  dy = (short) (sdy >> 16);
302  if (flipx) dx = (src->w-1)-dx;
303  if (flipy) dy = (src->h-1)-dy;
304  if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
305  sp = (tColorY *) (src->pixels);
306  sp += (src->pitch * dy + dx);
307  *pc = *sp;
308  }
309  sdx += icos;
310  sdy += isin;
311  pc++;
312  }
313  pc += gap;
314  }
315 }
316 
317 
318 
319 
320 /* !
321 \brief Rotates and zooms a surface with different horizontal and vertival scaling factors and optional anti-aliasing.
322 
323 Rotates a 32bit or 8bit 'src' surface to newly created 'dst' surface.
324 'angle' is the rotation in degrees, 'centerx' and 'centery' the rotation center. If 'smooth' is set
325 then the destination 32bit surface is anti-aliased. If the surface is not 8bit
326 or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
327 
328 \param src The surface to rotozoom.
329 \param angle The angle to rotate in degrees.
330 \param centerx The horizontal coordinate of the center of rotation
331 \param zoomy The vertical coordinate of the center of rotation
332 \param smooth Antialiasing flag; set to SMOOTHING_ON to enable.
333 \param flipx Set to 1 to flip the image horizontally
334 \param flipy Set to 1 to flip the image vertically
335 \param dstwidth The destination surface width
336 \param dstheight The destination surface height
337 \param cangle The angle cosine
338 \param sangle The angle sine
339 \return The new rotated surface.
340 
341 */
342 
343 SDL_Surface *_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery, int smooth, int flipx, int flipy, int dstwidth, int dstheight, double cangle, double sangle)
344 {
345  SDL_Surface *rz_src;
346  SDL_Surface *rz_dst;
347  int is32bit;
348  int i, src_converted;
349  Uint8 r,g,b;
350  Uint32 colorkey = 0;
351  int colorKeyAvailable = 0;
352  double sangleinv, cangleinv;
353 
354  /*
355  * Sanity check
356  */
357  if (src == NULL)
358  return (NULL);
359 
360  if (src->flags & SDL_TRUE/* SDL_SRCCOLORKEY */)
361  {
362  colorkey = _colorkey(src);
363  SDL_GetRGB(colorkey, src->format, &r, &g, &b);
364  colorKeyAvailable = 1;
365  }
366  /*
367  * Determine if source surface is 32bit or 8bit
368  */
369  is32bit = (src->format->BitsPerPixel == 32);
370  if ((is32bit) || (src->format->BitsPerPixel == 8)) {
371  /*
372  * Use source surface 'as is'
373  */
374  rz_src = src;
375  src_converted = 0;
376  } else {
377  /*
378  * New source surface is 32bit with a defined RGBA ordering
379  */
380  rz_src =
381  SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
383  0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
384 #else
385  0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
386 #endif
387  );
388  if(colorKeyAvailable)
389  SDL_SetColorKey(src, 0, 0);
390 
391  SDL_BlitSurface(src, NULL, rz_src, NULL);
392 
393  if(colorKeyAvailable)
394  SDL_SetColorKey(src, SDL_TRUE /* SDL_SRCCOLORKEY */, colorkey);
395  src_converted = 1;
396  is32bit = 1;
397  }
398 
399 
400  /* Determine target size */
401  /* _rotozoomSurfaceSizeTrig(rz_src->w, rz_src->h, angle, &dstwidth, &dstheight, &cangle, &sangle); */
402 
403  /*
404  * Calculate target factors from sin/cos and zoom
405  */
406  sangleinv = sangle*65536.0;
407  cangleinv = cangle*65536.0;
408 
409  /*
410  * Alloc space to completely contain the rotated surface
411  */
412  rz_dst = NULL;
413  if (is32bit) {
414  /*
415  * Target surface is 32bit with source RGBA/ABGR ordering
416  */
417  rz_dst =
418  SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
419  rz_src->format->Rmask, rz_src->format->Gmask,
420  rz_src->format->Bmask, rz_src->format->Amask);
421  } else {
422  /*
423  * Target surface is 8bit
424  */
425  rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
426  }
427 
428  /* Check target */
429  if (rz_dst == NULL)
430  return NULL;
431 
432  /* Adjust for guard rows */
433  rz_dst->h = dstheight;
434 
435  if (colorKeyAvailable == 1){
436  colorkey = SDL_MapRGB(rz_dst->format, r, g, b);
437 
438  SDL_FillRect(rz_dst, NULL, colorkey );
439  }
440 
441  /*
442  * Lock source surface
443  */
444  if (SDL_MUSTLOCK(rz_src)) {
445  SDL_LockSurface(rz_src);
446  }
447 
448  /*
449  * Check which kind of surface we have
450  */
451  if (is32bit) {
452  /*
453  * Call the 32bit transformation routine to do the rotation (using alpha)
454  */
455  _transformSurfaceRGBA(rz_src, rz_dst, centerx, centery,
456  (int) (sangleinv), (int) (cangleinv),
457  flipx, flipy,
458  smooth);
459  /*
460  * Turn on source-alpha support
461  */
462  /* SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255); */
463  SDL_SetColorKey(rz_dst, /* SDL_SRCCOLORKEY */ SDL_TRUE | SDL_RLEACCEL, _colorkey(rz_src));
464  } else {
465  /*
466  * Copy palette and colorkey info
467  */
468  for (i = 0; i < rz_src->format->palette->ncolors; i++) {
469  rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
470  }
471  rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
472  /*
473  * Call the 8bit transformation routine to do the rotation
474  */
475  transformSurfaceY(rz_src, rz_dst, centerx, centery,
476  (int) (sangleinv), (int) (cangleinv),
477  flipx, flipy);
478  SDL_SetColorKey(rz_dst, /* SDL_SRCCOLORKEY */ SDL_TRUE | SDL_RLEACCEL, _colorkey(rz_src));
479  }
480  /*
481  * Unlock source surface
482  */
483  if (SDL_MUSTLOCK(rz_src)) {
484  SDL_UnlockSurface(rz_src);
485  }
486 
487  /*
488  * Cleanup temp surface
489  */
490  if (src_converted) {
491  SDL_FreeSurface(rz_src);
492  }
493 
494  /*
495  * Return destination surface
496  */
497  return (rz_dst);
498 }
499 
DECLSPEC double SDLCALL SDL_cos(double x)
Definition: SDL_stdlib.c:70
DECLSPEC void SDLCALL SDL_FreeSurface(SDL_Surface *surface)
Definition: SDL_surface.c:1053
DECLSPEC SDL_Surface *SDLCALL SDL_CreateRGBSurface(Uint32 flags, int width, int height, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
Definition: SDL_surface.c:35
DECLSPEC double SDLCALL SDL_fabs(double x)
Definition: SDL_stdlib.c:90
GLboolean GLboolean g
Definition: glew.h:8736
#define NULL
Definition: ftobjs.h:61
t2
Definition: e_log.c:151
#define SDL_SWSURFACE
Definition: SDL_surface.h:52
GLdouble angle
Definition: glew.h:8396
#define GUARD_ROWS
Definition: SDL_rotate.c:77
EGLSurface EGLint x
Definition: eglext.h:293
A collection of pixels used in software blitting.
Definition: SDL_surface.h:69
#define SDL_BlitSurface
Definition: SDL_surface.h:447
EGLSurface EGLint EGLint EGLint EGLint height
Definition: eglext.h:293
GLboolean GLboolean GLboolean GLboolean a
Definition: glew.h:8736
#define SDL_LIL_ENDIAN
Definition: SDL_endian.h:37
DECLSPEC int SDLCALL SDL_GetColorKey(SDL_Surface *surface, Uint32 *key)
Gets the color key (transparent pixel) in a blittable surface.
Definition: SDL_surface.c:218
if(!yyg->yy_init)
struct tColorRGBA tColorRGBA
DECLSPEC double SDLCALL SDL_sin(double x)
Definition: SDL_stdlib.c:140
DECLSPEC int SDLCALL SDL_FillRect(SDL_Surface *dst, const SDL_Rect *rect, Uint32 color)
Definition: SDL_fillrect.c:332
Uint32 flags
Definition: SDL_surface.h:71
Uint32 _colorkey(SDL_Surface *src)
Definition: SDL_rotate.c:87
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t1
Definition: glew.h:11582
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:145
DECLSPEC void SDLCALL SDL_UnlockSurface(SDL_Surface *surface)
Definition: SDL_surface.c:786
GLenum GLenum dst
Definition: glew.h:2396
void * pixels
Definition: SDL_surface.h:75
EGLSurface EGLint EGLint EGLint width
Definition: eglext.h:293
Uint8 BitsPerPixel
Definition: SDL_pixels.h:276
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
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:156
DECLSPEC void *SDLCALL SDL_memset(void *dst, int c, size_t len)
Definition: SDL_string.c:261
SDL_Surface * _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:343
struct tColorY tColorY
void _rotozoomSurfaceSizeTrig(int width, int height, double angle, int *dstwidth, int *dstheight, double *cangle, double *sangle)
Definition: SDL_rotate.c:107
#define M_PI
Definition: os.h:45
DECLSPEC int SDLCALL SDL_SetColorKey(SDL_Surface *surface, int flag, Uint32 key)
Sets the color key (transparent pixel) in a blittable surface.
Definition: SDL_surface.c:173
EGLSurface EGLint EGLint y
Definition: eglext.h:293
SDL_Color * colors
Definition: SDL_pixels.h:264
SDL_PixelFormat * format
Definition: SDL_surface.h:72
#define SDL_MUSTLOCK(S)
Definition: SDL_surface.h:61
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:129
DECLSPEC Uint32 SDLCALL SDL_MapRGB(const SDL_PixelFormat *format, Uint8 r, Uint8 g, Uint8 b)
Maps an RGB triple to an opaque pixel value for a given pixel format.
Definition: SDL_pixels.c:799
DECLSPEC void SDLCALL SDL_GetRGB(Uint32 pixel, const SDL_PixelFormat *format, Uint8 *r, Uint8 *g, Uint8 *b)
Get the RGB components from a pixel of the specified format.
Definition: SDL_pixels.c:826
DECLSPEC double SDLCALL SDL_ceil(double x)
Definition: SDL_stdlib.c:50
GLdouble GLdouble GLdouble r
Definition: glew.h:1392
GLdouble GLdouble GLdouble b
Definition: glew.h:8383
#define MAX(a, b)
Definition: SDL_rotate.c:65
GLint GLint GLint GLint GLint w
Definition: gl2ext.h:1215
SDL_Palette * palette
Definition: SDL_pixels.h:275
GLenum src
Definition: glew.h:2396
int i
Definition: pngrutil.c:1377
#define SDL_BYTEORDER
DECLSPEC int SDLCALL SDL_LockSurface(SDL_Surface *surface)
Sets up a surface for directly accessing the pixels.
Definition: SDL_surface.c:765
#define SDL_RLEACCEL
Definition: SDL_surface.h:54