Files
itgmania212121/stepmania/src/SDL_rotozoom.cpp
T

160 lines
4.3 KiB
C++
Raw Normal View History

2003-02-16 04:01:45 +00:00
#include "global.h"
/*
2002-10-31 03:55:50 +00:00
* SDL_rotozoom.c - rotozoomer for 32bit or 8bit surfaces
*
* LGPL (c) A. Schiffler, Glenn Maynard
*/
2002-10-29 01:35:39 +00:00
#include "SDL_rotozoom.h"
2002-10-31 01:24:56 +00:00
#include <vector>
using namespace std;
/* 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.)
*/
2004-03-19 22:08:21 +00:00
static void ZoomSurface( SDL_Surface * src, SDL_Surface * dst )
{
/* Ratio from source to dest. */
2004-03-19 23:14:30 +00:00
const float sx = float(src->w) / dst->w;
const float sy = float(src->h) / dst->h;
2002-10-31 01:24:56 +00:00
/* For each destination coordinate, two source rows, two source columns
* and the percentage of the first row and first column: */
vector<int> esx0, esx1, esy0, esy1;
vector<float> ex0, ey0;
int x, y;
2002-10-31 01:24:56 +00:00
/* sax[x] is the exact (floating-point) x coordinate in the source
* that the destination pixel at x should from. For example, if we're
* going 512->256, then dst[0] should come from the pixels from 0..1 and
* 1..2, so sax[0] is 1. sx is the total number of pixels, so sx/2 is the
* distance from the start of the sample to its center. */
2004-03-19 22:08:21 +00:00
for( x = 0; x < dst->w; x++ )
{
const float sax = sx*x + sx/2;
2002-10-31 01:27:45 +00:00
/* sx/2 is the distance from the start of the sample to the center;
2004-03-19 22:08:21 +00:00
* sx/4 is the distance from the center of the sample to the center of
* either pixel. */
const float xstep = sx/4;
2002-10-31 01:24:56 +00:00
2002-10-31 01:27:45 +00:00
/* source x coordinates of left and right pixels to sample */
esx0.push_back(int(sax-xstep));
esx1.push_back(int(sax+xstep));
2002-10-31 01:24:56 +00:00
2004-03-19 22:08:21 +00:00
if( esx1[x] == esx0[x] )
{
2002-10-31 01:27:45 +00:00
/* If the sampled pixels happen to be the same, the distance
2004-03-19 22:08:21 +00:00
* will be 0. Avoid division by zero. */
ex0.push_back( 1.f );
2002-10-31 01:27:45 +00:00
} else {
2004-03-19 22:08:21 +00:00
const int xdist = esx1[x] - esx0[x];
2002-10-31 01:24:56 +00:00
2002-10-31 01:27:45 +00:00
/* fleft is the left pixel sampled; +.5 is the center: */
2004-03-19 22:08:21 +00:00
const float fleft = esx0[x] + .5f;
2002-10-31 01:27:45 +00:00
/* sax is somewhere between the centers of both sampled
2004-03-19 22:08:21 +00:00
* pixels; find the percentage: */
const float p = (sax - fleft) / xdist;
2002-10-31 01:27:45 +00:00
ex0.push_back(1-p);
}
2002-10-31 01:24:56 +00:00
}
2004-03-19 22:08:21 +00:00
for( y = 0; y < dst->h; y++ )
{
2002-10-31 01:27:45 +00:00
float say = sy*y + sy/2;
2002-10-31 01:24:56 +00:00
2002-10-31 01:27:45 +00:00
float ystep = sy/4;
2002-10-31 01:24:56 +00:00
2004-03-19 22:08:21 +00:00
esy0.push_back( int(say-ystep) );
esy1.push_back( int(say+ystep) );
2002-10-31 01:24:56 +00:00
2004-03-19 22:08:21 +00:00
if( esy0[y] == esy1[y] )
{
ey0.push_back( 1.f );
2002-10-31 01:27:45 +00:00
} else {
2004-03-19 22:08:21 +00:00
const int ydist = esy1[y] - esy0[y];
const float ftop = esy0[y] + .5f;
const float p = (say - ftop) / ydist;
ey0.push_back( 1-p );
2002-10-31 01:27:45 +00:00
}
2002-10-31 01:24:56 +00:00
}
2004-03-19 23:14:30 +00:00
const Uint8 *sp = (Uint8 *) src->pixels;
2004-03-19 22:08:21 +00:00
for( y = 0; y < dst->h; y++ )
{
2004-03-19 23:14:30 +00:00
Uint8 *dp = ((Uint8 *) dst->pixels + dst->pitch*y);
2002-10-31 01:27:45 +00:00
/* current source pointer and next source pointer (first and second
2004-03-19 22:08:21 +00:00
* rows sampled for this row): */
2004-03-19 23:14:30 +00:00
const Uint8 *csp = (Uint8 *) (sp + esy0[y] * src->pitch);
const Uint8 *ncsp = (Uint8 *) (sp + esy1[y] * src->pitch);
2004-03-19 22:08:21 +00:00
for( x = 0; x < dst->w; x++ )
{
2002-10-31 01:27:45 +00:00
/* Grab pointers to the sampled pixels: */
2004-03-19 23:14:30 +00:00
const Uint8 *c00 = (Uint8 *) (csp + esx0[x]*4);
const Uint8 *c01 = (Uint8 *) (csp + esx1[x]*4);
const Uint8 *c10 = (Uint8 *) (ncsp + esx0[x]*4);
const Uint8 *c11 = (Uint8 *) (ncsp + esx1[x]*4);
2004-03-19 23:14:30 +00:00
Uint8 color[4];
2004-03-19 22:08:21 +00:00
for( int c = 0; c < 4; ++c )
{
2002-10-31 01:27:45 +00:00
float x0, x1;
2004-03-19 23:14:30 +00:00
x0 = c00[c] * ex0[x];
x0 += c01[c] * (1-ex0[x]);
x1 = c10[c] * ex0[x];
x1 += c11[c] * (1-ex0[x]);
2004-03-19 22:08:21 +00:00
const float res = (x0 * ey0[y]) + (x1 * (1-ey0[y]));
2004-03-19 23:14:30 +00:00
color[c] = Uint8(res);
2002-10-31 01:27:45 +00:00
}
2004-03-19 23:14:30 +00:00
*(Uint32 *) dp = *(Uint32 *) color;
2002-10-31 01:27:45 +00:00
/* Advance destination pointer. */
2004-03-19 23:14:30 +00:00
dp += 4;
2002-10-31 01:27:45 +00:00
}
}
}
2004-03-19 22:08:21 +00:00
void zoomSurface( SDL_Surface *&src, int dstwidth, int dstheight )
{
2004-03-19 22:08:21 +00:00
if( src == NULL )
return;
2004-03-19 22:08:21 +00:00
while( src->w != dstwidth || src->h != dstheight )
{
float xscale = float(dstwidth)/src->w;
float yscale = float(dstheight)/src->h;
/* Our 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. */
2004-03-19 22:08:21 +00:00
xscale = max( xscale, .5f );
yscale = max( yscale, .5f );
int target_width = int(src->w*xscale + .5);
int target_height = int(src->h*yscale + .5);
2004-03-19 23:14:30 +00:00
SDL_Surface *dst =
SDL_CreateRGBSurface(SDL_SWSURFACE, target_width, target_height, 32,
src->format->Rmask, src->format->Gmask,
src->format->Bmask, src->format->Amask);
ZoomSurface( src, dst );
SDL_FreeSurface(src);
src = dst;
}
}