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
24 inline std::string getTexturePath(std::string filename)
26 std::string texture_path = g_settings.get("texture_path");
27 if(texture_path == "")
28 return porting::getDataPath(filename.c_str());
30 return texture_path + '/' + filename;
33 TextureSource::TextureSource(IrrlichtDevice *device):
35 m_main_atlas_image(NULL),
36 m_main_atlas_texture(NULL)
40 m_atlaspointer_cache_mutex.Init();
42 m_main_thread = get_current_thread_id();
44 // Add a NULL AtlasPointer as the first index, named ""
45 m_atlaspointer_cache.push_back(SourceAtlasPointer(""));
48 // Build main texture atlas
49 if(g_settings.getBool("enable_texture_atlas"))
52 dstream<<"INFO: Not building texture atlas."<<std::endl;
55 TextureSource::~TextureSource()
59 void TextureSource::processQueue()
64 if(m_get_texture_queue.size() > 0)
66 GetRequest<std::string, u32, u8, u8>
67 request = m_get_texture_queue.pop();
69 dstream<<"INFO: TextureSource::processQueue(): "
70 <<"got texture request with "
71 <<"name="<<request.key
74 GetResult<std::string, u32, u8, u8>
76 result.key = request.key;
77 result.callers = request.callers;
78 result.item = getTextureIdDirect(request.key);
80 request.dest->push_back(result);
84 u32 TextureSource::getTextureId(const std::string &name)
86 //dstream<<"INFO: getTextureId(): name="<<name<<std::endl;
90 See if texture already exists
92 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
93 core::map<std::string, u32>::Node *n;
94 n = m_name_to_id.find(name);
104 if(get_current_thread_id() == m_main_thread)
106 return getTextureIdDirect(name);
110 dstream<<"INFO: getTextureId(): Queued: name="<<name<<std::endl;
112 // We're gonna ask the result to be put into here
113 ResultQueue<std::string, u32, u8, u8> result_queue;
115 // Throw a request in
116 m_get_texture_queue.add(name, 0, 0, &result_queue);
118 dstream<<"INFO: Waiting for texture from main thread, name="
123 // Wait result for a second
124 GetResult<std::string, u32, u8, u8>
125 result = result_queue.pop_front(1000);
127 // Check that at least something worked OK
128 assert(result.key == name);
132 catch(ItemNotFoundException &e)
134 dstream<<"WARNING: Waiting for texture timed out."<<std::endl;
139 dstream<<"WARNING: getTextureId(): Failed"<<std::endl;
144 // Draw a progress bar on the image
145 void make_progressbar(float value, video::IImage *image);
148 Generate image based on a string like "stone.png" or "[crack0".
149 if baseimg is NULL, it is created. Otherwise stuff is made on it.
151 bool generate_image(std::string part_of_name, video::IImage *& baseimg,
152 IrrlichtDevice *device);
155 Generates an image from a full string like
156 "stone.png^mineral_coal.png^[crack0".
158 This is used by buildMainAtlas().
160 video::IImage* generate_image_from_scratch(std::string name,
161 IrrlichtDevice *device);
164 This method generates all the textures
166 u32 TextureSource::getTextureIdDirect(const std::string &name)
168 dstream<<"INFO: getTextureIdDirect(): name="<<name<<std::endl;
170 // Empty name means texture 0
173 dstream<<"INFO: getTextureIdDirect(): name is empty"<<std::endl;
178 Calling only allowed from main thread
180 if(get_current_thread_id() != m_main_thread)
182 dstream<<"ERROR: TextureSource::getTextureIdDirect() "
183 "called not from main thread"<<std::endl;
188 See if texture already exists
191 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
193 core::map<std::string, u32>::Node *n;
194 n = m_name_to_id.find(name);
197 dstream<<"INFO: getTextureIdDirect(): name="<<name
198 <<" found in cache"<<std::endl;
199 return n->getValue();
203 dstream<<"INFO: getTextureIdDirect(): name="<<name
204 <<" NOT found in cache. Creating it."<<std::endl;
210 char separator = '^';
213 This is set to the id of the base image.
214 If left 0, there is no base image and a completely new image
217 u32 base_image_id = 0;
219 // Find last meta separator in name
220 s32 last_separator_position = -1;
221 for(s32 i=name.size()-1; i>=0; i--)
223 if(name[i] == separator)
225 last_separator_position = i;
230 If separator was found, construct the base name and make the
231 base image using a recursive call
233 std::string base_image_name;
234 if(last_separator_position != -1)
236 // Construct base name
237 base_image_name = name.substr(0, last_separator_position);
238 dstream<<"INFO: getTextureIdDirect(): Calling itself recursively"
239 " to get base image, name="<<base_image_name<<std::endl;
240 base_image_id = getTextureIdDirect(base_image_name);
243 dstream<<"base_image_id="<<base_image_id<<std::endl;
245 video::IVideoDriver* driver = m_device->getVideoDriver();
248 video::ITexture *t = NULL;
251 An image will be built from files and then converted into a texture.
253 video::IImage *baseimg = NULL;
255 // If a base image was found, copy it to baseimg
256 if(base_image_id != 0)
258 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
260 SourceAtlasPointer ap = m_atlaspointer_cache[base_image_id];
262 video::IImage *image = ap.atlas_img;
266 dstream<<"WARNING: getTextureIdDirect(): NULL image in "
267 <<"cache: \""<<base_image_name<<"\""
272 core::dimension2d<u32> dim = ap.intsize;
274 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
276 core::position2d<s32> pos_to(0,0);
277 core::position2d<s32> pos_from = ap.intpos;
281 v2s32(0,0), // position in target
282 core::rect<s32>(pos_from, dim) // from
285 dstream<<"INFO: getTextureIdDirect(): Loaded \""
286 <<base_image_name<<"\" from image cache"
292 Parse out the last part of the name of the image and act
296 std::string last_part_of_name = name.substr(last_separator_position+1);
297 dstream<<"last_part_of_name="<<last_part_of_name<<std::endl;
299 // Generate image according to part of name
300 if(generate_image(last_part_of_name, baseimg, m_device) == false)
302 dstream<<"INFO: getTextureIdDirect(): "
303 "failed to generate \""<<last_part_of_name<<"\""
307 // If no resulting image, print a warning
310 dstream<<"WARNING: getTextureIdDirect(): baseimg is NULL (attempted to"
311 " create texture \""<<name<<"\""<<std::endl;
316 // Create texture from resulting image
317 t = driver->addTexture(name.c_str(), baseimg);
321 Add texture to caches (add NULL textures too)
324 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
326 u32 id = m_atlaspointer_cache.size();
332 core::dimension2d<u32> baseimg_dim(0,0);
334 baseimg_dim = baseimg->getDimension();
335 SourceAtlasPointer nap(name, ap, baseimg, v2s32(0,0), baseimg_dim);
336 m_atlaspointer_cache.push_back(nap);
337 m_name_to_id.insert(name, id);
339 dstream<<"INFO: getTextureIdDirect(): name="<<name
340 <<": succesfully returning id="<<id<<std::endl;
345 std::string TextureSource::getTextureName(u32 id)
347 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
349 if(id >= m_atlaspointer_cache.size())
351 dstream<<"WARNING: TextureSource::getTextureName(): id="<<id
352 <<" >= m_atlaspointer_cache.size()="
353 <<m_atlaspointer_cache.size()<<std::endl;
357 return m_atlaspointer_cache[id].name;
361 AtlasPointer TextureSource::getTexture(u32 id)
363 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
365 if(id >= m_atlaspointer_cache.size())
366 return AtlasPointer(0, NULL);
368 return m_atlaspointer_cache[id].a;
371 void TextureSource::buildMainAtlas()
373 dstream<<"TextureSource::buildMainAtlas()"<<std::endl;
375 //return; // Disable (for testing)
377 video::IVideoDriver* driver = m_device->getVideoDriver();
380 JMutexAutoLock lock(m_atlaspointer_cache_mutex);
382 // Create an image of the right size
383 core::dimension2d<u32> atlas_dim(1024,1024);
384 video::IImage *atlas_img =
385 driver->createImage(video::ECF_A8R8G8B8, atlas_dim);
389 A list of stuff to add. This should contain as much of the
390 stuff shown in game as possible, to minimize texture changes.
393 core::array<std::string> sourcelist;
395 sourcelist.push_back("stone.png");
396 sourcelist.push_back("mud.png");
397 sourcelist.push_back("sand.png");
398 sourcelist.push_back("grass.png");
399 sourcelist.push_back("grass_footsteps.png");
400 sourcelist.push_back("tree.png");
401 sourcelist.push_back("tree_top.png");
402 sourcelist.push_back("water.png");
403 sourcelist.push_back("leaves.png");
404 sourcelist.push_back("mud.png^grass_side.png");
406 sourcelist.push_back("stone.png^mineral_coal.png");
407 sourcelist.push_back("stone.png^mineral_iron.png");
408 sourcelist.push_back("mud.png^mineral_coal.png");
409 sourcelist.push_back("mud.png^mineral_iron.png");
410 sourcelist.push_back("sand.png^mineral_coal.png");
411 sourcelist.push_back("sand.png^mineral_iron.png");
413 // Padding to disallow texture bleeding
417 First pass: generate almost everything
419 core::position2d<s32> pos_in_atlas(0,0);
421 pos_in_atlas.Y += padding;
423 for(u32 i=0; i<sourcelist.size(); i++)
425 std::string name = sourcelist[i];
427 /*video::IImage *img = driver->createImageFromFile(
428 getTexturePath(name.c_str()).c_str());
432 core::dimension2d<u32> dim = img->getDimension();
433 // Make a copy with the right color format
434 video::IImage *img2 =
435 driver->createImage(video::ECF_A8R8G8B8, dim);
439 // Generate image by name
440 video::IImage *img2 = generate_image_from_scratch(name, m_device);
443 dstream<<"WARNING: TextureSource::buildMainAtlas(): Couldn't generate texture atlas: Couldn't generate image \""<<name<<"\""<<std::endl;
447 core::dimension2d<u32> dim = img2->getDimension();
449 // Tile it a few times in the X direction
450 u16 xwise_tiling = 16;
451 for(u32 j=0; j<xwise_tiling; j++)
453 // Copy the copy to the atlas
454 img2->copyToWithAlpha(atlas_img,
455 pos_in_atlas + v2s32(j*dim.Width,0),
456 core::rect<s32>(v2s32(0,0), dim),
457 video::SColor(255,255,255,255),
461 // Copy the borders a few times to disallow texture bleeding
462 for(u32 side=0; side<2; side++) // top and bottom
463 for(s32 y0=0; y0<padding; y0++)
464 for(s32 x0=0; x0<(s32)xwise_tiling*(s32)dim.Width; x0++)
470 dst_y = y0 + pos_in_atlas.Y + dim.Height;
471 src_y = pos_in_atlas.Y + dim.Height - 1;
475 dst_y = -y0 + pos_in_atlas.Y-1;
476 src_y = pos_in_atlas.Y;
478 s32 x = x0 + pos_in_atlas.X * dim.Width;
479 video::SColor c = atlas_img->getPixel(x, src_y);
480 atlas_img->setPixel(x,dst_y,c);
486 Add texture to caches
490 u32 id = m_atlaspointer_cache.size();
492 // Create AtlasPointer
494 ap.atlas = NULL; // Set on the second pass
495 ap.pos = v2f((float)pos_in_atlas.X/(float)atlas_dim.Width,
496 (float)pos_in_atlas.Y/(float)atlas_dim.Height);
497 ap.size = v2f((float)dim.Width/(float)atlas_dim.Width,
498 (float)dim.Width/(float)atlas_dim.Height);
499 ap.tiled = xwise_tiling;
501 // Create SourceAtlasPointer and add to containers
502 SourceAtlasPointer nap(name, ap, atlas_img, pos_in_atlas, dim);
503 m_atlaspointer_cache.push_back(nap);
504 m_name_to_id.insert(name, id);
506 // Increment position
507 pos_in_atlas.Y += dim.Height + padding * 2;
513 video::ITexture *t = driver->addTexture("__main_atlas__", atlas_img);
517 Second pass: set texture pointer in generated AtlasPointers
519 for(u32 i=0; i<sourcelist.size(); i++)
521 std::string name = sourcelist[i];
522 if(m_name_to_id.find(name) == NULL)
524 u32 id = m_name_to_id[name];
525 //dstream<<"id of name "<<name<<" is "<<id<<std::endl;
526 m_atlaspointer_cache[id].a.atlas = t;
530 Write image to file so that it can be inspected
532 /*driver->writeImageToFile(atlas_img,
533 getTexturePath("main_atlas.png").c_str());*/
536 video::IImage* generate_image_from_scratch(std::string name,
537 IrrlichtDevice *device)
539 dstream<<"INFO: generate_image_from_scratch(): "
540 "name="<<name<<std::endl;
542 video::IVideoDriver* driver = device->getVideoDriver();
549 video::IImage *baseimg = NULL;
551 char separator = '^';
553 // Find last meta separator in name
554 s32 last_separator_position = -1;
555 for(s32 i=name.size()-1; i>=0; i--)
557 if(name[i] == separator)
559 last_separator_position = i;
564 /*dstream<<"INFO: generate_image_from_scratch(): "
565 <<"last_separator_position="<<last_separator_position
569 If separator was found, construct the base name and make the
570 base image using a recursive call
572 std::string base_image_name;
573 if(last_separator_position != -1)
575 // Construct base name
576 base_image_name = name.substr(0, last_separator_position);
577 dstream<<"INFO: generate_image_from_scratch(): Calling itself recursively"
578 " to get base image, name="<<base_image_name<<std::endl;
579 baseimg = generate_image_from_scratch(base_image_name, device);
583 Parse out the last part of the name of the image and act
587 std::string last_part_of_name = name.substr(last_separator_position+1);
588 dstream<<"last_part_of_name="<<last_part_of_name<<std::endl;
590 // Generate image according to part of name
591 if(generate_image(last_part_of_name, baseimg, device) == false)
593 dstream<<"INFO: generate_image_from_scratch(): "
594 "failed to generate \""<<last_part_of_name<<"\""
602 bool generate_image(std::string part_of_name, video::IImage *& baseimg,
603 IrrlichtDevice *device)
605 video::IVideoDriver* driver = device->getVideoDriver();
608 // Stuff starting with [ are special commands
609 if(part_of_name[0] != '[')
611 // A normal texture; load it from a file
612 std::string path = getTexturePath(part_of_name.c_str());
613 dstream<<"INFO: getTextureIdDirect(): Loading path \""<<path
616 video::IImage *image = driver->createImageFromFile(path.c_str());
620 dstream<<"WARNING: Could not load image \""<<part_of_name
621 <<"\" from path \""<<path<<"\""
622 <<" while building texture"<<std::endl;
626 dstream<<"WARNING: Creating a dummy"<<" image for \""
627 <<part_of_name<<"\""<<std::endl;
629 // Just create a dummy image
630 //core::dimension2d<u32> dim(2,2);
631 core::dimension2d<u32> dim(1,1);
632 image = driver->createImage(video::ECF_A8R8G8B8, dim);
634 /*image->setPixel(0,0, video::SColor(255,255,0,0));
635 image->setPixel(1,0, video::SColor(255,0,255,0));
636 image->setPixel(0,1, video::SColor(255,0,0,255));
637 image->setPixel(1,1, video::SColor(255,255,0,255));*/
638 image->setPixel(0,0, video::SColor(255,myrand()%256,
639 myrand()%256,myrand()%256));
640 /*image->setPixel(1,0, video::SColor(255,myrand()%256,
641 myrand()%256,myrand()%256));
642 image->setPixel(0,1, video::SColor(255,myrand()%256,
643 myrand()%256,myrand()%256));
644 image->setPixel(1,1, video::SColor(255,myrand()%256,
645 myrand()%256,myrand()%256));*/
648 // If base image is NULL, load as base.
651 dstream<<"INFO: Setting "<<part_of_name<<" as base"<<std::endl;
653 Copy it this way to get an alpha channel.
654 Otherwise images with alpha cannot be blitted on
655 images that don't have alpha in the original file.
657 core::dimension2d<u32> dim = image->getDimension();
658 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
659 image->copyTo(baseimg);
662 // Else blit on base.
665 dstream<<"INFO: Blitting "<<part_of_name<<" on base"<<std::endl;
666 // Size of the copied area
667 core::dimension2d<u32> dim = image->getDimension();
668 //core::dimension2d<u32> dim(16,16);
669 // Position to copy the blitted to in the base image
670 core::position2d<s32> pos_to(0,0);
671 // Position to copy the blitted from in the blitted image
672 core::position2d<s32> pos_from(0,0);
674 image->copyToWithAlpha(baseimg, pos_to,
675 core::rect<s32>(pos_from, dim),
676 video::SColor(255,255,255,255),
684 // A special texture modification
686 dstream<<"INFO: getTextureIdDirect(): generating special "
687 <<"modification \""<<part_of_name<<"\""
691 This is the simplest of all; it just adds stuff to the
692 name so that a separate texture is created.
694 It is used to make textures for stuff that doesn't want
695 to implement getting the texture from a bigger texture
698 if(part_of_name == "[forcesingle")
703 Adds a cracking texture
705 else if(part_of_name.substr(0,6) == "[crack")
709 dstream<<"WARNING: getTextureIdDirect(): baseimg==NULL "
710 <<"for part_of_name="<<part_of_name
711 <<", cancelling."<<std::endl;
715 u16 progression = stoi(part_of_name.substr(6));
716 // Size of the base image
717 core::dimension2d<u32> dim_base = baseimg->getDimension();
718 // Crack will be drawn at this size
720 // Size of the crack image
721 core::dimension2d<u32> dim_crack(cracksize,cracksize);
722 // Position to copy the crack from in the crack image
723 core::position2d<s32> pos_other(0, 16 * progression);
725 video::IImage *crackimage = driver->createImageFromFile(
726 getTexturePath("crack.png").c_str());
730 /*crackimage->copyToWithAlpha(baseimg, v2s32(0,0),
731 core::rect<s32>(pos_other, dim_base),
732 video::SColor(255,255,255,255),
735 for(u32 y0=0; y0<dim_base.Height/dim_crack.Height; y0++)
736 for(u32 x0=0; x0<dim_base.Width/dim_crack.Width; x0++)
738 // Position to copy the crack to in the base image
739 core::position2d<s32> pos_base(x0*cracksize, y0*cracksize);
740 crackimage->copyToWithAlpha(baseimg, pos_base,
741 core::rect<s32>(pos_other, dim_crack),
742 video::SColor(255,255,255,255),
750 [combine:WxH:X,Y=filename:X,Y=filename2
751 Creates a bigger texture from an amount of smaller ones
753 else if(part_of_name.substr(0,8) == "[combine")
755 Strfnd sf(part_of_name);
757 u32 w0 = stoi(sf.next("x"));
758 u32 h0 = stoi(sf.next(":"));
759 dstream<<"INFO: combined w="<<w0<<" h="<<h0<<std::endl;
760 core::dimension2d<u32> dim(w0,h0);
761 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
762 while(sf.atend() == false)
764 u32 x = stoi(sf.next(","));
765 u32 y = stoi(sf.next("="));
766 std::string filename = sf.next(":");
767 dstream<<"INFO: Adding \""<<filename
768 <<"\" to combined ("<<x<<","<<y<<")"
770 video::IImage *img = driver->createImageFromFile(
771 getTexturePath(filename.c_str()).c_str());
774 core::dimension2d<u32> dim = img->getDimension();
775 dstream<<"INFO: Size "<<dim.Width
776 <<"x"<<dim.Height<<std::endl;
777 core::position2d<s32> pos_base(x, y);
778 video::IImage *img2 =
779 driver->createImage(video::ECF_A8R8G8B8, dim);
782 img2->copyToWithAlpha(baseimg, pos_base,
783 core::rect<s32>(v2s32(0,0), dim),
784 video::SColor(255,255,255,255),
790 dstream<<"WARNING: img==NULL"<<std::endl;
796 Adds a progress bar, 0.0 <= N <= 1.0
798 else if(part_of_name.substr(0,12) == "[progressbar")
802 dstream<<"WARNING: getTextureIdDirect(): baseimg==NULL "
803 <<"for part_of_name="<<part_of_name
804 <<", cancelling."<<std::endl;
808 float value = stof(part_of_name.substr(12));
809 make_progressbar(value, baseimg);
812 "[noalpha:filename.png"
813 Use an image without it's alpha channel.
814 Used for the leaves texture when in old leaves mode, so
815 that the transparent parts don't look completely black
816 when simple alpha channel is used for rendering.
818 else if(part_of_name.substr(0,8) == "[noalpha")
822 dstream<<"WARNING: getTextureIdDirect(): baseimg!=NULL "
823 <<"for part_of_name="<<part_of_name
824 <<", cancelling."<<std::endl;
828 std::string filename = part_of_name.substr(9);
830 std::string path = getTexturePath(filename.c_str());
832 dstream<<"INFO: getTextureIdDirect(): Loading path \""<<path
835 video::IImage *image = driver->createImageFromFile(path.c_str());
839 dstream<<"WARNING: getTextureIdDirect(): Loading path \""
840 <<path<<"\" failed"<<std::endl;
844 core::dimension2d<u32> dim = image->getDimension();
845 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
848 for(u32 y=0; y<dim.Height; y++)
849 for(u32 x=0; x<dim.Width; x++)
851 video::SColor c = image->getPixel(x,y);
853 image->setPixel(x,y,c);
856 image->copyTo(baseimg);
862 [inventorycube{topimage{leftimage{rightimage
863 In every subimage, replace ^ with &.
864 Create an "inventory cube".
865 NOTE: This should be used only on its own.
866 Example (a grass block (not actually used in game):
867 "[inventorycube{grass.png{mud.png&grass_side.png{mud.png&grass_side.png"
869 else if(part_of_name.substr(0,14) == "[inventorycube")
873 dstream<<"WARNING: getTextureIdDirect(): baseimg!=NULL "
874 <<"for part_of_name="<<part_of_name
875 <<", cancelling."<<std::endl;
879 str_replace_char(part_of_name, '&', '^');
880 Strfnd sf(part_of_name);
882 std::string imagename_top = sf.next("{");
883 std::string imagename_left = sf.next("{");
884 std::string imagename_right = sf.next("{");
889 if(driver->queryFeature(video::EVDF_RENDER_TO_TARGET) == false)
891 dstream<<"WARNING: getTextureIdDirect(): EVDF_RENDER_TO_TARGET"
892 " not supported. Creating fallback image"<<std::endl;
893 baseimg = generate_image_from_scratch(
894 imagename_top, device);
900 dstream<<"INFO: inventorycube w="<<w0<<" h="<<h0<<std::endl;
901 core::dimension2d<u32> dim(w0,h0);
903 // Generate images for the faces of the cube
904 video::IImage *img_top = generate_image_from_scratch(
905 imagename_top, device);
906 video::IImage *img_left = generate_image_from_scratch(
907 imagename_left, device);
908 video::IImage *img_right = generate_image_from_scratch(
909 imagename_right, device);
910 assert(img_top && img_left && img_right);
912 // TODO: Create textures from images
913 video::ITexture *texture_top = driver->addTexture(
914 (imagename_top + "__temp__").c_str(), img_top);
922 // Create render target texture
923 video::ITexture *rtt = NULL;
924 std::string rtt_name = part_of_name + "_RTT";
925 rtt = driver->addRenderTargetTexture(dim, rtt_name.c_str(),
926 video::ECF_A8R8G8B8);
930 driver->setRenderTarget(rtt, true, true,
931 video::SColor(0,0,0,0));
933 // Get a scene manager
934 scene::ISceneManager *smgr_main = device->getSceneManager();
936 scene::ISceneManager *smgr = smgr_main->createNewSceneManager();
941 - An unit cube is centered at 0,0,0
942 - Camera looks at cube from Y+, Z- towards Y-, Z+
943 NOTE: Cube has to be changed to something else because
944 the textures cannot be set individually (or can they?)
947 scene::ISceneNode* cube = smgr->addCubeSceneNode(1.0, NULL, -1,
948 v3f(0,0,0), v3f(0, 45, 0));
949 // Set texture of cube
950 cube->setMaterialTexture(0, texture_top);
951 //cube->setMaterialFlag(video::EMF_LIGHTING, false);
952 cube->setMaterialFlag(video::EMF_ANTI_ALIASING, false);
953 cube->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
955 scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(0,
956 v3f(0, 1.0, -1.5), v3f(0, 0, 0));
957 // Set orthogonal projection
958 core::CMatrix4<f32> pm;
959 pm.buildProjectionMatrixOrthoLH(1.65, 1.65, 0, 100);
960 camera->setProjectionMatrix(pm, true);
962 scene::ILightSceneNode *light = smgr->addLightSceneNode(0,
963 v3f(-50, 100, 0), video::SColorf(0.5,0.5,0.5), 1000);
966 driver->beginScene(true, true, video::SColor(0,0,0,0));
970 // NOTE: The scene nodes should not be dropped, otherwise
971 // smgr->drop() segfaults
975 // Drop scene manager
978 // Unset render target
979 driver->setRenderTarget(0, true, true, 0);
981 //TODO: Free textures of images
982 driver->removeTexture(texture_top);
984 // Create image of render target
985 video::IImage *image = driver->createImage(rtt, v2s32(0,0), dim);
989 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
993 image->copyTo(baseimg);
1000 dstream<<"WARNING: getTextureIdDirect(): Invalid "
1001 " modification: \""<<part_of_name<<"\""<<std::endl;
1008 void make_progressbar(float value, video::IImage *image)
1013 core::dimension2d<u32> size = image->getDimension();
1018 u32 barwidth = size.Width - barpad_x*2;
1019 v2u32 barpos(barpad_x, size.Height - barheight - barpad_y);
1021 u32 barvalue_i = (u32)(((float)barwidth * value) + 0.5);
1023 video::SColor active(255,255,0,0);
1024 video::SColor inactive(255,0,0,0);
1025 for(u32 x0=0; x0<barwidth; x0++)
1032 u32 x = x0 + barpos.X;
1033 for(u32 y=barpos.Y; y<barpos.Y+barheight; y++)
1035 image->setPixel(x,y, *c);