3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
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 General Public License for more details.
15 You should have received a copy of the GNU 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.
22 #include "main.h" // for g_settings
26 Replaces the filename extension.
28 std::string image = "a/image.png"
29 replace_ext(image, "jpg")
30 -> image = "a/image.jpg"
31 Returns true on success.
33 inline bool replace_ext(std::string &path, const char *ext)
37 // Find place of last dot, fail if \ or / found.
39 for(s32 i=path.size()-1; i>=0; i--)
47 if(path[i] == '\\' || path[i] == '/')
50 // If not found, return an empty string
53 // Else make the new path
54 path = path.substr(0, last_dot_i+1) + ext;
59 Find out the full path of an image by trying different filename
64 inline std::string getImagePath(std::string path)
66 // A NULL-ended list of possible image extensions
67 const char *extensions[] = {
68 "png", "jpg", "bmp", "tga",
69 "pcx", "ppm", "psd", "wal", "rgb",
73 const char **ext = extensions;
75 bool r = replace_ext(path, *ext);
78 if(fs::PathExists(path))
81 while((++ext) != NULL);
87 Gets the path to a texture by first checking if the texture exists
88 in texture_path and if not, using the data path.
90 inline std::string getTexturePath(std::string filename)
92 std::string texture_path = g_settings.get("texture_path");
93 if(texture_path != "")
95 std::string fullpath = texture_path + '/' + filename;
96 // Check all filename extensions
97 fullpath = getImagePath(fullpath);
98 // If found, return it
102 std::string fullpath = porting::getDataPath(filename.c_str());
103 // Check all filename extensions
104 fullpath = getImagePath(fullpath);
108 TextureSource::TextureSource(IrrlichtDevice *device):
110 m_main_atlas_image(NULL),
111 m_main_atlas_texture(NULL)
115 m_atlaspointer_cache_mutex.Init();
117 m_main_thread = get_current_thread_id();
119 // Add a NULL AtlasPointer as the first index, named ""
120 m_atlaspointer_cache.push_back(SourceAtlasPointer(""));
121 m_name_to_id[""] = 0;
123 // Build main texture atlas
124 if(g_settings.getBool("enable_texture_atlas"))
127 dstream<<"INFO: Not building texture atlas."<<std::endl;
130 TextureSource::~TextureSource()
134 void TextureSource::processQueue()
139 if(m_get_texture_queue.size() > 0)
141 GetRequest<std::string, u32, u8, u8>
142 request = m_get_texture_queue.pop();
144 dstream<<"INFO: TextureSource::processQueue(): "
145 <<"got texture request with "
146 <<"name="<<request.key
149 GetResult<std::string, u32, u8, u8>
151 result.key = request.key;
152 result.callers = request.callers;
153 result.item = getTextureIdDirect(request.key);
155 request.dest->push_back(result);
159 u32 TextureSource::getTextureId(const std::string &name)
161 //dstream<<"INFO: getTextureId(): name="<<name<<std::endl;
165 See if texture already exists
167 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
168 core::map<std::string, u32>::Node *n;
169 n = m_name_to_id.find(name);
172 return n->getValue();
179 if(get_current_thread_id() == m_main_thread)
181 return getTextureIdDirect(name);
185 dstream<<"INFO: getTextureId(): Queued: name="<<name<<std::endl;
187 // We're gonna ask the result to be put into here
188 ResultQueue<std::string, u32, u8, u8> result_queue;
190 // Throw a request in
191 m_get_texture_queue.add(name, 0, 0, &result_queue);
193 dstream<<"INFO: Waiting for texture from main thread, name="
198 // Wait result for a second
199 GetResult<std::string, u32, u8, u8>
200 result = result_queue.pop_front(1000);
202 // Check that at least something worked OK
203 assert(result.key == name);
207 catch(ItemNotFoundException &e)
209 dstream<<"WARNING: Waiting for texture timed out."<<std::endl;
214 dstream<<"WARNING: getTextureId(): Failed"<<std::endl;
219 // Draw a progress bar on the image
220 void make_progressbar(float value, video::IImage *image);
223 Generate image based on a string like "stone.png" or "[crack0".
224 if baseimg is NULL, it is created. Otherwise stuff is made on it.
226 bool generate_image(std::string part_of_name, video::IImage *& baseimg,
227 IrrlichtDevice *device);
230 Generates an image from a full string like
231 "stone.png^mineral_coal.png^[crack0".
233 This is used by buildMainAtlas().
235 video::IImage* generate_image_from_scratch(std::string name,
236 IrrlichtDevice *device);
239 This method generates all the textures
241 u32 TextureSource::getTextureIdDirect(const std::string &name)
243 dstream<<"INFO: getTextureIdDirect(): name="<<name<<std::endl;
245 // Empty name means texture 0
248 dstream<<"INFO: getTextureIdDirect(): name is empty"<<std::endl;
253 Calling only allowed from main thread
255 if(get_current_thread_id() != m_main_thread)
257 dstream<<"ERROR: TextureSource::getTextureIdDirect() "
258 "called not from main thread"<<std::endl;
263 See if texture already exists
266 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
268 core::map<std::string, u32>::Node *n;
269 n = m_name_to_id.find(name);
272 dstream<<"INFO: getTextureIdDirect(): name="<<name
273 <<" found in cache"<<std::endl;
274 return n->getValue();
278 dstream<<"INFO: getTextureIdDirect(): name="<<name
279 <<" NOT found in cache. Creating it."<<std::endl;
285 char separator = '^';
288 This is set to the id of the base image.
289 If left 0, there is no base image and a completely new image
292 u32 base_image_id = 0;
294 // Find last meta separator in name
295 s32 last_separator_position = -1;
296 for(s32 i=name.size()-1; i>=0; i--)
298 if(name[i] == separator)
300 last_separator_position = i;
305 If separator was found, construct the base name and make the
306 base image using a recursive call
308 std::string base_image_name;
309 if(last_separator_position != -1)
311 // Construct base name
312 base_image_name = name.substr(0, last_separator_position);
313 dstream<<"INFO: getTextureIdDirect(): Calling itself recursively"
314 " to get base image, name="<<base_image_name<<std::endl;
315 base_image_id = getTextureIdDirect(base_image_name);
318 dstream<<"base_image_id="<<base_image_id<<std::endl;
320 video::IVideoDriver* driver = m_device->getVideoDriver();
323 video::ITexture *t = NULL;
326 An image will be built from files and then converted into a texture.
328 video::IImage *baseimg = NULL;
330 // If a base image was found, copy it to baseimg
331 if(base_image_id != 0)
333 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
335 SourceAtlasPointer ap = m_atlaspointer_cache[base_image_id];
337 video::IImage *image = ap.atlas_img;
341 dstream<<"WARNING: getTextureIdDirect(): NULL image in "
342 <<"cache: \""<<base_image_name<<"\""
347 core::dimension2d<u32> dim = ap.intsize;
349 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
351 core::position2d<s32> pos_to(0,0);
352 core::position2d<s32> pos_from = ap.intpos;
356 v2s32(0,0), // position in target
357 core::rect<s32>(pos_from, dim) // from
360 dstream<<"INFO: getTextureIdDirect(): Loaded \""
361 <<base_image_name<<"\" from image cache"
367 Parse out the last part of the name of the image and act
371 std::string last_part_of_name = name.substr(last_separator_position+1);
372 dstream<<"last_part_of_name="<<last_part_of_name<<std::endl;
374 // Generate image according to part of name
375 if(generate_image(last_part_of_name, baseimg, m_device) == false)
377 dstream<<"INFO: getTextureIdDirect(): "
378 "failed to generate \""<<last_part_of_name<<"\""
382 // If no resulting image, print a warning
385 dstream<<"WARNING: getTextureIdDirect(): baseimg is NULL (attempted to"
386 " create texture \""<<name<<"\""<<std::endl;
391 // Create texture from resulting image
392 t = driver->addTexture(name.c_str(), baseimg);
396 Add texture to caches (add NULL textures too)
399 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
401 u32 id = m_atlaspointer_cache.size();
407 core::dimension2d<u32> baseimg_dim(0,0);
409 baseimg_dim = baseimg->getDimension();
410 SourceAtlasPointer nap(name, ap, baseimg, v2s32(0,0), baseimg_dim);
411 m_atlaspointer_cache.push_back(nap);
412 m_name_to_id.insert(name, id);
414 dstream<<"INFO: getTextureIdDirect(): name="<<name
415 <<": succesfully returning id="<<id<<std::endl;
420 std::string TextureSource::getTextureName(u32 id)
422 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
424 if(id >= m_atlaspointer_cache.size())
426 dstream<<"WARNING: TextureSource::getTextureName(): id="<<id
427 <<" >= m_atlaspointer_cache.size()="
428 <<m_atlaspointer_cache.size()<<std::endl;
432 return m_atlaspointer_cache[id].name;
436 AtlasPointer TextureSource::getTexture(u32 id)
438 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
440 if(id >= m_atlaspointer_cache.size())
441 return AtlasPointer(0, NULL);
443 return m_atlaspointer_cache[id].a;
446 void TextureSource::buildMainAtlas()
448 dstream<<"TextureSource::buildMainAtlas()"<<std::endl;
450 //return; // Disable (for testing)
452 video::IVideoDriver* driver = m_device->getVideoDriver();
455 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
457 // Create an image of the right size
458 core::dimension2d<u32> atlas_dim(1024,1024);
459 video::IImage *atlas_img =
460 driver->createImage(video::ECF_A8R8G8B8, atlas_dim);
464 A list of stuff to add. This should contain as much of the
465 stuff shown in game as possible, to minimize texture changes.
468 core::array<std::string> sourcelist;
470 sourcelist.push_back("stone.png");
471 sourcelist.push_back("mud.png");
472 sourcelist.push_back("sand.png");
473 sourcelist.push_back("grass.png");
474 sourcelist.push_back("grass_footsteps.png");
475 sourcelist.push_back("tree.png");
476 sourcelist.push_back("tree_top.png");
477 sourcelist.push_back("water.png");
478 sourcelist.push_back("leaves.png");
479 sourcelist.push_back("glass.png");
480 sourcelist.push_back("mud.png^grass_side.png");
481 sourcelist.push_back("cobble.png");
483 sourcelist.push_back("stone.png^mineral_coal.png");
484 sourcelist.push_back("stone.png^mineral_iron.png");
485 sourcelist.push_back("mud.png^mineral_coal.png");
486 sourcelist.push_back("mud.png^mineral_iron.png");
487 sourcelist.push_back("sand.png^mineral_coal.png");
488 sourcelist.push_back("sand.png^mineral_iron.png");
490 // Padding to disallow texture bleeding
494 First pass: generate almost everything
496 core::position2d<s32> pos_in_atlas(0,0);
498 pos_in_atlas.Y += padding;
500 for(u32 i=0; i<sourcelist.size(); i++)
502 std::string name = sourcelist[i];
504 /*video::IImage *img = driver->createImageFromFile(
505 getTexturePath(name.c_str()).c_str());
509 core::dimension2d<u32> dim = img->getDimension();
510 // Make a copy with the right color format
511 video::IImage *img2 =
512 driver->createImage(video::ECF_A8R8G8B8, dim);
516 // Generate image by name
517 video::IImage *img2 = generate_image_from_scratch(name, m_device);
520 dstream<<"WARNING: TextureSource::buildMainAtlas(): Couldn't generate texture atlas: Couldn't generate image \""<<name<<"\""<<std::endl;
524 core::dimension2d<u32> dim = img2->getDimension();
526 // Don't add to atlas if image is large
527 core::dimension2d<u32> max_size_in_atlas(32,32);
528 if(dim.Width > max_size_in_atlas.Width
529 || dim.Height > max_size_in_atlas.Height)
531 dstream<<"INFO: TextureSource::buildMainAtlas(): Not adding "
532 <<"\""<<name<<"\" because image is large"<<std::endl;
536 // Stop making atlas if atlas is full
537 if(pos_in_atlas.Y + dim.Height > atlas_dim.Height)
539 dstream<<"WARNING: TextureSource::buildMainAtlas(): "
540 <<"Atlas is full, not adding more textures."
545 // Tile it a few times in the X direction
546 u16 xwise_tiling = 16;
547 for(u32 j=0; j<xwise_tiling; j++)
549 // Copy the copy to the atlas
550 img2->copyToWithAlpha(atlas_img,
551 pos_in_atlas + v2s32(j*dim.Width,0),
552 core::rect<s32>(v2s32(0,0), dim),
553 video::SColor(255,255,255,255),
557 // Copy the borders a few times to disallow texture bleeding
558 for(u32 side=0; side<2; side++) // top and bottom
559 for(s32 y0=0; y0<padding; y0++)
560 for(s32 x0=0; x0<(s32)xwise_tiling*(s32)dim.Width; x0++)
566 dst_y = y0 + pos_in_atlas.Y + dim.Height;
567 src_y = pos_in_atlas.Y + dim.Height - 1;
571 dst_y = -y0 + pos_in_atlas.Y-1;
572 src_y = pos_in_atlas.Y;
574 s32 x = x0 + pos_in_atlas.X * dim.Width;
575 video::SColor c = atlas_img->getPixel(x, src_y);
576 atlas_img->setPixel(x,dst_y,c);
582 Add texture to caches
586 u32 id = m_atlaspointer_cache.size();
588 // Create AtlasPointer
590 ap.atlas = NULL; // Set on the second pass
591 ap.pos = v2f((float)pos_in_atlas.X/(float)atlas_dim.Width,
592 (float)pos_in_atlas.Y/(float)atlas_dim.Height);
593 ap.size = v2f((float)dim.Width/(float)atlas_dim.Width,
594 (float)dim.Width/(float)atlas_dim.Height);
595 ap.tiled = xwise_tiling;
597 // Create SourceAtlasPointer and add to containers
598 SourceAtlasPointer nap(name, ap, atlas_img, pos_in_atlas, dim);
599 m_atlaspointer_cache.push_back(nap);
600 m_name_to_id.insert(name, id);
602 // Increment position
603 pos_in_atlas.Y += dim.Height + padding * 2;
609 video::ITexture *t = driver->addTexture("__main_atlas__", atlas_img);
613 Second pass: set texture pointer in generated AtlasPointers
615 for(u32 i=0; i<sourcelist.size(); i++)
617 std::string name = sourcelist[i];
618 if(m_name_to_id.find(name) == NULL)
620 u32 id = m_name_to_id[name];
621 //dstream<<"id of name "<<name<<" is "<<id<<std::endl;
622 m_atlaspointer_cache[id].a.atlas = t;
626 Write image to file so that it can be inspected
628 /*driver->writeImageToFile(atlas_img,
629 getTexturePath("main_atlas.png").c_str());*/
632 video::IImage* generate_image_from_scratch(std::string name,
633 IrrlichtDevice *device)
635 dstream<<"INFO: generate_image_from_scratch(): "
636 "name="<<name<<std::endl;
638 video::IVideoDriver* driver = device->getVideoDriver();
645 video::IImage *baseimg = NULL;
647 char separator = '^';
649 // Find last meta separator in name
650 s32 last_separator_position = -1;
651 for(s32 i=name.size()-1; i>=0; i--)
653 if(name[i] == separator)
655 last_separator_position = i;
660 /*dstream<<"INFO: generate_image_from_scratch(): "
661 <<"last_separator_position="<<last_separator_position
665 If separator was found, construct the base name and make the
666 base image using a recursive call
668 std::string base_image_name;
669 if(last_separator_position != -1)
671 // Construct base name
672 base_image_name = name.substr(0, last_separator_position);
673 dstream<<"INFO: generate_image_from_scratch(): Calling itself recursively"
674 " to get base image, name="<<base_image_name<<std::endl;
675 baseimg = generate_image_from_scratch(base_image_name, device);
679 Parse out the last part of the name of the image and act
683 std::string last_part_of_name = name.substr(last_separator_position+1);
684 dstream<<"last_part_of_name="<<last_part_of_name<<std::endl;
686 // Generate image according to part of name
687 if(generate_image(last_part_of_name, baseimg, device) == false)
689 dstream<<"INFO: generate_image_from_scratch(): "
690 "failed to generate \""<<last_part_of_name<<"\""
698 bool generate_image(std::string part_of_name, video::IImage *& baseimg,
699 IrrlichtDevice *device)
701 video::IVideoDriver* driver = device->getVideoDriver();
704 // Stuff starting with [ are special commands
705 if(part_of_name[0] != '[')
707 // A normal texture; load it from a file
708 std::string path = getTexturePath(part_of_name.c_str());
709 dstream<<"INFO: getTextureIdDirect(): Loading path \""<<path
712 video::IImage *image = driver->createImageFromFile(path.c_str());
716 dstream<<"WARNING: Could not load image \""<<part_of_name
717 <<"\" from path \""<<path<<"\""
718 <<" while building texture"<<std::endl;
722 dstream<<"WARNING: Creating a dummy"<<" image for \""
723 <<part_of_name<<"\""<<std::endl;
725 // Just create a dummy image
726 //core::dimension2d<u32> dim(2,2);
727 core::dimension2d<u32> dim(1,1);
728 image = driver->createImage(video::ECF_A8R8G8B8, dim);
730 /*image->setPixel(0,0, video::SColor(255,255,0,0));
731 image->setPixel(1,0, video::SColor(255,0,255,0));
732 image->setPixel(0,1, video::SColor(255,0,0,255));
733 image->setPixel(1,1, video::SColor(255,255,0,255));*/
734 image->setPixel(0,0, video::SColor(255,myrand()%256,
735 myrand()%256,myrand()%256));
736 /*image->setPixel(1,0, video::SColor(255,myrand()%256,
737 myrand()%256,myrand()%256));
738 image->setPixel(0,1, video::SColor(255,myrand()%256,
739 myrand()%256,myrand()%256));
740 image->setPixel(1,1, video::SColor(255,myrand()%256,
741 myrand()%256,myrand()%256));*/
744 // If base image is NULL, load as base.
747 dstream<<"INFO: Setting "<<part_of_name<<" as base"<<std::endl;
749 Copy it this way to get an alpha channel.
750 Otherwise images with alpha cannot be blitted on
751 images that don't have alpha in the original file.
753 core::dimension2d<u32> dim = image->getDimension();
754 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
755 image->copyTo(baseimg);
758 // Else blit on base.
761 dstream<<"INFO: Blitting "<<part_of_name<<" on base"<<std::endl;
762 // Size of the copied area
763 core::dimension2d<u32> dim = image->getDimension();
764 //core::dimension2d<u32> dim(16,16);
765 // Position to copy the blitted to in the base image
766 core::position2d<s32> pos_to(0,0);
767 // Position to copy the blitted from in the blitted image
768 core::position2d<s32> pos_from(0,0);
770 image->copyToWithAlpha(baseimg, pos_to,
771 core::rect<s32>(pos_from, dim),
772 video::SColor(255,255,255,255),
780 // A special texture modification
782 dstream<<"INFO: getTextureIdDirect(): generating special "
783 <<"modification \""<<part_of_name<<"\""
787 This is the simplest of all; it just adds stuff to the
788 name so that a separate texture is created.
790 It is used to make textures for stuff that doesn't want
791 to implement getting the texture from a bigger texture
794 if(part_of_name == "[forcesingle")
799 Adds a cracking texture
801 else if(part_of_name.substr(0,6) == "[crack")
805 dstream<<"WARNING: getTextureIdDirect(): baseimg==NULL "
806 <<"for part_of_name="<<part_of_name
807 <<", cancelling."<<std::endl;
811 // Crack image number
812 u16 progression = stoi(part_of_name.substr(6));
814 // Size of the base image
815 core::dimension2d<u32> dim_base = baseimg->getDimension();
820 It is an image with a number of cracking stages
823 video::IImage *img_crack = driver->createImageFromFile(
824 getTexturePath("crack.png").c_str());
828 // Dimension of original image
829 core::dimension2d<u32> dim_crack
830 = img_crack->getDimension();
831 // Count of crack stages
832 u32 crack_count = dim_crack.Height / dim_crack.Width;
834 if(progression > crack_count-1)
835 progression = crack_count-1;
836 // Dimension of a single scaled crack stage
837 core::dimension2d<u32> dim_crack_scaled_single(
841 // Dimension of scaled size
842 core::dimension2d<u32> dim_crack_scaled(
843 dim_crack_scaled_single.Width,
844 dim_crack_scaled_single.Height * crack_count
846 // Create scaled crack image
847 video::IImage *img_crack_scaled = driver->createImage(
848 video::ECF_A8R8G8B8, dim_crack_scaled);
851 // Scale crack image by copying
852 img_crack->copyToScaling(img_crack_scaled);
854 // Position to copy the crack from
855 core::position2d<s32> pos_crack_scaled(
857 dim_crack_scaled_single.Height * progression
860 // This tiling does nothing currently but is useful
861 for(u32 y0=0; y0<dim_base.Height
862 / dim_crack_scaled_single.Height; y0++)
863 for(u32 x0=0; x0<dim_base.Width
864 / dim_crack_scaled_single.Width; x0++)
866 // Position to copy the crack to in the base image
867 core::position2d<s32> pos_base(
868 x0*dim_crack_scaled_single.Width,
869 y0*dim_crack_scaled_single.Height
871 // Rectangle to copy the crack from on the scaled image
872 core::rect<s32> rect_crack_scaled(
874 dim_crack_scaled_single
877 img_crack_scaled->copyToWithAlpha(baseimg, pos_base,
879 video::SColor(255,255,255,255),
883 img_crack_scaled->drop();
890 [combine:WxH:X,Y=filename:X,Y=filename2
891 Creates a bigger texture from an amount of smaller ones
893 else if(part_of_name.substr(0,8) == "[combine")
895 Strfnd sf(part_of_name);
897 u32 w0 = stoi(sf.next("x"));
898 u32 h0 = stoi(sf.next(":"));
899 dstream<<"INFO: combined w="<<w0<<" h="<<h0<<std::endl;
900 core::dimension2d<u32> dim(w0,h0);
901 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
902 while(sf.atend() == false)
904 u32 x = stoi(sf.next(","));
905 u32 y = stoi(sf.next("="));
906 std::string filename = sf.next(":");
907 dstream<<"INFO: Adding \""<<filename
908 <<"\" to combined ("<<x<<","<<y<<")"
910 video::IImage *img = driver->createImageFromFile(
911 getTexturePath(filename.c_str()).c_str());
914 core::dimension2d<u32> dim = img->getDimension();
915 dstream<<"INFO: Size "<<dim.Width
916 <<"x"<<dim.Height<<std::endl;
917 core::position2d<s32> pos_base(x, y);
918 video::IImage *img2 =
919 driver->createImage(video::ECF_A8R8G8B8, dim);
922 img2->copyToWithAlpha(baseimg, pos_base,
923 core::rect<s32>(v2s32(0,0), dim),
924 video::SColor(255,255,255,255),
930 dstream<<"WARNING: img==NULL"<<std::endl;
936 Adds a progress bar, 0.0 <= N <= 1.0
938 else if(part_of_name.substr(0,12) == "[progressbar")
942 dstream<<"WARNING: getTextureIdDirect(): baseimg==NULL "
943 <<"for part_of_name="<<part_of_name
944 <<", cancelling."<<std::endl;
948 float value = stof(part_of_name.substr(12));
949 make_progressbar(value, baseimg);
952 "[noalpha:filename.png"
953 Use an image without it's alpha channel.
954 Used for the leaves texture when in old leaves mode, so
955 that the transparent parts don't look completely black
956 when simple alpha channel is used for rendering.
958 else if(part_of_name.substr(0,8) == "[noalpha")
962 dstream<<"WARNING: getTextureIdDirect(): baseimg!=NULL "
963 <<"for part_of_name="<<part_of_name
964 <<", cancelling."<<std::endl;
968 std::string filename = part_of_name.substr(9);
970 std::string path = getTexturePath(filename.c_str());
972 dstream<<"INFO: getTextureIdDirect(): Loading path \""<<path
975 video::IImage *image = driver->createImageFromFile(path.c_str());
979 dstream<<"WARNING: getTextureIdDirect(): Loading path \""
980 <<path<<"\" failed"<<std::endl;
984 core::dimension2d<u32> dim = image->getDimension();
985 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
988 for(u32 y=0; y<dim.Height; y++)
989 for(u32 x=0; x<dim.Width; x++)
991 video::SColor c = image->getPixel(x,y);
993 image->setPixel(x,y,c);
996 image->copyTo(baseimg);
1002 [inventorycube{topimage{leftimage{rightimage
1003 In every subimage, replace ^ with &.
1004 Create an "inventory cube".
1005 NOTE: This should be used only on its own.
1006 Example (a grass block (not actually used in game):
1007 "[inventorycube{grass.png{mud.png&grass_side.png{mud.png&grass_side.png"
1009 else if(part_of_name.substr(0,14) == "[inventorycube")
1013 dstream<<"WARNING: getTextureIdDirect(): baseimg!=NULL "
1014 <<"for part_of_name="<<part_of_name
1015 <<", cancelling."<<std::endl;
1019 str_replace_char(part_of_name, '&', '^');
1020 Strfnd sf(part_of_name);
1022 std::string imagename_top = sf.next("{");
1023 std::string imagename_left = sf.next("{");
1024 std::string imagename_right = sf.next("{");
1029 if(driver->queryFeature(video::EVDF_RENDER_TO_TARGET) == false)
1031 dstream<<"WARNING: getTextureIdDirect(): EVDF_RENDER_TO_TARGET"
1032 " not supported. Creating fallback image"<<std::endl;
1033 baseimg = generate_image_from_scratch(
1034 imagename_top, device);
1040 dstream<<"INFO: inventorycube w="<<w0<<" h="<<h0<<std::endl;
1041 core::dimension2d<u32> dim(w0,h0);
1043 // Generate images for the faces of the cube
1044 video::IImage *img_top = generate_image_from_scratch(
1045 imagename_top, device);
1046 video::IImage *img_left = generate_image_from_scratch(
1047 imagename_left, device);
1048 video::IImage *img_right = generate_image_from_scratch(
1049 imagename_right, device);
1050 assert(img_top && img_left && img_right);
1052 // TODO: Create textures from images
1053 video::ITexture *texture_top = driver->addTexture(
1054 (imagename_top + "__temp__").c_str(), img_top);
1055 assert(texture_top);
1062 // Create render target texture
1063 video::ITexture *rtt = NULL;
1064 std::string rtt_name = part_of_name + "_RTT";
1065 rtt = driver->addRenderTargetTexture(dim, rtt_name.c_str(),
1066 video::ECF_A8R8G8B8);
1069 // Set render target
1070 driver->setRenderTarget(rtt, true, true,
1071 video::SColor(0,0,0,0));
1073 // Get a scene manager
1074 scene::ISceneManager *smgr_main = device->getSceneManager();
1076 scene::ISceneManager *smgr = smgr_main->createNewSceneManager();
1081 - An unit cube is centered at 0,0,0
1082 - Camera looks at cube from Y+, Z- towards Y-, Z+
1083 NOTE: Cube has to be changed to something else because
1084 the textures cannot be set individually (or can they?)
1087 scene::ISceneNode* cube = smgr->addCubeSceneNode(1.0, NULL, -1,
1088 v3f(0,0,0), v3f(0, 45, 0));
1089 // Set texture of cube
1090 cube->setMaterialTexture(0, texture_top);
1091 //cube->setMaterialFlag(video::EMF_LIGHTING, false);
1092 cube->setMaterialFlag(video::EMF_ANTI_ALIASING, false);
1093 cube->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
1095 scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(0,
1096 v3f(0, 1.0, -1.5), v3f(0, 0, 0));
1097 // Set orthogonal projection
1098 core::CMatrix4<f32> pm;
1099 pm.buildProjectionMatrixOrthoLH(1.65, 1.65, 0, 100);
1100 camera->setProjectionMatrix(pm, true);
1102 /*scene::ILightSceneNode *light =*/ smgr->addLightSceneNode(0,
1103 v3f(-50, 100, 0), video::SColorf(0.5,0.5,0.5), 1000);
1105 smgr->setAmbientLight(video::SColorf(0.2,0.2,0.2));
1108 driver->beginScene(true, true, video::SColor(0,0,0,0));
1112 // NOTE: The scene nodes should not be dropped, otherwise
1113 // smgr->drop() segfaults
1117 // Drop scene manager
1120 // Unset render target
1121 driver->setRenderTarget(0, true, true, 0);
1123 //TODO: Free textures of images
1124 driver->removeTexture(texture_top);
1126 // Create image of render target
1127 video::IImage *image = driver->createImage(rtt, v2s32(0,0), dim);
1131 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
1135 image->copyTo(baseimg);
1142 dstream<<"WARNING: getTextureIdDirect(): Invalid "
1143 " modification: \""<<part_of_name<<"\""<<std::endl;
1150 void make_progressbar(float value, video::IImage *image)
1155 core::dimension2d<u32> size = image->getDimension();
1157 u32 barheight = size.Height/16;
1158 u32 barpad_x = size.Width/16;
1159 u32 barpad_y = size.Height/16;
1160 u32 barwidth = size.Width - barpad_x*2;
1161 v2u32 barpos(barpad_x, size.Height - barheight - barpad_y);
1163 u32 barvalue_i = (u32)(((float)barwidth * value) + 0.5);
1165 video::SColor active(255,255,0,0);
1166 video::SColor inactive(255,0,0,0);
1167 for(u32 x0=0; x0<barwidth; x0++)
1174 u32 x = x0 + barpos.X;
1175 for(u32 y=barpos.Y; y<barpos.Y+barheight; y++)
1177 image->setPixel(x,y, *c);