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