#include "settings.h"
#include <ICameraSceneNode.h>
#include "log.h"
+#include "mapnode.h" // For texture atlas making
+#include "mineral.h" // For texture atlas making
+#include "nodedef.h" // For texture atlas making
+#include "gamedef.h"
/*
A cache from texture name to texture path
*/
if(fullpath == "")
{
- std::string testpath = porting::getDataPath(filename.c_str());
+ std::string rel_path = std::string("clienttextures")+DIR_DELIM+filename;
+ std::string testpath = porting::path_data + DIR_DELIM + rel_path;
// Check all filename extensions. Returns "" if not found.
fullpath = getImagePath(testpath);
}
return fullpath;
}
+/*
+ An internal variant of AtlasPointer with more data.
+ (well, more like a wrapper)
+*/
+
+struct SourceAtlasPointer
+{
+ std::string name;
+ AtlasPointer a;
+ video::IImage *atlas_img; // The source image of the atlas
+ // Integer variants of position and size
+ v2s32 intpos;
+ v2u32 intsize;
+
+ SourceAtlasPointer(
+ const std::string &name_,
+ AtlasPointer a_=AtlasPointer(0, NULL),
+ video::IImage *atlas_img_=NULL,
+ v2s32 intpos_=v2s32(0,0),
+ v2u32 intsize_=v2u32(0,0)
+ ):
+ name(name_),
+ a(a_),
+ atlas_img(atlas_img_),
+ intpos(intpos_),
+ intsize(intsize_)
+ {
+ }
+};
+
+/*
+ SourceImageCache: A cache used for storing source images.
+*/
+
+class SourceImageCache
+{
+public:
+ void insert(const std::string &name, video::IImage *img,
+ bool do_overwrite)
+ {
+ assert(img);
+ core::map<std::string, video::IImage*>::Node *n;
+ n = m_images.find(name);
+ if(n){
+ if(!do_overwrite)
+ return;
+ video::IImage *oldimg = n->getValue();
+ if(oldimg)
+ oldimg->drop();
+ }
+ img->grab();
+ m_images[name] = img;
+ }
+ video::IImage* get(const std::string &name)
+ {
+ core::map<std::string, video::IImage*>::Node *n;
+ n = m_images.find(name);
+ if(n)
+ return n->getValue();
+ return NULL;
+ }
+ // Primarily fetches from cache, secondarily tries to read from filesystem
+ video::IImage* getOrLoad(const std::string &name, IrrlichtDevice *device)
+ {
+ core::map<std::string, video::IImage*>::Node *n;
+ n = m_images.find(name);
+ if(n){
+ n->getValue()->grab(); // Grab for caller
+ return n->getValue();
+ }
+ video::IVideoDriver* driver = device->getVideoDriver();
+ std::string path = getTexturePath(name.c_str());
+ if(path == ""){
+ infostream<<"SourceImageCache::getOrLoad(): No path found for \""
+ <<name<<"\""<<std::endl;
+ return NULL;
+ }
+ infostream<<"SourceImageCache::getOrLoad(): Loading path \""<<path
+ <<"\""<<std::endl;
+ video::IImage *img = driver->createImageFromFile(path.c_str());
+ // Even if could not be loaded, put as NULL
+ //m_images[name] = img;
+ if(img){
+ m_images[name] = img;
+ img->grab(); // Grab for caller
+ }
+ return img;
+ }
+private:
+ core::map<std::string, video::IImage*> m_images;
+};
+
/*
TextureSource
*/
+class TextureSource : public IWritableTextureSource
+{
+public:
+ TextureSource(IrrlichtDevice *device);
+ ~TextureSource();
+
+ /*
+ Example case:
+ Now, assume a texture with the id 1 exists, and has the name
+ "stone.png^mineral1".
+ Then a random thread calls getTextureId for a texture called
+ "stone.png^mineral1^crack0".
+ ...Now, WTF should happen? Well:
+ - getTextureId strips off stuff recursively from the end until
+ the remaining part is found, or nothing is left when
+ something is stripped out
+
+ But it is slow to search for textures by names and modify them
+ like that?
+ - ContentFeatures is made to contain ids for the basic plain
+ textures
+ - Crack textures can be slow by themselves, but the framework
+ must be fast.
+
+ Example case #2:
+ - Assume a texture with the id 1 exists, and has the name
+ "stone.png^mineral1" and is specified as a part of some atlas.
+ - Now MapBlock::getNodeTile() stumbles upon a node which uses
+ texture id 1, and finds out that NODEMOD_CRACK must be applied
+ with progression=0
+ - It finds out the name of the texture with getTextureName(1),
+ appends "^crack0" to it and gets a new texture id with
+ getTextureId("stone.png^mineral1^crack0")
+
+ */
+
+ /*
+ Gets a texture id from cache or
+ - if main thread, from getTextureIdDirect
+ - if other thread, adds to request queue and waits for main thread
+ */
+ u32 getTextureId(const std::string &name);
+
+ /*
+ Example names:
+ "stone.png"
+ "stone.png^crack2"
+ "stone.png^blit:mineral_coal.png"
+ "stone.png^blit:mineral_coal.png^crack1"
+
+ - If texture specified by name is found from cache, return the
+ cached id.
+ - Otherwise generate the texture, add to cache and return id.
+ Recursion is used to find out the largest found part of the
+ texture and continue based on it.
+
+ The id 0 points to a NULL texture. It is returned in case of error.
+ */
+ u32 getTextureIdDirect(const std::string &name);
+
+ // Finds out the name of a cached texture.
+ std::string getTextureName(u32 id);
+
+ /*
+ If texture specified by the name pointed by the id doesn't
+ exist, create it, then return the cached texture.
+
+ Can be called from any thread. If called from some other thread
+ and not found in cache, the call is queued to the main thread
+ for processing.
+ */
+ AtlasPointer getTexture(u32 id);
+
+ AtlasPointer getTexture(const std::string &name)
+ {
+ return getTexture(getTextureId(name));
+ }
+
+ // Gets a separate texture
+ video::ITexture* getTextureRaw(const std::string &name)
+ {
+ AtlasPointer ap = getTexture(name);
+ return ap.atlas;
+ }
+
+ // Update new texture pointer and texture coordinates to an
+ // AtlasPointer based on it's texture id
+ void updateAP(AtlasPointer &ap);
+
+ // Processes queued texture requests from other threads.
+ // Shall be called from the main thread.
+ void processQueue();
+
+ // Insert an image into the cache without touching the filesystem.
+ // Shall be called from the main thread.
+ void insertSourceImage(const std::string &name, video::IImage *img);
+
+ // Rebuild images and textures from the current set of source images
+ // Shall be called from the main thread.
+ void rebuildImagesAndTextures();
+
+ // Build the main texture atlas which contains most of the
+ // textures.
+ void buildMainAtlas(class IGameDef *gamedef);
+
+private:
+
+ // The id of the thread that is allowed to use irrlicht directly
+ threadid_t m_main_thread;
+ // The irrlicht device
+ IrrlichtDevice *m_device;
+
+ // Cache of source images
+ // This should be only accessed from the main thread
+ SourceImageCache m_sourcecache;
+
+ // A texture id is index in this array.
+ // The first position contains a NULL texture.
+ core::array<SourceAtlasPointer> m_atlaspointer_cache;
+ // Maps a texture name to an index in the former.
+ core::map<std::string, u32> m_name_to_id;
+ // The two former containers are behind this mutex
+ JMutex m_atlaspointer_cache_mutex;
+
+ // Main texture atlas. This is filled at startup and is then not touched.
+ video::IImage *m_main_atlas_image;
+ video::ITexture *m_main_atlas_texture;
+
+ // Queued texture fetches (to be processed by the main thread)
+ RequestQueue<std::string, u32, u8, u8> m_get_texture_queue;
+};
+
+IWritableTextureSource* createTextureSource(IrrlichtDevice *device)
+{
+ return new TextureSource(device);
+}
+
TextureSource::TextureSource(IrrlichtDevice *device):
m_device(device),
m_main_atlas_image(NULL),
// Add a NULL AtlasPointer as the first index, named ""
m_atlaspointer_cache.push_back(SourceAtlasPointer(""));
m_name_to_id[""] = 0;
-
- // Build main texture atlas
- if(g_settings->getBool("enable_texture_atlas"))
- buildMainAtlas();
- else
- infostream<<"Not building texture atlas."<<std::endl;
}
TextureSource::~TextureSource()
{
}
-void TextureSource::processQueue()
-{
- /*
- Fetch textures
- */
- if(m_get_texture_queue.size() > 0)
- {
- GetRequest<std::string, u32, u8, u8>
- request = m_get_texture_queue.pop();
-
- infostream<<"TextureSource::processQueue(): "
- <<"got texture request with "
- <<"name=\""<<request.key<<"\""
- <<std::endl;
-
- GetResult<std::string, u32, u8, u8>
- result;
- result.key = request.key;
- result.callers = request.callers;
- result.item = getTextureIdDirect(request.key);
-
- request.dest->push_back(result);
- }
-}
-
u32 TextureSource::getTextureId(const std::string &name)
{
//infostream<<"getTextureId(): \""<<name<<"\""<<std::endl;
if baseimg is NULL, it is created. Otherwise stuff is made on it.
*/
bool generate_image(std::string part_of_name, video::IImage *& baseimg,
- IrrlichtDevice *device);
+ IrrlichtDevice *device, SourceImageCache *sourcecache);
/*
Generates an image from a full string like
This is used by buildMainAtlas().
*/
video::IImage* generate_image_from_scratch(std::string name,
- IrrlichtDevice *device);
+ IrrlichtDevice *device, SourceImageCache *sourcecache);
/*
This method generates all the textures
//infostream<<"last_part_of_name=\""<<last_part_of_name<<"\""<<std::endl;
// Generate image according to part of name
- if(generate_image(last_part_of_name, baseimg, m_device) == false)
+ if(!generate_image(last_part_of_name, baseimg, m_device, &m_sourcecache))
{
infostream<<"getTextureIdDirect(): "
"failed to generate \""<<last_part_of_name<<"\""
return m_atlaspointer_cache[id].a;
}
-void TextureSource::buildMainAtlas()
+void TextureSource::updateAP(AtlasPointer &ap)
+{
+ AtlasPointer ap2 = getTexture(ap.id);
+ ap = ap2;
+}
+
+void TextureSource::processQueue()
+{
+ /*
+ Fetch textures
+ */
+ if(m_get_texture_queue.size() > 0)
+ {
+ GetRequest<std::string, u32, u8, u8>
+ request = m_get_texture_queue.pop();
+
+ infostream<<"TextureSource::processQueue(): "
+ <<"got texture request with "
+ <<"name=\""<<request.key<<"\""
+ <<std::endl;
+
+ GetResult<std::string, u32, u8, u8>
+ result;
+ result.key = request.key;
+ result.callers = request.callers;
+ result.item = getTextureIdDirect(request.key);
+
+ request.dest->push_back(result);
+ }
+}
+
+void TextureSource::insertSourceImage(const std::string &name, video::IImage *img)
+{
+ infostream<<"TextureSource::insertSourceImage(): name="<<name<<std::endl;
+
+ assert(get_current_thread_id() == m_main_thread);
+
+ m_sourcecache.insert(name, img, false);
+
+#if 0
+ JMutexAutoLock lock(m_atlaspointer_cache_mutex);
+
+ video::IVideoDriver* driver = m_device->getVideoDriver();
+ assert(driver);
+
+ // Create texture
+ video::ITexture *t = driver->addTexture(name.c_str(), img);
+
+ bool reuse_old_id = false;
+ u32 id = m_atlaspointer_cache.size();
+ // Check old id without fetching a texture
+ core::map<std::string, u32>::Node *n;
+ n = m_name_to_id.find(name);
+ // If it exists, we will replace the old definition
+ if(n){
+ id = n->getValue();
+ reuse_old_id = true;
+ }
+
+ // Create AtlasPointer
+ AtlasPointer ap(id);
+ ap.atlas = t;
+ ap.pos = v2f(0,0);
+ ap.size = v2f(1,1);
+ ap.tiled = 0;
+ core::dimension2d<u32> dim = img->getDimension();
+
+ // Create SourceAtlasPointer and add to containers
+ SourceAtlasPointer nap(name, ap, img, v2s32(0,0), dim);
+ if(reuse_old_id)
+ m_atlaspointer_cache[id] = nap;
+ else
+ m_atlaspointer_cache.push_back(nap);
+ m_name_to_id[name] = id;
+#endif
+}
+
+void TextureSource::rebuildImagesAndTextures()
+{
+ JMutexAutoLock lock(m_atlaspointer_cache_mutex);
+
+ /*// Oh well... just clear everything, they'll load sometime.
+ m_atlaspointer_cache.clear();
+ m_name_to_id.clear();*/
+
+ video::IVideoDriver* driver = m_device->getVideoDriver();
+
+ // Remove source images from textures to disable inheriting textures
+ // from existing textures
+ /*for(u32 i=0; i<m_atlaspointer_cache.size(); i++){
+ SourceAtlasPointer *sap = &m_atlaspointer_cache[i];
+ sap->atlas_img->drop();
+ sap->atlas_img = NULL;
+ }*/
+
+ // Recreate textures
+ for(u32 i=0; i<m_atlaspointer_cache.size(); i++){
+ SourceAtlasPointer *sap = &m_atlaspointer_cache[i];
+ video::IImage *img =
+ generate_image_from_scratch(sap->name, m_device, &m_sourcecache);
+ // Create texture from resulting image
+ video::ITexture *t = NULL;
+ if(img)
+ t = driver->addTexture(sap->name.c_str(), img);
+
+ // Replace texture
+ sap->a.atlas = t;
+ sap->a.pos = v2f(0,0);
+ sap->a.size = v2f(1,1);
+ sap->a.tiled = 0;
+ sap->atlas_img = img;
+ sap->intpos = v2s32(0,0);
+ sap->intsize = img->getDimension();
+ }
+}
+
+void TextureSource::buildMainAtlas(class IGameDef *gamedef)
{
+ assert(gamedef->tsrc() == this);
+ INodeDefManager *ndef = gamedef->ndef();
+
infostream<<"TextureSource::buildMainAtlas()"<<std::endl;
//return; // Disable (for testing)
}
/*
- A list of stuff to include in the texture atlas.
-
- It is a single-dimensional texture atlas due to the need to tile
- textures.
-
- It should contain as much of the stuff shown in game as possible,
- to minimize texture changes.
-
- It fills up quickly, so do not add anything that isn't contained
- in most MapBlocks. E.g. mese isn't suitable but stone is.
+ Grab list of stuff to include in the texture atlas from the
+ main content features
*/
- core::array<std::string> sourcelist;
-
- sourcelist.push_back("stone.png");
- sourcelist.push_back("mud.png");
- sourcelist.push_back("sand.png");
- sourcelist.push_back("grass.png");
- sourcelist.push_back("grass_footsteps.png");
- sourcelist.push_back("tree.png");
- sourcelist.push_back("tree_top.png");
- sourcelist.push_back("water.png");
- sourcelist.push_back("leaves.png");
- sourcelist.push_back("glass.png");
- sourcelist.push_back("mud.png^grass_side.png");
- sourcelist.push_back("cobble.png");
- sourcelist.push_back("mossycobble.png");
- sourcelist.push_back("gravel.png");
- sourcelist.push_back("jungletree.png");
-
- sourcelist.push_back("stone.png^mineral_coal.png");
- sourcelist.push_back("stone.png^mineral_iron.png");
+ core::map<std::string, bool> sourcelist;
+
+ for(u16 j=0; j<MAX_CONTENT+1; j++)
+ {
+ if(j == CONTENT_IGNORE || j == CONTENT_AIR)
+ continue;
+ const ContentFeatures &f = ndef->get(j);
+ for(std::set<std::string>::const_iterator
+ i = f.used_texturenames.begin();
+ i != f.used_texturenames.end(); i++)
+ {
+ std::string name = *i;
+ sourcelist[name] = true;
+
+ if(f.often_contains_mineral){
+ for(int k=1; k<MINERAL_COUNT; k++){
+ std::string mineraltexture = mineral_block_texture(k);
+ std::string fulltexture = name + "^" + mineraltexture;
+ sourcelist[fulltexture] = true;
+ }
+ }
+ }
+ }
+ infostream<<"Creating texture atlas out of textures: ";
+ for(core::map<std::string, bool>::Iterator
+ i = sourcelist.getIterator();
+ i.atEnd() == false; i++)
+ {
+ std::string name = i.getNode()->getKey();
+ infostream<<"\""<<name<<"\" ";
+ }
+ infostream<<std::endl;
+
// Padding to disallow texture bleeding
s32 padding = 16;
+ s32 column_width = 256;
+ s32 column_padding = 16;
+
/*
First pass: generate almost everything
*/
core::position2d<s32> pos_in_atlas(0,0);
- pos_in_atlas.Y += padding;
+ pos_in_atlas.Y = padding;
- for(u32 i=0; i<sourcelist.size(); i++)
+ for(core::map<std::string, bool>::Iterator
+ i = sourcelist.getIterator();
+ i.atEnd() == false; i++)
{
- std::string name = sourcelist[i];
+ std::string name = i.getNode()->getKey();
- /*video::IImage *img = driver->createImageFromFile(
- getTexturePath(name.c_str()).c_str());
- if(img == NULL)
- continue;
-
- core::dimension2d<u32> dim = img->getDimension();
- // Make a copy with the right color format
- video::IImage *img2 =
- driver->createImage(video::ECF_A8R8G8B8, dim);
- img->copyTo(img2);
- img->drop();*/
-
// Generate image by name
- video::IImage *img2 = generate_image_from_scratch(name, m_device);
+ video::IImage *img2 = generate_image_from_scratch(name, m_device,
+ &m_sourcecache);
if(img2 == NULL)
{
infostream<<"TextureSource::buildMainAtlas(): Couldn't generate texture atlas: Couldn't generate image \""<<name<<"\""<<std::endl;
continue;
}
- // Stop making atlas if atlas is full
+ // Wrap columns and stop making atlas if atlas is full
if(pos_in_atlas.Y + dim.Height > atlas_dim.Height)
{
- infostream<<"TextureSource::buildMainAtlas(): "
- <<"Atlas is full, not adding more textures."
- <<std::endl;
- break;
+ if(pos_in_atlas.X > (s32)atlas_dim.Width - 256 - padding){
+ errorstream<<"TextureSource::buildMainAtlas(): "
+ <<"Atlas is full, not adding more textures."
+ <<std::endl;
+ break;
+ }
+ pos_in_atlas.Y = padding;
+ pos_in_atlas.X += column_width + column_padding;
}
infostream<<"TextureSource::buildMainAtlas(): Adding \""<<name
<<"\" to texture atlas"<<std::endl;
// Tile it a few times in the X direction
- u16 xwise_tiling = 16;
+ u16 xwise_tiling = column_width / dim.Width;
+ if(xwise_tiling > 16) // Limit to 16 (more gives no benefit)
+ xwise_tiling = 16;
for(u32 j=0; j<xwise_tiling; j++)
{
// Copy the copy to the atlas
dst_y = -y0 + pos_in_atlas.Y-1;
src_y = pos_in_atlas.Y;
}
- s32 x = x0 + pos_in_atlas.X * dim.Width;
+ s32 x = x0 + pos_in_atlas.X;
video::SColor c = atlas_img->getPixel(x, src_y);
atlas_img->setPixel(x,dst_y,c);
}
Add texture to caches
*/
- // Get next id
+ bool reuse_old_id = false;
u32 id = m_atlaspointer_cache.size();
+ // Check old id without fetching a texture
+ core::map<std::string, u32>::Node *n;
+ n = m_name_to_id.find(name);
+ // If it exists, we will replace the old definition
+ if(n){
+ id = n->getValue();
+ reuse_old_id = true;
+ infostream<<"TextureSource::buildMainAtlas(): "
+ <<"Replacing old AtlasPointer"<<std::endl;
+ }
// Create AtlasPointer
AtlasPointer ap(id);
// Create SourceAtlasPointer and add to containers
SourceAtlasPointer nap(name, ap, atlas_img, pos_in_atlas, dim);
- m_atlaspointer_cache.push_back(nap);
- m_name_to_id.insert(name, id);
+ if(reuse_old_id)
+ m_atlaspointer_cache[id] = nap;
+ else
+ m_atlaspointer_cache.push_back(nap);
+ m_name_to_id[name] = id;
// Increment position
pos_in_atlas.Y += dim.Height + padding * 2;
/*
Second pass: set texture pointer in generated AtlasPointers
*/
- for(u32 i=0; i<sourcelist.size(); i++)
+ for(core::map<std::string, bool>::Iterator
+ i = sourcelist.getIterator();
+ i.atEnd() == false; i++)
{
- std::string name = sourcelist[i];
+ std::string name = i.getNode()->getKey();
if(m_name_to_id.find(name) == NULL)
continue;
u32 id = m_name_to_id[name];
/*
Write image to file so that it can be inspected
*/
- /*driver->writeImageToFile(atlas_img,
- getTexturePath("main_atlas.png").c_str());*/
+ /*std::string atlaspath = porting::path_userdata
+ + DIR_DELIM + "generated_texture_atlas.png";
+ infostream<<"Removing and writing texture atlas for inspection to "
+ <<atlaspath<<std::endl;
+ fs::RecursiveDelete(atlaspath);
+ driver->writeImageToFile(atlas_img, atlaspath.c_str());*/
}
video::IImage* generate_image_from_scratch(std::string name,
- IrrlichtDevice *device)
+ IrrlichtDevice *device, SourceImageCache *sourcecache)
{
/*infostream<<"generate_image_from_scratch(): "
"\""<<name<<"\""<<std::endl;*/
/*infostream<<"generate_image_from_scratch(): Calling itself recursively"
" to get base image of \""<<name<<"\" = \""
<<base_image_name<<"\""<<std::endl;*/
- baseimg = generate_image_from_scratch(base_image_name, device);
+ baseimg = generate_image_from_scratch(base_image_name, device,
+ sourcecache);
}
/*
//infostream<<"last_part_of_name=\""<<last_part_of_name<<"\""<<std::endl;
// Generate image according to part of name
- if(generate_image(last_part_of_name, baseimg, device) == false)
+ if(!generate_image(last_part_of_name, baseimg, device, sourcecache))
{
infostream<<"generate_image_from_scratch(): "
"failed to generate \""<<last_part_of_name<<"\""
}
bool generate_image(std::string part_of_name, video::IImage *& baseimg,
- IrrlichtDevice *device)
+ IrrlichtDevice *device, SourceImageCache *sourcecache)
{
video::IVideoDriver* driver = device->getVideoDriver();
assert(driver);
// Stuff starting with [ are special commands
if(part_of_name[0] != '[')
{
- // A normal texture; load it from a file
- std::string path = getTexturePath(part_of_name.c_str());
- /*infostream<<"generate_image(): Loading path \""<<path
- <<"\""<<std::endl;*/
-
- video::IImage *image = driver->createImageFromFile(path.c_str());
+ video::IImage *image = sourcecache->getOrLoad(part_of_name, device);
if(image == NULL)
{
infostream<<"generate_image(): Could not load image \""
- <<part_of_name<<"\" from path \""<<path<<"\""
- <<" while building texture"<<std::endl;
+ <<part_of_name<<"\""<<" while building texture"<<std::endl;
//return false;
It is an image with a number of cracking stages
horizontally tiled.
*/
- video::IImage *img_crack = driver->createImageFromFile(
- getTexturePath("crack.png").c_str());
+ video::IImage *img_crack = sourcecache->getOrLoad("crack.png", device);
if(img_crack)
{
infostream<<"Adding \""<<filename
<<"\" to combined ("<<x<<","<<y<<")"
<<std::endl;
- video::IImage *img = driver->createImageFromFile(
- getTexturePath(filename.c_str()).c_str());
+ video::IImage *img = sourcecache->getOrLoad(filename, device);
if(img)
{
core::dimension2d<u32> dim = img->getDimension();
std::string path = getTexturePath(filename.c_str());
- infostream<<"generate_image(): Loading path \""<<path
+ infostream<<"generate_image(): Loading file \""<<filename
<<"\""<<std::endl;
- video::IImage *image = driver->createImageFromFile(path.c_str());
+ video::IImage *image = sourcecache->getOrLoad(filename, device);
if(image == NULL)
{
u32 b1 = stoi(sf.next(":"));
std::string filename = sf.next("");
- std::string path = getTexturePath(filename.c_str());
-
- infostream<<"generate_image(): Loading path \""<<path
+ infostream<<"generate_image(): Loading file \""<<filename
<<"\""<<std::endl;
- video::IImage *image = driver->createImageFromFile(path.c_str());
+ video::IImage *image = sourcecache->getOrLoad(filename, device);
if(image == NULL)
{
- infostream<<"generate_image(): Loading path \""
- <<path<<"\" failed"<<std::endl;
+ infostream<<"generate_image(): Loading file \""
+ <<filename<<"\" failed"<<std::endl;
}
else
{
core::dimension2d<u32> dim = image->getDimension();
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
+ // Blit
+ image->copyTo(baseimg);
+
+ image->drop();
+
for(u32 y=0; y<dim.Height; y++)
for(u32 x=0; x<dim.Width; x++)
{
- video::SColor c = image->getPixel(x,y);
+ video::SColor c = baseimg->getPixel(x,y);
u32 r = c.getRed();
u32 g = c.getGreen();
u32 b = c.getBlue();
if(!(r == r1 && g == g1 && b == b1))
continue;
c.setAlpha(0);
- image->setPixel(x,y,c);
+ baseimg->setPixel(x,y,c);
}
- // Blit
- image->copyTo(baseimg);
-
- image->drop();
}
}
/*
u32 b2 = stoi(sf.next(":"));
std::string filename = sf.next("");
- std::string path = getTexturePath(filename.c_str());
-
- infostream<<"generate_image(): Loading path \""<<path
+ infostream<<"generate_image(): Loading filename \""<<filename
<<"\""<<std::endl;
- video::IImage *image = driver->createImageFromFile(path.c_str());
+ video::IImage *image = sourcecache->getOrLoad(filename, device);
if(image == NULL)
{
- infostream<<"generate_image(): Loading path \""
- <<path<<"\" failed"<<std::endl;
+ infostream<<"generate_image(): Loading file \""
+ <<filename<<"\" failed"<<std::endl;
}
else
{
core::dimension2d<u32> dim = image->getDimension();
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
+
+ // Blit
+ image->copyTo(baseimg);
+
+ image->drop();
for(u32 y=0; y<dim.Height; y++)
for(u32 x=0; x<dim.Width; x++)
{
- video::SColor c = image->getPixel(x,y);
+ video::SColor c = baseimg->getPixel(x,y);
u32 r = c.getRed();
u32 g = c.getGreen();
u32 b = c.getBlue();
!(r == r2 && g == g2 && b == b2))
continue;
c.setAlpha(0);
- image->setPixel(x,y,c);
+ baseimg->setPixel(x,y,c);
}
- // Blit
- image->copyTo(baseimg);
-
- image->drop();
}
}
/*
std::string imagename_right = sf.next("{");
#if 1
- //TODO
+ // TODO: Create cube with different textures on different sides
if(driver->queryFeature(video::EVDF_RENDER_TO_TARGET) == false)
{
infostream<<"generate_image(): EVDF_RENDER_TO_TARGET"
" not supported. Creating fallback image"<<std::endl;
baseimg = generate_image_from_scratch(
- imagename_top, device);
+ imagename_top, device, sourcecache);
return true;
}
// Generate images for the faces of the cube
video::IImage *img_top = generate_image_from_scratch(
- imagename_top, device);
+ imagename_top, device, sourcecache);
video::IImage *img_left = generate_image_from_scratch(
- imagename_left, device);
+ imagename_left, device, sourcecache);
video::IImage *img_right = generate_image_from_scratch(
- imagename_right, device);
+ imagename_right, device, sourcecache);
assert(img_top && img_left && img_right);
- // TODO: Create textures from images
+ // Create textures from images
+ // TODO: Use them all
video::ITexture *texture_top = driver->addTexture(
(imagename_top + "__temp__").c_str(), img_top);
assert(texture_top);
// Unset render target
driver->setRenderTarget(0, true, true, 0);
- //TODO: Free textures of images
+ // Free textures of images
+ // TODO: When all are used, free them all
driver->removeTexture(texture_top);
// Create image of render target