]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/tile.cpp
Install menu textures of minetest_game
[dragonfireclient.git] / src / tile.cpp
index 6dbe4c63a606b29ba6b8cef22b8816ebf7e373c6..5f25e123bdd21556029e407cd81304a7e3cbee91 100644 (file)
@@ -1,6 +1,6 @@
 /*
-Minetest-c55
-Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+Minetest
+Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License as published by
@@ -77,7 +77,7 @@ static bool replace_ext(std::string &path, const char *ext)
 
        If failed, return "".
 */
-static std::string getImagePath(std::string path)
+std::string getImagePath(std::string path)
 {
        // A NULL-ended list of possible image extensions
        const char *extensions[] = {
@@ -201,48 +201,60 @@ struct SourceAtlasPointer
 class SourceImageCache
 {
 public:
+       ~SourceImageCache() {
+               for(std::map<std::string, video::IImage*>::iterator iter = m_images.begin();
+                               iter != m_images.end(); iter++) {
+                       iter->second->drop();
+               }
+               m_images.clear();
+       }
        void insert(const std::string &name, video::IImage *img,
                        bool prefer_local, video::IVideoDriver *driver)
        {
                assert(img);
                // Remove old image
-               core::map<std::string, video::IImage*>::Node *n;
+               std::map<std::string, video::IImage*>::iterator n;
                n = m_images.find(name);
-               if(n){
-                       video::IImage *oldimg = n->getValue();
-                       if(oldimg)
-                               oldimg->drop();
+               if(n != m_images.end()){
+                       if(n->second)
+                               n->second->drop();
                }
+
+               video::IImage* toadd = img;
+               bool need_to_grab = true;
+
                // Try to use local texture instead if asked to
                if(prefer_local){
                        std::string path = getTexturePath(name.c_str());
                        if(path != ""){
                                video::IImage *img2 = driver->createImageFromFile(path.c_str());
                                if(img2){
-                                       m_images[name] = img2;
-                                       return;
+                                       toadd = img2;
+                                       need_to_grab = false;
                                }
                        }
                }
-               img->grab();
-               m_images[name] = img;
+
+               if (need_to_grab)
+                       toadd->grab();
+               m_images[name] = toadd;
        }
        video::IImage* get(const std::string &name)
        {
-               core::map<std::string, video::IImage*>::Node *n;
+               std::map<std::string, video::IImage*>::iterator n;
                n = m_images.find(name);
-               if(n)
-                       return n->getValue();
+               if(n != m_images.end())
+                       return n->second;
                return NULL;
        }
        // Primarily fetches from cache, secondarily tries to read from filesystem
        video::IImage* getOrLoad(const std::string &name, IrrlichtDevice *device)
        {
-               core::map<std::string, video::IImage*>::Node *n;
+               std::map<std::string, video::IImage*>::iterator n;
                n = m_images.find(name);
-               if(n){
-                       n->getValue()->grab(); // Grab for caller
-                       return n->getValue();
+               if(n != m_images.end()){
+                       n->second->grab(); // Grab for caller
+                       return n->second;
                }
                video::IVideoDriver* driver = device->getVideoDriver();
                std::string path = getTexturePath(name.c_str());
@@ -254,8 +266,7 @@ class SourceImageCache
                infostream<<"SourceImageCache::getOrLoad(): Loading path \""<<path
                                <<"\""<<std::endl;
                video::IImage *img = driver->createImageFromFile(path.c_str());
-               // Even if could not be loaded, put as NULL
-               //m_images[name] = img;
+
                if(img){
                        m_images[name] = img;
                        img->grab(); // Grab for caller
@@ -263,7 +274,7 @@ class SourceImageCache
                return img;
        }
 private:
-       core::map<std::string, video::IImage*> m_images;
+       std::map<std::string, video::IImage*> m_images;
 };
 
 /*
@@ -274,7 +285,7 @@ class TextureSource : public IWritableTextureSource
 {
 public:
        TextureSource(IrrlichtDevice *device);
-       ~TextureSource();
+       virtual ~TextureSource();
 
        /*
                Example case:
@@ -372,6 +383,18 @@ class TextureSource : public IWritableTextureSource
        // Update new texture pointer and texture coordinates to an
        // AtlasPointer based on it's texture id
        void updateAP(AtlasPointer &ap);
+       bool isKnownSourceImage(const std::string &name)
+       {
+               bool is_known = false;
+               bool cache_found = m_source_image_existence.get(name, &is_known);
+               if(cache_found)
+                       return is_known;
+               // Not found in cache; find out if a local file exists
+               is_known = (getTexturePath(name) != "");
+               m_source_image_existence.set(name, is_known);
+               return is_known;
+       }
 
        // Processes queued texture requests from other threads.
        // Shall be called from the main thread.
@@ -400,11 +423,14 @@ class TextureSource : public IWritableTextureSource
        // This should be only accessed from the main thread
        SourceImageCache m_sourcecache;
 
+       // Thread-safe cache of what source images are known (true = known)
+       MutexedMap<std::string, bool> m_source_image_existence;
+
        // A texture id is index in this array.
        // The first position contains a NULL texture.
-       core::array<SourceAtlasPointer> m_atlaspointer_cache;
+       std::vector<SourceAtlasPointer> m_atlaspointer_cache;
        // Maps a texture name to an index in the former.
-       core::map<std::string, u32> m_name_to_id;
+       std::map<std::string, u32> m_name_to_id;
        // The two former containers are behind this mutex
        JMutex m_atlaspointer_cache_mutex;
        
@@ -439,6 +465,28 @@ TextureSource::TextureSource(IrrlichtDevice *device):
 
 TextureSource::~TextureSource()
 {
+       video::IVideoDriver* driver = m_device->getVideoDriver();
+
+       unsigned int textures_before = driver->getTextureCount();
+
+       for (std::vector<SourceAtlasPointer>::iterator iter =
+                       m_atlaspointer_cache.begin();  iter != m_atlaspointer_cache.end();
+                       iter++)
+       {
+               video::ITexture *t = driver->getTexture(iter->name.c_str());
+
+               //cleanup texture
+               if (t)
+                       driver->removeTexture(t);
+
+               //cleanup source image
+               if (iter->atlas_img)
+                       iter->atlas_img->drop();
+       }
+       m_atlaspointer_cache.clear();
+
+       infostream << "~TextureSource() "<< textures_before << "/"
+                       << driver->getTextureCount() << std::endl;
 }
 
 u32 TextureSource::getTextureId(const std::string &name)
@@ -450,11 +498,11 @@ u32 TextureSource::getTextureId(const std::string &name)
                        See if texture already exists
                */
                JMutexAutoLock lock(m_atlaspointer_cache_mutex);
-               core::map<std::string, u32>::Node *n;
+               std::map<std::string, u32>::iterator n;
                n = m_name_to_id.find(name);
-               if(n != NULL)
+               if(n != m_name_to_id.end())
                {
-                       return n->getValue();
+                       return n->second;
                }
        }
        
@@ -564,13 +612,13 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
        {
                JMutexAutoLock lock(m_atlaspointer_cache_mutex);
 
-               core::map<std::string, u32>::Node *n;
+               std::map<std::string, u32>::iterator n;
                n = m_name_to_id.find(name);
-               if(n != NULL)
+               if(n != m_name_to_id.end())
                {
                        /*infostream<<"getTextureIdDirect(): \""<<name
                                        <<"\" found in cache"<<std::endl;*/
-                       return n->getValue();
+                       return n->second;
                }
        }
 
@@ -709,7 +757,7 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
                baseimg_dim = baseimg->getDimension();
        SourceAtlasPointer nap(name, ap, baseimg, v2s32(0,0), baseimg_dim);
        m_atlaspointer_cache.push_back(nap);
-       m_name_to_id.insert(name, id);
+       m_name_to_id[name] = id;
 
        /*infostream<<"getTextureIdDirect(): "
                        <<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;*/
@@ -754,7 +802,7 @@ void TextureSource::processQueue()
        /*
                Fetch textures
        */
-       if(m_get_texture_queue.size() > 0)
+       if(!m_get_texture_queue.empty())
        {
                GetRequest<std::string, u32, u8, u8>
                                request = m_get_texture_queue.pop();
@@ -781,6 +829,7 @@ void TextureSource::insertSourceImage(const std::string &name, video::IImage *im
        assert(get_current_thread_id() == m_main_thread);
        
        m_sourcecache.insert(name, img, true, m_device->getVideoDriver());
+       m_source_image_existence.set(name, true);
 }
        
 void TextureSource::rebuildImagesAndTextures()
@@ -810,7 +859,7 @@ void TextureSource::rebuildImagesAndTextures()
                video::ITexture *t = NULL;
                if(img)
                        t = driver->addTexture(sap->name.c_str(), img);
-               
+               video::ITexture *t_old = sap->a.atlas;
                // Replace texture
                sap->a.atlas = t;
                sap->a.pos = v2f(0,0);
@@ -819,6 +868,9 @@ void TextureSource::rebuildImagesAndTextures()
                sap->atlas_img = img;
                sap->intpos = v2s32(0,0);
                sap->intsize = img->getDimension();
+
+               if (t_old != 0)
+                       driver->removeTexture(t_old);
        }
 }
 
@@ -856,7 +908,7 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef)
                main content features
        */
 
-       core::map<std::string, bool> sourcelist;
+       std::set<std::string> sourcelist;
 
        for(u16 j=0; j<MAX_CONTENT+1; j++)
        {
@@ -866,16 +918,16 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef)
                for(u32 i=0; i<6; i++)
                {
                        std::string name = f.tiledef[i].name;
-                       sourcelist[name] = true;
+                       sourcelist.insert(name);
                }
        }
        
        infostream<<"Creating texture atlas out of textures: ";
-       for(core::map<std::string, bool>::Iterator
-                       i = sourcelist.getIterator();
-                       i.atEnd() == false; i++)
+       for(std::set<std::string>::iterator
+                       i = sourcelist.begin();
+                       i != sourcelist.end(); ++i)
        {
-               std::string name = i.getNode()->getKey();
+               std::string name = *i;
                infostream<<"\""<<name<<"\" ";
        }
        infostream<<std::endl;
@@ -894,11 +946,11 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef)
        pos_in_atlas.X = column_padding;
        pos_in_atlas.Y = padding;
 
