From 01ae0daea501f47ec56a8368e530cb4176fc44cd Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Tue, 15 Nov 2011 13:13:18 +0200 Subject: [PATCH] Properly update textures in node definitions --- src/client.cpp | 23 +++- src/client.h | 13 +- src/game.cpp | 71 +++++----- src/nodedef.cpp | 7 +- src/nodedef.h | 3 + src/tile.cpp | 344 ++++++++++++++++++++++++++++++++---------------- src/tile.h | 32 +---- 7 files changed, 301 insertions(+), 192 deletions(-) diff --git a/src/client.cpp b/src/client.cpp index c89273a8..7093a519 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -222,16 +222,14 @@ Client::Client( // Build main texture atlas, now that the GameDef exists (that is, us) if(g_settings->getBool("enable_texture_atlas")) - tsrc->buildMainAtlas(this); + m_tsrc->buildMainAtlas(this); else infostream<<"Not building texture atlas."<updateTextures(tsrc); + // Update node textures + m_nodedef->updateTextures(m_tsrc); - // NOTE: This should be done only after getting possible dynamic - // game definitions from the server, or at least shut down and - // restarted when doing so + // Start threads after setting up content definitions m_mesh_update_thread.Start(); /* @@ -1568,17 +1566,28 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) rfile->drop(); continue; } - m_tsrc->insertImage(name, img); + m_tsrc->insertSourceImage(name, img); + img->drop(); rfile->drop(); } + + // Rebuild inherited images and recreate textures + m_tsrc->rebuildImagesAndTextures(); // Update texture atlas if(g_settings->getBool("enable_texture_atlas")) m_tsrc->buildMainAtlas(this); + // Update node textures + m_nodedef->updateTextures(m_tsrc); + // Resume threads m_mesh_update_thread.setRun(true); m_mesh_update_thread.Start(); + + ClientEvent event; + event.type = CE_TEXTURES_UPDATED; + m_client_event_queue.push_back(event); } else { diff --git a/src/client.h b/src/client.h index abbbed2f..148acc07 100644 --- a/src/client.h +++ b/src/client.h @@ -122,6 +122,7 @@ enum ClientEventType CE_PLAYER_DAMAGE, CE_PLAYER_FORCE_MOVE, CE_DEATHSCREEN, + CE_TEXTURES_UPDATED }; struct ClientEvent @@ -143,6 +144,8 @@ struct ClientEvent f32 camera_point_target_y; f32 camera_point_target_z; } deathscreen; + struct{ + } textures_updated; }; }; @@ -302,15 +305,11 @@ public: ClientEvent getClientEvent(); inline bool accessDenied() - { - return m_access_denied; - } + { return m_access_denied; } inline std::wstring accessDeniedReason() - { - return m_access_denied_reason; - } - + { return m_access_denied_reason; } + float getRTT(void); // IGameDef interface diff --git a/src/game.cpp b/src/game.cpp index fc87deb2..a8525a04 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -50,6 +50,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "content_mapnode.h" // For content_mapnode_init #include "tooldef.h" #include "content_mapnode.h" // Default nodes +#include "tile.h" // For TextureSource /* Setting this to 1 enables a special camera mode that forces @@ -519,7 +520,7 @@ void getPointedNode(Client *client, v3f player_position, } // for coords } -void update_skybox(video::IVideoDriver* driver, +void update_skybox(video::IVideoDriver* driver, ITextureSource *tsrc, scene::ISceneManager* smgr, scene::ISceneNode* &skybox, float brightness) { @@ -535,32 +536,32 @@ void update_skybox(video::IVideoDriver* driver, if(brightness >= 0.5) { skybox = smgr->addSkyBoxSceneNode( - driver->getTexture(getTexturePath("skybox2.png").c_str()), - driver->getTexture(getTexturePath("skybox3.png").c_str()), - driver->getTexture(getTexturePath("skybox1.png").c_str()), - driver->getTexture(getTexturePath("skybox1.png").c_str()), - driver->getTexture(getTexturePath("skybox1.png").c_str()), - driver->getTexture(getTexturePath("skybox1.png").c_str())); + tsrc->getTextureRaw("skybox2.png"), + tsrc->getTextureRaw("skybox3.png"), + tsrc->getTextureRaw("skybox1.png"), + tsrc->getTextureRaw("skybox1.png"), + tsrc->getTextureRaw("skybox1.png"), + tsrc->getTextureRaw("skybox1.png")); } else if(brightness >= 0.2) { skybox = smgr->addSkyBoxSceneNode( - driver->getTexture(getTexturePath("skybox2_dawn.png").c_str()), - driver->getTexture(getTexturePath("skybox3_dawn.png").c_str()), - driver->getTexture(getTexturePath("skybox1_dawn.png").c_str()), - driver->getTexture(getTexturePath("skybox1_dawn.png").c_str()), - driver->getTexture(getTexturePath("skybox1_dawn.png").c_str()), - driver->getTexture(getTexturePath("skybox1_dawn.png").c_str())); + tsrc->getTextureRaw("skybox2_dawn.png"), + tsrc->getTextureRaw("skybox3_dawn.png"), + tsrc->getTextureRaw("skybox1_dawn.png"), + tsrc->getTextureRaw("skybox1_dawn.png"), + tsrc->getTextureRaw("skybox1_dawn.png"), + tsrc->getTextureRaw("skybox1_dawn.png")); } else { skybox = smgr->addSkyBoxSceneNode( - driver->getTexture(getTexturePath("skybox2_night.png").c_str()), - driver->getTexture(getTexturePath("skybox3_night.png").c_str()), - driver->getTexture(getTexturePath("skybox1_night.png").c_str()), - driver->getTexture(getTexturePath("skybox1_night.png").c_str()), - driver->getTexture(getTexturePath("skybox1_night.png").c_str()), - driver->getTexture(getTexturePath("skybox1_night.png").c_str())); + tsrc->getTextureRaw("skybox2_night.png"), + tsrc->getTextureRaw("skybox3_night.png"), + tsrc->getTextureRaw("skybox1_night.png"), + tsrc->getTextureRaw("skybox1_night.png"), + tsrc->getTextureRaw("skybox1_night.png"), + tsrc->getTextureRaw("skybox1_night.png")); } } @@ -771,7 +772,7 @@ void the_game( */ float old_brightness = 1.0; scene::ISceneNode* skybox = NULL; - update_skybox(driver, smgr, skybox, 1.0); + update_skybox(driver, tsrc, smgr, skybox, 1.0); /* Create the camera node @@ -886,6 +887,8 @@ void the_game( // A test //throw con::PeerNotFoundException("lol"); + float brightness = 1.0; + core::list frametime_log; float nodig_delay_counter = 0.0; @@ -1537,6 +1540,10 @@ void the_game( player->setPosition(player->getPosition() + v3f(0,-BS,0)); camera.update(player, busytime, screensize);*/ } + else if(event.type == CE_TEXTURES_UPDATED) + { + update_skybox(driver, tsrc, smgr, skybox, brightness); + } } } @@ -1902,25 +1909,27 @@ void the_game( /* Calculate stuff for drawing */ - + + /* + Calculate general brightness + */ u32 daynight_ratio = client.getDayNightRatio(); - u8 l = decode_light((daynight_ratio * LIGHT_SUN) / 1000); + u8 light8 = decode_light((daynight_ratio * LIGHT_SUN) / 1000); + brightness = (float)light8/255.0; video::SColor bgcolor = video::SColor( 255, - bgcolor_bright.getRed() * l / 255, - bgcolor_bright.getGreen() * l / 255, - bgcolor_bright.getBlue() * l / 255); - /*skycolor.getRed() * l / 255, - skycolor.getGreen() * l / 255, - skycolor.getBlue() * l / 255);*/ - - float brightness = (float)l/255.0; + bgcolor_bright.getRed() * brightness, + bgcolor_bright.getGreen() * brightness, + bgcolor_bright.getBlue() * brightness); + /*skycolor.getRed() * brightness, + skycolor.getGreen() * brightness, + skycolor.getBlue() * brightness);*/ /* Update skybox */ if(fabs(brightness - old_brightness) > 0.01) - update_skybox(driver, smgr, skybox, brightness); + update_skybox(driver, tsrc, smgr, skybox, brightness); /* Update clouds diff --git a/src/nodedef.cpp b/src/nodedef.cpp index 7b723e95..d589c5ec 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -174,8 +174,13 @@ public: ContentFeatures *f = &m_content_features[i]; for(u16 j=0; j<6; j++) tsrc->updateAP(f->tiles[j].texture); - if(f->special_atlas) + if(f->special_atlas){ tsrc->updateAP(*(f->special_atlas)); + if(f->special_material) + f->special_material->setTexture(0, f->special_atlas->atlas); + if(f->special_material2) + f->special_material2->setTexture(0, f->special_atlas->atlas); + } } #endif } diff --git a/src/nodedef.h b/src/nodedef.h index 5aba69c4..0430621e 100644 --- a/src/nodedef.h +++ b/src/nodedef.h @@ -122,6 +122,9 @@ struct ContentFeatures // Special irrlicht material, used sometimes video::SMaterial *special_material; video::SMaterial *special_material2; + // Currently used for fetching liquid texture coordinates + // - This is also updated to the above two (if they are non-NULL) + // when textures are updated AtlasPointer *special_atlas; #endif diff --git a/src/tile.cpp b/src/tile.cpp index 8ab92d10..b0e1fbf5 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -145,6 +145,95 @@ std::string getTexturePath(const std::string &filename) 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) + { + assert(img); + core::map::Node *n; + n = m_images.find(name); + if(n){ + video::IImage *oldimg = n->getValue(); + if(oldimg) + oldimg->drop(); + } + img->grab(); + m_images[name] = img; + } + video::IImage* get(const std::string &name) + { + core::map::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::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 \"" + <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 m_images; +}; + /* TextureSource */ @@ -209,9 +298,7 @@ public: */ u32 getTextureIdDirect(const std::string &name); - /* - Finds out the name of a cached texture. - */ + // Finds out the name of a cached texture. std::string getTextureName(u32 id); /* @@ -236,29 +323,25 @@ public: return ap.atlas; } - /* - Update new texture pointer and texture coordinates to an - AtlasPointer based on it's texture id - */ + // 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. - */ + // Processes queued texture requests from other threads. + // Shall be called from the main thread. void processQueue(); - /* - Build the main texture atlas which contains most of the - textures. - */ - void buildMainAtlas(class IGameDef *gamedef); + // 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); - /* - Insert an image into the cache without touching the filesystem. - */ - void insertImage(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: @@ -267,6 +350,10 @@ private: // 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 m_atlaspointer_cache; @@ -376,7 +463,7 @@ void make_progressbar(float value, video::IImage *image); 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 @@ -385,7 +472,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg, 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 @@ -525,7 +612,7 @@ u32 TextureSource::getTextureIdDirect(const std::string &name) //infostream<<"last_part_of_name=\""<getValue(); reuse_old_id = true; + infostream<<"TextureSource::buildMainAtlas(): " + <<"Replacing old AtlasPointer"<writeImageToFile(atlas_img, atlaspath.c_str());*/ } -void TextureSource::insertImage(const std::string &name, video::IImage *img) -{ - infostream<<"TextureSource::insertImage(): name="<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::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 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; -} - video::IImage* generate_image_from_scratch(std::string name, - IrrlichtDevice *device) + IrrlichtDevice *device, SourceImageCache *sourcecache) { /*infostream<<"generate_image_from_scratch(): " "\""<getVideoDriver(); assert(driver); @@ -983,18 +1105,12 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg, // 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 \""<createImageFromFile(path.c_str()); + video::IImage *image = sourcecache->getOrLoad(part_of_name, device); if(image == NULL) { infostream<<"generate_image(): Could not load image \"" - <createImageFromFile( - getTexturePath("crack.png").c_str()); + video::IImage *img_crack = sourcecache->getOrLoad("crack.png", device); if(img_crack) { @@ -1186,8 +1301,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg, infostream<<"Adding \""<createImageFromFile( - getTexturePath(filename.c_str()).c_str()); + video::IImage *img = sourcecache->getOrLoad(filename, device); if(img) { core::dimension2d dim = img->getDimension(); @@ -1248,10 +1362,10 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg, std::string path = getTexturePath(filename.c_str()); - infostream<<"generate_image(): Loading path \""<createImageFromFile(path.c_str()); + video::IImage *image = sourcecache->getOrLoad(filename, device); if(image == NULL) { @@ -1297,17 +1411,15 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg, u32 b1 = stoi(sf.next(":")); std::string filename = sf.next(""); - std::string path = getTexturePath(filename.c_str()); - - infostream<<"generate_image(): Loading path \""<createImageFromFile(path.c_str()); + video::IImage *image = sourcecache->getOrLoad(filename, device); if(image == NULL) { - infostream<<"generate_image(): Loading path \"" - <createImageFromFile(path.c_str()); + video::IImage *image = sourcecache->getOrLoad(filename, device); if(image == NULL) { - infostream<<"generate_image(): Loading path \"" - <queryFeature(video::EVDF_RENDER_TO_TARGET) == false) { infostream<<"generate_image(): EVDF_RENDER_TO_TARGET" " not supported. Creating fallback image"<addTexture( (imagename_top + "__temp__").c_str(), img_top); assert(texture_top); @@ -1515,7 +1626,8 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg, // 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 diff --git a/src/tile.h b/src/tile.h index 17ba74e3..23849ca1 100644 --- a/src/tile.h +++ b/src/tile.h @@ -93,34 +93,6 @@ struct AtlasPointer float y1(){ return pos.Y + size.Y; } }; -/* - An internal variant of the former with more data. -*/ -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_) - { - } -}; - /* TextureSource creates and caches textures. */ @@ -157,9 +129,9 @@ public: virtual void updateAP(AtlasPointer &ap){}; virtual void processQueue()=0; + virtual void insertSourceImage(const std::string &name, video::IImage *img)=0; + virtual void rebuildImagesAndTextures()=0; virtual void buildMainAtlas(class IGameDef *gamedef)=0; - // img is eaten, do not drop it - virtual void insertImage(const std::string &name, video::IImage *img)=0; }; IWritableTextureSource* createTextureSource(IrrlichtDevice *device); -- 2.30.2