Add bilinear filtering to TexturePeeker

This commit is contained in:
tobspr 2016-02-18 19:43:26 +01:00
parent 862f0e4db2
commit 1c9985d2f7
3 changed files with 69 additions and 1 deletions

View File

@ -48,3 +48,11 @@ INLINE int TexturePeeker::
get_z_size() const {
return _z_size;
}
/**
* Returns whether a given coordinate is inside of the texture dimensions.
*/
INLINE bool TexturePeeker::
has_pixel(size_t x, size_t y) const {
return x >= 0 && y >= 0 && x < _x_size && y < _y_size;
}

View File

@ -168,13 +168,70 @@ void TexturePeeker::
lookup(LColor &color, PN_stdfloat u, PN_stdfloat v) const {
int x = int((u - cfloor(u)) * (PN_stdfloat)_x_size) % _x_size;
int y = int((v - cfloor(v)) * (PN_stdfloat)_y_size) % _y_size;
fetch_pixel(color, x, y);
}
/**
* Works like TexturePeeker::lookup(), but instead uv-coordinates integer
* coordinates are used.
*/
void TexturePeeker::
fetch_pixel(LColor& color, size_t x, size_t y) const {
nassertv(x >= 0 && x < _x_size && y >= 0 && y < _y_size);
const unsigned char *p = _image.p() + (y * _x_size + x) * _pixel_width;
(*_get_texel)(color, p, _get_component);
}
/**
* Performs a bilinear lookup to retrieve the color value stored at the uv
* coordinate (u, v).
*
* In case the point is outside of the uv range, color is set to zero,
* and false is returned. Otherwise true is returned.
*/
bool TexturePeeker::
lookup_bilinear(LColor &color, PN_stdfloat u, PN_stdfloat v) const {
color = LColor::zero();
u = u * _x_size - 0.5;
v = v * _y_size - 0.5;
int min_u = int(floor(u));
int min_v = int(floor(v));
PN_stdfloat frac_u = u - min_u;
PN_stdfloat frac_v = v - min_v;
LColor p00(LColor::zero()), p01(LColor::zero()), p10(LColor::zero()), p11(LColor::zero());
PN_stdfloat w00 = 0.0, w01 = 0.0, w10 = 0.0, w11 = 0.0;
if (has_pixel(min_u, min_v)) {
w00 = (1.0 - frac_v) * (1.0 - frac_u);
fetch_pixel(p00, min_u, min_v);
}
if (has_pixel(min_u + 1, min_v)) {
w10 = (1.0 - frac_v) * frac_u;
fetch_pixel(p10, min_u + 1, min_v);
}
if (has_pixel(min_u, min_v + 1)) {
w01 = frac_v * (1.0 - frac_u);
fetch_pixel(p01, min_u, min_v + 1);
}
if (has_pixel(min_u + 1, min_v + 1)) {
w11 = frac_v * frac_u;
fetch_pixel(p11, min_u + 1, min_v + 1);
}
PN_stdfloat net_w = w00 + w01 + w10 + w11;
if (net_w == 0.0) {
return false;
}
color = (p00 * w00 + p01 * w01 + p10 * w10 + p11 * w11) / net_w;
return true;
}
/**
* Fills "color" with the RGBA color of the texel at point (u, v, w).
*

View File

@ -36,8 +36,11 @@ PUBLISHED:
INLINE int get_y_size() const;
INLINE int get_z_size() const;
INLINE bool has_pixel(size_t x, size_t y) const;
void lookup(LColor &color, PN_stdfloat u, PN_stdfloat v) const;
void lookup(LColor &color, PN_stdfloat u, PN_stdfloat v, PN_stdfloat w) const;
void fetch_pixel(LColor &color, size_t x, size_t y) const;
bool lookup_bilinear(LColor &color, PN_stdfloat u, PN_stdfloat v) const;
void filter_rect(LColor &color,
PN_stdfloat min_u, PN_stdfloat min_v,
PN_stdfloat max_u, PN_stdfloat max_v) const;