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
23 32bit integer-factor averaging Shrinker
24
25 Shrinks 32bit RGBA/ABGR 'src' surface to 'dst' surface.
26
27 */
28
shrinkSurfaceRGBA(SDL_Surface * src,SDL_Surface * dst,int factorx,int factory)29 int shrinkSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
30 {
31 int x, y, dx, dy, sgap, dgap, ra, ga, ba, aa;
32 int n_average;
33 tColorRGBA *sp, *osp, *oosp;
34 tColorRGBA *dp;
35
36 /*
37 * Averaging integer shrink
38 */
39
40 /* Precalculate division factor */
41 n_average = factorx*factory;
42
43 /*
44 * Scan destination
45 */
46 sp = (tColorRGBA *) src->pixels;
47 sgap = src->pitch - src->w * 4;
48
49 dp = (tColorRGBA *) dst->pixels;
50 dgap = dst->pitch - dst->w * 4;
51
52 for (y = 0; y < dst->h; y++) {
53
54 osp=sp;
55 for (x = 0; x < dst->w; x++) {
56
57 /* Trace out source box and accumulate */
58 oosp=sp;
59 ra=ga=ba=aa=0;
60 for (dy=0; dy < factory; dy++) {
61 for (dx=0; dx < factorx; dx++) {
62 ra += sp->r;
63 ga += sp->g;
64 ba += sp->b;
65 aa += sp->a;
66
67 sp++;
68 } // src dx loop
69 sp = (tColorRGBA *)((Uint8*)sp + (src->pitch - 4*factorx)); // next y
70 } // src dy loop
71
72 // next box-x
73 sp = (tColorRGBA *)((Uint8*)oosp + 4*factorx);
74
75 /* Store result in destination */
76 dp->r = ra/n_average;
77 dp->g = ga/n_average;
78 dp->b = ba/n_average;
79 dp->a = aa/n_average;
80
81 /*
82 * Advance destination pointer
83 */
84 dp++;
85 } // dst x loop
86
87 // next box-y
88 sp = (tColorRGBA *)((Uint8*)osp + src->pitch*factory);
89
90 /*
91 * Advance destination pointers
92 */
93 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
94 } // dst y loop
95
96 return (0);
97 }
98
99 /*
100
101 8bit integer-factor averaging Shrinker
102
103 Shrinks 8bit Y 'src' surface to 'dst' surface.
104
105 */
106
shrinkSurfaceY(SDL_Surface * src,SDL_Surface * dst,int factorx,int factory)107 int shrinkSurfaceY(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
108 {
109 int x, y, dx, dy, sgap, dgap, a;
110 int n_average;
111 Uint8 *sp, *osp, *oosp;
112 Uint8 *dp;
113
114 /*
115 * Averaging integer shrink
116 */
117
118 /* Precalculate division factor */
119 n_average = factorx*factory;
120
121 /*
122 * Scan destination
123 */
124 sp = (Uint8 *) src->pixels;
125 sgap = src->pitch - src->w;
126
127 dp = (Uint8 *) dst->pixels;
128 dgap = dst->pitch - dst->w;
129
130 for (y = 0; y < dst->h; y++) {
131
132 osp=sp;
133 for (x = 0; x < dst->w; x++) {
134
135 /* Trace out source box and accumulate */
136 oosp=sp;
137 a=0;
138 for (dy=0; dy < factory; dy++) {
139 for (dx=0; dx < factorx; dx++) {
140 a += (*sp);
141 sp++; // next x
142 } // src dx loop
143 sp = (Uint8 *)((Uint8*)sp + (src->pitch - factorx)); // next y
144 } // src dy loop
145
146 // next box-x
147 sp = (Uint8 *)((Uint8*)oosp + factorx);
148
149 /* Store result in destination */
150 *dp = a/n_average;
151
152 /*
153 * Advance destination pointer
154 */
155 dp++;
156 } // dst x loop
157
158 // next box-y
159 sp = (Uint8 *)((Uint8*)osp + src->pitch*factory);
160
161 /*
162 * Advance destination pointers
163 */
164 dp = (Uint8 *)((Uint8 *)dp + dgap);
165 } // dst y loop
166
167 return (0);
168 }
169
170 /*
171
172 32bit Zoomer with optional anti-aliasing by bilinear interpolation.
173
174 Zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
175
176 */
177
zoomSurfaceRGBA(SDL_Surface * src,SDL_Surface * dst,int flipx,int flipy,int smooth)178 int zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy, int smooth)
179 {
180 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy, ex, ey, t1, t2, sstep;
181 tColorRGBA *c00, *c01, *c10, *c11;
182 tColorRGBA *sp, *csp, *dp;
183 int dgap;
184
185 /*
186 * Variable setup
187 */
188 if (smooth) {
189 /*
190 * For interpolation: assume source dimension is one pixel
191 */
192 /*
193 * smaller to avoid overflow on right and bottom edge.
194 */
195 sx = (int) (65536.0 * (float) (src->w - 1) / (float) dst->w);
196 sy = (int) (65536.0 * (float) (src->h - 1) / (float) dst->h);
197 } else {
198 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
199 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
200 }
201
202 /*
203 * Allocate memory for row increments
204 */
205 if ((sax = (int *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
206 return (-1);
207 }
208 if ((say = (int *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
209 free(sax);
210 return (-1);
211 }
212
213 /*
214 * Precalculate row increments
215 */
216 sp = csp = (tColorRGBA *) src->pixels;
217 dp = (tColorRGBA *) dst->pixels;
218
219 if (flipx) csp += (src->w-1);
220 if (flipy) csp = (tColorRGBA*)( (Uint8*)csp + src->pitch*(src->h-1) );
221
222 csx = 0;
223 csax = sax;
224 for (x = 0; x <= dst->w; x++) {
225 *csax = csx;
226 csax++;
227 csx &= 0xffff;
228 csx += sx;
229 }
230 csy = 0;
231 csay = say;
232 for (y = 0; y <= dst->h; y++) {
233 *csay = csy;
234 csay++;
235 csy &= 0xffff;
236 csy += sy;
237 }
238
239 dgap = dst->pitch - dst->w * 4;
240
241 /*
242 * Switch between interpolating and non-interpolating code
243 */
244 if (smooth) {
245
246 /*
247 * Interpolating Zoom
248 */
249
250 /*
251 * Scan destination
252 */
253 csay = say;
254 for (y = 0; y < dst->h; y++) {
255 /*
256 * Setup color source pointers
257 */
258 c00 = csp;
259 c01 = csp;
260 c01++;
261 c10 = (tColorRGBA *) ((Uint8 *) csp + src->pitch);
262 c11 = c10;
263 c11++;
264 csax = sax;
265 for (x = 0; x < dst->w; x++) {
266
267 /*
268 * Interpolate colors
269 */
270 ex = (*csax & 0xffff);
271 ey = (*csay & 0xffff);
272 t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
273 t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
274 dp->r = (((t2 - t1) * ey) >> 16) + t1;
275 t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff;
276 t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff;
277 dp->g = (((t2 - t1) * ey) >> 16) + t1;
278 t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff;
279 t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff;
280 dp->b = (((t2 - t1) * ey) >> 16) + t1;
281 t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff;
282 t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff;
283 dp->a = (((t2 - t1) * ey) >> 16) + t1;
284
285 /*
286 * Advance source pointers
287 */
288 csax++;
289 sstep = (*csax >> 16);
290 c00 += sstep;
291 c01 += sstep;
292 c10 += sstep;
293 c11 += sstep;
294 /*
295 * Advance destination pointer
296 */
297 dp++;
298 }
299 /*
300 * Advance source pointer
301 */
302 csay++;
303 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
304 /*
305 * Advance destination pointers
306 */
307 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
308 }
309
310 } else {
311
312 /*
313 * Non-Interpolating Zoom
314 */
315
316 csay = say;
317 for (y = 0; y < dst->h; y++) {
318 sp = csp;
319 csax = sax;
320 for (x = 0; x < dst->w; x++) {
321 /*
322 * Draw
323 */
324 *dp = *sp;
325 /*
326 * Advance source pointers
327 */
328 csax++;
329 sstep = (*csax >> 16);
330 if (flipx) sstep = -sstep;
331 sp += sstep;
332 /*
333 * Advance destination pointer
334 */
335 dp++;
336 }
337 /*
338 * Advance source pointer
339 */
340 csay++;
341 sstep = (*csay >> 16) * src->pitch;
342 if (flipy) sstep = -sstep;
343 csp = (tColorRGBA *) ((Uint8 *) csp + sstep);
344
345 /*
346 * Advance destination pointers
347 */
348 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
349 }
350
351 }
352
353 /*
354 * Remove temp arrays
355 */
356 free(sax);
357 free(say);
358
359 return (0);
360 }
361
362 /*
363
364 8bit Zoomer without smoothing.
365
366 Zoomes 8bit palette/Y 'src' surface to 'dst' surface.
367
368 */
369
zoomSurfaceY(SDL_Surface * src,SDL_Surface * dst,int flipx,int flipy)370 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy)
371 {
372 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
373 Uint8 *sp, *dp, *csp;
374 int dgap;
375
376 /*
377 * Variable setup
378 */
379 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
380 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
381
382 /*
383 * Allocate memory for row increments
384 */
385 if ((sax = (Uint32 *) malloc(dst->w * sizeof(Uint32))) == NULL) {
386 return (-1);
387 }
388 if ((say = (Uint32 *) malloc(dst->h * sizeof(Uint32))) == NULL) {
389 if (sax != NULL) {
390 free(sax);
391 }
392 return (-1);
393 }
394
395 /*
396 * Precalculate row increments
397 */
398 csx = 0;
399 csax = sax;
400 for (x = 0; x < dst->w; x++) {
401 csx += sx;
402 *csax = (csx >> 16);
403 csx &= 0xffff;
404 csax++;
405 }
406 csy = 0;
407 csay = say;
408 for (y = 0; y < dst->h; y++) {
409 csy += sy;
410 *csay = (csy >> 16);
411 csy &= 0xffff;
412 csay++;
413 }
414
415 csx = 0;
416 csax = sax;
417 for (x = 0; x < dst->w; x++) {
418 csx += (*csax);
419 csax++;
420 }
421 csy = 0;
422 csay = say;
423 for (y = 0; y < dst->h; y++) {
424 csy += (*csay);
425 csay++;
426 }
427
428 /*
429 * Pointer setup
430 */
431 sp = csp = (Uint8 *) src->pixels;
432 dp = (Uint8 *) dst->pixels;
433 dgap = dst->pitch - dst->w;
434
435 /*
436 * Draw
437 */
438 csay = say;
439 for (y = 0; y < dst->h; y++) {
440 csax = sax;
441 sp = csp;
442 for (x = 0; x < dst->w; x++) {
443 /*
444 * Draw
445 */
446 *dp = *sp;
447 /*
448 * Advance source pointers
449 */
450 sp += (*csax);
451 csax++;
452 /*
453 * Advance destination pointer
454 */
455 dp++;
456 }
457 /*
458 * Advance source pointer (for row)
459 */
460 csp += ((*csay) * src->pitch);
461 csay++;
462 /*
463 * Advance destination pointers
464 */
465 dp += dgap;
466 }
467
468 /*
469 * Remove temp arrays
470 */
471 free(sax);
472 free(say);
473
474 return (0);
475 }
476
477 /*
478
479 32bit Rotozoomer with optional anti-aliasing by bilinear interpolation.
480
481 Rotates and zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
482
483 */
484
transformSurfaceRGBA(SDL_Surface * src,SDL_Surface * dst,int cx,int cy,int isin,int icos,int flipx,int flipy,int smooth)485 void transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy, int smooth)
486 {
487 int x, y, t1, t2, dx, dy, xd, yd, sdx, sdy, ax, ay, ex, ey, sw, sh;
488 tColorRGBA c00, c01, c10, c11;
489 tColorRGBA *pc, *sp;
490 int gap;
491
492 /*
493 * Variable setup
494 */
495 xd = ((src->w - dst->w) << 15);
496 yd = ((src->h - dst->h) << 15);
497 ax = (cx << 16) - (icos * cx);
498 ay = (cy << 16) - (isin * cx);
499 sw = src->w - 1;
500 sh = src->h - 1;
501 pc = dst->pixels;
502 gap = dst->pitch - dst->w * 4;
503
504 /*
505 * Switch between interpolating and non-interpolating code
506 */
507 if (smooth) {
508 for (y = 0; y < dst->h; y++) {
509 dy = cy - y;
510 sdx = (ax + (isin * dy)) + xd;
511 sdy = (ay - (icos * dy)) + yd;
512 for (x = 0; x < dst->w; x++) {
513 dx = (sdx >> 16);
514 dy = (sdy >> 16);
515 if ((dx >= -1) && (dy >= -1) && (dx < src->w) && (dy < src->h)) {
516 if ((dx >= 0) && (dy >= 0) && (dx < sw) && (dy < sh)) {
517 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
518 sp += dx;
519 c00 = *sp;
520 sp += 1;
521 c01 = *sp;
522 sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
523 sp -= 1;
524 c10 = *sp;
525 sp += 1;
526 c11 = *sp;
527 } else if ((dx == sw) && (dy == sh)) {
528 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
529 sp += dx;
530 c00 = *sp;
531 c01 = *sp;
532 c10 = *sp;
533 c11 = *sp;
534 } else if ((dx == -1) && (dy == -1)) {
535 sp = (tColorRGBA *) (src->pixels);
536 c00 = *sp;
537 c01 = *sp;
538 c10 = *sp;
539 c11 = *sp;
540 } else if ((dx == -1) && (dy == sh)) {
541 sp = (tColorRGBA *) (src->pixels);
542 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
543 c00 = *sp;
544 c01 = *sp;
545 c10 = *sp;
546 c11 = *sp;
547 } else if ((dx == sw) && (dy == -1)) {
548 sp = (tColorRGBA *) (src->pixels);
549 sp += dx;
550 c00 = *sp;
551 c01 = *sp;
552 c10 = *sp;
553 c11 = *sp;
554 } else if (dx == -1) {
555 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
556 c00 = *sp;
557 c01 = *sp;
558 c10 = *sp;
559 sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
560 c11 = *sp;
561 } else if (dy == -1) {
562 sp = (tColorRGBA *) (src->pixels);
563 sp += dx;
564 c00 = *sp;
565 c01 = *sp;
566 c10 = *sp;
567 sp += 1;
568 c11 = *sp;
569 } else if (dx == sw) {
570 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
571 sp += dx;
572 c00 = *sp;
573 c01 = *sp;
574 sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
575 c10 = *sp;
576 c11 = *sp;
577 } else if (dy == sh) {
578 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
579 sp += dx;
580 c00 = *sp;
581 sp += 1;
582 c01 = *sp;
583 c10 = *sp;
584 c11 = *sp;
585 }
586 /*
587 * Interpolate colors
588 */
589 ex = (sdx & 0xffff);
590 ey = (sdy & 0xffff);
591 t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff;
592 t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff;
593 pc->r = (((t2 - t1) * ey) >> 16) + t1;
594 t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff;
595 t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff;
596 pc->g = (((t2 - t1) * ey) >> 16) + t1;
597 t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff;
598 t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff;
599 pc->b = (((t2 - t1) * ey) >> 16) + t1;
600 t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff;
601 t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff;
602 pc->a = (((t2 - t1) * ey) >> 16) + t1;
603 }
604 sdx += icos;
605 sdy += isin;
606 pc++;
607 }
608 pc = (tColorRGBA *) ((Uint8 *) pc + gap);
609 }
610 } else {
611 for (y = 0; y < dst->h; y++) {
612 dy = cy - y;
613 sdx = (ax + (isin * dy)) + xd;
614 sdy = (ay - (icos * dy)) + yd;
615 for (x = 0; x < dst->w; x++) {
616 dx = (short) (sdx >> 16);
617 dy = (short) (sdy >> 16);
618 if (flipx) dx = (src->w-1)-dx;
619 if (flipy) dy = (src->h-1)-dy;
620 if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
621 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
622 sp += dx;
623 *pc = *sp;
624 }
625 sdx += icos;
626 sdy += isin;
627 pc++;
628 }
629 pc = (tColorRGBA *) ((Uint8 *) pc + gap);
630 }
631 }
632 }
633
634 /*
635
636 8bit Rotozoomer without smoothing
637
638 Rotates and zoomes 8bit palette/Y 'src' surface to 'dst' surface.
639
640 */
641
transformSurfaceY(SDL_Surface * src,SDL_Surface * dst,int cx,int cy,int isin,int icos)642 void transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos)
643 {
644 int x, y, dx, dy, xd, yd, sdx, sdy, ax, ay, sw, sh;
645 tColorY *pc, *sp;
646 int gap;
647
648 /*
649 * Variable setup
650 */
651 xd = ((src->w - dst->w) << 15);
652 yd = ((src->h - dst->h) << 15);
653 ax = (cx << 16) - (icos * cx);
654 ay = (cy << 16) - (isin * cx);
655 sw = src->w - 1;
656 sh = src->h - 1;
657 pc = dst->pixels;
658 gap = dst->pitch - dst->w;
659 /*
660 * Clear surface to colorkey
661 */
662 memset(pc, (unsigned char) (src->format->colorkey & 0xff), dst->pitch * dst->h);
663 /*
664 * Iterate through destination surface
665 */
666 for (y = 0; y < dst->h; y++) {
667 dy = cy - y;
668 sdx = (ax + (isin * dy)) + xd;
669 sdy = (ay - (icos * dy)) + yd;
670 for (x = 0; x < dst->w; x++) {
671 dx = (short) (sdx >> 16);
672 dy = (short) (sdy >> 16);
673 if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
674 sp = (tColorY *) (src->pixels);
675 sp += (src->pitch * dy + dx);
676 *pc = *sp;
677 }
678 sdx += icos;
679 sdy += isin;
680 pc++;
681 }
682 pc += gap;
683 }
684 }
685
686
687 /*
688
689 32bit specialized 90degree rotator
690
691 Rotates and zooms 'src' surface to 'dst' surface in 90degree increments.
692
693 (contributed by Jeff Schiller)
694
695 */
rotateSurface90Degrees(SDL_Surface * pSurf,int numClockwiseTurns)696 SDL_Surface* rotateSurface90Degrees(SDL_Surface* pSurf, int numClockwiseTurns)
697 {
698 int row, col;
699
700 // Has to be a valid surface pointer and only 32-bit surfaces (for now)
701 if (!pSurf || pSurf->format->BitsPerPixel != 32) { return NULL; }
702
703 // normalize numClockwiseTurns
704 while(numClockwiseTurns < 0) { numClockwiseTurns += 4; }
705 numClockwiseTurns = (numClockwiseTurns % 4);
706
707 // if it's even, our new width will be the same as the source surface
708 int newWidth = (numClockwiseTurns % 2) ? (pSurf->h) : (pSurf->w);
709 int newHeight = (numClockwiseTurns % 2) ? (pSurf->w) : (pSurf->h);
710 SDL_Surface* pSurfOut = SDL_CreateRGBSurface( pSurf->flags, newWidth, newHeight, pSurf->format->BitsPerPixel,
711 pSurf->format->Rmask,
712 pSurf->format->Gmask,
713 pSurf->format->Bmask,
714 pSurf->format->Amask);
715 if(!pSurfOut) {
716 return NULL;
717 }
718
719 if(numClockwiseTurns != 0) {
720 SDL_LockSurface(pSurf);
721 SDL_LockSurface(pSurfOut);
722 switch(numClockwiseTurns) {
723 // rotate clockwise
724 case 1: // rotated 90 degrees clockwise
725 {
726 Uint32* srcBuf = NULL;
727 Uint32* dstBuf = NULL;
728
729 for (row = 0; row < pSurf->h; ++row) {
730 srcBuf = (Uint32*)(pSurf->pixels) + (row*pSurf->pitch/4);
731 dstBuf = (Uint32*)(pSurfOut->pixels) + (pSurfOut->w - row - 1);
732 for (col = 0; col < pSurf->w; ++col) {
733 *dstBuf = *srcBuf;
734 ++srcBuf;
735 dstBuf += pSurfOut->pitch/4;
736 } // for(col)
737 } // for(row)
738 }
739 break;
740
741 case 2: // rotated 180 degrees clockwise
742 {
743 Uint32* srcBuf = NULL;
744 Uint32* dstBuf = NULL;
745
746 for(row = 0; row < pSurf->h; ++row) {
747 srcBuf = (Uint32*)(pSurf->pixels) + (row*pSurf->pitch/4);
748 dstBuf = (Uint32*)(pSurfOut->pixels) + ((pSurfOut->h - row - 1)*pSurfOut->pitch/4) + (pSurfOut->w - 1);
749 for(col = 0; col < pSurf->w; ++col) {
750 *dstBuf = *srcBuf;
751 ++srcBuf;
752 --dstBuf;
753 } // for(col)
754 } // for(row)
755 }
756 break;
757
758 case 3:
759 {
760 Uint32* srcBuf = NULL;
761 Uint32* dstBuf = NULL;
762
763 for(row = 0; row < pSurf->h; ++row) {
764 srcBuf = (Uint32*)(pSurf->pixels) + (row*pSurf->pitch/4);
765 dstBuf = (Uint32*)(pSurfOut->pixels) + row + ((pSurfOut->h - 1)*pSurfOut->pitch/4);
766 for(col = 0; col < pSurf->w; ++col) {
767 *dstBuf = *srcBuf;
768 ++srcBuf;
769 dstBuf -= pSurfOut->pitch/4;
770 } // for(col)
771 } // for(row)
772 }
773 break;
774 } // switch
775
776 SDL_UnlockSurface(pSurf);
777 SDL_UnlockSurface(pSurfOut);
778 } // if numClockwiseTurns > 0
779 else {
780 // simply copy surface to output
781 if(SDL_BlitSurface(pSurf, NULL, pSurfOut, NULL)) {
782 return NULL;
783 }
784 }
785 return pSurfOut;
786 }
787
788 /*
789
790 rotozoomSurface()
791
792 Rotates and zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
793 'angle' is the rotation in degrees. 'zoom' a scaling factor. If 'smooth' is 1
794 then the destination 32bit surface is anti-aliased. If the surface is not 8bit
795 or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
796
797 */
798
799 #define VALUE_LIMIT 0.001
800
801
802 /* Local rotozoom-size function with trig result return */
803
rotozoomSurfaceSizeTrig(int width,int height,double angle,double zoomx,double zoomy,int * dstwidth,int * dstheight,double * canglezoom,double * sanglezoom)804 void rotozoomSurfaceSizeTrig(int width, int height, double angle, double zoomx, double zoomy, int *dstwidth, int *dstheight,
805 double *canglezoom, double *sanglezoom)
806 {
807 double x, y, cx, cy, sx, sy;
808 double radangle;
809 int dstwidthhalf, dstheighthalf;
810
811 /*
812 * Determine destination width and height by rotating a centered source box
813 */
814 radangle = angle * (M_PI / 180.0);
815 *sanglezoom = sin(radangle);
816 *canglezoom = cos(radangle);
817 *sanglezoom *= zoomx;
818 *canglezoom *= zoomx;
819 x = width / 2;
820 y = height / 2;
821 cx = *canglezoom * x;
822 cy = *canglezoom * y;
823 sx = *sanglezoom * x;
824 sy = *sanglezoom * y;
825
826 dstwidthhalf = MAX((int)
827 ceil(MAX(MAX(MAX(fabs(cx + sy), fabs(cx - sy)), fabs(-cx + sy)), fabs(-cx - sy))), 1);
828 dstheighthalf = MAX((int)
829 ceil(MAX(MAX(MAX(fabs(sx + cy), fabs(sx - cy)), fabs(-sx + cy)), fabs(-sx - cy))), 1);
830 *dstwidth = 2 * dstwidthhalf;
831 *dstheight = 2 * dstheighthalf;
832 }
833
834
835 /* Publically available rotozoom-size function */
836
rotozoomSurfaceSizeXY(int width,int height,double angle,double zoomx,double zoomy,int * dstwidth,int * dstheight)837 void rotozoomSurfaceSizeXY(int width, int height, double angle, double zoomx, double zoomy, int *dstwidth, int *dstheight)
838 {
839 double dummy_sanglezoom, dummy_canglezoom;
840
841 rotozoomSurfaceSizeTrig(width, height, angle, zoomx, zoomy, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
842 }
843
844 /* Publically available rotozoom-size function */
845
rotozoomSurfaceSize(int width,int height,double angle,double zoom,int * dstwidth,int * dstheight)846 void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth, int *dstheight)
847 {
848 double dummy_sanglezoom, dummy_canglezoom;
849
850 rotozoomSurfaceSizeTrig(width, height, angle, zoom, zoom, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
851 }
852
853 /* Publically available rotozoom function */
854
rotozoomSurface(SDL_Surface * src,double angle,double zoom,int smooth)855 SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth)
856 {
857 return rotozoomSurfaceXY(src, angle, zoom, zoom, smooth);
858 }
859
860 /* Publically available rotozoom function */
861
rotozoomSurfaceXY(SDL_Surface * src,double angle,double zoomx,double zoomy,int smooth)862 SDL_Surface *rotozoomSurfaceXY(SDL_Surface * src, double angle, double zoomx, double zoomy, int smooth)
863 {
864 SDL_Surface *rz_src;
865 SDL_Surface *rz_dst;
866 double zoominv;
867 double sanglezoom, canglezoom, sanglezoominv, canglezoominv;
868 int dstwidthhalf, dstwidth, dstheighthalf, dstheight;
869 int is32bit;
870 int i, src_converted;
871 int flipx,flipy;
872
873 /*
874 * Sanity check
875 */
876 if (src == NULL)
877 return (NULL);
878
879 /*
880 * Determine if source surface is 32bit or 8bit
881 */
882 is32bit = (src->format->BitsPerPixel == 32);
883 if ((is32bit) || (src->format->BitsPerPixel == 8)) {
884 /*
885 * Use source surface 'as is'
886 */
887 rz_src = src;
888 src_converted = 0;
889 } else {
890 /*
891 * New source surface is 32bit with a defined RGBA ordering
892 */
893 rz_src =
894 SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
895 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
896 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
897 #else
898 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
899 #endif
900 );
901 SDL_BlitSurface(src, NULL, rz_src, NULL);
902 src_converted = 1;
903 is32bit = 1;
904 }
905
906 /*
907 * Sanity check zoom factor
908 */
909 flipx = (zoomx<0);
910 if (flipx) zoomx=-zoomx;
911 flipy = (zoomy<0);
912 if (flipy) zoomy=-zoomy;
913 if (zoomx < VALUE_LIMIT) zoomx = VALUE_LIMIT;
914 if (zoomy < VALUE_LIMIT) zoomy = VALUE_LIMIT;
915 zoominv = 65536.0 / (zoomx * zoomx);
916
917 /*
918 * Check if we have a rotozoom or just a zoom
919 */
920 if (fabs(angle) > VALUE_LIMIT) {
921
922 /*
923 * Angle!=0: full rotozoom
924 */
925 /*
926 * -----------------------
927 */
928
929 /* Determine target size */
930 rotozoomSurfaceSizeTrig(rz_src->w, rz_src->h, angle, zoomx, zoomy, &dstwidth, &dstheight, &canglezoom, &sanglezoom);
931
932 /*
933 * Calculate target factors from sin/cos and zoom
934 */
935 sanglezoominv = sanglezoom;
936 canglezoominv = canglezoom;
937 sanglezoominv *= zoominv;
938 canglezoominv *= zoominv;
939
940 /* Calculate half size */
941 dstwidthhalf = dstwidth / 2;
942 dstheighthalf = dstheight / 2;
943
944 /*
945 * Alloc space to completely contain the rotated surface
946 */
947 rz_dst = NULL;
948 if (is32bit) {
949 /*
950 * Target surface is 32bit with source RGBA/ABGR ordering
951 */
952 rz_dst =
953 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
954 rz_src->format->Rmask, rz_src->format->Gmask,
955 rz_src->format->Bmask, rz_src->format->Amask);
956 } else {
957 /*
958 * Target surface is 8bit
959 */
960 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
961 }
962
963 /*
964 * Lock source surface
965 */
966 SDL_LockSurface(rz_src);
967 /*
968 * Check which kind of surface we have
969 */
970 if (is32bit) {
971 /*
972 * Call the 32bit transformation routine to do the rotation (using alpha)
973 */
974 transformSurfaceRGBA(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
975 (int) (sanglezoominv), (int) (canglezoominv),
976 flipx, flipy,
977 smooth);
978 /*
979 * Turn on source-alpha support
980 */
981 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
982 } else {
983 /*
984 * Copy palette and colorkey info
985 */
986 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
987 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
988 }
989 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
990 /*
991 * Call the 8bit transformation routine to do the rotation
992 */
993 transformSurfaceY(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
994 (int) (sanglezoominv), (int) (canglezoominv));
995 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
996 }
997 /*
998 * Unlock source surface
999 */
1000 SDL_UnlockSurface(rz_src);
1001
1002 } else {
1003
1004 /*
1005 * Angle=0: Just a zoom
1006 */
1007 /*
1008 * --------------------
1009 */
1010
1011 /*
1012 * Calculate target size
1013 */
1014 zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
1015
1016 /*
1017 * Alloc space to completely contain the zoomed surface
1018 */
1019 rz_dst = NULL;
1020 if (is32bit) {
1021 /*
1022 * Target surface is 32bit with source RGBA/ABGR ordering
1023 */
1024 rz_dst =
1025 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
1026 rz_src->format->Rmask, rz_src->format->Gmask,
1027 rz_src->format->Bmask, rz_src->format->Amask);
1028 } else {
1029 /*
1030 * Target surface is 8bit
1031 */
1032 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
1033 }
1034
1035 /*
1036 * Lock source surface
1037 */
1038 SDL_LockSurface(rz_src);
1039 /*
1040 * Check which kind of surface we have
1041 */
1042 if (is32bit) {
1043 /*
1044 * Call the 32bit transformation routine to do the zooming (using alpha)
1045 */
1046 zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
1047 /*
1048 * Turn on source-alpha support
1049 */
1050 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1051 } else {
1052 /*
1053 * Copy palette and colorkey info
1054 */
1055 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1056 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1057 }
1058 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1059 /*
1060 * Call the 8bit transformation routine to do the zooming
1061 */
1062 zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
1063 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
1064 }
1065 /*
1066 * Unlock source surface
1067 */
1068 SDL_UnlockSurface(rz_src);
1069 }
1070
1071 /*
1072 * Cleanup temp surface
1073 */
1074 if (src_converted) {
1075 SDL_FreeSurface(rz_src);
1076 }
1077
1078 /*
1079 * Return destination surface
1080 */
1081 return (rz_dst);
1082 }
1083
1084 /*
1085
1086 zoomSurface()
1087
1088 Zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1089 'zoomx' and 'zoomy' are scaling factors for width and height. If 'smooth' is 1
1090 then the destination 32bit surface is anti-aliased. If the surface is not 8bit
1091 or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
1092
1093 */
1094
1095 #define VALUE_LIMIT 0.001
1096
zoomSurfaceSize(int width,int height,double zoomx,double zoomy,int * dstwidth,int * dstheight)1097 void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight)
1098 {
1099 /*
1100 * Sanity check zoom factors
1101 */
1102 if (zoomx < VALUE_LIMIT) {
1103 zoomx = VALUE_LIMIT;
1104 }
1105 if (zoomy < VALUE_LIMIT) {
1106 zoomy = VALUE_LIMIT;
1107 }
1108
1109 /*
1110 * Calculate target size
1111 */
1112 *dstwidth = (int) ((double) width * zoomx);
1113 *dstheight = (int) ((double) height * zoomy);
1114 if (*dstwidth < 1) {
1115 *dstwidth = 1;
1116 }
1117 if (*dstheight < 1) {
1118 *dstheight = 1;
1119 }
1120 }
1121
zoomSurface(SDL_Surface * src,double zoomx,double zoomy,int smooth)1122 SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth)
1123 {
1124 SDL_Surface *rz_src;
1125 SDL_Surface *rz_dst;
1126 int dstwidth, dstheight;
1127 int is32bit;
1128 int i, src_converted;
1129 int flipx, flipy;
1130
1131 /*
1132 * Sanity check
1133 */
1134 if (src == NULL)
1135 return (NULL);
1136
1137 /*
1138 * Determine if source surface is 32bit or 8bit
1139 */
1140 is32bit = (src->format->BitsPerPixel == 32);
1141 if ((is32bit) || (src->format->BitsPerPixel == 8)) {
1142 /*
1143 * Use source surface 'as is'
1144 */
1145 rz_src = src;
1146 src_converted = 0;
1147 } else {
1148 /*
1149 * New source surface is 32bit with a defined RGBA ordering
1150 */
1151 rz_src =
1152 SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1153 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
1154 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
1155 #else
1156 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
1157 #endif
1158 );
1159 SDL_BlitSurface(src, NULL, rz_src, NULL);
1160 src_converted = 1;
1161 is32bit = 1;
1162 }
1163
1164 flipx = (zoomx<0);
1165 if (flipx) zoomx = -zoomx;
1166 flipy = (zoomy<0);
1167 if (flipy) zoomy = -zoomy;
1168
1169 /* Get size if target */
1170 zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
1171
1172 /*
1173 * Alloc space to completely contain the zoomed surface
1174 */
1175 rz_dst = NULL;
1176 if (is32bit) {
1177 /*
1178 * Target surface is 32bit with source RGBA/ABGR ordering
1179 */
1180 rz_dst =
1181 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
1182 rz_src->format->Rmask, rz_src->format->Gmask,
1183 rz_src->format->Bmask, rz_src->format->Amask);
1184 } else {
1185 /*
1186 * Target surface is 8bit
1187 */
1188 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
1189 }
1190
1191 /*
1192 * Lock source surface
1193 */
1194 SDL_LockSurface(rz_src);
1195 /*
1196 * Check which kind of surface we have
1197 */
1198 if (is32bit) {
1199 /*
1200 * Call the 32bit transformation routine to do the zooming (using alpha)
1201 */
1202 zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
1203 /*
1204 * Turn on source-alpha support
1205 */
1206 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1207 } else {
1208 /*
1209 * Copy palette and colorkey info
1210 */
1211 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1212 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1213 }
1214 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1215 /*
1216 * Call the 8bit transformation routine to do the zooming
1217 */
1218 zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
1219 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
1220 }
1221 /*
1222 * Unlock source surface
1223 */
1224 SDL_UnlockSurface(rz_src);
1225
1226 /*
1227 * Cleanup temp surface
1228 */
1229 if (src_converted) {
1230 SDL_FreeSurface(rz_src);
1231 }
1232
1233 /*
1234 * Return destination surface
1235 */
1236 return (rz_dst);
1237 }
1238
shrinkSurface(SDL_Surface * src,int factorx,int factory)1239 SDL_Surface *shrinkSurface(SDL_Surface * src, int factorx, int factory)
1240 {
1241 SDL_Surface *rz_src;
1242 SDL_Surface *rz_dst;
1243 int dstwidth, dstheight;
1244 int is32bit;
1245 int i, src_converted;
1246
1247 /*
1248 * Sanity check
1249 */
1250 if (src == NULL)
1251 return (NULL);
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 * Use source surface 'as is'
1260 */
1261 rz_src = src;
1262 src_converted = 0;
1263 } else {
1264 /*
1265 * New source surface is 32bit with a defined RGBA ordering
1266 */
1267 rz_src =
1268 SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1269 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
1270 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
1271 #else
1272 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
1273 #endif
1274 );
1275 SDL_BlitSurface(src, NULL, rz_src, NULL);
1276 src_converted = 1;
1277 is32bit = 1;
1278 }
1279
1280 /* Get size for target */
1281 dstwidth=rz_src->w/factorx;
1282 while (dstwidth*factorx>rz_src->w) { dstwidth--; }
1283 dstheight=rz_src->h/factory;
1284 while (dstheight*factory>rz_src->h) { dstheight--; }
1285
1286 /*
1287 * Alloc space to completely contain the shrunken surface
1288 */
1289 rz_dst = NULL;
1290 if (is32bit) {
1291 /*
1292 * Target surface is 32bit with source RGBA/ABGR ordering
1293 */
1294 rz_dst =
1295 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
1296 rz_src->format->Rmask, rz_src->format->Gmask,
1297 rz_src->format->Bmask, rz_src->format->Amask);
1298 } else {
1299 /*
1300 * Target surface is 8bit
1301 */
1302 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
1303 }
1304
1305 /*
1306 * Lock source surface
1307 */
1308 SDL_LockSurface(rz_src);
1309 /*
1310 * Check which kind of surface we have
1311 */
1312 if (is32bit) {
1313 /*
1314 * Call the 32bit transformation routine to do the shrinking (using alpha)
1315 */
1316 shrinkSurfaceRGBA(rz_src, rz_dst, factorx, factory);
1317 /*
1318 * Turn on source-alpha support
1319 */
1320 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1321 } else {
1322 /*
1323 * Copy palette and colorkey info
1324 */
1325 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1326 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1327 }
1328 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1329 /*
1330 * Call the 8bit transformation routine to do the shrinking
1331 */
1332 shrinkSurfaceY(rz_src, rz_dst, factorx, factory);
1333 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
1334 }
1335 /*
1336 * Unlock source surface
1337 */
1338 SDL_UnlockSurface(rz_src);
1339
1340 /*
1341 * Cleanup temp surface
1342 */
1343 if (src_converted) {
1344 SDL_FreeSurface(rz_src);
1345 }
1346
1347 /*
1348 * Return destination surface
1349 */
1350 return (rz_dst);
1351 }
1352