Arg. This is ugly and slow, but at least it's a real linear filter.
Handle extreme resizing iteratively, which gives us something like a triangle filter--slower and probably not quite as good, but much better than it was.
This commit is contained in:
@@ -183,8 +183,8 @@ void RageBitmapTexture::Create(
|
|||||||
/* Don't use more than we were hinted to. */
|
/* Don't use more than we were hinted to. */
|
||||||
src_alpha_bits = min( iAlphaBits, src_alpha_bits );
|
src_alpha_bits = min( iAlphaBits, src_alpha_bits );
|
||||||
|
|
||||||
/* XXX Scan the image, and see if it actually uses its alpha channel/color key
|
/* XXX Scan the image, and see if it actually uses its alpha channel/color key
|
||||||
* (if any). Reduce to 1 or 0 bits of alpha if possible. */
|
* (if any). Reduce to 1 or 0 bits of alpha if possible. */
|
||||||
|
|
||||||
switch( src_alpha_bits ) {
|
switch( src_alpha_bits ) {
|
||||||
case 0: fmtTexture = D3DFMT_R5G6B5; break;
|
case 0: fmtTexture = D3DFMT_R5G6B5; break;
|
||||||
@@ -250,25 +250,36 @@ void RageBitmapTexture::Create(
|
|||||||
|
|
||||||
if( bStretch ) {
|
if( bStretch ) {
|
||||||
/* zoomSurface takes a ratio. I'm not sure if it's always exact; we don't
|
/* zoomSurface takes a ratio. I'm not sure if it's always exact; we don't
|
||||||
* want to accidentally create a 513x513 texture, for example (it won't just
|
* want to accidentally create a 513x513 texture, for example (it won't just
|
||||||
* cause lines; it'll be copied to the texture completely wrong). */
|
* cause lines; it'll be copied to the texture completely wrong). */
|
||||||
|
|
||||||
/* resize currently only does RGBA8888 */
|
/* resize currently only does RGBA8888 */
|
||||||
if(img->format->BitsPerPixel != 32 || img->format->colorkey) {
|
{
|
||||||
int mask = 0;
|
int mask = 0;
|
||||||
ConvertSDLSurface(img, img->w, img->h, PixFmtMasks[mask][4],
|
ConvertSDLSurface(img, img->w, img->h, PixFmtMasks[mask][4],
|
||||||
PixFmtMasks[mask][0], PixFmtMasks[mask][1], PixFmtMasks[mask][2], PixFmtMasks[mask][3]);
|
PixFmtMasks[mask][0], PixFmtMasks[mask][1], PixFmtMasks[mask][2], PixFmtMasks[mask][3]);
|
||||||
}
|
}
|
||||||
SDL_Surface *dst;
|
|
||||||
dst = zoomSurface(img, float(m_iTextureWidth)/m_iImageWidth,
|
|
||||||
float(m_iTextureHeight) / m_iImageHeight, SMOOTHING_ON);
|
|
||||||
|
|
||||||
SDL_FreeSurface(img);
|
while (m_iImageWidth != m_iTextureWidth || m_iImageHeight != m_iTextureHeight) {
|
||||||
img = dst;
|
SDL_Surface *dst;
|
||||||
|
|
||||||
/* The new image size is the full texture size. */
|
float xscale = float(m_iTextureWidth)/m_iImageWidth;
|
||||||
m_iImageWidth = m_iTextureWidth;
|
float yscale = float(m_iTextureHeight)/m_iImageHeight;
|
||||||
m_iImageHeight = m_iTextureHeight;
|
/* Our simple filter is a simple linear filter, so it can't
|
||||||
|
* scale to less than .5 very well. If we need to go lower
|
||||||
|
* than .5, do it iteratively. */
|
||||||
|
xscale = max(xscale, .5f);
|
||||||
|
yscale = max(yscale, .5f);
|
||||||
|
|
||||||
|
dst = zoomSurface(img, xscale, yscale);
|
||||||
|
|
||||||
|
SDL_FreeSurface(img);
|
||||||
|
img = dst;
|
||||||
|
|
||||||
|
/* The new image size is the full texture size. */
|
||||||
|
m_iImageWidth = int(m_iImageWidth * xscale + .0001);
|
||||||
|
m_iImageHeight = int(m_iImageHeight * yscale + .0001);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( bDither )
|
if( bDither )
|
||||||
|
|||||||
+94
-116
@@ -13,15 +13,12 @@
|
|||||||
|
|
||||||
#include "SDL_rotozoom.h"
|
#include "SDL_rotozoom.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
struct tColorRGBA {
|
struct tColorRGBA {
|
||||||
Uint8 r,g,b,a;
|
Uint8 c[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
32bit Zoomer with optional anti-aliasing by bilinear interpolation.
|
32bit Zoomer with optional anti-aliasing by bilinear interpolation.
|
||||||
@@ -29,133 +26,114 @@ struct tColorRGBA {
|
|||||||
Zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
|
Zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
/* Coordinate 0x0 represents the exact top-left corner of a bitmap. .5x.5
|
||||||
|
* represents the center of the top-left pixel; 1x1 is the center of the top
|
||||||
|
* square of pixels.
|
||||||
|
*
|
||||||
|
* (Look at a grid: map coordinates to the lines, not the squares between the
|
||||||
|
* lines.)
|
||||||
|
*/
|
||||||
|
|
||||||
int zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int smooth)
|
float frac(float x) { return x-int(x); }
|
||||||
|
int zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst)
|
||||||
{
|
{
|
||||||
int x, y, sx, sy, *sax, *say;
|
/* Ratio from source to dest. */
|
||||||
|
float sx = float(src->w) / dst->w;
|
||||||
|
float sy = float(src->h) / dst->h;
|
||||||
|
|
||||||
/* Variable setup */
|
float *sax = new float[dst->w];
|
||||||
// if (smooth) {
|
float *say = new float[dst->h];
|
||||||
/* For interpolation: assume source dimension is one pixel */
|
|
||||||
/* smaller to avoid overflow on right and bottom edge. */
|
|
||||||
/* XXX: no, this misaligns stuff; we need to clamp properly -glenn */
|
|
||||||
// sx = (int) (65536.0 * (float) (src->w - 1) / (float) dst->w);
|
|
||||||
// sy = (int) (65536.0 * (float) (src->h - 1) / (float) dst->h);
|
|
||||||
// } else {
|
|
||||||
sx = 65536 * src->w / dst->w;
|
|
||||||
sy = 65536 * src->h / 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 */
|
/* Precalculate row increments */
|
||||||
int csx = 0;
|
int x, y;
|
||||||
int *csax = sax;
|
/* sax[x] is the exact (floating-point) x coordinate in the source
|
||||||
for (x = 0; x <= dst->w; x++) {
|
* that the destination pixel at x should from. For example, if we're
|
||||||
*csax = csx;
|
* going 512->256, then dst[0] should come from the pixels from 0..1 and
|
||||||
csx &= 0xffff;
|
* 1..2, so sax[0] is 1. sx is the total number of pixels, so sx/2 is the
|
||||||
csax++;
|
* distance from the start of the sample to its center. */
|
||||||
csx += sx;
|
for (x = 0; x < dst->w; x++)
|
||||||
}
|
sax[x] = sx*x + sx/2;
|
||||||
int csy = 0;
|
|
||||||
int *csay = say;
|
|
||||||
for (y = 0; y <= dst->h; y++) {
|
|
||||||
*csay = csy;
|
|
||||||
csy &= 0xffff;
|
|
||||||
csay++;
|
|
||||||
csy += sy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Pointer setup */
|
for (y = 0; y < dst->h; y++)
|
||||||
tColorRGBA *sp, *csp;
|
say[y] = sy*y + sy/2;
|
||||||
sp = csp = (tColorRGBA *) src->pixels;
|
|
||||||
|
|
||||||
/* Switch between interpolating and non-interpolating code */
|
tColorRGBA *sp = (tColorRGBA *) src->pixels;
|
||||||
csay = say;
|
|
||||||
if (smooth) {
|
|
||||||
/* Interpolating Zoom */
|
|
||||||
|
|
||||||
/* Scan destination */
|
/* Scan destination */
|
||||||
for (y = 0; y < dst->h; y++) {
|
for (y = 0; y < dst->h; y++) {
|
||||||
/* Set up color source pointers */
|
/* Set destination pointer. */
|
||||||
tColorRGBA *c00 = csp;
|
|
||||||
tColorRGBA *c01 = csp+1;
|
|
||||||
tColorRGBA *c10 = (tColorRGBA *) ((Uint8 *) csp + src->pitch);
|
|
||||||
tColorRGBA *c11 = c10+1;
|
|
||||||
csax = sax;
|
|
||||||
/* Set destination pointer. */
|
|
||||||
tColorRGBA *dp = (tColorRGBA *) ((Uint8 *) dst->pixels + dst->pitch*y);
|
|
||||||
|
|
||||||
for (x = 0; x < dst->w; x++) {
|
/* sx/2 is the distance from the start of the sample to the center;
|
||||||
|
* sx/4 is the distance from the center of the sample to the center of
|
||||||
|
* either pixel. */
|
||||||
|
float xstep = sx/4;
|
||||||
|
float ystep = sy/4;
|
||||||
|
|
||||||
/*
|
int ytop = int(say[y]-ystep);
|
||||||
* Interpolate colors
|
int ybottom = int(say[y]+ystep);
|
||||||
*/
|
|
||||||
int ex = *csax & 0xffff;
|
|
||||||
int ey = *csay & 0xffff;
|
|
||||||
int t1, t2;
|
|
||||||
t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
|
|
||||||
t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
|
|
||||||
dp->r = (Uint8)((((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 = (Uint8)((((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 = (Uint8)((((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 = (Uint8)((((t2 - t1) * ey) >> 16) + t1);
|
|
||||||
|
|
||||||
/* Advance source pointers. */
|
tColorRGBA *dp = (tColorRGBA *) ((Uint8 *) dst->pixels + dst->pitch*y);
|
||||||
csax++;
|
tColorRGBA *csp = (tColorRGBA *) ((Uint8 *) sp + ytop * src->pitch);
|
||||||
int sstep = (*csax >> 16);
|
tColorRGBA *ncsp = (tColorRGBA *) ((Uint8 *) sp + ybottom * src->pitch);
|
||||||
c00 += sstep;
|
|
||||||
c01 += sstep;
|
for (x = 0; x < dst->w; x++) {
|
||||||
c10 += sstep;
|
/* x coordinates of left and right pixels to sample */
|
||||||
c11 += sstep;
|
int xleft = int(sax[x]-xstep);
|
||||||
/* Advance destination pointer. */
|
int xright = int(sax[x]+xstep);
|
||||||
dp++;
|
|
||||||
|
/* Grab pointers to the sampled pixels: */
|
||||||
|
tColorRGBA *c00 = csp + xleft;
|
||||||
|
tColorRGBA *c01 = csp + xright;
|
||||||
|
tColorRGBA *c10 = ncsp + xleft;
|
||||||
|
tColorRGBA *c11 = ncsp + xright;
|
||||||
|
|
||||||
|
/* Distance between the pixels that were sampled: */
|
||||||
|
int xdist = xright - xleft;
|
||||||
|
int ydist = ybottom - ytop;
|
||||||
|
|
||||||
|
float ex0, ex1, ey0, ey1;
|
||||||
|
if(xdist == 0) {
|
||||||
|
/* If the sampled pixels happen to be the same, the distance
|
||||||
|
* will be 0. Avoid division by zero. */
|
||||||
|
ex0 = 1.f; ex1 = 0.f;
|
||||||
|
} else {
|
||||||
|
/* fleft is the left pixel sampled; +.5 is the center: */
|
||||||
|
float fleft = xleft + .5f;
|
||||||
|
/* sax[x] is somewhere between the centers of both sampled
|
||||||
|
* pixels; find the percentage: */
|
||||||
|
float p = (sax[x] - fleft) / xdist;
|
||||||
|
ex0 = 1-p;
|
||||||
|
ex1 = 1-ex0;
|
||||||
}
|
}
|
||||||
/* Advance source pointer. */
|
|
||||||
csay++;
|
|
||||||
csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
if(ydist == 0) {
|
||||||
/* Non-Interpolating Zoom */
|
ey0 = 1.f; ey1 = 0.f;
|
||||||
for (y = 0; y < dst->h; y++) {
|
} else {
|
||||||
sp = csp;
|
float ftop = ytop + .5f;
|
||||||
csax = sax;
|
float p = (say[y] - ftop) / ydist;
|
||||||
tColorRGBA *dp = (tColorRGBA *) ((Uint8 *) dst->pixels + dst->pitch*y);
|
ey0 = 1-p;
|
||||||
for (x = 0; x < dst->w; x++) {
|
ey1 = 1-ey0;
|
||||||
/* Draw */
|
|
||||||
*dp = *sp;
|
|
||||||
/* Advance source pointers */
|
|
||||||
csax++;
|
|
||||||
sp += (*csax >> 16);
|
|
||||||
/* Advance destination pointer */
|
|
||||||
dp++;
|
|
||||||
}
|
}
|
||||||
/* Advance source pointer */
|
|
||||||
csay++;
|
|
||||||
csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
for(int c = 0; c < 4; ++c) {
|
||||||
|
float xxx0, xxx1;
|
||||||
|
xxx0 = c01->c[c] * ex1;
|
||||||
|
xxx0 += c00->c[c] * ex0;
|
||||||
|
xxx1 = c11->c[c] * ex1;
|
||||||
|
xxx1 += c10->c[c] * ex0;
|
||||||
|
|
||||||
|
float res = (xxx0 * ey0) + (xxx1 * ey1);
|
||||||
|
dp->c[c] = Uint8(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Advance destination pointer. */
|
||||||
|
dp++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Remove temp arrays */
|
||||||
* Remove temp arrays
|
delete [] sax;
|
||||||
*/
|
delete [] say;
|
||||||
free(sax);
|
|
||||||
free(say);
|
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@@ -193,7 +171,7 @@ void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dst
|
|||||||
if (*dstheight < 1) *dstheight = 1;
|
if (*dstheight < 1) *dstheight = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth)
|
SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy)
|
||||||
{
|
{
|
||||||
SDL_Surface *rz_dst;
|
SDL_Surface *rz_dst;
|
||||||
int dstwidth, dstheight;
|
int dstwidth, dstheight;
|
||||||
@@ -220,7 +198,7 @@ SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smoo
|
|||||||
SDL_LockSurface(src);
|
SDL_LockSurface(src);
|
||||||
|
|
||||||
/* Call the 32bit transformation routine to do the zooming (using alpha) */
|
/* Call the 32bit transformation routine to do the zooming (using alpha) */
|
||||||
zoomSurfaceRGBA(src, rz_dst, smooth);
|
zoomSurfaceRGBA(src, rz_dst);
|
||||||
/* Turn on source-alpha support */
|
/* Turn on source-alpha support */
|
||||||
SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
|
SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
|
||||||
/* Unlock source surface */
|
/* Unlock source surface */
|
||||||
|
|||||||
@@ -11,11 +11,6 @@
|
|||||||
|
|
||||||
#include "SDL.h"
|
#include "SDL.h"
|
||||||
|
|
||||||
/* ---- Defines */
|
|
||||||
|
|
||||||
#define SMOOTHING_OFF 0
|
|
||||||
#define SMOOTHING_ON 1
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
zoomSurface()
|
zoomSurface()
|
||||||
@@ -27,7 +22,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth);
|
SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy);
|
||||||
|
|
||||||
/* Returns the size of the target surface for a zoomSurface() call */
|
/* Returns the size of the target surface for a zoomSurface() call */
|
||||||
void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight);
|
void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight);
|
||||||
|
|||||||
Reference in New Issue
Block a user