Send Position packet on event, don't check it at each AsyncRunStep.
[oweals/minetest.git] / src / tile.cpp
index 7cb39eabfbf39cbb99a033b55482e0617c8aa22f..81b362d616f2c61e249fea235c1dca49b996bbf9 100644 (file)
@@ -18,19 +18,22 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 */
 
 #include "tile.h"
+
+#include <ICameraSceneNode.h>
+#include "util/string.h"
+#include "util/container.h"
+#include "util/thread.h"
+#include "util/numeric.h"
 #include "irrlichttypes_extrabloated.h"
 #include "debug.h"
 #include "main.h" // for g_settings
 #include "filesys.h"
 #include "settings.h"
 #include "mesh.h"
-#include <ICameraSceneNode.h>
 #include "log.h"
 #include "gamedef.h"
-#include "util/string.h"
-#include "util/container.h"
-#include "util/thread.h"
-#include "util/numeric.h"
+#include "strfnd.h"
+#include "util/string.h" // for parseColorString()
 
 #ifdef __ANDROID__
 #include <GLES/gl.h>
@@ -51,23 +54,23 @@ MutexedMap<std::string, std::string> g_texturename_to_path_cache;
 */
 static bool replace_ext(std::string &path, const char *ext)
 {
-       if(ext == NULL)
+       if (ext == NULL)
                return false;
        // Find place of last dot, fail if \ or / found.
        s32 last_dot_i = -1;
-       for(s32 i=path.size()-1; i>=0; i--)
+       for (s32 i=path.size()-1; i>=0; i--)
        {
-               if(path[i] == '.')
+               if (path[i] == '.')
                {
                        last_dot_i = i;
                        break;
                }
 
-               if(path[i] == '\\' || path[i] == '/')
+               if (path[i] == '\\' || path[i] == '/')
                        break;
        }
        // If not found, return an empty string
-       if(last_dot_i == -1)
+       if (last_dot_i == -1)
                return false;
        // Else make the new path
        path = path.substr(0, last_dot_i+1) + ext;
@@ -89,15 +92,15 @@ std::string getImagePath(std::string path)
                NULL
        };
        // If there is no extension, add one
-       if(removeStringEnd(path, extensions) == "")
+       if (removeStringEnd(path, extensions) == "")
                path = path + ".png";
        // Check paths until something is found to exist
        const char **ext = extensions;
        do{
                bool r = replace_ext(path, *ext);
-               if(r == false)
+               if (r == false)
                        return "";
-               if(fs::PathExists(path))
+               if (fs::PathExists(path))
                        return path;
        }
        while((++ext) != NULL);
@@ -122,14 +125,14 @@ std::string getTexturePath(const std::string &filename)
                Check from cache
        */
        bool incache = g_texturename_to_path_cache.get(filename, &fullpath);
-       if(incache)
+       if (incache)
                return fullpath;
 
        /*
                Check from texture_path
        */
        std::string texture_path = g_settings->get("texture_path");
