]> git.lizzy.rs Git - minetest.git/blobdiff - src/tile.cpp
Set the BS constant to be floating-point; this removes the need for floating point...
[minetest.git] / src / tile.cpp
index 71e0c9638a15b9778206a587601cfeed0de6ab21..32de8cda23cbd6dc079390b2da48c23610972337 100644 (file)
@@ -22,6 +22,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "main.h" // for g_settings
 #include "filesys.h"
 #include "utility.h"
+#include "settings.h"
+#include <ICameraSceneNode.h>
+#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
 
 /*
        A cache from texture name to texture path
@@ -112,10 +118,10 @@ std::string getTexturePath(const std::string &filename)
        /*
                Check from texture_path
        */
-       std::string texture_path = g_settings.get("texture_path");
+       std::string texture_path = g_settings->get("texture_path");
        if(texture_path != "")
        {
-               std::string testpath = texture_path + '/' + filename;
+               std::string testpath = texture_path + DIR_DELIM + filename;
                // Check all filename extensions. Returns "" if not found.
                fullpath = getImagePath(testpath);
        }
@@ -125,7 +131,8 @@ std::string getTexturePath(const std::string &filename)
        */
        if(fullpath == "")
        {
-               std::string testpath = porting::getDataPath(filename.c_str());
+               std::string rel_path = std::string("textures")+DIR_DELIM+filename;
+               std::string testpath = porting::path_data + DIR_DELIM + rel_path;
                // Check all filename extensions. Returns "" if not found.
                fullpath = getImagePath(testpath);
        }
@@ -157,10 +164,10 @@ TextureSource::TextureSource(IrrlichtDevice *device):
        m_name_to_id[""] = 0;
 
        // Build main texture atlas
-       if(g_settings.getBool("enable_texture_atlas"))
+       if(g_settings->getBool("enable_texture_atlas"))
                buildMainAtlas();
        else
-               dstream<<"INFO: Not building texture atlas."<<std::endl;
+               infostream<<"Not building texture atlas."<<std::endl;
 }
 
 TextureSource::~TextureSource()
@@ -177,9 +184,9 @@ void TextureSource::processQueue()
                GetRequest<std::string, u32, u8, u8>
                                request = m_get_texture_queue.pop();
 
-               dstream<<"INFO: TextureSource::processQueue(): "
+               infostream<<"TextureSource::processQueue(): "
                                <<"got texture request with "
-                               <<"name="<<request.key
+                               <<"name=\""<<request.key<<"\""
                                <<std::endl;
 
                GetResult<std::string, u32, u8, u8>
