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)
35 // Find place of last dot, fail if \ or / found.
37 for(s32 i=path.size()-1; i>=0; i--)
45 if(path[i] == '\\' || path[i] == '/')
48 // If not found, return an empty string
51 // Else make the new path
52 path = path.substr(0, last_dot_i+1) + ext;
57 Find out the full path of an image by trying different filename
62 inline std::string getImagePath(std::string path)
64 // A NULL-ended list of possible image extensions
65 const char *extensions[] = {
66 "png", "jpg", "bmp", "tga", "bmp",
67 "pcx", "ppm", "psd", "wal", "rgb",
71 const char **ext = extensions;
73 bool r = replace_ext(path, *ext);
76 if(fs::PathExists(path))
79 while((++ext) != NULL);
85 Gets the path to a texture by first checking if the texture exists
86 in texture_path and if not, using the data path.
88 inline std::string getTexturePath(std::string filename)
90 std::string texture_path = g_settings.get("texture_path");
91 if(texture_path != "")
93 std::string fullpath = texture_path + '/' + filename;
94 // Check all filename extensions
95 fullpath = getImagePath(fullpath);
96 // If found, return it
100 std::string fullpath = porting::getDataPath(filename.c_str());
101 // Check all filename extensions
102 fullpath = getImagePath(fullpath);
106 TextureSource::TextureSource(IrrlichtDevice *device):
108 m_main_atlas_image(NULL),
109 m_main_atlas_texture(NULL)
113 m_atlaspointer_cache_mutex.Init();
115 m_main_thread = get_current_thread_id();
117 // Add a NULL AtlasPointer as the first index, named ""
118 m_atlaspointer_cache.push_back(SourceAtlasPointer(""));
119 m_name_to_id[""] = 0;
121 // Build main texture atlas
122 if(g_settings.getBool("enable_texture_atlas"))
125 dstream<<"INFO: Not building texture atlas."<<std::endl;
128 TextureSource::~TextureSource()
132 void TextureSource::processQueue()
137 if(m_get_texture_queue.size() > 0)
139 GetRequest<std::string, u32, u8, u8>
140 request = m_get_texture_queue.pop();
142 dstream<<"INFO: TextureSource::processQueue(): "
143 <<"got texture request with "
144 <<"name="<<request.key
147 GetResult<std::string, u32, u8, u8>
149 result.key = request.key;
150 result.callers = request.callers;
151 result.item = getTextureIdDirect(request.key);
153 request.dest->push_back(result);
157 u32 TextureSource::getTextureId(const std::string &name)
159 //dstream<<"INFO: getTextureId(): name="<<name<<std::endl;
163 See if texture already exists
165 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
166 core::map<std::string, u32>::Node *n;
167 n = m_name_to_id.find(name);
170 return n->getValue();
177 if(get_current_thread_id() == m_main_thread)
179 return getTextureIdDirect(name);
183 dstream<<"INFO: getTextureId(): Queued: name="<<name<<std::endl;
185 // We're gonna ask the result to be put into here
186 ResultQueue<std::string, u32, u8, u8> result_queue;
188 // Throw a request in
189 m_get_texture_queue.add(name, 0, 0, &result_queue);
191 dstream<<"INFO: Waiting for texture from main thread, name="
196 // Wait result for a second
197 GetResult<std::string, u32, u8, u8>
198 result = result_queue.pop_front(1000);
200 // Check that at least something worked OK
201 assert(result.key == name);
205 catch(ItemNotFoundException &e)
207 dstream<<"WARNING: Waiting for texture timed out."<<std::endl;
212 dstream<<"WARNING: getTextureId(): Failed"<<std::endl;
217 // Draw a progress bar on the image
218 void make_progressbar(float value, video::IImage *image);
221 Generate image based on a string like "stone.png" or "[crack0".
222 if baseimg is NULL, it is created. Otherwise stuff is made on it.
224 bool generate_image(std::string part_of_name, video::IImage *& baseimg,
225 IrrlichtDevice *device);
228 Generates an image from a full string like
229 "stone.png^mineral_coal.png^[crack0".
231 This is used by buildMainAtlas().
233 video::IImage* generate_image_from_scratch(std::string name,
234 IrrlichtDevice *device);
237 This method generates all the textures
239 u32 TextureSource::getTextureIdDirect(const std::string &name)
241 dstream<<"INFO: getTextureIdDirect(): name="<<name<<std::endl;
243 // Empty name means texture 0
246 dstream<<"INFO: getTextureIdDirect(): name is empty"<<std::endl;
251 Calling only allowed from main thread
253 if(get_current_thread_id() != m_main_thread)
255 dstream<<"ERROR: TextureSource::getTextureIdDirect() "
256 "called not from main thread"<<std::endl;
261 See if texture already exists
264 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
266 core::map<std::string, u32>::Node *n;
267 n = m_name_to_id.find(name);
270 dstream<<"INFO: getTextureIdDirect(): name="<<name
271 <<" found in cache"<<std::endl;
272 return n->getValue();
276 dstream<<"INFO: getTextureIdDirect(): name="<<name
277 <<" NOT found in cache. Creating it."<<std::endl;
283 char separator = '^';
286 This is set to the id of the base image.
287 If left 0, there is no base image and a completely new image
290 u32 base_image_id = 0;
292 // Find last meta separator in name
293 s32 last_separator_position = -1;
294 for(s32 i=name.size()-1; i>=0; i--)
296 if(name[i] == separator)
298 last_separator_position = i;
303 If separator was found, construct the base name and make the
304 base image using a recursive call
306 std::string base_image_name;
307 if(last_separator_position != -1)
309 // Construct base name
310 base_image_name = name.substr(0, last_separator_position);
311 dstream<<"INFO: getTextureIdDirect(): Calling itself recursively"
312 " to get base image, name="<<base_image_name<<std::endl;
313 base_image_id = getTextureIdDirect(base_image_name);
316 dstream<<"base_image_id="<<base_image_id<<std::endl;
318 video::IVideoDriver* driver = m_device->getVideoDriver();
321 video::ITexture *t = NULL;
324 An image will be built from files and then converted into a texture.
326 video::IImage *baseimg = NULL;
328 // If a base image was found, copy it to baseimg
329 if(base_image_id != 0)
331 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
333 SourceAtlasPointer ap = m_atlaspointer_cache[base_image_id];
335 video::IImage *image = ap.atlas_img;
339 dstream<<"WARNING: getTextureIdDirect(): NULL image in "
340 <<"cache: \""<<base_image_name<<"\""
345 core::dimension2d<u32> dim = ap.intsize;
347 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
349 core::position2d<s32> pos_to(0,0);
350 core::position2d<s32> pos_from = ap.intpos;
354 v2s32(0,0), // position in target
355 core::rect<s32>(pos_from, dim) // from
358 dstream<<"INFO: getTextureIdDirect(): Loaded \""
359 <<base_image_name<<"\" from image cache"
365 Parse out the last part of the name of the image and act
369 std::string last_part_of_name = name.substr(last_separator_position+1);
370 dstream<<"last_part_of_name="<<last_part_of_name<<std::endl;
372 // Generate image according to part of name
373 if(generate_image(last_part_of_name, baseimg, m_device) == false)
375 dstream<<"INFO: getTextureIdDirect(): "
376 "failed to generate \""<<last_part_of_name<<"\""
380 // If no resulting image, print a warning
383 dstream<<"WARNING: getTextureIdDirect(): baseimg is NULL (attempted to"
384 " create texture \""<<name<<"\""<<std::endl;
389 // Create texture from resulting image
390 t = driver->addTexture(name.c_str(), baseimg);
394 Add texture to caches (add NULL textures too)
397 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
399 u32 id = m_atlaspointer_cache.size();
405 core::dimension2d<u32> baseimg_dim(0,0);
407 baseimg_dim = baseimg->getDimension();
408 SourceAtlasPointer nap(name, ap, baseimg, v2s32(0,0), baseimg_dim);
409 m_atlaspointer_cache.push_back(nap);
410 m_name_to_id.insert(name, id);
412 dstream<<"INFO: getTextureIdDirect(): name="<<name
413 <<": succesfully returning id="<<id<<std::endl;
418 std::string TextureSource::getTextureName(u32 id)
420 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
422 if(id >= m_atlaspointer_cache.size())
424 dstream<<"WARNING: TextureSource::getTextureName(): id="<<id
425 <<" >= m_atlaspointer_cache.size()="
426 <<m_atlaspointer_cache.size()<<std::endl;
430 return m_atlaspointer_cache[id].name;
434 AtlasPointer TextureSource::getTexture(u32 id)
436 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
438 if(id >= m_atlaspointer_cache.size())
439 return AtlasPointer(0, NULL);
441 return m_atlaspointer_cache[id].a;
444 void TextureSource::buildMainAtlas()
446 dstream<<"TextureSource::buildMainAtlas()"<<std::endl;
448 //return; // Disable (for testing)
450 video::IVideoDriver* driver = m_device->getVideoDriver();
453 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
455 // Create an image of the right size
456 core::dimension2d<u32> atlas_dim(1024,1024);
457 video::IImage *atlas_img =
458 driver->createImage(video::ECF_A8R8G8B8, atlas_dim);
462 A list of stuff to add. This should contain as much of the
463 stuff shown in game as possible, to minimize texture changes.
466 core::array<std::string> sourcelist;
468 sourcelist.push_back("stone.png");
469 sourcelist.push_back("mud.png");
470 sourcelist.push_back("sand.png");
471 sourcelist.push_back("grass.png");
472 sourcelist.push_back("grass_footsteps.png");
473 sourcelist.push_back("tree.png");
474 sourcelist.push_back("tree_top.png");
475 sourcelist.push_back("water.png");
476 sourcelist.push_back("leaves.png");
477 sourcelist.push_back("mud.png^grass_side.png");
479 sourcelist.push_back("stone.png^mineral_coal.png");
480 sourcelist.push_back("stone.png^mineral_iron.png");
481 sourcelist.push_back("mud.png^mineral_coal.png");
482 sourcelist.push_back("mud.png^mineral_iron.png");
483 sourcelist.push_back("sand.png^mineral_coal.png");
484 sourcelist.push_back("sand.png^mineral_iron.png");
486 // Padding to disallow texture bleeding
490 First pass: generate almost everything
492 core::position2d<s32> pos_in_atlas(0,0);
494 pos_in_atlas.Y += padding;
496 for(u32 i=0; i<sourcelist.size(); i++)
498 std::string name = sourcelist[i];
500 /*video::IImage *img = driver->createImageFromFile(
501 getTexturePath(name.c_str()).c_str());
505 core::dimension2d<u32> dim = img->getDimension();
506 // Make a copy with the right color format
507 video::IImage *img2 =
508 driver->createImage(video::ECF_A8R8G8B8, dim);
512 // Generate image by name
513 video::IImage *img2 = generate_image_from_scratch(name, m_device);
516 dstream<<"WARNING: TextureSource::buildMainAtlas(): Couldn't generate texture atlas: Couldn't generate image \""<<name<<"\""<<std::endl;
520 core::dimension2d<u32> dim = img2->getDimension();
522 // Don't add to atlas if image is large
523 core::dimension2d<u32> max_size_in_atlas(32,32);
524 if(dim.Width > max_size_in_atlas.Width
525 || dim.Height > max_size_in_atlas.Height)
527 dstream<<"INFO: TextureSource::buildMainAtlas(): Not adding "
528 <<"\""<<name<<"\" because image is large"<<std::endl;
532 // Stop making atlas if atlas is full
533 if(pos_in_atlas.Y + dim.Height > atlas_dim.Height)
535 dstream<<"WARNING: TextureSource::buildMainAtlas(): "
536 <<"Atlas is full, not adding more textures."
541 // Tile it a few times in the X direction
542 u16 xwise_tiling = 16;
543 for(u32 j=0; j<xwise_tiling; j++)
545 // Copy the copy to the atlas
546 img2->copyToWithAlpha(atlas_img,
547 pos_in_atlas + v2s32(j*dim.Width,0),
548 core::rect<s32>(v2s32(0,0), dim),
549 video::SColor(255,255,255,255),
553 // Copy the borders a few times to disallow texture bleeding
554 for(u32 side=0; side<2; side++) // top and bottom
555 for(s32 y0=0; y0<padding; y0++)
556 for(s32 x0=0; x0<(s32)xwise_tiling*(s32)dim.Width; x0++)
562 dst_y = y0 + pos_in_atlas.Y + dim.Height;
563 src_y = pos_in_atlas.Y + dim.Height - 1;
567 dst_y = -y0 + pos_in_atlas.Y-1;
568 src_y = pos_in_atlas.Y;
570 s32 x = x0 + pos_in_atlas.X * dim.Width;
571 video::SColor c = atlas_img->getPixel(x, src_y);
572 atlas_img->setPixel(x,dst_y,c);
578 Add texture to caches
582 u32 id = m_atlaspointer_cache.size();
584 // Create AtlasPointer
586 ap.atlas = NULL; // Set on the second pass
587 ap.pos = v2f((float)pos_in_atlas.X/(float)atlas_dim.Width,
588 (float)pos_in_atlas.Y/(float)atlas_dim.Height);
589 ap.size = v2f((float)dim.Width/(float)atlas_dim.Width,
590 (float)dim.Width/(float)atlas_dim.Height);
591 ap.tiled = xwise_tiling;
593 // Create SourceAtlasPointer and add to containers
594 SourceAtlasPointer nap(name, ap, atlas_img, pos_in_atlas, dim);
595 m_atlaspointer_cache.push_back(nap);
596 m_name_to_id.insert(name, id);
598 // Increment position
599 pos_in_atlas.Y += dim.Height + padding * 2;
605 video::ITexture *t = driver->addTexture("__main_atlas__", atlas_img);
609 Second pass: set texture pointer in generated AtlasPointers
611 for(u32 i=0; i<sourcelist.size(); i++)
613 std::string name = sourcelist[i];
614 if(m_name_to_id.find(name) == NULL)
616 u32 id = m_name_to_id[name];
617 //dstream<<"id of name "<<name<<" is "<<id<<std::endl;
618 m_atlaspointer_cache[id].a.atlas = t;
622 Write image to file so that it can be inspected
624 /*driver->writeImageToFile(atlas_img,
625 getTexturePath("main_atlas.png").c_str());*/
628 video::IImage* generate_image_from_scratch(std::string name,
629 IrrlichtDevice *device)
631 dstream<<"INFO: generate_image_from_scratch(): "
632 "name="<<name<<std::endl;
634 video::IVideoDriver* driver = device->getVideoDriver();
641 video::IImage *baseimg = NULL;
643 char separator = '^';
645 // Find last meta separator in name
646 s32 last_separator_position = -1;
647 for(s32 i=name.size()-1; i>=0; i--)
649 if(name[i] == separator)
651 last_separator_position = i;
656 /*dstream<<"INFO: generate_image_from_scratch(): "
657 <<"last_separator_position="<<last_separator_position
661 If separator was found, construct the base name and make the
662 base image using a recursive call
664 std::string base_image_name;
665 if(last_separator_position != -1)
667 // Construct base name
668 base_image_name = name.substr(0, last_separator_position);
669 dstream<<"INFO: generate_image_from_scratch(): Calling itself recursively"
670 " to get base image, name="<<base_image_name<<std::endl;
671 baseimg = generate_image_from_scratch(base_image_name, device);
675 Parse out the last part of the name of the image and act
679 std::string last_part_of_name = name.substr(last_separator_position+1);
680 dstream<<"last_part_of_name="<<last_part_of_name<<std::endl;
682 // Generate image according to part of name
683 if(generate_image(last_part_of_name, baseimg, device) == false)
685 dstream<<"INFO: generate_image_from_scratch(): "
686 "failed to generate \""<<last_part_of_name<<"\""
694 bool generate_image(std::string part_of_name, video::IImage *& baseimg,
695 IrrlichtDevice *device)
697 video::IVideoDriver* driver = device->getVideoDriver();
700 // Stuff starting with [ are special commands
701 if(part_of_name[0] != '[')
703 // A normal texture; load it from a file
704 std::string path = getTexturePath(part_of_name.c_str());
705 dstream<<"INFO: getTextureIdDirect(): Loading path \""<<path
708 video::IImage *image = driver->createImageFromFile(path.c_str());
712 dstream<<"WARNING: Could not load image \""<<part_of_name
713 <<"\" from path \""<<path<<"\""
714 <<" while building texture"<<std::endl;
718 dstream<<"WARNING: Creating a dummy"<<" image for \""
719 <<part_of_name<<"\""<<std::endl;
721 // Just create a dummy image
722 //core::dimension2d<u32> dim(2,2);
723 core::dimension2d<u32> dim(1,1);
724 image = driver->createImage(video::ECF_A8R8G8B8, dim);
726 /*image->setPixel(0,0, video::SColor(255,255,0,0));
727 image->setPixel(1,0, video::SColor(255,0,255,0));
728 image->setPixel(0,1, video::SColor(255,0,0,255));
729 image->setPixel(1,1, video::SColor(255,255,0,255));*/
730 image->setPixel(0,0, video::SColor(255,myrand()%256,
731 myrand()%256,myrand()%256));
732 /*image->setPixel(1,0, video::SColor(255,myrand()%256,
733 myrand()%256,myrand()%256));
734 image->setPixel(0,1, video::SColor(255,myrand()%256,
735 myrand()%256,myrand()%256));
736 image->setPixel(1,1, video::SColor(255,myrand()%256,
737 myrand()%256,myrand()%256));*/
740 // If base image is NULL, load as base.
743 dstream<<"INFO: Setting "<<part_of_name<<" as base"<<std::endl;
745 Copy it this way to get an alpha channel.
746 Otherwise images with alpha cannot be blitted on
747 images that don't have alpha in the original file.
749 core::dimension2d<u32> dim = image->getDimension();
750 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
751 image->copyTo(baseimg);
754 // Else blit on base.
757 dstream<<"INFO: Blitting "<<part_of_name<<" on base"<<std::endl;
758 // Size of the copied area
759 core::dimension2d<u32> dim = image->getDimension();
760 //core::dimension2d<u32> dim(16,16);
761 // Position to copy the blitted to in the base image
762 core::position2d<s32> pos_to(0,0);
763 // Position to copy the blitted from in the blitted image
764 core::position2d<s32> pos_from(0,0);
766 image->copyToWithAlpha(baseimg, pos_to,
767 core::rect<s32>(pos_from, dim),
768 video::SColor(255,255,255,255),
776 // A special texture modification
778 dstream<<"INFO: getTextureIdDirect(): generating special "
779 <<"modification \""<<part_of_name<<"\""
783 This is the simplest of all; it just adds stuff to the
784 name so that a separate texture is created.
786 It is used to make textures for stuff that doesn't want
787 to implement getting the texture from a bigger texture
790 if(part_of_name == "[forcesingle")
795 Adds a cracking texture
797 else if(part_of_name.substr(0,6) == "[crack")
801 dstream<<"WARNING: getTextureIdDirect(): baseimg==NULL "
802 <<"for part_of_name="<<part_of_name
803 <<", cancelling."<<std::endl;
807 // Crack image number
808 u16 progression = stoi(part_of_name.substr(6));
810 // Size of the base image
811 core::dimension2d<u32> dim_base = baseimg->getDimension();
816 It is an image with a number of cracking stages
819 video::IImage *img_crack = driver->createImageFromFile(
820 getTexturePath("crack.png").c_str());
824 // Dimension of original image
825 core::dimension2d<u32> dim_crack
826 = img_crack->getDimension();
827 // Count of crack stages
828 u32 crack_count = dim_crack.Height / dim_crack.Width;
830 if(progression > crack_count-1)
831 progression = crack_count-1;
832 // Dimension of a single scaled crack stage
833 core::dimension2d<u32> dim_crack_scaled_single(
837 // Dimension of scaled size
838 core::dimension2d<u32> dim_crack_scaled(
839 dim_crack_scaled_single.Width,
840 dim_crack_scaled_single.Height * crack_count
842 // Create scaled crack image
843 video::IImage *img_crack_scaled = driver->createImage(
844 video::ECF_A8R8G8B8, dim_crack_scaled);
847 // Scale crack image by copying
848 img_crack->copyToScaling(img_crack_scaled);
850 // Position to copy the crack from
851 core::position2d<s32> pos_crack_scaled(
853 dim_crack_scaled_single.Height * progression
856 // This tiling does nothing currently but is useful
857 for(u32 y0=0; y0<dim_base.Height
858 / dim_crack_scaled_single.Height; y0++)
859 for(u32 x0=0; x0<dim_base.Width
860 / dim_crack_scaled_single.Width; x0++)
862 // Position to copy the crack to in the base image
863 core::position2d<s32> pos_base(
864 x0*dim_crack_scaled_single.Width,
865 y0*dim_crack_scaled_single.Height
867 // Rectangle to copy the crack from on the scaled image
868 core::rect<s32> rect_crack_scaled(
870 dim_crack_scaled_single
873 img_crack_scaled->copyToWithAlpha(baseimg, pos_base,
875 video::SColor(255,255,255,255),
879 img_crack_scaled->drop();
886 [combine:WxH:X,Y=filename:X,Y=filename2
887 Creates a bigger texture from an amount of smaller ones
889 else if(part_of_name.substr(0,8) == "[combine")
891 Strfnd sf(part_of_name);
893 u32 w0 = stoi(sf.next("x"));
894 u32 h0 = stoi(sf.next(":"));
895 dstream<<"INFO: combined w="<<w0<<" h="<<h0<<std::endl;
896 core::dimension2d<u32> dim(w0,h0);
897 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
898 while(sf.atend() == false)
900 u32 x = stoi(sf.next(","));
901 u32 y = stoi(sf.next("="));
902 std::string filename = sf.next(":");
903 dstream<<"INFO: Adding \""<<filename
904 <<"\" to combined ("<<x<<","<<y<<")"
906 video::IImage *img = driver->createImageFromFile(
907 getTexturePath(filename.c_str()).c_str());
910 core::dimension2d<u32> dim = img->getDimension();
911 dstream<<"INFO: Size "<<dim.Width
912 <<"x"<<dim.Height<<std::endl;
913 core::position2d<s32> pos_base(x, y);
914 video::IImage *img2 =
915 driver->createImage(video::ECF_A8R8G8B8, dim);
918 img2->copyToWithAlpha(baseimg, pos_base,
919 core::rect<s32>(v2s32(0,0), dim),
920 video::SColor(255,255,255,255),
926 dstream<<"WARNING: img==NULL"<<std::endl;
932 Adds a progress bar, 0.0 <= N <= 1.0
934 else if(part_of_name.substr(0,12) == "[progressbar")
938 dstream<<"WARNING: getTextureIdDirect(): baseimg==NULL "
939 <<"for part_of_name="<<part_of_name
940 <<", cancelling."<<std::endl;
944 float value = stof(part_of_name.substr(12));
945 make_progressbar(value, baseimg);
948 "[noalpha:filename.png"
949 Use an image without it's alpha channel.
950 Used for the leaves texture when in old leaves mode, so
951 that the transparent parts don't look completely black
952 when simple alpha channel is used for rendering.
954 else if(part_of_name.substr(0,8) == "[noalpha")
958 dstream<<"WARNING: getTextureIdDirect(): baseimg!=NULL "
959 <<"for part_of_name="<<part_of_name
960 <<", cancelling."<<std::endl;
964 std::string filename = part_of_name.substr(9);
966 std::string path = getTexturePath(filename.c_str());
968 dstream<<"INFO: getTextureIdDirect(): Loading path \""<<path
971 video::IImage *image = driver->createImageFromFile(path.c_str());
975 dstream<<"WARNING: getTextureIdDirect(): Loading path \""
976 <<path<<"\" failed"<<std::endl;
980 core::dimension2d<u32> dim = image->getDimension();
981 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
984 for(u32 y=0; y<dim.Height; y++)
985 for(u32 x=0; x<dim.Width; x++)
987 video::SColor c = image->getPixel(x,y);
989 image->setPixel(x,y,c);
992 image->copyTo(baseimg);
998 [inventorycube{topimage{leftimage{rightimage
999 In every subimage, replace ^ with &.
1000 Create an "inventory cube".
1001 NOTE: This should be used only on its own.
1002 Example (a grass block (not actually used in game):
1003 "[inventorycube{grass.png{mud.png&grass_side.png{mud.png&grass_side.png"
1005 else if(part_of_name.substr(0,14) == "[inventorycube")
1009 dstream<<"WARNING: getTextureIdDirect(): baseimg!=NULL "
1010 <<"for part_of_name="<<part_of_name
1011 <<", cancelling."<<std::endl;
1015 str_replace_char(part_of_name, '&', '^');
1016 Strfnd sf(part_of_name);
1018 std::string imagename_top = sf.next("{");
1019 std::string imagename_left = sf.next("{");
1020 std::string imagename_right = sf.next("{");
1025 if(driver->queryFeature(video::EVDF_RENDER_TO_TARGET) == false)
1027 dstream<<"WARNING: getTextureIdDirect(): EVDF_RENDER_TO_TARGET"
1028 " not supported. Creating fallback image"<<std::endl;
1029 baseimg = generate_image_from_scratch(
1030 imagename_top, device);
1036 dstream<<"INFO: inventorycube w="<<w0<<" h="<<h0<<std::endl;
1037 core::dimension2d<u32> dim(w0,h0);
1039 // Generate images for the faces of the cube
1040 video::IImage *img_top = generate_image_from_scratch(
1041 imagename_top, device);
1042 video::IImage *img_left = generate_image_from_scratch(
1043 imagename_left, device);
1044 video::IImage *img_right = generate_image_from_scratch(
1045 imagename_right, device);
1046 assert(img_top && img_left && img_right);
1048 // TODO: Create textures from images
1049 video::ITexture *texture_top = driver->addTexture(
1050 (imagename_top + "__temp__").c_str(), img_top);
1051 assert(texture_top);
1058 // Create render target texture
1059 video::ITexture *rtt = NULL;
1060 std::string rtt_name = part_of_name + "_RTT";
1061 rtt = driver->addRenderTargetTexture(dim, rtt_name.c_str(),
1062 video::ECF_A8R8G8B8);
1065 // Set render target
1066 driver->setRenderTarget(rtt, true, true,
1067 video::SColor(0,0,0,0));
1069 // Get a scene manager
1070 scene::ISceneManager *smgr_main = device->getSceneManager();
1072 scene::ISceneManager *smgr = smgr_main->createNewSceneManager();
1077 - An unit cube is centered at 0,0,0
1078 - Camera looks at cube from Y+, Z- towards Y-, Z+
1079 NOTE: Cube has to be changed to something else because
1080 the textures cannot be set individually (or can they?)
1083 scene::ISceneNode* cube = smgr->addCubeSceneNode(1.0, NULL, -1,
1084 v3f(0,0,0), v3f(0, 45, 0));
1085 // Set texture of cube
1086 cube->setMaterialTexture(0, texture_top);
1087 //cube->setMaterialFlag(video::EMF_LIGHTING, false);
1088 cube->setMaterialFlag(video::EMF_ANTI_ALIASING, false);
1089 cube->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
1091 scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(0,
1092 v3f(0, 1.0, -1.5), v3f(0, 0, 0));
1093 // Set orthogonal projection
1094 core::CMatrix4<f32> pm;
1095 pm.buildProjectionMatrixOrthoLH(1.65, 1.65, 0, 100);
1096 camera->setProjectionMatrix(pm, true);
1098 /*scene::ILightSceneNode *light =*/ smgr->addLightSceneNode(0,
1099 v3f(-50, 100, 0), video::SColorf(0.5,0.5,0.5), 1000);
1102 driver->beginScene(true, true, video::SColor(0,0,0,0));
1106 // NOTE: The scene nodes should not be dropped, otherwise
1107 // smgr->drop() segfaults
1111 // Drop scene manager
1114 // Unset render target
1115 driver->setRenderTarget(0, true, true, 0);
1117 //TODO: Free textures of images
1118 driver->removeTexture(texture_top);
1120 // Create image of render target
1121 video::IImage *image = driver->createImage(rtt, v2s32(0,0), dim);
1125 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
1129 image->copyTo(baseimg);
1136 dstream<<"WARNING: getTextureIdDirect(): Invalid "
1137 " modification: \""<<part_of_name<<"\""<<std::endl;
1144 void make_progressbar(float value, video::IImage *image)
1149 core::dimension2d<u32> size = image->getDimension();
1151 u32 barheight = size.Height/16;
1152 u32 barpad_x = size.Width/16;
1153 u32 barpad_y = size.Height/16;
1154 u32 barwidth = size.Width - barpad_x*2;
1155 v2u32 barpos(barpad_x, size.Height - barheight - barpad_y);
1157 u32 barvalue_i = (u32)(((float)barwidth * value) + 0.5);
1159 video::SColor active(255,255,0,0);
1160 video::SColor inactive(255,0,0,0);
1161 for(u32 x0=0; x0<barwidth; x0++)
1168 u32 x = x0 + barpos.X;
1169 for(u32 y=barpos.Y; y<barpos.Y+barheight; y++)
1171 image->setPixel(x,y, *c);