Apply fixes and documentation notes for Windows builds
[tennix.git] / SDL_rotozoom.c
blob59af2896c5763bca90d0e3e1399db4762ffb82fd
1 /*
3 SDL_rotozoom.c - rotozoomer for 32bit or 8bit surfaces
5 LGPL (c) A. Schiffler
7 */
9 #include <stdlib.h>
10 #include <string.h>
12 #include "SDL_rotozoom.h"
14 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
17 /*
19 32bit integer-factor averaging Shrinker
21 Shrinks 32bit RGBA/ABGR 'src' surface to 'dst' surface.
25 int shrinkSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
27 int x, y, dx, dy, sgap, dgap, ra, ga, ba, aa;
28 int n_average;
29 tColorRGBA *sp, *osp, *oosp;
30 tColorRGBA *dp;
33 * Averaging integer shrink
36 /* Precalculate division factor */
37 n_average = factorx*factory;
40 * Scan destination
42 sp = (tColorRGBA *) src->pixels;
43 sgap = src->pitch - src->w * 4;
45 dp = (tColorRGBA *) dst->pixels;
46 dgap = dst->pitch - dst->w * 4;
48 for (y = 0; y < dst->h; y++) {
50 osp=sp;
51 for (x = 0; x < dst->w; x++) {
53 /* Trace out source box and accumulate */
54 oosp=sp;
55 ra=ga=ba=aa=0;
56 for (dy=0; dy < factory; dy++) {
57 for (dx=0; dx < factorx; dx++) {
58 ra += sp->r;
59 ga += sp->g;
60 ba += sp->b;
61 aa += sp->a;
63 sp++;
65 sp = (tColorRGBA *)((Uint8*)sp + (src->pitch - 4*factorx));
69 sp = (tColorRGBA *)((Uint8*)oosp + 4*factorx);
71 /* Store result in destination */
72 dp->r = ra/n_average;
73 dp->g = ga/n_average;
74 dp->b = ba/n_average;
75 dp->a = aa/n_average;
78 * Advance destination pointer
80 dp++;
84 sp = (tColorRGBA *)((Uint8*)osp + src->pitch*factory);
87 * Advance destination pointers
89 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
92 return (0);
95 /*
97 8bit integer-factor averaging Shrinker
99 Shrinks 8bit Y 'src' surface to 'dst' surface.
103 int shrinkSurfaceY(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
105 int x, y, dx, dy, sgap, dgap, a;
106 int n_average;
107 Uint8 *sp, *osp, *oosp;
108 Uint8 *dp;
111 * Averaging integer shrink
114 /* Precalculate division factor */
115 n_average = factorx*factory;
118 * Scan destination
120 sp = (Uint8 *) src->pixels;
121 sgap = src->pitch - src->w;
123 dp = (Uint8 *) dst->pixels;
124 dgap = dst->pitch - dst->w;
126 for (y = 0; y < dst->h; y++) {
128 osp=sp;
129 for (x = 0; x < dst->w; x++) {
131 /* Trace out source box and accumulate */
132 oosp=sp;
133 a=0;
134 for (dy=0; dy < factory; dy++) {
135 for (dx=0; dx < factorx; dx++) {
136 a += (*sp);
137 sp++;
139 sp = (Uint8 *)((Uint8*)sp + (src->pitch - factorx));
143 sp = (Uint8 *)((Uint8*)oosp + factorx);
145 /* Store result in destination */
146 *dp = a/n_average;
149 * Advance destination pointer
151 dp++;
155 sp = (Uint8 *)((Uint8*)osp + src->pitch*factory);
158 * Advance destination pointers
160 dp = (Uint8 *)((Uint8 *)dp + dgap);
163 return (0);
168 32bit Zoomer with optional anti-aliasing by bilinear interpolation.
170 Zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
174 int zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy, int smooth)
176 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy, ex, ey, t1, t2, sstep;
177 tColorRGBA *c00, *c01, *c10, *c11;
178 tColorRGBA *sp, *csp, *dp;
179 int dgap;
182 * Variable setup
184 if (smooth) {
186 * For interpolation: assume source dimension is one pixel
189 * smaller to avoid overflow on right and bottom edge.
191 sx = (int) (65536.0 * (float) (src->w - 1) / (float) dst->w);
192 sy = (int) (65536.0 * (float) (src->h - 1) / (float) dst->h);
193 } else {
194 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
195 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
199 * Allocate memory for row increments
201 if ((sax = (int *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
202 return (-1);
204 if ((say = (int *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
205 free(sax);
206 return (-1);
210 * Precalculate row increments
212 sp = csp = (tColorRGBA *) src->pixels;
213 dp = (tColorRGBA *) dst->pixels;
215 if (flipx) csp += (src->w-1);
216 if (flipy) csp = (tColorRGBA*)( (Uint8*)csp + src->pitch*(src->h-1) );
218 csx = 0;
219 csax = sax;
220 for (x = 0; x <= dst->w; x++) {
221 *csax = csx;
222 csax++;
223 csx &= 0xffff;
224 csx += sx;
226 csy = 0;
227 csay = say;
228 for (y = 0; y <= dst->h; y++) {
229 *csay = csy;
230 csay++;
231 csy &= 0xffff;
232 csy += sy;
235 dgap = dst->pitch - dst->w * 4;
238 * Switch between interpolating and non-interpolating code
240 if (smooth) {
243 * Interpolating Zoom
247 * Scan destination
249 csay = say;
250 for (y = 0; y < dst->h; y++) {
252 * Setup color source pointers
254 c00 = csp;
255 c01 = csp;
256 c01++;
257 c10 = (tColorRGBA *) ((Uint8 *) csp + src->pitch);
258 c11 = c10;
259 c11++;
260 csax = sax;
261 for (x = 0; x < dst->w; x++) {
264 * Interpolate colors
266 ex = (*csax & 0xffff);
267 ey = (*csay & 0xffff);
268 t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
269 t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
270 dp->r = (((t2 - t1) * ey) >> 16) + t1;
271 t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff;
272 t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff;
273 dp->g = (((t2 - t1) * ey) >> 16) + t1;
274 t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff;
275 t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff;
276 dp->b = (((t2 - t1) * ey) >> 16) + t1;
277 t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff;
278 t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff;
279 dp->a = (((t2 - t1) * ey) >> 16) + t1;
282 * Advance source pointers
284 csax++;
285 sstep = (*csax >> 16);
286 c00 += sstep;
287 c01 += sstep;
288 c10 += sstep;
289 c11 += sstep;
291 * Advance destination pointer
293 dp++;
296 * Advance source pointer
298 csay++;
299 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
301 * Advance destination pointers
303 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
306 } else {
309 * Non-Interpolating Zoom
312 csay = say;
313 for (y = 0; y < dst->h; y++) {
314 sp = csp;
315 csax = sax;
316 for (x = 0; x < dst->w; x++) {
318 * Draw
320 *dp = *sp;
322 * Advance source pointers
324 csax++;
325 sstep = (*csax >> 16);
326 if (flipx) sstep = -sstep;
327 sp += sstep;
329 * Advance destination pointer
331 dp++;
334 * Advance source pointer
336 csay++;
337 sstep = (*csay >> 16) * src->pitch;
338 if (flipy) sstep = -sstep;
339 csp = (tColorRGBA *) ((Uint8 *) csp + sstep);
342 * Advance destination pointers
344 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
350 * Remove temp arrays
352 free(sax);
353 free(say);
355 return (0);
360 8bit Zoomer without smoothing.
362 Zoomes 8bit palette/Y 'src' surface to 'dst' surface.
366 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy)
368 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
369 Uint8 *sp, *dp, *csp;
370 int dgap;
373 * Variable setup
375 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
376 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
379 * Allocate memory for row increments
381 if ((sax = (Uint32 *) malloc(dst->w * sizeof(Uint32))) == NULL) {
382 return (-1);
384 if ((say = (Uint32 *) malloc(dst->h * sizeof(Uint32))) == NULL) {
385 if (sax != NULL) {
386 free(sax);
388 return (-1);
392 * Precalculate row increments
394 csx = 0;
395 csax = sax;
396 for (x = 0; x < dst->w; x++) {
397 csx += sx;
398 *csax = (csx >> 16);
399 csx &= 0xffff;
400 csax++;
402 csy = 0;
403 csay = say;
404 for (y = 0; y < dst->h; y++) {
405 csy += sy;
406 *csay = (csy >> 16);
407 csy &= 0xffff;
408 csay++;
411 csx = 0;
412 csax = sax;
413 for (x = 0; x < dst->w; x++) {
414 csx += (*csax);
415 csax++;
417 csy = 0;
418 csay = say;
419 for (y = 0; y < dst->h; y++) {
420 csy += (*csay);
421 csay++;
425 * Pointer setup
427 sp = csp = (Uint8 *) src->pixels;
428 dp = (Uint8 *) dst->pixels;
429 dgap = dst->pitch - dst->w;
432 * Draw
434 csay = say;
435 for (y = 0; y < dst->h; y++) {
436 csax = sax;
437 sp = csp;
438 for (x = 0; x < dst->w; x++) {
440 * Draw
442 *dp = *sp;
444 * Advance source pointers
446 sp += (*csax);
447 csax++;
449 * Advance destination pointer
451 dp++;
454 * Advance source pointer (for row)
456 csp += ((*csay) * src->pitch);
457 csay++;
459 * Advance destination pointers
461 dp += dgap;
465 * Remove temp arrays
467 free(sax);
468 free(say);
470 return (0);
475 32bit Rotozoomer with optional anti-aliasing by bilinear interpolation.
477 Rotates and zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
481 void transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy, int smooth)
483 int x, y, t1, t2, dx, dy, xd, yd, sdx, sdy, ax, ay, ex, ey, sw, sh;
484 tColorRGBA c00, c01, c10, c11;
485 tColorRGBA *pc, *sp;
486 int gap;
489 * Variable setup
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 * 4;
501 * Switch between interpolating and non-interpolating code
503 if (smooth) {
504 for (y = 0; y < dst->h; y++) {
505 dy = cy - y;
506 sdx = (ax + (isin * dy)) + xd;
507 sdy = (ay - (icos * dy)) + yd;
508 for (x = 0; x < dst->w; x++) {
509 dx = (sdx >> 16);
510 dy = (sdy >> 16);
511 if ((dx >= -1) && (dy >= -1) && (dx < src->w) && (dy < src->h)) {
512 if ((dx >= 0) && (dy >= 0) && (dx < sw) && (dy < sh)) {
513 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
514 sp += dx;
515 c00 = *sp;
516 sp += 1;
517 c01 = *sp;
518 sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
519 sp -= 1;
520 c10 = *sp;
521 sp += 1;
522 c11 = *sp;
523 } else if ((dx == sw) && (dy == sh)) {
524 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
525 sp += dx;
526 c00 = *sp;
527 c01 = *sp;
528 c10 = *sp;
529 c11 = *sp;
530 } else if ((dx == -1) && (dy == -1)) {
531 sp = (tColorRGBA *) (src->pixels);
532 c00 = *sp;
533 c01 = *sp;
534 c10 = *sp;
535 c11 = *sp;
536 } else if ((dx == -1) && (dy == sh)) {
537 sp = (tColorRGBA *) (src->pixels);
538 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
539 c00 = *sp;
540 c01 = *sp;
541 c10 = *sp;
542 c11 = *sp;
543 } else if ((dx == sw) && (dy == -1)) {
544 sp = (tColorRGBA *) (src->pixels);
545 sp += dx;
546 c00 = *sp;
547 c01 = *sp;
548 c10 = *sp;
549 c11 = *sp;
550 } else if (dx == -1) {
551 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
552 c00 = *sp;
553 c01 = *sp;
554 c10 = *sp;
555 sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
556 c11 = *sp;
557 } else if (dy == -1) {
558 sp = (tColorRGBA *) (src->pixels);
559 sp += dx;
560 c00 = *sp;
561 c01 = *sp;
562 c10 = *sp;
563 sp += 1;
564 c11 = *sp;
565 } else if (dx == sw) {
566 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
567 sp += dx;
568 c00 = *sp;
569 c01 = *sp;
570 sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
571 c10 = *sp;
572 c11 = *sp;
573 } else if (dy == sh) {
574 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
575 sp += dx;
576 c00 = *sp;
577 sp += 1;
578 c01 = *sp;
579 c10 = *sp;
580 c11 = *sp;
583 * Interpolate colors
585 ex = (sdx & 0xffff);
586 ey = (sdy & 0xffff);
587 t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff;
588 t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff;
589 pc->r = (((t2 - t1) * ey) >> 16) + t1;
590 t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff;
591 t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff;
592 pc->g = (((t2 - t1) * ey) >> 16) + t1;
593 t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff;
594 t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff;
595 pc->b = (((t2 - t1) * ey) >> 16) + t1;
596 t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff;
597 t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff;
598 pc->a = (((t2 - t1) * ey) >> 16) + t1;
600 sdx += icos;
601 sdy += isin;
602 pc++;
604 pc = (tColorRGBA *) ((Uint8 *) pc + gap);
606 } else {
607 for (y = 0; y < dst->h; y++) {
608 dy = cy - y;
609 sdx = (ax + (isin * dy)) + xd;
610 sdy = (ay - (icos * dy)) + yd;
611 for (x = 0; x < dst->w; x++) {
612 dx = (short) (sdx >> 16);
613 dy = (short) (sdy >> 16);
614 if (flipx) dx = (src->w-1)-dx;
615 if (flipy) dy = (src->h-1)-dy;
616 if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
617 sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
618 sp += dx;
619 *pc = *sp;
621 sdx += icos;
622 sdy += isin;
623 pc++;
625 pc = (tColorRGBA *) ((Uint8 *) pc + gap);
632 8bit Rotozoomer without smoothing
634 Rotates and zoomes 8bit palette/Y 'src' surface to 'dst' surface.
638 void transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos)
640 int x, y, dx, dy, xd, yd, sdx, sdy, ax, ay, sw, sh;
641 tColorY *pc, *sp;
642 int gap;
645 * Variable setup
647 xd = ((src->w - dst->w) << 15);
648 yd = ((src->h - dst->h) << 15);
649 ax = (cx << 16) - (icos * cx);
650 ay = (cy << 16) - (isin * cx);
651 sw = src->w - 1;
652 sh = src->h - 1;
653 pc = dst->pixels;
654 gap = dst->pitch - dst->w;
656 * Clear surface to colorkey
658 memset(pc, (unsigned char) (src->format->colorkey & 0xff), dst->pitch * dst->h);
660 * Iterate through destination surface
662 for (y = 0; y < dst->h; y++) {
663 dy = cy - y;
664 sdx = (ax + (isin * dy)) + xd;
665 sdy = (ay - (icos * dy)) + yd;
666 for (x = 0; x < dst->w; x++) {
667 dx = (short) (sdx >> 16);
668 dy = (short) (sdy >> 16);
669 if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
670 sp = (tColorY *) (src->pixels);
671 sp += (src->pitch * dy + dx);
672 *pc = *sp;
674 sdx += icos;
675 sdy += isin;
676 pc++;
678 pc += gap;
685 32bit specialized 90degree rotator
687 Rotates and zooms 'src' surface to 'dst' surface in 90degree increments.
689 (contributed by Jeff Schiller)
692 SDL_Surface* rotateSurface90Degrees(SDL_Surface* pSurf, int numClockwiseTurns)
694 int row, col, newWidth, newHeight;
695 SDL_Surface* pSurfOut;
698 if (!pSurf || pSurf->format->BitsPerPixel != 32) { return NULL; }
701 while(numClockwiseTurns < 0) { numClockwiseTurns += 4; }
702 numClockwiseTurns = (numClockwiseTurns % 4);
705 newWidth = (numClockwiseTurns % 2) ? (pSurf->h) : (pSurf->w);
706 newHeight = (numClockwiseTurns % 2) ? (pSurf->w) : (pSurf->h);
707 pSurfOut = SDL_CreateRGBSurface( pSurf->flags, newWidth, newHeight, pSurf->format->BitsPerPixel,
708 pSurf->format->Rmask,
709 pSurf->format->Gmask,
710 pSurf->format->Bmask,
711 pSurf->format->Amask);
712 if(!pSurfOut) {
713 return NULL;
716 if(numClockwiseTurns != 0) {
717 SDL_LockSurface(pSurf);
718 SDL_LockSurface(pSurfOut);
719 switch(numClockwiseTurns) {
721 case 1:
723 Uint32* srcBuf = NULL;
724 Uint32* dstBuf = NULL;
726 for (row = 0; row < pSurf->h; ++row) {
727 srcBuf = (Uint32*)(pSurf->pixels) + (row*pSurf->pitch/4);
728 dstBuf = (Uint32*)(pSurfOut->pixels) + (pSurfOut->w - row - 1);
729 for (col = 0; col < pSurf->w; ++col) {
730 *dstBuf = *srcBuf;
731 ++srcBuf;
732 dstBuf += pSurfOut->pitch/4;
736 break;
738 case 2:
740 Uint32* srcBuf = NULL;
741 Uint32* dstBuf = NULL;
743 for(row = 0; row < pSurf->h; ++row) {
744 srcBuf = (Uint32*)(pSurf->pixels) + (row*pSurf->pitch/4);
745 dstBuf = (Uint32*)(pSurfOut->pixels) + ((pSurfOut->h - row - 1)*pSurfOut->pitch/4) + (pSurfOut->w - 1);
746 for(col = 0; col < pSurf->w; ++col) {
747 *dstBuf = *srcBuf;
748 ++srcBuf;
749 --dstBuf;
753 break;
755 case 3:
757 Uint32* srcBuf = NULL;
758 Uint32* dstBuf = NULL;
760 for(row = 0; row < pSurf->h; ++row) {
761 srcBuf = (Uint32*)(pSurf->pixels) + (row*pSurf->pitch/4);
762 dstBuf = (Uint32*)(pSurfOut->pixels) + row + ((pSurfOut->h - 1)*pSurfOut->pitch/4);
763 for(col = 0; col < pSurf->w; ++col) {
764 *dstBuf = *srcBuf;
765 ++srcBuf;
766 dstBuf -= pSurfOut->pitch/4;
770 break;
773 SDL_UnlockSurface(pSurf);
774 SDL_UnlockSurface(pSurfOut);
776 else {
777 /* simply copy surface to output */
778 if(SDL_BlitSurface(pSurf, NULL, pSurfOut, NULL)) {
779 return NULL;
782 return pSurfOut;
787 rotozoomSurface()
789 Rotates and zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
790 'angle' is the rotation in degrees. 'zoom' a scaling factor. If 'smooth' is 1
791 then the destination 32bit surface is anti-aliased. If the surface is not 8bit
792 or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
796 #define VALUE_LIMIT 0.001
799 /* Local rotozoom-size function with trig result return */
801 void rotozoomSurfaceSizeTrig(int width, int height, double angle, double zoomx, double zoomy, int *dstwidth, int *dstheight,
802 double *canglezoom, double *sanglezoom)
804 double x, y, cx, cy, sx, sy;
805 double radangle;
806 int dstwidthhalf, dstheighthalf;
809 * Determine destination width and height by rotating a centered source box
811 radangle = angle * (M_PI / 180.0);
812 *sanglezoom = sin(radangle);
813 *canglezoom = cos(radangle);
814 *sanglezoom *= zoomx;
815 *canglezoom *= zoomx;
816 x = width / 2;
817 y = height / 2;
818 cx = *canglezoom * x;
819 cy = *canglezoom * y;
820 sx = *sanglezoom * x;
821 sy = *sanglezoom * y;
823 dstwidthhalf = MAX((int)
824 ceil(MAX(MAX(MAX(fabs(cx + sy), fabs(cx - sy)), fabs(-cx + sy)), fabs(-cx - sy))), 1);
825 dstheighthalf = MAX((int)
826 ceil(MAX(MAX(MAX(fabs(sx + cy), fabs(sx - cy)), fabs(-sx + cy)), fabs(-sx - cy))), 1);
827 *dstwidth = 2 * dstwidthhalf;
828 *dstheight = 2 * dstheighthalf;
832 /* Publically available rotozoom-size function */
834 void rotozoomSurfaceSizeXY(int width, int height, double angle, double zoomx, double zoomy, int *dstwidth, int *dstheight)
836 double dummy_sanglezoom, dummy_canglezoom;
838 rotozoomSurfaceSizeTrig(width, height, angle, zoomx, zoomy, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
841 /* Publically available rotozoom-size function */
843 void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth, int *dstheight)
845 double dummy_sanglezoom, dummy_canglezoom;
847 rotozoomSurfaceSizeTrig(width, height, angle, zoom, zoom, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
850 /* Publically available rotozoom function */
852 SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth)
854 return rotozoomSurfaceXY(src, angle, zoom, zoom, smooth);
857 /* Publically available rotozoom function */
859 SDL_Surface *rotozoomSurfaceXY(SDL_Surface * src, double angle, double zoomx, double zoomy, int smooth)
861 SDL_Surface *rz_src;
862 SDL_Surface *rz_dst;
863 double zoominv;
864 double sanglezoom, canglezoom, sanglezoominv, canglezoominv;
865 int dstwidthhalf, dstwidth, dstheighthalf, dstheight;
866 int is32bit;
867 int i, src_converted;
868 int flipx,flipy;
869 Uint8 r,g,b;
870 Uint32 colorkey;
871 int colorKeyAvailable = 0;
874 * Sanity check
876 if (src == NULL)
877 return (NULL);
879 if( src->flags & SDL_SRCCOLORKEY )
881 colorkey = src->format->colorkey;
882 SDL_GetRGB(colorkey, src->format, &r, &g, &b);
883 colorKeyAvailable = 1;
886 * Determine if source surface is 32bit or 8bit
888 is32bit = (src->format->BitsPerPixel == 32);
889 if ((is32bit) || (src->format->BitsPerPixel == 8)) {
891 * Use source surface 'as is'
893 rz_src = src;
894 src_converted = 0;
895 } else {
897 * New source surface is 32bit with a defined RGBA ordering
899 rz_src =
900 SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
901 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
902 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
903 #else
904 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
905 #endif
907 if(colorKeyAvailable)
908 SDL_SetColorKey(src, 0, 0);
910 SDL_BlitSurface(src, NULL, rz_src, NULL);
912 if(colorKeyAvailable)
913 SDL_SetColorKey(src, SDL_SRCCOLORKEY, colorkey);
914 src_converted = 1;
915 is32bit = 1;
919 * Sanity check zoom factor
921 flipx = (zoomx<0);
922 if (flipx) zoomx=-zoomx;
923 flipy = (zoomy<0);
924 if (flipy) zoomy=-zoomy;
925 if (zoomx < VALUE_LIMIT) zoomx = VALUE_LIMIT;
926 if (zoomy < VALUE_LIMIT) zoomy = VALUE_LIMIT;
927 zoominv = 65536.0 / (zoomx * zoomx);
930 * Check if we have a rotozoom or just a zoom
932 if (fabs(angle) > VALUE_LIMIT) {
935 * Angle!=0: full rotozoom
938 * -----------------------
941 /* Determine target size */
942 rotozoomSurfaceSizeTrig(rz_src->w, rz_src->h, angle, zoomx, zoomy, &dstwidth, &dstheight, &canglezoom, &sanglezoom);
945 * Calculate target factors from sin/cos and zoom
947 sanglezoominv = sanglezoom;
948 canglezoominv = canglezoom;
949 sanglezoominv *= zoominv;
950 canglezoominv *= zoominv;
952 /* Calculate half size */
953 dstwidthhalf = dstwidth / 2;
954 dstheighthalf = dstheight / 2;
957 * Alloc space to completely contain the rotated surface
959 rz_dst = NULL;
960 if (is32bit) {
962 * Target surface is 32bit with source RGBA/ABGR ordering
964 rz_dst =
965 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
966 rz_src->format->Rmask, rz_src->format->Gmask,
967 rz_src->format->Bmask, rz_src->format->Amask);
968 } else {
970 * Target surface is 8bit
972 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
975 if (colorKeyAvailable == 1){
976 colorkey = SDL_MapRGB(rz_dst->format, r, g, b);
978 SDL_FillRect(rz_dst, NULL, colorkey );
982 * Lock source surface
984 SDL_LockSurface(rz_src);
986 * Check which kind of surface we have
988 if (is32bit) {
990 * Call the 32bit transformation routine to do the rotation (using alpha)
992 transformSurfaceRGBA(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
993 (int) (sanglezoominv), (int) (canglezoominv),
994 flipx, flipy,
995 smooth);
997 * Turn on source-alpha support
999 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1000 } else {
1002 * Copy palette and colorkey info
1004 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1005 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1007 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1009 * Call the 8bit transformation routine to do the rotation
1011 transformSurfaceY(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
1012 (int) (sanglezoominv), (int) (canglezoominv));
1013 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
1016 * Unlock source surface
1018 SDL_UnlockSurface(rz_src);
1020 } else {
1023 * Angle=0: Just a zoom
1026 * --------------------
1030 * Calculate target size
1032 zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
1035 * Alloc space to completely contain the zoomed surface
1037 rz_dst = NULL;
1038 if (is32bit) {
1040 * Target surface is 32bit with source RGBA/ABGR ordering
1042 rz_dst =
1043 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
1044 rz_src->format->Rmask, rz_src->format->Gmask,
1045 rz_src->format->Bmask, rz_src->format->Amask);
1046 } else {
1048 * Target surface is 8bit
1050 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
1053 if (colorKeyAvailable == 1){
1054 colorkey = SDL_MapRGB(rz_dst->format, r, g, b);
1056 SDL_FillRect(rz_dst, NULL, colorkey );
1060 * Lock source surface
1062 SDL_LockSurface(rz_src);
1064 * Check which kind of surface we have
1066 if (is32bit) {
1068 * Call the 32bit transformation routine to do the zooming (using alpha)
1070 zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
1072 * Turn on source-alpha support
1074 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1075 } else {
1077 * Copy palette and colorkey info
1079 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1080 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1082 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1084 * Call the 8bit transformation routine to do the zooming
1086 zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
1087 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
1090 * Unlock source surface
1092 SDL_UnlockSurface(rz_src);
1096 * Cleanup temp surface
1098 if (src_converted) {
1099 SDL_FreeSurface(rz_src);
1103 * Return destination surface
1105 return (rz_dst);
1110 zoomSurface()
1112 Zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
1113 'zoomx' and 'zoomy' are scaling factors for width and height. If 'smooth' is 1
1114 then the destination 32bit surface is anti-aliased. If the surface is not 8bit
1115 or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
1119 #define VALUE_LIMIT 0.001
1121 void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight)
1124 * Sanity check zoom factors
1126 if (zoomx < VALUE_LIMIT) {
1127 zoomx = VALUE_LIMIT;
1129 if (zoomy < VALUE_LIMIT) {
1130 zoomy = VALUE_LIMIT;
1134 * Calculate target size
1136 *dstwidth = (int) ((double) width * zoomx);
1137 *dstheight = (int) ((double) height * zoomy);
1138 if (*dstwidth < 1) {
1139 *dstwidth = 1;
1141 if (*dstheight < 1) {
1142 *dstheight = 1;
1146 SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth)
1148 SDL_Surface *rz_src;
1149 SDL_Surface *rz_dst;
1150 int dstwidth, dstheight;
1151 int is32bit;
1152 int i, src_converted;
1153 int flipx, flipy;
1156 * Sanity check
1158 if (src == NULL)
1159 return (NULL);
1162 * Determine if source surface is 32bit or 8bit
1164 is32bit = (src->format->BitsPerPixel == 32);
1165 if ((is32bit) || (src->format->BitsPerPixel == 8)) {
1167 * Use source surface 'as is'
1169 rz_src = src;
1170 src_converted = 0;
1171 } else {
1173 * New source surface is 32bit with a defined RGBA ordering
1175 rz_src =
1176 SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1177 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
1178 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
1179 #else
1180 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
1181 #endif
1183 SDL_BlitSurface(src, NULL, rz_src, NULL);
1184 src_converted = 1;
1185 is32bit = 1;
1188 flipx = (zoomx<0);
1189 if (flipx) zoomx = -zoomx;
1190 flipy = (zoomy<0);
1191 if (flipy) zoomy = -zoomy;
1193 /* Get size if target */
1194 zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
1197 * Alloc space to completely contain the zoomed surface
1199 rz_dst = NULL;
1200 if (is32bit) {
1202 * Target surface is 32bit with source RGBA/ABGR ordering
1204 rz_dst =
1205 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
1206 rz_src->format->Rmask, rz_src->format->Gmask,
1207 rz_src->format->Bmask, rz_src->format->Amask);
1208 } else {
1210 * Target surface is 8bit
1212 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
1216 * Lock source surface
1218 SDL_LockSurface(rz_src);
1220 * Check which kind of surface we have
1222 if (is32bit) {
1224 * Call the 32bit transformation routine to do the zooming (using alpha)
1226 zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
1228 * Turn on source-alpha support
1230 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1231 } else {
1233 * Copy palette and colorkey info
1235 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1236 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1238 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1240 * Call the 8bit transformation routine to do the zooming
1242 zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
1243 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
1246 * Unlock source surface
1248 SDL_UnlockSurface(rz_src);
1251 * Cleanup temp surface
1253 if (src_converted) {
1254 SDL_FreeSurface(rz_src);
1258 * Return destination surface
1260 return (rz_dst);
1263 SDL_Surface *shrinkSurface(SDL_Surface * src, int factorx, int factory)
1265 SDL_Surface *rz_src;
1266 SDL_Surface *rz_dst;
1267 int dstwidth, dstheight;
1268 int is32bit;
1269 int i, src_converted;
1272 * Sanity check
1274 if (src == NULL)
1275 return (NULL);
1278 * Determine if source surface is 32bit or 8bit
1280 is32bit = (src->format->BitsPerPixel == 32);
1281 if ((is32bit) || (src->format->BitsPerPixel == 8)) {
1283 * Use source surface 'as is'
1285 rz_src = src;
1286 src_converted = 0;
1287 } else {
1289 * New source surface is 32bit with a defined RGBA ordering
1291 rz_src =
1292 SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
1293 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
1294 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
1295 #else
1296 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
1297 #endif
1299 SDL_BlitSurface(src, NULL, rz_src, NULL);
1300 src_converted = 1;
1301 is32bit = 1;
1304 /* Get size for target */
1305 dstwidth=rz_src->w/factorx;
1306 while (dstwidth*factorx>rz_src->w) { dstwidth--; }
1307 dstheight=rz_src->h/factory;
1308 while (dstheight*factory>rz_src->h) { dstheight--; }
1311 * Alloc space to completely contain the shrunken surface
1313 rz_dst = NULL;
1314 if (is32bit) {
1316 * Target surface is 32bit with source RGBA/ABGR ordering
1318 rz_dst =
1319 SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
1320 rz_src->format->Rmask, rz_src->format->Gmask,
1321 rz_src->format->Bmask, rz_src->format->Amask);
1322 } else {
1324 * Target surface is 8bit
1326 rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
1330 * Lock source surface
1332 SDL_LockSurface(rz_src);
1334 * Check which kind of surface we have
1336 if (is32bit) {
1338 * Call the 32bit transformation routine to do the shrinking (using alpha)
1340 shrinkSurfaceRGBA(rz_src, rz_dst, factorx, factory);
1342 * Turn on source-alpha support
1344 SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
1345 } else {
1347 * Copy palette and colorkey info
1349 for (i = 0; i < rz_src->format->palette->ncolors; i++) {
1350 rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
1352 rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
1354 * Call the 8bit transformation routine to do the shrinking
1356 shrinkSurfaceY(rz_src, rz_dst, factorx, factory);
1357 SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
1360 * Unlock source surface
1362 SDL_UnlockSurface(rz_src);
1365 * Cleanup temp surface
1367 if (src_converted) {
1368 SDL_FreeSurface(rz_src);
1372 * Return destination surface
1374 return (rz_dst);