@@ -194,7 +201,7 @@ void TextureSource::processQueue()
 
 u32 TextureSource::getTextureId(const std::string &name)
 {
-       //dstream<<"INFO: getTextureId(): name="<<name<<std::endl;
+       //infostream<<"getTextureId(): \""<<name<<"\""<<std::endl;
 
        {
                /*
@@ -218,7 +225,7 @@ u32 TextureSource::getTextureId(const std::string &name)
        }
        else
        {
-               dstream<<"INFO: getTextureId(): Queued: name="<<name<<std::endl;
+               infostream<<"getTextureId(): Queued: name=\""<<name<<"\""<<std::endl;
 
                // We're gonna ask the result to be put into here
                ResultQueue<std::string, u32, u8, u8> result_queue;
@@ -226,8 +233,8 @@ u32 TextureSource::getTextureId(const std::string &name)
                // Throw a request in
                m_get_texture_queue.add(name, 0, 0, &result_queue);
                
-               dstream<<"INFO: Waiting for texture from main thread, name="
-                               <<name<<std::endl;
+               infostream<<"Waiting for texture from main thread, name=\""
+                               <<name<<"\""<<std::endl;
                
                try
                {
@@ -242,12 +249,12 @@ u32 TextureSource::getTextureId(const std::string &name)
                }
                catch(ItemNotFoundException &e)
                {
-                       dstream<<"WARNING: Waiting for texture timed out."<<std::endl;
+                       infostream<<"Waiting for texture timed out."<<std::endl;
                        return 0;
                }
        }
        
-       dstream<<"WARNING: getTextureId(): Failed"<<std::endl;
+       infostream<<"getTextureId(): Failed"<<std::endl;
 
        return 0;
 }
@@ -276,12 +283,12 @@ video::IImage* generate_image_from_scratch(std::string name,
 */
 u32 TextureSource::getTextureIdDirect(const std::string &name)
 {
-       dstream<<"INFO: getTextureIdDirect(): name="<<name<<std::endl;
+       //infostream<<"getTextureIdDirect(): name=\""<<name<<"\""<<std::endl;
 
        // Empty name means texture 0
        if(name == "")
        {
-               dstream<<"INFO: getTextureIdDirect(): name is empty"<<std::endl;
+               infostream<<"getTextureIdDirect(): name is empty"<<std::endl;
                return 0;
        }
        
@@ -290,7 +297,7 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
        */
        if(get_current_thread_id() != m_main_thread)
        {
-               dstream<<"ERROR: TextureSource::getTextureIdDirect() "
+               errorstream<<"TextureSource::getTextureIdDirect() "
                                "called not from main thread"<<std::endl;
                return 0;
        }
@@ -305,14 +312,14 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
                n = m_name_to_id.find(name);
                if(n != NULL)
                {
-                       dstream<<"INFO: getTextureIdDirect(): name="<<name
-                                       <<" found in cache"<<std::endl;
+                       infostream<<"getTextureIdDirect(): \""<<name
+                                       <<"\" found in cache"<<std::endl;
                        return n->getValue();
                }
        }
 
-       dstream<<"INFO: getTextureIdDirect(): name="<<name
-                       <<" NOT found in cache. Creating it."<<std::endl;
+       infostream<<"getTextureIdDirect(): \""<<name
+                       <<"\" NOT found in cache. Creating it."<<std::endl;
        
        /*
                Get the base image
@@ -346,12 +353,13 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
        {
                // Construct base name
                base_image_name = name.substr(0, last_separator_position);
-               dstream<<"INFO: getTextureIdDirect(): Calling itself recursively"
-                               " to get base image, name="<<base_image_name<<std::endl;
+               /*infostream<<"getTextureIdDirect(): Calling itself recursively"
+                               " to get base image of \""<<name<<"\" = \""
+                <<base_image_name<<"\""<<std::endl;*/
                base_image_id = getTextureIdDirect(base_image_name);
        }
        
-       dstream<<"base_image_id="<<base_image_id<<std::endl;
+       //infostream<<"base_image_id="<<base_image_id<<std::endl;
        
        video::IVideoDriver* driver = m_device->getVideoDriver();
        assert(driver);
@@ -374,7 +382,7 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
                
                if(image == NULL)
                {
-                       dstream<<"WARNING: getTextureIdDirect(): NULL image in "
+                       infostream<<"getTextureIdDirect(): NULL image in "
                                        <<"cache: \""<<base_image_name<<"\""
                                        <<std::endl;
                }
@@ -393,9 +401,9 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
                                        core::rect<s32>(pos_from, dim) // from
                        );
 
-                       dstream<<"INFO: getTextureIdDirect(): Loaded \""
+                       /*infostream<<"getTextureIdDirect(): Loaded \""
                                        <<base_image_name<<"\" from image cache"
-                                       <<std::endl;
+                                       <<std::endl;*/
                }
        }
        
@@ -405,12 +413,12 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
        */
 
        std::string last_part_of_name = name.substr(last_separator_position+1);
-       dstream<<"last_part_of_name="<<last_part_of_name<<std::endl;
+       //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)
        {
-               dstream<<"INFO: getTextureIdDirect(): "
+               infostream<<"getTextureIdDirect(): "
                                "failed to generate \""<<last_part_of_name<<"\""
                                <<std::endl;
        }
@@ -418,7 +426,7 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
        // If no resulting image, print a warning
        if(baseimg == NULL)
        {
-               dstream<<"WARNING: getTextureIdDirect(): baseimg is NULL (attempted to"
+               infostream<<"getTextureIdDirect(): baseimg is NULL (attempted to"
                                " create texture \""<<name<<"\""<<std::endl;
        }
        
@@ -447,8 +455,8 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
        m_atlaspointer_cache.push_back(nap);
        m_name_to_id.insert(name, id);
 
-       dstream<<"INFO: getTextureIdDirect(): name="<<name
-                       <<": succesfully returning id="<<id<<std::endl;
+       /*infostream<<"getTextureIdDirect(): "
+                       <<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;*/
        
        return id;
 }
