Improve glass
[oweals/minetest.git] / src / tile.cpp
index 32de8cda23cbd6dc079390b2da48c23610972337..f57abfbb8e9cc4a646351c105175e14d3f1edeba 100644 (file)
@@ -27,7 +27,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "log.h"
 #include "mapnode.h" // For texture atlas making
 #include "mineral.h" // For texture atlas making
-#include "mapnode_contentfeatures.h" // For texture atlas making
+#include "nodedef.h" // For texture atlas making
+#include "gamedef.h"
 
 /*
        A cache from texture name to texture path
@@ -131,7 +132,7 @@ std::string getTexturePath(const std::string &filename)
        */
        if(fullpath == "")
        {
-               std::string rel_path = std::string("textures")+DIR_DELIM+filename;
+               std::string rel_path = std::string("clienttextures")+DIR_DELIM+filename;
                std::string testpath = porting::path_data + DIR_DELIM + rel_path;
                // Check all filename extensions. Returns "" if not found.
                fullpath = getImagePath(testpath);
@@ -144,10 +145,239 @@ std::string getTexturePath(const std::string &filename)
        return fullpath;
 }
 
+/*
+       An internal variant of AtlasPointer with more data.
+       (well, more like a wrapper)
+*/
+
+struct SourceAtlasPointer
+{
+       std::string name;
+       AtlasPointer a;
+       video::IImage *atlas_img; // The source image of the atlas
+       // Integer variants of position and size
+       v2s32 intpos;
+       v2u32 intsize;
+
+       SourceAtlasPointer(
+                       const std::string &name_,
+                       AtlasPointer a_=AtlasPointer(0, NULL),
+                       video::IImage *atlas_img_=NULL,
+                       v2s32 intpos_=v2s32(0,0),
+                       v2u32 intsize_=v2u32(0,0)
+               ):
+               name(name_),
+               a(a_),
+               atlas_img(atlas_img_),
+               intpos(intpos_),
+               intsize(intsize_)
+       {
+       }
+};
+
+/*
+       SourceImageCache: A cache used for storing source images.
+*/
+
+class SourceImageCache
+{
+public:
+       void insert(const std::string &name, video::IImage *img,
+                       bool do_overwrite)
+       {
+               assert(img);
+               core::map<std::string, video::IImage*>::Node *n;
+               n = m_images.find(name);
+               if(n){
+                       if(!do_overwrite)
+                               return;
+                       video::IImage *oldimg = n->getValue();
+                       if(oldimg)
+                               oldimg->drop();
+               }
+               img->grab();
+               m_images[name] = img;
+       }
+       video::IImage* get(const std::string &name)
+       {
+               core::map<std::string, video::IImage*>::Node *n;
+               n = m_images.find(name);
+               if(n)
+                       return n->getValue();
+               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;
+               n = m_images.find(name);
+               if(n){
+                       n->getValue()->grab(); // Grab for caller
+                       return n->getValue();
+               }
+               video::IVideoDriver* driver = device->getVideoDriver();
+               std::string path = getTexturePath(name.c_str());
+               if(path == ""){
+                       infostream<<"SourceImageCache::getOrLoad(): No path found for \""
+                                       <<name<<"\""<<std::endl;
+                       return NULL;
+               }
+               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
+               }
+               return img;
+       }
+private:
+       core::map<std::string, video::IImage*> m_images;
+};
+
 /*
        TextureSource
 */
 