-       if(texture_path != "")
+       if (texture_path != "")
        {
                std::string testpath = texture_path + DIR_DELIM + filename;
                // Check all filename extensions. Returns "" if not found.
@@ -139,7 +142,7 @@ std::string getTexturePath(const std::string &filename)
        /*
                Check from default data directory
        */
-       if(fullpath == "")
+       if (fullpath == "")
        {
                std::string base_path = porting::path_share + DIR_DELIM + "textures"
                                + DIR_DELIM + "base" + DIR_DELIM + "pack";
@@ -187,7 +190,7 @@ class SourceImageCache
 {
 public:
        ~SourceImageCache() {
-               for(std::map<std::string, video::IImage*>::iterator iter = m_images.begin();
+               for (std::map<std::string, video::IImage*>::iterator iter = m_images.begin();
                                iter != m_images.end(); iter++) {
                        iter->second->drop();
                }
@@ -200,8 +203,8 @@ public:
                // Remove old image
                std::map<std::string, video::IImage*>::iterator n;
                n = m_images.find(name);
-               if(n != m_images.end()){
-                       if(n->second)
+               if (n != m_images.end()){
+                       if (n->second)
                                n->second->drop();
                }
 
@@ -209,11 +212,11 @@ public:
                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 != ""){
+               if (prefer_local){
+                       std::string path = getTexturePath(name);
+                       if (path != ""){
                                video::IImage *img2 = driver->createImageFromFile(path.c_str());
-                               if(img2){
+                               if (img2){
                                        toadd = img2;
                                        need_to_grab = false;
                                }
@@ -228,7 +231,7 @@ public:
        {
                std::map<std::string, video::IImage*>::iterator n;
                n = m_images.find(name);
-               if(n != m_images.end())
+               if (n != m_images.end())
                        return n->second;
                return NULL;
        }
@@ -237,13 +240,13 @@ public:
        {
                std::map<std::string, video::IImage*>::iterator n;
                n = m_images.find(name);
-               if(n != m_images.end()){
+               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());
-               if(path == ""){
+               std::string path = getTexturePath(name);
+               if (path == ""){
                        infostream<<"SourceImageCache::getOrLoad(): No path found for \""
                                        <<name<<"\""<<std::endl;
                        return NULL;
@@ -252,7 +255,7 @@ public:
                                <<"\""<<std::endl;
                video::IImage *img = driver->createImageFromFile(path.c_str());
 
-               if(img){
+               if (img){
                        m_images[name] = img;
                        img->grab(); // Grab for caller
                }
@@ -306,27 +309,12 @@ public:
 
        /*
                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^mineral_coal.png"
-               "stone.png^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.
+               - if main thread, generates the texture, adds to cache and returns id.
+               - if other thread, adds to request queue and waits for main thread.
 
                The id 0 points to a NULL texture. It is returned in case of error.
        */
-       u32 getTextureIdDirect(const std::string &name);
+       u32 getTextureId(const std::string &name);
 
        // Finds out the name of a cached texture.
        std::string getTextureName(u32 id);
@@ -353,7 +341,7 @@ public:
        {
                bool is_known = false;
                bool cache_found = m_source_image_existence.get(name, &is_known);
-               if(cache_found)
+               if (cache_found)
                        return is_known;
                // Not found in cache; find out if a local file exists
                is_known = (getTexturePath(name) != "");
@@ -382,12 +370,7 @@ public:
        // Generates an image from a full string like
        // "stone.png^mineral_coal.png^[crack:1:0".
        // Shall be called from the main thread.
-       video::IImage* generateImageFromScratch(std::string name);
-
-       // Generate image based on a string like "stone.png" or "[crack:1:0".
-       // if baseimg is NULL, it is created. Otherwise stuff is made on it.
-       // Shall be called from the main thread.
-       bool generateImage(std::string part_of_name, video::IImage *& baseimg);
+       video::IImage* generateImage(const std::string &name);
 
        video::ITexture* getNormalTexture(const std::string &name);
 private:
@@ -401,6 +384,13 @@ private:
        // This should be only accessed from the main thread
        SourceImageCache m_sourcecache;
 
+       // Generate a texture
+       u32 generateTexture(const std::string &name);
+
+       // Generate image based on a string like "stone.png" or "[crack:1:0".
+       // if baseimg is NULL, it is created. Otherwise stuff is made on it.
+       bool generateImagePart(std::string part_of_name, video::IImage *& baseimg);
+
        // Thread-safe cache of what source images are known (true = known)
        MutexedMap<std::string, bool> m_source_image_existence;
 
@@ -490,7 +480,7 @@ u32 TextureSource::getTextureId(const std::string &name)
                JMutexAutoLock lock(m_textureinfo_cache_mutex);
                std::map<std::string, u32>::iterator n;
                n = m_name_to_id.find(name);
-               if(n != m_name_to_id.end())
+               if (n != m_name_to_id.end())
                {
                        return n->second;
                }
@@ -499,9 +489,9 @@ u32 TextureSource::getTextureId(const std::string &name)
        /*
                Get texture
        */
-       if(get_current_thread_id() == m_main_thread)
+       if (get_current_thread_id() == m_main_thread)
        {
-               return getTextureIdDirect(name);
+               return generateTexture(name);
        }
        else
        {
@@ -550,6 +540,15 @@ static void blit_with_alpha(video::IImage *src, video::IImage *dst,
 static void blit_with_alpha_overlay(video::IImage *src, video::IImage *dst,
                v2s32 src_pos, v2s32 dst_pos, v2u32 size);
 
+// Like blit_with_alpha overlay, but uses an int to calculate the ratio
+// and modifies any destination pixels that are not fully transparent
+static void blit_with_interpolate_overlay(video::IImage *src, video::IImage *dst,
+               v2s32 src_pos, v2s32 dst_pos, v2u32 size, int ratio);
+
+// Apply a mask to an image
+static void apply_mask(video::IImage *mask, video::IImage *dst,
+               v2s32 mask_pos, v2s32 dst_pos, v2u32 size);
+
 // Draw or overlay a crack
 static void draw_crack(video::IImage *crack, video::IImage *dst,
                bool use_overlay, s32 frame_count, s32 progression,
@@ -567,152 +566,51 @@ void imageTransform(u32 transform, video::IImage *src, video::IImage *dst);
 /*
        This method generates all the textures
 */
-u32 TextureSource::getTextureIdDirect(const std::string &name)
+u32 TextureSource::generateTexture(const std::string &name)
 {
-       //infostream<<"getTextureIdDirect(): name=\""<<name<<"\""<<std::endl;
+       //infostream << "generateTexture(): name=\"" << name << "\"" << std::endl;
 
        // Empty name means texture 0
-       if(name == "")
-       {
-               infostream<<"getTextureIdDirect(): name is empty"<<std::endl;
-               return 0;
-       }
-
-       /*
-               Calling only allowed from main thread
-       */
-       if(get_current_thread_id() != m_main_thread)
-       {
-               errorstream<<"TextureSource::getTextureIdDirect() "
-                               "called not from main thread"<<std::endl;
+       if (name == "") {
+               infostream<<"generateTexture(): name is empty"<<std::endl;
                return 0;
        }
 
-       /*
-               See if texture already exists
-       */
        {
+               /*
+                       See if texture already exists
+               */
                JMutexAutoLock lock(m_textureinfo_cache_mutex);
-
                std::map<std::string, u32>::iterator n;
                n = m_name_to_id.find(name);
-               if(n != m_name_to_id.end())
-               {
-                       /*infostream<<"getTextureIdDirect(): \""<<name
-                                       <<"\" found in cache"<<std::endl;*/
+               if (n != m_name_to_id.end()) {
                        return n->second;
                }
        }
 
-       /*infostream<<"getTextureIdDirect(): \""<<name
-                       <<"\" NOT found in cache. Creating it."<<std::endl;*/
-
-       /*
-               Get the base image
-       */
-
-       char separator = '^';
-
-       /*
-               This is set to the id of the base image.
-               If left 0, there is no base image and a completely new image
-               is made.
-       */
-       u32 base_image_id = 0;
-
-       // Find last meta separator in name
-       s32 last_separator_position = -1;
-       for(s32 i=name.size()-1; i>=0; i--)
-       {
-               if(name[i] == separator)
-               {
-                       last_separator_position = i;
-                       break;
-               }
-       }
        /*
-               If separator was found, construct the base name and make the
-               base image using a recursive call
+               Calling only allowed from main thread
        */
-       std::string base_image_name;
-       if(last_separator_position != -1)
-       {
-               // Construct base name
-               base_image_name = name.substr(0, last_separator_position);
-               /*infostream<<"getTextureIdDirect(): Calling itself recursively"
-                               " to get base image of \""<<name<<"\" = \""
-                <<base_image_name<<"\""<<std::endl;*/
-               base_image_id = getTextureIdDirect(base_image_name);
+       if (get_current_thread_id() != m_main_thread) {
+               errorstream<<"TextureSource::generateTexture() "
+                               "called not from main thread"<<std::endl;
+               return 0;
        }
 
-       //infostream<<"base_image_id="<<base_image_id<<std::endl;
-
-       video::IVideoDriver* driver = m_device->getVideoDriver();
+       video::IVideoDriver *driver = m_device->getVideoDriver();
        assert(driver);
 
-       video::ITexture *t = NULL;
-
-       /*
-               An image will be built from files and then converted into a texture.
-       */
-       video::IImage *baseimg = NULL;
-
-       // If a base image was found, copy it to baseimg
-       if(base_image_id != 0)
-       {
-               JMutexAutoLock lock(m_textureinfo_cache_mutex);
+       video::IImage *img = generateImage(name);
 
-               TextureInfo *ti = &m_textureinfo_cache[base_image_id];
+       video::ITexture *tex = NULL;
 
-               if(ti->texture == NULL)
-               {
-                       infostream<<"getTextureIdDirect(): WARNING: NULL Texture in "
-                                       <<"cache: \""<<base_image_name<<"\""
-                                       <<std::endl;
-               }
-               else
-               {
-                       core::dimension2d<u32> dim = ti->texture->getSize();
-
-                       baseimg = driver->createImage(ti->texture,v2s32(0,0), dim);
-
-                       /*infostream<<"getTextureIdDirect(): Loaded \""
-                                       <<base_image_name<<"\" from image cache"
-                                       <<std::endl;*/
-               }
-       }
-
-       /*
-               Parse out the last part of the name of the image and act
-               according to it
-       */
-
-       std::string last_part_of_name = name.substr(last_separator_position+1);
-       //infostream<<"last_part_of_name=\""<<last_part_of_name<<"\""<<std::endl;
-
-       // Generate image according to part of name
-       if(!generateImage(last_part_of_name, baseimg))
-       {
-               errorstream<<"getTextureIdDirect(): "
-                               "failed to generate \""<<last_part_of_name<<"\""
-                               <<std::endl;
-       }
-
-       // If no resulting image, print a warning
-       if(baseimg == NULL)
-       {
-               errorstream<<"getTextureIdDirect(): baseimg is NULL (attempted to"
-                               " create texture \""<<name<<"\""<<std::endl;
-       }
-
-       if(baseimg != NULL)
-       {
+       if (img != NULL) {
 #ifdef __ANDROID__
-               baseimg = Align2Npot2(baseimg, driver);
+               img = Align2Npot2(img, driver);
 #endif
                // Create texture from resulting image
-               t = driver->addTexture(name.c_str(), baseimg);
-               baseimg->drop();
+               tex = driver->addTexture(name.c_str(), img);
+               img->drop();
        }
 
        /*
@@ -722,7 +620,7 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
        JMutexAutoLock lock(m_textureinfo_cache_mutex);
 
        u32 id = m_textureinfo_cache.size();
-       TextureInfo ti(name, t);
+       TextureInfo ti(name, tex);
        m_textureinfo_cache.push_back(ti);
        m_name_to_id[name] = id;
 
@@ -733,7 +631,7 @@ std::string TextureSource::getTextureName(u32 id)
 {
        JMutexAutoLock lock(m_textureinfo_cache_mutex);
 
-       if(id >= m_textureinfo_cache.size())
+       if (id >= m_textureinfo_cache.size())
        {
                errorstream<<"TextureSource::getTextureName(): id="<<id
                                <<" >= m_textureinfo_cache.size()="
@@ -748,7 +646,7 @@ video::ITexture* TextureSource::getTexture(u32 id)
 {
        JMutexAutoLock lock(m_textureinfo_cache_mutex);
 
-       if(id >= m_textureinfo_cache.size())
+       if (id >= m_textureinfo_cache.size())
                return NULL;
 
        return m_textureinfo_cache[id].texture;
@@ -757,7 +655,7 @@ video::ITexture* TextureSource::getTexture(u32 id)
 video::ITexture* TextureSource::getTexture(const std::string &name, u32 *id)
 {
        u32 actual_id = getTextureId(name);
-       if(id){
+       if (id){
                *id = actual_id;
        }
        return getTexture(actual_id);
@@ -769,7 +667,7 @@ void TextureSource::processQueue()
                Fetch textures
        */
        //NOTE this is only thread safe for ONE consumer thread!
-       if(!m_get_texture_queue.empty())
+       if (!m_get_texture_queue.empty())
        {
                GetRequest<std::string, u32, u8, u8>
                                request = m_get_texture_queue.pop();
@@ -779,7 +677,7 @@ void TextureSource::processQueue()
                                <<"name=\""<<request.key<<"\""
                                <<std::endl;*/
 
-               m_get_texture_queue.pushResult(request,getTextureIdDirect(request.key));
+               m_get_texture_queue.pushResult(request, generateTexture(request.key));
        }
 }
 
@@ -801,17 +699,17 @@ void TextureSource::rebuildImagesAndTextures()
        assert(driver != 0);
 
        // Recreate textures
-       for(u32 i=0; i<m_textureinfo_cache.size(); i++){
+       for (u32 i=0; i<m_textureinfo_cache.size(); i++){
                TextureInfo *ti = &m_textureinfo_cache[i];
-               video::IImage *img = generateImageFromScratch(ti->name);
+               video::IImage *img = generateImage(ti->name);
 #ifdef __ANDROID__
-               img = Align2Npot2(img,driver);
+               img = Align2Npot2(img, driver);
                assert(img->getDimension().Height == npot2(img->getDimension().Height));
                assert(img->getDimension().Width == npot2(img->getDimension().Width));
 #endif
                // Create texture from resulting image
                video::ITexture *t = NULL;
-               if(img) {
+               if (img) {
                        t = driver->addTexture(ti->name.c_str(), img);
                        img->drop();
                }
@@ -819,7 +717,7 @@ void TextureSource::rebuildImagesAndTextures()
                // Replace texture
                ti->texture = t;
 
-               if (t_old != 0)
+               if (t_old)
                        m_texture_trash.push_back(t_old);
        }
 }
@@ -943,17 +841,17 @@ video::ITexture* TextureSource::generateTextureFromMesh(
 
                driver->makeColorKeyTexture(rtt, v2s32(0,0));
 
-               if(params.delete_texture_on_shutdown)
+               if (params.delete_texture_on_shutdown)
                        m_texture_trash.push_back(rtt);
 
                return rtt;
        }
 #endif
 
-       if(driver->queryFeature(video::EVDF_RENDER_TO_TARGET) == false)
+       if (driver->queryFeature(video::EVDF_RENDER_TO_TARGET) == false)
        {
                static bool warned = false;
-               if(!warned)
+               if (!warned)
                {
                        errorstream<<"TextureSource::generateTextureFromMesh(): "
                                <<"EVDF_RENDER_TO_TARGET not supported."<<std::endl;
@@ -966,7 +864,7 @@ video::ITexture* TextureSource::generateTextureFromMesh(
        video::ITexture *rtt = driver->addRenderTargetTexture(
                        params.dim, params.rtt_texture_name.c_str(),
                        video::ECF_A8R8G8B8);
-       if(rtt == NULL)
+       if (rtt == NULL)
        {
                errorstream<<"TextureSource::generateTextureFromMesh(): "
                        <<"addRenderTargetTexture returned NULL."<<std::endl;
@@ -1018,57 +916,109 @@ video::ITexture* TextureSource::generateTextureFromMesh(
        // Unset render target
        driver->setRenderTarget(0, false, true, 0);
 
-       if(params.delete_texture_on_shutdown)
+       if (params.delete_texture_on_shutdown)
                m_texture_trash.push_back(rtt);
 
        return rtt;
 }
 
-video::IImage* TextureSource::generateImageFromScratch(std::string name)
+video::IImage* TextureSource::generateImage(const std::string &name)
 {
-       /*infostream<<"generateImageFromScratch(): "
-                       "\""<<name<<"\""<<std::endl;*/
-
-       video::IVideoDriver *driver = m_device->getVideoDriver();
-       assert(driver);
-
        /*
                Get the base image
        */
 
-       video::IImage *baseimg = NULL;
+       const char separator = '^';
+       const char paren_open = '(';
+       const char paren_close = ')';
+
+       // Find last separator in the name
+       s32 last_separator_pos = -1;
+       u8 paren_bal = 0;
+       for (s32 i = name.size() - 1; i >= 0; i--) {
+               switch(name[i]) {
+               case separator:
+                       if (paren_bal == 0) {
+                               last_separator_pos = i;
+                               i = -1; // break out of loop
+                       }
+                       break;
+               case paren_open:
+                       if (paren_bal == 0) {
+                               errorstream << "generateImage(): unbalanced parentheses"
+                                               << "(extranous '(') while generating texture \""
+                                               << name << "\"" << std::endl;
+                               return NULL;
+                       }
+                       paren_bal--;
+                       break;
+               case paren_close:
+                       paren_bal++;
+                       break;
+               default:
+                       break;
+               }
+       }
+       if (paren_bal > 0) {
+               errorstream << "generateImage(): unbalanced parentheses"
+                               << "(missing matching '(') while generating texture \""
+                               << name << "\"" << std::endl;
+               return NULL;
+       }
 
-       char separator = '^';
 
-       // Find last meta separator in name
-       s32 last_separator_position = name.find_last_of(separator);
+       video::IImage *baseimg = NULL;
 
        /*
-               If separator was found, construct the base name and make the
-               base image using a recursive call
+               If separator was found, make the base image
+               using a recursive call.
        */
-       std::string base_image_name;
-       if(last_separator_position != -1)
-       {
-               // Construct base name
-               base_image_name = name.substr(0, last_separator_position);
-               baseimg = generateImageFromScratch(base_image_name);
+       if (last_separator_pos != -1) {
+               baseimg = generateImage(name.substr(0, last_separator_pos));
        }
 
+
+       video::IVideoDriver* driver = m_device->getVideoDriver();
+       assert(driver);
+
        /*
                Parse out the last part of the name of the image and act
                according to it
        */
 
-       std::string last_part_of_name = name.substr(last_separator_position+1);
+       std::string last_part_of_name = name.substr(last_separator_pos + 1);
 
-       // Generate image according to part of name
-       if(!generateImage(last_part_of_name, baseimg))
-       {
-               errorstream<<"generateImageFromScratch(): "
-                               "failed to generate \""<<last_part_of_name<<"\""
-                               <<std::endl;
-               return NULL;
+       /* 
+               If this name is enclosed in parentheses, generate it
+               and blit it onto the base image
+       */
+       if (last_part_of_name[0] == paren_open
+                       && last_part_of_name[last_part_of_name.size() - 1] == paren_close) {
+               std::string name2 = last_part_of_name.substr(1,
+                               last_part_of_name.size() - 2);
+               video::IImage *tmp = generateImage(name2);
+               if (!tmp) {
+                       errorstream << "generateImage(): "
+                               "Failed to generate \"" << name2 << "\""
+                               << std::endl;
+                       return NULL;
+               }
+               core::dimension2d<u32> dim = tmp->getDimension();
+               if (!baseimg)
+                       baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
+               blit_with_alpha(tmp, baseimg, v2s32(0, 0), v2s32(0, 0), dim);
+               tmp->drop();
+       } else if (!generateImagePart(last_part_of_name, baseimg)) {
+               // Generate image according to part of name
+               errorstream << "generateImage(): "
+                               "Failed to generate \"" << last_part_of_name << "\""
+                               << std::endl;
+       }
+
+       // If no resulting image, print a warning
+       if (baseimg == NULL) {
+               errorstream << "generateImage(): baseimg is NULL (attempted to"
+                               " create texture \"" << name << "\")" << std::endl;
        }
 
        return baseimg;
@@ -1085,7 +1035,7 @@ video::IImage* TextureSource::generateImageFromScratch(std::string name)
 video::IImage * Align2Npot2(video::IImage * image,
                video::IVideoDriver* driver)
 {
-       if(image == NULL) {
+       if (image == NULL) {
                return image;
        }
 
@@ -1125,17 +1075,18 @@ video::IImage * Align2Npot2(video::IImage * image,
 
 #endif
 
-bool TextureSource::generateImage(std::string part_of_name, video::IImage *& baseimg)
+bool TextureSource::generateImagePart(std::string part_of_name,
+               video::IImage *& baseimg)
 {
        video::IVideoDriver* driver = m_device->getVideoDriver();
        assert(driver);
 
        // Stuff starting with [ are special commands
-       if(part_of_name.size() == 0 || part_of_name[0] != '[')
+       if (part_of_name.size() == 0 || part_of_name[0] != '[')
        {
                video::IImage *image = m_sourcecache.getOrLoad(part_of_name, m_device);
 #ifdef __ANDROID__
-               image = Align2Npot2(image,driver);
+               image = Align2Npot2(image, driver);
 #endif
                if (image == NULL) {
                        if (part_of_name != "") {
@@ -1172,7 +1123,7 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas
                }
 
                // If base image is NULL, load as base.
-               if(baseimg == NULL)
+               if (baseimg == NULL)
                {
                        //infostream<<"Setting "<<part_of_name<<" as base"<<std::endl;
                        /*
@@ -1219,11 +1170,10 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas
                        Adds a cracking texture
                        N = animation frame count, P = crack progression
                */
-               if(part_of_name.substr(0,6) == "[crack")
+               if (part_of_name.substr(0,6) == "[crack")
                {
-                       if(baseimg == NULL)
-                       {
-                               errorstream<<"generateImage(): baseimg==NULL "
+                       if (baseimg == NULL) {
+                               errorstream<<"generateImagePart(): baseimg == NULL "
                                                <<"for part_of_name=\""<<part_of_name
                                                <<"\", cancelling."<<std::endl;
                                return false;
@@ -1245,7 +1195,7 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas
                        video::IImage *img_crack = m_sourcecache.getOrLoad(
                                        "crack_anylength.png", m_device);
 
-                       if(img_crack && progression >= 0)
+                       if (img_crack && progression >= 0)
                        {
                                draw_crack(img_crack, baseimg,
                                                use_overlay, frame_count,
@@ -1257,21 +1207,19 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas
                        [combine:WxH:X,Y=filename:X,Y=filename2
                        Creates a bigger texture from an amount of smaller ones
                */
-               else if(part_of_name.substr(0,8) == "[combine")
+               else if (part_of_name.substr(0,8) == "[combine")
                {
                        Strfnd sf(part_of_name);
                        sf.next(":");
                        u32 w0 = stoi(sf.next("x"));
                        u32 h0 = stoi(sf.next(":"));
-                       infostream<<"combined w="<<w0<<" h="<<h0<<std::endl;
+                       //infostream<<"combined w="<<w0<<" h="<<h0<<std::endl;
                        core::dimension2d<u32> dim(w0,h0);
-                       if(baseimg == NULL)
-                       {
+                       if (baseimg == NULL) {
                                baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
                                baseimg->fill(video::SColor(0,0,0,0));
                        }
-                       while(sf.atend() == false)
-                       {
+                       while (sf.atend() == false) {
                                u32 x = stoi(sf.next(","));
                                u32 y = stoi(sf.next("="));
                                std::string filename = sf.next(":");
@@ -1279,8 +1227,7 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas
                                                <<"\" to combined ("<<x<<","<<y<<")"
                                                <<std::endl;
                                video::IImage *img = m_sourcecache.getOrLoad(filename, m_device);
-                               if(img)
-                               {
+                               if (img) {
                                        core::dimension2d<u32> dim = img->getDimension();
                                        infostream<<"Size "<<dim.Width
                                                        <<"x"<<dim.Height<<std::endl;
@@ -1295,21 +1242,19 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas
                                                        NULL);*/
                                        blit_with_alpha(img2, baseimg, v2s32(0,0), pos_base, dim);
                                        img2->drop();
-                               }
-                               else
-                               {
-                                       infostream<<"img==NULL"<<std::endl;
+                               } else {
+                                       errorstream << "generateImagePart(): Failed to load image \""
+                                               << filename << "\" for [combine" << std::endl;
                                }
                        }
                }
                /*
                        "[brighten"
                */
-               else if(part_of_name.substr(0,9) == "[brighten")
+               else if (part_of_name.substr(0,9) == "[brighten")
                {
-                       if(baseimg == NULL)
-                       {
-                               errorstream<<"generateImage(): baseimg==NULL "
+                       if (baseimg == NULL) {
+                               errorstream<<"generateImagePart(): baseimg==NULL "
                                                <<"for part_of_name=\""<<part_of_name
                                                <<"\", cancelling."<<std::endl;
                                return false;
@@ -1324,11 +1269,10 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas
                        that the transparent parts don't look completely black
                        when simple alpha channel is used for rendering.
                */
-               else if(part_of_name.substr(0,8) == "[noalpha")
+               else if (part_of_name.substr(0,8) == "[noalpha")
                {
-                       if(baseimg == NULL)
-                       {
-                               errorstream<<"generateImage(): baseimg==NULL "
+                       if (baseimg == NULL){
+                               errorstream<<"generateImagePart(): baseimg==NULL "
                                                <<"for part_of_name=\""<<part_of_name
                                                <<"\", cancelling."<<std::endl;
                                return false;
@@ -1337,8 +1281,8 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas
                        core::dimension2d<u32> dim = baseimg->getDimension();
 
                        // Set alpha to full
-                       for(u32 y=0; y<dim.Height; y++)
-                       for(u32 x=0; x<dim.Width; x++)
+                       for (u32 y=0; y<dim.Height; y++)
+                       for (u32 x=0; x<dim.Width; x++)
                        {
                                video::SColor c = baseimg->getPixel(x,y);
                                c.setAlpha(255);
@@ -1349,11 +1293,10 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas
                        "[makealpha:R,G,B"
                        Convert one color to transparent.
                */
-               else if(part_of_name.substr(0,11) == "[makealpha:")
+               else if (part_of_name.substr(0,11) == "[makealpha:")
                {
-                       if(baseimg == NULL)
-                       {
-                               errorstream<<"generateImage(): baseimg==NULL "
+                       if (baseimg == NULL) {
+                               errorstream<<"generateImagePart(): baseimg == NULL "
                                                <<"for part_of_name=\""<<part_of_name
                                                <<"\", cancelling."<<std::endl;
                                return false;
@@ -1373,14 +1316,14 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas
                        oldbaseimg->drop();*/
 
                        // Set alpha to full
-                       for(u32 y=0; y<dim.Height; y++)
-                       for(u32 x=0; x<dim.Width; x++)
+                       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))
+                               if (!(r == r1 && g == g1 && b == b1))
                                        continue;
                                c.setAlpha(0);
                                baseimg->setPixel(x,y,c);
@@ -1406,11 +1349,10 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas
                        The resulting transform will be equivalent to one of the
                        eight existing ones, though (see: dihedral group).
                */
-               else if(part_of_name.substr(0,10) == "[transform")
+               else if (part_of_name.substr(0,10) == "[transform")
                {
-                       if(baseimg == NULL)
-                       {
-                               errorstream<<"generateImage(): baseimg==NULL "
+                       if (baseimg == NULL) {
+                               errorstream<<"generateImagePart(): baseimg == NULL "
                                                <<"for part_of_name=\""<<part_of_name
                                                <<"\", cancelling."<<std::endl;
                                return false;
@@ -1434,17 +1376,16 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas
                        Example (a grass block (not actually used in game):
                        "[inventorycube{grass.png{mud.png&grass_side.png{mud.png&grass_side.png"
                */
-               else if(part_of_name.substr(0,14) == "[inventorycube")
+               else if (part_of_name.substr(0,14) == "[inventorycube")
                {
-                       if(baseimg != NULL)
-                       {
-                               errorstream<<"generateImage(): baseimg!=NULL "
+                       if (baseimg != NULL){
+                               errorstream<<"generateImagePart(): baseimg != NULL "
                                                <<"for part_of_name=\""<<part_of_name
                                                <<"\", cancelling."<<std::endl;
                                return false;
                        }
 
-                       str_replace_char(part_of_name, '&', '^');
+                       str_replace(part_of_name, '&', '^');
                        Strfnd sf(part_of_name);
                        sf.next("{");
                        std::string imagename_top = sf.next("{");
@@ -1452,13 +1393,18 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas
                        std::string imagename_right = sf.next("{");
 
                        // Generate images for the faces of the cube
-                       video::IImage *img_top =
-                               generateImageFromScratch(imagename_top);
-                       video::IImage *img_left =
-                               generateImageFromScratch(imagename_left);
-                       video::IImage *img_right =
-                               generateImageFromScratch(imagename_right);
-                       assert(img_top && img_left && img_right);
+                       video::IImage *img_top = generateImage(imagename_top);
+                       video::IImage *img_left = generateImage(imagename_left);
+                       video::IImage *img_right = generateImage(imagename_right);
+
+                       if (img_top == NULL || img_left == NULL || img_right == NULL) {
+                               errorstream << "generateImagePart(): Failed to create textures"
+                                               << " for inventorycube \"" << part_of_name << "\""
+                                               << std::endl;
+                               baseimg = generateImage(imagename_top);
+                               return true;
+                       }
+
 #ifdef __ANDROID__
                        assert(img_top->getDimension().Height == npot2(img_top->getDimension().Height));
                        assert(img_top->getDimension().Width == npot2(img_top->getDimension().Width));
@@ -1469,6 +1415,7 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas
                        assert(img_right->getDimension().Height == npot2(img_right->getDimension().Height));
                        assert(img_right->getDimension().Width == npot2(img_right->getDimension().Width));
 #endif
+
                        // Create textures from images
                        video::ITexture *texture_top = driver->addTexture(
                                        (imagename_top + "__temp__").c_str(), img_top);
@@ -1518,19 +1465,18 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas
                        // Drop mesh
                        cube->drop();
 
-                       // Free textures of images
+                       // Free textures
                        driver->removeTexture(texture_top);
                        driver->removeTexture(texture_left);
                        driver->removeTexture(texture_right);
 
-                       if(rtt == NULL)
-                       {
-                               baseimg = generateImageFromScratch(imagename_top);
+                       if (rtt == NULL) {
+                               baseimg = generateImage(imagename_top);
                                return true;
                        }
 
                        // Create image of render target
-                       video::IImage *image = driver->createImage(rtt, v2s32(0,0), params.dim);
+                       video::IImage *image = driver->createImage(rtt, v2s32(0, 0), params.dim);
                        assert(image);
 
                        // Cleanup texture
@@ -1538,8 +1484,7 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas
 
                        baseimg = driver->createImage(video::ECF_A8R8G8B8, params.dim);
 
-                       if(image)
-                       {
+                       if (image) {
                                image->copyTo(baseimg);
                                image->drop();
                        }
@@ -1548,7 +1493,7 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas
                        [lowpart:percent:filename
                        Adds the lower part of a texture
                */
-               else if(part_of_name.substr(0,9) == "[lowpart:")
+               else if (part_of_name.substr(0,9) == "[lowpart:")
                {
                        Strfnd sf(part_of_name);
                        sf.next(":");
@@ -1556,10 +1501,10 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas
                        std::string filename = sf.next(":");
                        //infostream<<"power part "<<percent<<"%% of "<<filename<<std::endl;
 
-                       if(baseimg == NULL)
+                       if (baseimg == NULL)
                                baseimg = driver->createImage(video::ECF_A8R8G8B8, v2u32(16,16));
                        video::IImage *img = m_sourcecache.getOrLoad(filename, m_device);
-                       if(img)
+                       if (img)
                        {
                                core::dimension2d<u32> dim = img->getDimension();
                                core::position2d<s32> pos_base(0, 0);
@@ -1584,15 +1529,15 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas
                        Crops a frame of a vertical animation.
                        N = frame count, I = frame index
                */
-               else if(part_of_name.substr(0,15) == "[verticalframe:")
+               else if (part_of_name.substr(0,15) == "[verticalframe:")
                {
                        Strfnd sf(part_of_name);
                        sf.next(":");
                        u32 frame_count = stoi(sf.next(":"));
                        u32 frame_index = stoi(sf.next(":"));
 
-                       if(baseimg == NULL){
-                               errorstream<<"generateImage(): baseimg!=NULL "
+                       if (baseimg == NULL){
+                               errorstream<<"generateImagePart(): baseimg != NULL "
                                                <<"for part_of_name=\""<<part_of_name
                                                <<"\", cancelling."<<std::endl;
                                return false;
@@ -1603,8 +1548,8 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas
 
                        video::IImage *img = driver->createImage(video::ECF_A8R8G8B8,
                                        frame_size);
-                       if(!img){
-                               errorstream<<"generateImage(): Could not create image "
+                       if (!img){
+                               errorstream<<"generateImagePart(): Could not create image "
                                                <<"for part_of_name=\""<<part_of_name
                                                <<"\", cancelling."<<std::endl;
                                return false;
@@ -1624,10 +1569,77 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas
                        baseimg->drop();
                        baseimg = img;
                }
+               /*
+                       [mask:filename
+                       Applies a mask to an image
+               */
+               else if (part_of_name.substr(0,6) == "[mask:")
+               {
+                       if (baseimg == NULL) {
+                               errorstream << "generateImage(): baseimg == NULL "
+                                               << "for part_of_name=\"" << part_of_name
+                                               << "\", cancelling." << std::endl;
+                               return false;
+                       }
+                       Strfnd sf(part_of_name);
+                       sf.next(":");
+                       std::string filename = sf.next(":");
+
+                       video::IImage *img = m_sourcecache.getOrLoad(filename, m_device);
+                       if (img) {
+                               apply_mask(img, baseimg, v2s32(0, 0), v2s32(0, 0),
+                                               img->getDimension());
+                       } else {
+                               errorstream << "generateImage(): Failed to load \""
+                                               << filename << "\".";
+                       }
+               }
+               /*
+                       [colorize:color
+                       Overlays image with given color
+                       color = color as ColorString
+               */
+               else if (part_of_name.substr(0,10) == "[colorize:") {
+                       Strfnd sf(part_of_name);
+                       sf.next(":");
+                       std::string color_str = sf.next(":");
+                       std::string ratio_str = sf.next(":");
+
+                       if (baseimg == NULL) {
+                               errorstream << "generateImagePart(): baseimg != NULL "
+                                               << "for part_of_name=\"" << part_of_name
+                                               << "\", cancelling." << std::endl;
+                               return false;
+                       }
+
+                       video::SColor color;
+                       int ratio = -1;
+
+                       if (!parseColorString(color_str, color, false))
+                               return false;
+
+                       if (is_number(ratio_str))
+                               ratio = mystoi(ratio_str, 0, 255);
+
+                       core::dimension2d<u32> dim = baseimg->getDimension();
+                       video::IImage *img = driver->createImage(video::ECF_A8R8G8B8, dim);
+
+                       if (!img) {
+                               errorstream << "generateImagePart(): Could not create image "
+                                               << "for part_of_name=\"" << part_of_name
+                                               << "\", cancelling." << std::endl;
+                               return false;
+                       }
+
+                       img->fill(video::SColor(color));
+                       // Overlay the colored image
+                       blit_with_interpolate_overlay(img, baseimg, v2s32(0,0), v2s32(0,0), dim, ratio);
+                       img->drop();
+               }
                else
                {
-                       errorstream<<"generateImage(): Invalid "
-                                       " modification: \""<<part_of_name<<"\""<<std::endl;
+                       errorstream << "generateImagePart(): Invalid "
+                                       " modification: \"" << part_of_name << "\"" << std::endl;
                }
        }
 
@@ -1644,8 +1656,8 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas
 static void blit_with_alpha(video::IImage *src, video::IImage *dst,
                v2s32 src_pos, v2s32 dst_pos, v2u32 size)
 {
-       for(u32 y0=0; y0<size.Y; y0++)
-       for(u32 x0=0; x0<size.X; x0++)
+       for (u32 y0=0; y0<size.Y; y0++)
+       for (u32 x0=0; x0<size.X; x0++)
        {
                s32 src_x = src_pos.X + x0;
                s32 src_y = src_pos.Y + y0;
@@ -1665,8 +1677,8 @@ static void blit_with_alpha(video::IImage *src, video::IImage *dst,
 static void blit_with_alpha_overlay(video::IImage *src, video::IImage *dst,
                v2s32 src_pos, v2s32 dst_pos, v2u32 size)
 {
-       for(u32 y0=0; y0<size.Y; y0++)
-       for(u32 x0=0; x0<size.X; x0++)
+       for (u32 y0=0; y0<size.Y; y0++)
+       for (u32 x0=0; x0<size.X; x0++)
        {
                s32 src_x = src_pos.X + x0;
                s32 src_y = src_pos.Y + y0;
@@ -1674,7 +1686,7 @@ static void blit_with_alpha_overlay(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);
-               if(dst_c.getAlpha() == 255 && src_c.getAlpha() != 0)
+               if (dst_c.getAlpha() == 255 && src_c.getAlpha() != 0)
                {
                        dst_c = src_c.getInterpolated(dst_c, (float)src_c.getAlpha()/255.0f);
                        dst->setPixel(dst_x, dst_y, dst_c);
@@ -1682,6 +1694,53 @@ static void blit_with_alpha_overlay(video::IImage *src, video::IImage *dst,
        }
 }
 
+/*
+       Draw an image on top of an another one, using the specified ratio
+       modify all partially-opaque pixels in the destination.
+*/
+static void blit_with_interpolate_overlay(video::IImage *src, video::IImage *dst,
+               v2s32 src_pos, v2s32 dst_pos, v2u32 size, int ratio)
+{
+       for (u32 y0 = 0; y0 < size.Y; y0++)
+       for (u32 x0 = 0; x0 < size.X; x0++)
+       {
+               s32 src_x = src_pos.X + x0;
+               s32 src_y = src_pos.Y + y0;
+               s32 dst_x = dst_pos.X + x0;
+               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);
+               if (dst_c.getAlpha() > 0 && src_c.getAlpha() != 0)
+               {
+                       if (ratio == -1)
+                               dst_c = src_c.getInterpolated(dst_c, (float)src_c.getAlpha()/255.0f);
+                       else
+                               dst_c = src_c.getInterpolated(dst_c, (float)ratio/255.0f);
+                       dst->setPixel(dst_x, dst_y, dst_c);
+               }
+       }
+}
+
+/*
+       Apply mask to destination
+*/
+static void apply_mask(video::IImage *mask, video::IImage *dst,
+               v2s32 mask_pos, v2s32 dst_pos, v2u32 size)
+{
+       for (u32 y0 = 0; y0 < size.Y; y0++) {
+               for (u32 x0 = 0; x0 < size.X; x0++) {
+                       s32 mask_x = x0 + mask_pos.X;
+                       s32 mask_y = y0 + mask_pos.Y;
+                       s32 dst_x = x0 + dst_pos.X;
+                       s32 dst_y = y0 + dst_pos.Y;
+                       video::SColor mask_c = mask->getPixel(mask_x, mask_y);
+                       video::SColor dst_c = dst->getPixel(dst_x, dst_y);
+                       dst_c.color &= mask_c.color;
+                       dst->setPixel(dst_x, dst_y, dst_c);
+               }
+       }
+}
+
 static void draw_crack(video::IImage *crack, video::IImage *dst,
                bool use_overlay, s32 frame_count, s32 progression,
                video::IVideoDriver *driver)
@@ -1693,12 +1752,12 @@ static void draw_crack(video::IImage *crack, video::IImage *dst,
        // Count of crack stages
        s32 crack_count = dim_crack.Height / dim_crack.Width;
        // Limit frame_count
-       if(frame_count > (s32) dim_dst.Height)
+       if (frame_count > (s32) dim_dst.Height)
                frame_count = dim_dst.Height;
-       if(frame_count < 1)
+       if (frame_count < 1)
                frame_count = 1;
        // Limit progression
-       if(progression > crack_count-1)
+       if (progression > crack_count-1)
                progression = crack_count-1;
        // Dimension of a single crack stage
        core::dimension2d<u32> dim_crack_cropped(
@@ -1717,7 +1776,7 @@ static void draw_crack(video::IImage *crack, video::IImage *dst,
        video::IImage *crack_scaled = driver->createImage(
                        video::ECF_A8R8G8B8, dim_crack_scaled);
 
-       if(crack_cropped && crack_scaled)
+       if (crack_cropped && crack_scaled)
        {
                // Crop crack image
                v2s32 pos_crack(0, progression*dim_crack.Width);
@@ -1727,10 +1786,10 @@ static void draw_crack(video::IImage *crack, video::IImage *dst,
                // Scale crack image by copying
                crack_cropped->copyToScaling(crack_scaled);
                // Copy or overlay crack image onto each frame
-               for(s32 i = 0; i < frame_count; ++i)
+               for (s32 i = 0; i < frame_count; ++i)
                {
                        v2s32 dst_pos(0, dim_crack_scaled.Height * i);
-                       if(use_overlay)
+                       if (use_overlay)
                        {
                                blit_with_alpha_overlay(crack_scaled, dst,
                                                v2s32(0,0), dst_pos,
@@ -1745,22 +1804,22 @@ static void draw_crack(video::IImage *crack, video::IImage *dst,
                }
        }
 
-       if(crack_scaled)
+       if (crack_scaled)
                crack_scaled->drop();
 
-       if(crack_cropped)
+       if (crack_cropped)
                crack_cropped->drop();
 }
 
 void brighten(video::IImage *image)
 {
-       if(image == NULL)
+       if (image == NULL)
                return;
 
        core::dimension2d<u32> dim = image->getDimension();
 
-       for(u32 y=0; y<dim.Height; y++)
-       for(u32 x=0; x<dim.Width; x++)
+       for (u32 y=0; y<dim.Height; y++)
+       for (u32 x=0; x<dim.Width; x++)
        {
                video::SColor c = image->getPixel(x,y);
                c.setRed(0.5 * 255 + 0.5 * (float)c.getRed());
@@ -1786,17 +1845,17 @@ u32 parseImageTransform(const std::string& s)
        while(pos < s.size())
        {
                int transform = -1;
-               for(int i = 0; i <= 7; ++i)
+               for (int i = 0; i <= 7; ++i)
                {
                        const std::string &name_i = transform_names[i];
 
-                       if(s[pos] == ('0' + i))
+                       if (s[pos] == ('0' + i))
                        {
                                transform = i;
                                pos++;
                                break;
                        }
-                       else if(!(name_i.empty()) &&
+                       else if (!(name_i.empty()) &&
                                lowercase(s.substr(pos, name_i.size())) == name_i)
                        {
                                transform = i;
@@ -1804,16 +1863,16 @@ u32 parseImageTransform(const std::string& s)
                                break;
                        }
                }
-               if(transform < 0)
+               if (transform < 0)
                        break;
 
                // Multiply total_transform and transform in the group D4
                int new_total = 0;
-               if(transform < 4)
+               if (transform < 4)
                        new_total = (transform + total_transform) % 4;
                else
                        new_total = (transform - total_transform + 8) % 4;
-               if((transform >= 4) ^ (total_transform >= 4))
+               if ((transform >= 4) ^ (total_transform >= 4))
                        new_total += 4;
 
                total_transform = new_total;
@@ -1823,7 +1882,7 @@ u32 parseImageTransform(const std::string& s)
 
 core::dimension2d<u32> imageTransformDimension(u32 transform, core::dimension2d<u32> dim)
 {
-       if(transform % 2 == 0)
+       if (transform % 2 == 0)
                return dim;
        else
                return core::dimension2d<u32>(dim.Height, dim.Width);
@@ -1831,14 +1890,14 @@ core::dimension2d<u32> imageTransformDimension(u32 transform, core::dimension2d<
 
 void imageTransform(u32 transform, video::IImage *src, video::IImage *dst)
 {
-       if(src == NULL || dst == NULL)
+       if (src == NULL || dst == NULL)
                return;
 
        core::dimension2d<u32> srcdim = src->getDimension();
        core::dimension2d<u32> dstdim = dst->getDimension();
 
        assert(dstdim == imageTransformDimension(transform, srcdim));
-       assert(transform >= 0 && transform <= 7);
+       assert(transform <= 7);
 
        /*
                Compute the transformation from source coordinates (sx,sy)
@@ -1846,25 +1905,25 @@ void imageTransform(u32 transform, video::IImage *src, video::IImage *dst)
        */
        int sxn = 0;
        int syn = 2;
-       if(transform == 0)         // identity
+       if (transform == 0)         // identity
                sxn = 0, syn = 2;  //   sx = dx, sy = dy
-       else if(transform == 1)    // rotate by 90 degrees ccw
+       else if (transform == 1)    // rotate by 90 degrees ccw
                sxn = 3, syn = 0;  //   sx = (H-1) - dy, sy = dx
-       else if(transform == 2)    // rotate by 180 degrees
+       else if (transform == 2)    // rotate by 180 degrees
                sxn = 1, syn = 3;  //   sx = (W-1) - dx, sy = (H-1) - dy
-       else if(transform == 3)    // rotate by 270 degrees ccw
+       else if (transform == 3)    // rotate by 270 degrees ccw
                sxn = 2, syn = 1;  //   sx = dy, sy = (W-1) - dx
-       else if(transform == 4)    // flip x
+       else if (transform == 4)    // flip x
                sxn = 1, syn = 2;  //   sx = (W-1) - dx, sy = dy
-       else if(transform == 5)    // flip x then rotate by 90 degrees ccw
+       else if (transform == 5)    // flip x then rotate by 90 degrees ccw
                sxn = 2, syn = 0;  //   sx = dy, sy = dx
-       else if(transform == 6)    // flip y
+       else if (transform == 6)    // flip y
                sxn = 0, syn = 3;  //   sx = dx, sy = (H-1) - dy
-       else if(transform == 7)    // flip y then rotate by 90 degrees ccw
+       else if (transform == 7)    // flip y then rotate by 90 degrees ccw
                sxn = 3, syn = 1;  //   sx = (H-1) - dy, sy = (W-1) - dx
 
-       for(u32 dy=0; dy<dstdim.Height; dy++)
-       for(u32 dx=0; dx<dstdim.Width; dx++)
+       for (u32 dy=0; dy<dstdim.Height; dy++)
+       for (u32 dx=0; dx<dstdim.Width; dx++)
        {
                u32 entries[4] = {dx, dstdim.Width-1-dx, dy, dstdim.Height-1-dy};
                u32 sx = entries[sxn];