aboutsummaryrefslogtreecommitdiff
path: root/src/client
diff options
context:
space:
mode:
authorAaron Suen <warr1024@gmail.com>2015-03-07 19:52:59 -0500
committerkwolekr <kwolekr@minetest.net>2015-03-20 20:21:42 -0400
commit1e4fb80d46da634f04d84e3f1065aaabc6909468 (patch)
tree4b1cf2b1d797b8f63848e6da1e262af6be27ef0d /src/client
parent26153bab7dbe57a0200949c9a121058150e67f6c (diff)
downloadminetest-1e4fb80d46da634f04d84e3f1065aaabc6909468.tar.gz
minetest-1e4fb80d46da634f04d84e3f1065aaabc6909468.tar.bz2
minetest-1e4fb80d46da634f04d84e3f1065aaabc6909468.zip
Configurable automatic texture scaling and filtering at load time.
Signed off by: Zeno, kwolekr
Diffstat (limited to 'src/client')
-rw-r--r--src/client/tile.cpp83
1 files changed, 83 insertions, 0 deletions
diff --git a/src/client/tile.cpp b/src/client/tile.cpp
index 541247fa8..078e62741 100644
--- a/src/client/tile.cpp
+++ b/src/client/tile.cpp
@@ -223,6 +223,89 @@ public:
}
}
+ /* Apply the "clean transparent" filter to textures, removing borders on transparent textures.
+ * PNG optimizers discard RGB values of fully-transparent pixels, but filters may expose the
+ * replacement colors at borders by blending to them; this filter compensates for that by
+ * filling in those RGB values from nearby pixels.
+ */
+ if (g_settings->getBool("texture_clean_transparent")) {
+ const core::dimension2d<u32> dim = toadd->getDimension();
+
+ // Walk each pixel looking for ones that will show as transparent.
+ for (u32 ctrx = 0; ctrx < dim.Width; ctrx++)
+ for (u32 ctry = 0; ctry < dim.Height; ctry++) {
+ irr::video::SColor c = toadd->getPixel(ctrx, ctry);
+ if (c.getAlpha() > 127)
+ continue;
+
+ // Sample size and total weighted r, g, b values.
+ u32 ss = 0, sr = 0, sg = 0, sb = 0;
+
+ // Walk each neighbor pixel (clipped to image bounds).
+ for (u32 sx = (ctrx < 1) ? 0 : (ctrx - 1);
+ sx <= (ctrx + 1) && sx < dim.Width; sx++)
+ for (u32 sy = (ctry < 1) ? 0 : (ctry - 1);
+ sy <= (ctry + 1) && sy < dim.Height; sy++) {
+
+ // Ignore the center pixel (its RGB is already
+ // presumed meaningless).
+ if ((sx == ctrx) && (sy == ctry))
+ continue;
+
+ // Ignore other nearby pixels that would be
+ // transparent upon display.
+ irr::video::SColor d = toadd->getPixel(sx, sy);
+ if(d.getAlpha() < 128)
+ continue;
+
+ // Add one weighted sample.
+ ss++;
+ sr += d.getRed();
+ sg += d.getGreen();
+ sb += d.getBlue();
+ }
+
+ // If we found any neighbor RGB data, set pixel to average
+ // weighted by alpha.
+ if (ss > 0) {
+ c.setRed(sr / ss);
+ c.setGreen(sg / ss);
+ c.setBlue(sb / ss);
+ toadd->setPixel(ctrx, ctry, c);
+ }
+ }
+ }
+
+ /* Upscale textures to user's requested minimum size. This is a trick to make
+ * filters look as good on low-res textures as on high-res ones, by making
+ * low-res textures BECOME high-res ones. This is helpful for worlds that
+ * mix high- and low-res textures, or for mods with least-common-denominator
+ * textures that don't have the resources to offer high-res alternatives.
+ */
+ s32 scaleto = g_settings->getS32("texture_min_size");
+ if (scaleto > 0) {
+
+ /* Calculate scaling needed to make the shortest texture dimension
+ * equal to the target minimum. If e.g. this is a vertical frames
+ * animation, the short dimension will be the real size.
+ */
+ const core::dimension2d<u32> dim = toadd->getDimension();
+ u32 xscale = scaleto / dim.Width;
+ u32 yscale = scaleto / dim.Height;
+ u32 scale = (xscale > yscale) ? xscale : yscale;
+
+ // Never downscale; only scale up by 2x or more.
+ if (scale > 1) {
+ u32 w = scale * dim.Width;
+ u32 h = scale * dim.Height;
+ const core::dimension2d<u32> newdim = core::dimension2d<u32>(w, h);
+ video::IImage *newimg = driver->createImage(
+ toadd->getColorFormat(), newdim);
+ toadd->copyToScaling(newimg);
+ toadd = newimg;
+ }
+ }
+
if (need_to_grab)
toadd->grab();
m_images[name] = toadd;