+class TextureSource : public IWritableTextureSource
+{
+public:
+       TextureSource(IrrlichtDevice *device);
+       ~TextureSource();
+
+       /*
+               Example case:
+               Now, assume a texture with the id 1 exists, and has the name
+               "stone.png^mineral1".
+               Then a random thread calls getTextureId for a texture called
+               "stone.png^mineral1^crack0".
+               ...Now, WTF should happen? Well:
+               - getTextureId strips off stuff recursively from the end until
+                 the remaining part is found, or nothing is left when
+                 something is stripped out
+
+               But it is slow to search for textures by names and modify them
+               like that?
+               - ContentFeatures is made to contain ids for the basic plain
+                 textures
+               - Crack textures can be slow by themselves, but the framework
+                 must be fast.
+
+               Example case #2:
+               - Assume a texture with the id 1 exists, and has the name
+                 "stone.png^mineral1" and is specified as a part of some atlas.
+               - Now MapBlock::getNodeTile() stumbles upon a node which uses
+                 texture id 1, and finds out that NODEMOD_CRACK must be applied
+                 with progression=0
+               - It finds out the name of the texture with getTextureName(1),
+                 appends "^crack0" to it and gets a new texture id with
+                 getTextureId("stone.png^mineral1^crack0")
+
+       */
+       
+       /*
+               Gets a texture id from cache or
+               - if main thread, from getTextureIdDirect
+               - if other thread, adds to request queue and waits for main thread
+       */
+       u32 getTextureId(const std::string &name);
+       
+       /*
+               Example names:
+               "stone.png"
+               "stone.png^crack2"
+               "stone.png^blit:mineral_coal.png"
+               "stone.png^blit:mineral_coal.png^crack1"
+
+               - If texture specified by name is found from cache, return the
+                 cached id.
+               - Otherwise generate the texture, add to cache and return id.
+                 Recursion is used to find out the largest found part of the
+                 texture and continue based on it.
+
+               The id 0 points to a NULL texture. It is returned in case of error.
+       */
+       u32 getTextureIdDirect(const std::string &name);
+
+       // Finds out the name of a cached texture.
+       std::string getTextureName(u32 id);
+
+       /*
+               If texture specified by the name pointed by the id doesn't
+               exist, create it, then return the cached texture.
+
+               Can be called from any thread. If called from some other thread
+               and not found in cache, the call is queued to the main thread
+               for processing.
+       */
+       AtlasPointer getTexture(u32 id);
+       
+       AtlasPointer getTexture(const std::string &name)
+       {
+               return getTexture(getTextureId(name));
+       }
+       
+       // Gets a separate texture
+       video::ITexture* getTextureRaw(const std::string &name)
+       {
+               AtlasPointer ap = getTexture(name);
+               return ap.atlas;
+       }
+
+       // Update new texture pointer and texture coordinates to an
+       // AtlasPointer based on it's texture id
+       void updateAP(AtlasPointer &ap);
+
+       // Processes queued texture requests from other threads.
+       // Shall be called from the main thread.
+       void processQueue();
+       
+       // Insert an image into the cache without touching the filesystem.
+       // Shall be called from the main thread.
+       void insertSourceImage(const std::string &name, video::IImage *img);
+       
+       // Rebuild images and textures from the current set of source images
+       // Shall be called from the main thread.
+       void rebuildImagesAndTextures();
+
+       // Build the main texture atlas which contains most of the
+       // textures.
+       void buildMainAtlas(class IGameDef *gamedef);
+       
+private:
+       
+       // The id of the thread that is allowed to use irrlicht directly
+       threadid_t m_main_thread;
+       // The irrlicht device
+       IrrlichtDevice *m_device;
+       
+       // Cache of source images
+       // This should be only accessed from the main thread
+       SourceImageCache m_sourcecache;
+
+       // A texture id is index in this array.
+       // The first position contains a NULL texture.
+       core::array<SourceAtlasPointer> m_atlaspointer_cache;
+       // Maps a texture name to an index in the former.
+       core::map<std::string, u32> m_name_to_id;
+       // The two former containers are behind this mutex
+       JMutex m_atlaspointer_cache_mutex;
+       
+       // Main texture atlas. This is filled at startup and is then not touched.
+       video::IImage *m_main_atlas_image;
+       video::ITexture *m_main_atlas_texture;
+
+       // Queued texture fetches (to be processed by the main thread)
+       RequestQueue<std::string, u32, u8, u8> m_get_texture_queue;
+};
+
+IWritableTextureSource* createTextureSource(IrrlichtDevice *device)
+{
+       return new TextureSource(device);
+}
+
 TextureSource::TextureSource(IrrlichtDevice *device):
                m_device(device),
                m_main_atlas_image(NULL),
@@ -162,43 +392,12 @@ TextureSource::TextureSource(IrrlichtDevice *device):
        // Add a NULL AtlasPointer as the first index, named ""
        m_atlaspointer_cache.push_back(SourceAtlasPointer(""));
        m_name_to_id[""] = 0;
