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("mud.png^grass_side.png");
480 sourcelist.push_back("cobble.png");
482 sourcelist.push_back("stone.png^mineral_coal.png");
483 sourcelist.push_back("stone.png^mineral_iron.png");
484 sourcelist.push_back("mud.png^mineral_coal.png");
485 sourcelist.push_back("mud.png^mineral_iron.png");
486 sourcelist.push_back("sand.png^mineral_coal.png");
487 sourcelist.push_back("sand.png^mineral_iron.png");
489 // Padding to disallow texture bleeding
493 First pass: generate almost everything
495 core::position2d<s32> pos_in_atlas(0,0);
497 pos_in_atlas.Y += padding;
499 for(u32 i=0; i<sourcelist.size(); i++)
501 std::string name = sourcelist[i];
503 /*video::IImage *img = driver->createImageFromFile(
504 getTexturePath(name.c_str()).c_str());
508 core::dimension2d<u32> dim = img->getDimension();
509 // Make a copy with the right color format
510 video::IImage *img2 =
511 driver->createImage(video::ECF_A8R8G8B8, dim);
515 // Generate image by name
516 video::IImage *img2 = generate_image_from_scratch(name, m_device);
519 dstream<<"WARNING: TextureSource::buildMainAtlas(): Couldn't generate texture atlas: Couldn't generate image \""<<name<<"\""<<std::endl;
523 core::dimension2d<u32> dim = img2->getDimension();
525 // Don't add to atlas if image is large
526 core::dimension2d<u32> max_size_in_atlas(32,32);
527 if(dim.Width > max_size_in_atlas.Width
528 || dim.Height > max_size_in_atlas.Height)
530 dstream<<"INFO: TextureSource::buildMainAtlas(): Not adding "
531 <<"\""<<name<<"\" because image is large"<<std::endl;
535 // Stop making atlas if atlas is full
536 if(pos_in_atlas.Y + dim.Height > atlas_dim.Height)
538 dstream<<"WARNING: TextureSource::buildMainAtlas(): "
539 <<"Atlas is full, not adding more textures."
544 // Tile it a few times in the X direction
545 u16 xwise_tiling = 16;
546 for(u32 j=0; j<xwise_tiling; j++)
548 // Copy the copy to the atlas
549 img2->copyToWithAlpha(atlas_img,
550 pos_in_atlas + v2s32(j*dim.Width,0),
551 core::rect<s32>(v2s32(0,0), dim),
552 video::SColor(255,255,255,255),
556 // Copy the borders a few times to disallow texture bleeding
557 for(u32 side=0; side<2; side++) // top and bottom
558 for(s32 y0=0; y0<padding; y0++)
559 for(s32 x0=0; x0<(s32)xwise_tiling*(s32)dim.Width; x0++)
565 dst_y = y0 + pos_in_atlas.Y + dim.Height;
566 src_y = pos_in_atlas.Y + dim.Height - 1;
570 dst_y = -y0 + pos_in_atlas.Y-1;
571 src_y = pos_in_atlas.Y;
573 s32 x = x0 + pos_in_atlas.X * dim.Width;
574 video::SColor c = atlas_img->getPixel(x, src_y);
575 atlas_img->setPixel(x,dst_y,c);
581 Add texture to caches
585 u32 id = m_atlaspointer_cache.size();
587 // Create AtlasPointer
589 ap.atlas = NULL; // Set on the second pass
590 ap.pos = v2f((float)pos_in_atlas.X/(float)atlas_dim.Width,
591 (float)pos_in_atlas.Y/(float)atlas_dim.Height);
592 ap.size = v2f((float)dim.Width/(float)atlas_dim.Width,
593 (float)dim.Width/(float)atlas_dim.Height);
594 ap.tiled = xwise_tiling;
596 // Create SourceAtlasPointer and add to containers
597 SourceAtlasPointer nap(name, ap, atlas_img, pos_in_atlas, dim);
598 m_atlaspointer_cache.push_back(nap);
599 m_name_to_id.insert(name, id);
601 // Increment position
602 pos_in_atlas.Y += dim.Height + padding * 2;
608 video::ITexture *t = driver->addTexture("__main_atlas__", atlas_img);
612 Second pass: set texture pointer in generated AtlasPointers
614 for(u32 i=0; i<sourcelist.size(); i++)
616 std::string name = sourcelist[i];
617 if(m_name_to_id.find(name) == NULL)
619 u32 id = m_name_to_id[name];
620 //dstream<<"id of name "<<name<<" is "<<id<<std::endl;
621 m_atlaspointer_cache[id].a.atlas = t;
625 Write image to file so that it can be inspected
627 /*driver->writeImageToFile(atlas_img,
628 getTexturePath("main_atlas.png").c_str());*/
631 video::IImage* generate_image_from_scratch(std::string name,
632 IrrlichtDevice *device)
634 dstream<<"INFO: generate_image_from_scratch(): "
635 "name="<<name<<std::endl;
637 video::IVideoDriver* driver = device->getVideoDriver();
644 video::IImage *baseimg = NULL;
646 char separator = '^';
648 // Find last meta separator in name
649 s32 last_separator_position = -1;
650 for(s32 i=name.size()-1; i>=0; i--)
652 if(name[i] == separator)
654 last_separator_position = i;
659 /*dstream<<"INFO: generate_image_from_scratch(): "
660 <<"last_separator_position="<<last_separator_position
664 If separator was found, construct the base name and make the
665 base image using a recursive call
667 std::string base_image_name;
668 if(last_separator_position != -1)
670 // Construct base name
671 base_image_name = name.substr(0, last_separator_position);
672 dstream<<"INFO: generate_image_from_scratch(): Calling itself recursively"
673 " to get base image, name="<<base_image_name<<std::endl;
674 baseimg = generate_image_from_scratch(base_image_name, device);
678 Parse out the last part of the name of the image and act
682 std::string last_part_of_name = name.substr(last_separator_position+1);
683 dstream<<"last_part_of_name="<<last_part_of_name<<std::endl;
685 // Generate image according to part of name
686 if(generate_image(last_part_of_name, baseimg, device) == false)
688 dstream<<"INFO: generate_image_from_scratch(): "
689 "failed to generate \""<<last_part_of_name<<"\""
697 bool generate_image(std::string part_of_name, video::IImage *& baseimg,
698 IrrlichtDevice *device)
700 video::IVideoDriver* driver = device->getVideoDriver();
703 // Stuff starting with [ are special commands
704 if(part_of_name[0] != '[')
706 // A normal texture; load it from a file
707 std::string path = getTexturePath(part_of_name.c_str());
708 dstream<<"INFO: getTextureIdDirect(): Loading path \""<<path
711 video::IImage *image = driver->createImageFromFile(path.c_str());
715 dstream<<"WARNING: Could not load image \""<<part_of_name
716 <<"\" from path \""<<path<<"\""
717 <<" while building texture"<<std::endl;
721 dstream<<"WARNING: Creating a dummy"<<" image for \""
722 <<part_of_name<<"\""<<std::endl;
724 // Just create a dummy image
725 //core::dimension2d<u32> dim(2,2);
726 core::dimension2d<u32> dim(1,1);
727 image = driver->createImage(video::ECF_A8R8G8B8, dim);
729 /*image->setPixel(0,0, video::SColor(255,255,0,0));
730 image->setPixel(1,0, video::SColor(255,0,255,0));
731 image->setPixel(0,1, video::SColor(255,0,0,255));
732 image->setPixel(1,1, video::SColor(255,255,0,255));*/
733 image->setPixel(0,0, video::SColor(255,myrand()%256,
734 myrand()%256,myrand()%256));
735 /*image->setPixel(1,0, video::SColor(255,myrand()%256,
736 myrand()%256,myrand()%256));
737 image->setPixel(0,1, video::SColor(255,myrand()%256,
738 myrand()%256,myrand()%256));
739 image->setPixel(1,1, video::SColor(255,myrand()%256,
740 myrand()%256,myrand()%256));*/
743 // If base image is NULL, load as base.
746 dstream<<"INFO: Setting "<<part_of_name<<" as base"<<std::endl;
748 Copy it this way to get an alpha channel.
749 Otherwise images with alpha cannot be blitted on
750 images that don't have alpha in the original file.
752 core::dimension2d<u32> dim = image->getDimension();
753 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
754 image->copyTo(baseimg);
757 // Else blit on base.
760 dstream<<"INFO: Blitting "<<part_of_name<<" on base"<<std::endl;
761 // Size of the copied area
762 core::dimension2d<u32> dim = image->getDimension();
763 //core::dimension2d<u32> dim(16,16);
764 // Position to copy the blitted to in the base image
765 core::position2d<s32> pos_to(0,0);
766 // Position to copy the blitted from in the blitted image
767 core::position2d<s32> pos_from(0,0);
769 image->copyToWithAlpha(baseimg, pos_to,
770 core::rect<s32>(pos_from, dim),
771 video::SColor(255,255,255,255),
779 // A special texture modification
781 dstream<<"INFO: getTextureIdDirect(): generating special "
782 <<"modification \""<<part_of_name<<"\""
786 This is the simplest of all; it just adds stuff to the
787 name so that a separate texture is created.
789 It is used to make textures for stuff that doesn't want
790 to implement getting the texture from a bigger texture
793 if(part_of_name == "[forcesingle")
798 Adds a cracking texture
800 else if(part_of_name.substr(0,6) == "[crack")
804 dstream<<"WARNING: getTextureIdDirect(): baseimg==NULL "
805 <<"for part_of_name="<<part_of_name
806 <<", cancelling."<<std::endl;
810 // Crack image number
811 u16 progression = stoi(part_of_name.substr(6));
813 // Size of the base image
814 core::dimension2d<u32> dim_base = baseimg->getDimension();
819 It is an image with a number of cracking stages
822 video::IImage *img_crack = driver->createImageFromFile(
823 getTexturePath("crack.png").c_str());
827 // Dimension of original image
828 core::dimension2d<u32> dim_crack
829 = img_crack->getDimension();
830 // Count of crack stages
831 u32 crack_count = dim_crack.Height / dim_crack.Width;
833 if(progression > crack_count-1)
834 progression = crack_count-1;
835 // Dimension of a single scaled crack stage
836 core::dimension2d<u32> dim_crack_scaled_single(
840 // Dimension of scaled size
841 core::dimension2d<u32> dim_crack_scaled(
842 dim_crack_scaled_single.Width,
843 dim_crack_scaled_single.Height * crack_count
845 // Create scaled crack image
846 video::IImage *img_crack_scaled = driver->createImage(
847 video::ECF_A8R8G8B8, dim_crack_scaled);
850 // Scale crack image by copying
851 img_crack->copyToScaling(img_crack_scaled);
853 // Position to copy the crack from
854 core::position2d<s32> pos_crack_scaled(
856 dim_crack_scaled_single.Height * progression
859 // This tiling does nothing currently but is useful
860 for(u32 y0=0; y0<dim_base.Height
861 / dim_crack_scaled_single.Height; y0++)
862 for(u32 x0=0; x0<dim_base.Width
863 / dim_crack_scaled_single.Width; x0++)
865 // Position to copy the crack to in the base image
866 core::position2d<s32> pos_base(
867 x0*dim_crack_scaled_single.Width,
868 y0*dim_crack_scaled_single.Height
870 // Rectangle to copy the crack from on the scaled image
871 core::rect<s32> rect_crack_scaled(
873 dim_crack_scaled_single
876 img_crack_scaled->copyToWithAlpha(baseimg, pos_base,
878 video::SColor(255,255,255,255),
882 img_crack_scaled->drop();
889 [combine:WxH:X,Y=filename:X,Y=filename2
890 Creates a bigger texture from an amount of smaller ones
892 else if(part_of_name.substr(0,8) == "[combine")
894 Strfnd sf(part_of_name);
896 u32 w0 = stoi(sf.next("x"));
897 u32 h0 = stoi(sf.next(":"));
898 dstream<<"INFO: combined w="<<w0<<" h="<<h0<<std::endl;
899 core::dimension2d<u32> dim(w0,h0);
900 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
901 while(sf.atend() == false)
903 u32 x = stoi(sf.next(","));
904 u32 y = stoi(sf.next("="));
905 std::string filename = sf.next(":");
906 dstream<<"INFO: Adding \""<<filename
907 <<"\" to combined ("<<x<<","<<y<<")"
909 video::IImage *img = driver->createImageFromFile(
910 getTexturePath(filename.c_str()).c_str());
913 core::dimension2d<u32> dim = img->getDimension();
914 dstream<<"INFO: Size "<<dim.Width
915 <<"x"<<dim.Height<<std::endl;
916 core::position2d<s32> pos_base(x, y);
917 video::IImage *img2 =
918 driver->createImage(video::ECF_A8R8G8B8, dim);
921 img2->copyToWithAlpha(baseimg, pos_base,
922 core::rect<s32>(v2s32(0,0), dim),
923 video::SColor(255,255,255,255),
929 dstream<<"WARNING: img==NULL"<<std::endl;
935 Adds a progress bar, 0.0 <= N <= 1.0
937 else if(part_of_name.substr(0,12) == "[progressbar")
941 dstream<<"WARNING: getTextureIdDirect(): baseimg==NULL "
942 <<"for part_of_name="<<part_of_name
943 <<", cancelling."<<std::endl;
947 float value = stof(part_of_name.substr(12));
948 make_progressbar(value, baseimg);
951 "[noalpha:filename.png"
952 Use an image without it's alpha channel.
953 Used for the leaves texture when in old leaves mode, so
954 that the transparent parts don't look completely black
955 when simple alpha channel is used for rendering.
957 else if(part_of_name.substr(0,8) == "[noalpha")
961 dstream<<"WARNING: getTextureIdDirect(): baseimg!=NULL "
962 <<"for part_of_name="<<part_of_name
963 <<", cancelling."<<std::endl;
967 std::string filename = part_of_name.substr(9);
969 std::string path = getTexturePath(filename.c_str());
971 dstream<<"INFO: getTextureIdDirect(): Loading path \""<<path
974 video::IImage *image = driver->createImageFromFile(path.c_str());
978 dstream<<"WARNING: getTextureIdDirect(): Loading path \""
979 <<path<<"\" failed"<<std::endl;
983 core::dimension2d<u32> dim = image->getDimension();
984 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
987 for(u32 y=0; y<dim.Height; y++)
988 for(u32 x=0; x<dim.Width; x++)
990 video::SColor c = image->getPixel(x,y);
992 image->setPixel(x,y,c);
995 image->copyTo(baseimg);
1001 [inventorycube{topimage{leftimage{rightimage
1002 In every subimage, replace ^ with &.
1003 Create an "inventory cube".
1004 NOTE: This should be used only on its own.
1005 Example (a grass block (not actually used in game):
1006 "[inventorycube{grass.png{mud.png&grass_side.png{mud.png&grass_side.png"
1008 else if(part_of_name.substr(0,14) == "[inventorycube")
1012 dstream<<"WARNING: getTextureIdDirect(): baseimg!=NULL "
1013 <<"for part_of_name="<<part_of_name
1014 <<", cancelling."<<std::endl;
1018 str_replace_char(part_of_name, '&', '^');
1019 Strfnd sf(part_of_name);
1021 std::string imagename_top = sf.next("{");
1022 std::string imagename_left = sf.next("{");
1023 std::string imagename_right = sf.next("{");
1028 if(driver->queryFeature(video::EVDF_RENDER_TO_TARGET) == false)
1030 dstream<<"WARNING: getTextureIdDirect(): EVDF_RENDER_TO_TARGET"
1031 " not supported. Creating fallback image"<<std::endl;
1032 baseimg = generate_image_from_scratch(
1033 imagename_top, device);
1039 dstream<<"INFO: inventorycube w="<<w0<<" h="<<h0<<std::endl;
1040 core::dimension2d<u32> dim(w0,h0);
1042 // Generate images for the faces of the cube
1043 video::IImage *img_top = generate_image_from_scratch(
1044 imagename_top, device);
1045 video::IImage *img_left = generate_image_from_scratch(
1046 imagename_left, device);
1047 video::IImage *img_right = generate_image_from_scratch(
1048 imagename_right, device);
1049 assert(img_top && img_left && img_right);
1051 // TODO: Create textures from images
1052 video::ITexture *texture_top = driver->addTexture(
1053 (imagename_top + "__temp__").c_str(), img_top);
1054 assert(texture_top);
1061 // Create render target texture
1062 video::ITexture *rtt = NULL;
1063 std::string rtt_name = part_of_name + "_RTT";
1064 rtt = driver->addRenderTargetTexture(dim, rtt_name.c_str(),
1065 video::ECF_A8R8G8B8);
1068 // Set render target
1069 driver->setRenderTarget(rtt, true, true,
1070 video::SColor(0,0,0,0));
1072 // Get a scene manager
1073 scene::ISceneManager *smgr_main = device->getSceneManager();
1075 scene::ISceneManager *smgr = smgr_main->createNewSceneManager();
1080 - An unit cube is centered at 0,0,0
1081 - Camera looks at cube from Y+, Z- towards Y-, Z+
1082 NOTE: Cube has to be changed to something else because
1083 the textures cannot be set individually (or can they?)
1086 scene::ISceneNode* cube = smgr->addCubeSceneNode(1.0, NULL, -1,
1087 v3f(0,0,0), v3f(0, 45, 0));
1088 // Set texture of cube
1089 cube->setMaterialTexture(0, texture_top);
1090 //cube->setMaterialFlag(video::EMF_LIGHTING, false);
1091 cube->setMaterialFlag(video::EMF_ANTI_ALIASING, false);
1092 cube->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
1094 scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(0,
1095 v3f(0, 1.0, -1.5), v3f(0, 0, 0));
1096 // Set orthogonal projection
1097 core::CMatrix4<f32> pm;
1098 pm.buildProjectionMatrixOrthoLH(1.65, 1.65, 0, 100);
1099 camera->setProjectionMatrix(pm, true);
1101 /*scene::ILightSceneNode *light =*/ smgr->addLightSceneNode(0,
1102 v3f(-50, 100, 0), video::SColorf(0.5,0.5,0.5), 1000);
1104 smgr->setAmbientLight(video::SColorf(0.2,0.2,0.2));
1107 driver->beginScene(true, true, video::SColor(0,0,0,0));
1111 // NOTE: The scene nodes should not be dropped, otherwise
1112 // smgr->drop() segfaults
1116 // Drop scene manager
1119 // Unset render target
1120 driver->setRenderTarget(0, true, true, 0);
1122 //TODO: Free textures of images
1123 driver->removeTexture(texture_top);
1125 // Create image of render target
1126 video::IImage *image = driver->createImage(rtt, v2s32(0,0), dim);
1130 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
1134 image->copyTo(baseimg);
1141 dstream<<"WARNING: getTextureIdDirect(): Invalid "
1142 " modification: \""<<part_of_name<<"\""<<std::endl;
1149 void make_progressbar(float value, video::IImage *image)
1154 core::dimension2d<u32> size = image->getDimension();
1156 u32 barheight = size.Height/16;
1157 u32 barpad_x = size.Width/16;
1158 u32 barpad_y = size.Height/16;
1159 u32 barwidth = size.Width - barpad_x*2;
1160 v2u32 barpos(barpad_x, size.Height - barheight - barpad_y);
1162 u32 barvalue_i = (u32)(((float)barwidth * value) + 0.5);
1164 video::SColor active(255,255,0,0);
1165 video::SColor inactive(255,0,0,0);
1166 for(u32 x0=0; x0<barwidth; x0++)
1173 u32 x = x0 + barpos.X;
1174 for(u32 y=barpos.Y; y<barpos.Y+barheight; y++)
1176 image->setPixel(x,y, *c);