From db32e6c5aa3bf79c23fa51f9297440fcaf09215d Mon Sep 17 00:00:00 2001 From: Aaron Suen Date: Mon, 30 Mar 2015 20:04:19 -0400 Subject: [PATCH] Move texture_min_size even further down the pipe. Now, textures are JIT-upscaled using an image transformation, right at the time they're added to a mesh or particle; images used in 2D elements are left unscaled. This should fix any remaining issues with HUD elements. --- src/client/tile.cpp | 96 ++++++++++++++++++++-------------------- src/client/tile.h | 2 + src/content_cao.cpp | 14 +++--- src/content_cso.cpp | 2 +- src/content_mapblock.cpp | 2 +- src/game.cpp | 12 ++--- src/mapblock_mesh.cpp | 12 ++--- src/nodedef.cpp | 4 +- src/particles.cpp | 4 +- src/sky.cpp | 6 +-- src/wieldmesh.cpp | 2 +- 11 files changed, 78 insertions(+), 78 deletions(-) diff --git a/src/client/tile.cpp b/src/client/tile.cpp index 1cf9f1506..b7f63502d 100644 --- a/src/client/tile.cpp +++ b/src/client/tile.cpp @@ -182,47 +182,6 @@ struct TextureInfo } }; -/* 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. - */ -video::IImage *textureMinSizeUpscale(video::IVideoDriver *driver, video::IImage *orig) { - if(orig == NULL) - return orig; - s32 scaleto = g_settings->getS32("texture_min_size"); - if (scaleto > 1) { - const core::dimension2d dim = orig->getDimension(); - - // Don't upscale 1px images. They don't benefit from it anyway - // (wouldn't have been blurred) and MIGHT be sun/moon tonemaps. - if ((dim.Width <= 1) || (dim.Height <= 1)) - return orig; - - /* 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. - */ - 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( - orig->getColorFormat(), newdim); - orig->copyToScaling(newimg); - return newimg; - } - } - - return orig; -} - /* SourceImageCache: A cache used for storing source images. */ @@ -425,6 +384,14 @@ public: video::ITexture* getTexture(const std::string &name, u32 *id); + /* + Get a texture specifically intended for mesh + application, i.e. not HUD, compositing, or other 2D + use. This texture may be a different size and may + have had additional filters applied. + */ + video::ITexture* getTextureForMesh(const std::string &name, u32 *id); + // Returns a pointer to the irrlicht device virtual IrrlichtDevice* getDevice() { @@ -693,8 +660,7 @@ u32 TextureSource::generateTexture(const std::string &name) video::IVideoDriver *driver = m_device->getVideoDriver(); sanity_check(driver); - video::IImage *origimg = generateImage(name); - video::IImage *img = textureMinSizeUpscale(driver, origimg); + video::IImage *img = generateImage(name); video::ITexture *tex = NULL; @@ -705,8 +671,6 @@ u32 TextureSource::generateTexture(const std::string &name) // Create texture from resulting image tex = driver->addTexture(name.c_str(), img); img->drop(); - if((origimg != NULL) && (img != origimg)) - origimg->drop(); } /* @@ -757,6 +721,11 @@ video::ITexture* TextureSource::getTexture(const std::string &name, u32 *id) return getTexture(actual_id); } +video::ITexture* TextureSource::getTextureForMesh(const std::string &name, u32 *id) +{ + return getTexture(name + "^[autoupscaleformesh", id); +} + void TextureSource::processQueue() { /* @@ -797,8 +766,7 @@ void TextureSource::rebuildImagesAndTextures() // Recreate textures for (u32 i=0; iname); - video::IImage *img = textureMinSizeUpscale(driver, origimg); + video::IImage *img = generateImage(ti->name); #ifdef __ANDROID__ img = Align2Npot2(img, driver); sanity_check(img->getDimension().Height == npot2(img->getDimension().Height)); @@ -809,8 +777,6 @@ void TextureSource::rebuildImagesAndTextures() if (img) { t = driver->addTexture(ti->name.c_str(), img); img->drop(); - if(origimg && (origimg != img)) - origimg->drop(); } video::ITexture *t_old = ti->texture; // Replace texture @@ -1735,6 +1701,38 @@ bool TextureSource::generateImagePart(std::string part_of_name, blit_with_interpolate_overlay(img, baseimg, v2s32(0,0), v2s32(0,0), dim, ratio); img->drop(); } + else if (part_of_name.substr(0,19) == "[autoupscaleformesh") { + /* 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 > 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. + */ + 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; + } + } + } else { errorstream << "generateImagePart(): Invalid " diff --git a/src/client/tile.h b/src/client/tile.h index ea7a9135a..eadfdc2a5 100644 --- a/src/client/tile.h +++ b/src/client/tile.h @@ -102,6 +102,8 @@ public: virtual video::ITexture* getTexture(u32 id)=0; virtual video::ITexture* getTexture( const std::string &name, u32 *id = NULL)=0; + virtual video::ITexture* getTextureForMesh( + const std::string &name, u32 *id = NULL) = 0; virtual IrrlichtDevice* getDevice()=0; virtual bool isKnownSourceImage(const std::string &name)=0; virtual video::ITexture* generateTextureFromMesh( diff --git a/src/content_cao.cpp b/src/content_cao.cpp index 4c8962edb..6b7083d83 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -211,7 +211,7 @@ void TestCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc, // Set material buf->getMaterial().setFlag(video::EMF_LIGHTING, false); buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false); - buf->getMaterial().setTexture(0, tsrc->getTexture("rat.png")); + buf->getMaterial().setTexture(0, tsrc->getTextureForMesh("rat.png")); buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false); buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true); buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; @@ -822,7 +822,7 @@ void GenericCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc, NULL, v2f(1, 1), v3f(0,0,0), -1); m_spritenode->grab(); m_spritenode->setMaterialTexture(0, - tsrc->getTexture("unknown_node.png")); + tsrc->getTextureForMesh("unknown_node.png")); m_spritenode->setMaterialFlag(video::EMF_LIGHTING, false); m_spritenode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false); m_spritenode->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF); @@ -1299,7 +1299,7 @@ void GenericCAO::updateTextures(const std::string &mod) texturestring = m_prop.textures[0]; texturestring += mod; m_spritenode->setMaterialTexture(0, - tsrc->getTexture(texturestring)); + tsrc->getTextureForMesh(texturestring)); // This allows setting per-material colors. However, until a real lighting // system is added, the code below will have no effect. Once MineTest @@ -1327,7 +1327,7 @@ void GenericCAO::updateTextures(const std::string &mod) if(texturestring == "") continue; // Empty texture string means don't modify that material texturestring += mod; - video::ITexture* texture = tsrc->getTexture(texturestring); + video::ITexture* texture = tsrc->getTextureForMesh(texturestring); if(!texture) { errorstream<<"GenericCAO::updateTextures(): Could not load texture "<getTexture(texturestring)); + tsrc->getTextureForMesh(texturestring)); material.getTextureMatrix(0).makeIdentity(); // This allows setting per-material colors. However, until a real lighting @@ -1404,7 +1404,7 @@ void GenericCAO::updateTextures(const std::string &mod) tname += mod; scene::IMeshBuffer *buf = mesh->getMeshBuffer(0); buf->getMaterial().setTexture(0, - tsrc->getTexture(tname)); + tsrc->getTextureForMesh(tname)); // This allows setting per-material colors. However, until a real lighting // system is added, the code below will have no effect. Once MineTest @@ -1429,7 +1429,7 @@ void GenericCAO::updateTextures(const std::string &mod) tname += mod; scene::IMeshBuffer *buf = mesh->getMeshBuffer(1); buf->getMaterial().setTexture(0, - tsrc->getTexture(tname)); + tsrc->getTextureForMesh(tname)); // This allows setting per-material colors. However, until a real lighting // system is added, the code below will have no effect. Once MineTest diff --git a/src/content_cso.cpp b/src/content_cso.cpp index c337472ff..0790024fc 100644 --- a/src/content_cso.cpp +++ b/src/content_cso.cpp @@ -50,7 +50,7 @@ public: m_spritenode = smgr->addBillboardSceneNode( NULL, v2f(1,1), pos, -1); m_spritenode->setMaterialTexture(0, - env->getGameDef()->tsrc()->getTexture("smoke_puff.png")); + env->getGameDef()->tsrc()->getTextureForMesh("smoke_puff.png")); m_spritenode->setMaterialFlag(video::EMF_LIGHTING, false); m_spritenode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false); //m_spritenode->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF); diff --git a/src/content_mapblock.cpp b/src/content_mapblock.cpp index 70a1da0b7..a730c50a3 100644 --- a/src/content_mapblock.cpp +++ b/src/content_mapblock.cpp @@ -1686,7 +1686,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data, std::vector boxes = n.getSelectionBoxes(nodedef); TileSpec h_tile; h_tile.material_flags |= MATERIAL_FLAG_HIGHLIGHTED; - h_tile.texture = tsrc->getTexture("halo.png",&h_tile.texture_id); + h_tile.texture = tsrc->getTextureForMesh("halo.png",&h_tile.texture_id); v3f pos = intToFloat(p, BS); f32 d = 0.05 * BS; for (std::vector::iterator i = boxes.begin(); diff --git a/src/game.cpp b/src/game.cpp index 25b4048a3..6bddfe905 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -3202,12 +3202,12 @@ void Game::processClientEvents(CameraOrientation *cam, float *damage_flash) event.set_sky.params->size() == 6) { sky->setFallbackBgColor(*event.set_sky.bgcolor); skybox = smgr->addSkyBoxSceneNode( - texture_src->getTexture((*event.set_sky.params)[0]), - texture_src->getTexture((*event.set_sky.params)[1]), - texture_src->getTexture((*event.set_sky.params)[2]), - texture_src->getTexture((*event.set_sky.params)[3]), - texture_src->getTexture((*event.set_sky.params)[4]), - texture_src->getTexture((*event.set_sky.params)[5])); + texture_src->getTextureForMesh((*event.set_sky.params)[0]), + texture_src->getTextureForMesh((*event.set_sky.params)[1]), + texture_src->getTextureForMesh((*event.set_sky.params)[2]), + texture_src->getTextureForMesh((*event.set_sky.params)[3]), + texture_src->getTextureForMesh((*event.set_sky.params)[4]), + texture_src->getTextureForMesh((*event.set_sky.params)[5])); } // Handle everything else as plain color else { diff --git a/src/mapblock_mesh.cpp b/src/mapblock_mesh.cpp index d95b8d286..d1637891a 100644 --- a/src/mapblock_mesh.cpp +++ b/src/mapblock_mesh.cpp @@ -1130,7 +1130,7 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset): os<<":"<<(u32)p.tile.animation_frame_count<<":"; m_crack_materials.insert(std::make_pair(i, os.str())); // Replace tile texture with the cracked one - p.tile.texture = tsrc->getTexture( + p.tile.texture = tsrc->getTextureForMesh( os.str()+"0", &p.tile.texture_id); } @@ -1204,9 +1204,9 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset): p.tile.applyMaterialOptionsWithShaders(material); if (p.tile.normal_texture) { material.setTexture(1, p.tile.normal_texture); - material.setTexture(2, tsrc->getTexture("enable_img.png")); + material.setTexture(2, tsrc->getTextureForMesh("enable_img.png")); } else { - material.setTexture(2, tsrc->getTexture("disable_img.png")); + material.setTexture(2, tsrc->getTextureForMesh("disable_img.png")); } } else { p.tile.applyMaterialOptions(material); @@ -1298,7 +1298,7 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_rat os<getTexture(os.str(), &new_texture_id); + tsrc->getTextureForMesh(os.str(), &new_texture_id); buf->getMaterial().setTexture(0, new_texture); // If the current material is also animated, @@ -1341,9 +1341,9 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_rat if (m_enable_shaders) { if (animation_frame.normal_texture) { buf->getMaterial().setTexture(1, animation_frame.normal_texture); - buf->getMaterial().setTexture(2, tsrc->getTexture("enable_img.png")); + buf->getMaterial().setTexture(2, tsrc->getTextureForMesh("enable_img.png")); } else { - buf->getMaterial().setTexture(2, tsrc->getTexture("disable_img.png")); + buf->getMaterial().setTexture(2, tsrc->getTextureForMesh("disable_img.png")); } } } diff --git a/src/nodedef.cpp b/src/nodedef.cpp index 0654f66c5..ce087f6b8 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -930,7 +930,7 @@ void CNodeDefManager::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile, bool backface_culling, u8 alpha, u8 material_type) { tile->shader_id = shader_id; - tile->texture = tsrc->getTexture(tiledef->name, &tile->texture_id); + tile->texture = tsrc->getTextureForMesh(tiledef->name, &tile->texture_id); tile->alpha = alpha; tile->material_type = material_type; @@ -973,7 +973,7 @@ void CNodeDefManager::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile, os << tiledef->name << "^[verticalframe:" << frame_count << ":" << i; - frame.texture = tsrc->getTexture(os.str(), &frame.texture_id); + frame.texture = tsrc->getTextureForMesh(os.str(), &frame.texture_id); if (tile->normal_texture) frame.normal_texture = tsrc->getNormalTexture(os.str()); tile->frames[i] = frame; diff --git a/src/particles.cpp b/src/particles.cpp index a137aaaba..e9268be27 100644 --- a/src/particles.cpp +++ b/src/particles.cpp @@ -434,7 +434,7 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef, } } video::ITexture *texture = - gamedef->tsrc()->getTexture(*(event->add_particlespawner.texture)); + gamedef->tsrc()->getTextureForMesh(*(event->add_particlespawner.texture)); ParticleSpawner* toadd = new ParticleSpawner(gamedef, smgr, player, event->add_particlespawner.amount, @@ -477,7 +477,7 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef, if (event->type == CE_SPAWN_PARTICLE) { video::ITexture *texture = - gamedef->tsrc()->getTexture(*(event->spawn_particle.texture)); + gamedef->tsrc()->getTextureForMesh(*(event->spawn_particle.texture)); Particle* toadd = new Particle(gamedef, smgr, player, m_env, *event->spawn_particle.pos, diff --git a/src/sky.cpp b/src/sky.cpp index ac8e2cbf6..e40602914 100644 --- a/src/sky.cpp +++ b/src/sky.cpp @@ -47,14 +47,14 @@ Sky::Sky(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id, m_materials[1].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; m_materials[2] = mat; - m_materials[2].setTexture(0, tsrc->getTexture("sunrisebg.png")); + m_materials[2].setTexture(0, tsrc->getTextureForMesh("sunrisebg.png")); m_materials[2].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; //m_materials[2].MaterialType = video::EMT_TRANSPARENT_ADD_COLOR; m_sun_texture = tsrc->isKnownSourceImage("sun.png") ? - tsrc->getTexture("sun.png") : NULL; + tsrc->getTextureForMesh("sun.png") : NULL; m_moon_texture = tsrc->isKnownSourceImage("moon.png") ? - tsrc->getTexture("moon.png") : NULL; + tsrc->getTextureForMesh("moon.png") : NULL; m_sun_tonemap = tsrc->isKnownSourceImage("sun_tonemap.png") ? tsrc->getTexture("sun_tonemap.png") : NULL; m_moon_tonemap = tsrc->isKnownSourceImage("moon_tonemap.png") ? diff --git a/src/wieldmesh.cpp b/src/wieldmesh.cpp index c1a898c1b..23310ef27 100644 --- a/src/wieldmesh.cpp +++ b/src/wieldmesh.cpp @@ -276,7 +276,7 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename, // Customize material video::SMaterial &material = m_meshnode->getMaterial(0); - material.setTexture(0, texture); + material.setTexture(0, tsrc->getTextureForMesh(imagename)); material.MaterialType = m_material_type; material.setFlag(video::EMF_BACK_FACE_CULLING, true); // Enable bi/trilinear filtering only for high resolution textures