0
|
1 /*
|
|
2
|
|
3 SDL_rotozoom.c - rotozoomer for 32bit or 8bit surfaces
|
|
4
|
|
5 LGPL (c) A. Schiffler
|
|
6
|
|
7 */
|
|
8
|
|
9 #ifdef WIN32
|
|
10 #include <windows.h>
|
|
11 #endif
|
|
12
|
|
13 #include <stdlib.h>
|
|
14 #include <string.h>
|
|
15
|
|
16 #include "SDL_rotozoom.h"
|
|
17
|
|
18 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
|
|
19
|
|
20 /*
|
|
21
|
|
22 32bit Zoomer with optional anti-aliasing by bilinear interpolation.
|
|
23
|
|
24 Zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
|
|
25
|
|
26 */
|
|
27
|
|
28 int zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int smooth)
|
|
29 {
|
|
30 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy, ex, ey, t1, t2, sstep;
|
|
31 tColorRGBA *c00, *c01, *c10, *c11;
|
|
32 tColorRGBA *sp, *csp, *dp;
|
|
33 int sgap, dgap;
|
|
34
|
|
35 /*
|
|
36 * Variable setup
|
|
37 */
|
|
38 if (smooth) {
|
|
39 /*
|
|
40 * For interpolation: assume source dimension is one pixel
|
|
41 */
|
|
42 /*
|
|
43 * smaller to avoid overflow on right and bottom edge.
|
|
44 */
|
|
45 sx = (int) (65536.0 * (float) (src->w - 1) / (float) dst->w);
|
|
46 sy = (int) (65536.0 * (float) (src->h - 1) / (float) dst->h);
|
|
47 } else {
|
|
48 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
|
|
49 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
|
|
50 }
|
|
51
|
|
52 /*
|
|
53 * Allocate memory for row increments
|
|
54 */
|
|
55 if ((sax = (int *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
|
|
56 return (-1);
|
|
57 }
|
|
58 if ((say = (int *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
|
|
59 free(sax);
|
|
60 return (-1);
|
|
61 }
|
|
62
|
|
63 /*
|
|
64 * Precalculate row increments
|
|
65 */
|
|
66 csx = 0;
|
|
67 csax = sax;
|
|
68 for (x = 0; x <= dst->w; x++) {
|
|
69 *csax = csx;
|
|
70 csax++;
|
|
71 csx &= 0xffff;
|
|
72 csx += sx;
|
|
73 }
|
|
74 csy = 0;
|
|
75 csay = say;
|
|
76 for (y = 0; y <= dst->h; y++) {
|
|
77 *csay = csy;
|
|
78 csay++;
|
|
79 csy &= 0xffff;
|
|
80 csy += sy;
|
|
81 }
|
|
82
|
|
83 /*
|
|
84 * Pointer setup
|
|
85 */
|
|
86 sp = csp = (tColorRGBA *) src->pixels;
|
|
87 dp = (tColorRGBA *) dst->pixels;
|
|
88 sgap = src->pitch - src->w * 4;
|
|
89 dgap = dst->pitch - dst->w * 4;
|
|
90
|
|
91 /*
|
|
92 * Switch between interpolating and non-interpolating code
|
|
93 */
|
|
94 if (smooth) {
|
|
95
|
|
96 /*
|
|
97 * Interpolating Zoom
|
|
98 */
|
|
99
|
|
100 /*
|
|
101 * Scan destination
|
|
102 */
|
|
103 csay = say;
|
|
104 for (y = 0; y < dst->h; y++) {
|
|
105 /*
|
|
106 * Setup color source pointers
|
|
107 */
|
|
108 c00 = csp;
|
|
109 c01 = csp;
|
|
110 c01++;
|
|
111 c10 = (tColorRGBA *) ((Uint8 *) csp + src->pitch);
|
|
112 c11 = c10;
|
|
113 c11++;
|
|
114 csax = sax;
|
|
115 for (x = 0; x < dst->w; x++) {
|
|
116
|
|
117 /*
|
|
118 * Interpolate colors
|
|
119 */
|
|
120 ex = (*csax & 0xffff);
|
|
121 ey = (*csay & 0xffff);
|
|
122 t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
|
|
123 t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
|
|
124 dp->r = (((t2 - t1) * ey) >> 16) + t1;
|
|
125 t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff;
|
|
126 t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff;
|
|
127 dp->g = (((t2 - t1) * ey) >> 16) + t1;
|
|
128 t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff;
|
|
129 t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff;
|
|
130 dp->b = (((t2 - t1) * ey) >> 16) + t1;
|
|
131 t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff;
|
|
132 t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff;
|
|
133 dp->a = (((t2 - t1) * ey) >> 16) + t1;
|
|
134
|
|
135 /*
|
|
136 * Advance source pointers
|
|
137 */
|
|
138 csax++;
|
|
139 sstep = (*csax >> 16);
|
|
140 c00 += sstep;
|
|
141 c01 += sstep;
|
|
142 c10 += sstep;
|
|
143 c11 += sstep;
|
|
144 /*
|
|
145 * Advance destination pointer
|
|
146 */
|
|
147 dp++;
|
|
148 }
|
|
149 /*
|
|
150 * Advance source pointer
|
|
151 */
|
|
152 csay++;
|
|
153 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
|
|
154 /*
|
|
155 * Advance destination pointers
|
|
156 */
|
|
157 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
|
|
158 }
|
|
159
|
|
160 } else {
|
|
161
|
|
162 /*
|
|
163 * Non-Interpolating Zoom
|
|
164 */
|
|
165
|
|
166 csay = say;
|
|
167 for (y = 0; y < dst->h; y++) {
|
|
168 sp = csp;
|
|
169 csax = sax;
|
|
170 for (x = 0; x < dst->w; x++) {
|
|
171 /*
|
|
172 * Draw
|
|
173 */
|
|
174 *dp = *sp;
|
|
175 /*
|
|
176 * Advance source pointers
|
|
177 */
|
|
178 csax++;
|
|
179 sp += (*csax >> 16);
|
|
180 /*
|
|
181 * Advance destination pointer
|
|
182 */
|
|
183 dp++;
|
|
184 }
|
|
185 /*
|
|
186 * Advance source pointer
|
|
187 */
|
|
188 csay++;
|
|
189 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
|
|
190 /*
|
|
191 * Advance destination pointers
|
|
192 */
|
|
193 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
|
|
194 }
|
|
195
|
|
196 }
|
|
197
|
|
198 /*
|
|
199 * Remove temp arrays
|
|
200 */
|
|
201 free(sax);
|
|
202 free(say);
|
|
203
|
|
204 return (0);
|
|
205 }
|
|
206
|
|
207 /*
|
|
208
|
|
209 8bit Zoomer without smoothing.
|
|
210
|
|
211 Zoomes 8bit palette/Y 'src' surface to 'dst' surface.
|
|
212
|
|
213 */
|
|
214
|
|
215 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
|
|
216 {
|
|
217 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
|
|
218 Uint8 *sp, *dp, *csp;
|
|
219 int dgap;
|
|
220
|
|
221 /*
|
|
222 * Variable setup
|
|
223 */
|
|
224 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
|
|
225 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
|
|
226
|
|
227 /*
|
|
228 * Allocate memory for row increments
|
|
229 */
|
|
230 if ((sax = (Uint32 *) malloc(dst->w * sizeof(Uint32))) == NULL) {
|
|
231 return (-1);
|
|
232 }
|
|
233 if ((say = (Uint32 *) malloc(dst->h * sizeof(Uint32))) == NULL) {
|
|
234 if (sax != NULL) {
|
|
235 free(sax);
|
|
236 }
|
|
237 return (-1);
|
|
238 }
|
|
239
|
|
240 /*
|
|
241 * Precalculate row increments
|
|
242 */
|
|
243 csx = 0;
|
|
244 csax = sax;
|
|
245 for (x = 0; x < dst->w; x++) {
|
|
246 csx += sx;
|
|
247 *csax = (csx >> 16);
|
|
248 csx &= 0xffff;
|
|
249 csax++;
|
|
250 }
|
|
251 csy = 0;
|
|
252 csay = say;
|
|
253 for (y = 0; y < dst->h; y++) {
|
|
254 csy += sy;
|
|
255 *csay = (csy >> 16);
|
|
256 csy &= 0xffff;
|
|
257 csay++;
|
|
258 }
|
|
259
|
|
260 csx = 0;
|
|
261 csax = sax;
|
|
262 for (x = 0; x < dst->w; x++) {
|
|
263 csx += (*csax);
|
|
264 csax++;
|
|
265 }
|
|
266 csy = 0;
|
|
267 csay = say;
|
|
268 for (y = 0; y < dst->h; y++) {
|
|
269 csy += (*csay);
|
|
270 csay++;
|
|
271 }
|
|
272
|
|
273 /*
|
|
274 * Pointer setup
|
|
275 */
|
|
276 sp = csp = (Uint8 *) src->pixels;
|
|
277 dp = (Uint8 *) dst->pixels;
|
|
278 dgap = dst->pitch - dst->w;
|
|
279
|
|
280 /*
|
|
281 * Draw
|
|
282 */
|
|
283 csay = say;
|
|
284 for (y = 0; y < dst->h; y++) {
|
|
285 csax = sax;
|
|
286 sp = csp;
|
|
287 for (x = 0; x < dst->w; x++) {
|
|
288 /*
|
|
289 * Draw
|
|
290 */
|
|
291 *dp = *sp;
|
|
292 /*
|
|
293 * Advance source pointers
|
|
294 */
|
|
295 sp += (*csax);
|
|
296 csax++;
|
|
297 /*
|
|
298 * Advance destination pointer
|
|
299 */
|
|
300 dp++;
|
|
301 }
|
|
302 /*
|
|
303 * Advance source pointer (for row)
|
|
304 */
|
|
305 csp += ((*csay) * src->pitch);
|
|
306 csay++;
|
|
307 /*
|
|
308 * Advance destination pointers
|
|
309 */
|
|
310 dp += dgap;
|
|
311 }
|
|
312
|
|
313 /*
|
|
314 * Remove temp arrays
|
|
315 */
|
|
316 free(sax);
|
|
317 free(say);
|
|
318
|
|
319 return (0);
|
|
320 }
|
|
321
|
|
322 /*
|
|
323
|
|
324 32bit Rotozoomer with optional anti-aliasing by bilinear interpolation.
|
|
325
|
|
326 Rotates and zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
|
|
327
|
|
328 */
|
|
329
|
|
330 void transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int smooth)
|
|
331 {
|
|
332 int x, y, t1, t2, dx, dy, xd, yd, sdx, sdy, ax, ay, ex, ey, sw, sh;
|
|
333 tColorRGBA c00, c01, c10, c11;
|
|
334 tColorRGBA *pc, *sp, *spb;
|
|
335 int gap;
|
|
336
|
|
337 /*
|
|
338 * Variable setup
|
|
339 */
|
|
340 xd = ((src->w - dst->w) << 15);
|
|
341 yd = ((src->h - dst->h) << 15);
|
|
342 ax = (cx << 16) - (icos * cx);
|
|
343 ay = (cy << 16) - (isin * cx);
|
|
344 sw = src->w - 1;
|
|
345 sh = src->h - 1;
|
|
346 pc = (tColorRGBA*)(dst->pixels);
|
|
347 gap = dst->pitch - dst->w * 4;
|
|
348
|
|
349 /*
|
|
350 * Switch between interpolating and non-interpolating code
|
|
351 */
|
|
352 if (smooth) {
|
|
353 for (y = 0; y < dst->h; y++) {
|
|
354 dy = cy - y;
|
|
355 sdx = (ax + (isin * dy)) + xd;
|
|
356 sdy = (ay - (icos * dy)) + yd;
|
|
357 for (x = 0; x < dst->w; x++) {
|
|
358 dx = (sdx >> 16);
|
|
359 dy = (sdy >> 16);
|
|
360 if ((dx >= -1) && (dy >= -1) && (dx < src->w) && (dy < src->h)) {
|
|
361 if ((dx >= 0) && (dy >= 0) && (dx < sw) && (dy < sh)) {
|
|
362 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
|
|
363 sp += dx;
|
|
364 c00 = *sp;
|
|
365 sp += 1;
|
|
366 c01 = *sp;
|
|
367 sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
|
|
368 sp -= 1;
|
|
369 c10 = *sp;
|
|
370 sp += 1;
|
|
371 c11 = *sp;
|
|
372 } else if ((dx == sw) && (dy == sh)) {
|
|
373 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
|
|
374 sp += dx;
|
|
375 c00 = *sp;
|
|
376 c01 = *sp;
|
|
377 c10 = *sp;
|
|
378 c11 = *sp;
|
|
379 } else if ((dx == -1) && (dy == -1)) {
|
|
380 sp = (tColorRGBA *) (src->pixels);
|
|
381 c00 = *sp;
|
|
382 c01 = *sp;
|
|
383 c10 = *sp;
|
|
384 c11 = *sp;
|
|
385 } else if ((dx == -1) && (dy == sh)) {
|
|
386 sp = (tColorRGBA *) (src->pixels);
|
|
387 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
|
|
388 c00 = *sp;
|
|
389 c01 = *sp;
|
|
390 c10 = *sp;
|
|
391 c11 = *sp;
|
|
392 } else if ((dx == sw) && (dy == -1)) {
|
|
393 sp = (tColorRGBA *) (src->pixels);
|
|
394 sp += dx;
|
|
395 c00 = *sp;
|
|
396 c01 = *sp;
|
|
397 c10 = *sp;
|
|
398 c11 = *sp;
|
|
399 } else if (dx == -1) {
|
|
400 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
|
|
401 c00 = *sp;
|
|
402 c01 = *sp;
|
|
403 c10 = *sp;
|
|
404 sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
|
|
405 c11 = *sp;
|
|
406 } else if (dy == -1) {
|
|
407 sp = (tColorRGBA *) (src->pixels);
|
|
408 sp += dx;
|
|
409 c00 = *sp;
|
|
410 c01 = *sp;
|
|
411 c10 = *sp;
|
|
412 sp += 1;
|
|
413 c11 = *sp;
|
|
414 } else if (dx == sw) {
|
|
415 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
|
|
416 sp += dx;
|
|
417 c00 = *sp;
|
|
418 c01 = *sp;
|
|
419 sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
|
|
420 c10 = *sp;
|
|
421 c11 = *sp;
|
|
422 } else if (dy == sh) {
|
|
423 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
|
|
424 sp += dx;
|
|
425 c00 = *sp;
|
|
426 sp += 1;
|
|
427 c01 = *sp;
|
|
428 c10 = *sp;
|
|
429 c11 = *sp;
|
|
430 }
|
|
431 /*
|
|
432 * Interpolate colors
|
|
433 */
|
|
434 ex = (sdx & 0xffff);
|
|
435 ey = (sdy & 0xffff);
|
|
436 t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff;
|
|
437 t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff;
|
|
438 pc->r = (((t2 - t1) * ey) >> 16) + t1;
|
|
439 t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff;
|
|
440 t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff;
|
|
441 pc->g = (((t2 - t1) * ey) >> 16) + t1;
|
|
442 t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff;
|
|
443 t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff;
|
|
444 pc->b = (((t2 - t1) * ey) >> 16) + t1;
|
|
445 t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff;
|
|
446 t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff;
|
|
447 pc->a = (((t2 - t1) * ey) >> 16) + t1;
|
|
448 }
|
|
449 sdx += icos;
|
|
450 sdy += isin;
|
|
451 pc++;
|
|
452 }
|
|
453 pc = (tColorRGBA *) ((Uint8 *) pc + gap);
|
|
454 }
|
|
455 } else {
|
|
456 for (y = 0; y < dst->h; y++) {
|
|
457 dy = cy - y;
|
|
458 sdx = (ax + (isin * dy)) + xd;
|
|
459 sdy = (ay - (icos * dy)) + yd;
|
|
460 for (x = 0; x < dst->w; x++) {
|
|
461 dx = (short) (sdx >> 16);
|
|
462 dy = (short) (sdy >> 16);
|
|
463 if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
|
|
464 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
|
|
465 sp += dx;
|
|
466 *pc = *sp;
|
|
467 }
|
|
468 sdx += icos;
|
|
469 sdy += isin;
|
|
470 pc++;
|
|
471 }
|
|
472 pc = (tColorRGBA *) ((Uint8 *) pc + gap);
|
|
473 }
|
|
474 }
|
|
475 }
|
|
476
|
|
477 /*
|
|
478
|
|
479 8bit Rotozoomer without smoothing
|
|
480
|
|
481 Rotates and zoomes 8bit palette/Y 'src' surface to 'dst' surface.
|
|
482
|
|
483 */
|
|
484
|
|
485 void transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos)
|
|
486 {
|
|
487 int x, y, dx, dy, xd, yd, sdx, sdy, ax, ay, sw, sh;
|
|
488 tColorY *pc, *sp;
|
|
489 int gap;
|
|
490
|
|
491 /*
|
|
492 * Variable setup
|
|
493 */
|
|
494 xd = ((src->w - dst->w) << 15);
|
|
495 yd = ((src->h - dst->h) << 15);
|
|
496 ax = (cx << 16) - (icos * cx);
|
|
497 ay = (cy << 16) - (isin * cx);
|
|
498 sw = src->w - 1;
|
|
499 sh = src->h - 1;
|
|
500 pc = (tColorY*)(dst->pixels);
|
|
501 gap = dst->pitch - dst->w;
|
|
502 /*
|
|
503 * Clear surface to colorkey
|
|
504 */
|
|
505 memset(pc, (unsigned char) (src->format->colorkey & 0xff), dst->pitch * dst->h);
|
|
506 /*
|
|
507 * Iterate through destination surface
|
|
508 */
|
|
509 for (y = 0; y < dst->h; y++) {
|
|
510 dy = cy - y;
|
|
511 sdx = (ax + (isin * dy)) + xd;
|
|
512 sdy = (ay - (icos * dy)) + yd;
|
|
513 for (x = 0; x < dst->w; x++) {
|
|
514 dx = (short) (sdx >> 16);
|
|
515 dy = (short) (sdy >> 16);
|
|
516 if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
|
|
517 sp = (tColorY *) (src->pixels);
|
|
518 sp += (src->pitch * dy + dx);
|
|
519 *pc = *sp;
|
|
520 }
|
|
521 sdx += icos;
|
|
522 sdy += isin;
|
|
523 pc++;
|
|
524 }
|
|
525 pc += gap;
|
|
526 }
|
|
527 }
|
|
528
|
|
529 /*
|
|
530
|
|
531 rotozoomSurface()
|
|
532
|
|
533 Rotates and zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
|
|
534 'angle' is the rotation in degrees. 'zoom' a scaling factor. If 'smooth' is 1
|
|
535 then the destination 32bit surface is anti-aliased. If the surface is not 8bit
|
|
536 or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
|
|
537
|
|
538 */
|
|
539
|
|
540 #define VALUE_LIMIT 0.001
|
|
541
|
|
542
|
|
543 /* Local rotozoom-size function with trig result return */
|
|
544
|
|
545 void rotozoomSurfaceSizeTrig(int width, int height, double angle, double zoom, int *dstwidth, int *dstheight,
|
|
546 double *canglezoom, double *sanglezoom)
|
|
547 {
|
|
548 double x, y, cx, cy, sx, sy;
|
|
549 double radangle;
|
|
550 int dstwidthhalf, dstheighthalf;
|
|
551
|
|
552 /*
|
|
553 * Determine destination width and height by rotating a centered source box
|
|
554 */
|
|
555 radangle = angle * (M_PI / 180.0);
|
|
556 *sanglezoom = sin(radangle);
|
|
557 *canglezoom = cos(radangle);
|
|
558 *sanglezoom *= zoom;
|
|
559 *canglezoom *= zoom;
|
|
560 x = width / 2;
|
|
561 y = height / 2;
|
|
562 cx = *canglezoom * x;
|
|
563 cy = *canglezoom * y;
|
|
564 sx = *sanglezoom * x;
|
|
565 sy = *sanglezoom * y;
|
|
566 dstwidthhalf = MAX((int)
|
|
567 ceil(MAX(MAX(MAX(fabs(cx + sy), fabs(cx - sy)), fabs(-cx + sy)), fabs(-cx - sy))), 1);
|
|
568 dstheighthalf = MAX((int)
|
|
569 ceil(MAX(MAX(MAX(fabs(sx + cy), fabs(sx - cy)), fabs(-sx + cy)), fabs(-sx - cy))), 1);
|
|
570 *dstwidth = 2 * dstwidthhalf;
|
|
571 *dstheight = 2 * dstheighthalf;
|
|
572 }
|
|
573
|
|
574
|
|
575 /* Publically available rotozoom-size function */
|
|
576
|
|
577 void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth, int *dstheight)
|
|
578 {
|
|
579 double dummy_sanglezoom, dummy_canglezoom;
|
|
580
|
|
581 rotozoomSurfaceSizeTrig(width, height, angle, zoom, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
|
|
582 }
|
|
583
|
|
584
|
|
585 /* Publically available rotozoom function */
|
|
586
|
|
587 SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth)
|
|
588 {
|
|
589 SDL_Surface *rz_src;
|
|
590 SDL_Surface *rz_dst;
|
|
591 double zoominv;
|
|
592 double sanglezoom, canglezoom, sanglezoominv, canglezoominv;
|
|
593 int dstwidthhalf, dstwidth, dstheighthalf, dstheight;
|
|
594 double x, y, cx, cy, sx, sy;
|
|
595 int is32bit;
|
|
596 int i, src_converted;
|
|
597
|
|
598 /*
|
|
599 * Sanity check
|
|
600 */
|
|
601 if (src == NULL)
|
|
602 return (NULL);
|
|
603
|
|
604 /*
|
|
605 * Determine if source surface is 32bit or 8bit
|
|
606 */
|
|
607 is32bit = (src->format->BitsPerPixel == 32);
|
|
608 if ((is32bit) || (src->format->BitsPerPixel == 8)) {
|
|
609 /*
|
|
610 * Use source surface 'as is'
|
|
611 */
|
|
612 rz_src = src;
|
|
613 src_converted = 0;
|
|
614 } else {
|
|
615 /*
|
|
616 * New source surface is 32bit with a defined RGBA ordering
|
|
617 */
|
|
618 rz_src =
|
|
619 SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
|
|
620 SDL_BlitSurface(src, NULL, rz_src, NULL);
|
|
621 src_converted = 1;
|
|
622 is32bit = 1;
|
|
623 }
|
|
624
|
|
625 /*
|
|
626 * Sanity check zoom factor
|
|
627 */
|
|
628 if (zoom < VALUE_LIMIT) {
|
|
629 zoom = VALUE_LIMIT;
|
|
630 }
|
|
631 zoominv = 65536.0 / (zoom * zoom);
|
|
632
|
|
633 /*
|
|
634 * Check if we have a rotozoom or just a zoom
|
|
635 */
|
|
636 if (fabs(angle) > VALUE_LIMIT) {
|
|
637
|
|
638 /*
|
|
639 * Angle!=0: full rotozoom
|
|
640 */
|
|
641 /*
|
|
642 * -----------------------
|
|
643 */
|
|
644
|
|
645 /* Determine target size */
|
|
646 rotozoomSurfaceSizeTrig(rz_src->w, rz_src->h, angle, zoom, &dstwidth, &dstheight, &canglezoom, &sanglezoom);
|
|
647
|
|
648 /*
|
|
649 * Calculate target factors from sin/cos and zoom
|
|
650 */
|
|
651 sanglezoominv = sanglezoom;
|
|
652 canglezoominv = canglezoom;
|
|
653 sanglezoominv *= zoominv;
|
|
654 canglezoominv *= zoominv;
|
|
655
|
|
656 /* Calculate half size */
|
|
657 dstwidthhalf = dstwidth / 2;
|
|
658 dstheighthalf = dstheight / 2;
|
|
659
|
|
660 /*
|
|
661 * Alloc space to completely contain the rotated surface
|
|
662 */
|
|
663 rz_dst = NULL;
|
|
664 if (is32bit) {
|
|
665 /*
|
|
666 * Target surface is 32bit with source RGBA/ABGR ordering
|
|
667 */
|
|
668 rz_dst =
|
|
669 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
|
|
670 rz_src->format->Rmask, rz_src->format->Gmask,
|
|
671 rz_src->format->Bmask, rz_src->format->Amask);
|
|
672 } else {
|
|
673 /*
|
|
674 * Target surface is 8bit
|
|
675 */
|
|
676 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
|
|
677 }
|
|
678
|
|
679 /*
|
|
680 * Lock source surface
|
|
681 */
|
|
682 SDL_LockSurface(rz_src);
|
|
683 /*
|
|
684 * Check which kind of surface we have
|
|
685 */
|
|
686 if (is32bit) {
|
|
687 /*
|
|
688 * Call the 32bit transformation routine to do the rotation (using alpha)
|
|
689 */
|
|
690 transformSurfaceRGBA(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
|
|
691 (int) (sanglezoominv), (int) (canglezoominv), smooth);
|
|
692 /*
|
|
693 * Turn on source-alpha support
|
|
694 */
|
|
695 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
|
|
696 } else {
|
|
697 /*
|
|
698 * Copy palette and colorkey info
|
|
699 */
|
|
700 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
|
|
701 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
|
|
702 }
|
|
703 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
|
|
704 /*
|
|
705 * Call the 8bit transformation routine to do the rotation
|
|
706 */
|
|
707 transformSurfaceY(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
|
|
708 (int) (sanglezoominv), (int) (canglezoominv));
|
|
709 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
|
|
710 }
|
|
711 /*
|
|
712 * Unlock source surface
|
|
713 */
|
|
714 SDL_UnlockSurface(rz_src);
|
|
715
|
|
716 } else {
|
|
717
|
|
718 /*
|
|
719 * Angle=0: Just a zoom
|
|
720 */
|
|
721 /*
|
|
722 * --------------------
|
|
723 */
|
|
724
|
|
725 /*
|
|
726 * Calculate target size
|
|
727 */
|
|
728 zoomSurfaceSize(rz_src->w, rz_src->h, zoom, zoom, &dstwidth, &dstheight);
|
|
729
|
|
730 /*
|
|
731 * Alloc space to completely contain the zoomed surface
|
|
732 */
|
|
733 rz_dst = NULL;
|
|
734 if (is32bit) {
|
|
735 /*
|
|
736 * Target surface is 32bit with source RGBA/ABGR ordering
|
|
737 */
|
|
738 rz_dst =
|
|
739 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
|
|
740 rz_src->format->Rmask, rz_src->format->Gmask,
|
|
741 rz_src->format->Bmask, rz_src->format->Amask);
|
|
742 } else {
|
|
743 /*
|
|
744 * Target surface is 8bit
|
|
745 */
|
|
746 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
|
|
747 }
|
|
748
|
|
749 /*
|
|
750 * Lock source surface
|
|
751 */
|
|
752 SDL_LockSurface(rz_src);
|
|
753 /*
|
|
754 * Check which kind of surface we have
|
|
755 */
|
|
756 if (is32bit) {
|
|
757 /*
|
|
758 * Call the 32bit transformation routine to do the zooming (using alpha)
|
|
759 */
|
|
760 zoomSurfaceRGBA(rz_src, rz_dst, smooth);
|
|
761 /*
|
|
762 * Turn on source-alpha support
|
|
763 */
|
|
764 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
|
|
765 } else {
|
|
766 /*
|
|
767 * Copy palette and colorkey info
|
|
768 */
|
|
769 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
|
|
770 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
|
|
771 }
|
|
772 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
|
|
773 /*
|
|
774 * Call the 8bit transformation routine to do the zooming
|
|
775 */
|
|
776 zoomSurfaceY(rz_src, rz_dst);
|
|
777 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
|
|
778 }
|
|
779 /*
|
|
780 * Unlock source surface
|
|
781 */
|
|
782 SDL_UnlockSurface(rz_src);
|
|
783 }
|
|
784
|
|
785 /*
|
|
786 * Cleanup temp surface
|
|
787 */
|
|
788 if (src_converted) {
|
|
789 SDL_FreeSurface(rz_src);
|
|
790 }
|
|
791
|
|
792 /*
|
|
793 * Return destination surface
|
|
794 */
|
|
795 return (rz_dst);
|
|
796 }
|
|
797
|
|
798 /*
|
|
799
|
|
800 zoomSurface()
|
|
801
|
|
802 Zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
|
|
803 'zoomx' and 'zoomy' are scaling factors for width and height. If 'smooth' is 1
|
|
804 then the destination 32bit surface is anti-aliased. If the surface is not 8bit
|
|
805 or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
|
|
806
|
|
807 */
|
|
808
|
|
809 #define VALUE_LIMIT 0.001
|
|
810
|
|
811 void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight)
|
|
812 {
|
|
813 /*
|
|
814 * Sanity check zoom factors
|
|
815 */
|
|
816 if (zoomx < VALUE_LIMIT) {
|
|
817 zoomx = VALUE_LIMIT;
|
|
818 }
|
|
819 if (zoomy < VALUE_LIMIT) {
|
|
820 zoomy = VALUE_LIMIT;
|
|
821 }
|
|
822
|
|
823 /*
|
|
824 * Calculate target size
|
|
825 */
|
|
826 *dstwidth = (int) ((double) width * zoomx);
|
|
827 *dstheight = (int) ((double) height * zoomy);
|
|
828 if (*dstwidth < 1) {
|
|
829 *dstwidth = 1;
|
|
830 }
|
|
831 if (*dstheight < 1) {
|
|
832 *dstheight = 1;
|
|
833 }
|
|
834 }
|
|
835
|
|
836 SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth)
|
|
837 {
|
|
838 SDL_Surface *rz_src;
|
|
839 SDL_Surface *rz_dst;
|
|
840 int dstwidth, dstheight;
|
|
841 int is32bit;
|
|
842 int i, src_converted;
|
|
843
|
|
844 /*
|
|
845 * Sanity check
|
|
846 */
|
|
847 if (src == NULL)
|
|
848 return (NULL);
|
|
849
|
|
850 /*
|
|
851 * Determine if source surface is 32bit or 8bit
|
|
852 */
|
|
853 is32bit = (src->format->BitsPerPixel == 32);
|
|
854 if ((is32bit) || (src->format->BitsPerPixel == 8)) {
|
|
855 /*
|
|
856 * Use source surface 'as is'
|
|
857 */
|
|
858 rz_src = src;
|
|
859 src_converted = 0;
|
|
860 } else {
|
|
861 /*
|
|
862 * New source surface is 32bit with a defined RGBA ordering
|
|
863 */
|
|
864 rz_src =
|
|
865 SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
|
|
866 SDL_BlitSurface(src, NULL, rz_src, NULL);
|
|
867 src_converted = 1;
|
|
868 is32bit = 1;
|
|
869 }
|
|
870
|
|
871 /* Get size if target */
|
|
872 zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
|
|
873
|
|
874 /*
|
|
875 * Alloc space to completely contain the zoomed surface
|
|
876 */
|
|
877 rz_dst = NULL;
|
|
878 if (is32bit) {
|
|
879 /*
|
|
880 * Target surface is 32bit with source RGBA/ABGR ordering
|
|
881 */
|
|
882 rz_dst =
|
|
883 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
|
|
884 rz_src->format->Rmask, rz_src->format->Gmask,
|
|
885 rz_src->format->Bmask, rz_src->format->Amask);
|
|
886 } else {
|
|
887 /*
|
|
888 * Target surface is 8bit
|
|
889 */
|
|
890 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
|
|
891 }
|
|
892
|
|
893 /*
|
|
894 * Lock source surface
|
|
895 */
|
|
896 SDL_LockSurface(rz_src);
|
|
897 /*
|
|
898 * Check which kind of surface we have
|
|
899 */
|
|
900 if (is32bit) {
|
|
901 /*
|
|
902 * Call the 32bit transformation routine to do the zooming (using alpha)
|
|
903 */
|
|
904 zoomSurfaceRGBA(rz_src, rz_dst, smooth);
|
|
905 /*
|
|
906 * Turn on source-alpha support
|
|
907 */
|
|
908 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
|
|
909 } else {
|
|
910 /*
|
|
911 * Copy palette and colorkey info
|
|
912 */
|
|
913 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
|
|
914 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
|
|
915 }
|
|
916 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
|
|
917 /*
|
|
918 * Call the 8bit transformation routine to do the zooming
|
|
919 */
|
|
920 zoomSurfaceY(rz_src, rz_dst);
|
|
921 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
|
|
922 }
|
|
923 /*
|
|
924 * Unlock source surface
|
|
925 */
|
|
926 SDL_UnlockSurface(rz_src);
|
|
927
|
|
928 /*
|
|
929 * Cleanup temp surface
|
|
930 */
|
|
931 if (src_converted) {
|
|
932 SDL_FreeSurface(rz_src);
|
|
933 }
|
|
934
|
|
935 /*
|
|
936 * Return destination surface
|
|
937 */
|
|
938 return (rz_dst);
|
|
939 }
|