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