]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/client/tile.cpp
Remove unused ITextSceneNode header (#11476)
[dragonfireclient.git] / src / client / tile.cpp
index 019b6e7fabdb6f0ac3544836d5013c490fe5badf..96312ea27c96322ee99ae024c58d4c14b43224b3 100644 (file)
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include <algorithm>
 #include <ICameraSceneNode.h>
+#include <IrrCompileConfig.h>
 #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 <GLES/gl.h>
-#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<std::string, Palette> 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<u32 *>(image->lock());
+               return reinterpret_cast<u32 *>(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<u32 *>(result->lock());
+       u32 *target = reinterpret_cast<u32 *>(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 <GLES/gl.h>
+#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<u32> 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<u32> 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<u32>(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<u32> dim = img->getDimension();
-                                       infostream<<"Size "<<dim.Width
-                                                       <<"x"<<dim.Height<<std::endl;
                                        core::position2d<s32> 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<s32>(0, 0),
                texture->getOriginalSize());
+       if (!image)
+               return c;
+
        u32 total = 0;
        u32 tR = 0;
        u32 tG = 0;