Merge remote-tracking branch 'origin/master'
[oweals/minetest.git] / src / tile.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "tile.h"
21 #include "debug.h"
22 #include "main.h" // for g_settings
23 #include "filesys.h"
24 #include "settings.h"
25 #include "mesh.h"
26 #include <ICameraSceneNode.h>
27 #include "log.h"
28 #include "mapnode.h" // For texture atlas making
29 #include "nodedef.h" // For texture atlas making
30 #include "gamedef.h"
31 #include "util/string.h"
32 #include "util/container.h"
33 #include "util/thread.h"
34 #include "util/numeric.h"
35
36 /*
37         A cache from texture name to texture path
38 */
39 MutexedMap<std::string, std::string> g_texturename_to_path_cache;
40
41 /*
42         Replaces the filename extension.
43         eg:
44                 std::string image = "a/image.png"
45                 replace_ext(image, "jpg")
46                 -> image = "a/image.jpg"
47         Returns true on success.
48 */
49 static bool replace_ext(std::string &path, const char *ext)
50 {
51         if(ext == NULL)
52                 return false;
53         // Find place of last dot, fail if \ or / found.
54         s32 last_dot_i = -1;
55         for(s32 i=path.size()-1; i>=0; i--)
56         {
57                 if(path[i] == '.')
58                 {
59                         last_dot_i = i;
60                         break;
61                 }
62                 
63                 if(path[i] == '\\' || path[i] == '/')
64                         break;
65         }
66         // If not found, return an empty string
67         if(last_dot_i == -1)
68                 return false;
69         // Else make the new path
70         path = path.substr(0, last_dot_i+1) + ext;
71         return true;
72 }
73
74 /*
75         Find out the full path of an image by trying different filename
76         extensions.
77
78         If failed, return "".
79 */
80 std::string getImagePath(std::string path)
81 {
82         // A NULL-ended list of possible image extensions
83         const char *extensions[] = {
84                 "png", "jpg", "bmp", "tga",
85                 "pcx", "ppm", "psd", "wal", "rgb",
86                 NULL
87         };
88         // If there is no extension, add one
89         if(removeStringEnd(path, extensions) == "")
90                 path = path + ".png";
91         // Check paths until something is found to exist
92         const char **ext = extensions;
93         do{
94                 bool r = replace_ext(path, *ext);
95                 if(r == false)
96                         return "";
97                 if(fs::PathExists(path))
98                         return path;
99         }
100         while((++ext) != NULL);
101         
102         return "";
103 }
104
105 /*
106         Gets the path to a texture by first checking if the texture exists
107         in texture_path and if not, using the data path.
108
109         Checks all supported extensions by replacing the original extension.
110
111         If not found, returns "".
112
113         Utilizes a thread-safe cache.
114 */
115 std::string getTexturePath(const std::string &filename)
116 {
117         std::string fullpath = "";
118         /*
119                 Check from cache
120         */
121         bool incache = g_texturename_to_path_cache.get(filename, &fullpath);
122         if(incache)
123                 return fullpath;
124         
125         /*
126                 Check from texture_path
127         */
128         std::string texture_path = g_settings->get("texture_path");
129         if(texture_path != "")
130         {
131                 std::string testpath = texture_path + DIR_DELIM + filename;
132                 // Check all filename extensions. Returns "" if not found.
133                 fullpath = getImagePath(testpath);
134         }
135         
136         /*
137                 Check from $user/textures/all
138         */
139         if(fullpath == "")
140         {
141                 std::string texture_path = porting::path_user + DIR_DELIM
142                                 + "textures" + DIR_DELIM + "all";
143                 std::string testpath = texture_path + DIR_DELIM + filename;
144                 // Check all filename extensions. Returns "" if not found.
145                 fullpath = getImagePath(testpath);
146         }
147
148         /*
149                 Check from default data directory
150         */
151         if(fullpath == "")
152         {
153                 std::string base_path = porting::path_share + DIR_DELIM + "textures"
154                                 + DIR_DELIM + "base" + DIR_DELIM + "pack";
155                 std::string testpath = base_path + DIR_DELIM + filename;
156                 // Check all filename extensions. Returns "" if not found.
157                 fullpath = getImagePath(testpath);
158         }
159         
160         // Add to cache (also an empty result is cached)
161         g_texturename_to_path_cache.set(filename, fullpath);
162         
163         // Finally return it
164         return fullpath;
165 }
166
167 /*
168         An internal variant of AtlasPointer with more data.
169         (well, more like a wrapper)
170 */
171
172 struct SourceAtlasPointer
173 {
174         std::string name;
175         AtlasPointer a;
176         video::IImage *atlas_img; // The source image of the atlas
177         // Integer variants of position and size
178         v2s32 intpos;
179         v2u32 intsize;
180
181         SourceAtlasPointer(
182                         const std::string &name_,
183                         AtlasPointer a_=AtlasPointer(0, NULL),
184                         video::IImage *atlas_img_=NULL,
185                         v2s32 intpos_=v2s32(0,0),
186                         v2u32 intsize_=v2u32(0,0)
187                 ):
188                 name(name_),
189                 a(a_),
190                 atlas_img(atlas_img_),
191                 intpos(intpos_),
192                 intsize(intsize_)
193         {
194         }
195 };
196
197 /*
198         SourceImageCache: A cache used for storing source images.
199 */
200
201 class SourceImageCache
202 {
203 public:
204         ~SourceImageCache() {
205                 for(std::map<std::string, video::IImage*>::iterator iter = m_images.begin();
206                                 iter != m_images.end(); iter++) {
207                         iter->second->drop();
208                 }
209                 m_images.clear();
210         }
211         void insert(const std::string &name, video::IImage *img,
212                         bool prefer_local, video::IVideoDriver *driver)
213         {
214                 assert(img);
215                 // Remove old image
216                 std::map<std::string, video::IImage*>::iterator n;
217                 n = m_images.find(name);
218                 if(n != m_images.end()){
219                         if(n->second)
220                                 n->second->drop();
221                 }
222
223                 video::IImage* toadd = img;
224                 bool need_to_grab = true;
225
226                 // Try to use local texture instead if asked to
227                 if(prefer_local){
228                         std::string path = getTexturePath(name.c_str());
229                         if(path != ""){
230                                 video::IImage *img2 = driver->createImageFromFile(path.c_str());
231                                 if(img2){
232                                         toadd = img2;
233                                         need_to_grab = false;
234                                 }
235                         }
236                 }
237
238                 if (need_to_grab)
239                         toadd->grab();
240                 m_images[name] = toadd;
241         }
242         video::IImage* get(const std::string &name)
243         {
244                 std::map<std::string, video::IImage*>::iterator n;
245                 n = m_images.find(name);
246                 if(n != m_images.end())
247                         return n->second;
248                 return NULL;
249         }
250         // Primarily fetches from cache, secondarily tries to read from filesystem
251         video::IImage* getOrLoad(const std::string &name, IrrlichtDevice *device)
252         {
253                 std::map<std::string, video::IImage*>::iterator n;
254                 n = m_images.find(name);
255                 if(n != m_images.end()){
256                         n->second->grab(); // Grab for caller
257                         return n->second;
258                 }
259                 video::IVideoDriver* driver = device->getVideoDriver();
260                 std::string path = getTexturePath(name.c_str());
261                 if(path == ""){
262                         infostream<<"SourceImageCache::getOrLoad(): No path found for \""
263                                         <<name<<"\""<<std::endl;
264                         return NULL;
265                 }
266                 infostream<<"SourceImageCache::getOrLoad(): Loading path \""<<path
267                                 <<"\""<<std::endl;
268                 video::IImage *img = driver->createImageFromFile(path.c_str());
269
270                 if(img){
271                         m_images[name] = img;
272                         img->grab(); // Grab for caller
273                 }
274                 return img;
275         }
276 private:
277         std::map<std::string, video::IImage*> m_images;
278 };
279
280 /*
281         TextureSource
282 */
283
284 class TextureSource : public IWritableTextureSource
285 {
286 public:
287         TextureSource(IrrlichtDevice *device);
288         virtual ~TextureSource();
289
290         /*
291                 Example case:
292                 Now, assume a texture with the id 1 exists, and has the name
293                 "stone.png^mineral1".
294                 Then a random thread calls getTextureId for a texture called
295                 "stone.png^mineral1^crack0".
296                 ...Now, WTF should happen? Well:
297                 - getTextureId strips off stuff recursively from the end until
298                   the remaining part is found, or nothing is left when
299                   something is stripped out
300
301                 But it is slow to search for textures by names and modify them
302                 like that?
303                 - ContentFeatures is made to contain ids for the basic plain
304                   textures
305                 - Crack textures can be slow by themselves, but the framework
306                   must be fast.
307
308                 Example case #2:
309                 - Assume a texture with the id 1 exists, and has the name
310                   "stone.png^mineral1" and is specified as a part of some atlas.
311                 - Now getNodeTile() stumbles upon a node which uses
312                   texture id 1, and determines that MATERIAL_FLAG_CRACK
313                   must be applied to the tile
314                 - MapBlockMesh::animate() finds the MATERIAL_FLAG_CRACK and
315                   has received the current crack level 0 from the client. It
316                   finds out the name of the texture with getTextureName(1),
317                   appends "^crack0" to it and gets a new texture id with
318                   getTextureId("stone.png^mineral1^crack0").
319
320         */
321         
322         /*
323                 Gets a texture id from cache or
324                 - if main thread, from getTextureIdDirect
325                 - if other thread, adds to request queue and waits for main thread
326         */
327         u32 getTextureId(const std::string &name);
328         
329         /*
330                 Example names:
331                 "stone.png"
332                 "stone.png^crack2"
333                 "stone.png^mineral_coal.png"
334                 "stone.png^mineral_coal.png^crack1"
335
336                 - If texture specified by name is found from cache, return the
337                   cached id.
338                 - Otherwise generate the texture, add to cache and return id.
339                   Recursion is used to find out the largest found part of the
340                   texture and continue based on it.
341
342                 The id 0 points to a NULL texture. It is returned in case of error.
343         */
344         u32 getTextureIdDirect(const std::string &name);
345
346         // Finds out the name of a cached texture.
347         std::string getTextureName(u32 id);
348
349         /*
350                 If texture specified by the name pointed by the id doesn't
351                 exist, create it, then return the cached texture.
352
353                 Can be called from any thread. If called from some other thread
354                 and not found in cache, the call is queued to the main thread
355                 for processing.
356         */
357         AtlasPointer getTexture(u32 id);
358         
359         AtlasPointer getTexture(const std::string &name)
360         {
361                 return getTexture(getTextureId(name));
362         }
363         
364         // Gets a separate texture
365         video::ITexture* getTextureRaw(const std::string &name)
366         {
367                 AtlasPointer ap = getTexture(name + m_forcesingle_suffix);
368                 return ap.atlas;
369         }
370
371         // Gets a separate texture atlas pointer
372         AtlasPointer getTextureRawAP(const AtlasPointer &ap)
373         {
374                 return getTexture(getTextureName(ap.id) + m_forcesingle_suffix);
375         }
376
377         // Returns a pointer to the irrlicht device
378         virtual IrrlichtDevice* getDevice()
379         {
380                 return m_device;
381         }
382
383         // Update new texture pointer and texture coordinates to an
384         // AtlasPointer based on it's texture id
385         void updateAP(AtlasPointer &ap);
386  
387         bool isKnownSourceImage(const std::string &name)
388         {
389                 bool is_known = false;
390                 bool cache_found = m_source_image_existence.get(name, &is_known);
391                 if(cache_found)
392                         return is_known;
393                 // Not found in cache; find out if a local file exists
394                 is_known = (getTexturePath(name) != "");
395                 m_source_image_existence.set(name, is_known);
396                 return is_known;
397         }
398
399         // Processes queued texture requests from other threads.
400         // Shall be called from the main thread.
401         void processQueue();
402         
403         // Insert an image into the cache without touching the filesystem.
404         // Shall be called from the main thread.
405         void insertSourceImage(const std::string &name, video::IImage *img);
406         
407         // Rebuild images and textures from the current set of source images
408         // Shall be called from the main thread.
409         void rebuildImagesAndTextures();
410
411         // Build the main texture atlas which contains most of the
412         // textures.
413         void buildMainAtlas(class IGameDef *gamedef);
414         
415 private:
416         
417         // The id of the thread that is allowed to use irrlicht directly
418         threadid_t m_main_thread;
419         // The irrlicht device
420         IrrlichtDevice *m_device;
421         
422         // Cache of source images
423         // This should be only accessed from the main thread
424         SourceImageCache m_sourcecache;
425
426         // Thread-safe cache of what source images are known (true = known)
427         MutexedMap<std::string, bool> m_source_image_existence;
428
429         // A texture id is index in this array.
430         // The first position contains a NULL texture.
431         std::vector<SourceAtlasPointer> m_atlaspointer_cache;
432         // Maps a texture name to an index in the former.
433         std::map<std::string, u32> m_name_to_id;
434         // The two former containers are behind this mutex
435         JMutex m_atlaspointer_cache_mutex;
436         
437         // Main texture atlas. This is filled at startup and is then not touched.
438         video::IImage *m_main_atlas_image;
439         video::ITexture *m_main_atlas_texture;
440         std::string m_forcesingle_suffix;
441
442         // Queued texture fetches (to be processed by the main thread)
443         RequestQueue<std::string, u32, u8, u8> m_get_texture_queue;
444
445         // Textures that have been overwritten with other ones
446         // but can't be deleted because the ITexture* might still be used
447         std::list<video::ITexture*> m_texture_trash;
448 };
449
450 IWritableTextureSource* createTextureSource(IrrlichtDevice *device)
451 {
452         return new TextureSource(device);
453 }
454
455 TextureSource::TextureSource(IrrlichtDevice *device):
456                 m_device(device),
457                 m_main_atlas_image(NULL),
458                 m_main_atlas_texture(NULL)
459 {
460         assert(m_device);
461         
462         m_atlaspointer_cache_mutex.Init();
463         
464         m_main_thread = get_current_thread_id();
465         
466         // Add a NULL AtlasPointer as the first index, named ""
467         m_atlaspointer_cache.push_back(SourceAtlasPointer(""));
468         m_name_to_id[""] = 0;
469 }
470
471 TextureSource::~TextureSource()
472 {
473         video::IVideoDriver* driver = m_device->getVideoDriver();
474
475         unsigned int textures_before = driver->getTextureCount();
476
477         for (std::vector<SourceAtlasPointer>::iterator iter =
478                         m_atlaspointer_cache.begin();  iter != m_atlaspointer_cache.end();
479                         iter++)
480         {
481                 video::ITexture *t = driver->getTexture(iter->name.c_str());
482
483                 //cleanup texture
484                 if (t)
485                         driver->removeTexture(t);
486
487                 //cleanup source image
488                 if (iter->atlas_img)
489                         iter->atlas_img->drop();
490         }
491         m_atlaspointer_cache.clear();
492
493         for (std::list<video::ITexture*>::iterator iter =
494                         m_texture_trash.begin(); iter != m_texture_trash.end();
495                         iter++)
496         {
497                 video::ITexture *t = *iter;
498
499                 //cleanup trashed texture
500                 driver->removeTexture(t);
501         }
502
503         infostream << "~TextureSource() "<< textures_before << "/"
504                         << driver->getTextureCount() << std::endl;
505 }
506
507 u32 TextureSource::getTextureId(const std::string &name)
508 {
509         //infostream<<"getTextureId(): \""<<name<<"\""<<std::endl;
510
511         {
512                 /*
513                         See if texture already exists
514                 */
515                 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
516                 std::map<std::string, u32>::iterator n;
517                 n = m_name_to_id.find(name);
518                 if(n != m_name_to_id.end())
519                 {
520                         return n->second;
521                 }
522         }
523         
524         /*
525                 Get texture
526         */
527         if(get_current_thread_id() == m_main_thread)
528         {
529                 return getTextureIdDirect(name);
530         }
531         else
532         {
533                 infostream<<"getTextureId(): Queued: name=\""<<name<<"\""<<std::endl;
534
535                 // We're gonna ask the result to be put into here
536                 ResultQueue<std::string, u32, u8, u8> result_queue;
537                 
538                 // Throw a request in
539                 m_get_texture_queue.add(name, 0, 0, &result_queue);
540                 
541                 infostream<<"Waiting for texture from main thread, name=\""
542                                 <<name<<"\""<<std::endl;
543                 
544                 try
545                 {
546                         // Wait result for a second
547                         GetResult<std::string, u32, u8, u8>
548                                         result = result_queue.pop_front(1000);
549                 
550                         // Check that at least something worked OK
551                         assert(result.key == name);
552
553                         return result.item;
554                 }
555                 catch(ItemNotFoundException &e)
556                 {
557                         infostream<<"Waiting for texture timed out."<<std::endl;
558                         return 0;
559                 }
560         }
561         
562         infostream<<"getTextureId(): Failed"<<std::endl;
563
564         return 0;
565 }
566
567 // Overlay image on top of another image (used for cracks)
568 void overlay(video::IImage *image, video::IImage *overlay);
569
570 // Draw an image on top of an another one, using the alpha channel of the
571 // source image
572 static void blit_with_alpha(video::IImage *src, video::IImage *dst,
573                 v2s32 src_pos, v2s32 dst_pos, v2u32 size);
574
575 // Brighten image
576 void brighten(video::IImage *image);
577 // Parse a transform name
578 u32 parseImageTransform(const std::string& s);
579 // Apply transform to image dimension
580 core::dimension2d<u32> imageTransformDimension(u32 transform, core::dimension2d<u32> dim);
581 // Apply transform to image data
582 void imageTransform(u32 transform, video::IImage *src, video::IImage *dst);
583
584 /*
585         Generate image based on a string like "stone.png" or "[crack0".
586         if baseimg is NULL, it is created. Otherwise stuff is made on it.
587 */
588 bool generate_image(std::string part_of_name, video::IImage *& baseimg,
589                 IrrlichtDevice *device, SourceImageCache *sourcecache);
590
591 /*
592         Generates an image from a full string like
593         "stone.png^mineral_coal.png^[crack0".
594
595         This is used by buildMainAtlas().
596 */
597 video::IImage* generate_image_from_scratch(std::string name,
598                 IrrlichtDevice *device, SourceImageCache *sourcecache);
599
600 /*
601         This method generates all the textures
602 */
603 u32 TextureSource::getTextureIdDirect(const std::string &name)
604 {
605         //infostream<<"getTextureIdDirect(): name=\""<<name<<"\""<<std::endl;
606
607         // Empty name means texture 0
608         if(name == "")
609         {
610                 infostream<<"getTextureIdDirect(): name is empty"<<std::endl;
611                 return 0;
612         }
613         
614         /*
615                 Calling only allowed from main thread
616         */
617         if(get_current_thread_id() != m_main_thread)
618         {
619                 errorstream<<"TextureSource::getTextureIdDirect() "
620                                 "called not from main thread"<<std::endl;
621                 return 0;
622         }
623
624         /*
625                 See if texture already exists
626         */
627         {
628                 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
629
630                 std::map<std::string, u32>::iterator n;
631                 n = m_name_to_id.find(name);
632                 if(n != m_name_to_id.end())
633                 {
634                         /*infostream<<"getTextureIdDirect(): \""<<name
635                                         <<"\" found in cache"<<std::endl;*/
636                         return n->second;
637                 }
638         }
639
640         /*infostream<<"getTextureIdDirect(): \""<<name
641                         <<"\" NOT found in cache. Creating it."<<std::endl;*/
642         
643         /*
644                 Get the base image
645         */
646
647         char separator = '^';
648
649         /*
650                 This is set to the id of the base image.
651                 If left 0, there is no base image and a completely new image
652                 is made.
653         */
654         u32 base_image_id = 0;
655         
656         // Find last meta separator in name
657         s32 last_separator_position = -1;
658         for(s32 i=name.size()-1; i>=0; i--)
659         {
660                 if(name[i] == separator)
661                 {
662                         last_separator_position = i;
663                         break;
664                 }
665         }
666         /*
667                 If separator was found, construct the base name and make the
668                 base image using a recursive call
669         */
670         std::string base_image_name;
671         if(last_separator_position != -1)
672         {
673                 // Construct base name
674                 base_image_name = name.substr(0, last_separator_position);
675                 /*infostream<<"getTextureIdDirect(): Calling itself recursively"
676                                 " to get base image of \""<<name<<"\" = \""
677                 <<base_image_name<<"\""<<std::endl;*/
678                 base_image_id = getTextureIdDirect(base_image_name);
679         }
680         
681         //infostream<<"base_image_id="<<base_image_id<<std::endl;
682         
683         video::IVideoDriver* driver = m_device->getVideoDriver();
684         assert(driver);
685
686         video::ITexture *t = NULL;
687
688         /*
689                 An image will be built from files and then converted into a texture.
690         */
691         video::IImage *baseimg = NULL;
692         
693         // If a base image was found, copy it to baseimg
694         if(base_image_id != 0)
695         {
696                 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
697
698                 SourceAtlasPointer ap = m_atlaspointer_cache[base_image_id];
699
700                 video::IImage *image = ap.atlas_img;
701                 
702                 if(image == NULL)
703                 {
704                         infostream<<"getTextureIdDirect(): WARNING: NULL image in "
705                                         <<"cache: \""<<base_image_name<<"\""
706                                         <<std::endl;
707                 }
708                 else
709                 {
710                         core::dimension2d<u32> dim = ap.intsize;
711
712                         baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
713
714                         core::position2d<s32> pos_to(0,0);
715                         core::position2d<s32> pos_from = ap.intpos;
716                         
717                         image->copyTo(
718                                         baseimg, // target
719                                         v2s32(0,0), // position in target
720                                         core::rect<s32>(pos_from, dim) // from
721                         );
722
723                         /*infostream<<"getTextureIdDirect(): Loaded \""
724                                         <<base_image_name<<"\" from image cache"
725                                         <<std::endl;*/
726                 }
727         }
728         
729         /*
730                 Parse out the last part of the name of the image and act
731                 according to it
732         */
733
734         std::string last_part_of_name = name.substr(last_separator_position+1);
735         //infostream<<"last_part_of_name=\""<<last_part_of_name<<"\""<<std::endl;
736
737         // Generate image according to part of name
738         if(!generate_image(last_part_of_name, baseimg, m_device, &m_sourcecache))
739         {
740                 errorstream<<"getTextureIdDirect(): "
741                                 "failed to generate \""<<last_part_of_name<<"\""
742                                 <<std::endl;
743         }
744
745         // If no resulting image, print a warning
746         if(baseimg == NULL)
747         {
748                 errorstream<<"getTextureIdDirect(): baseimg is NULL (attempted to"
749                                 " create texture \""<<name<<"\""<<std::endl;
750         }
751         
752         if(baseimg != NULL)
753         {
754                 // Create texture from resulting image
755                 t = driver->addTexture(name.c_str(), baseimg);
756         }
757         
758         /*
759                 Add texture to caches (add NULL textures too)
760         */
761
762         JMutexAutoLock lock(m_atlaspointer_cache_mutex);
763         
764         u32 id = m_atlaspointer_cache.size();
765         AtlasPointer ap(id);
766         ap.atlas = t;
767         ap.pos = v2f(0,0);
768         ap.size = v2f(1,1);
769         ap.tiled = 0;
770         core::dimension2d<u32> baseimg_dim(0,0);
771         if(baseimg)
772                 baseimg_dim = baseimg->getDimension();
773         SourceAtlasPointer nap(name, ap, baseimg, v2s32(0,0), baseimg_dim);
774         m_atlaspointer_cache.push_back(nap);
775         m_name_to_id[name] = id;
776
777         /*infostream<<"getTextureIdDirect(): "
778                         <<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;*/
779         
780         return id;
781 }
782
783 std::string TextureSource::getTextureName(u32 id)
784 {
785         JMutexAutoLock lock(m_atlaspointer_cache_mutex);
786
787         if(id >= m_atlaspointer_cache.size())
788         {
789                 errorstream<<"TextureSource::getTextureName(): id="<<id
790                                 <<" >= m_atlaspointer_cache.size()="
791                                 <<m_atlaspointer_cache.size()<<std::endl;
792                 return "";
793         }
794         
795         return m_atlaspointer_cache[id].name;
796 }
797
798
799 AtlasPointer TextureSource::getTexture(u32 id)
800 {
801         JMutexAutoLock lock(m_atlaspointer_cache_mutex);
802
803         if(id >= m_atlaspointer_cache.size())
804                 return AtlasPointer(0, NULL);
805         
806         return m_atlaspointer_cache[id].a;
807 }
808
809 void TextureSource::updateAP(AtlasPointer &ap)
810 {
811         AtlasPointer ap2 = getTexture(ap.id);
812         ap = ap2;
813 }
814
815 void TextureSource::processQueue()
816 {
817         /*
818                 Fetch textures
819         */
820         if(!m_get_texture_queue.empty())
821         {
822                 GetRequest<std::string, u32, u8, u8>
823                                 request = m_get_texture_queue.pop();
824
825                 /*infostream<<"TextureSource::processQueue(): "
826                                 <<"got texture request with "
827                                 <<"name=\""<<request.key<<"\""
828                                 <<std::endl;*/
829
830                 GetResult<std::string, u32, u8, u8>
831                                 result;
832                 result.key = request.key;
833                 result.callers = request.callers;
834                 result.item = getTextureIdDirect(request.key);
835
836                 request.dest->push_back(result);
837         }
838 }
839
840 void TextureSource::insertSourceImage(const std::string &name, video::IImage *img)
841 {
842         //infostream<<"TextureSource::insertSourceImage(): name="<<name<<std::endl;
843         
844         assert(get_current_thread_id() == m_main_thread);
845         
846         m_sourcecache.insert(name, img, true, m_device->getVideoDriver());
847         m_source_image_existence.set(name, true);
848 }
849         
850 void TextureSource::rebuildImagesAndTextures()
851 {
852         JMutexAutoLock lock(m_atlaspointer_cache_mutex);
853
854         /*// Oh well... just clear everything, they'll load sometime.
855         m_atlaspointer_cache.clear();
856         m_name_to_id.clear();*/
857
858         video::IVideoDriver* driver = m_device->getVideoDriver();
859         
860         // Remove source images from textures to disable inheriting textures
861         // from existing textures
862         /*for(u32 i=0; i<m_atlaspointer_cache.size(); i++){
863                 SourceAtlasPointer *sap = &m_atlaspointer_cache[i];
864                 sap->atlas_img->drop();
865                 sap->atlas_img = NULL;
866         }*/
867         
868         // Recreate textures
869         for(u32 i=0; i<m_atlaspointer_cache.size(); i++){
870                 SourceAtlasPointer *sap = &m_atlaspointer_cache[i];
871                 video::IImage *img =
872                         generate_image_from_scratch(sap->name, m_device, &m_sourcecache);
873                 // Create texture from resulting image
874                 video::ITexture *t = NULL;
875                 if(img)
876                         t = driver->addTexture(sap->name.c_str(), img);
877                 video::ITexture *t_old = sap->a.atlas;
878                 // Replace texture
879                 sap->a.atlas = t;
880                 sap->a.pos = v2f(0,0);
881                 sap->a.size = v2f(1,1);
882                 sap->a.tiled = 0;
883                 sap->atlas_img = img;
884                 sap->intpos = v2s32(0,0);
885                 sap->intsize = img->getDimension();
886
887                 if (t_old != 0)
888                         m_texture_trash.push_back(t_old);
889         }
890 }
891
892 void TextureSource::buildMainAtlas(class IGameDef *gamedef) 
893 {
894         assert(gamedef->tsrc() == this);
895         INodeDefManager *ndef = gamedef->ndef();
896
897         infostream<<"TextureSource::buildMainAtlas()"<<std::endl;
898
899         //return; // Disable (for testing)
900         
901         video::IVideoDriver* driver = m_device->getVideoDriver();
902         assert(driver);
903
904         JMutexAutoLock lock(m_atlaspointer_cache_mutex);
905
906         // Create an image of the right size
907         core::dimension2d<u32> max_dim = driver->getMaxTextureSize();
908         core::dimension2d<u32> atlas_dim(2048,2048);
909         atlas_dim.Width  = MYMIN(atlas_dim.Width,  max_dim.Width);
910         atlas_dim.Height = MYMIN(atlas_dim.Height, max_dim.Height);
911         video::IImage *atlas_img =
912                         driver->createImage(video::ECF_A8R8G8B8, atlas_dim);
913         //assert(atlas_img);
914         if(atlas_img == NULL)
915         {
916                 errorstream<<"TextureSource::buildMainAtlas(): Failed to create atlas "
917                                 "image; not building texture atlas."<<std::endl;
918                 return;
919         }
920
921         /*
922                 Grab list of stuff to include in the texture atlas from the
923                 main content features
924         */
925
926         std::set<std::string> sourcelist;
927
928         for(u16 j=0; j<MAX_CONTENT+1; j++)
929         {
930                 if(j == CONTENT_IGNORE || j == CONTENT_AIR)
931                         continue;
932                 const ContentFeatures &f = ndef->get(j);
933                 for(u32 i=0; i<6; i++)
934                 {
935                         std::string name = f.tiledef[i].name;
936                         sourcelist.insert(name);
937                 }
938         }
939         
940         infostream<<"Creating texture atlas out of textures: ";
941         for(std::set<std::string>::iterator
942                         i = sourcelist.begin();
943                         i != sourcelist.end(); ++i)
944         {
945                 std::string name = *i;
946                 infostream<<"\""<<name<<"\" ";
947         }
948         infostream<<std::endl;
949
950         // Padding to disallow texture bleeding
951         // (16 needed if mipmapping is used; otherwise less will work too)
952         s32 padding = 16;
953         s32 column_padding = 16;
954         s32 column_width = 256; // Space for 16 pieces of 16x16 textures
955
956         /*
957                 First pass: generate almost everything
958         */
959         core::position2d<s32> pos_in_atlas(0,0);
960         
961         pos_in_atlas.X = column_padding;
962         pos_in_atlas.Y = padding;
963
964         for(std::set<std::string>::iterator
965                         i = sourcelist.begin();
966                         i != sourcelist.end(); ++i)
967         {
968                 std::string name = *i;
969
970                 // Generate image by name
971                 video::IImage *img2 = generate_image_from_scratch(name, m_device,
972                                 &m_sourcecache);
973                 if(img2 == NULL)
974                 {
975                         errorstream<<"TextureSource::buildMainAtlas(): "
976                                         <<"Couldn't generate image \""<<name<<"\""<<std::endl;
977                         continue;
978                 }
979
980                 core::dimension2d<u32> dim = img2->getDimension();
981
982                 // Don't add to atlas if image is too large
983                 core::dimension2d<u32> max_size_in_atlas(64,64);
984                 if(dim.Width > max_size_in_atlas.Width
985                 || dim.Height > max_size_in_atlas.Height)
986                 {
987                         infostream<<"TextureSource::buildMainAtlas(): Not adding "
988                                         <<"\""<<name<<"\" because image is large"<<std::endl;
989                         continue;
990                 }
991
992                 // Wrap columns and stop making atlas if atlas is full
993                 if(pos_in_atlas.Y + dim.Height > atlas_dim.Height)
994                 {
995                         if(pos_in_atlas.X > (s32)atlas_dim.Width - column_width - column_padding){
996                                 errorstream<<"TextureSource::buildMainAtlas(): "
997                                                 <<"Atlas is full, not adding more textures."
998                                                 <<std::endl;
999                                 break;
1000                         }
1001                         pos_in_atlas.Y = padding;
1002                         pos_in_atlas.X += column_width + column_padding*2;
1003                 }
1004                 
1005                 /*infostream<<"TextureSource::buildMainAtlas(): Adding \""<<name
1006                                 <<"\" to texture atlas"<<std::endl;*/
1007
1008                 // Tile it a few times in the X direction
1009                 u16 xwise_tiling = column_width / dim.Width;
1010                 if(xwise_tiling > 16) // Limit to 16 (more gives no benefit)
1011                         xwise_tiling = 16;
1012                 for(u32 j=0; j<xwise_tiling; j++)
1013                 {
1014                         // Copy the copy to the atlas
1015                         /*img2->copyToWithAlpha(atlas_img,
1016                                         pos_in_atlas + v2s32(j*dim.Width,0),
1017                                         core::rect<s32>(v2s32(0,0), dim),
1018                                         video::SColor(255,255,255,255),
1019                                         NULL);*/
1020                         img2->copyTo(atlas_img,
1021                                         pos_in_atlas + v2s32(j*dim.Width,0),
1022                                         core::rect<s32>(v2s32(0,0), dim),
1023                                         NULL);
1024                 }
1025
1026                 // Copy the borders a few times to disallow texture bleeding
1027                 for(u32 side=0; side<2; side++) // top and bottom
1028                 for(s32 y0=0; y0<padding; y0++)
1029                 for(s32 x0=0; x0<(s32)xwise_tiling*(s32)dim.Width; x0++)
1030                 {
1031                         s32 dst_y;
1032                         s32 src_y;
1033                         if(side==0)
1034                         {
1035                                 dst_y = y0 + pos_in_atlas.Y + dim.Height;
1036                                 src_y = pos_in_atlas.Y + dim.Height - 1;
1037                         }
1038                         else
1039                         {
1040                                 dst_y = -y0 + pos_in_atlas.Y-1;
1041                                 src_y = pos_in_atlas.Y;
1042                         }
1043                         s32 x = x0 + pos_in_atlas.X;
1044                         video::SColor c = atlas_img->getPixel(x, src_y);
1045                         atlas_img->setPixel(x,dst_y,c);
1046                 }
1047
1048                 for(u32 side=0; side<2; side++) // left and right
1049                 for(s32 x0=0; x0<column_padding; x0++)
1050                 for(s32 y0=-padding; y0<(s32)dim.Height+padding; y0++)
1051                 {
1052                         s32 dst_x;
1053                         s32 src_x;
1054                         if(side==0)
1055                         {
1056                                 dst_x = x0 + pos_in_atlas.X + dim.Width*xwise_tiling;
1057                                 src_x = pos_in_atlas.X + dim.Width*xwise_tiling - 1;
1058                         }
1059                         else
1060                         {
1061                                 dst_x = -x0 + pos_in_atlas.X-1;
1062                                 src_x = pos_in_atlas.X;
1063                         }
1064                         s32 y = y0 + pos_in_atlas.Y;
1065                         s32 src_y = MYMAX((int)pos_in_atlas.Y, MYMIN((int)pos_in_atlas.Y + (int)dim.Height - 1, y));
1066                         s32 dst_y = y;
1067                         video::SColor c = atlas_img->getPixel(src_x, src_y);
1068                         atlas_img->setPixel(dst_x,dst_y,c);
1069                 }
1070
1071                 img2->drop();
1072
1073                 /*
1074                         Add texture to caches
1075                 */
1076                 
1077                 bool reuse_old_id = false;
1078                 u32 id = m_atlaspointer_cache.size();
1079                 // Check old id without fetching a texture
1080                 std::map<std::string, u32>::iterator n;
1081                 n = m_name_to_id.find(name);
1082                 // If it exists, we will replace the old definition
1083                 if(n != m_name_to_id.end()){
1084                         id = n->second;
1085                         reuse_old_id = true;
1086                         /*infostream<<"TextureSource::buildMainAtlas(): "
1087                                         <<"Replacing old AtlasPointer"<<std::endl;*/
1088                 }
1089
1090                 // Create AtlasPointer
1091                 AtlasPointer ap(id);
1092                 ap.atlas = NULL; // Set on the second pass
1093                 ap.pos = v2f((float)pos_in_atlas.X/(float)atlas_dim.Width,
1094                                 (float)pos_in_atlas.Y/(float)atlas_dim.Height);
1095                 ap.size = v2f((float)dim.Width/(float)atlas_dim.Width,
1096                                 (float)dim.Width/(float)atlas_dim.Height);
1097                 ap.tiled = xwise_tiling;
1098
1099                 // Create SourceAtlasPointer and add to containers
1100                 SourceAtlasPointer nap(name, ap, atlas_img, pos_in_atlas, dim);
1101                 if(reuse_old_id)
1102                         m_atlaspointer_cache[id] = nap;
1103                 else
1104                         m_atlaspointer_cache.push_back(nap);
1105                 m_name_to_id[name] = id;
1106                         
1107                 // Increment position
1108                 pos_in_atlas.Y += dim.Height + padding * 2;
1109         }
1110
1111         /*
1112                 Make texture
1113         */
1114         video::ITexture *t = driver->addTexture("__main_atlas__", atlas_img);
1115         assert(t);
1116
1117         /*
1118                 Second pass: set texture pointer in generated AtlasPointers
1119         */
1120         for(std::set<std::string>::iterator
1121                         i = sourcelist.begin();
1122                         i != sourcelist.end(); ++i)
1123         {
1124                 std::string name = *i;
1125                 if(m_name_to_id.find(name) == m_name_to_id.end())
1126                         continue;
1127                 u32 id = m_name_to_id[name];
1128                 //infostream<<"id of name "<<name<<" is "<<id<<std::endl;
1129                 m_atlaspointer_cache[id].a.atlas = t;
1130         }
1131
1132         /*
1133                 Write image to file so that it can be inspected
1134         */
1135         /*std::string atlaspath = porting::path_user
1136                         + DIR_DELIM + "generated_texture_atlas.png";
1137         infostream<<"Removing and writing texture atlas for inspection to "
1138                         <<atlaspath<<std::endl;
1139         fs::RecursiveDelete(atlaspath);
1140         driver->writeImageToFile(atlas_img, atlaspath.c_str());*/
1141
1142         m_forcesingle_suffix = "^[forcesingle";
1143 }
1144
1145 video::IImage* generate_image_from_scratch(std::string name,
1146                 IrrlichtDevice *device, SourceImageCache *sourcecache)
1147 {
1148         /*infostream<<"generate_image_from_scratch(): "
1149                         "\""<<name<<"\""<<std::endl;*/
1150         
1151         video::IVideoDriver* driver = device->getVideoDriver();
1152         assert(driver);
1153
1154         /*
1155                 Get the base image
1156         */
1157
1158         video::IImage *baseimg = NULL;
1159
1160         char separator = '^';
1161
1162         // Find last meta separator in name
1163         s32 last_separator_position = name.find_last_of(separator);
1164         //if(last_separator_position == std::npos)
1165         //      last_separator_position = -1;
1166
1167         /*infostream<<"generate_image_from_scratch(): "
1168                         <<"last_separator_position="<<last_separator_position
1169                         <<std::endl;*/
1170
1171         /*
1172                 If separator was found, construct the base name and make the
1173                 base image using a recursive call
1174         */
1175         std::string base_image_name;
1176         if(last_separator_position != -1)
1177         {
1178                 // Construct base name
1179                 base_image_name = name.substr(0, last_separator_position);
1180                 /*infostream<<"generate_image_from_scratch(): Calling itself recursively"
1181                                 " to get base image of \""<<name<<"\" = \""
1182                 <<base_image_name<<"\""<<std::endl;*/
1183                 baseimg = generate_image_from_scratch(base_image_name, device,
1184                                 sourcecache);
1185         }
1186         
1187         /*
1188                 Parse out the last part of the name of the image and act
1189                 according to it
1190         */
1191
1192         std::string last_part_of_name = name.substr(last_separator_position+1);
1193         //infostream<<"last_part_of_name=\""<<last_part_of_name<<"\""<<std::endl;
1194         
1195         // Generate image according to part of name
1196         if(!generate_image(last_part_of_name, baseimg, device, sourcecache))
1197         {
1198                 errorstream<<"generate_image_from_scratch(): "
1199                                 "failed to generate \""<<last_part_of_name<<"\""
1200                                 <<std::endl;
1201                 return NULL;
1202         }
1203         
1204         return baseimg;
1205 }
1206
1207 bool generate_image(std::string part_of_name, video::IImage *& baseimg,
1208                 IrrlichtDevice *device, SourceImageCache *sourcecache)
1209 {
1210         video::IVideoDriver* driver = device->getVideoDriver();
1211         assert(driver);
1212
1213         // Stuff starting with [ are special commands
1214         if(part_of_name.size() == 0 || part_of_name[0] != '[')
1215         {
1216                 video::IImage *image = sourcecache->getOrLoad(part_of_name, device);
1217
1218                 if(image == NULL)
1219                 {
1220                         if(part_of_name != ""){
1221                                 errorstream<<"generate_image(): Could not load image \""
1222                                                 <<part_of_name<<"\""<<" while building texture"<<std::endl;
1223                                 errorstream<<"generate_image(): Creating a dummy"
1224                                                 <<" image for \""<<part_of_name<<"\""<<std::endl;
1225                         }
1226
1227                         // Just create a dummy image
1228                         //core::dimension2d<u32> dim(2,2);
1229                         core::dimension2d<u32> dim(1,1);
1230                         image = driver->createImage(video::ECF_A8R8G8B8, dim);
1231                         assert(image);
1232                         /*image->setPixel(0,0, video::SColor(255,255,0,0));
1233                         image->setPixel(1,0, video::SColor(255,0,255,0));
1234                         image->setPixel(0,1, video::SColor(255,0,0,255));
1235                         image->setPixel(1,1, video::SColor(255,255,0,255));*/
1236                         image->setPixel(0,0, video::SColor(255,myrand()%256,
1237                                         myrand()%256,myrand()%256));
1238                         /*image->setPixel(1,0, video::SColor(255,myrand()%256,
1239                                         myrand()%256,myrand()%256));
1240                         image->setPixel(0,1, video::SColor(255,myrand()%256,
1241                                         myrand()%256,myrand()%256));
1242                         image->setPixel(1,1, video::SColor(255,myrand()%256,
1243                                         myrand()%256,myrand()%256));*/
1244                 }
1245
1246                 // If base image is NULL, load as base.
1247                 if(baseimg == NULL)
1248                 {
1249                         //infostream<<"Setting "<<part_of_name<<" as base"<<std::endl;
1250                         /*
1251                                 Copy it this way to get an alpha channel.
1252                                 Otherwise images with alpha cannot be blitted on 
1253                                 images that don't have alpha in the original file.
1254                         */
1255                         core::dimension2d<u32> dim = image->getDimension();
1256                         baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
1257                         image->copyTo(baseimg);
1258                 }
1259                 // Else blit on base.
1260                 else
1261                 {
1262                         //infostream<<"Blitting "<<part_of_name<<" on base"<<std::endl;
1263                         // Size of the copied area
1264                         core::dimension2d<u32> dim = image->getDimension();
1265                         //core::dimension2d<u32> dim(16,16);
1266                         // Position to copy the blitted to in the base image
1267                         core::position2d<s32> pos_to(0,0);
1268                         // Position to copy the blitted from in the blitted image
1269                         core::position2d<s32> pos_from(0,0);
1270                         // Blit
1271                         /*image->copyToWithAlpha(baseimg, pos_to,
1272                                         core::rect<s32>(pos_from, dim),
1273                                         video::SColor(255,255,255,255),
1274                                         NULL);*/
1275                         blit_with_alpha(image, baseimg, pos_from, pos_to, dim);
1276                 }
1277                 //cleanup
1278                 image->drop();
1279         }
1280         else
1281         {
1282                 // A special texture modification
1283
1284                 /*infostream<<"generate_image(): generating special "
1285                                 <<"modification \""<<part_of_name<<"\""
1286                                 <<std::endl;*/
1287                 
1288                 /*
1289                         This is the simplest of all; it just adds stuff to the
1290                         name so that a separate texture is created.
1291
1292                         It is used to make textures for stuff that doesn't want
1293                         to implement getting the texture from a bigger texture
1294                         atlas.
1295                 */
1296                 if(part_of_name == "[forcesingle")
1297                 {
1298                         // If base image is NULL, create a random color
1299                         if(baseimg == NULL)
1300                         {
1301                                 core::dimension2d<u32> dim(1,1);
1302                                 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
1303                                 assert(baseimg);
1304                                 baseimg->setPixel(0,0, video::SColor(255,myrand()%256,
1305                                                 myrand()%256,myrand()%256));
1306                         }
1307                 }
1308                 /*
1309                         [crackN
1310                         Adds a cracking texture
1311                 */
1312                 else if(part_of_name.substr(0,6) == "[crack")
1313                 {
1314                         if(baseimg == NULL)
1315                         {
1316                                 errorstream<<"generate_image(): baseimg==NULL "
1317                                                 <<"for part_of_name=\""<<part_of_name
1318                                                 <<"\", cancelling."<<std::endl;
1319                                 return false;
1320                         }
1321                         
1322                         // Crack image number and overlay option
1323                         s32 progression = 0;
1324                         bool use_overlay = false;
1325                         if(part_of_name.substr(6,1) == "o")
1326                         {
1327                                 progression = stoi(part_of_name.substr(7));
1328                                 use_overlay = true;
1329                         }
1330                         else
1331                         {
1332                                 progression = stoi(part_of_name.substr(6));
1333                                 use_overlay = false;
1334                         }
1335
1336                         // Size of the base image
1337                         core::dimension2d<u32> dim_base = baseimg->getDimension();
1338                         
1339                         /*
1340                                 Load crack image.
1341
1342                                 It is an image with a number of cracking stages
1343                                 horizontally tiled.
1344                         */
1345                         video::IImage *img_crack = sourcecache->getOrLoad(
1346                                         "crack_anylength.png", device);
1347                 
1348                         if(img_crack && progression >= 0)
1349                         {
1350                                 // Dimension of original image
1351                                 core::dimension2d<u32> dim_crack
1352                                                 = img_crack->getDimension();
1353                                 // Count of crack stages
1354                                 s32 crack_count = dim_crack.Height / dim_crack.Width;
1355                                 // Limit progression
1356                                 if(progression > crack_count-1)
1357                                         progression = crack_count-1;
1358                                 // Dimension of a single crack stage
1359                                 core::dimension2d<u32> dim_crack_cropped(
1360                                         dim_crack.Width,
1361                                         dim_crack.Width
1362                                 );
1363                                 // Create cropped and scaled crack images
1364                                 video::IImage *img_crack_cropped = driver->createImage(
1365                                                 video::ECF_A8R8G8B8, dim_crack_cropped);
1366                                 video::IImage *img_crack_scaled = driver->createImage(
1367                                                 video::ECF_A8R8G8B8, dim_base);
1368
1369                                 if(img_crack_cropped && img_crack_scaled)
1370                                 {
1371                                         // Crop crack image
1372                                         v2s32 pos_crack(0, progression*dim_crack.Width);
1373                                         img_crack->copyTo(img_crack_cropped,
1374                                                         v2s32(0,0),
1375                                                         core::rect<s32>(pos_crack, dim_crack_cropped));
1376                                         // Scale crack image by copying
1377                                         img_crack_cropped->copyToScaling(img_crack_scaled);
1378                                         // Copy or overlay crack image
1379                                         if(use_overlay)
1380                                         {
1381                                                 overlay(baseimg, img_crack_scaled);
1382                                         }
1383                                         else
1384                                         {
1385                                                 /*img_crack_scaled->copyToWithAlpha(
1386                                                                 baseimg,
1387                                                                 v2s32(0,0),
1388                                                                 core::rect<s32>(v2s32(0,0), dim_base),
1389                                                                 video::SColor(255,255,255,255));*/
1390                                                 blit_with_alpha(img_crack_scaled, baseimg,
1391                                                                 v2s32(0,0), v2s32(0,0), dim_base);
1392                                         }
1393                                 }
1394
1395                                 if(img_crack_scaled)
1396                                         img_crack_scaled->drop();
1397
1398                                 if(img_crack_cropped)
1399                                         img_crack_cropped->drop();
1400                                 
1401                                 img_crack->drop();
1402                         }
1403                 }
1404                 /*
1405                         [combine:WxH:X,Y=filename:X,Y=filename2
1406                         Creates a bigger texture from an amount of smaller ones
1407                 */
1408                 else if(part_of_name.substr(0,8) == "[combine")
1409                 {
1410                         Strfnd sf(part_of_name);
1411                         sf.next(":");
1412                         u32 w0 = stoi(sf.next("x"));
1413                         u32 h0 = stoi(sf.next(":"));
1414                         infostream<<"combined w="<<w0<<" h="<<h0<<std::endl;
1415                         core::dimension2d<u32> dim(w0,h0);
1416                         if(baseimg == NULL)
1417                         {
1418                                 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
1419                                 baseimg->fill(video::SColor(0,0,0,0));
1420                         }
1421                         while(sf.atend() == false)
1422                         {
1423                                 u32 x = stoi(sf.next(","));
1424                                 u32 y = stoi(sf.next("="));
1425                                 std::string filename = sf.next(":");
1426                                 infostream<<"Adding \""<<filename
1427                                                 <<"\" to combined ("<<x<<","<<y<<")"
1428                                                 <<std::endl;
1429                                 video::IImage *img = sourcecache->getOrLoad(filename, device);
1430                                 if(img)
1431                                 {
1432                                         core::dimension2d<u32> dim = img->getDimension();
1433                                         infostream<<"Size "<<dim.Width
1434                                                         <<"x"<<dim.Height<<std::endl;
1435                                         core::position2d<s32> pos_base(x, y);
1436                                         video::IImage *img2 =
1437                                                         driver->createImage(video::ECF_A8R8G8B8, dim);
1438                                         img->copyTo(img2);
1439                                         img->drop();
1440                                         /*img2->copyToWithAlpha(baseimg, pos_base,
1441                                                         core::rect<s32>(v2s32(0,0), dim),
1442                                                         video::SColor(255,255,255,255),
1443                                                         NULL);*/
1444                                         blit_with_alpha(img2, baseimg, v2s32(0,0), pos_base, dim);
1445                                         img2->drop();
1446                                 }
1447                                 else
1448                                 {
1449                                         infostream<<"img==NULL"<<std::endl;
1450                                 }
1451                         }
1452                 }
1453                 /*
1454                         "[brighten"
1455                 */
1456                 else if(part_of_name.substr(0,9) == "[brighten")
1457                 {
1458                         if(baseimg == NULL)
1459                         {
1460                                 errorstream<<"generate_image(): baseimg==NULL "
1461                                                 <<"for part_of_name=\""<<part_of_name
1462                                                 <<"\", cancelling."<<std::endl;
1463                                 return false;
1464                         }
1465
1466                         brighten(baseimg);
1467                 }
1468                 /*
1469                         "[noalpha"
1470                         Make image completely opaque.
1471                         Used for the leaves texture when in old leaves mode, so
1472                         that the transparent parts don't look completely black 
1473                         when simple alpha channel is used for rendering.
1474                 */
1475                 else if(part_of_name.substr(0,8) == "[noalpha")
1476                 {
1477                         if(baseimg == NULL)
1478                         {
1479                                 errorstream<<"generate_image(): baseimg==NULL "
1480                                                 <<"for part_of_name=\""<<part_of_name
1481                                                 <<"\", cancelling."<<std::endl;
1482                                 return false;
1483                         }
1484
1485                         core::dimension2d<u32> dim = baseimg->getDimension();
1486                         
1487                         // Set alpha to full
1488                         for(u32 y=0; y<dim.Height; y++)
1489                         for(u32 x=0; x<dim.Width; x++)
1490                         {
1491                                 video::SColor c = baseimg->getPixel(x,y);
1492                                 c.setAlpha(255);
1493                                 baseimg->setPixel(x,y,c);
1494                         }
1495                 }
1496                 /*
1497                         "[makealpha:R,G,B"
1498                         Convert one color to transparent.
1499                 */
1500                 else if(part_of_name.substr(0,11) == "[makealpha:")
1501                 {
1502                         if(baseimg == NULL)
1503                         {
1504                                 errorstream<<"generate_image(): baseimg==NULL "
1505                                                 <<"for part_of_name=\""<<part_of_name
1506                                                 <<"\", cancelling."<<std::endl;
1507                                 return false;
1508                         }
1509
1510                         Strfnd sf(part_of_name.substr(11));
1511                         u32 r1 = stoi(sf.next(","));
1512                         u32 g1 = stoi(sf.next(","));
1513                         u32 b1 = stoi(sf.next(""));
1514                         std::string filename = sf.next("");
1515
1516                         core::dimension2d<u32> dim = baseimg->getDimension();
1517                         
1518                         /*video::IImage *oldbaseimg = baseimg;
1519                         baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
1520                         oldbaseimg->copyTo(baseimg);
1521                         oldbaseimg->drop();*/
1522
1523                         // Set alpha to full
1524                         for(u32 y=0; y<dim.Height; y++)
1525                         for(u32 x=0; x<dim.Width; x++)
1526                         {
1527                                 video::SColor c = baseimg->getPixel(x,y);
1528                                 u32 r = c.getRed();
1529                                 u32 g = c.getGreen();
1530                                 u32 b = c.getBlue();
1531                                 if(!(r == r1 && g == g1 && b == b1))
1532                                         continue;
1533                                 c.setAlpha(0);
1534                                 baseimg->setPixel(x,y,c);
1535                         }
1536                 }
1537                 /*
1538                         "[transformN"
1539                         Rotates and/or flips the image.
1540
1541                         N can be a number (between 0 and 7) or a transform name.
1542                         Rotations are counter-clockwise.
1543                         0  I      identity
1544                         1  R90    rotate by 90 degrees
1545                         2  R180   rotate by 180 degrees
1546                         3  R270   rotate by 270 degrees
1547                         4  FX     flip X
1548                         5  FXR90  flip X then rotate by 90 degrees
1549                         6  FY     flip Y
1550                         7  FYR90  flip Y then rotate by 90 degrees
1551
1552                         Note: Transform names can be concatenated to produce
1553                         their product (applies the first then the second).
1554                         The resulting transform will be equivalent to one of the
1555                         eight existing ones, though (see: dihedral group).
1556                 */
1557                 else if(part_of_name.substr(0,10) == "[transform")
1558                 {
1559                         if(baseimg == NULL)
1560                         {
1561                                 errorstream<<"generate_image(): baseimg==NULL "
1562                                                 <<"for part_of_name=\""<<part_of_name
1563                                                 <<"\", cancelling."<<std::endl;
1564                                 return false;
1565                         }
1566
1567                         u32 transform = parseImageTransform(part_of_name.substr(10));
1568                         core::dimension2d<u32> dim = imageTransformDimension(
1569                                         transform, baseimg->getDimension());
1570                         video::IImage *image = driver->createImage(
1571                                         baseimg->getColorFormat(), dim);
1572                         assert(image);
1573                         imageTransform(transform, baseimg, image);
1574                         baseimg->drop();
1575                         baseimg = image;
1576                 }
1577                 /*
1578                         [inventorycube{topimage{leftimage{rightimage
1579                         In every subimage, replace ^ with &.
1580                         Create an "inventory cube".
1581                         NOTE: This should be used only on its own.
1582                         Example (a grass block (not actually used in game):
1583                         "[inventorycube{grass.png{mud.png&grass_side.png{mud.png&grass_side.png"
1584                 */
1585                 else if(part_of_name.substr(0,14) == "[inventorycube")
1586                 {
1587                         if(baseimg != NULL)
1588                         {
1589                                 errorstream<<"generate_image(): baseimg!=NULL "
1590                                                 <<"for part_of_name=\""<<part_of_name
1591                                                 <<"\", cancelling."<<std::endl;
1592                                 return false;
1593                         }
1594
1595                         str_replace_char(part_of_name, '&', '^');
1596                         Strfnd sf(part_of_name);
1597                         sf.next("{");
1598                         std::string imagename_top = sf.next("{");
1599                         std::string imagename_left = sf.next("{");
1600                         std::string imagename_right = sf.next("{");
1601
1602                         // Generate images for the faces of the cube
1603                         video::IImage *img_top = generate_image_from_scratch(
1604                                         imagename_top, device, sourcecache);
1605                         video::IImage *img_left = generate_image_from_scratch(
1606                                         imagename_left, device, sourcecache);
1607                         video::IImage *img_right = generate_image_from_scratch(
1608                                         imagename_right, device, sourcecache);
1609                         assert(img_top && img_left && img_right);
1610
1611                         // Create textures from images
1612                         video::ITexture *texture_top = driver->addTexture(
1613                                         (imagename_top + "__temp__").c_str(), img_top);
1614                         video::ITexture *texture_left = driver->addTexture(
1615                                         (imagename_left + "__temp__").c_str(), img_left);
1616                         video::ITexture *texture_right = driver->addTexture(
1617                                         (imagename_right + "__temp__").c_str(), img_right);
1618                         assert(texture_top && texture_left && texture_right);
1619
1620                         // Drop images
1621                         img_top->drop();
1622                         img_left->drop();
1623                         img_right->drop();
1624                         
1625                         /*
1626                                 Draw a cube mesh into a render target texture
1627                         */
1628                         scene::IMesh* cube = createCubeMesh(v3f(1, 1, 1));
1629                         setMeshColor(cube, video::SColor(255, 255, 255, 255));
1630                         cube->getMeshBuffer(0)->getMaterial().setTexture(0, texture_top);
1631                         cube->getMeshBuffer(1)->getMaterial().setTexture(0, texture_top);
1632                         cube->getMeshBuffer(2)->getMaterial().setTexture(0, texture_right);
1633                         cube->getMeshBuffer(3)->getMaterial().setTexture(0, texture_right);
1634                         cube->getMeshBuffer(4)->getMaterial().setTexture(0, texture_left);
1635                         cube->getMeshBuffer(5)->getMaterial().setTexture(0, texture_left);
1636
1637                         core::dimension2d<u32> dim(64,64);
1638                         std::string rtt_texture_name = part_of_name + "_RTT";
1639
1640                         v3f camera_position(0, 1.0, -1.5);
1641                         camera_position.rotateXZBy(45);
1642                         v3f camera_lookat(0, 0, 0);
1643                         core::CMatrix4<f32> camera_projection_matrix;
1644                         // Set orthogonal projection
1645                         camera_projection_matrix.buildProjectionMatrixOrthoLH(
1646                                         1.65, 1.65, 0, 100);
1647
1648                         video::SColorf ambient_light(0.2,0.2,0.2);
1649                         v3f light_position(10, 100, -50);
1650                         video::SColorf light_color(0.5,0.5,0.5);
1651                         f32 light_radius = 1000;
1652
1653                         video::ITexture *rtt = generateTextureFromMesh(
1654                                         cube, device, dim, rtt_texture_name,
1655                                         camera_position,
1656                                         camera_lookat,
1657                                         camera_projection_matrix,
1658                                         ambient_light,
1659                                         light_position,
1660                                         light_color,
1661                                         light_radius);
1662                         
1663                         // Drop mesh
1664                         cube->drop();
1665
1666                         // Free textures of images
1667                         driver->removeTexture(texture_top);
1668                         driver->removeTexture(texture_left);
1669                         driver->removeTexture(texture_right);
1670                         
1671                         if(rtt == NULL)
1672                         {
1673                                 baseimg = generate_image_from_scratch(
1674                                                 imagename_top, device, sourcecache);
1675                                 return true;
1676                         }
1677
1678                         // Create image of render target
1679                         video::IImage *image = driver->createImage(rtt, v2s32(0,0), dim);
1680                         assert(image);
1681
1682                         //cleanup texture
1683                         driver->removeTexture(rtt);
1684
1685                         baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
1686
1687                         if(image)
1688                         {
1689                                 image->copyTo(baseimg);
1690                                 image->drop();
1691                         }
1692                 }
1693                 /*
1694                         [lowpart:percent:filename
1695                         Adds the lower part of a texture
1696                 */
1697                 else if(part_of_name.substr(0,9) == "[lowpart:")
1698                 {
1699                         Strfnd sf(part_of_name);
1700                         sf.next(":");
1701                         u32 percent = stoi(sf.next(":"));
1702                         std::string filename = sf.next(":");
1703                         //infostream<<"power part "<<percent<<"%% of "<<filename<<std::endl;
1704
1705                         if(baseimg == NULL)
1706                                 baseimg = driver->createImage(video::ECF_A8R8G8B8, v2u32(16,16));
1707                         video::IImage *img = sourcecache->getOrLoad(filename, device);
1708                         if(img)
1709                         {
1710                                 core::dimension2d<u32> dim = img->getDimension();
1711                                 core::position2d<s32> pos_base(0, 0);
1712                                 video::IImage *img2 =
1713                                                 driver->createImage(video::ECF_A8R8G8B8, dim);
1714                                 img->copyTo(img2);
1715                                 img->drop();
1716                                 core::position2d<s32> clippos(0, 0);
1717                                 clippos.Y = dim.Height * (100-percent) / 100;
1718                                 core::dimension2d<u32> clipdim = dim;
1719                                 clipdim.Height = clipdim.Height * percent / 100 + 1;
1720                                 core::rect<s32> cliprect(clippos, clipdim);
1721                                 img2->copyToWithAlpha(baseimg, pos_base,
1722                                                 core::rect<s32>(v2s32(0,0), dim),
1723                                                 video::SColor(255,255,255,255),
1724                                                 &cliprect);
1725                                 img2->drop();
1726                         }
1727                 }
1728                 /*
1729                         [verticalframe:N:I
1730                         Crops a frame of a vertical animation.
1731                         N = frame count, I = frame index
1732                 */
1733                 else if(part_of_name.substr(0,15) == "[verticalframe:")
1734                 {
1735                         Strfnd sf(part_of_name);
1736                         sf.next(":");
1737                         u32 frame_count = stoi(sf.next(":"));
1738                         u32 frame_index = stoi(sf.next(":"));
1739
1740                         if(baseimg == NULL){
1741                                 errorstream<<"generate_image(): baseimg!=NULL "
1742                                                 <<"for part_of_name=\""<<part_of_name
1743                                                 <<"\", cancelling."<<std::endl;
1744                                 return false;
1745                         }
1746                         
1747                         v2u32 frame_size = baseimg->getDimension();
1748                         frame_size.Y /= frame_count;
1749
1750                         video::IImage *img = driver->createImage(video::ECF_A8R8G8B8,
1751                                         frame_size);
1752                         if(!img){
1753                                 errorstream<<"generate_image(): Could not create image "
1754                                                 <<"for part_of_name=\""<<part_of_name
1755                                                 <<"\", cancelling."<<std::endl;
1756                                 return false;
1757                         }
1758
1759                         // Fill target image with transparency
1760                         img->fill(video::SColor(0,0,0,0));
1761
1762                         core::dimension2d<u32> dim = frame_size;
1763                         core::position2d<s32> pos_dst(0, 0);
1764                         core::position2d<s32> pos_src(0, frame_index * frame_size.Y);
1765                         baseimg->copyToWithAlpha(img, pos_dst,
1766                                         core::rect<s32>(pos_src, dim),
1767                                         video::SColor(255,255,255,255),
1768                                         NULL);
1769                         // Replace baseimg
1770                         baseimg->drop();
1771                         baseimg = img;
1772                 }
1773                 else
1774                 {
1775                         errorstream<<"generate_image(): Invalid "
1776                                         " modification: \""<<part_of_name<<"\""<<std::endl;
1777                 }
1778         }
1779
1780         return true;
1781 }
1782
1783 void overlay(video::IImage *image, video::IImage *overlay)
1784 {
1785         /*
1786                 Copy overlay to image, taking alpha into account.
1787                 Where image is transparent, don't copy from overlay.
1788                 Images sizes must be identical.
1789         */
1790         if(image == NULL || overlay == NULL)
1791                 return;
1792         
1793         core::dimension2d<u32> dim = image->getDimension();
1794         core::dimension2d<u32> dim_overlay = overlay->getDimension();
1795         assert(dim == dim_overlay);
1796
1797         for(u32 y=0; y<dim.Height; y++)
1798         for(u32 x=0; x<dim.Width; x++)
1799         {
1800                 video::SColor c1 = image->getPixel(x,y);
1801                 video::SColor c2 = overlay->getPixel(x,y);
1802                 u32 a1 = c1.getAlpha();
1803                 u32 a2 = c2.getAlpha();
1804                 if(a1 == 255 && a2 != 0)
1805                 {
1806                         c1.setRed((c1.getRed()*(255-a2) + c2.getRed()*a2)/255);
1807                         c1.setGreen((c1.getGreen()*(255-a2) + c2.getGreen()*a2)/255);
1808                         c1.setBlue((c1.getBlue()*(255-a2) + c2.getBlue()*a2)/255);
1809                 }
1810                 image->setPixel(x,y,c1);
1811         }
1812 }
1813
1814 /*
1815         Draw an image on top of an another one, using the alpha channel of the
1816         source image
1817
1818         This exists because IImage::copyToWithAlpha() doesn't seem to always
1819         work.
1820 */
1821 static void blit_with_alpha(video::IImage *src, video::IImage *dst,
1822                 v2s32 src_pos, v2s32 dst_pos, v2u32 size)
1823 {
1824         for(u32 y0=0; y0<size.Y; y0++)
1825         for(u32 x0=0; x0<size.X; x0++)
1826         {
1827                 s32 src_x = src_pos.X + x0;
1828                 s32 src_y = src_pos.Y + y0;
1829                 s32 dst_x = dst_pos.X + x0;
1830                 s32 dst_y = dst_pos.Y + y0;
1831                 video::SColor src_c = src->getPixel(src_x, src_y);
1832                 video::SColor dst_c = dst->getPixel(dst_x, dst_y);
1833                 dst_c = src_c.getInterpolated(dst_c, (float)src_c.getAlpha()/255.0f);
1834                 dst->setPixel(dst_x, dst_y, dst_c);
1835         }
1836 }
1837
1838 void brighten(video::IImage *image)
1839 {
1840         if(image == NULL)
1841                 return;
1842         
1843         core::dimension2d<u32> dim = image->getDimension();
1844
1845         for(u32 y=0; y<dim.Height; y++)
1846         for(u32 x=0; x<dim.Width; x++)
1847         {
1848                 video::SColor c = image->getPixel(x,y);
1849                 c.setRed(0.5 * 255 + 0.5 * (float)c.getRed());
1850                 c.setGreen(0.5 * 255 + 0.5 * (float)c.getGreen());
1851                 c.setBlue(0.5 * 255 + 0.5 * (float)c.getBlue());
1852                 image->setPixel(x,y,c);
1853         }
1854 }
1855
1856 u32 parseImageTransform(const std::string& s)
1857 {
1858         int total_transform = 0;
1859
1860         std::string transform_names[8];
1861         transform_names[0] = "i";
1862         transform_names[1] = "r90";
1863         transform_names[2] = "r180";
1864         transform_names[3] = "r270";
1865         transform_names[4] = "fx";
1866         transform_names[6] = "fy";
1867
1868         std::size_t pos = 0;
1869         while(pos < s.size())
1870         {
1871                 int transform = -1;
1872                 for(int i = 0; i <= 7; ++i)
1873                 {
1874                         const std::string &name_i = transform_names[i];
1875
1876                         if(s[pos] == ('0' + i))
1877                         {
1878                                 transform = i;
1879                                 pos++;
1880                                 break;
1881                         }
1882                         else if(!(name_i.empty()) &&
1883                                 lowercase(s.substr(pos, name_i.size())) == name_i)
1884                         {
1885                                 transform = i;
1886                                 pos += name_i.size();
1887                                 break;
1888                         }
1889                 }
1890                 if(transform < 0)
1891                         break;
1892
1893                 // Multiply total_transform and transform in the group D4
1894                 int new_total = 0;
1895                 if(transform < 4)
1896                         new_total = (transform + total_transform) % 4;
1897                 else
1898                         new_total = (transform - total_transform + 8) % 4;
1899                 if((transform >= 4) ^ (total_transform >= 4))
1900                         new_total += 4;
1901
1902                 total_transform = new_total;
1903         }
1904         return total_transform;
1905 }
1906
1907 core::dimension2d<u32> imageTransformDimension(u32 transform, core::dimension2d<u32> dim)
1908 {
1909         if(transform % 2 == 0)
1910                 return dim;
1911         else
1912                 return core::dimension2d<u32>(dim.Height, dim.Width);
1913 }
1914
1915 void imageTransform(u32 transform, video::IImage *src, video::IImage *dst)
1916 {
1917         if(src == NULL || dst == NULL)
1918                 return;
1919         
1920         core::dimension2d<u32> srcdim = src->getDimension();
1921         core::dimension2d<u32> dstdim = dst->getDimension();
1922
1923         assert(dstdim == imageTransformDimension(transform, srcdim));
1924         assert(transform >= 0 && transform <= 7);
1925
1926         /*
1927                 Compute the transformation from source coordinates (sx,sy)
1928                 to destination coordinates (dx,dy).
1929         */
1930         int sxn = 0;
1931         int syn = 2;
1932         if(transform == 0)         // identity
1933                 sxn = 0, syn = 2;  //   sx = dx, sy = dy
1934         else if(transform == 1)    // rotate by 90 degrees ccw
1935                 sxn = 3, syn = 0;  //   sx = (H-1) - dy, sy = dx
1936         else if(transform == 2)    // rotate by 180 degrees
1937                 sxn = 1, syn = 3;  //   sx = (W-1) - dx, sy = (H-1) - dy
1938         else if(transform == 3)    // rotate by 270 degrees ccw
1939                 sxn = 2, syn = 1;  //   sx = dy, sy = (W-1) - dx
1940         else if(transform == 4)    // flip x
1941                 sxn = 1, syn = 2;  //   sx = (W-1) - dx, sy = dy
1942         else if(transform == 5)    // flip x then rotate by 90 degrees ccw
1943                 sxn = 2, syn = 0;  //   sx = dy, sy = dx
1944         else if(transform == 6)    // flip y
1945                 sxn = 0, syn = 3;  //   sx = dx, sy = (H-1) - dy
1946         else if(transform == 7)    // flip y then rotate by 90 degrees ccw
1947                 sxn = 3, syn = 1;  //   sx = (H-1) - dy, sy = (W-1) - dx
1948
1949         for(u32 dy=0; dy<dstdim.Height; dy++)
1950         for(u32 dx=0; dx<dstdim.Width; dx++)
1951         {
1952                 u32 entries[4] = {dx, dstdim.Width-1-dx, dy, dstdim.Height-1-dy};
1953                 u32 sx = entries[sxn];
1954                 u32 sy = entries[syn];
1955                 video::SColor c = src->getPixel(sx,sy);
1956                 dst->setPixel(dx,dy,c);
1957         }
1958 }