Change the Pandora code to all integers.

The code no longer uses the floating point emulation. The output still
differs slightly from the original algorithm, but that might also be
floating point rounding issues in the original algorithm.

Note I still want to try some other things as well, therefore no comment
yet.
This commit is contained in:
Mark de Wever 2012-03-15 20:33:01 +00:00
parent fcc5e09153
commit 3f9ce95fd2

View file

@ -313,7 +313,7 @@ surface stretch_surface_vertical(
#ifdef PANDORA
static void
scale_surface_down(surface& dst, const surface& src, const int w, const int h)
scale_surface_down(surface& dst, const surface& src, const int w_dst, const int h_dst)
{
const_surface_lock src_lock(src);
surface_lock dst_lock(dst);
@ -321,54 +321,81 @@ scale_surface_down(surface& dst, const surface& src, const int w, const int h)
const Uint32* const src_pixels = src_lock.pixels();
Uint32* const dst_pixels = dst_lock.pixels();
tfloat xratio = tfloat(src->w) / w;
tfloat yratio = tfloat(src->h) / h;
int y_dst = 0; // The current y in the destination surface
tfloat ysrc;
for(int ydst = 0; ydst != h; ++ydst, ysrc += yratio) {
tfloat xsrc;
for(int xdst = 0; xdst != w; ++xdst, xsrc += xratio) {
tfloat red, green, blue, alpha;
int y_src = 0; // The current y in the source surface
int y_src_next = 0; // The next y in the source surface
int y_step = 0; // The y stepper
int h_src = src->h; // The height of the source surface
tfloat summation;
for( ; y_dst != h_dst; ++y_dst, y_src = y_src_next) {
y_step += h_src;
do {
++y_src_next;
y_step -= h_dst;
} while(y_step >= h_dst);
int x_dst = 0; // The current x in the destination surface
int x_src = 0; // The current x in the source surface
int x_src_next = 0; // The next x in the source surface
int x_step = 0; // The x stepper
int w_src = src->w; // The width of the source surface
for( ; x_dst != w_dst; ++x_dst, x_src = x_src_next) {
x_step += w_src;
do {
++x_src_next;
x_step -= w_dst;
} while(x_step >= w_dst);
int r_sum = 0, g_sum = 0, b_sum = 0, a_sum = 0;
int samples = 0;
// We now have a rectangle, (xsrc,ysrc,xratio,yratio)
// which we want to derive the pixel from
for(tfloat xloc = xsrc; xloc < xsrc+xratio; xloc += 1) {
const tfloat xsize = std::min<tfloat>(floor(xloc + 1)-xloc,xsrc+xratio-xloc);
for(tfloat yloc = ysrc; yloc < ysrc+yratio; yloc += 1) {
const int xsrcint = std::max<int>(0,std::min<int>(src->w-1,xsrc.to_int()));
const int ysrcint = std::max<int>(0,std::min<int>(src->h-1,ysrc.to_int()));
for(int x = x_src; x < x_src_next; ++x) {
for(int y = y_src; y < y_src_next; ++y) {
const tfloat ysize = std::min<tfloat>(floor(yloc+1)-yloc,ysrc+yratio-yloc);
++samples;
Uint8 r,g,b,a;
SDL_GetRGBA(src_pixels[ysrcint*src->w + xsrcint],src->format,&r,&g,&b,&a);
tfloat value = xsize * ysize;
summation += value;
if (!a) continue;
value *= a;
alpha += value;
red += r * value;
green += g * value;
blue += b * value;
SDL_GetRGBA(src_pixels[y_src * w_src + x_src], src->format, &r, &g, &b, &a);
if(a) {
a_sum += a;
r_sum += r * a;
g_sum += g * a;
b_sum += b * a;
}
}
}
if (alpha != 0) {
red = red / alpha + 0.5;
green = green / alpha + 0.5;
blue = blue / alpha + 0.5;
alpha = alpha / summation + 0.5;
if(a_sum) {
const int adjustment = (a_sum + (a_sum > 1)) >> 1;
r_sum += adjustment;
g_sum += adjustment;
b_sum += adjustment;
r_sum /= a_sum;
g_sum /= a_sum;
b_sum /= a_sum;
assert(samples == (x_src_next - x_src) * (y_src_next - y_src));
if(samples != 1) {
a_sum += (samples + 1) >> 1;
a_sum /= samples;
}
}
dst_pixels[ydst*dst->w + xdst] = SDL_MapRGBA(
dst_pixels[y_dst * w_dst + x_dst] = SDL_MapRGBA(
dst->format
, red.to_int()
, green.to_int()
, blue.to_int()
, alpha.to_int());
, r_sum
, g_sum
, b_sum
, a_sum);
}
}
}