mirror of
https://github.com/minetest/minetest.git
synced 2024-11-27 10:03:45 +01:00
Source image tracking in tile generation (#12514)
This commit is contained in:
parent
2a8becd650
commit
75e6cc190a
@ -552,8 +552,6 @@ private:
|
|||||||
std::vector<std::string> m_remote_media_servers;
|
std::vector<std::string> m_remote_media_servers;
|
||||||
// Media downloader, only exists during init
|
// Media downloader, only exists during init
|
||||||
ClientMediaDownloader *m_media_downloader;
|
ClientMediaDownloader *m_media_downloader;
|
||||||
// Set of media filenames pushed by server at runtime
|
|
||||||
std::unordered_set<std::string> m_media_pushed_files;
|
|
||||||
// Pending downloads of dynamic media (key: token)
|
// Pending downloads of dynamic media (key: token)
|
||||||
std::vector<std::pair<u32, std::shared_ptr<SingleMediaDownloader>>> m_pending_media_downloads;
|
std::vector<std::pair<u32, std::shared_ptr<SingleMediaDownloader>>> m_pending_media_downloads;
|
||||||
|
|
||||||
|
@ -171,6 +171,7 @@ struct TextureInfo
|
|||||||
{
|
{
|
||||||
std::string name;
|
std::string name;
|
||||||
video::ITexture *texture;
|
video::ITexture *texture;
|
||||||
|
std::set<std::string> sourceImages;
|
||||||
|
|
||||||
TextureInfo(
|
TextureInfo(
|
||||||
const std::string &name_,
|
const std::string &name_,
|
||||||
@ -180,6 +181,17 @@ struct TextureInfo
|
|||||||
texture(texture_)
|
texture(texture_)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextureInfo(
|
||||||
|
const std::string &name_,
|
||||||
|
video::ITexture *texture_,
|
||||||
|
std::set<std::string> &sourceImages_
|
||||||
|
):
|
||||||
|
name(name_),
|
||||||
|
texture(texture_),
|
||||||
|
sourceImages(sourceImages_)
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -379,19 +391,26 @@ private:
|
|||||||
// This should be only accessed from the main thread
|
// This should be only accessed from the main thread
|
||||||
SourceImageCache m_sourcecache;
|
SourceImageCache m_sourcecache;
|
||||||
|
|
||||||
|
// Rebuild images and textures from the current set of source images
|
||||||
|
// Shall be called from the main thread.
|
||||||
|
// You ARE expected to be holding m_textureinfo_cache_mutex
|
||||||
|
void rebuildTexture(video::IVideoDriver *driver, TextureInfo &ti);
|
||||||
|
|
||||||
// Generate a texture
|
// Generate a texture
|
||||||
u32 generateTexture(const std::string &name);
|
u32 generateTexture(const std::string &name);
|
||||||
|
|
||||||
// Generate image based on a string like "stone.png" or "[crack:1:0".
|
// Generate image based on a string like "stone.png" or "[crack:1:0".
|
||||||
// if baseimg is NULL, it is created. Otherwise stuff is made on it.
|
// if baseimg is NULL, it is created. Otherwise stuff is made on it.
|
||||||
bool generateImagePart(std::string part_of_name, video::IImage *& baseimg);
|
// source_image_names is important to determine when to flush the image from a cache (dynamic media)
|
||||||
|
bool generateImagePart(std::string part_of_name, video::IImage *& baseimg, std::set<std::string> &source_image_names);
|
||||||
|
|
||||||
/*! Generates an image from a full string like
|
/*! Generates an image from a full string like
|
||||||
* "stone.png^mineral_coal.png^[crack:1:0".
|
* "stone.png^mineral_coal.png^[crack:1:0".
|
||||||
* Shall be called from the main thread.
|
* Shall be called from the main thread.
|
||||||
* The returned Image should be dropped.
|
* The returned Image should be dropped.
|
||||||
|
* source_image_names is important to determine when to flush the image from a cache (dynamic media)
|
||||||
*/
|
*/
|
||||||
video::IImage* generateImage(const std::string &name);
|
video::IImage* generateImage(const std::string &name, std::set<std::string> &source_image_names);
|
||||||
|
|
||||||
// Thread-safe cache of what source images are known (true = known)
|
// Thread-safe cache of what source images are known (true = known)
|
||||||
MutexedMap<std::string, bool> m_source_image_existence;
|
MutexedMap<std::string, bool> m_source_image_existence;
|
||||||
@ -592,7 +611,9 @@ u32 TextureSource::generateTexture(const std::string &name)
|
|||||||
video::IVideoDriver *driver = RenderingEngine::get_video_driver();
|
video::IVideoDriver *driver = RenderingEngine::get_video_driver();
|
||||||
sanity_check(driver);
|
sanity_check(driver);
|
||||||
|
|
||||||
video::IImage *img = generateImage(name);
|
// passed into texture info for dynamic media tracking
|
||||||
|
std::set<std::string> source_image_names;
|
||||||
|
video::IImage *img = generateImage(name, source_image_names);
|
||||||
|
|
||||||
video::ITexture *tex = NULL;
|
video::ITexture *tex = NULL;
|
||||||
|
|
||||||
@ -613,7 +634,7 @@ u32 TextureSource::generateTexture(const std::string &name)
|
|||||||
MutexAutoLock lock(m_textureinfo_cache_mutex);
|
MutexAutoLock lock(m_textureinfo_cache_mutex);
|
||||||
|
|
||||||
u32 id = m_textureinfo_cache.size();
|
u32 id = m_textureinfo_cache.size();
|
||||||
TextureInfo ti(name, tex);
|
TextureInfo ti(name, tex, source_image_names);
|
||||||
m_textureinfo_cache.push_back(ti);
|
m_textureinfo_cache.push_back(ti);
|
||||||
m_name_to_id[name] = id;
|
m_name_to_id[name] = id;
|
||||||
|
|
||||||
@ -677,7 +698,8 @@ Palette* TextureSource::getPalette(const std::string &name)
|
|||||||
auto it = m_palettes.find(name);
|
auto it = m_palettes.find(name);
|
||||||
if (it == m_palettes.end()) {
|
if (it == m_palettes.end()) {
|
||||||
// Create palette
|
// Create palette
|
||||||
video::IImage *img = generateImage(name);
|
std::set<std::string> source_image_names; // unused, sadly.
|
||||||
|
video::IImage *img = generateImage(name, source_image_names);
|
||||||
if (!img) {
|
if (!img) {
|
||||||
warningstream << "TextureSource::getPalette(): palette \"" << name
|
warningstream << "TextureSource::getPalette(): palette \"" << name
|
||||||
<< "\" could not be loaded." << std::endl;
|
<< "\" could not be loaded." << std::endl;
|
||||||
@ -749,6 +771,26 @@ void TextureSource::insertSourceImage(const std::string &name, video::IImage *im
|
|||||||
|
|
||||||
m_sourcecache.insert(name, img, true);
|
m_sourcecache.insert(name, img, true);
|
||||||
m_source_image_existence.set(name, true);
|
m_source_image_existence.set(name, true);
|
||||||
|
|
||||||
|
// now we need to check for any textures that need updating
|
||||||
|
MutexAutoLock lock(m_textureinfo_cache_mutex);
|
||||||
|
|
||||||
|
video::IVideoDriver *driver = RenderingEngine::get_video_driver();
|
||||||
|
sanity_check(driver);
|
||||||
|
|
||||||
|
// Recreate affected textures
|
||||||
|
u32 affected = 0;
|
||||||
|
for (TextureInfo &ti : m_textureinfo_cache) {
|
||||||
|
if (ti.name.empty())
|
||||||
|
continue; // Skip dummy entry
|
||||||
|
// If the source image was used, we need to rebuild this texture
|
||||||
|
if (ti.sourceImages.find(name) != ti.sourceImages.end()) {
|
||||||
|
rebuildTexture(driver, ti);
|
||||||
|
affected++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (affected > 0)
|
||||||
|
verbosestream << "TextureSource: inserting \"" << name << "\" caused rebuild of " << affected << " textures." << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextureSource::rebuildImagesAndTextures()
|
void TextureSource::rebuildImagesAndTextures()
|
||||||
@ -765,27 +807,38 @@ void TextureSource::rebuildImagesAndTextures()
|
|||||||
for (TextureInfo &ti : m_textureinfo_cache) {
|
for (TextureInfo &ti : m_textureinfo_cache) {
|
||||||
if (ti.name.empty())
|
if (ti.name.empty())
|
||||||
continue; // Skip dummy entry
|
continue; // Skip dummy entry
|
||||||
|
rebuildTexture(driver, ti);
|
||||||
video::IImage *img = generateImage(ti.name);
|
|
||||||
#if ENABLE_GLES
|
|
||||||
img = Align2Npot2(img, driver);
|
|
||||||
#endif
|
|
||||||
// Create texture from resulting image
|
|
||||||
video::ITexture *t = NULL;
|
|
||||||
if (img) {
|
|
||||||
t = driver->addTexture(ti.name.c_str(), img);
|
|
||||||
guiScalingCache(io::path(ti.name.c_str()), driver, img);
|
|
||||||
img->drop();
|
|
||||||
}
|
|
||||||
video::ITexture *t_old = ti.texture;
|
|
||||||
// Replace texture
|
|
||||||
ti.texture = t;
|
|
||||||
|
|
||||||
if (t_old)
|
|
||||||
m_texture_trash.push_back(t_old);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextureSource::rebuildTexture(video::IVideoDriver *driver, TextureInfo &ti)
|
||||||
|
{
|
||||||
|
if (ti.name.empty())
|
||||||
|
return; // this shouldn't happen, just a precaution
|
||||||
|
|
||||||
|
// replaces the previous sourceImages
|
||||||
|
// shouldn't really need to be done, but can't hurt
|
||||||
|
std::set<std::string> source_image_names;
|
||||||
|
video::IImage *img = generateImage(ti.name, source_image_names);
|
||||||
|
#if ENABLE_GLES
|
||||||
|
img = Align2Npot2(img, driver);
|
||||||
|
#endif
|
||||||
|
// Create texture from resulting image
|
||||||
|
video::ITexture *t = NULL;
|
||||||
|
if (img) {
|
||||||
|
t = driver->addTexture(ti.name.c_str(), img);
|
||||||
|
guiScalingCache(io::path(ti.name.c_str()), driver, img);
|
||||||
|
img->drop();
|
||||||
|
}
|
||||||
|
video::ITexture *t_old = ti.texture;
|
||||||
|
// Replace texture
|
||||||
|
ti.texture = t;
|
||||||
|
ti.sourceImages = source_image_names;
|
||||||
|
|
||||||
|
if (t_old)
|
||||||
|
m_texture_trash.push_back(t_old);
|
||||||
|
}
|
||||||
|
|
||||||
inline static void applyShadeFactor(video::SColor &color, u32 factor)
|
inline static void applyShadeFactor(video::SColor &color, u32 factor)
|
||||||
{
|
{
|
||||||
u32 f = core::clamp<u32>(factor, 0, 256);
|
u32 f = core::clamp<u32>(factor, 0, 256);
|
||||||
@ -901,7 +954,7 @@ static video::IImage *createInventoryCubeImage(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
video::IImage* TextureSource::generateImage(const std::string &name)
|
video::IImage* TextureSource::generateImage(const std::string &name, std::set<std::string> &source_image_names)
|
||||||
{
|
{
|
||||||
// Get the base image
|
// Get the base image
|
||||||
|
|
||||||
@ -954,7 +1007,7 @@ video::IImage* TextureSource::generateImage(const std::string &name)
|
|||||||
using a recursive call.
|
using a recursive call.
|
||||||
*/
|
*/
|
||||||
if (last_separator_pos != -1) {
|
if (last_separator_pos != -1) {
|
||||||
baseimg = generateImage(name.substr(0, last_separator_pos));
|
baseimg = generateImage(name.substr(0, last_separator_pos), source_image_names);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -972,7 +1025,7 @@ video::IImage* TextureSource::generateImage(const std::string &name)
|
|||||||
&& last_part_of_name[last_part_of_name.size() - 1] == paren_close) {
|
&& last_part_of_name[last_part_of_name.size() - 1] == paren_close) {
|
||||||
std::string name2 = last_part_of_name.substr(1,
|
std::string name2 = last_part_of_name.substr(1,
|
||||||
last_part_of_name.size() - 2);
|
last_part_of_name.size() - 2);
|
||||||
video::IImage *tmp = generateImage(name2);
|
video::IImage *tmp = generateImage(name2, source_image_names);
|
||||||
if (!tmp) {
|
if (!tmp) {
|
||||||
errorstream << "generateImage(): "
|
errorstream << "generateImage(): "
|
||||||
"Failed to generate \"" << name2 << "\""
|
"Failed to generate \"" << name2 << "\""
|
||||||
@ -987,7 +1040,7 @@ video::IImage* TextureSource::generateImage(const std::string &name)
|
|||||||
} else {
|
} else {
|
||||||
baseimg = tmp;
|
baseimg = tmp;
|
||||||
}
|
}
|
||||||
} else if (!generateImagePart(last_part_of_name, baseimg)) {
|
} else if (!generateImagePart(last_part_of_name, baseimg, source_image_names)) {
|
||||||
// Generate image according to part of name
|
// Generate image according to part of name
|
||||||
errorstream << "generateImage(): "
|
errorstream << "generateImage(): "
|
||||||
"Failed to generate \"" << last_part_of_name << "\""
|
"Failed to generate \"" << last_part_of_name << "\""
|
||||||
@ -1101,7 +1154,7 @@ void blitBaseImage(video::IImage* &src, video::IImage* &dst)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool TextureSource::generateImagePart(std::string part_of_name,
|
bool TextureSource::generateImagePart(std::string part_of_name,
|
||||||
video::IImage *& baseimg)
|
video::IImage *& baseimg, std::set<std::string> &source_image_names)
|
||||||
{
|
{
|
||||||
const char escape = '\\'; // same as in generateImage()
|
const char escape = '\\'; // same as in generateImage()
|
||||||
video::IVideoDriver *driver = RenderingEngine::get_video_driver();
|
video::IVideoDriver *driver = RenderingEngine::get_video_driver();
|
||||||
@ -1109,6 +1162,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
|
|
||||||
// Stuff starting with [ are special commands
|
// Stuff starting with [ are special commands
|
||||||
if (part_of_name.empty() || part_of_name[0] != '[') {
|
if (part_of_name.empty() || part_of_name[0] != '[') {
|
||||||
|
source_image_names.insert(part_of_name);
|
||||||
video::IImage *image = m_sourcecache.getOrLoad(part_of_name);
|
video::IImage *image = m_sourcecache.getOrLoad(part_of_name);
|
||||||
if (image == NULL) {
|
if (image == NULL) {
|
||||||
if (!part_of_name.empty()) {
|
if (!part_of_name.empty()) {
|
||||||
@ -1246,7 +1300,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
infostream<<"Adding \""<<filename
|
infostream<<"Adding \""<<filename
|
||||||
<<"\" to combined ("<<x<<","<<y<<")"
|
<<"\" to combined ("<<x<<","<<y<<")"
|
||||||
<<std::endl;
|
<<std::endl;
|
||||||
video::IImage *img = generateImage(filename);
|
video::IImage *img = generateImage(filename, source_image_names);
|
||||||
if (img) {
|
if (img) {
|
||||||
core::dimension2d<u32> dim = img->getDimension();
|
core::dimension2d<u32> dim = img->getDimension();
|
||||||
core::position2d<s32> pos_base(x, y);
|
core::position2d<s32> pos_base(x, y);
|
||||||
@ -1410,15 +1464,15 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
std::string imagename_right = sf.next("{");
|
std::string imagename_right = sf.next("{");
|
||||||
|
|
||||||
// Generate images for the faces of the cube
|
// Generate images for the faces of the cube
|
||||||
video::IImage *img_top = generateImage(imagename_top);
|
video::IImage *img_top = generateImage(imagename_top, source_image_names);
|
||||||
video::IImage *img_left = generateImage(imagename_left);
|
video::IImage *img_left = generateImage(imagename_left, source_image_names);
|
||||||
video::IImage *img_right = generateImage(imagename_right);
|
video::IImage *img_right = generateImage(imagename_right, source_image_names);
|
||||||
|
|
||||||
if (img_top == NULL || img_left == NULL || img_right == NULL) {
|
if (img_top == NULL || img_left == NULL || img_right == NULL) {
|
||||||
errorstream << "generateImagePart(): Failed to create textures"
|
errorstream << "generateImagePart(): Failed to create textures"
|
||||||
<< " for inventorycube \"" << part_of_name << "\""
|
<< " for inventorycube \"" << part_of_name << "\""
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
baseimg = generateImage(imagename_top);
|
baseimg = generateImage(imagename_top, source_image_names);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1444,7 +1498,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
|
|
||||||
if (baseimg == NULL)
|
if (baseimg == NULL)
|
||||||
baseimg = driver->createImage(video::ECF_A8R8G8B8, v2u32(16,16));
|
baseimg = driver->createImage(video::ECF_A8R8G8B8, v2u32(16,16));
|
||||||
video::IImage *img = generateImage(filename);
|
video::IImage *img = generateImage(filename, source_image_names);
|
||||||
if (img)
|
if (img)
|
||||||
{
|
{
|
||||||
core::dimension2d<u32> dim = img->getDimension();
|
core::dimension2d<u32> dim = img->getDimension();
|
||||||
@ -1526,7 +1580,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
sf.next(":");
|
sf.next(":");
|
||||||
std::string filename = unescape_string(sf.next_esc(":", escape), escape);
|
std::string filename = unescape_string(sf.next_esc(":", escape), escape);
|
||||||
|
|
||||||
video::IImage *img = generateImage(filename);
|
video::IImage *img = generateImage(filename, source_image_names);
|
||||||
if (img) {
|
if (img) {
|
||||||
apply_mask(img, baseimg, v2s32(0, 0), v2s32(0, 0),
|
apply_mask(img, baseimg, v2s32(0, 0), v2s32(0, 0),
|
||||||
img->getDimension());
|
img->getDimension());
|
||||||
|
@ -1592,14 +1592,6 @@ void Client::handleCommand_MediaPush(NetworkPacket *pkt)
|
|||||||
verbosestream << "with " << filedata.size() << " bytes ";
|
verbosestream << "with " << filedata.size() << " bytes ";
|
||||||
verbosestream << "(cached=" << cached << ")" << std::endl;
|
verbosestream << "(cached=" << cached << ")" << std::endl;
|
||||||
|
|
||||||
if (m_media_pushed_files.count(filename) != 0) {
|
|
||||||
// Ignore (but acknowledge). Previously this was for sync purposes,
|
|
||||||
// but even in new versions media cannot be replaced at runtime.
|
|
||||||
if (m_proto_ver >= 40)
|
|
||||||
sendHaveMedia({ token });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!filedata.empty()) {
|
if (!filedata.empty()) {
|
||||||
// LEGACY CODEPATH
|
// LEGACY CODEPATH
|
||||||
// Compute and check checksum of data
|
// Compute and check checksum of data
|
||||||
@ -1618,7 +1610,6 @@ void Client::handleCommand_MediaPush(NetworkPacket *pkt)
|
|||||||
|
|
||||||
// Actually load media
|
// Actually load media
|
||||||
loadMedia(filedata, filename, true);
|
loadMedia(filedata, filename, true);
|
||||||
m_media_pushed_files.insert(filename);
|
|
||||||
|
|
||||||
// Cache file for the next time when this client joins the same server
|
// Cache file for the next time when this client joins the same server
|
||||||
if (cached)
|
if (cached)
|
||||||
@ -1626,8 +1617,6 @@ void Client::handleCommand_MediaPush(NetworkPacket *pkt)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_media_pushed_files.insert(filename);
|
|
||||||
|
|
||||||
// create a downloader for this file
|
// create a downloader for this file
|
||||||
auto downloader(std::make_shared<SingleMediaDownloader>(cached));
|
auto downloader(std::make_shared<SingleMediaDownloader>(cached));
|
||||||
m_pending_media_downloads.emplace_back(token, downloader);
|
m_pending_media_downloads.emplace_back(token, downloader);
|
||||||
|
Loading…
Reference in New Issue
Block a user