@@ -459,7 +467,7 @@ std::string TextureSource::getTextureName(u32 id)
 
        if(id >= m_atlaspointer_cache.size())
        {
-               dstream<<"WARNING: TextureSource::getTextureName(): id="<<id
+               infostream<<"TextureSource::getTextureName(): id="<<id
                                <<" >= m_atlaspointer_cache.size()="
                                <<m_atlaspointer_cache.size()<<std::endl;
                return "";
@@ -481,7 +489,7 @@ AtlasPointer TextureSource::getTexture(u32 id)
 
 void TextureSource::buildMainAtlas() 
 {
-       dstream<<"TextureSource::buildMainAtlas()"<<std::endl;
+       infostream<<"TextureSource::buildMainAtlas()"<<std::endl;
 
        //return; // Disable (for testing)
        
@@ -494,53 +502,71 @@ void TextureSource::buildMainAtlas()
        core::dimension2d<u32> atlas_dim(1024,1024);
        video::IImage *atlas_img =
                        driver->createImage(video::ECF_A8R8G8B8, atlas_dim);
-       assert(atlas_img);
+       //assert(atlas_img);
+       if(atlas_img == NULL)
+       {
+               errorstream<<"TextureSource::buildMainAtlas(): Failed to create atlas "
+                               "image; not building texture atlas."<<std::endl;
+               return;
+       }
 
        /*
-               A list of stuff to add. This should contain as much of the
-               stuff shown in game as possible, to minimize texture changes.
+               Grab list of stuff to include in the texture atlas from the
+               main content features
        */
 
-       core::array<std::string> sourcelist;
-
-       sourcelist.push_back("stone.png");
-       sourcelist.push_back("mud.png");
-       sourcelist.push_back("sand.png");
-       sourcelist.push_back("sandstone.png");
-       sourcelist.push_back("clay.png");
-       sourcelist.push_back("brick.png");
-       sourcelist.push_back("grass.png");
-       sourcelist.push_back("grass_footsteps.png");
-       sourcelist.push_back("tree.png");
-       sourcelist.push_back("tree_top.png");
-       sourcelist.push_back("water.png");
-       sourcelist.push_back("leaves.png");
-       sourcelist.push_back("cactus_side.png");
-       sourcelist.push_back("cactus_top.png");
-       sourcelist.push_back("glass.png");
-       sourcelist.push_back("mud.png^grass_side.png");
-       sourcelist.push_back("cobble.png");
-       
-       sourcelist.push_back("stone.png^mineral_coal.png");
-       sourcelist.push_back("stone.png^mineral_iron.png");
-       sourcelist.push_back("mud.png^mineral_coal.png");
-       sourcelist.push_back("mud.png^mineral_iron.png");
-       sourcelist.push_back("sand.png^mineral_coal.png");
-       sourcelist.push_back("sand.png^mineral_iron.png");
+       core::map<std::string, bool> sourcelist;
+
+       for(u16 j=0; j<MAX_CONTENT+1; j++)
+       {
+               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++)
+               {
+                       std::string name = i.getNode()->getKey();
+                       sourcelist[name] = true;
+
+                       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;
+                                       sourcelist[fulltexture] = true;
+                               }
+                       }
+               }
+       }
        
+       infostream<<"Creating texture atlas out of textures: ";
+       for(core::map<std::string, bool>::Iterator
+                       i = sourcelist.getIterator();
+                       i.atEnd() == false; i++)
+       {
+               std::string name = i.getNode()->getKey();
+               infostream<<"\""<<name<<"\" ";
+       }
+       infostream<<std::endl;
+
        // Padding to disallow texture bleeding
        s32 padding = 16;
 
+       s32 column_width = 256;
+       s32 column_padding = 16;
+
        /*
                First pass: generate almost everything
        */
        core::position2d<s32> pos_in_atlas(0,0);
        
-       pos_in_atlas.Y += padding;
+       pos_in_atlas.Y = padding;
 
