fix scaling up in zoomSurface: calculate source pixels and weights differently
fix scaling > 2:1 in the same way as < 1:2 do lrintf(x), not int(x+0.5f)
This commit is contained in:
@@ -157,8 +157,6 @@ void RageBitmapTexture::Create()
|
|||||||
|
|
||||||
if( img->w != m_iImageWidth || img->h != m_iImageHeight )
|
if( img->w != m_iImageWidth || img->h != m_iImageHeight )
|
||||||
{
|
{
|
||||||
/* resize currently only does RGBA8888 */
|
|
||||||
RageSurfaceUtils::ConvertSurface(img, img->w, img->h, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
|
|
||||||
zoomSurface(img, m_iImageWidth, m_iImageHeight );
|
zoomSurface(img, m_iImageWidth, m_iImageHeight );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "SDL_rotozoom.h"
|
#include "SDL_rotozoom.h"
|
||||||
#include "RageSurface.h"
|
#include "RageSurface.h"
|
||||||
|
#include "RageSurfaceUtils.h"
|
||||||
#include "RageUtil.h"
|
#include "RageUtil.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -14,27 +15,20 @@ using namespace std;
|
|||||||
* lines.)
|
* lines.)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void ZoomSurface( RageSurface * src, RageSurface * dst )
|
static void InitVectors( vector<int> &s0, vector<int> &s1, vector<float> &percent, int src, int dst )
|
||||||
{
|
{
|
||||||
/* Ratio from source to dest. */
|
if( src >= dst )
|
||||||
const float sx = float(src->w) / dst->w;
|
{
|
||||||
const float sy = float(src->h) / dst->h;
|
float sx = float(src) / dst;
|
||||||
|
printf("sx %f\n", sx);
|
||||||
/* For each destination coordinate, two source rows, two source columns
|
for( int x = 0; x < dst; x++ )
|
||||||
* and the percentage of the first row and first column: */
|
{
|
||||||
vector<int> esx0, esx1, esy0, esy1;
|
/* sax is the exact (floating-point) x coordinate in the source
|
||||||
vector<float> ex0, ey0;
|
|
||||||
|
|
||||||
int x, y;
|
|
||||||
|
|
||||||
/* 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
|
* 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
|
* 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
|
* 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. */
|
* distance from the start of the sample to its center. */
|
||||||
for( x = 0; x < dst->w; x++ )
|
const float sax = sx*x + sx/2;
|
||||||
{
|
|
||||||
float sax = sx*x + sx/2;
|
|
||||||
|
|
||||||
/* sx/2 is the distance from the start of the sample to the center;
|
/* 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
|
* sx/4 is the distance from the center of the sample to the center of
|
||||||
@@ -42,64 +36,84 @@ static void ZoomSurface( RageSurface * src, RageSurface * dst )
|
|||||||
const float xstep = sx/4;
|
const float xstep = sx/4;
|
||||||
|
|
||||||
/* source x coordinates of left and right pixels to sample */
|
/* source x coordinates of left and right pixels to sample */
|
||||||
esx0.push_back(int(sax-xstep));
|
s0.push_back(int(sax-xstep));
|
||||||
esx1.push_back(int(sax+xstep));
|
s1.push_back(int(sax+xstep));
|
||||||
|
|
||||||
if( esx1[x] == esx0[x] )
|
if( s0[x] == s1[x] )
|
||||||
{
|
{
|
||||||
/* If the sampled pixels happen to be the same, the distance
|
/* If the sampled pixels happen to be the same, the distance
|
||||||
* will be 0. Avoid division by zero. */
|
* will be 0. Avoid division by zero. */
|
||||||
ex0.push_back( 1.f );
|
percent.push_back( 1.f );
|
||||||
} else {
|
} else {
|
||||||
const int xdist = esx1[x] - esx0[x];
|
const int xdist = s1[x] - s0[x];
|
||||||
|
|
||||||
/* fleft is the left pixel sampled; +.5 is the center: */
|
/* fleft is the left pixel sampled; +.5 is the center: */
|
||||||
const float fleft = esx0[x] + .5f;
|
const float fleft = s0[x] + .5f;
|
||||||
|
|
||||||
/* sax is somewhere between the centers of both sampled
|
/* sax is somewhere between the centers of both sampled
|
||||||
* pixels; find the percentage: */
|
* pixels; find the percentage: */
|
||||||
const float p = (sax - fleft) / xdist;
|
const float p = (sax - fleft) / xdist;
|
||||||
ex0.push_back(1-p);
|
percent.push_back(1-p);
|
||||||
|
printf("p %.3f\n", p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
for( y = 0; y < dst->h; y++ )
|
else
|
||||||
{
|
{
|
||||||
float say = sy*y + sy/2;
|
/*
|
||||||
|
* Fencepost: If we have source:
|
||||||
float ystep = sy/4;
|
* abcd
|
||||||
|
* and dest:
|
||||||
esy0.push_back( int(say-ystep) );
|
* xyz
|
||||||
esy1.push_back( int(say+ystep) );
|
* then we want x to be sampled entirely from a, and z entirely from d;
|
||||||
|
* the inner pixels are interpolated. (This behavior mimics Photoshop's
|
||||||
if( esy0[y] == esy1[y] )
|
* resize.)
|
||||||
|
*/
|
||||||
|
float sx = float(src-1) / (dst-1);
|
||||||
|
printf("sx %f\n", sx);
|
||||||
|
for( int x = 0; x < dst; x++ )
|
||||||
{
|
{
|
||||||
ey0.push_back( 1.f );
|
const float sax = sx*x;
|
||||||
} else {
|
|
||||||
const int ydist = esy1[y] - esy0[y];
|
|
||||||
const float ftop = esy0[y] + .5f;
|
|
||||||
const float p = (say - ftop) / ydist;
|
|
||||||
ey0.push_back( 1-p );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* source x coordinates of left and right pixels to sample */
|
||||||
|
s0.push_back( clamp(int(sax), 0, src-1));
|
||||||
|
s1.push_back( clamp(int(sax+1), 0, src-1) );
|
||||||
|
printf("sax: %.3f, esx0 %i, esx1 %i\n", sax, s0.back(), s1.back());
|
||||||
|
|
||||||
|
const float p = 1 - (sax - floorf(sax));
|
||||||
|
percent.push_back( p );
|
||||||
|
printf("p %.3f\n", p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ZoomSurface( const RageSurface * src, RageSurface * dst )
|
||||||
|
{
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
InitVectors( esx0, esx1, ex0, src->w, dst->w );
|
||||||
|
InitVectors( esy0, esy1, ey0, src->h, dst->h );
|
||||||
|
|
||||||
|
/* This is where all of the real work is done. */
|
||||||
const uint8_t *sp = (uint8_t *) src->pixels;
|
const uint8_t *sp = (uint8_t *) src->pixels;
|
||||||
|
for( int y = 0; y < dst->h; y++ )
|
||||||
for( y = 0; y < dst->h; y++ )
|
|
||||||
{
|
{
|
||||||
uint8_t *dp = ((uint8_t *) dst->pixels + dst->pitch*y);
|
uint32_t *dp = (uint32_t *) (dst->pixels + dst->pitch*y);
|
||||||
/* current source pointer and next source pointer (first and second
|
/* current source pointer and next source pointer (first and second
|
||||||
* rows sampled for this row): */
|
* rows sampled for this row): */
|
||||||
const uint8_t *csp = (uint8_t *) (sp + esy0[y] * src->pitch);
|
const uint8_t *csp = sp + esy0[y] * src->pitch;
|
||||||
const uint8_t *ncsp = (uint8_t *) (sp + esy1[y] * src->pitch);
|
const uint8_t *ncsp = sp + esy1[y] * src->pitch;
|
||||||
|
|
||||||
for( x = 0; x < dst->w; x++ )
|
for( int x = 0; x < dst->w; x++ )
|
||||||
{
|
{
|
||||||
/* Grab pointers to the sampled pixels: */
|
/* Grab pointers to the sampled pixels: */
|
||||||
const uint8_t *c00 = (uint8_t *) (csp + esx0[x]*4);
|
const uint8_t *c00 = csp + esx0[x]*4;
|
||||||
const uint8_t *c01 = (uint8_t *) (csp + esx1[x]*4);
|
const uint8_t *c01 = csp + esx1[x]*4;
|
||||||
const uint8_t *c10 = (uint8_t *) (ncsp + esx0[x]*4);
|
const uint8_t *c10 = ncsp + esx0[x]*4;
|
||||||
const uint8_t *c11 = (uint8_t *) (ncsp + esx1[x]*4);
|
const uint8_t *c11 = ncsp + esx1[x]*4;
|
||||||
|
|
||||||
uint8_t color[4];
|
uint8_t color[4];
|
||||||
for( int c = 0; c < 4; ++c )
|
for( int c = 0; c < 4; ++c )
|
||||||
@@ -113,10 +127,10 @@ static void ZoomSurface( RageSurface * src, RageSurface * dst )
|
|||||||
const float res = (x0 * ey0[y]) + (x1 * (1-ey0[y]));
|
const float res = (x0 * ey0[y]) + (x1 * (1-ey0[y]));
|
||||||
color[c] = uint8_t(res);
|
color[c] = uint8_t(res);
|
||||||
}
|
}
|
||||||
*(uint32_t *) dp = *(uint32_t *) color;
|
*dp = *(uint32_t *) color;
|
||||||
|
|
||||||
/* Advance destination pointer. */
|
/* Advance destination pointer. */
|
||||||
dp += 4;
|
++dp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,19 +141,26 @@ void zoomSurface( RageSurface *&src, int dstwidth, int dstheight )
|
|||||||
if( src == NULL )
|
if( src == NULL )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* resize currently only does RGBA8888 */
|
||||||
|
if( src->fmt.BytesPerPixel != 4 )
|
||||||
|
{
|
||||||
|
RageSurfaceUtils::ConvertSurface( src, src->w, src->h, 32,
|
||||||
|
0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
|
||||||
|
}
|
||||||
|
|
||||||
while( src->w != dstwidth || src->h != dstheight )
|
while( src->w != dstwidth || src->h != dstheight )
|
||||||
{
|
{
|
||||||
float xscale = float(dstwidth)/src->w;
|
float xscale = float(dstwidth)/src->w;
|
||||||
float yscale = float(dstheight)/src->h;
|
float yscale = float(dstheight)/src->h;
|
||||||
|
|
||||||
/* Our filter is a simple linear filter, so it can't scale to
|
/* Our filter is a simple linear filter, so it can't scale to less than
|
||||||
* less than .5 very well. If we need to go lower than .5, do
|
* 1:2 or more than 2:1 very well. If we need to go beyond that, do it
|
||||||
* it iteratively. */
|
* iteratively. */
|
||||||
xscale = max( xscale, .5f );
|
xscale = clamp( xscale, .5f, 2.0f );
|
||||||
yscale = max( yscale, .5f );
|
yscale = clamp( yscale, .5f, 2.0f );
|
||||||
|
|
||||||
int target_width = int(src->w*xscale + .5);
|
int target_width = lrintf( src->w*xscale );
|
||||||
int target_height = int(src->h*yscale + .5);
|
int target_height = lrintf( src->h*yscale );
|
||||||
|
|
||||||
RageSurface *dst =
|
RageSurface *dst =
|
||||||
CreateSurface(target_width, target_height, 32,
|
CreateSurface(target_width, target_height, 32,
|
||||||
|
|||||||
Reference in New Issue
Block a user