diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index 172616194..14e1c60ea 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -371,35 +371,21 @@ enable_3d_clouds (3D clouds) bool true [**Filtering and Antialiasing] -# Use mipmapping to scale textures. May slightly increase performance, +# Use mipmaps when scaling textures down. May slightly increase performance, # especially when using a high resolution texture pack. -# Gamma correct downscaling is not supported. +# Gamma-correct downscaling is not supported. mip_map (Mipmapping) bool false -# Use anisotropic filtering when viewing at textures from an angle. -anisotropic_filter (Anisotropic filtering) bool false - -# Use bilinear filtering when scaling textures. +# Use bilinear filtering when scaling textures down. bilinear_filter (Bilinear filtering) bool false -# Use trilinear filtering when scaling textures. +# Use trilinear filtering when scaling textures down. +# If both bilinear and trilinear filtering are enabled, trilinear filtering +# is applied. trilinear_filter (Trilinear filtering) bool false -# Filtered textures can blend RGB values with fully-transparent neighbors, -# which PNG optimizers usually discard, often resulting in dark or -# light edges to transparent textures. Apply a filter to clean that up -# at texture load time. This is automatically enabled if mipmapping is enabled. -texture_clean_transparent (Clean transparent textures) bool false - -# When using bilinear/trilinear/anisotropic filters, low-resolution textures -# can be blurred, so automatically upscale them with nearest-neighbor -# interpolation to preserve crisp pixels. This sets the minimum texture size -# for the upscaled textures; higher values look sharper, but require more -# memory. Powers of 2 are recommended. This setting is ONLY applied if -# bilinear/trilinear/anisotropic filtering is enabled. -# This is also used as the base node texture size for world-aligned -# texture autoscaling. -texture_min_size (Minimum texture size) int 64 1 32768 +# Use anisotropic filtering when looking at textures from an angle. +anisotropic_filter (Anisotropic filtering) bool false # Select the antialiasing method to apply. # @@ -1831,6 +1817,9 @@ world_aligned_mode (World-aligned textures mode) enum enable disable,enable,forc # Warning: This option is EXPERIMENTAL! autoscale_mode (Autoscaling mode) enum disable disable,enable,force +# The base node texture size used for world-aligned texture autoscaling. +texture_min_size (Base texture size) int 64 1 32768 + # Side length of a cube of map blocks that the client will consider together # when generating meshes. # Larger values increase the utilization of the GPU by reducing the number of diff --git a/src/client/clientmap.cpp b/src/client/clientmap.cpp index 00218cc55..e77fd7116 100644 --- a/src/client/clientmap.cpp +++ b/src/client/clientmap.cpp @@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "clientmap.h" #include "client.h" +#include "client/mesh.h" #include "mapblock_mesh.h" #include #include @@ -843,7 +844,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) // Apply filter settings material.forEachTexture([this] (auto &tex) { - tex.setFiltersMinetest(m_cache_bilinear_filter, m_cache_trilinear_filter, + setMaterialFilters(tex, m_cache_bilinear_filter, m_cache_trilinear_filter, m_cache_anistropic_filter); }); material.Wireframe = m_control.show_wireframe; diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp index 28f9d18cb..eb166806b 100644 --- a/src/client/content_cao.cpp +++ b/src/client/content_cao.cpp @@ -1355,7 +1355,7 @@ void GenericCAO::updateTextures(std::string mod) } material.forEachTexture([=] (auto &tex) { - tex.setFiltersMinetest(use_bilinear_filter, use_trilinear_filter, + setMaterialFilters(tex, use_bilinear_filter, use_trilinear_filter, use_anisotropic_filter); }); } @@ -1383,15 +1383,8 @@ void GenericCAO::updateTextures(std::string mod) material.Lighting = true; material.BackfaceCulling = m_prop.backface_culling; - // don't filter low-res textures, makes them look blurry - // player models have a res of 64 - const core::dimension2d &size = texture->getOriginalSize(); - const u32 res = std::min(size.Height, size.Width); - use_trilinear_filter &= res > 64; - use_bilinear_filter &= res > 64; - material.forEachTexture([=] (auto &tex) { - tex.setFiltersMinetest(use_bilinear_filter, use_trilinear_filter, + setMaterialFilters(tex, use_bilinear_filter, use_trilinear_filter, use_anisotropic_filter); }); } @@ -1438,7 +1431,7 @@ void GenericCAO::updateTextures(std::string mod) } material.forEachTexture([=] (auto &tex) { - tex.setFiltersMinetest(use_bilinear_filter, use_trilinear_filter, + setMaterialFilters(tex, use_bilinear_filter, use_trilinear_filter, use_anisotropic_filter); }); } @@ -1463,7 +1456,7 @@ void GenericCAO::updateTextures(std::string mod) } material.forEachTexture([=] (auto &tex) { - tex.setFiltersMinetest(use_bilinear_filter, use_trilinear_filter, + setMaterialFilters(tex, use_bilinear_filter, use_trilinear_filter, use_anisotropic_filter); }); } @@ -1492,7 +1485,7 @@ void GenericCAO::updateTextures(std::string mod) } material.forEachTexture([=] (auto &tex) { - tex.setFiltersMinetest(use_bilinear_filter, use_trilinear_filter, + setMaterialFilters(tex, use_bilinear_filter, use_trilinear_filter, use_anisotropic_filter); }); } diff --git a/src/client/mesh.cpp b/src/client/mesh.cpp index 6cdcb0b78..b2cab4faa 100644 --- a/src/client/mesh.cpp +++ b/src/client/mesh.cpp @@ -503,3 +503,18 @@ scene::IMesh* convertNodeboxesToMesh(const std::vector &boxes, } return dst_mesh; } + +void setMaterialFilters(video::SMaterialLayer &tex, bool bilinear, bool trilinear, bool anisotropic) { + if (trilinear) + tex.MinFilter = video::ETMINF_LINEAR_MIPMAP_LINEAR; + else if (bilinear) + tex.MinFilter = video::ETMINF_LINEAR_MIPMAP_NEAREST; + else + tex.MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST; + + // "We don't want blurriness after all." ~ Desour, #13108 + // (because of pixel art) + tex.MagFilter = video::ETMAGF_NEAREST; + + tex.AnisotropicFilter = anisotropic ? 0xFF : 0; +} diff --git a/src/client/mesh.h b/src/client/mesh.h index 1ed753c01..0c3e8942e 100644 --- a/src/client/mesh.h +++ b/src/client/mesh.h @@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #pragma once +#include "SMaterialLayer.h" #include "irrlichttypes_extrabloated.h" #include "nodedef.h" @@ -133,3 +134,10 @@ void recalculateBoundingBox(scene::IMesh *src_mesh); We assume normal to be valid when it's 0 < length < Inf. and not NaN */ bool checkMeshNormals(scene::IMesh *mesh); + +/* + Set the MinFilter, MagFilter and AnisotropicFilter properties of a texture + layer according to the three relevant boolean values found in the Minetest + settings. +*/ +void setMaterialFilters(video::SMaterialLayer &tex, bool bilinear, bool trilinear, bool anisotropic); diff --git a/src/client/tile.cpp b/src/client/tile.cpp index 4e6e68b46..867c28dd3 100644 --- a/src/client/tile.cpp +++ b/src/client/tile.cpp @@ -433,10 +433,8 @@ private: // Maps image file names to loaded palettes. std::unordered_map m_palettes; - // Cached settings needed for making textures from meshes - bool m_setting_mipmap; - bool m_setting_trilinear_filter; - bool m_setting_bilinear_filter; + // Cached settings needed for making textures for meshes + bool m_mesh_texture_prefilter; }; IWritableTextureSource *createTextureSource() @@ -455,9 +453,9 @@ TextureSource::TextureSource() // Cache some settings // Note: Since this is only done once, the game must be restarted // for these settings to take effect - m_setting_mipmap = g_settings->getBool("mip_map"); - m_setting_trilinear_filter = g_settings->getBool("trilinear_filter"); - m_setting_bilinear_filter = g_settings->getBool("bilinear_filter"); + m_mesh_texture_prefilter = + g_settings->getBool("mip_map") || g_settings->getBool("bilinear_filter") || + g_settings->getBool("trilinear_filter") || g_settings->getBool("anisotropic_filter"); } TextureSource::~TextureSource() @@ -701,12 +699,8 @@ video::ITexture* TextureSource::getTexture(const std::string &name, u32 *id) video::ITexture* TextureSource::getTextureForMesh(const std::string &name, u32 *id) { - static thread_local bool filter_needed = - g_settings->getBool("texture_clean_transparent") || m_setting_mipmap || - ((m_setting_trilinear_filter || m_setting_bilinear_filter) && - g_settings->getS32("texture_min_size") > 1); // Avoid duplicating texture if it won't actually change - if (filter_needed) + if (m_mesh_texture_prefilter) return getTexture(name + "^[applyfiltersformesh", id); return getTexture(name, id); } @@ -1741,46 +1735,8 @@ bool TextureSource::generateImagePart(std::string part_of_name, } // Apply the "clean transparent" filter, if needed - if (m_setting_mipmap || g_settings->getBool("texture_clean_transparent")) + if (m_mesh_texture_prefilter) imageCleanTransparent(baseimg, 127); - - /* 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. - */ - const bool filter = m_setting_trilinear_filter || m_setting_bilinear_filter; - const s32 scaleto = filter ? g_settings->getU16("texture_min_size") : 1; - if (scaleto > 1) { - const core::dimension2d dim = baseimg->getDimension(); - - /* 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. - */ - if ((dim.Width == 0) || (dim.Height == 0)) { - errorstream << "generateImagePart(): Illegal 0 dimension " - << "for part_of_name=\""<< part_of_name - << "\", cancelling." << std::endl; - return false; - } - 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 newdim = core::dimension2d(w, h); - video::IImage *newimg = driver->createImage( - baseimg->getColorFormat(), newdim); - baseimg->copyToScaling(newimg); - baseimg->drop(); - baseimg = newimg; - } - } } /* [resize:WxH diff --git a/src/client/wieldmesh.cpp b/src/client/wieldmesh.cpp index 10a8a5665..60c303c78 100644 --- a/src/client/wieldmesh.cpp +++ b/src/client/wieldmesh.cpp @@ -297,11 +297,8 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename, material.MaterialType = m_material_type; material.MaterialTypeParam = 0.5f; material.BackfaceCulling = true; - // Enable bi/trilinear filtering only for high resolution textures - bool bilinear_filter = dim.Width > 32 && m_bilinear_filter; - bool trilinear_filter = dim.Width > 32 && m_trilinear_filter; material.forEachTexture([=] (auto &tex) { - tex.setFiltersMinetest(bilinear_filter, trilinear_filter, + setMaterialFilters(tex, m_bilinear_filter, m_trilinear_filter, m_anisotropic_filter); }); // mipmaps cause "thin black line" artifacts @@ -465,7 +462,7 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che material.MaterialTypeParam = 0.5f; material.BackfaceCulling = cull_backface; material.forEachTexture([this] (auto &tex) { - tex.setFiltersMinetest(m_bilinear_filter, m_trilinear_filter, + setMaterialFilters(tex, m_bilinear_filter, m_trilinear_filter, m_anisotropic_filter); }); } diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 8744de44d..6f10cfd36 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -176,6 +176,7 @@ void set_default_settings() settings->setDefault("undersampling", "1"); settings->setDefault("world_aligned_mode", "enable"); settings->setDefault("autoscale_mode", "disable"); + settings->setDefault("texture_min_size", "64"); settings->setDefault("enable_fog", "true"); settings->setDefault("fog_start", "0.4"); settings->setDefault("3d_mode", "none"); @@ -235,8 +236,6 @@ void set_default_settings() settings->setDefault("hud_hotbar_max_width", "1.0"); settings->setDefault("enable_local_map_saving", "false"); settings->setDefault("show_entity_selectionbox", "false"); - settings->setDefault("texture_clean_transparent", "false"); - settings->setDefault("texture_min_size", "64"); settings->setDefault("ambient_occlusion_gamma", "1.8"); settings->setDefault("enable_shaders", "true"); settings->setDefault("enable_particles", "true"); @@ -252,9 +251,9 @@ void set_default_settings() settings->setDefault("directional_colored_fog", "true"); settings->setDefault("inventory_items_animations", "false"); settings->setDefault("mip_map", "false"); - settings->setDefault("anisotropic_filter", "false"); settings->setDefault("bilinear_filter", "false"); settings->setDefault("trilinear_filter", "false"); + settings->setDefault("anisotropic_filter", "false"); settings->setDefault("tone_mapping", "false"); settings->setDefault("enable_waving_water", "false"); settings->setDefault("water_wave_height", "1.0");