-       for(u32 i=0; i<sourcelist.size(); i++)
+       for(core::map<std::string, bool>::Iterator
+                       i = sourcelist.getIterator();
+                       i.atEnd() == false; i++)
        {
-               std::string name = sourcelist[i];
+               std::string name = i.getNode()->getKey();
 
                /*video::IImage *img = driver->createImageFromFile(
                                getTexturePath(name.c_str()).c_str());
@@ -558,7 +584,7 @@ void TextureSource::buildMainAtlas()
                video::IImage *img2 = generate_image_from_scratch(name, m_device);
                if(img2 == NULL)
                {
-                       dstream<<"WARNING: TextureSource::buildMainAtlas(): Couldn't generate texture atlas: Couldn't generate image \""<<name<<"\""<<std::endl;
+                       infostream<<"TextureSource::buildMainAtlas(): Couldn't generate texture atlas: Couldn't generate image \""<<name<<"\""<<std::endl;
                        continue;
                }
 
@@ -569,22 +595,31 @@ void TextureSource::buildMainAtlas()
                if(dim.Width > max_size_in_atlas.Width
                || dim.Height > max_size_in_atlas.Height)
                {
-                       dstream<<"INFO: TextureSource::buildMainAtlas(): Not adding "
+                       infostream<<"TextureSource::buildMainAtlas(): Not adding "
                                        <<"\""<<name<<"\" because image is large"<<std::endl;
                        continue;
                }
 
-               // Stop making atlas if atlas is full
+               // Wrap columns and stop making atlas if atlas is full
                if(pos_in_atlas.Y + dim.Height > atlas_dim.Height)
                {
-                       dstream<<"WARNING: TextureSource::buildMainAtlas(): "
-                                       <<"Atlas is full, not adding more textures."
-                                       <<std::endl;
-                       break;
+                       if(pos_in_atlas.X > (s32)atlas_dim.Width - 256 - padding){
+                               errorstream<<"TextureSource::buildMainAtlas(): "
+                                               <<"Atlas is full, not adding more textures."
+                                               <<std::endl;
+                               break;
+                       }
+                       pos_in_atlas.Y = padding;
+                       pos_in_atlas.X += column_width + column_padding;
                }
                
+        infostream<<"TextureSource::buildMainAtlas(): Adding \""<<name
+                <<"\" to texture atlas"<<std::endl;
+
                // Tile it a few times in the X direction
-               u16 xwise_tiling = 16;
+               u16 xwise_tiling = column_width / dim.Width;
+               if(xwise_tiling > 16) // Limit to 16 (more gives no benefit)
+                       xwise_tiling = 16;
                for(u32 j=0; j<xwise_tiling; j++)
                {
                        // Copy the copy to the atlas
@@ -612,7 +647,7 @@ void TextureSource::buildMainAtlas()
                                dst_y = -y0 + pos_in_atlas.Y-1;
                                src_y = pos_in_atlas.Y;
                        }
-                       s32 x = x0 + pos_in_atlas.X * dim.Width;
+                       s32 x = x0 + pos_in_atlas.X;
                        video::SColor c = atlas_img->getPixel(x, src_y);
                        atlas_img->setPixel(x,dst_y,c);
                }
@@ -653,28 +688,34 @@ void TextureSource::buildMainAtlas()
        /*
                Second pass: set texture pointer in generated AtlasPointers
        */
-       for(u32 i=0; i<sourcelist.size(); i++)
+       for(core::map<std::string, bool>::Iterator
+                       i = sourcelist.getIterator();
+                       i.atEnd() == false; i++)
        {
-               std::string name = sourcelist[i];
+               std::string name = i.getNode()->getKey();
                if(m_name_to_id.find(name) == NULL)
                        continue;
                u32 id = m_name_to_id[name];
-               //dstream<<"id of name "<<name<<" is "<<id<<std::endl;
+               //infostream<<"id of name "<<name<<" is "<<id<<std::endl;
                m_atlaspointer_cache[id].a.atlas = t;
        }
 
        /*
                Write image to file so that it can be inspected
        */
-       /*driver->writeImageToFile(atlas_img, 
-                       getTexturePath("main_atlas.png").c_str());*/
+       /*std::string atlaspath = porting::path_userdata
+                       + DIR_DELIM + "generated_texture_atlas.png";
+       infostream<<"Removing and writing texture atlas for inspection to "
+                       <<atlaspath<<std::endl;
+       fs::RecursiveDelete(atlaspath);
+       driver->writeImageToFile(atlas_img, atlaspath.c_str());*/
 }
 
 video::IImage* generate_image_from_scratch(std::string name,
                IrrlichtDevice *device)
 {
-       dstream<<"INFO: generate_image_from_scratch(): "
-                       "name="<<name<<std::endl;
+       /*infostream<<"generate_image_from_scratch(): "
+                       "\""<<name<<"\""<<std::endl;*/
        
        video::IVideoDriver* driver = device->getVideoDriver();
        assert(driver);
@@ -698,7 +739,7 @@ video::IImage* generate_image_from_scratch(std::string name,
                }
        }
 
