/*
SDL_rotozoom.c - rotozoomer for 32bit or 8bit surfaces
LGPL (c) A. Schiffler
*/
#ifdef WIN32
#include <windows.h>
#endif
#include <stdlib.h>
#include <string.h>
#include "SDL_rotozoom.h"
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
/*
32bit integer-factor averaging Shrinker
Shrinks 32bit RGBA/ABGR 'src' surface to 'dst' surface.
*/
int shrinkSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
{
int x, y, dx, dy, sgap, dgap, ra, ga, ba, aa;
int n_average;
tColorRGBA *sp, *osp, *oosp;
tColorRGBA *dp;
/*
* Averaging integer shrink
*/
/* Precalculate division factor */
n_average = factorx*factory;
/*
* Scan destination
*/
sp = (tColorRGBA *) src->pixels;
sgap = src->pitch - src->w * 4;
dp = (tColorRGBA *) dst->pixels;
dgap = dst->pitch - dst->w * 4;
for (y = 0; y < dst->h; y++) {
osp=sp;
for (x = 0; x < dst->w; x++) {
/* Trace out source box and accumulate */
oosp=sp;
ra=ga=ba=aa=0;
for (dy=0; dy < factory; dy++) {
for (dx=0; dx < factorx; dx++) {
ra += sp->r;
ga += sp->g;
ba += sp->b;
aa += sp->a;
sp++;
} // src dx loop
sp = (tColorRGBA *)((Uint8*)sp + (src->pitch - 4*factorx)); // next y
} // src dy loop
// next box-x
sp = (tColorRGBA *)((Uint8*)oosp + 4*factorx);
/* Store result in destination */
dp->r = ra/n_average;
dp->g = ga/n_average;
dp->b = ba/n_average;
dp->a = aa/n_average;
/*
* Advance destination pointer
*/
dp++;
} // dst x loop
// next box-y
sp = (tColorRGBA *)((Uint8*)osp + src->pitch*factory);
/*
* Advance destination pointers
*/
dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
} // dst y loop
return (0);
}
/*
8bit integer-factor averaging Shrinker
Shrinks 8bit Y 'src' surface to 'dst' surface.
*/
int shrinkSurfaceY(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
{
int x, y, dx, dy, sgap, dgap, a;
int n_average;
Uint8 *sp, *osp, *oosp;
Uint8 *dp;
/*
* Averaging integer shrink
*/
/* Precalculate division factor */
n_average = factorx*factory;
/*
* Scan destination
*/
sp = (Uint8 *) src->pixels;
sgap = src->pitch - src->w;
dp = (Uint8 *) dst->pixels;
dgap = dst->pitch - dst->w;
for (y = 0; y < dst->h; y++) {
osp=sp;
for (x = 0; x < dst->w; x++) {
/* Trace out source box and accumulate */
oosp=sp;
a=0;
for (dy=0; dy < factory; dy++) {
for (dx=0; dx < factorx; dx++) {
a += (*sp);
sp++; // next x
} // src dx loop
sp = (Uint8 *)((Uint8*)sp + (src->pitch - factorx)); // next y
} // src dy loop
// next box-x
sp = (Uint8 *)((Uint8*)oosp + factorx);
/* Store result in destination */
*dp = a/n_average;
/*
* Advance destination pointer
*/
dp++;
} // dst x loop
// next box-y
sp = (Uint8 *)((Uint8*)osp + src->pitch*factory);
/*
* Advance destination pointers
*/
dp = (Uint8 *)((Uint8 *)dp + dgap);
} // dst y loop
return (0);
}
/*
32bit Zoomer with optional anti-aliasing by bilinear interpolation.
Zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
*/
int zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy, int smooth)
{
int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy, ex, ey, t1, t2, sstep;
tColorRGBA *c00, *c01, *c10, *c11;
tColorRGBA *sp, *csp, *dp;
int dgap;
/*
* Variable setup
*/
if (smooth) {
/*
* For interpolation: assume source dimension is one pixel
*/
/*
* smaller to avoid overflow on right and bottom edge.
*/
sx = (int) (65536.0 * (float) (src->w - 1) / (float) dst->w);
sy = (int) (65536.0 * (float) (src->h - 1) / (float) dst->h);
} else {
sx = (int) (65536.0 * (float) src->w / (float) dst->w);
sy = (int) (65536.0 * (float) src->h / (float) dst->h);
}
/*
* Allocate memory for row increments
*/
if ((sax = (int *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
return (-1);
}
if ((say = (int *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
free(sax);
return (-1);
}
/*
* Precalculate row increments
*/
sp = csp = (tColorRGBA *) src->pixels;
dp = (tColorRGBA *) dst->pixels;
if (flipx) csp += (src->w-1);
if (flipy) csp = (tColorRGBA*)( (Uint8*)csp + src->pitch*(src->h-1) );
csx = 0;
csax = sax;
for (x = 0; x <= dst->w; x++) {
*csax = csx;
csax++;
csx &= 0xffff;
csx += sx;
}
csy = 0;
csay = say;
for (y = 0; y <= dst->h; y++) {
*csay = csy;
csay++;
csy &= 0xffff;
csy += sy;
}
dgap = dst->pitch - dst->w * 4;
/*
* Switch between interpolating and non-interpolating code
*/
if (smooth) {
/*
* Interpolating Zoom
*/
/*
* Scan destination
*/
csay = say;
for (y = 0; y < dst->h; y++) {
/*
* Setup color source pointers
*/
c00 = csp;
c01 = csp;
c01++;
c10 = (tColorRGBA *) ((Uint8 *) csp + src->pitch);
c11 = c10;
c11++;
csax = sax;
for (x = 0; x < dst->w; x++) {
/*
* Interpolate colors
*/
ex = (*csax & 0xffff);
ey = (*csay & 0xffff);
t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
dp->r = (((t2 - t1) * ey) >> 16) + t1;
t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff;
t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff;
dp->g = (((t2 - t1) * ey) >> 16) + t1;
t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff;
t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff;
dp->b = (((t2 - t1) * ey) >> 16) + t1;
t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff;
t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff;
dp->a = (((t2 - t1) * ey) >> 16) + t1;
/*
* Advance source pointers
*/
csax++;
sstep = (*csax >> 16);
c00 += sstep;
c01 += sstep;
c10 += sstep;
c11 += sstep;
/*
* Advance destination pointer
*/
dp++;
}
/*
* Advance source pointer
*/
csay++;
csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
/*
* Advance destination pointers
*/
dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
}
} else {
/*
* Non-Interpolating Zoom
*/
csay = say;
for (y = 0; y < dst->h; y++) {
sp = csp;
csax = sax;
for (x = 0; x < dst->w; x++) {
/*
* Draw
*/
*dp = *sp;
/*
* Advance source pointers
*/
csax++;
sstep = (*csax >> 16);
if (flipx) sstep = -sstep;
sp += sstep;
/*
* Advance destination pointer
*/
dp++;
}
/*
* Advance source pointer
*/
csay++;
sstep = (*csay >> 16) * src->pitch;
if (flipy) sstep = -sstep;
csp = (tColorRGBA *) ((Uint8 *) csp + sstep);
/*
* Advance destination pointers
*/
dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
}
}
/*
* Remove temp arrays
*/
free(sax);
free(say);
return (0);
}
/*
8bit Zoomer without smoothing.
Zoomes 8bit palette/Y 'src' surface to 'dst' surface.
*/
int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy)
{
Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
Uint8 *sp, *dp, *csp;
int dgap;
/*
* Variable setup
*/
sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
sy = (Uint32) (65536.0 * (float) src->h / (float) dst-