@@ -223,6 +223,89 @@ class SourceImageCache
223
223
}
224
224
}
225
225
226
+ /* Apply the "clean transparent" filter to textures, removing borders on transparent textures.
227
+ * PNG optimizers discard RGB values of fully-transparent pixels, but filters may expose the
228
+ * replacement colors at borders by blending to them; this filter compensates for that by
229
+ * filling in those RGB values from nearby pixels.
230
+ */
231
+ if (g_settings->getBool (" texture_clean_transparent" )) {
232
+ const core::dimension2d<u32> dim = toadd->getDimension ();
233
+
234
+ // Walk each pixel looking for ones that will show as transparent.
235
+ for (u32 ctrx = 0 ; ctrx < dim.Width ; ctrx++)
236
+ for (u32 ctry = 0 ; ctry < dim.Height ; ctry++) {
237
+ irr::video::SColor c = toadd->getPixel (ctrx, ctry);
238
+ if (c.getAlpha () > 127 )
239
+ continue ;
240
+
241
+ // Sample size and total weighted r, g, b values.
242
+ u32 ss = 0 , sr = 0 , sg = 0 , sb = 0 ;
243
+
244
+ // Walk each neighbor pixel (clipped to image bounds).
245
+ for (u32 sx = (ctrx < 1 ) ? 0 : (ctrx - 1 );
246
+ sx <= (ctrx + 1 ) && sx < dim.Width ; sx++)
247
+ for (u32 sy = (ctry < 1 ) ? 0 : (ctry - 1 );
248
+ sy <= (ctry + 1 ) && sy < dim.Height ; sy++) {
249
+
250
+ // Ignore the center pixel (its RGB is already
251
+ // presumed meaningless).
252
+ if ((sx == ctrx) && (sy == ctry))
253
+ continue ;
254
+
255
+ // Ignore other nearby pixels that would be
256
+ // transparent upon display.
257
+ irr::video::SColor d = toadd->getPixel (sx, sy);
258
+ if (d.getAlpha () < 128 )
259
+ continue ;
260
+
261
+ // Add one weighted sample.
262
+ ss++;
263
+ sr += d.getRed ();
264
+ sg += d.getGreen ();
265
+ sb += d.getBlue ();
266
+ }
267
+
268
+ // If we found any neighbor RGB data, set pixel to average
269
+ // weighted by alpha.
270
+ if (ss > 0 ) {
271
+ c.setRed (sr / ss);
272
+ c.setGreen (sg / ss);
273
+ c.setBlue (sb / ss);
274
+ toadd->setPixel (ctrx, ctry, c);
275
+ }
276
+ }
277
+ }
278
+
279
+ /* Upscale textures to user's requested minimum size. This is a trick to make
280
+ * filters look as good on low-res textures as on high-res ones, by making
281
+ * low-res textures BECOME high-res ones. This is helpful for worlds that
282
+ * mix high- and low-res textures, or for mods with least-common-denominator
283
+ * textures that don't have the resources to offer high-res alternatives.
284
+ */
285
+ s32 scaleto = g_settings->getS32 (" texture_min_size" );
286
+ if (scaleto > 0 ) {
287
+
288
+ /* Calculate scaling needed to make the shortest texture dimension
289
+ * equal to the target minimum. If e.g. this is a vertical frames
290
+ * animation, the short dimension will be the real size.
291
+ */
292
+ const core::dimension2d<u32> dim = toadd->getDimension ();
293
+ u32 xscale = scaleto / dim.Width ;
294
+ u32 yscale = scaleto / dim.Height ;
295
+ u32 scale = (xscale > yscale) ? xscale : yscale;
296
+
297
+ // Never downscale; only scale up by 2x or more.
298
+ if (scale > 1 ) {
299
+ u32 w = scale * dim.Width ;
300
+ u32 h = scale * dim.Height ;
301
+ const core::dimension2d<u32> newdim = core::dimension2d<u32>(w, h);
302
+ video::IImage *newimg = driver->createImage (
303
+ toadd->getColorFormat (), newdim);
304
+ toadd->copyToScaling (newimg);
305
+ toadd = newimg;
306
+ }
307
+ }
308
+
226
309
if (need_to_grab)
227
310
toadd->grab ();
228
311
m_images[name] = toadd;
0 commit comments