-       /*dstream<<"INFO: generate_image_from_scratch(): "
+       /*infostream<<"generate_image_from_scratch(): "
                        <<"last_separator_position="<<last_separator_position
                        <<std::endl;*/
 
@@ -711,8 +752,9 @@ video::IImage* generate_image_from_scratch(std::string name,
        {
                // Construct base name
                base_image_name = name.substr(0, last_separator_position);
-               dstream<<"INFO: generate_image_from_scratch(): Calling itself recursively"
-                               " to get base image, name="<<base_image_name<<std::endl;
+               /*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);
        }
        
@@ -722,12 +764,12 @@ video::IImage* generate_image_from_scratch(std::string name,
        */
 
        std::string last_part_of_name = name.substr(last_separator_position+1);
-       dstream<<"last_part_of_name="<<last_part_of_name<<std::endl;
+       //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)
        {
-               dstream<<"INFO: generate_image_from_scratch(): "
+               infostream<<"generate_image_from_scratch(): "
                                "failed to generate \""<<last_part_of_name<<"\""
                                <<std::endl;
                return NULL;
@@ -747,21 +789,21 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
        {
                // A normal texture; load it from a file
                std::string path = getTexturePath(part_of_name.c_str());
-               dstream<<"INFO: getTextureIdDirect(): Loading path \""<<path
-                               <<"\""<<std::endl;
+               /*infostream<<"generate_image(): Loading path \""<<path
+                               <<"\""<<std::endl;*/
                
                video::IImage *image = driver->createImageFromFile(path.c_str());
 
                if(image == NULL)
                {
-                       dstream<<"WARNING: Could not load image \""<<part_of_name
-                                       <<"\" from path \""<<path<<"\""
+                       infostream<<"generate_image(): Could not load image \""
+                    <<part_of_name<<"\" from path \""<<path<<"\""
                                        <<" while building texture"<<std::endl;
 
                        //return false;
 
-                       dstream<<"WARNING: Creating a dummy"<<" image for \""
-                                       <<part_of_name<<"\""<<std::endl;
+                       infostream<<"generate_image(): Creating a dummy"
+                    <<" image for \""<<part_of_name<<"\""<<std::endl;
 
                        // Just create a dummy image
                        //core::dimension2d<u32> dim(2,2);
@@ -785,7 +827,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                // If base image is NULL, load as base.
                if(baseimg == NULL)
                {
-                       dstream<<"INFO: Setting "<<part_of_name<<" as base"<<std::endl;
+                       //infostream<<"Setting "<<part_of_name<<" as base"<<std::endl;
                        /*
                                Copy it this way to get an alpha channel.
                                Otherwise images with alpha cannot be blitted on 
@@ -799,7 +841,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                // Else blit on base.
                else
                {
-                       dstream<<"INFO: Blitting "<<part_of_name<<" on base"<<std::endl;
+                       //infostream<<"Blitting "<<part_of_name<<" on base"<<std::endl;
                        // Size of the copied area
                        core::dimension2d<u32> dim = image->getDimension();
                        //core::dimension2d<u32> dim(16,16);
@@ -820,7 +862,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
        {
                // A special texture modification
 
-               dstream<<"INFO: getTextureIdDirect(): generating special "
+               infostream<<"generate_image(): generating special "
                                <<"modification \""<<part_of_name<<"\""
                                <<std::endl;
                
@@ -843,9 +885,9 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                {
                        if(baseimg == NULL)
                        {
-                               dstream<<"WARNING: getTextureIdDirect(): baseimg==NULL "
-                                               <<"for part_of_name="<<part_of_name
-                                               <<", cancelling."<<std::endl;
+                               infostream<<"generate_image(): baseimg==NULL "
+                                               <<"for part_of_name=\""<<part_of_name
+                                               <<"\", cancelling."<<std::endl;
                                return false;
                        }
                        
@@ -937,7 +979,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                        sf.next(":");
                        u32 w0 = stoi(sf.next("x"));
                        u32 h0 = stoi(sf.next(":"));
-                       dstream<<"INFO: combined w="<<w0<<" h="<<h0<<std::endl;
+                       infostream<<"combined w="<<w0<<" h="<<h0<<std::endl;
                        core::dimension2d<u32> dim(w0,h0);
                        baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
                        while(sf.atend() == false)
@@ -945,7 +987,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                                u32 x = stoi(sf.next(","));
                                u32 y = stoi(sf.next("="));
                                std::string filename = sf.next(":");
-                               dstream<<"INFO: Adding \""<<filename
+                               infostream<<"Adding \""<<filename
                                                <<"\" to combined ("<<x<<","<<y<<")"
                                                <<std::endl;
                                video::IImage *img = driver->createImageFromFile(
@@ -953,7 +995,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                                if(img)
                                {
                                        core::dimension2d<u32> dim = img->getDimension();
-                                       dstream<<"INFO: Size "<<dim.Width
+                                       infostream<<"Size "<<dim.Width
                                                        <<"x"<<dim.Height<<std::endl;
                                        core::position2d<s32> pos_base(x, y);
                                        video::IImage *img2 =
@@ -968,7 +1010,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                                }
                                else
                                {
-                                       dstream<<"WARNING: img==NULL"<<std::endl;
+                                       infostream<<"img==NULL"<<std::endl;
                                }
                        }
                }
@@ -980,9 +1022,9 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                {
                        if(baseimg == NULL)
                        {
-                               dstream<<"WARNING: getTextureIdDirect(): baseimg==NULL "
-                                               <<"for part_of_name="<<part_of_name
-                                               <<", cancelling."<<std::endl;
+                               infostream<<"generate_image(): baseimg==NULL "
+                                               <<"for part_of_name=\""<<part_of_name
+                                               <<"\", cancelling."<<std::endl;
                                return false;
                        }
 
@@ -1000,9 +1042,9 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                {
                        if(baseimg != NULL)
                        {
-                               dstream<<"WARNING: getTextureIdDirect(): baseimg!=NULL "
-                                               <<"for part_of_name="<<part_of_name
-                                               <<", cancelling."<<std::endl;
+                               infostream<<"generate_image(): baseimg!=NULL "
+                                               <<"for part_of_name=\""<<part_of_name
+                                               <<"\", cancelling."<<std::endl;
                                return false;
                        }
 
@@ -1010,14 +1052,14 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
 
                        std::string path = getTexturePath(filename.c_str());
 
-                       dstream<<"INFO: getTextureIdDirect(): Loading path \""<<path
+                       infostream<<"generate_image(): Loading path \""<<path
                                        <<"\""<<std::endl;
                        
                        video::IImage *image = driver->createImageFromFile(path.c_str());
                        
                        if(image == NULL)
                        {
-                               dstream<<"WARNING: getTextureIdDirect(): Loading path \""
+                               infostream<<"generate_image(): Loading path \""
                                                <<path<<"\" failed"<<std::endl;
                        }
                        else
@@ -1039,6 +1081,122 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                                image->drop();
                        }
                }
+               /*
+                       "[makealpha:R,G,B:filename.png"
+                       Use an image with converting one color to transparent.
+               */
+               else if(part_of_name.substr(0,11) == "[makealpha:")
+               {
+                       if(baseimg != NULL)
+                       {
+                               infostream<<"generate_image(): baseimg!=NULL "
+                                               <<"for part_of_name=\""<<part_of_name
+                                               <<"\", cancelling."<<std::endl;
+                               return false;
+                       }
+
+                       Strfnd sf(part_of_name.substr(11));
+                       u32 r1 = stoi(sf.next(","));
+                       u32 g1 = stoi(sf.next(","));
+                       u32 b1 = stoi(sf.next(":"));
+                       std::string filename = sf.next("");
+
+                       std::string path = getTexturePath(filename.c_str());
+
+                       infostream<<"generate_image(): Loading path \""<<path
+                                       <<"\""<<std::endl;
+                       
+                       video::IImage *image = driver->createImageFromFile(path.c_str());
+                       
+                       if(image == NULL)
+                       {
+                               infostream<<"generate_image(): Loading path \""
+                                               <<path<<"\" failed"<<std::endl;
+                       }
+                       else
+                       {
+                               core::dimension2d<u32> dim = image->getDimension();
+                               baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
+                               
+                               // Blit
+                               image->copyTo(baseimg);
+
+                               image->drop();
+
+                               for(u32 y=0; y<dim.Height; y++)
+                               for(u32 x=0; x<dim.Width; x++)
+                               {
+                                       video::SColor c = baseimg->getPixel(x,y);
+                                       u32 r = c.getRed();
+                                       u32 g = c.getGreen();
+                                       u32 b = c.getBlue();
+                                       if(!(r == r1 && g == g1 && b == b1))
+                                               continue;
+                                       c.setAlpha(0);
+                                       baseimg->setPixel(x,y,c);
+                               }
+                       }
+               }
+               /*
+                       "[makealpha2:R,G,B;R2,G2,B2:filename.png"
+                       Use an image with converting two colors to transparent.
+               */
+               else if(part_of_name.substr(0,12) == "[makealpha2:")
+               {
+                       if(baseimg != NULL)
+                       {
+                               infostream<<"generate_image(): baseimg!=NULL "
+                                               <<"for part_of_name=\""<<part_of_name
+                                               <<"\", cancelling."<<std::endl;
+                               return false;
+                       }
+
+                       Strfnd sf(part_of_name.substr(12));
+                       u32 r1 = stoi(sf.next(","));
+                       u32 g1 = stoi(sf.next(","));
+                       u32 b1 = stoi(sf.next(";"));
+                       u32 r2 = stoi(sf.next(","));
+                       u32 g2 = stoi(sf.next(","));
+                       u32 b2 = stoi(sf.next(":"));
+                       std::string filename = sf.next("");
+
+                       std::string path = getTexturePath(filename.c_str());
+
+                       infostream<<"generate_image(): Loading path \""<<path
+                                       <<"\""<<std::endl;
+                       
+                       video::IImage *image = driver->createImageFromFile(path.c_str());
+                       
+                       if(image == NULL)
+                       {
+                               infostream<<"generate_image(): Loading path \""
+                                               <<path<<"\" failed"<<std::endl;
+                       }
+                       else
+                       {
+                               core::dimension2d<u32> dim = image->getDimension();
+                               baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
+
+                               // Blit
+                               image->copyTo(baseimg);
+
+                               image->drop();
+                               
+                               for(u32 y=0; y<dim.Height; y++)
+                               for(u32 x=0; x<dim.Width; x++)
+                               {
+                                       video::SColor c = baseimg->getPixel(x,y);
+                                       u32 r = c.getRed();
+                                       u32 g = c.getGreen();
+                                       u32 b = c.getBlue();
+                                       if(!(r == r1 && g == g1 && b == b1) &&
+                                          !(r == r2 && g == g2 && b == b2))
+                                               continue;
+                                       c.setAlpha(0);
+                                       baseimg->setPixel(x,y,c);
+                               }
+                       }
+               }
                /*
                        [inventorycube{topimage{leftimage{rightimage
                        In every subimage, replace ^ with &.
@@ -1051,9 +1209,9 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                {
                        if(baseimg != NULL)
                        {
-                               dstream<<"WARNING: getTextureIdDirect(): baseimg!=NULL "
-                                               <<"for part_of_name="<<part_of_name
-                                               <<", cancelling."<<std::endl;
+                               infostream<<"generate_image(): baseimg!=NULL "
+                                               <<"for part_of_name=\""<<part_of_name
+                                               <<"\", cancelling."<<std::endl;
                                return false;
                        }
 
@@ -1069,7 +1227,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
 
                        if(driver->queryFeature(video::EVDF_RENDER_TO_TARGET) == false)
                        {
-                               dstream<<"WARNING: getTextureIdDirect(): EVDF_RENDER_TO_TARGET"
+                               infostream<<"generate_image(): EVDF_RENDER_TO_TARGET"
                                                " not supported. Creating fallback image"<<std::endl;
                                baseimg = generate_image_from_scratch(
                                                imagename_top, device);
@@ -1078,7 +1236,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                        
                        u32 w0 = 64;
                        u32 h0 = 64;
-                       dstream<<"INFO: inventorycube w="<<w0<<" h="<<h0<<std::endl;
+                       //infostream<<"inventorycube w="<<w0<<" h="<<h0<<std::endl;
                        core::dimension2d<u32> dim(w0,h0);
                        
                        // Generate images for the faces of the cube
@@ -1180,7 +1338,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                }
                else
                {
-                       dstream<<"WARNING: getTextureIdDirect(): Invalid "
+                       infostream<<"generate_image(): Invalid "
                                        " modification: \""<<part_of_name<<"\""<<std::endl;
                }
        }