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 Gets the path to a texture by first checking if the texture exists
27 in texture_path and if not, using the data path.
29 inline std::string getTexturePath(std::string filename)
31 std::string texture_path = g_settings.get("texture_path");
32 if(texture_path != "")
34 std::string fullpath = texture_path + '/' + filename;
35 if(fs::PathExists(fullpath))
39 return porting::getDataPath(filename.c_str());
42 TextureSource::TextureSource(IrrlichtDevice *device):
44 m_main_atlas_image(NULL),
45 m_main_atlas_texture(NULL)
49 m_atlaspointer_cache_mutex.Init();
51 m_main_thread = get_current_thread_id();
53 // Add a NULL AtlasPointer as the first index, named ""
54 m_atlaspointer_cache.push_back(SourceAtlasPointer(""));
57 // Build main texture atlas
58 if(g_settings.getBool("enable_texture_atlas"))
61 dstream<<"INFO: Not building texture atlas."<<std::endl;
64 TextureSource::~TextureSource()
68 void TextureSource::processQueue()
73 if(m_get_texture_queue.size() > 0)
75 GetRequest<std::string, u32, u8, u8>
76 request = m_get_texture_queue.pop();
78 dstream<<"INFO: TextureSource::processQueue(): "
79 <<"got texture request with "
80 <<"name="<<request.key
83 GetResult<std::string, u32, u8, u8>
85 result.key = request.key;
86 result.callers = request.callers;
87 result.item = getTextureIdDirect(request.key);
89 request.dest->push_back(result);
93 u32 TextureSource::getTextureId(const std::string &name)
95 //dstream<<"INFO: getTextureId(): name="<<name<<std::endl;
99 See if texture already exists
101 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
102 core::map<std::string, u32>::Node *n;
103 n = m_name_to_id.find(name);
106 return n->getValue();
113 if(get_current_thread_id() == m_main_thread)
115 return getTextureIdDirect(name);
119 dstream<<"INFO: getTextureId(): Queued: name="<<name<<std::endl;
121 // We're gonna ask the result to be put into here
122 ResultQueue<std::string, u32, u8, u8> result_queue;
124 // Throw a request in
125 m_get_texture_queue.add(name, 0, 0, &result_queue);
127 dstream<<"INFO: Waiting for texture from main thread, name="
132 // Wait result for a second
133 GetResult<std::string, u32, u8, u8>
134 result = result_queue.pop_front(1000);
136 // Check that at least something worked OK
137 assert(result.key == name);
141 catch(ItemNotFoundException &e)
143 dstream<<"WARNING: Waiting for texture timed out."<<std::endl;
148 dstream<<"WARNING: getTextureId(): Failed"<<std::endl;
153 // Draw a progress bar on the image
154 void make_progressbar(float value, video::IImage *image);
157 Generate image based on a string like "stone.png" or "[crack0".
158 if baseimg is NULL, it is created. Otherwise stuff is made on it.
160 bool generate_image(std::string part_of_name, video::IImage *& baseimg,
161 IrrlichtDevice *device);
164 Generates an image from a full string like
165 "stone.png^mineral_coal.png^[crack0".
167 This is used by buildMainAtlas().
169 video::IImage* generate_image_from_scratch(std::string name,
170 IrrlichtDevice *device);
173 This method generates all the textures
175 u32 TextureSource::getTextureIdDirect(const std::string &name)
177 dstream<<"INFO: getTextureIdDirect(): name="<<name<<std::endl;
179 // Empty name means texture 0
182 dstream<<"INFO: getTextureIdDirect(): name is empty"<<std::endl;
187 Calling only allowed from main thread
189 if(get_current_thread_id() != m_main_thread)
191 dstream<<"ERROR: TextureSource::getTextureIdDirect() "
192 "called not from main thread"<<std::endl;
197 See if texture already exists
200 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
202 core::map<std::string, u32>::Node *n;
203 n = m_name_to_id.find(name);
206 dstream<<"INFO: getTextureIdDirect(): name="<<name
207 <<" found in cache"<<std::endl;
208 return n->getValue();
212 dstream<<"INFO: getTextureIdDirect(): name="<<name
213 <<" NOT found in cache. Creating it."<<std::endl;
219 char separator = '^';
222 This is set to the id of the base image.
223 If left 0, there is no base image and a completely new image
226 u32 base_image_id = 0;
228 // Find last meta separator in name
229 s32 last_separator_position = -1;
230 for(s32 i=name.size()-1; i>=0; i--)
232 if(name[i] == separator)
234 last_separator_position = i;
239 If separator was found, construct the base name and make the
240 base image using a recursive call
242 std::string base_image_name;
243 if(last_separator_position != -1)
245 // Construct base name
246 base_image_name = name.substr(0, last_separator_position);
247 dstream<<"INFO: getTextureIdDirect(): Calling itself recursively"
248 " to get base image, name="<<base_image_name<<std::endl;
249 base_image_id = getTextureIdDirect(base_image_name);
252 dstream<<"base_image_id="<<base_image_id<<std::endl;
254 video::IVideoDriver* driver = m_device->getVideoDriver();
257 video::ITexture *t = NULL;
260 An image will be built from files and then converted into a texture.
262 video::IImage *baseimg = NULL;
264 // If a base image was found, copy it to baseimg
265 if(base_image_id != 0)
267 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
269 SourceAtlasPointer ap = m_atlaspointer_cache[base_image_id];
271 video::IImage *image = ap.atlas_img;
275 dstream<<"WARNING: getTextureIdDirect(): NULL image in "
276 <<"cache: \""<<base_image_name<<"\""
281 core::dimension2d<u32> dim = ap.intsize;
283 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
285 core::position2d<s32> pos_to(0,0);
286 core::position2d<s32> pos_from = ap.intpos;
290 v2s32(0,0), // position in target
291 core::rect<s32>(pos_from, dim) // from
294 dstream<<"INFO: getTextureIdDirect(): Loaded \""
295 <<base_image_name<<"\" from image cache"
301 Parse out the last part of the name of the image and act
305 std::string last_part_of_name = name.substr(last_separator_position+1);
306 dstream<<"last_part_of_name="<<last_part_of_name<<std::endl;
308 // Generate image according to part of name
309 if(generate_image(last_part_of_name, baseimg, m_device) == false)
311 dstream<<"INFO: getTextureIdDirect(): "
312 "failed to generate \""<<last_part_of_name<<"\""
316 // If no resulting image, print a warning
319 dstream<<"WARNING: getTextureIdDirect(): baseimg is NULL (attempted to"
320 " create texture \""<<name<<"\""<<std::endl;
325 // Create texture from resulting image
326 t = driver->addTexture(name.c_str(), baseimg);
330 Add texture to caches (add NULL textures too)
333 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
335 u32 id = m_atlaspointer_cache.size();
341 core::dimension2d<u32> baseimg_dim(0,0);
343 baseimg_dim = baseimg->getDimension();
344 SourceAtlasPointer nap(name, ap, baseimg, v2s32(0,0), baseimg_dim);
345 m_atlaspointer_cache.push_back(nap);
346 m_name_to_id.insert(name, id);
348 dstream<<"INFO: getTextureIdDirect(): name="<<name
349 <<": succesfully returning id="<<id<<std::endl;
354 std::string TextureSource::getTextureName(u32 id)
356 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
358 if(id >= m_atlaspointer_cache.size())
360 dstream<<"WARNING: TextureSource::getTextureName(): id="<<id
361 <<" >= m_atlaspointer_cache.size()="
362 <<m_atlaspointer_cache.size()<<std::endl;
366 return m_atlaspointer_cache[id].name;
370 AtlasPointer TextureSource::getTexture(u32 id)
372 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
374 if(id >= m_atlaspointer_cache.size())
375 return AtlasPointer(0, NULL);
377 return m_atlaspointer_cache[id].a;
380 void TextureSource::buildMainAtlas()
382 dstream<<"TextureSource::buildMainAtlas()"<<std::endl;
384 //return; // Disable (for testing)
386 video::IVideoDriver* driver = m_device->getVideoDriver();
389 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
391 // Create an image of the right size
392 core::dimension2d<u32> atlas_dim(1024,1024);
393 video::IImage *atlas_img =
394 driver->createImage(video::ECF_A8R8G8B8, atlas_dim);
398 A list of stuff to add. This should contain as much of the
399 stuff shown in game as possible, to minimize texture changes.
402 core::array<std::string> sourcelist;
404 sourcelist.push_back("stone.png");
405 sourcelist.push_back("mud.png");
406 sourcelist.push_back("sand.png");
407 sourcelist.push_back("grass.png");
408 sourcelist.push_back("grass_footsteps.png");
409 sourcelist.push_back("tree.png");
410 sourcelist.push_back("tree_top.png");
411 sourcelist.push_back("water.png");
412 sourcelist.push_back("leaves.png");
413 sourcelist.push_back("mud.png^grass_side.png");
415 sourcelist.push_back("stone.png^mineral_coal.png");
416 sourcelist.push_back("stone.png^mineral_iron.png");
417 sourcelist.push_back("mud.png^mineral_coal.png");
418 sourcelist.push_back("mud.png^mineral_iron.png");
419 sourcelist.push_back("sand.png^mineral_coal.png");
420 sourcelist.push_back("sand.png^mineral_iron.png");
422 // Padding to disallow texture bleeding
426 First pass: generate almost everything
428 core::position2d<s32> pos_in_atlas(0,0);
430 pos_in_atlas.Y += padding;
432 for(u32 i=0; i<sourcelist.size(); i++)
434 std::string name = sourcelist[i];
436 /*video::IImage *img = driver->createImageFromFile(
437 getTexturePath(name.c_str()).c_str());
441 core::dimension2d<u32> dim = img->getDimension();
442 // Make a copy with the right color format
443 video::IImage *img2 =
444 driver->createImage(video::ECF_A8R8G8B8, dim);
448 // Generate image by name
449 video::IImage *img2 = generate_image_from_scratch(name, m_device);
452 dstream<<"WARNING: TextureSource::buildMainAtlas(): Couldn't generate texture atlas: Couldn't generate image \""<<name<<"\""<<std::endl;
456 core::dimension2d<u32> dim = img2->getDimension();
458 // Tile it a few times in the X direction
459 u16 xwise_tiling = 16;
460 for(u32 j=0; j<xwise_tiling; j++)
462 // Copy the copy to the atlas
463 img2->copyToWithAlpha(atlas_img,
464 pos_in_atlas + v2s32(j*dim.Width,0),
465 core::rect<s32>(v2s32(0,0), dim),
466 video::SColor(255,255,255,255),
470 // Copy the borders a few times to disallow texture bleeding
471 for(u32 side=0; side<2; side++) // top and bottom
472 for(s32 y0=0; y0<padding; y0++)
473 for(s32 x0=0; x0<(s32)xwise_tiling*(s32)dim.Width; x0++)
479 dst_y = y0 + pos_in_atlas.Y + dim.Height;
480 src_y = pos_in_atlas.Y + dim.Height - 1;
484 dst_y = -y0 + pos_in_atlas.Y-1;
485 src_y = pos_in_atlas.Y;
487 s32 x = x0 + pos_in_atlas.X * dim.Width;
488 video::SColor c = atlas_img->getPixel(x, src_y);
489 atlas_img->setPixel(x,dst_y,c);
495 Add texture to caches
499 u32 id = m_atlaspointer_cache.size();
501 // Create AtlasPointer
503 ap.atlas = NULL; // Set on the second pass
504 ap.pos = v2f((float)pos_in_atlas.X/(float)atlas_dim.Width,
505 (float)pos_in_atlas.Y/(float)atlas_dim.Height);
506 ap.size = v2f((float)dim.Width/(float)atlas_dim.Width,
507 (float)dim.Width/(float)atlas_dim.Height);
508 ap.tiled = xwise_tiling;
510 // Create SourceAtlasPointer and add to containers
511 SourceAtlasPointer nap(name, ap, atlas_img, pos_in_atlas, dim);
512 m_atlaspointer_cache.push_back(nap);
513 m_name_to_id.insert(name, id);
515 // Increment position
516 pos_in_atlas.Y += dim.Height + padding * 2;
522 video::ITexture *t = driver->addTexture("__main_atlas__", atlas_img);
526 Second pass: set texture pointer in generated AtlasPointers
528 for(u32 i=0; i<sourcelist.size(); i++)
530 std::string name = sourcelist[i];
531 if(m_name_to_id.find(name) == NULL)
533 u32 id = m_name_to_id[name];
534 //dstream<<"id of name "<<name<<" is "<<id<<std::endl;
535 m_atlaspointer_cache[id].a.atlas = t;
539 Write image to file so that it can be inspected
541 /*driver->writeImageToFile(atlas_img,
542 getTexturePath("main_atlas.png").c_str());*/
545 video::IImage* generate_image_from_scratch(std::string name,
546 IrrlichtDevice *device)
548 dstream<<"INFO: generate_image_from_scratch(): "
549 "name="<<name<<std::endl;
551 video::IVideoDriver* driver = device->getVideoDriver();
558 video::IImage *baseimg = NULL;
560 char separator = '^';
562 // Find last meta separator in name
563 s32 last_separator_position = -1;
564 for(s32 i=name.size()-1; i>=0; i--)
566 if(name[i] == separator)
568 last_separator_position = i;
573 /*dstream<<"INFO: generate_image_from_scratch(): "
574 <<"last_separator_position="<<last_separator_position
578 If separator was found, construct the base name and make the
579 base image using a recursive call
581 std::string base_image_name;
582 if(last_separator_position != -1)
584 // Construct base name
585 base_image_name = name.substr(0, last_separator_position);
586 dstream<<"INFO: generate_image_from_scratch(): Calling itself recursively"
587 " to get base image, name="<<base_image_name<<std::endl;
588 baseimg = generate_image_from_scratch(base_image_name, device);
592 Parse out the last part of the name of the image and act
596 std::string last_part_of_name = name.substr(last_separator_position+1);
597 dstream<<"last_part_of_name="<<last_part_of_name<<std::endl;
599 // Generate image according to part of name
600 if(generate_image(last_part_of_name, baseimg, device) == false)
602 dstream<<"INFO: generate_image_from_scratch(): "
603 "failed to generate \""<<last_part_of_name<<"\""
611 bool generate_image(std::string part_of_name, video::IImage *& baseimg,
612 IrrlichtDevice *device)
614 video::IVideoDriver* driver = device->getVideoDriver();
617 // Stuff starting with [ are special commands
618 if(part_of_name[0] != '[')
620 // A normal texture; load it from a file
621 std::string path = getTexturePath(part_of_name.c_str());
622 dstream<<"INFO: getTextureIdDirect(): Loading path \""<<path
625 video::IImage *image = driver->createImageFromFile(path.c_str());
629 dstream<<"WARNING: Could not load image \""<<part_of_name
630 <<"\" from path \""<<path<<"\""
631 <<" while building texture"<<std::endl;
635 dstream<<"WARNING: Creating a dummy"<<" image for \""
636 <<part_of_name<<"\""<<std::endl;
638 // Just create a dummy image
639 //core::dimension2d<u32> dim(2,2);
640 core::dimension2d<u32> dim(1,1);
641 image = driver->createImage(video::ECF_A8R8G8B8, dim);
643 /*image->setPixel(0,0, video::SColor(255,255,0,0));
644 image->setPixel(1,0, video::SColor(255,0,255,0));
645 image->setPixel(0,1, video::SColor(255,0,0,255));
646 image->setPixel(1,1, video::SColor(255,255,0,255));*/
647 image->setPixel(0,0, video::SColor(255,myrand()%256,
648 myrand()%256,myrand()%256));
649 /*image->setPixel(1,0, video::SColor(255,myrand()%256,
650 myrand()%256,myrand()%256));
651 image->setPixel(0,1, video::SColor(255,myrand()%256,
652 myrand()%256,myrand()%256));
653 image->setPixel(1,1, video::SColor(255,myrand()%256,
654 myrand()%256,myrand()%256));*/
657 // If base image is NULL, load as base.
660 dstream<<"INFO: Setting "<<part_of_name<<" as base"<<std::endl;
662 Copy it this way to get an alpha channel.
663 Otherwise images with alpha cannot be blitted on
664 images that don't have alpha in the original file.
666 core::dimension2d<u32> dim = image->getDimension();
667 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
668 image->copyTo(baseimg);
671 // Else blit on base.
674 dstream<<"INFO: Blitting "<<part_of_name<<" on base"<<std::endl;
675 // Size of the copied area
676 core::dimension2d<u32> dim = image->getDimension();
677 //core::dimension2d<u32> dim(16,16);
678 // Position to copy the blitted to in the base image
679 core::position2d<s32> pos_to(0,0);
680 // Position to copy the blitted from in the blitted image
681 core::position2d<s32> pos_from(0,0);
683 image->copyToWithAlpha(baseimg, pos_to,
684 core::rect<s32>(pos_from, dim),
685 video::SColor(255,255,255,255),
693 // A special texture modification
695 dstream<<"INFO: getTextureIdDirect(): generating special "
696 <<"modification \""<<part_of_name<<"\""
700 This is the simplest of all; it just adds stuff to the
701 name so that a separate texture is created.
703 It is used to make textures for stuff that doesn't want
704 to implement getting the texture from a bigger texture
707 if(part_of_name == "[forcesingle")
712 Adds a cracking texture
714 else if(part_of_name.substr(0,6) == "[crack")
718 dstream<<"WARNING: getTextureIdDirect(): baseimg==NULL "
719 <<"for part_of_name="<<part_of_name
720 <<", cancelling."<<std::endl;
724 u16 progression = stoi(part_of_name.substr(6));
725 // Size of the base image
726 core::dimension2d<u32> dim_base = baseimg->getDimension();
727 // Crack will be drawn at this size
729 // Size of the crack image
730 core::dimension2d<u32> dim_crack(cracksize,cracksize);
731 // Position to copy the crack from in the crack image
732 core::position2d<s32> pos_other(0, 16 * progression);
734 video::IImage *crackimage = driver->createImageFromFile(
735 getTexturePath("crack.png").c_str());
739 /*crackimage->copyToWithAlpha(baseimg, v2s32(0,0),
740 core::rect<s32>(pos_other, dim_base),
741 video::SColor(255,255,255,255),
744 for(u32 y0=0; y0<dim_base.Height/dim_crack.Height; y0++)
745 for(u32 x0=0; x0<dim_base.Width/dim_crack.Width; x0++)
747 // Position to copy the crack to in the base image
748 core::position2d<s32> pos_base(x0*cracksize, y0*cracksize);
749 crackimage->copyToWithAlpha(baseimg, pos_base,
750 core::rect<s32>(pos_other, dim_crack),
751 video::SColor(255,255,255,255),
759 [combine:WxH:X,Y=filename:X,Y=filename2
760 Creates a bigger texture from an amount of smaller ones
762 else if(part_of_name.substr(0,8) == "[combine")
764 Strfnd sf(part_of_name);
766 u32 w0 = stoi(sf.next("x"));
767 u32 h0 = stoi(sf.next(":"));
768 dstream<<"INFO: combined w="<<w0<<" h="<<h0<<std::endl;
769 core::dimension2d<u32> dim(w0,h0);
770 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
771 while(sf.atend() == false)
773 u32 x = stoi(sf.next(","));
774 u32 y = stoi(sf.next("="));
775 std::string filename = sf.next(":");
776 dstream<<"INFO: Adding \""<<filename
777 <<"\" to combined ("<<x<<","<<y<<")"
779 video::IImage *img = driver->createImageFromFile(
780 getTexturePath(filename.c_str()).c_str());
783 core::dimension2d<u32> dim = img->getDimension();
784 dstream<<"INFO: Size "<<dim.Width
785 <<"x"<<dim.Height<<std::endl;
786 core::position2d<s32> pos_base(x, y);
787 video::IImage *img2 =
788 driver->createImage(video::ECF_A8R8G8B8, dim);
791 img2->copyToWithAlpha(baseimg, pos_base,
792 core::rect<s32>(v2s32(0,0), dim),
793 video::SColor(255,255,255,255),
799 dstream<<"WARNING: img==NULL"<<std::endl;
805 Adds a progress bar, 0.0 <= N <= 1.0
807 else if(part_of_name.substr(0,12) == "[progressbar")
811 dstream<<"WARNING: getTextureIdDirect(): baseimg==NULL "
812 <<"for part_of_name="<<part_of_name
813 <<", cancelling."<<std::endl;
817 float value = stof(part_of_name.substr(12));
818 make_progressbar(value, baseimg);
821 "[noalpha:filename.png"
822 Use an image without it's alpha channel.
823 Used for the leaves texture when in old leaves mode, so
824 that the transparent parts don't look completely black
825 when simple alpha channel is used for rendering.
827 else if(part_of_name.substr(0,8) == "[noalpha")
831 dstream<<"WARNING: getTextureIdDirect(): baseimg!=NULL "
832 <<"for part_of_name="<<part_of_name
833 <<", cancelling."<<std::endl;
837 std::string filename = part_of_name.substr(9);
839 std::string path = getTexturePath(filename.c_str());
841 dstream<<"INFO: getTextureIdDirect(): Loading path \""<<path
844 video::IImage *image = driver->createImageFromFile(path.c_str());
848 dstream<<"WARNING: getTextureIdDirect(): Loading path \""
849 <<path<<"\" failed"<<std::endl;
853 core::dimension2d<u32> dim = image->getDimension();
854 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
857 for(u32 y=0; y<dim.Height; y++)
858 for(u32 x=0; x<dim.Width; x++)
860 video::SColor c = image->getPixel(x,y);
862 image->setPixel(x,y,c);
865 image->copyTo(baseimg);
871 [inventorycube{topimage{leftimage{rightimage
872 In every subimage, replace ^ with &.
873 Create an "inventory cube".
874 NOTE: This should be used only on its own.
875 Example (a grass block (not actually used in game):
876 "[inventorycube{grass.png{mud.png&grass_side.png{mud.png&grass_side.png"
878 else if(part_of_name.substr(0,14) == "[inventorycube")
882 dstream<<"WARNING: getTextureIdDirect(): baseimg!=NULL "
883 <<"for part_of_name="<<part_of_name
884 <<", cancelling."<<std::endl;
888 str_replace_char(part_of_name, '&', '^');
889 Strfnd sf(part_of_name);
891 std::string imagename_top = sf.next("{");
892 std::string imagename_left = sf.next("{");
893 std::string imagename_right = sf.next("{");
898 if(driver->queryFeature(video::EVDF_RENDER_TO_TARGET) == false)
900 dstream<<"WARNING: getTextureIdDirect(): EVDF_RENDER_TO_TARGET"
901 " not supported. Creating fallback image"<<std::endl;
902 baseimg = generate_image_from_scratch(
903 imagename_top, device);
909 dstream<<"INFO: inventorycube w="<<w0<<" h="<<h0<<std::endl;
910 core::dimension2d<u32> dim(w0,h0);
912 // Generate images for the faces of the cube
913 video::IImage *img_top = generate_image_from_scratch(
914 imagename_top, device);
915 video::IImage *img_left = generate_image_from_scratch(
916 imagename_left, device);
917 video::IImage *img_right = generate_image_from_scratch(
918 imagename_right, device);
919 assert(img_top && img_left && img_right);
921 // TODO: Create textures from images
922 video::ITexture *texture_top = driver->addTexture(
923 (imagename_top + "__temp__").c_str(), img_top);
931 // Create render target texture
932 video::ITexture *rtt = NULL;
933 std::string rtt_name = part_of_name + "_RTT";
934 rtt = driver->addRenderTargetTexture(dim, rtt_name.c_str(),
935 video::ECF_A8R8G8B8);
939 driver->setRenderTarget(rtt, true, true,
940 video::SColor(0,0,0,0));
942 // Get a scene manager
943 scene::ISceneManager *smgr_main = device->getSceneManager();
945 scene::ISceneManager *smgr = smgr_main->createNewSceneManager();
950 - An unit cube is centered at 0,0,0
951 - Camera looks at cube from Y+, Z- towards Y-, Z+
952 NOTE: Cube has to be changed to something else because
953 the textures cannot be set individually (or can they?)
956 scene::ISceneNode* cube = smgr->addCubeSceneNode(1.0, NULL, -1,
957 v3f(0,0,0), v3f(0, 45, 0));
958 // Set texture of cube
959 cube->setMaterialTexture(0, texture_top);
960 //cube->setMaterialFlag(video::EMF_LIGHTING, false);
961 cube->setMaterialFlag(video::EMF_ANTI_ALIASING, false);
962 cube->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
964 scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(0,
965 v3f(0, 1.0, -1.5), v3f(0, 0, 0));
966 // Set orthogonal projection
967 core::CMatrix4<f32> pm;
968 pm.buildProjectionMatrixOrthoLH(1.65, 1.65, 0, 100);
969 camera->setProjectionMatrix(pm, true);
971 scene::ILightSceneNode *light = smgr->addLightSceneNode(0,
972 v3f(-50, 100, 0), video::SColorf(0.5,0.5,0.5), 1000);
975 driver->beginScene(true, true, video::SColor(0,0,0,0));
979 // NOTE: The scene nodes should not be dropped, otherwise
980 // smgr->drop() segfaults
984 // Drop scene manager
987 // Unset render target
988 driver->setRenderTarget(0, true, true, 0);
990 //TODO: Free textures of images
991 driver->removeTexture(texture_top);
993 // Create image of render target
994 video::IImage *image = driver->createImage(rtt, v2s32(0,0), dim);
998 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
1002 image->copyTo(baseimg);
1009 dstream<<"WARNING: getTextureIdDirect(): Invalid "
1010 " modification: \""<<part_of_name<<"\""<<std::endl;
1017 void make_progressbar(float value, video::IImage *image)
1022 core::dimension2d<u32> size = image->getDimension();
1027 u32 barwidth = size.Width - barpad_x*2;
1028 v2u32 barpos(barpad_x, size.Height - barheight - barpad_y);
1030 u32 barvalue_i = (u32)(((float)barwidth * value) + 0.5);
1032 video::SColor active(255,255,0,0);
1033 video::SColor inactive(255,0,0,0);
1034 for(u32 x0=0; x0<barwidth; x0++)
1041 u32 x = x0 + barpos.X;
1042 for(u32 y=barpos.Y; y<barpos.Y+barheight; y++)
1044 image->setPixel(x,y, *c);