bilinear interpolation of images

This commit is contained in:
Jérémy Rosen 2005-12-18 13:46:19 +00:00
parent f952fc0c1d
commit 2df60619f0
3 changed files with 127 additions and 3 deletions

View file

@ -92,6 +92,8 @@ SVN trunk (1.1.x):
* new villages: snow (human & elven), underground
* updated snow hills and hills
* new mountains
* bilinear interpolation of images (better interpolation at high zoom
level)
* language and i18n:
* added support for right-to-left languages (patch #470)
* made the list of languages configurable via the locale WML

View file

@ -1428,15 +1428,32 @@ void display::draw_unit_on_tile(int x, int y, surface unit_image_override,
void display::draw_bar(const std::string& image, int xpos, int ypos, size_t height, double filled, const SDL_Color& col, fixed_t alpha)
{
filled = minimum<double>(maximum<double>(filled,0.0),1.0);
surface surf(image::get_image(image,image::SCALED,image::NO_ADJUST_COLOUR));
surface unmoved_surf(image::get_image("misc/bar-energy-unmoved.png",image::SCALED,image::NO_ADJUST_COLOUR));
surface unmoved_surf(image::get_image("misc/bar-energy-unmoved.png",image::UNSCALED,image::NO_ADJUST_COLOUR));
if(surf == NULL || unmoved_surf == NULL) {
return;
}
const SDL_Rect& bar_loc = calculate_energy_bar(unmoved_surf);
// calculate_energy_bar returns incorrect results if the surface colors
// have changed (for example, due to bilinear interpolaion)
const SDL_Rect& unscaled_bar_loc = calculate_energy_bar(unmoved_surf);
SDL_Rect bar_loc;
if (surf->w == unmoved_surf->w && surf->h == unmoved_surf->h)
bar_loc = unscaled_bar_loc;
else {
const fixed_t xratio = fxpdiv(surf->w,unmoved_surf->w);
const fixed_t yratio = fxpdiv(surf->h,unmoved_surf->h);
const SDL_Rect scaled_bar_loc = {fxptoi(unscaled_bar_loc. x * xratio),
fxptoi(unscaled_bar_loc. y * yratio + 127),
fxptoi(unscaled_bar_loc. w * yratio + 255),
fxptoi(unscaled_bar_loc. h * yratio + 255)};
bar_loc = scaled_bar_loc;
}
if(height > bar_loc.h) {
height = bar_loc.h;
}

View file

@ -129,6 +129,8 @@ surface create_optimized_surface(surface const &surf)
// don't pass this function 0 scaling arguments
surface scale_surface(surface const &surf, int w, int h)
{
assert(SDL_ALPHA_TRANSPARENT==0);
if(surf == NULL)
return NULL;
@ -163,7 +165,110 @@ surface scale_surface(surface const &surf, int w, int h)
const int xsrcint = fxptoi(xsrc);
const int ysrcint = fxptoi(ysrc);
dst_pixels[ydst*dst->w + xdst] = src_pixels[ysrcint*src->w + xsrcint];
Uint32* const src_word = src_pixels + ysrcint*src->w + xsrcint;
Uint32* const dst_word = dst_pixels + ydst*dst->w + xdst;
const int dx = (xsrcint + 1 < src->w) ? 1 : 0;
const int dy = (ysrcint + 1 < src->h) ? src->w : 0;
Uint8 r,g,b,a;
Uint32 rr,gg,bb,aa;
Uint16 avg_r, avg_g, avg_b, avg_a;
Uint32 pix[4], bilin[4];
// This next part is the fixed point
// equivalent of "take everything to
// the right of the decimal point."
// These fundamental weights decide
// the contributions from various
// input pixels. The labels assume
// that the upper left corner of the
// screen ("northeast") is 0,0 but the
// code should still be consistant if
// the graphics origin is actually
// somewhere else.
const fixed_t e = 0x000000FF & xsrc;
const fixed_t s = 0x000000FF & ysrc;
const fixed_t n = 0xFF - s;
const fixed_t w = 0xFF - e;
pix[0] = *src_word; // northwest
pix[1] = *(src_word + dx); // northeast
pix[2] = *(src_word + dy); // southwest
pix[3] = *(src_word + dx + dy); // southeast
bilin[0] = n*w;
bilin[1] = n*e;
bilin[2] = s*w;
bilin[3] = s*e;
// Scope out the neighboorhood, see
// what the pixel values are like.
int count = 0;
avg_r = avg_g = avg_b = avg_a = 0;
for (int loc=0; loc<4; loc++) {
SDL_GetRGBA(pix[loc],src->format,&r,&g,&b,&a);
if (a != 0) {
avg_r += r;
avg_g += g;
avg_b += b;
avg_a += a;
count++;
}
}
if (count>0) {
avg_r /= count;
avg_b /= count;
avg_g /= count;
avg_a /= count;
}
// Perform modified bilinear
// interpolation. Don't trust any
// color information from an RGBA
// sample when the alpha channel is
// set to fully transparent.
//
// Some of the input images are hex
// tiles, created using a hexagon
// shaped alpha channel that is either
// set to full-on or full-off. If
// intermediate alpha values are
// introduced along a hex edge, it
// produces a gametime artifact.
// Moving the mouse around will leave
// behind "hexagon halos" from the
// temporary highlighting. In other
// words the Wesnoth rendering engine
// freaks out.
//
// The alpha thresholding step
// attempts to accomodates this
// limitation. There is a small loss
// of quality. For example, skeleton
// bowstrings are not as good as they
// could be.
rr = gg = bb = aa = 0;
for (int loc=0; loc<4; loc++) {
SDL_GetRGBA(pix[loc],src->format,&r,&g,&b,&a);
if (a == 0) {
r = avg_r;
g = avg_g;
b = avg_b;
}
rr += r * bilin[loc];
gg += g * bilin[loc];
bb += b * bilin[loc];
aa += a * bilin[loc];
}
r = rr >> 16;
g = gg >> 16;
b = bb >> 16;
a = aa >> 16;
a = (a < avg_a/2) ? 0 : avg_a;
*dst_word = SDL_MapRGBA(dst->format,r,g,b,a);
}
}
}