Refactor texturepaths.cpp and SourceImageCache

This commit is contained in:
cx384 2024-03-17 15:04:40 +01:00 committed by sfan5
parent 6ac053bbaa
commit 673d2499e8
3 changed files with 80 additions and 128 deletions

View File

@ -75,13 +75,14 @@ void SourceImageCache::insert(const std::string &name, video::IImage *img, bool
toadd->grab();
m_images[name] = toadd;
}
video::IImage* SourceImageCache::get(const std::string &name)
{
std::map<std::string, video::IImage*>::iterator n;
n = m_images.find(name);
if (n != m_images.end())
return n->second;
return NULL;
return nullptr;
}
// Primarily fetches from cache, secondarily tries to read from filesystem
@ -96,12 +97,12 @@ video::IImage* SourceImageCache::getOrLoad(const std::string &name)
video::IVideoDriver *driver = RenderingEngine::get_video_driver();
std::string path = getTexturePath(name);
if (path.empty()) {
infostream<<"SourceImageCache::getOrLoad(): No path found for \""
<<name<<"\""<<std::endl;
return NULL;
infostream << "SourceImageCache::getOrLoad(): No path found for \""
<< name << "\"" << std::endl;
return nullptr;
}
infostream<<"SourceImageCache::getOrLoad(): Loading path \""<<path
<<"\""<<std::endl;
infostream << "SourceImageCache::getOrLoad(): Loading path \"" << path
<< "\"" << std::endl;
video::IImage *img = driver->createImageFromFile(path.c_str());
if (img){
@ -1970,6 +1971,6 @@ video::SColor ImageSource::getImageAverageColor(const video::IImage &image)
return c;
}
void ImageSource::insertImage(const std::string &name, video::IImage *img, bool prefer_local) {
void ImageSource::insertSourceImage(const std::string &name, video::IImage *img, bool prefer_local) {
m_sourcecache.insert(name, img, prefer_local);
}

View File

@ -23,10 +23,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <string>
#include "settings.h"
// This file is only for internal generation/modification of images.
// Use texturesource.h instead to handle textures.
// This file is only used for internal generation of images.
// Use texturesource.h to handle textures.
// A cache used for storing source images.
// (A "source image" is an unmodified image directly taken from the filesystem.)
// Does not contain modified images.
class SourceImageCache {
public:
~SourceImageCache();
@ -35,16 +37,13 @@ public:
video::IImage* get(const std::string &name);
// Primarily fetches from cache, secondarily tries to read from filesystem
// Primarily fetches from cache, secondarily tries to read from filesystem.
video::IImage *getOrLoad(const std::string &name);
private:
std::map<std::string, video::IImage*> m_images;
};
/*
* Generates and caches images.
* The image name defines the image by filename and texture modifiers.
*/
// Generates images using texture modifiers, and caches source images.
struct ImageSource {
/*! Generates an image from a full string like
* "stone.png^mineral_coal.png^[crack:1:0".
@ -53,8 +52,8 @@ struct ImageSource {
*/
video::IImage* generateImage(std::string_view name, std::set<std::string> &source_image_names);
// To add self made images.
void insertImage(const std::string &name, video::IImage *img, bool prefer_local);
// Insert a source image into the cache without touching the filesystem.
void insertSourceImage(const std::string &name, video::IImage *img, bool prefer_local);
// TODO should probably be moved elsewhere
static video::SColor getImageAverageColor(const video::IImage &image);
@ -69,9 +68,10 @@ struct ImageSource {
private:
// 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.
// source_image_names is important to determine when to flush the image from a cache (dynamic media)
bool generateImagePart(std::string_view part_of_name, video::IImage *& baseimg, std::set<std::string> &source_image_names);
// If baseimg is NULL, it is created. Otherwise stuff is made on it.
// source_image_names is important to determine when to flush the image from a cache (dynamic media).
bool generateImagePart(std::string_view part_of_name, video::IImage *& baseimg,
std::set<std::string> &source_image_names);
// Cached settings needed for making textures from meshes
bool m_setting_mipmap;

View File

@ -27,41 +27,18 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "texturepaths.h"
#include "imagesource.h"
/*
Stores internal information about a texture.
*/
// Stores internal information about a texture.
struct TextureInfo
{
std::string name;
video::ITexture *texture;
std::set<std::string> sourceImages;
video::ITexture *texture = nullptr;
TextureInfo(
const std::string &name_,
video::ITexture *texture_=NULL
):
name(name_),
texture(texture_)
{
}
TextureInfo(
const std::string &name_,
video::ITexture *texture_,
std::set<std::string> &&sourceImages_
):
name(name_),
texture(texture_),
sourceImages(std::move(sourceImages_))
{
}
// Stores source image names which ImageSource::generateImage used.
std::set<std::string> sourceImages{};
};
/*
TextureSource
*/
// TextureSource
class TextureSource : public IWritableTextureSource
{
public:
@ -150,7 +127,7 @@ public:
// Shall be called from the main thread.
void processQueue();
// Insert an image into the cache without touching the filesystem.
// Insert a source image into the cache without touching the filesystem.
// Shall be called from the main thread.
void insertSourceImage(const std::string &name, video::IImage *img);
@ -200,11 +177,8 @@ private:
// Maps image file names to loaded palettes.
std::unordered_map<std::string, Palette> m_palettes;
// Cached settings needed for making textures from meshes
bool m_setting_mipmap;
bool m_setting_trilinear_filter;
bool m_setting_bilinear_filter;
bool m_setting_anisotropic_filter;
// Cached from settings for making textures from meshes
bool mesh_filter_needed;
};
IWritableTextureSource *createTextureSource()
@ -217,16 +191,17 @@ TextureSource::TextureSource()
m_main_thread = std::this_thread::get_id();
// Add a NULL TextureInfo as the first index, named ""
m_textureinfo_cache.emplace_back("");
m_textureinfo_cache.emplace_back(TextureInfo{""});
m_name_to_id[""] = 0;
// Cache some settings
// Note: Since this is only done once, the game must be restarted
// for these settings to take effect
m_setting_mipmap = g_settings->getBool("mip_map");
m_setting_trilinear_filter = g_settings->getBool("trilinear_filter");
m_setting_bilinear_filter = g_settings->getBool("bilinear_filter");
m_setting_anisotropic_filter = g_settings->getBool("anisotropic_filter");
// for these settings to take effect.
mesh_filter_needed =
g_settings->getBool("mip_map") ||
g_settings->getBool("trilinear_filter") ||
g_settings->getBool("bilinear_filter") ||
g_settings->getBool("anisotropic_filter");
}
TextureSource::~TextureSource()
@ -236,45 +211,37 @@ TextureSource::~TextureSource()
unsigned int textures_before = driver->getTextureCount();
for (const auto &iter : m_textureinfo_cache) {
//cleanup texture
// cleanup texture
if (iter.texture)
driver->removeTexture(iter.texture);
}
m_textureinfo_cache.clear();
for (auto t : m_texture_trash) {
//cleanup trashed texture
// cleanup trashed texture
driver->removeTexture(t);
}
infostream << "~TextureSource() before cleanup: "<< textures_before
infostream << "~TextureSource() before cleanup: " << textures_before
<< " after: " << driver->getTextureCount() << std::endl;
}
u32 TextureSource::getTextureId(const std::string &name)
{
{
/*
See if texture already exists
*/
{ // See if texture already exists
MutexAutoLock lock(m_textureinfo_cache_mutex);
std::map<std::string, u32>::iterator n;
n = m_name_to_id.find(name);
auto n = m_name_to_id.find(name);
if (n != m_name_to_id.end())
{
return n->second;
}
}
/*
Get texture
*/
// Get texture
if (std::this_thread::get_id() == m_main_thread) {
return generateTexture(name);
}
infostream<<"getTextureId(): Queued: name=\""<<name<<"\""<<std::endl;
infostream << "getTextureId(): Queued: name=\"" << name << "\"" << std::endl;
// We're gonna ask the result to be put into here
static thread_local ResultQueue<std::string, u32, std::thread::id, u8> result_queue;
@ -302,34 +269,26 @@ u32 TextureSource::getTextureId(const std::string &name)
return 0;
}
/*
This method generates all the textures
*/
// This method generates all the textures
u32 TextureSource::generateTexture(const std::string &name)
{
// Empty name means texture 0
if (name.empty()) {
infostream<<"generateTexture(): name is empty"<<std::endl;
infostream << "generateTexture(): name is empty" << std::endl;
return 0;
}
{
/*
See if texture already exists
*/
{ // See if texture already exists
MutexAutoLock lock(m_textureinfo_cache_mutex);
auto n = m_name_to_id.find(name);
if (n != m_name_to_id.end()) {
if (n != m_name_to_id.end())
return n->second;
}
}
/*
Calling only allowed from main thread
*/
// Calling only allowed from main thread
if (std::this_thread::get_id() != m_main_thread) {
errorstream<<"TextureSource::generateTexture() "
"called not from main thread"<<std::endl;
errorstream << "TextureSource::generateTexture() "
"called not from main thread" << std::endl;
return 0;
}
@ -340,9 +299,9 @@ u32 TextureSource::generateTexture(const std::string &name)
std::set<std::string> source_image_names;
video::IImage *img = m_imagesource.generateImage(name, source_image_names);
video::ITexture *tex = NULL;
video::ITexture *tex = nullptr;
if (img != NULL) {
if (img) {
img = Align2Npot2(img, driver);
// Create texture from resulting image
tex = driver->addTexture(name.c_str(), img);
@ -350,14 +309,12 @@ u32 TextureSource::generateTexture(const std::string &name)
img->drop();
}
/*
Add texture to caches (add NULL textures too)
*/
// Add texture to caches (add NULL textures too)
MutexAutoLock lock(m_textureinfo_cache_mutex);
u32 id = m_textureinfo_cache.size();
TextureInfo ti(name, tex, std::move(source_image_names));
TextureInfo ti{name, tex, std::move(source_image_names)};
m_textureinfo_cache.emplace_back(std::move(ti));
m_name_to_id[name] = id;
@ -368,11 +325,10 @@ std::string TextureSource::getTextureName(u32 id)
{
MutexAutoLock lock(m_textureinfo_cache_mutex);
if (id >= m_textureinfo_cache.size())
{
errorstream<<"TextureSource::getTextureName(): id="<<id
<<" >= m_textureinfo_cache.size()="
<<m_textureinfo_cache.size()<<std::endl;
if (id >= m_textureinfo_cache.size()) {
errorstream << "TextureSource::getTextureName(): id=" << id
<< " >= m_textureinfo_cache.size()=" << m_textureinfo_cache.size()
<< std::endl;
return "";
}
@ -384,7 +340,7 @@ video::ITexture* TextureSource::getTexture(u32 id)
MutexAutoLock lock(m_textureinfo_cache_mutex);
if (id >= m_textureinfo_cache.size())
return NULL;
return nullptr;
return m_textureinfo_cache[id].texture;
}
@ -392,19 +348,16 @@ video::ITexture* TextureSource::getTexture(u32 id)
video::ITexture* TextureSource::getTexture(const std::string &name, u32 *id)
{
u32 actual_id = getTextureId(name);
if (id){
if (id)
*id = actual_id;
}
return getTexture(actual_id);
}
video::ITexture* TextureSource::getTextureForMesh(const std::string &name, u32 *id)
{
// Avoid duplicating texture if it won't actually change
const bool filter_needed =
m_setting_mipmap || m_setting_trilinear_filter ||
m_setting_bilinear_filter || m_setting_anisotropic_filter;
if (filter_needed && !name.empty())
if (mesh_filter_needed && !name.empty())
return getTexture(name + "^[applyfiltersformesh", id);
return getTexture(name, id);
}
@ -415,7 +368,7 @@ Palette* TextureSource::getPalette(const std::string &name)
sanity_check(std::this_thread::get_id() == m_main_thread);
if (name.empty())
return NULL;
return nullptr;
auto it = m_palettes.find(name);
if (it == m_palettes.end()) {
@ -425,7 +378,7 @@ Palette* TextureSource::getPalette(const std::string &name)
if (!img) {
warningstream << "TextureSource::getPalette(): palette \"" << name
<< "\" could not be loaded." << std::endl;
return NULL;
return nullptr;
}
Palette new_palette;
u32 w = img->getDimension().Width;
@ -433,7 +386,7 @@ Palette* TextureSource::getPalette(const std::string &name)
// Real area of the image
u32 area = h * w;
if (area == 0)
return NULL;
return nullptr;
if (area > 256) {
warningstream << "TextureSource::getPalette(): the specified"
<< " palette image \"" << name << "\" is larger than 256"
@ -462,17 +415,14 @@ Palette* TextureSource::getPalette(const std::string &name)
}
if (it != m_palettes.end())
return &((*it).second);
return NULL;
return nullptr;
}
void TextureSource::processQueue()
{
/*
Fetch textures
*/
// Fetch textures
// NOTE: process outstanding requests from all mesh generation threads
while (!m_get_texture_queue.empty())
{
while (!m_get_texture_queue.empty()) {
GetRequest<std::string, u32, std::thread::id, u8>
request = m_get_texture_queue.pop();
@ -484,7 +434,7 @@ void TextureSource::insertSourceImage(const std::string &name, video::IImage *im
{
sanity_check(std::this_thread::get_id() == m_main_thread);
m_imagesource.insertImage(name, img, true);
m_imagesource.insertSourceImage(name, img, true);
m_source_image_existence.set(name, true);
// now we need to check for any textures that need updating
@ -505,7 +455,8 @@ void TextureSource::insertSourceImage(const std::string &name, video::IImage *im
}
}
if (affected > 0)
verbosestream << "TextureSource: inserting \"" << name << "\" caused rebuild of " << affected << " textures." << std::endl;
verbosestream << "TextureSource: inserting \"" << name << "\" caused rebuild of "
<< affected << " textures." << std::endl;
}
void TextureSource::rebuildImagesAndTextures()
@ -516,7 +467,7 @@ void TextureSource::rebuildImagesAndTextures()
sanity_check(driver);
infostream << "TextureSource: recreating " << m_textureinfo_cache.size()
<< " textures" << std::endl;
<< " textures" << std::endl;
// Recreate textures
for (TextureInfo &ti : m_textureinfo_cache) {
@ -529,14 +480,15 @@ void TextureSource::rebuildImagesAndTextures()
void TextureSource::rebuildTexture(video::IVideoDriver *driver, TextureInfo &ti)
{
assert(!ti.name.empty());
sanity_check(std::this_thread::get_id() == m_main_thread);
// replaces the previous sourceImages
// shouldn't really need to be done, but can't hurt
// 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 = m_imagesource.generateImage(ti.name, source_image_names);
img = Align2Npot2(img, driver);
// Create texture from resulting image
video::ITexture *t = NULL;
video::ITexture *t = nullptr;
if (img) {
t = driver->addTexture(ti.name.c_str(), img);
guiScalingCache(io::path(ti.name.c_str()), driver, img);
@ -569,23 +521,22 @@ video::ITexture* TextureSource::getNormalTexture(const std::string &name)
}
return getTexture(fname_base);
}
return NULL;
return nullptr;
}
video::SColor TextureSource::getTextureAverageColor(const std::string &name)
{
video::IVideoDriver *driver = RenderingEngine::get_video_driver();
video::SColor c(0, 0, 0, 0);
video::ITexture *texture = getTexture(name);
if (!texture)
return c;
return {0, 0, 0, 0};
video::IImage *image = driver->createImage(texture,
core::position2d<s32>(0, 0),
texture->getOriginalSize());
if (!image)
return c;
return {0, 0, 0, 0};
c = ImageSource::getImageAverageColor(*image);
video::SColor c = ImageSource::getImageAverageColor(*image);
image->drop();
return c;
@ -604,7 +555,7 @@ video::ITexture *TextureSource::getShaderFlagsTexture(bool normalmap_present)
video::IVideoDriver *driver = RenderingEngine::get_video_driver();
video::IImage *flags_image = driver->createImage(
video::ECF_A8R8G8B8, core::dimension2d<u32>(1, 1));
sanity_check(flags_image != NULL);
sanity_check(flags_image);
video::SColor c(255, normalmap_present ? 255 : 0, 0, 0);
flags_image->setPixel(0, 0, c);
insertSourceImage(tname, flags_image);