Extend caching abilities to compressed textures. Also, improve the structure of cache directories to fit new needs.
This commit is contained in:
parent
ab824f0ac3
commit
af91b8b4ae
@ -68,6 +68,8 @@ PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer;
|
||||
PFNGLGETUNIFORMBLOCKINDEXPROC glGetUniformBlockIndex;
|
||||
PFNGLUNIFORMBLOCKBINDINGPROC glUniformBlockBinding;
|
||||
PFNGLBLENDCOLORPROC glBlendColor;
|
||||
PFNGLCOMPRESSEDTEXIMAGE2DPROC glCompressedTexImage2D;
|
||||
PFNGLGETCOMPRESSEDTEXIMAGEPROC glGetCompressedTexImage;
|
||||
#endif
|
||||
|
||||
static bool is_gl_init = false;
|
||||
@ -215,6 +217,8 @@ void initGL()
|
||||
glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC)IRR_OGL_LOAD_EXTENSION("glGetUniformBlockIndex");
|
||||
glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC)IRR_OGL_LOAD_EXTENSION("glUniformBlockBinding");
|
||||
glBlendColor = (PFNGLBLENDCOLORPROC)IRR_OGL_LOAD_EXTENSION("glBlendColor");
|
||||
glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)IRR_OGL_LOAD_EXTENSION("glCompressedTexImage2D");
|
||||
glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)IRR_OGL_LOAD_EXTENSION("glGetCompressedTexImage");
|
||||
#ifdef DEBUG
|
||||
glDebugMessageCallbackARB = (PFNGLDEBUGMESSAGECALLBACKARBPROC)IRR_OGL_LOAD_EXTENSION("glDebugMessageCallbackARB");
|
||||
#endif
|
||||
@ -303,17 +307,32 @@ GLuint getDepthTexture(irr::video::ITexture *tex)
|
||||
}
|
||||
|
||||
std::set<irr::video::ITexture *> AlreadyTransformedTexture;
|
||||
|
||||
void compressTexture(irr::video::ITexture *tex, bool srgb)
|
||||
{
|
||||
if (AlreadyTransformedTexture.find(tex) != AlreadyTransformedTexture.end())
|
||||
return;
|
||||
AlreadyTransformedTexture.insert(tex);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, getTextureGLuint(tex));
|
||||
|
||||
std::string cached_file;
|
||||
if (UserConfigParams::m_texture_compression)
|
||||
{
|
||||
// Try to retrieve the compressed texture in cache
|
||||
std::string tex_name = irr_driver->getTextureName(tex);
|
||||
if (!tex_name.empty()) {
|
||||
cached_file = file_manager->getTextureCacheLocation(tex_name) + ".gltz";
|
||||
if (!file_manager->fileIsNewer(tex_name, cached_file)) {
|
||||
if (loadCompressedTexture(cached_file))
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t w = tex->getSize().Width, h = tex->getSize().Height;
|
||||
char *data = new char[w * h * 4];
|
||||
memcpy(data, tex->lock(), w * h * 4);
|
||||
tex->unlock();
|
||||
glBindTexture(GL_TEXTURE_2D, getTextureGLuint(tex));
|
||||
unsigned internalFormat, Format;
|
||||
if (tex->hasAlpha())
|
||||
Format = GL_BGRA;
|
||||
@ -337,6 +356,84 @@ void compressTexture(irr::video::ITexture *tex, bool srgb)
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, w, h, 0, Format, GL_UNSIGNED_BYTE, (GLvoid *)data);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
delete[] data;
|
||||
|
||||
if (UserConfigParams::m_texture_compression && !cached_file.empty())
|
||||
{
|
||||
// Save the compressed texture in the cache for later use.
|
||||
saveCompressedTexture(cached_file);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Try to load a compressed texture from the given file name.
|
||||
* Data in the specified file need to have a specific format. See the
|
||||
* saveCompressedTexture() function for a description of the format.
|
||||
* \return true if the loading succeeded, false otherwise.
|
||||
* \see saveCompressedTexture
|
||||
*/
|
||||
bool loadCompressedTexture(const std::string& compressed_tex)
|
||||
{
|
||||
std::ifstream ifs(compressed_tex, std::ios::in | std::ios::binary);
|
||||
if (!ifs.is_open())
|
||||
return false;
|
||||
|
||||
int internal_format;
|
||||
int w, h;
|
||||
int size = -1;
|
||||
ifs.read((char*)&internal_format, sizeof(int));
|
||||
ifs.read((char*)&w, sizeof(int));
|
||||
ifs.read((char*)&h, sizeof(int));
|
||||
ifs.read((char*)&size, sizeof(int));
|
||||
|
||||
if (ifs.fail() || size == -1)
|
||||
return false;
|
||||
|
||||
char *data = new char[size];
|
||||
ifs.read(data, size);
|
||||
if (!ifs.fail())
|
||||
{
|
||||
glCompressedTexImage2D(GL_TEXTURE_2D, 0, internal_format,
|
||||
w, h, 0, size, (GLvoid*)data);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
delete[] data;
|
||||
ifs.close();
|
||||
return true;
|
||||
}
|
||||
delete[] data;
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Try to save the last texture sent to glTexImage2D in a file of the given
|
||||
* file name. This function should only be used for textures sent to
|
||||
* glTexImage2D with a compressed internal format as argument.<br>
|
||||
* \note The following format is used to save the compressed texture:<br>
|
||||
* <internal-format><width><height><size><data> <br>
|
||||
* The first four elements are integers and the last one is stored
|
||||
* on \c size bytes.
|
||||
* \see loadCompressedTexture
|
||||
*/
|
||||
void saveCompressedTexture(const std::string& compressed_tex)
|
||||
{
|
||||
int internal_format, width, height, size;
|
||||
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, (GLint *)&internal_format);
|
||||
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, (GLint *)&width);
|
||||
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, (GLint *)&height);
|
||||
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, (GLint *)&size);
|
||||
|
||||
char *data = new char[size];
|
||||
glGetCompressedTexImage(GL_TEXTURE_2D, 0, (GLvoid*)data);
|
||||
std::ofstream ofs(compressed_tex, std::ios::out | std::ios::binary);
|
||||
if (ofs.is_open())
|
||||
{
|
||||
ofs.write((char*)&internal_format, sizeof(int));
|
||||
ofs.write((char*)&width, sizeof(int));
|
||||
ofs.write((char*)&height, sizeof(int));
|
||||
ofs.write((char*)&size, sizeof(int));
|
||||
ofs.write(data, size);
|
||||
ofs.close();
|
||||
}
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
void setTexture(unsigned TextureUnit, GLuint TextureId, GLenum MagFilter, GLenum MinFilter, bool allowAF)
|
||||
|
@ -85,6 +85,8 @@ extern PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer;
|
||||
extern PFNGLGETUNIFORMBLOCKINDEXPROC glGetUniformBlockIndex;
|
||||
extern PFNGLUNIFORMBLOCKBINDINGPROC glUniformBlockBinding;
|
||||
extern PFNGLBLENDCOLORPROC glBlendColor;
|
||||
extern PFNGLCOMPRESSEDTEXIMAGE2DPROC glCompressedTexImage2D;
|
||||
extern PFNGLGETCOMPRESSEDTEXIMAGEPROC glGetCompressedTexImage;
|
||||
#ifdef DEBUG
|
||||
extern PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARB;
|
||||
#endif
|
||||
@ -160,6 +162,8 @@ GLint LoadProgram(Types ... args)
|
||||
GLuint getTextureGLuint(irr::video::ITexture *tex);
|
||||
GLuint getDepthTexture(irr::video::ITexture *tex);
|
||||
void compressTexture(irr::video::ITexture *tex, bool srgb);
|
||||
bool loadCompressedTexture(const std::string& compressed_tex);
|
||||
void saveCompressedTexture(const std::string& compressed_tex);
|
||||
void blitFBO(GLuint Src, GLuint Dst, size_t width, size_t height);
|
||||
|
||||
void draw2DImage(const irr::video::ITexture* texture, const irr::core::rect<s32>& destRect,
|
||||
|
@ -1245,7 +1245,8 @@ void IrrDriver::unsetTextureErrorMessage()
|
||||
* version for each of them and save them in the cache. Smaller textures are
|
||||
* generated only if they do not already exist or if their original version
|
||||
* is newer than the cached one.
|
||||
* \param dir Directory from where textures will be retrieve.
|
||||
* \param dir Directory from where textures will be retrieved.
|
||||
* Must end with '/'.
|
||||
* \return Directory where smaller textures were cached.
|
||||
*/
|
||||
std::string IrrDriver::generateSmallerTextures(const std::string& dir)
|
||||
@ -1263,7 +1264,7 @@ std::string IrrDriver::generateSmallerTextures(const std::string& dir)
|
||||
}
|
||||
} // for it in files
|
||||
|
||||
return file_manager->getCachedTexturesDir();
|
||||
return file_manager->getTextureCacheLocation(dir);
|
||||
} // generateSmallerTextures
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -1272,21 +1273,11 @@ std::string IrrDriver::generateSmallerTextures(const std::string& dir)
|
||||
* exist or if the original version is newer than the cached one.
|
||||
* \param filename File name of the original texture.
|
||||
* \return File name of the cached texture.
|
||||
*
|
||||
* \todo Regenerate the texture if the original version is newer than the
|
||||
* cached one.
|
||||
*/
|
||||
std::string IrrDriver::getSmallerTexture(const std::string& filename)
|
||||
{
|
||||
// Retrieve the filename of the cached texture
|
||||
std::string file = StringUtils::getBasename(filename);
|
||||
std::string parent_dir = StringUtils::getPath(filename);
|
||||
if (StringUtils::hasSuffix(parent_dir, "/"))
|
||||
parent_dir = parent_dir.substr(0, parent_dir.size() - 1);
|
||||
parent_dir = StringUtils::getBasename(parent_dir);
|
||||
std::string cached_file = file_manager->getCachedTexturesDir() + parent_dir + "/";
|
||||
file_manager->checkAndCreateDirectoryP(cached_file);
|
||||
cached_file += file;
|
||||
std::string cached_file = file_manager->getTextureCacheLocation(filename);
|
||||
|
||||
// If the cached texture does not exist, we generate it.
|
||||
if (!file_manager->fileExists(cached_file) ||
|
||||
@ -1428,9 +1419,26 @@ video::ITexture *IrrDriver::getTexture(const std::string &filename,
|
||||
Log::error("irr_driver", "Texture '%s' not found.", filename.c_str());
|
||||
}
|
||||
|
||||
m_texturesFileName[out] = filename;
|
||||
|
||||
return out;
|
||||
} // getTexture
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Get the texture file name using a texture pointer.
|
||||
* \param tex Pointer on the texture for which we want to find the file name.
|
||||
* \return Filename of the texture if found, or an empty string otherwise.
|
||||
*/
|
||||
std::string IrrDriver::getTextureName(video::ITexture* tex)
|
||||
{
|
||||
std::map<video::ITexture*, std::string>::iterator it;
|
||||
it = m_texturesFileName.find(tex);
|
||||
if (it != m_texturesFileName.end())
|
||||
return it->second;
|
||||
else
|
||||
return "";
|
||||
} // getTextureName
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Appends a pointer to each texture used in this mesh to the vector.
|
||||
* \param mesh The mesh from which the textures are being determined.
|
||||
|
@ -133,6 +133,8 @@ private:
|
||||
float greenSHCoeff[9];
|
||||
float redSHCoeff[9];
|
||||
|
||||
/** Keep a trace of the origin file name of a texture. */
|
||||
std::map<video::ITexture*, std::string> m_texturesFileName;
|
||||
|
||||
/** Flag to indicate if a resolution change is pending (which will be
|
||||
* acted upon in the next update). None means no change, yes means
|
||||
@ -311,6 +313,7 @@ public:
|
||||
bool is_premul=false,
|
||||
bool is_prediv=false,
|
||||
bool complain_if_not_found=true);
|
||||
std::string getTextureName(video::ITexture* tex);
|
||||
void grabAllTextures(const scene::IMesh *mesh);
|
||||
void dropAllTextures(const scene::IMesh *mesh);
|
||||
scene::IMesh *createQuadMesh(const video::SMaterial *material=NULL,
|
||||
|
@ -868,13 +868,13 @@ void FileManager::checkAndCreateScreenshotDir()
|
||||
void FileManager::checkAndCreateCachedTexturesDir()
|
||||
{
|
||||
#if defined(WIN32) || defined(__CYGWIN__)
|
||||
m_cached_textures_dir = m_user_config_dir + "resized-textures/";
|
||||
m_cached_textures_dir = m_user_config_dir + "cached-textures/";
|
||||
#elif defined(__APPLE__)
|
||||
m_cached_textures_dir = getenv("HOME");
|
||||
m_cached_textures_dir += "/Library/Application Support/SuperTuxKart/ResizedTextures/";
|
||||
m_cached_textures_dir += "/Library/Application Support/SuperTuxKart/CachedTextures/";
|
||||
#else
|
||||
m_cached_textures_dir = checkAndCreateLinuxDir("XDG_CACHE_HOME", "supertuxkart", ".cache/", ".");
|
||||
m_cached_textures_dir += "resized-textures/";
|
||||
m_cached_textures_dir += "cached-textures/";
|
||||
#endif
|
||||
|
||||
if (!checkAndCreateDirectory(m_cached_textures_dir))
|
||||
@ -1010,6 +1010,35 @@ void FileManager::redirectOutput()
|
||||
Log::openOutputFiles(logoutfile);
|
||||
} // redirectOutput
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Returns the theoretical location of the cached version of a texture
|
||||
* depending of the current config. (This function also works for directories:
|
||||
* in this case the returned directory will be the cache location for all
|
||||
* textures that you will find in the specified directory. The specified
|
||||
* directory must end with '/')
|
||||
* \note The returned location is where the cached data should be read or
|
||||
* written but the file itseft does not necessarity exist. However, the
|
||||
* directory structure is automatically created if it does not exist.
|
||||
*/
|
||||
std::string FileManager::getTextureCacheLocation(const std::string& filename)
|
||||
{
|
||||
std::string file = StringUtils::getBasename(filename);
|
||||
|
||||
std::string parent_dir = StringUtils::getPath(filename);
|
||||
if (StringUtils::hasSuffix(parent_dir, "/"))
|
||||
parent_dir = parent_dir.substr(0, parent_dir.size() - 1);
|
||||
parent_dir = StringUtils::getBasename(parent_dir);
|
||||
|
||||
std::string cache_subdir = UserConfigParams::m_high_definition_textures
|
||||
? "hd/"
|
||||
: "resized/";
|
||||
std::string cached_file =
|
||||
getCachedTexturesDir() + cache_subdir + parent_dir + "/";
|
||||
checkAndCreateDirectoryP(cached_file);
|
||||
cached_file += file;
|
||||
return cached_file;
|
||||
} // getTextureCacheLocation
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Returns the directory for addon files. */
|
||||
const std::string &FileManager::getAddonsDir() const
|
||||
|
@ -116,6 +116,7 @@ public:
|
||||
std::string getScreenshotDir() const;
|
||||
std::string getCachedTexturesDir() const;
|
||||
std::string getGPDir() const;
|
||||
std::string getTextureCacheLocation(const std::string& filename);
|
||||
bool checkAndCreateDirectoryP(const std::string &path);
|
||||
const std::string &getAddonsDir() const;
|
||||
std::string getAddonsFile(const std::string &name);
|
||||
|
Loading…
Reference in New Issue
Block a user