From 8161ab573fd6f8a45b3986278ce7fc1596140526 Mon Sep 17 00:00:00 2001 From: Kahrl Date: Mon, 24 Jun 2013 04:17:50 +0200 Subject: Remove texture atlas / AtlasPointer, rename getTextureRaw to getTexture --- src/tile.cpp | 478 +++++++++-------------------------------------------------- 1 file changed, 66 insertions(+), 412 deletions(-) (limited to 'src/tile.cpp') diff --git a/src/tile.cpp b/src/tile.cpp index f176d1549..da286fda9 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -25,8 +25,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mesh.h" #include #include "log.h" -#include "mapnode.h" // For texture atlas making -#include "nodedef.h" // For texture atlas making #include "gamedef.h" #include "util/string.h" #include "util/container.h" @@ -165,31 +163,23 @@ std::string getTexturePath(const std::string &filename) } /* - An internal variant of AtlasPointer with more data. - (well, more like a wrapper) + Stores internal information about a texture. */ -struct SourceAtlasPointer +struct TextureInfo { 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; + video::ITexture *texture; + video::IImage *img; // The source image - SourceAtlasPointer( + TextureInfo( const std::string &name_, - AtlasPointer a_=AtlasPointer(0, NULL), - video::IImage *atlas_img_=NULL, - v2s32 intpos_=v2s32(0,0), - v2u32 intsize_=v2u32(0,0) + video::ITexture *texture_=NULL, + video::IImage *img_=NULL ): name(name_), - a(a_), - atlas_img(atlas_img_), - intpos(intpos_), - intsize(intsize_) + texture(texture_), + img(img_) { } }; @@ -307,7 +297,7 @@ public: 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. + "stone.png^mineral_coal.png". - Now getNodeTile() stumbles upon a node which uses texture id 1, and determines that MATERIAL_FLAG_CRACK must be applied to the tile @@ -315,7 +305,7 @@ public: has received the current crack level 0 from the client. 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"). + getTextureId("stone.png^mineral_coal.png^crack0"). */ @@ -354,25 +344,9 @@ public: 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 + m_forcesingle_suffix); - return ap.atlas; - } + video::ITexture* getTexture(u32 id); - // Gets a separate texture atlas pointer - AtlasPointer getTextureRawAP(const AtlasPointer &ap) - { - return getTexture(getTextureName(ap.id) + m_forcesingle_suffix); - } + video::ITexture* getTexture(const std::string &name, u32 *id); // Returns a pointer to the irrlicht device virtual IrrlichtDevice* getDevice() @@ -380,10 +354,6 @@ public: return m_device; } - // Update new texture pointer and texture coordinates to an - // AtlasPointer based on it's texture id - void updateAP(AtlasPointer &ap); - bool isKnownSourceImage(const std::string &name) { bool is_known = false; @@ -407,10 +377,6 @@ public: // 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: @@ -428,17 +394,12 @@ private: // A texture id is index in this array. // The first position contains a NULL texture. - std::vector m_atlaspointer_cache; + std::vector m_textureinfo_cache; // Maps a texture name to an index in the former. std::map m_name_to_id; // The two former containers are behind this mutex - JMutex m_atlaspointer_cache_mutex; + JMutex m_textureinfo_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; - std::string m_forcesingle_suffix; - // Queued texture fetches (to be processed by the main thread) RequestQueue m_get_texture_queue; @@ -453,18 +414,16 @@ IWritableTextureSource* createTextureSource(IrrlichtDevice *device) } TextureSource::TextureSource(IrrlichtDevice *device): - m_device(device), - m_main_atlas_image(NULL), - m_main_atlas_texture(NULL) + m_device(device) { assert(m_device); - m_atlaspointer_cache_mutex.Init(); + m_textureinfo_cache_mutex.Init(); m_main_thread = get_current_thread_id(); - // Add a NULL AtlasPointer as the first index, named "" - m_atlaspointer_cache.push_back(SourceAtlasPointer("")); + // Add a NULL TextureInfo as the first index, named "" + m_textureinfo_cache.push_back(TextureInfo("")); m_name_to_id[""] = 0; } @@ -474,21 +433,19 @@ TextureSource::~TextureSource() unsigned int textures_before = driver->getTextureCount(); - for (std::vector::iterator iter = - m_atlaspointer_cache.begin(); iter != m_atlaspointer_cache.end(); - iter++) + for (std::vector::iterator iter = + m_textureinfo_cache.begin(); + iter != m_textureinfo_cache.end(); iter++) { - video::ITexture *t = driver->getTexture(iter->name.c_str()); - //cleanup texture - if (t) - driver->removeTexture(t); + if (iter->texture) + driver->removeTexture(iter->texture); //cleanup source image - if (iter->atlas_img) - iter->atlas_img->drop(); + if (iter->img) + iter->img->drop(); } - m_atlaspointer_cache.clear(); + m_textureinfo_cache.clear(); for (std::list::iterator iter = m_texture_trash.begin(); iter != m_texture_trash.end(); @@ -512,7 +469,7 @@ u32 TextureSource::getTextureId(const std::string &name) /* See if texture already exists */ - JMutexAutoLock lock(m_atlaspointer_cache_mutex); + JMutexAutoLock lock(m_textureinfo_cache_mutex); std::map::iterator n; n = m_name_to_id.find(name); if(n != m_name_to_id.end()) @@ -591,8 +548,6 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg, /* Generates an image from a full string like "stone.png^mineral_coal.png^[crack0". - - This is used by buildMainAtlas(). */ video::IImage* generate_image_from_scratch(std::string name, IrrlichtDevice *device, SourceImageCache *sourcecache); @@ -625,7 +580,7 @@ u32 TextureSource::getTextureIdDirect(const std::string &name) See if texture already exists */ { - JMutexAutoLock lock(m_atlaspointer_cache_mutex); + JMutexAutoLock lock(m_textureinfo_cache_mutex); std::map::iterator n; n = m_name_to_id.find(name); @@ -693,13 +648,11 @@ u32 TextureSource::getTextureIdDirect(const std::string &name) // If a base image was found, copy it to baseimg if(base_image_id != 0) { - JMutexAutoLock lock(m_atlaspointer_cache_mutex); - - SourceAtlasPointer ap = m_atlaspointer_cache[base_image_id]; + JMutexAutoLock lock(m_textureinfo_cache_mutex); - video::IImage *image = ap.atlas_img; + TextureInfo *ti = &m_textureinfo_cache[base_image_id]; - if(image == NULL) + if(ti->img == NULL) { infostream<<"getTextureIdDirect(): WARNING: NULL image in " <<"cache: \""< dim = ap.intsize; + core::dimension2d dim = ti->img->getDimension(); baseimg = driver->createImage(video::ECF_A8R8G8B8, dim); - core::position2d pos_to(0,0); - core::position2d pos_from = ap.intpos; - - image->copyTo( + ti->img->copyTo( baseimg, // target v2s32(0,0), // position in target - core::rect(pos_from, dim) // from + core::rect(v2s32(0,0), dim) // from ); /*infostream<<"getTextureIdDirect(): Loaded \"" @@ -759,19 +709,11 @@ u32 TextureSource::getTextureIdDirect(const std::string &name) Add texture to caches (add NULL textures too) */ - JMutexAutoLock lock(m_atlaspointer_cache_mutex); + JMutexAutoLock lock(m_textureinfo_cache_mutex); - u32 id = m_atlaspointer_cache.size(); - AtlasPointer ap(id); - ap.atlas = t; - ap.pos = v2f(0,0); - ap.size = v2f(1,1); - ap.tiled = 0; - core::dimension2d baseimg_dim(0,0); - if(baseimg) - baseimg_dim = baseimg->getDimension(); - SourceAtlasPointer nap(name, ap, baseimg, v2s32(0,0), baseimg_dim); - m_atlaspointer_cache.push_back(nap); + u32 id = m_textureinfo_cache.size(); + TextureInfo ti(name, t, baseimg); + m_textureinfo_cache.push_back(ti); m_name_to_id[name] = id; /*infostream<<"getTextureIdDirect(): " @@ -782,34 +724,36 @@ u32 TextureSource::getTextureIdDirect(const std::string &name) std::string TextureSource::getTextureName(u32 id) { - JMutexAutoLock lock(m_atlaspointer_cache_mutex); + JMutexAutoLock lock(m_textureinfo_cache_mutex); - if(id >= m_atlaspointer_cache.size()) + if(id >= m_textureinfo_cache.size()) { errorstream<<"TextureSource::getTextureName(): id="<= m_atlaspointer_cache.size()=" - <= m_textureinfo_cache.size()=" + <= m_atlaspointer_cache.size()) - return AtlasPointer(0, NULL); - - return m_atlaspointer_cache[id].a; + if(id >= m_textureinfo_cache.size()) + return NULL; + + return m_textureinfo_cache[id].texture; } -void TextureSource::updateAP(AtlasPointer &ap) +video::ITexture* TextureSource::getTexture(const std::string &name, u32 *id) { - AtlasPointer ap2 = getTexture(ap.id); - ap = ap2; + u32 actual_id = getTextureId(name); + if(id){ + *id = actual_id; + } + return getTexture(actual_id); } void TextureSource::processQueue() @@ -849,299 +793,29 @@ void TextureSource::insertSourceImage(const std::string &name, video::IImage *im 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();*/ + JMutexAutoLock lock(m_textureinfo_cache_mutex); video::IVideoDriver* driver = m_device->getVideoDriver(); - - // Remove source images from textures to disable inheriting textures - // from existing textures - /*for(u32 i=0; iatlas_img->drop(); - sap->atlas_img = NULL; - }*/ - + // Recreate textures - for(u32 i=0; iname, m_device, &m_sourcecache); + generate_image_from_scratch(ti->name, m_device, &m_sourcecache); // Create texture from resulting image video::ITexture *t = NULL; if(img) - t = driver->addTexture(sap->name.c_str(), img); - video::ITexture *t_old = sap->a.atlas; + t = driver->addTexture(ti->name.c_str(), img); + video::ITexture *t_old = ti->texture; // 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(); + ti->texture = t; + ti->img = img; if (t_old != 0) m_texture_trash.push_back(t_old); } } -void TextureSource::buildMainAtlas(class IGameDef *gamedef) -{ - assert(gamedef->tsrc() == this); - INodeDefManager *ndef = gamedef->ndef(); - - infostream<<"TextureSource::buildMainAtlas()"<getVideoDriver(); - assert(driver); - - JMutexAutoLock lock(m_atlaspointer_cache_mutex); - - // Create an image of the right size - core::dimension2d max_dim = driver->getMaxTextureSize(); - core::dimension2d atlas_dim(2048,2048); - atlas_dim.Width = MYMIN(atlas_dim.Width, max_dim.Width); - atlas_dim.Height = MYMIN(atlas_dim.Height, max_dim.Height); - video::IImage *atlas_img = - driver->createImage(video::ECF_A8R8G8B8, atlas_dim); - //assert(atlas_img); - if(atlas_img == NULL) - { - errorstream<<"TextureSource::buildMainAtlas(): Failed to create atlas " - "image; not building texture atlas."< sourcelist; - - for(u16 j=0; jget(j); - for(u32 i=0; i<6; i++) - { - std::string name = f.tiledef[i].name; - sourcelist.insert(name); - } - } - - infostream<<"Creating texture atlas out of textures: "; - for(std::set::iterator - i = sourcelist.begin(); - i != sourcelist.end(); ++i) - { - std::string name = *i; - infostream<<"\""< pos_in_atlas(0,0); - - pos_in_atlas.X = column_padding; - pos_in_atlas.Y = padding; - - for(std::set::iterator - i = sourcelist.begin(); - i != sourcelist.end(); ++i) - { - std::string name = *i; - - // Generate image by name - video::IImage *img2 = generate_image_from_scratch(name, m_device, - &m_sourcecache); - if(img2 == NULL) - { - errorstream<<"TextureSource::buildMainAtlas(): " - <<"Couldn't generate image \""< dim = img2->getDimension(); - - // Don't add to atlas if image is too large - core::dimension2d max_size_in_atlas(64,64); - if(dim.Width > max_size_in_atlas.Width - || dim.Height > max_size_in_atlas.Height) - { - infostream<<"TextureSource::buildMainAtlas(): Not adding " - <<"\""< atlas_dim.Height) - { - if(pos_in_atlas.X > (s32)atlas_dim.Width - column_width - column_padding){ - errorstream<<"TextureSource::buildMainAtlas(): " - <<"Atlas is full, not adding more textures." - < 16) // Limit to 16 (more gives no benefit) - xwise_tiling = 16; - for(u32 j=0; jcopyToWithAlpha(atlas_img, - pos_in_atlas + v2s32(j*dim.Width,0), - core::rect(v2s32(0,0), dim), - video::SColor(255,255,255,255), - NULL);*/ - img2->copyTo(atlas_img, - pos_in_atlas + v2s32(j*dim.Width,0), - core::rect(v2s32(0,0), dim), - NULL); - } - - // Copy the borders a few times to disallow texture bleeding - for(u32 side=0; side<2; side++) // top and bottom - for(s32 y0=0; y0getPixel(x, src_y); - atlas_img->setPixel(x,dst_y,c); - } - - for(u32 side=0; side<2; side++) // left and right - for(s32 x0=0; x0getPixel(src_x, src_y); - atlas_img->setPixel(dst_x,dst_y,c); - } - - img2->drop(); - - /* - Add texture to caches - */ - - bool reuse_old_id = false; - u32 id = m_atlaspointer_cache.size(); - // Check old id without fetching a texture - std::map::iterator n; - n = m_name_to_id.find(name); - // If it exists, we will replace the old definition - if(n != m_name_to_id.end()){ - id = n->second; - reuse_old_id = true; - /*infostream<<"TextureSource::buildMainAtlas(): " - <<"Replacing old AtlasPointer"<addTexture("__main_atlas__", atlas_img); - assert(t); - - /* - Second pass: set texture pointer in generated AtlasPointers - */ - for(std::set::iterator - i = sourcelist.begin(); - i != sourcelist.end(); ++i) - { - std::string name = *i; - if(m_name_to_id.find(name) == m_name_to_id.end()) - continue; - u32 id = m_name_to_id[name]; - //infostream<<"id of name "<writeImageToFile(atlas_img, atlaspath.c_str());*/ - - m_forcesingle_suffix = "^[forcesingle"; -} - video::IImage* generate_image_from_scratch(std::string name, IrrlichtDevice *device, SourceImageCache *sourcecache) { @@ -1285,31 +959,11 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg, <<"modification \""< dim(1,1); - baseimg = driver->createImage(video::ECF_A8R8G8B8, dim); - assert(baseimg); - baseimg->setPixel(0,0, video::SColor(255,myrand()%256, - myrand()%256,myrand()%256)); - } - } /* [crackN Adds a cracking texture */ - else if(part_of_name.substr(0,6) == "[crack") + if(part_of_name.substr(0,6) == "[crack") { if(baseimg == NULL) { -- cgit v1.2.3