First cut of multi-player support
[tennix.git] / SDL_rotozoom.c
blobddbc0137cc55d068b76ece3d250aabf321466366
1 /*
3 SDL_rotozoom.c - rotozoomer for 32bit or 8bit surfaces
5 LGPL (c) A. Schiffler
7 */
9 #ifdef WIN32
10 #include <windows.h>
11 #endif
13 #include <stdlib.h>
14 #include <string.h>
16 #include "SDL_rotozoom.h"
18 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
21 /*
23 32bit integer-factor averaging Shrinker
25 Shrinks 32bit RGBA/ABGR 'src' surface to 'dst' surface.
29 int shrinkSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
31 int x, y, dx, dy, sgap, dgap, ra, ga, ba, aa;
32 int n_average;
33 tColorRGBA *sp, *osp, *oosp;
34 tColorRGBA *dp;
37 * Averaging integer shrink
40 /* Precalculate division factor */
41 n_average = factorx*factory;
44 * Scan destination
46 sp = (tColorRGBA *) src->pixels;
47 sgap = src->pitch - src->w * 4;
49 dp = (tColorRGBA *) dst->pixels;
50 dgap = dst->pitch - dst->w * 4;
52 for (y = 0; y < dst->h; y++) {
54 osp=sp;
55 for (x = 0; x < dst->w; x++) {
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;
67 sp++;
69 sp = (tColorRGBA *)((Uint8*)sp + (src->pitch - 4*factorx));
73 sp = (tColorRGBA *)((Uint8*)oosp + 4*factorx);
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;
82 * Advance destination pointer
84 dp++;
88 sp = (tColorRGBA *)((Uint8*)osp + src->pitch*factory);
91 * Advance destination pointers
93 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
96 return (0);
99 /*
101 8bit integer-factor averaging Shrinker
103 Shrinks 8bit Y 'src' surface to 'dst' surface.
107 int shrinkSurfaceY(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
109 int x, y, dx, dy, sgap, dgap, a;
110 int n_average;
111 Uint8 *sp, *osp, *oosp;
112 Uint8 *dp;
115 * Averaging integer shrink
118 /* Precalculate division factor */
119 n_average = factorx*factory;
122 * Scan destination
124 sp = (Uint8 *) src->pixels;
125 sgap = src->pitch - src->w;
127 dp = (Uint8 *) dst->pixels;
128 dgap = dst->pitch - dst->w;
130 for (y = 0; y < dst->h; y++) {
132 osp=sp;
133 for (x = 0; x < dst->w; x++) {
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++;
143 sp = (Uint8 *)((Uint8*)sp + (src->pitch - factorx));
147 sp = (Uint8 *)((Uint8*)oosp + factorx);
149 /* Store result in destination */
150 *dp = a/n_average;
153 * Advance destination pointer
155 dp++;
159 sp = (Uint8 *)((Uint8*)osp + src->pitch*factory);
162 * Advance destination pointers
164 dp = (Uint8 *)((Uint8 *)dp + dgap);
167 return (0);
172 32bit Zoomer with optional anti-aliasing by bilinear interpolation.
174 Zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
178 int zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy, int smooth)
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;
186 * Variable setup
188 if (smooth) {
190 * For interpolation: assume source dimension is one pixel
193 * smaller to avoid overflow on right and bottom edge.
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);
203 * Allocate memory for row increments
205 if ((sax = (int *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
206 return (-1);
208 if ((say = (int *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
209 free(sax);
210 return (-1);
214 * Precalculate row increments
216 sp = csp = (tColorRGBA *) src->pixels;
217 dp = (tColorRGBA *) dst->pixels;
219 if (flipx) csp += (src->w-1);
220 if (flipy) csp = (tColorRGBA*)( (Uint8*)csp + src->pitch*(src->h-1) );
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;
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;
239 dgap = dst->pitch - dst->w * 4;
242 * Switch between interpolating and non-interpolating code
244 if (smooth) {
247 * Interpolating Zoom
251 * Scan destination
253 csay = say;
254 for (y = 0; y < dst->h; y++) {
256 * Setup color source pointers
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++) {
268 * Interpolate colors
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;
286 * Advance source pointers
288 csax++;
289 sstep = (*csax >> 16);
290 c00 += sstep;
291 c01 += sstep;
292 c10 += sstep;
293 c11 += sstep;
295 * Advance destination pointer
297 dp++;
300 * Advance source pointer
302 csay++;
303 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
305 * Advance destination pointers
307 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
310 } else {
313 * Non-Interpolating Zoom
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++) {
322 * Draw
324 *dp = *sp;
326 * Advance source pointers
328 csax++;
329 sstep = (*csax >> 16);
330 if (flipx) sstep = -sstep;
331 sp += sstep;
333 * Advance destination pointer
335 dp++;
338 * Advance source pointer
340 csay++;
341 sstep = (*csay >> 16) * src->pitch;
342 if (flipy) sstep = -sstep;
343 csp = (tColorRGBA *) ((Uint8 *) csp + sstep);
346 * Advance destination pointers
348 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
354 * Remove temp arrays
356 free(sax);
357 free(say);
359 return (0);
364 8bit Zoomer without smoothing.
366 Zoomes 8bit palette/Y 'src' surface to 'dst' surface.
370 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy)
372 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
373 Uint8 *sp, *dp, *csp;
374 int dgap;
377 * Variable setup
379 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
380 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
383 * Allocate memory for row increments
385 if ((sax = (Uint32 *) malloc(dst->w * sizeof(Uint32))) == NULL) {
386 return (-1);
388 if ((say = (Uint32 *) malloc(dst->h * sizeof(Uint32))) == NULL) {
389 if (sax != NULL) {
390 free(sax);
392 return (-1);
396 * Precalculate row increments
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++;
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++;
415 csx = 0;
416 csax = sax;
417 for (x = 0; x < dst->w; x++) {
418 csx += (*csax);
419 csax++;
421 csy = 0;
422 csay = say;
423 for (y = 0; y < dst->h; y++) {
424 csy += (*csay);
425 csay++;
429 * Pointer setup
431 sp = csp = (Uint8 *) src->pixels;
432 dp = (Uint8 *) dst->pixels;
433 dgap = dst->pitch - dst->w;
436 * Draw
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++) {
444 * Draw
446 *dp = *sp;
448 * Advance source pointers
450 sp += (*csax);
451 csax++;
453 * Advance destination pointer
455 dp++;
458 * Advance source pointer (for row)
460 csp += ((*csay) * src->pitch);
461 csay++;
463 * Advance destination pointers
465 dp += dgap;
469 * Remove temp arrays
471 free(sax);
472 free(say);
474 return (0);
479 32bit Rotozoomer with optional anti-aliasing by bilinear interpolation.
481 Rotates and zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
485 void transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy, int smooth)
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;
493 * Variable setup
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;
505 * Switch between interpolating and non-interpolating code
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;
587 * Interpolate colors
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;
604 sdx += icos;
605 sdy += isin;
606 pc++;
608 pc = (tColorRGBA *) ((Uint8 *) pc + gap);
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;
625 sdx += icos;
626 sdy += isin;
627 pc++;
629 pc = (tColorRGBA *) ((Uint8 *) pc + gap);
636 8bit Rotozoomer without smoothing
638 Rotates and zoomes 8bit palette/Y 'src' surface to 'dst' surface.
642 void transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos)
644 int x, y, dx, dy, xd, yd, sdx, sdy, ax, ay, sw, sh;
645 tColorY *pc, *sp;
646 int gap;
649 * Variable setup
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;
660 * Clear surface to colorkey
662 memset(pc, (unsigned char) (src->format->colorkey & 0xff), dst->pitch * dst->h);
664 * Iterate through destination surface
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;
678 sdx += icos;
679 sdy += isin;
680 pc++;
682 pc += gap;
689 32bit specialized 90degree rotator
691 Rotates and zooms 'src' surface to 'dst' surface in 90degree increments.
693 (contributed by Jeff Schiller)
696 SDL_Surface* rotateSurface90Degrees(SDL_Surface* pSurf, int numClockwiseTurns)
698 int row, col, newWidth, newHeight;
699 SDL_Surface* pSurfOut;
702 if (!pSurf || pSurf->format->BitsPerPixel != 32) { return NULL; }
705 while(numClockwiseTurns < 0) { numClockwiseTurns += 4; }
706 numClockwiseTurns = (numClockwiseTurns % 4);
709 newWidth = (numClockwiseTurns % 2) ? (pSurf->h) : (pSurf->w);
710 newHeight = (numClockwiseTurns % 2) ? (pSurf->w) : (pSurf->h);
711 pSurfOut = SDL_CreateRGBSurface( pSurf->flags, newWidth, newHeight, pSurf->format->BitsPerPixel,
712 pSurf->format->Rmask,
713 pSurf->format->Gmask,
714 pSurf->format->Bmask,
715 pSurf->format->Amask);
716 if(!pSurfOut) {
717 return NULL;
720 if(numClockwiseTurns != 0) {
721 SDL_LockSurface(pSurf);
722 SDL_LockSurface(pSurfOut);
723 switch(numClockwiseTurns) {
725 case 1:
727 Uint32* srcBuf = NULL;
728 Uint32* dstBuf = NULL;
730 for (row = 0; row < pSurf->h; ++row) {
731 srcBuf = (Uint32*)(pSurf->pixels) + (row*pSurf->pitch/4);
732 dstBuf = (Uint32*)(pSurfOut->pixels) + (pSurfOut->w - row - 1);
733 for (col = 0; col < pSurf->w; ++col) {
734 *dstBuf = *srcBuf;
735 ++srcBuf;
736 dstBuf += pSurfOut->pitch/4;
740 break;
742 case 2:
744 Uint32* srcBuf = NULL;
745 Uint32* dstBuf = NULL;
747 for(row = 0; row < pSurf->h; ++row) {
748 srcBuf = (Uint32*)(pSurf->pixels) + (row*pSurf->pitch/4);
749 dstBuf = (Uint32*)(pSurfOut->pixels) + ((pSurfOut->h - row - 1)*pSurfOut->pitch/4) + (pSurfOut->w - 1);
750 for(col = 0; col < pSurf->w; ++col) {
751 *dstBuf = *srcBuf;
752 ++srcBuf;
753 --dstBuf;
757 break;
759 case 3:
761 Uint32* srcBuf = NULL;
762 Uint32* dstBuf = NULL;
764 for(row = 0; row < pSurf->h; ++row) {
765 srcBuf = (Uint32*)(pSurf->pixels) + (row*pSurf->pitch/4);
766 dstBuf = (Uint32*)(pSurfOut->pixels) + row + ((pSurfOut->h - 1)*pSurfOut->pitch/4);
767 for(col = 0; col < pSurf->w; ++col) {
768 *dstBuf = *srcBuf;
769 ++srcBuf;
770 dstBuf -= pSurfOut->pitch/4;
774 break;
777 SDL_UnlockSurface(pSurf);
778 SDL_UnlockSurface(pSurfOut);
780 else {
781 /* simply copy surface to output */
782 if(SDL_BlitSurface(pSurf, NULL, pSurfOut, NULL)) {
783 return NULL;
786 return pSurfOut;
791 rotozoomSurface()
793 Rotates and zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
794 'angle' is the rotation in degrees. 'zoom' a scaling factor. If 'smooth' is 1
795 then the destination 32bit surface is anti-aliased. If the surface is not 8bit
796 or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
800 #define VALUE_LIMIT 0.001
803 /* Local rotozoom-size function with trig result return */
805 void rotozoomSurfaceSizeTrig(int width, int height, double angle, double zoomx, double zoomy, int *dstwidth, int *dstheight,
806 double *canglezoom, double *sanglezoom)
808 double x, y, cx, cy, sx, sy;
809 double radangle;
810 int dstwidthhalf, dstheighthalf;
813 * Determine destination width and height by rotating a centered source box
815 radangle = angle * (M_PI / 180.0);
816 *sanglezoom = sin(radangle);
817 *canglezoom = cos(radangle);
818 *sanglezoom *= zoomx;
819 *canglezoom *= zoomx;
820 x = width / 2;
821 y = height / 2;
822 cx = *canglezoom * x;
823 cy = *canglezoom * y;
824 sx = *sanglezoom * x;
825 sy = *sanglezoom * y;
827 dstwidthhalf = MAX((int)
828 ceil(MAX(MAX(MAX(fabs(cx + sy), fabs(cx - sy)), fabs(-cx + sy)), fabs(-cx - sy))), 1);
829 dstheighthalf = MAX((int)
830 ceil(MAX(MAX(MAX(fabs(sx + cy), fabs(sx - cy)), fabs(-sx + cy)), fabs(-sx - cy))), 1);
831 *dstwidth = 2 * dstwidthhalf;
832 *dstheight = 2 * dstheighthalf;
836 /* Publically available rotozoom-size function */
838 void rotozoomSurfaceSizeXY(int width, int height, double angle, double zoomx, double zoomy, int *dstwidth, int *dstheight)
840 double dummy_sanglezoom, dummy_canglezoom;
842 rotozoomSurfaceSizeTrig(width, height, angle, zoomx, zoomy, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
845 /* Publically available rotozoom-size function */
847 void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth, int *dstheight)
849 double dummy_sanglezoom, dummy_canglezoom;
851 rotozoomSurfaceSizeTrig(width, height, angle, zoom, zoom, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
854 /* Publically available rotozoom function */
856 SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth)
858 return rotozoomSurfaceXY(src, angle, zoom, zoom, smooth);
861 /* Publically available rotozoom function */
863 SDL_Surface *rotozoomSurfaceXY(SDL_Surface * src, double angle, double zoomx, double zoomy, int smooth)
865 SDL_Surface *rz_src;
866 SDL_Surface *rz_dst;
867 double zoominv;
868 double sanglezoom, canglezoom, sanglezoominv, canglezoominv;
869 int dstwidthhalf, dstwidth, dstheighthalf, dstheight;
870 int is32bit;
871 int i, src_converted;
872 int flipx,flipy;
873 Uint8 r,g,b;
874 Uint32 colorkey;
875 int colorKeyAvailable = 0;
878 * Sanity check
880 if (src == NULL)
881 return (NULL);
883 if( src->flags & SDL_SRCCOLORKEY )
885 colorkey = src->format->colorkey;
886 SDL_GetRGB(colorkey, src->format, &r, &g, &b);
887 colorKeyAvailable = 1;
890 * Determine if source surface is 32bit or 8bit
892 is32bit = (src->format->BitsPerPixel == 32);
893 if ((is32bit) || (src->format->BitsPerPixel == 8)) {
895 * Use source surface 'as is'
897 rz_src = src;
898 src_converted = 0;
899 } else {
901 * New source surface is 32bit with a defined RGBA ordering
903 rz_src =
904 SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
905 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
906 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
907 #else
908 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
909 #endif
911 if(colorKeyAvailable)
912 SDL_SetColorKey(src, 0, 0);
914 SDL_BlitSurface(src, NULL, rz_src, NULL);
916 if(colorKeyAvailable)
917 SDL_SetColorKey(src, SDL_SRCCOLORKEY, colorkey);
918 src_converted = 1;
919 is32bit = 1;
923 * Sanity check zoom factor
925 flipx = (zoomx<0);
926 if (flipx) zoomx=-zoomx;
927 flipy = (zoomy<0);
928 if (flipy) zoomy=-zoomy;
929 if (zoomx < VALUE_LIMIT) zoomx = VALUE_LIMIT;
930 if (zoomy < VALUE_LIMIT) zoomy = VALUE_LIMIT;
931 zoominv = 65536.0 / (zoomx * zoomx);
934 * Check if we have a rotozoom or just a zoom
936 if (fabs(angle) > VALUE_LIMIT) {
939 * Angle!=0: full rotozoom
942 * -----------------------
945 /* Determine target size */
946 rotozoomSurfaceSizeTrig(rz_src->w, rz_src->h, angle, zoomx, zoomy, &dstwidth, &dstheight, &canglezoom, &sanglezoom);
949 * Calculate target factors from sin/cos and zoom
951 sanglezoominv = sanglezoom;
952 canglezoominv = canglezoom;
953 sanglezoominv *= zoominv;
954 canglezoominv *= zoominv;
956 /* Calculate half size */
957 dstwidthhalf = dstwidth / 2;
958 dstheighthalf = dstheight / 2;
961 * Alloc space to completely contain the rotated surface
963 rz_dst = NULL;
964 if (is32bit) {
966 * Target surface is 32bit with source RGBA/ABGR ordering
968 rz_dst =
969 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
970 rz_src->format->Rmask, rz_src->format->Gmask,
971 rz_src->format->Bmask, rz_src->format->Amask);
972 } else {
974 * Target surface is 8bit
976 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
979 if (colorKeyAvailable == 1){
980 colorkey = SDL_MapRGB(rz_dst->format, r, g, b);
982 SDL_FillRect(rz_dst, NULL, colorkey );
986 * Lock source surface
988 SDL_LockSurface(rz_src);
990 * Check which kind of surface we have
992 if (is32bit) {
994 * Call the 32bit transformation routine to do the rotation (using alpha)
996 transformSurfaceRGBA(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
997 (int) (sanglezoominv), (int) (canglezoominv),
998 flipx, flipy,
999 smooth);
1001 * Turn on source-alpha support
1003 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1004 } else {
1006 * Copy palette and colorkey info
1008 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1009 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1011 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1013 * Call the 8bit transformation routine to do the rotation
1015 transformSurfaceY(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
1016 (int) (sanglezoominv), (int) (canglezoominv));
1017 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
1020 * Unlock source surface
1022 SDL_UnlockSurface(rz_src);
1024 } else {
1027 * Angle=0: Just a zoom
1030 * --------------------
1034 * Calculate target size
1036 zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
1039 * Alloc space to completely contain the zoomed surface
1041 rz_dst = NULL;
1042 if (is32bit) {
1044 * Target surface is 32bit with source RGBA/ABGR ordering
1046 rz_dst =
1047 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
1048 rz_src->format->Rmask, rz_src->format->Gmask,
1049 rz_src->format->Bmask, rz_src->format->Amask);
1050 } else {
1052 * Target surface is 8bit
1054 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
1057 if (colorKeyAvailable == 1){
1058 colorkey = SDL_MapRGB(rz_dst->format, r, g, b);
1060 SDL_FillRect(rz_dst, NULL, colorkey );
1064 * Lock source surface
1066 SDL_LockSurface(rz_src);
1068 * Check which kind of surface we have
1070 if (is32bit) {
1072 * Call the 32bit transformation routine to do the zooming (using alpha)
1074 zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
1076 * Turn on source-alpha support
1078 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1079 } else {
1081 * Copy palette and colorkey info
1083 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1084 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1086 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1088 * Call the 8bit transformation routine to do the zooming
1090 zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
1091 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
1094 * Unlock source surface
1096 SDL_UnlockSurface(rz_src);
1100 * Cleanup temp surface
1102 if (src_converted) {
1103 SDL_FreeSurface(rz_src);
1107 * Return destination surface
1109 return (rz_dst);
1114 zoomSurface()
1116 Zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1117 'zoomx' and 'zoomy' are scaling factors for width and height. If 'smooth' is 1
1118 then the destination 32bit surface is anti-aliased. If the surface is not 8bit
1119 or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
1123 #define VALUE_LIMIT 0.001
1125 void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight)
1128 * Sanity check zoom factors
1130 if (zoomx < VALUE_LIMIT) {
1131 zoomx = VALUE_LIMIT;
1133 if (zoomy < VALUE_LIMIT) {
1134 zoomy = VALUE_LIMIT;
1138 * Calculate target size
1140 *dstwidth = (int) ((double) width * zoomx);
1141 *dstheight = (int) ((double) height * zoomy);
1142 if (*dstwidth < 1) {
1143 *dstwidth = 1;
1145 if (*dstheight < 1) {
1146 *dstheight = 1;
1150 SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth)
1152 SDL_Surface *rz_src;
1153 SDL_Surface *rz_dst;
1154 int dstwidth, dstheight;
1155 int is32bit;
1156 int i, src_converted;
1157 int flipx, flipy;
1160 * Sanity check
1162 if (src == NULL)
1163 return (NULL);
1166 * Determine if source surface is 32bit or 8bit
1168 is32bit = (src->format->BitsPerPixel == 32);
1169 if ((is32bit) || (src->format->BitsPerPixel == 8)) {
1171 * Use source surface 'as is'
1173 rz_src = src;
1174 src_converted = 0;
1175 } else {
1177 * New source surface is 32bit with a defined RGBA ordering
1179 rz_src =
1180 SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1181 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
1182 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
1183 #else
1184 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
1185 #endif
1187 SDL_BlitSurface(src, NULL, rz_src, NULL);
1188 src_converted = 1;
1189 is32bit = 1;
1192 flipx = (zoomx<0);
1193 if (flipx) zoomx = -zoomx;
1194 flipy = (zoomy<0);
1195 if (flipy) zoomy = -zoomy;
1197 /* Get size if target */
1198 zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
1201 * Alloc space to completely contain the zoomed surface
1203 rz_dst = NULL;
1204 if (is32bit) {
1206 * Target surface is 32bit with source RGBA/ABGR ordering
1208 rz_dst =
1209 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
1210 rz_src->format->Rmask, rz_src->format->Gmask,
1211 rz_src->format->Bmask, rz_src->format->Amask);
1212 } else {
1214 * Target surface is 8bit
1216 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
1220 * Lock source surface
1222 SDL_LockSurface(rz_src);
1224 * Check which kind of surface we have
1226 if (is32bit) {
1228 * Call the 32bit transformation routine to do the zooming (using alpha)
1230 zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
1232 * Turn on source-alpha support
1234 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1235 } else {
1237 * Copy palette and colorkey info
1239 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1240 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1242 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1244 * Call the 8bit transformation routine to do the zooming
1246 zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
1247 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
1250 * Unlock source surface
1252 SDL_UnlockSurface(rz_src);
1255 * Cleanup temp surface
1257 if (src_converted) {
1258 SDL_FreeSurface(rz_src);
1262 * Return destination surface
1264 return (rz_dst);
1267 SDL_Surface *shrinkSurface(SDL_Surface * src, int factorx, int factory)
1269 SDL_Surface *rz_src;
1270 SDL_Surface *rz_dst;
1271 int dstwidth, dstheight;
1272 int is32bit;
1273 int i, src_converted;
1276 * Sanity check
1278 if (src == NULL)
1279 return (NULL);
1282 * Determine if source surface is 32bit or 8bit
1284 is32bit = (src->format->BitsPerPixel == 32);
1285 if ((is32bit) || (src->format->BitsPerPixel == 8)) {
1287 * Use source surface 'as is'
1289 rz_src = src;
1290 src_converted = 0;
1291 } else {
1293 * New source surface is 32bit with a defined RGBA ordering
1295 rz_src =
1296 SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1297 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
1298 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
1299 #else
1300 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
1301 #endif
1303 SDL_BlitSurface(src, NULL, rz_src, NULL);
1304 src_converted = 1;
1305 is32bit = 1;
1308 /* Get size for target */
1309 dstwidth=rz_src->w/factorx;
1310 while (dstwidth*factorx>rz_src->w) { dstwidth--; }
1311 dstheight=rz_src->h/factory;
1312 while (dstheight*factory>rz_src->h) { dstheight--; }
1315 * Alloc space to completely contain the shrunken surface
1317 rz_dst = NULL;
1318 if (is32bit) {
1320 * Target surface is 32bit with source RGBA/ABGR ordering
1322 rz_dst =
1323 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
1324 rz_src->format->Rmask, rz_src->format->Gmask,
1325 rz_src->format->Bmask, rz_src->format->Amask);
1326 } else {
1328 * Target surface is 8bit
1330 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
1334 * Lock source surface
1336 SDL_LockSurface(rz_src);
1338 * Check which kind of surface we have
1340 if (is32bit) {
1342 * Call the 32bit transformation routine to do the shrinking (using alpha)
1344 shrinkSurfaceRGBA(rz_src, rz_dst, factorx, factory);
1346 * Turn on source-alpha support
1348 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1349 } else {
1351 * Copy palette and colorkey info
1353 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1354 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1356 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1358 * Call the 8bit transformation routine to do the shrinking
1360 shrinkSurfaceY(rz_src, rz_dst, factorx, factory);
1361 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
1364 * Unlock source surface
1366 SDL_UnlockSurface(rz_src);
1369 * Cleanup temp surface
1371 if (src_converted) {
1372 SDL_FreeSurface(rz_src);
1376 * Return destination surface
1378 return (rz_dst);