-
-       // Build main texture atlas
-       if(g_settings->getBool("enable_texture_atlas"))
-               buildMainAtlas();
-       else
-               infostream<<"Not building texture atlas."<<std::endl;
 }
 
 TextureSource::~TextureSource()
 {
 }
 
-void TextureSource::processQueue()
-{
-       /*
-               Fetch textures
-       */
-       if(m_get_texture_queue.size() > 0)
-       {
-               GetRequest<std::string, u32, u8, u8>
-                               request = m_get_texture_queue.pop();
-
-               infostream<<"TextureSource::processQueue(): "
-                               <<"got texture request with "
-                               <<"name=\""<<request.key<<"\""
-                               <<std::endl;
-
-               GetResult<std::string, u32, u8, u8>
-                               result;
-               result.key = request.key;
-               result.callers = request.callers;
-               result.item = getTextureIdDirect(request.key);
-
-               request.dest->push_back(result);
-       }
-}
-
 u32 TextureSource::getTextureId(const std::string &name)
 {
        //infostream<<"getTextureId(): \""<<name<<"\""<<std::endl;
@@ -267,7 +466,7 @@ void make_progressbar(float value, video::IImage *image);
        if baseimg is NULL, it is created. Otherwise stuff is made on it.
 */
 bool generate_image(std::string part_of_name, video::IImage *& baseimg,
-               IrrlichtDevice *device);
+               IrrlichtDevice *device, SourceImageCache *sourcecache);
 
 /*
        Generates an image from a full string like
@@ -276,7 +475,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
        This is used by buildMainAtlas().
 */
 video::IImage* generate_image_from_scratch(std::string name,
-               IrrlichtDevice *device);
+               IrrlichtDevice *device, SourceImageCache *sourcecache);
 
 /*
        This method generates all the textures
@@ -416,7 +615,7 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
        //infostream<<"last_part_of_name=\""<<last_part_of_name<<"\""<<std::endl;
 
        // Generate image according to part of name
-       if(generate_image(last_part_of_name, baseimg, m_device) == false)
+       if(!generate_image(last_part_of_name, baseimg, m_device, &m_sourcecache))
        {
                infostream<<"getTextureIdDirect(): "
                                "failed to generate \""<<last_part_of_name<<"\""
@@ -487,8 +686,127 @@ AtlasPointer TextureSource::getTexture(u32 id)
        return m_atlaspointer_cache[id].a;
 }
 
-void TextureSource::buildMainAtlas() 
+void TextureSource::updateAP(AtlasPointer &ap)
 {
+       AtlasPointer ap2 = getTexture(ap.id);
+       ap = ap2;
+}
+
+void TextureSource::processQueue()
+{
+       /*
+               Fetch textures
+       */
+       if(m_get_texture_queue.size() > 0)
+       {
+               GetRequest<std::string, u32, u8, u8>
+                               request = m_get_texture_queue.pop();
+
+               infostream<<"TextureSource::processQueue(): "
+                               <<"got texture request with "
+                               <<"name=\""<<request.key<<"\""
+                               <<std::endl;
+
+               GetResult<std::string, u32, u8, u8>
+                               result;
+               result.key = request.key;
+               result.callers = request.callers;
+               result.item = getTextureIdDirect(request.key);
+
+               request.dest->push_back(result);
+       }
+}
+
+void TextureSource::insertSourceImage(const std::string &name, video::IImage *img)
+{
+       infostream<<"TextureSource::insertSourceImage(): name="<<name<<std::endl;
+       
+       assert(get_current_thread_id() == m_main_thread);
+       
+       m_sourcecache.insert(name, img, false);
+
+#if 0
+       JMutexAutoLock lock(m_atlaspointer_cache_mutex);
+
+       video::IVideoDriver* driver = m_device->getVideoDriver();
+       assert(driver);
+
+       // Create texture
+       video::ITexture *t = driver->addTexture(name.c_str(), img);
+
+       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;
+       n = m_name_to_id.find(name);
+       // If it exists, we will replace the old definition
+       if(n){
+               id = n->getValue();
+               reuse_old_id = true;
+       }
+       
+       // Create AtlasPointer
+       AtlasPointer ap(id);
+       ap.atlas = t;
+       ap.pos = v2f(0,0);
+       ap.size = v2f(1,1);
+       ap.tiled = 0;
+       core::dimension2d<u32> dim = img->getDimension();
+
+       // Create SourceAtlasPointer and add to containers
+       SourceAtlasPointer nap(name, ap, img, v2s32(0,0), dim);
+       if(reuse_old_id)
+               m_atlaspointer_cache[id] = nap;
+       else
+               m_atlaspointer_cache.push_back(nap);
+       m_name_to_id[name] = id;
+#endif
+}
+       
+void TextureSource::rebuildImagesAndTextures()
+{
+       JMutexAutoLock lock(m_atlaspointer_cache_mutex);
+
+       /*// Oh well... just clear everything, they'll load sometime.
+       m_atlaspointer_cache.clear();
+       m_name_to_id.clear();*/
+
+       video::IVideoDriver* driver = m_device->getVideoDriver();
+       
+       // Remove source images from textures to disable inheriting textures
+       // from existing textures
+       /*for(u32 i=0; i<m_atlaspointer_cache.size(); i++){
+               SourceAtlasPointer *sap = &m_atlaspointer_cache[i];
+               sap->atlas_img->drop();
+               sap->atlas_img = NULL;
+       }*/
+       
+       // Recreate textures
+       for(u32 i=0; i<m_atlaspointer_cache.size(); i++){
+               SourceAtlasPointer *sap = &m_atlaspointer_cache[i];
+               video::IImage *img =
+                       generate_image_from_scratch(sap->name, m_device, &m_sourcecache);
+               // Create texture from resulting image
+               video::ITexture *t = NULL;
+               if(img)
+                       t = driver->addTexture(sap->name.c_str(), img);
+               
+               // Replace texture
+               sap->a.atlas = t;
+               sap->a.pos = v2f(0,0);
+               sap->a.size = v2f(1,1);
+               sap->a.tiled = 0;
+               sap->atlas_img = img;
+               sap->intpos = v2s32(0,0);
+               sap->intsize = img->getDimension();
+       }
+}
+
+void TextureSource::buildMainAtlas(class IGameDef *gamedef) 
+{
+       assert(gamedef->tsrc() == this);
+       INodeDefManager *ndef = gamedef->ndef();
+
        infostream<<"TextureSource::buildMainAtlas()"<<std::endl;
 
        //return; // Disable (for testing)
@@ -521,15 +839,15 @@ void TextureSource::buildMainAtlas()
        {
                if(j == CONTENT_IGNORE || j == CONTENT_AIR)
                        continue;
-               ContentFeatures *f = &content_features(j);
-               for(core::map<std::string, bool>::Iterator
-                               i = f->used_texturenames.getIterator();
-                               i.atEnd() == false; i++)
+               const ContentFeatures &f = ndef->get(j);
+               for(std::set<std::string>::const_iterator
+                               i = f.used_texturenames.begin();
+                               i != f.used_texturenames.end(); i++)
                {
-                       std::string name = i.getNode()->getKey();
+                       std::string name = *i;
                        sourcelist[name] = true;
 
-                       if(f->often_contains_mineral){
+                       if(f.often_contains_mineral){
                                for(int k=1; k<MINERAL_COUNT; k++){
                                        std::string mineraltexture = mineral_block_texture(k);
                                        std::string fulltexture = name + "^" + mineraltexture;
@@ -568,20 +886,9 @@ void TextureSource::buildMainAtlas()
        {
                std::string name = i.getNode()->getKey();
 
-               /*video::IImage *img = driver->createImageFromFile(
-                               getTexturePath(name.c_str()).c_str());
-               if(img == NULL)
-                       continue;
-               
-               core::dimension2d<u32> dim = img->getDimension();
-               // Make a copy with the right color format
-               video::IImage *img2 =
-                               driver->createImage(video::ECF_A8R8G8B8, dim);
-               img->copyTo(img2);
-               img->drop();*/
-               
                // Generate image by name
-               video::IImage *img2 = generate_image_from_scratch(name, m_device);
+               video::IImage *img2 = generate_image_from_scratch(name, m_device,
+                               &m_sourcecache);
                if(img2 == NULL)
                {
                        infostream<<"TextureSource::buildMainAtlas(): Couldn't generate texture atlas: Couldn't generate image \""<<name<<"\""<<std::endl;
@@ -658,8 +965,18 @@ void TextureSource::buildMainAtlas()
                        Add texture to caches
                */
                
-               // Get next id
+               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;
+               n = m_name_to_id.find(name);
+               // If it exists, we will replace the old definition
+               if(n){
+                       id = n->getValue();
+                       reuse_old_id = true;
+                       infostream<<"TextureSource::buildMainAtlas(): "
+                                       <<"Replacing old AtlasPointer"<<std::endl;
+               }
 
                // Create AtlasPointer
                AtlasPointer ap(id);
@@ -672,8 +989,11 @@ void TextureSource::buildMainAtlas()
 
                // Create SourceAtlasPointer and add to containers
                SourceAtlasPointer nap(name, ap, atlas_img, pos_in_atlas, dim);
-               m_atlaspointer_cache.push_back(nap);
-               m_name_to_id.insert(name, id);
+               if(reuse_old_id)
+                       m_atlaspointer_cache[id] = nap;
+               else
+                       m_atlaspointer_cache.push_back(nap);
+               m_name_to_id[name] = id;
                        
                // Increment position
                pos_in_atlas.Y += dim.Height + padding * 2;
@@ -712,7 +1032,7 @@ void TextureSource::buildMainAtlas()
 }
 
 video::IImage* generate_image_from_scratch(std::string name,
-               IrrlichtDevice *device)
+               IrrlichtDevice *device, SourceImageCache *sourcecache)
 {
        /*infostream<<"generate_image_from_scratch(): "
                        "\""<<name<<"\""<<std::endl;*/
@@ -755,7 +1075,8 @@ video::IImage* generate_image_from_scratch(std::string name,
                /*infostream<<"generate_image_from_scratch(): Calling itself recursively"
                                " to get base image of \""<<name<<"\" = \""
                 <<base_image_name<<"\""<<std::endl;*/
-               baseimg = generate_image_from_scratch(base_image_name, device);
+               baseimg = generate_image_from_scratch(base_image_name, device,
+                               sourcecache);
        }
        
        /*
@@ -767,7 +1088,7 @@ video::IImage* generate_image_from_scratch(std::string name,
        //infostream<<"last_part_of_name=\""<<last_part_of_name<<"\""<<std::endl;
        
        // Generate image according to part of name
-       if(generate_image(last_part_of_name, baseimg, device) == false)
+       if(!generate_image(last_part_of_name, baseimg, device, sourcecache))
        {
                infostream<<"generate_image_from_scratch(): "
                                "failed to generate \""<<last_part_of_name<<"\""
@@ -779,7 +1100,7 @@ video::IImage* generate_image_from_scratch(std::string name,
 }
 
 bool generate_image(std::string part_of_name, video::IImage *& baseimg,
-               IrrlichtDevice *device)
+               IrrlichtDevice *device, SourceImageCache *sourcecache)
 {
        video::IVideoDriver* driver = device->getVideoDriver();
        assert(driver);
@@ -787,18 +1108,12 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
        // Stuff starting with [ are special commands
        if(part_of_name[0] != '[')
        {
-               // A normal texture; load it from a file
-               std::string path = getTexturePath(part_of_name.c_str());
-               /*infostream<<"generate_image(): Loading path \""<<path
-                               <<"\""<<std::endl;*/
-               
-               video::IImage *image = driver->createImageFromFile(path.c_str());
+               video::IImage *image = sourcecache->getOrLoad(part_of_name, device);
 
                if(image == NULL)
                {
                        infostream<<"generate_image(): Could not load image \""
-                    <<part_of_name<<"\" from path \""<<path<<"\""
-                                       <<" while building texture"<<std::endl;
+                    <<part_of_name<<"\""<<" while building texture"<<std::endl;
 
                        //return false;
 
@@ -903,8 +1218,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                                It is an image with a number of cracking stages
                                horizontally tiled.
                        */
-                       video::IImage *img_crack = driver->createImageFromFile(
-                                       getTexturePath("crack.png").c_str());
+                       video::IImage *img_crack = sourcecache->getOrLoad("crack.png", device);
                
                        if(img_crack)
                        {
@@ -990,8 +1304,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                                infostream<<"Adding \""<<filename
                                                <<"\" to combined ("<<x<<","<<y<<")"
                                                <<std::endl;
-                               video::IImage *img = driver->createImageFromFile(
-                                               getTexturePath(filename.c_str()).c_str());
+                               video::IImage *img = sourcecache->getOrLoad(filename, device);
                                if(img)
                                {
                                        core::dimension2d<u32> dim = img->getDimension();
@@ -1052,10 +1365,10 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
 
                        std::string path = getTexturePath(filename.c_str());
 
-                       infostream<<"generate_image(): Loading path \""<<path
+                       infostream<<"generate_image(): Loading file \""<<filename
                                        <<"\""<<std::endl;
                        
-                       video::IImage *image = driver->createImageFromFile(path.c_str());
+                       video::IImage *image = sourcecache->getOrLoad(filename, device);
                        
                        if(image == NULL)
                        {
@@ -1101,17 +1414,15 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                        u32 b1 = stoi(sf.next(":"));
                        std::string filename = sf.next("");
 
-                       std::string path = getTexturePath(filename.c_str());
-
-                       infostream<<"generate_image(): Loading path \""<<path
+                       infostream<<"generate_image(): Loading file \""<<filename
                                        <<"\""<<std::endl;
                        
-                       video::IImage *image = driver->createImageFromFile(path.c_str());
+                       video::IImage *image = sourcecache->getOrLoad(filename, device);
                        
                        if(image == NULL)
                        {
-                               infostream<<"generate_image(): Loading path \""
-                                               <<path<<"\" failed"<<std::endl;
+                               infostream<<"generate_image(): Loading file \""
+                                               <<filename<<"\" failed"<<std::endl;
                        }
                        else
                        {
@@ -1160,17 +1471,15 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                        u32 b2 = stoi(sf.next(":"));
                        std::string filename = sf.next("");
 
-                       std::string path = getTexturePath(filename.c_str());
-
-                       infostream<<"generate_image(): Loading path \""<<path
+                       infostream<<"generate_image(): Loading filename \""<<filename
                                        <<"\""<<std::endl;
                        
-                       video::IImage *image = driver->createImageFromFile(path.c_str());
+                       video::IImage *image = sourcecache->getOrLoad(filename, device);
                        
                        if(image == NULL)
                        {
-                               infostream<<"generate_image(): Loading path \""
-                                               <<path<<"\" failed"<<std::endl;
+                               infostream<<"generate_image(): Loading file \""
+                                               <<filename<<"\" failed"<<std::endl;
                        }
                        else
                        {
@@ -1223,14 +1532,14 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                        std::string imagename_right = sf.next("{");
 
 #if 1
-                       //TODO
+                       // TODO: Create cube with different textures on different sides
 
                        if(driver->queryFeature(video::EVDF_RENDER_TO_TARGET) == false)
                        {
                                infostream<<"generate_image(): EVDF_RENDER_TO_TARGET"
                                                " not supported. Creating fallback image"<<std::endl;
                                baseimg = generate_image_from_scratch(
-                                               imagename_top, device);
+                                               imagename_top, device, sourcecache);
                                return true;
                        }
                        
@@ -1241,14 +1550,15 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                        
                        // Generate images for the faces of the cube
                        video::IImage *img_top = generate_image_from_scratch(
-                                       imagename_top, device);
+                                       imagename_top, device, sourcecache);
                        video::IImage *img_left = generate_image_from_scratch(
-                                       imagename_left, device);
+                                       imagename_left, device, sourcecache);
                        video::IImage *img_right = generate_image_from_scratch(
-                                       imagename_right, device);
+                                       imagename_right, device, sourcecache);
                        assert(img_top && img_left && img_right);
 
-                       // TODO: Create textures from images
+                       // Create textures from images
+                       // TODO: Use them all
                        video::ITexture *texture_top = driver->addTexture(
                                        (imagename_top + "__temp__").c_str(), img_top);
                        assert(texture_top);
@@ -1319,7 +1629,8 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                        // Unset render target
                        driver->setRenderTarget(0, true, true, 0);
 
-                       //TODO: Free textures of images
+                       // Free textures of images
+                       // TODO: When all are used, free them all
                        driver->removeTexture(texture_top);
                        
                        // Create image of render target