X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fclient%2Ftile.cpp;h=96312ea27c96322ee99ae024c58d4c14b43224b3;hb=a049e8267fabd101cb5c6528b3270214cb0647f0;hp=019b6e7fabdb6f0ac3544836d5013c490fe5badf;hpb=18a8fbf465b47c4780d63f34c960af7a52d0cf82;p=dragonfireclient.git diff --git a/src/client/tile.cpp b/src/client/tile.cpp index 019b6e7fa..96312ea27 100644 --- a/src/client/tile.cpp +++ b/src/client/tile.cpp @@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include +#include #include "util/string.h" #include "util/container.h" #include "util/thread.h" @@ -33,11 +34,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "guiscalingfilter.h" #include "renderingengine.h" - -#ifdef __ANDROID__ -#include -#endif - /* A cache from texture name to texture path */ @@ -117,9 +113,14 @@ std::string getImagePath(std::string path) Utilizes a thread-safe cache. */ -std::string getTexturePath(const std::string &filename) +std::string getTexturePath(const std::string &filename, bool *is_base_pack) { std::string fullpath; + + // This can set a wrong value on cached textures, but is irrelevant because + // is_base_pack is only passed when initializing the textures the first time + if (is_base_pack) + *is_base_pack = false; /* Check from cache */ @@ -131,7 +132,8 @@ std::string getTexturePath(const std::string &filename) Check from texture_path */ for (const auto &path : getTextureDirs()) { - std::string testpath = path + DIR_DELIM + filename; + std::string testpath = path + DIR_DELIM; + testpath.append(filename); // Check all filename extensions. Returns "" if not found. fullpath = getImagePath(testpath); if (!fullpath.empty()) @@ -148,6 +150,8 @@ std::string getTexturePath(const std::string &filename) std::string testpath = base_path + DIR_DELIM + filename; // Check all filename extensions. Returns "" if not found. fullpath = getImagePath(testpath); + if (is_base_pack && !fullpath.empty()) + *is_base_pack = true; } // Add to cache (also an empty result is cached) @@ -209,9 +213,11 @@ class SourceImageCache bool need_to_grab = true; // Try to use local texture instead if asked to - if (prefer_local){ - std::string path = getTexturePath(name); - if (!path.empty()) { + if (prefer_local) { + bool is_base_pack; + std::string path = getTexturePath(name, &is_base_pack); + // Ignore base pack + if (!path.empty() && !is_base_pack) { video::IImage *img2 = RenderingEngine::get_video_driver()-> createImageFromFile(path.c_str()); if (img2){ @@ -412,9 +418,9 @@ class TextureSource : public IWritableTextureSource 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; - bool m_setting_anisotropic_filter; }; IWritableTextureSource *createTextureSource() @@ -433,9 +439,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_setting_anisotropic_filter = g_settings->getBool("anisotropic_filter"); } TextureSource::~TextureSource() @@ -456,8 +462,8 @@ TextureSource::~TextureSource() driver->removeTexture(t); } - infostream << "~TextureSource() "<< textures_before << "/" - << driver->getTextureCount() << std::endl; + infostream << "~TextureSource() before cleanup: "<< textures_before + << " after: " << driver->getTextureCount() << std::endl; } u32 TextureSource::getTextureId(const std::string &name) @@ -594,7 +600,7 @@ u32 TextureSource::generateTexture(const std::string &name) video::ITexture *tex = NULL; if (img != NULL) { -#ifdef __ANDROID__ +#if ENABLE_GLES img = Align2Npot2(img, driver); #endif // Create texture from resulting image @@ -653,7 +659,14 @@ video::ITexture* TextureSource::getTexture(const std::string &name, u32 *id) video::ITexture* TextureSource::getTextureForMesh(const std::string &name, u32 *id) { - return getTexture(name + "^[applyfiltersformesh", 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) + return getTexture(name + "^[applyfiltersformesh", id); + return getTexture(name, id); } Palette* TextureSource::getPalette(const std::string &name) @@ -748,10 +761,13 @@ void TextureSource::rebuildImagesAndTextures() video::IVideoDriver *driver = RenderingEngine::get_video_driver(); sanity_check(driver); + infostream << "TextureSource: recreating " << m_textureinfo_cache.size() + << " textures" << std::endl; + // Recreate textures for (TextureInfo &ti : m_textureinfo_cache) { video::IImage *img = generateImage(ti.name); -#ifdef __ANDROID__ +#if ENABLE_GLES img = Align2Npot2(img, driver); #endif // Create texture from resulting image @@ -814,17 +830,16 @@ static video::IImage *createInventoryCubeImage( image = scaled; } sanity_check(image->getPitch() == 4 * size); - return reinterpret_cast(image->lock()); + return reinterpret_cast(image->getData()); }; auto free_image = [] (video::IImage *image) -> void { - image->unlock(); image->drop(); }; video::IImage *result = driver->createImage(video::ECF_A8R8G8B8, {cube_size, cube_size}); sanity_check(result->getPitch() == 4 * cube_size); result->fill(video::SColor(0x00000000u)); - u32 *target = reinterpret_cast(result->lock()); + u32 *target = reinterpret_cast(result->getData()); // Draws single cube face // `shade_factor` is face brightness, in range [0.0, 1.0] @@ -883,7 +898,6 @@ static video::IImage *createInventoryCubeImage( {0, 5}, {1, 5}, }); - result->unlock(); return result; } @@ -988,61 +1002,41 @@ video::IImage* TextureSource::generateImage(const std::string &name) return baseimg; } -#ifdef __ANDROID__ -#include +#if ENABLE_GLES + /** * Check and align image to npot2 if required by hardware * @param image image to check for npot2 alignment * @param driver driver to use for image operations * @return image or copy of image aligned to npot2 */ - -inline u16 get_GL_major_version() -{ - const GLubyte *gl_version = glGetString(GL_VERSION); - return (u16) (gl_version[0] - '0'); -} - -video::IImage * Align2Npot2(video::IImage * image, - video::IVideoDriver* driver) +video::IImage *Align2Npot2(video::IImage *image, + video::IVideoDriver *driver) { - if (image == NULL) { + if (image == NULL) return image; - } - - core::dimension2d dim = image->getDimension(); - std::string extensions = (char*) glGetString(GL_EXTENSIONS); - - // Only GLES2 is trusted to correctly report npot support - if (get_GL_major_version() > 1 && - extensions.find("GL_OES_texture_npot") != std::string::npos) { + if (driver->queryFeature(video::EVDF_TEXTURE_NPOT)) return image; - } + core::dimension2d dim = image->getDimension(); unsigned int height = npot2(dim.Height); unsigned int width = npot2(dim.Width); - if ((dim.Height == height) && - (dim.Width == width)) { + if (dim.Height == height && dim.Width == width) return image; - } - if (dim.Height > height) { + if (dim.Height > height) height *= 2; - } - - if (dim.Width > width) { + if (dim.Width > width) width *= 2; - } video::IImage *targetimage = driver->createImage(video::ECF_A8R8G8B8, core::dimension2d(width, height)); - if (targetimage != NULL) { + if (targetimage != NULL) image->copyToScaling(targetimage); - } image->drop(); return targetimage; } @@ -1076,7 +1070,7 @@ bool TextureSource::generateImagePart(std::string part_of_name, // Stuff starting with [ are special commands if (part_of_name.empty() || part_of_name[0] != '[') { video::IImage *image = m_sourcecache.getOrLoad(part_of_name); -#ifdef __ANDROID__ +#if ENABLE_GLES image = Align2Npot2(image, driver); #endif if (image == NULL) { @@ -1252,8 +1246,6 @@ bool TextureSource::generateImagePart(std::string part_of_name, video::IImage *img = generateImage(filename); if (img) { core::dimension2d dim = img->getDimension(); - infostream<<"Size "< pos_base(x, y); video::IImage *img2 = driver->createImage(video::ECF_A8R8G8B8, dim); @@ -1604,8 +1596,18 @@ bool TextureSource::generateImagePart(std::string part_of_name, */ else if (str_starts_with(part_of_name, "[applyfiltersformesh")) { - // Apply the "clean transparent" filter, if configured. - if (g_settings->getBool("texture_clean_transparent")) + /* IMPORTANT: When changing this, getTextureForMesh() needs to be + * updated too. */ + + if (!baseimg) { + errorstream << "generateImagePart(): baseimg == NULL " + << "for part_of_name=\"" << part_of_name + << "\", cancelling." << std::endl; + return false; + } + + // Apply the "clean transparent" filter, if needed + if (m_setting_mipmap || g_settings->getBool("texture_clean_transparent")) imageCleanTransparent(baseimg, 127); /* Upscale textures to user's requested minimum size. This is a trick to make @@ -1793,6 +1795,24 @@ bool TextureSource::generateImagePart(std::string part_of_name, return true; } +/* + Calculate the color of a single pixel drawn on top of another pixel. + + This is a little more complicated than just video::SColor::getInterpolated + because getInterpolated does not handle alpha correctly. For example, a + pixel with alpha=64 drawn atop a pixel with alpha=128 should yield a + pixel with alpha=160, while getInterpolated would yield alpha=96. +*/ +static inline video::SColor blitPixel(const video::SColor &src_c, const video::SColor &dst_c, u32 ratio) +{ + if (dst_c.getAlpha() == 0) + return src_c; + video::SColor out_c = src_c.getInterpolated(dst_c, (float)ratio / 255.0f); + out_c.setAlpha(dst_c.getAlpha() + (255 - dst_c.getAlpha()) * + src_c.getAlpha() * ratio / (255 * 255)); + return out_c; +} + /* Draw an image on top of an another one, using the alpha channel of the source image @@ -1812,7 +1832,7 @@ static void blit_with_alpha(video::IImage *src, video::IImage *dst, s32 dst_y = dst_pos.Y + y0; video::SColor src_c = src->getPixel(src_x, src_y); video::SColor dst_c = dst->getPixel(dst_x, dst_y); - dst_c = src_c.getInterpolated(dst_c, (float)src_c.getAlpha()/255.0f); + dst_c = blitPixel(src_c, dst_c, src_c.getAlpha()); dst->setPixel(dst_x, dst_y, dst_c); } } @@ -1835,7 +1855,7 @@ static void blit_with_alpha_overlay(video::IImage *src, video::IImage *dst, video::SColor dst_c = dst->getPixel(dst_x, dst_y); if (dst_c.getAlpha() == 255 && src_c.getAlpha() != 0) { - dst_c = src_c.getInterpolated(dst_c, (float)src_c.getAlpha()/255.0f); + dst_c = blitPixel(src_c, dst_c, src_c.getAlpha()); dst->setPixel(dst_x, dst_y, dst_c); } } @@ -2172,9 +2192,14 @@ video::SColor TextureSource::getTextureAverageColor(const std::string &name) video::IVideoDriver *driver = RenderingEngine::get_video_driver(); video::SColor c(0, 0, 0, 0); video::ITexture *texture = getTexture(name); + if (!texture) + return c; video::IImage *image = driver->createImage(texture, core::position2d(0, 0), texture->getOriginalSize()); + if (!image) + return c; + u32 total = 0; u32 tR = 0; u32 tG = 0;