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