-       for(core::map<std::string, bool>::Iterator
-                       i = sourcelist.getIterator();
-                       i.atEnd() == false; i++)
+       for(std::set<std::string>::iterator
+                       i = sourcelist.begin();
+                       i != sourcelist.end(); ++i)
        {
-               std::string name = i.getNode()->getKey();
+               std::string name = *i;
 
                // Generate image by name
                video::IImage *img2 = generate_image_from_scratch(name, m_device,
@@ -1010,11 +1062,11 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef)
                bool reuse_old_id = false;
                u32 id = m_atlaspointer_cache.size();
                // Check old id without fetching a texture
-               core::map<std::string, u32>::Node *n;
+               std::map<std::string, u32>::iterator n;
                n = m_name_to_id.find(name);
                // If it exists, we will replace the old definition
-               if(n){
-                       id = n->getValue();
+               if(n != m_name_to_id.end()){
+                       id = n->second;
                        reuse_old_id = true;
                        /*infostream<<"TextureSource::buildMainAtlas(): "
                                        <<"Replacing old AtlasPointer"<<std::endl;*/
@@ -1050,12 +1102,12 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef)
        /*
                Second pass: set texture pointer in generated AtlasPointers
        */
-       for(core::map<std::string, bool>::Iterator
-                       i = sourcelist.getIterator();
-                       i.atEnd() == false; i++)
+       for(std::set<std::string>::iterator
+                       i = sourcelist.begin();
+                       i != sourcelist.end(); ++i)
        {
-               std::string name = i.getNode()->getKey();
-               if(m_name_to_id.find(name) == NULL)
+               std::string name = *i;
+               if(m_name_to_id.find(name) == m_name_to_id.end())
                        continue;
                u32 id = m_name_to_id[name];
                //infostream<<"id of name "<<name<<" is "<<id<<std::endl;
@@ -1186,7 +1238,6 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                        core::dimension2d<u32> dim = image->getDimension();
                        baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
                        image->copyTo(baseimg);
-                       image->drop();
                }
                // Else blit on base.
                else
@@ -1200,13 +1251,14 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                        // Position to copy the blitted from in the blitted image
                        core::position2d<s32> pos_from(0,0);
                        // Blit
-                       image->copyToWithAlpha(baseimg, pos_to,
+                       /*image->copyToWithAlpha(baseimg, pos_to,
                                        core::rect<s32>(pos_from, dim),
                                        video::SColor(255,255,255,255),
-                                       NULL);
-                       // Drop image
-                       image->drop();
+                                       NULL);*/
+                       blit_with_alpha(image, baseimg, pos_from, pos_to, dim);
                }
+               //cleanup
+               image->drop();
        }
        else
        {
@@ -1344,7 +1396,11 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                        u32 h0 = stoi(sf.next(":"));
                        infostream<<"combined w="<<w0<<" h="<<h0<<std::endl;
                        core::dimension2d<u32> dim(w0,h0);
-                       baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
+                       if(baseimg == NULL)
+                       {
+                               baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
+                               baseimg->fill(video::SColor(0,0,0,0));
+                       }
                        while(sf.atend() == false)
                        {
                                u32 x = stoi(sf.next(","));
@@ -1364,10 +1420,11 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                                                        driver->createImage(video::ECF_A8R8G8B8, dim);
                                        img->copyTo(img2);
                                        img->drop();
-                                       img2->copyToWithAlpha(baseimg, pos_base,
+                                       /*img2->copyToWithAlpha(baseimg, pos_base,
                                                        core::rect<s32>(v2s32(0,0), dim),
                                                        video::SColor(255,255,255,255),
-                                                       NULL);
+                                                       NULL);*/
+                                       blit_with_alpha(img2, baseimg, v2s32(0,0), pos_base, dim);
                                        img2->drop();
                                }
                                else
@@ -1605,6 +1662,9 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                        video::IImage *image = driver->createImage(rtt, v2s32(0,0), dim);
                        assert(image);
 
+                       //cleanup texture
+                       driver->removeTexture(rtt);
+
                        baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
 
                        if(image)