From d0a3a9f0f6dd3571e9f3a15bf4f8493a46d69eef Mon Sep 17 00:00:00 2001 From: Andrei Karas Date: Tue, 24 May 2016 23:09:33 +0300 Subject: Move resourcemanager into subdirectory. --- src/resources/ambientlayer.cpp | 3 +- src/resources/animation/simpleanimation.cpp | 3 +- src/resources/atlas/atlasmanager.cpp | 3 +- src/resources/atlas/atlasresource.cpp | 4 +- src/resources/dye/dyepalette_unittest.cc | 3 +- src/resources/image.cpp | 5 +- src/resources/item/item.cpp | 3 +- src/resources/map/map.cpp | 3 +- src/resources/map/mapitem.cpp | 3 +- src/resources/mapreader.cpp | 4 +- src/resources/memorymanager.cpp | 2 +- src/resources/resource.cpp | 2 +- src/resources/resourcemanager.cpp | 1128 --------------------- src/resources/resourcemanager.h | 277 ----- src/resources/resourcemanager/resourcemanager.cpp | 1128 +++++++++++++++++++++ src/resources/resourcemanager/resourcemanager.h | 277 +++++ src/resources/sdl2imagehelper.cpp | 10 +- src/resources/sdl2softwareimagehelper.cpp | 8 +- src/resources/sprite/animatedsprite.cpp | 3 +- src/resources/sprite/animatedsprite_unittest.cc | 3 +- src/resources/sprite/animationdelayload.cpp | 2 +- src/resources/sprite/spritedef.cpp | 3 +- src/resources/surfaceimagehelper.cpp | 8 +- 23 files changed, 1448 insertions(+), 1437 deletions(-) delete mode 100644 src/resources/resourcemanager.cpp delete mode 100644 src/resources/resourcemanager.h create mode 100644 src/resources/resourcemanager/resourcemanager.cpp create mode 100644 src/resources/resourcemanager/resourcemanager.h (limited to 'src/resources') diff --git a/src/resources/ambientlayer.cpp b/src/resources/ambientlayer.cpp index 3decec879..6c8e22893 100644 --- a/src/resources/ambientlayer.cpp +++ b/src/resources/ambientlayer.cpp @@ -27,7 +27,8 @@ #include "resources/image.h" #include "resources/imagehelper.h" -#include "resources/resourcemanager.h" + +#include "resources/resourcemanager/resourcemanager.h" #include "debug.h" diff --git a/src/resources/animation/simpleanimation.cpp b/src/resources/animation/simpleanimation.cpp index 8f0bfba0b..bc67ad747 100644 --- a/src/resources/animation/simpleanimation.cpp +++ b/src/resources/animation/simpleanimation.cpp @@ -27,12 +27,13 @@ #include "render/graphics.h" #include "resources/imageset.h" -#include "resources/resourcemanager.h" #include "resources/animation/animation.h" #include "resources/dye/dye.h" +#include "resources/resourcemanager/resourcemanager.h" + #include "utils/delete2.h" #include "debug.h" diff --git a/src/resources/atlas/atlasmanager.cpp b/src/resources/atlas/atlasmanager.cpp index 03d0b40fd..7a375b243 100644 --- a/src/resources/atlas/atlasmanager.cpp +++ b/src/resources/atlas/atlasmanager.cpp @@ -35,7 +35,6 @@ #include "resources/imagehelper.h" #include "resources/openglimagehelper.h" -#include "resources/resourcemanager.h" #include "resources/sdlimagehelper.h" #include "resources/atlas/atlasitem.h" @@ -44,6 +43,8 @@ #include "resources/dye/dye.h" +#include "resources/resourcemanager/resourcemanager.h" + #include "debug.h" AtlasManager::AtlasManager() diff --git a/src/resources/atlas/atlasresource.cpp b/src/resources/atlas/atlasresource.cpp index 48561bbbc..5f2e24160 100644 --- a/src/resources/atlas/atlasresource.cpp +++ b/src/resources/atlas/atlasresource.cpp @@ -22,12 +22,12 @@ #include "resources/atlas/atlasresource.h" -#include "resources/resourcemanager.h" - #include "resources/atlas/atlasitem.h" #include "resources/atlas/atlasmanager.h" #include "resources/atlas/textureatlas.h" +#include "resources/resourcemanager/resourcemanager.h" + #include "debug.h" AtlasResource::~AtlasResource() diff --git a/src/resources/dye/dyepalette_unittest.cc b/src/resources/dye/dyepalette_unittest.cc index cda902697..9bf8bbeb0 100644 --- a/src/resources/dye/dyepalette_unittest.cc +++ b/src/resources/dye/dyepalette_unittest.cc @@ -25,13 +25,14 @@ #include "logger.h" #include "graphicsmanager.h" -#include "resources/resourcemanager.h" #include "resources/sdlimagehelper.h" #include "resources/db/palettedb.h" #include "resources/dye/dyepalette.h" +#include "resources/resourcemanager/resourcemanager.h" + #include "utils/env.h" #include "utils/physfstools.h" #include "utils/xml.h" diff --git a/src/resources/image.cpp b/src/resources/image.cpp index c4bbf0a3c..26322aed9 100644 --- a/src/resources/image.cpp +++ b/src/resources/image.cpp @@ -22,17 +22,18 @@ #include "resources/image.h" -#include "resources/resourcemanager.h" - #include "logger.h" #ifdef USE_OPENGL #include "resources/openglimagehelper.h" #endif // USE_OPENGL + #include "resources/memorymanager.h" #include "resources/sdlimagehelper.h" #include "resources/subimage.h" +#include "resources/resourcemanager/resourcemanager.h" + #include "utils/sdlcheckutils.h" #ifdef USE_SDL2 diff --git a/src/resources/item/item.cpp b/src/resources/item/item.cpp index f6d0af1d9..d62d9aaf1 100644 --- a/src/resources/item/item.cpp +++ b/src/resources/item/item.cpp @@ -29,7 +29,8 @@ #include "gui/theme.h" #include "resources/iteminfo.h" -#include "resources/resourcemanager.h" + +#include "resources/resourcemanager/resourcemanager.h" #include "net/serverfeatures.h" diff --git a/src/resources/map/map.cpp b/src/resources/map/map.cpp index ee4e0dc59..7fde6a005 100644 --- a/src/resources/map/map.cpp +++ b/src/resources/map/map.cpp @@ -46,13 +46,14 @@ #include "particle/particle.h" #include "resources/ambientlayer.h" -#include "resources/resourcemanager.h" #include "resources/subimage.h" #include "resources/map/location.h" #include "resources/map/mapobjectlist.h" #include "resources/map/tileanimation.h" +#include "resources/resourcemanager/resourcemanager.h" + #ifdef USE_OPENGL #include "render/renderers.h" #endif diff --git a/src/resources/map/mapitem.cpp b/src/resources/map/mapitem.cpp index 2968123a9..58a105ab9 100644 --- a/src/resources/map/mapitem.cpp +++ b/src/resources/map/mapitem.cpp @@ -28,7 +28,8 @@ #include "gui/fonts/font.h" #include "resources/image.h" -#include "resources/resourcemanager.h" + +#include "resources/resourcemanager/resourcemanager.h" #include "render/graphics.h" diff --git a/src/resources/mapreader.cpp b/src/resources/mapreader.cpp index b5cad0661..979153c87 100644 --- a/src/resources/mapreader.cpp +++ b/src/resources/mapreader.cpp @@ -38,8 +38,6 @@ #include "resources/beingcommon.h" #include "resources/image.h" -#include "resources/resourcemanager.h" - #include "resources/animation/animation.h" #ifdef USE_OPENGL @@ -48,6 +46,8 @@ #include "resources/map/tileanimation.h" +#include "resources/resourcemanager/resourcemanager.h" + #include "utils/base64.h" #include "utils/delete2.h" #include "utils/physfstools.h" diff --git a/src/resources/memorymanager.cpp b/src/resources/memorymanager.cpp index 11fd40f4e..33d6f442e 100644 --- a/src/resources/memorymanager.cpp +++ b/src/resources/memorymanager.cpp @@ -22,7 +22,7 @@ #include "gui/widgets/tabs/chat/chattab.h" -#include "resources/resourcemanager.h" +#include "resources/resourcemanager/resourcemanager.h" #include "utils/gettext.h" #include "utils/stringutils.h" diff --git a/src/resources/resource.cpp b/src/resources/resource.cpp index 959298290..391e0ce1b 100644 --- a/src/resources/resource.cpp +++ b/src/resources/resource.cpp @@ -24,7 +24,7 @@ #include "logger.h" -#include "resources/resourcemanager.h" +#include "resources/resourcemanager/resourcemanager.h" #include "debug.h" diff --git a/src/resources/resourcemanager.cpp b/src/resources/resourcemanager.cpp deleted file mode 100644 index 8057acfba..000000000 --- a/src/resources/resourcemanager.cpp +++ /dev/null @@ -1,1128 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2016 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "resources/resourcemanager.h" - -#include "configuration.h" -#include "logger.h" -#include "navigationmanager.h" - -#include "resources/map/walklayer.h" - -#ifdef USE_OPENGL -#include "resources/atlas/atlasmanager.h" -#include "resources/atlas/atlasresource.h" -#else // USE_OPENGL -#include "resources/image.h" -#endif // USE_OPENGL -#include "resources/imagehelper.h" -#include "resources/imageset.h" -#include "resources/memorymanager.h" -#include "resources/sdlmusic.h" -#include "resources/soundeffect.h" - -#include "resources/dye/dye.h" - -#include "resources/sprite/spritedef.h" - -#include "utils/checkutils.h" -#include "utils/delete2.h" -#include "utils/physfscheckutils.h" -#include "utils/physfsrwops.h" -#include "utils/sdlcheckutils.h" - -#ifdef USE_OPENGL -#include "render/shaders/shader.h" -#include "render/shaders/shaderprogram.h" -#include "render/shaders/shadersmanager.h" -#endif - -#include -#include - -#include - -#include "debug.h" - -ResourceManager *resourceManager = nullptr; -ResourceManager *ResourceManager::instance = nullptr; - -ResourceManager::ResourceManager() : - deletedSurfaces(), - mResources(), - mOrphanedResources(), - mDeletedResources(), - mOldestOrphan(0), - mDestruction(0), - mUseLongLiveSprites(config.getBoolValue("uselonglivesprites")) -{ - logger->log1("Initializing resource manager..."); -} - -ResourceManager::~ResourceManager() -{ - mDestruction = true; - mResources.insert(mOrphanedResources.begin(), mOrphanedResources.end()); - - // Release any remaining spritedefs first because they depend on image sets - ResourceIterator iter = mResources.begin(); - -#ifdef DEBUG_LEAKS - while (iter != mResources.end()) - { - if (iter->second) - { - if (iter->second->getRefCount()) - { - logger->log(std::string("ResourceLeak: ").append( - iter->second->getIdPath()).append(" (").append( - toString(iter->second->getRefCount())).append(")")); - } - } - ++iter; - } - - iter = mResources.begin(); -#endif - - while (iter != mResources.end()) - { -#ifdef DEBUG_LEAKS - if (iter->second && iter->second->getRefCount()) - { - ++iter; - continue; - } -#endif - if (dynamic_cast(iter->second)) - { - cleanUp(iter->second); - const ResourceIterator toErase = iter; - ++iter; - mResources.erase(toErase); - } - else - { - ++iter; - } - } - - // Release any remaining image sets first because they depend on images - iter = mResources.begin(); - while (iter != mResources.end()) - { -#ifdef DEBUG_LEAKS - if (iter->second && iter->second->getRefCount()) - { - ++iter; - continue; - } -#endif - if (dynamic_cast(iter->second)) - { - cleanUp(iter->second); - const ResourceIterator toErase = iter; - ++iter; - mResources.erase(toErase); - } - else - { - ++iter; - } - } - - // Release remaining resources, logging the number of dangling references. - iter = mResources.begin(); - while (iter != mResources.end()) - { -#ifdef DEBUG_LEAKS - if (iter->second && iter->second->getRefCount()) - { - ++iter; - continue; - } -#endif - if (iter->second) - { - cleanUp(iter->second); - const ResourceIterator toErase = iter; - ++iter; - mResources.erase(toErase); - } - else - { - ++iter; - } - } - clearDeleted(); - clearScheduled(); -} - -void ResourceManager::init() -{ - if (!resourceManager) - resourceManager = new ResourceManager; -} - -void ResourceManager::cleanUp(Resource *const res) -{ - if (!res) - return; - - if (res->mRefCount > 0) - { - logger->log("ResourceManager::~ResourceManager() cleaning up %u " - "reference%s to %s", - res->mRefCount, - (res->mRefCount == 1) ? "" : "s", - res->mIdPath.c_str()); - } - - delete res; -#ifdef DEBUG_LEAKS - cleanOrphans(true); -#endif -} - -void ResourceManager::cleanProtected() -{ - ResourceIterator iter = mResources.begin(); - while (iter != mResources.end()) - { - Resource *const res = iter->second; - if (!res) - { - ++ iter; - continue; - } - if (res->isProtected()) - { - res->setProtected(false); - res->decRef(); - iter = mResources.begin(); - continue; - } - - ++ iter; - } -} - -bool ResourceManager::cleanOrphans(const bool always) -{ - timeval tv; - gettimeofday(&tv, nullptr); - // Delete orphaned resources after 30 seconds. - time_t oldest = static_cast(tv.tv_sec); - const time_t threshold = oldest - 30; - - if (mOrphanedResources.empty() || (!always && mOldestOrphan >= threshold)) - return false; - - bool status(false); - ResourceIterator iter = mOrphanedResources.begin(); - while (iter != mOrphanedResources.end()) - { - Resource *const res = iter->second; - if (!res) - { - ++iter; - continue; - } - const time_t t = res->mTimeStamp; - if (!always && t >= threshold) - { - if (t < oldest) - oldest = t; - ++ iter; - } - else - { - logResource(res); - const ResourceIterator toErase = iter; - ++iter; - mOrphanedResources.erase(toErase); - delete res; // delete only after removal from list, - // to avoid issues in recursion - status = true; - } - } - - mOldestOrphan = oldest; - return status; -} - -void ResourceManager::logResource(const Resource *const res) -{ - if (!res) - return; -#ifdef USE_OPENGL - const Image *const image = dynamic_cast(res); - if (image) - { - std::string src = image->getSource(); - const int count = image->getRefCount(); - if (count) - src.append(" ").append(toString(count)); - logger->log("resource(%s, %u) %s", res->mIdPath.c_str(), - image->getGLImage(), src.c_str()); - } - else - { - logger->log("resource(%s)", res->mIdPath.c_str()); - } -#else - logger->log("resource(%s)", res->mIdPath.c_str()); -#endif -} - -void ResourceManager::clearDeleted(const bool full) -{ - bool status(true); - logger->log1("clear deleted"); - while (status) - { - status = false; - std::set::iterator resDelIter = mDeletedResources.begin(); - while (resDelIter != mDeletedResources.end()) - { - if (!(*resDelIter)->getRefCount()) - { - status = true; - Resource *res = *resDelIter; - logResource(res); - mDeletedResources.erase(resDelIter); - delete res; - break; - } - ++ resDelIter; - } - } - if (full && !mDeletedResources.empty()) - { - logger->log1("leaks in deleted"); - std::set::iterator resDelIter = mDeletedResources.begin(); - while (resDelIter != mDeletedResources.end()) - { - logResource(*resDelIter); - - // for debug only -// delete *resDelIter; - // for debug only - - ++ resDelIter; - } - } -} -bool ResourceManager::setWriteDir(const std::string &path) const -{ - return static_cast(PhysFs::setWriteDir(path.c_str())); -} - -bool ResourceManager::addToSearchPath(const std::string &path, - const Append append) const -{ - logger->log("Adding to PhysicsFS: %s (%s)", path.c_str(), - append == Append_true ? "append" : "prepend"); - if (!PhysFs::addToSearchPath(path.c_str(), - append == Append_true ? 1 : 0)) - { - logger->log("Error: %s: addToSearchPath failed: %s", - path.c_str(), - PHYSFS_getLastError()); - return false; - } - return true; -} - -bool ResourceManager::removeFromSearchPath(const std::string &path) const -{ - logger->log("Removing from PhysicsFS: %s", path.c_str()); - if (!PhysFs::removeFromSearchPath(path.c_str())) - { - logger->log("Error: %s: removeFromSearchPath failed: %s", - path.c_str(), - PHYSFS_getLastError()); - return false; - } - return true; -} - -void ResourceManager::searchAndAddArchives(const std::string &restrict path, - const std::string &restrict ext, - const Append append) const -{ - const char *const dirSep = dirSeparator; - char **list = PhysFs::enumerateFiles(path.c_str()); - - for (char **i = list; *i; i++) - { - const size_t len = strlen(*i); - - if (len > ext.length() && !ext.compare((*i) + (len - ext.length()))) - { - const std::string file = path + (*i); - const std::string realPath = std::string( - PhysFs::getRealDir(file.c_str())); - addToSearchPath(std::string(realPath).append( - dirSep).append(file), append); - } - } - - PhysFs::freeList(list); -} - -void ResourceManager::searchAndRemoveArchives(const std::string &restrict path, - const std::string &restrict ext) - const -{ - const char *const dirSep = dirSeparator; - char **list = PhysFs::enumerateFiles(path.c_str()); - - for (char **i = list; *i; i++) - { - const size_t len = strlen(*i); - if (len > ext.length() && !ext.compare((*i) + (len - ext.length()))) - { - const std::string file = path + (*i); - const std::string realPath = std::string( - PhysFs::getRealDir(file.c_str())); - removeFromSearchPath(std::string(realPath).append( - dirSep).append(file)); - } - } - - PhysFs::freeList(list); -} - -bool ResourceManager::addResource(const std::string &idPath, - Resource *const resource) -{ - if (resource) - { - resource->incRef(); - resource->mIdPath = idPath; -#ifdef DEBUG_IMAGES - logger->log("set name %p, %s", static_cast(resource), - resource->mIdPath.c_str()); -#endif - mResources[idPath] = resource; - return true; - } - return false; -} - -Resource *ResourceManager::getFromCache(const std::string &filename, - const int variant) -{ - std::stringstream ss; - ss << filename << "[" << variant << "]"; - return getFromCache(ss.str()); -} - -bool ResourceManager::isInCache(const std::string &idPath) const -{ - const ResourceCIterator &resIter = mResources.find(idPath); - return (resIter != mResources.end() && resIter->second); -} - -Resource *ResourceManager::getTempResource(const std::string &idPath) -{ - const ResourceCIterator &resIter = mResources.find(idPath); - if (resIter != mResources.end()) - { - Resource *const res = resIter->second; - if (resIter->second) - return res; - } - return nullptr; -} - -Resource *ResourceManager::getFromCache(const std::string &idPath) -{ - // Check if the id exists, and return the value if it does. - ResourceIterator resIter = mResources.find(idPath); - if (resIter != mResources.end()) - { - if (resIter->second) - resIter->second->incRef(); - return resIter->second; - } - - resIter = mOrphanedResources.find(idPath); - if (resIter != mOrphanedResources.end()) - { - Resource *const res = resIter->second; - mResources.insert(*resIter); - mOrphanedResources.erase(resIter); - if (res) - res->incRef(); - return res; - } - return nullptr; -} - -Resource *ResourceManager::get(const std::string &idPath, - generator fun, - const void *const data) -{ -#ifndef DISABLE_RESOURCE_CACHING - Resource *resource = getFromCache(idPath); - if (resource) - return resource; - resource = fun(data); - - if (resource) - { - resource->incRef(); - resource->mIdPath = idPath; -#ifdef DEBUG_IMAGES - logger->log("set name %p, %s", static_cast(resource), - resource->mIdPath.c_str()); -#endif - mResources[idPath] = resource; - cleanOrphans(); - } - else - { - reportAlways("Error loading image: %s", idPath.c_str()); - } -#else - Resource *resource = fun(data, idPath); - - if (resource) - { - resource->incRef(); - resource->mIdPath = idPath; -#ifdef DEBUG_IMAGES - logger->log("set name %p, %s", static_cast(resource), - resource->mIdPath.c_str()); -#endif - } - else - { - reportAlways("Error loading image: " + idPath); - } -#endif - - // Returns nullptr if the object could not be created. - return resource; -} - -struct ResourceLoader final -{ - ResourceManager *manager; - std::string path; - ResourceManager::loader fun; - - static Resource *load(const void *const v) - { - if (!v) - return nullptr; - const ResourceLoader *const - rl = static_cast(v); - SDL_RWops *const rw = MPHYSFSRWOPS_openRead(rl->path.c_str()); - if (!rw) - { - reportAlways("Error loading resource: %s", - rl->path.c_str()); - return nullptr; - } - Resource *const res = rl->fun(rw, rl->path); - return res; - } -}; - -SDLMusic *ResourceManager::getMusic(const std::string &idPath) -{ - ResourceLoader rl = { this, idPath, &SDLMusic::load }; - return static_cast(get(idPath, ResourceLoader::load, &rl)); -} - -SoundEffect *ResourceManager::getSoundEffect(const std::string &idPath) -{ - ResourceLoader rl = { this, idPath, &SoundEffect::load }; - return static_cast(get(idPath, ResourceLoader::load, &rl)); -} - -struct DyedImageLoader final -{ - ResourceManager *manager; - std::string path; - static Resource *load(const void *const v) - { - BLOCK_START("DyedImageLoader::load") - if (!v) - { - BLOCK_END("DyedImageLoader::load") - return nullptr; - } - - const DyedImageLoader *const rl - = static_cast(v); - if (!rl->manager) - { - BLOCK_END("DyedImageLoader::load") - return nullptr; - } - - std::string path1 = rl->path; - const size_t p = path1.find('|'); - Dye *d = nullptr; - if (p != std::string::npos) - { - d = new Dye(path1.substr(p + 1)); - path1 = path1.substr(0, p); - } - SDL_RWops *const rw = MPHYSFSRWOPS_openRead(path1.c_str()); - if (!rw) - { - delete d; - reportAlways("Image loading error: %s", path1.c_str()); - BLOCK_END("DyedImageLoader::load") - return nullptr; - } - Resource *const res = d ? imageHelper->load(rw, *d) - : imageHelper->load(rw); - delete d; - if (!res) - reportAlways("Image loading error: %s", path1.c_str()); - BLOCK_END("DyedImageLoader::load") - return res; - } -}; - -Image *ResourceManager::getImage(const std::string &idPath) -{ - DyedImageLoader rl = { this, idPath }; - return static_cast(get(idPath, DyedImageLoader::load, &rl)); -} - -struct ImageSetLoader final -{ - ResourceManager *manager; - std::string path; - int w, h; - static Resource *load(const void *const v) - { - if (!v) - return nullptr; - - const ImageSetLoader *const - rl = static_cast(v); - if (!rl->manager) - return nullptr; - - Image *const img = rl->manager->getImage(rl->path); - if (!img) - { - reportAlways("Image loading error: %s", rl->path.c_str()); - return nullptr; - } - ImageSet *const res = new ImageSet(img, rl->w, rl->h); - img->decRef(); - return res; - } -}; - -ImageSet *ResourceManager::getImageSet(const std::string &imagePath, - const int w, const int h) -{ - ImageSetLoader rl = { this, imagePath, w, h }; - std::stringstream ss; - ss << imagePath << "[" << w << "x" << h << "]"; - return static_cast(get(ss.str(), ImageSetLoader::load, &rl)); -} - - -struct SubImageSetLoader final -{ - ResourceManager *manager; - Image *parent; - int width, height; - static Resource *load(const void *const v) - { - if (!v) - return nullptr; - - const SubImageSetLoader *const - rl = static_cast(v); - if (!rl->manager) - return nullptr; - - if (!rl->parent) - return nullptr; - ImageSet *const res = new ImageSet(rl->parent, rl->width, rl->height); - return res; - } -}; - -ImageSet *ResourceManager::getSubImageSet(Image *const parent, - const int width, const int height) -{ - if (!parent) - return nullptr; - - const SubImageSetLoader rl = { this, parent, width, height }; - std::stringstream ss; - ss << parent->getIdPath() << ", set[" << width << "x" << height << "]"; - return static_cast(get(ss.str(), - SubImageSetLoader::load, &rl)); -} - -struct SubImageLoader final -{ - ResourceManager *manager; - Image *parent; - int x, y; - int width, height; - static Resource *load(const void *const v) - { - if (!v) - return nullptr; - - const SubImageLoader *const - rl = static_cast(v); - if (!rl->manager || !rl->parent) - return nullptr; - - Image *const res = rl->parent->getSubImage(rl->x, rl->y, - rl->width, rl->height); - if (!res) - { - reportAlways("SubImage loading error: %s", - rl->parent->getSource().c_str()); - } - return res; - } -}; - -Image *ResourceManager::getSubImage(Image *const parent, - const int x, const int y, - const int width, const int height) -{ - if (!parent) - return nullptr; - - const SubImageLoader rl = { this, parent, x, y, width, height}; - - std::stringstream ss; - ss << parent->getIdPath() << ",[" << x << "," << y << "," - << width << "x" << height << "]"; - return static_cast(get(ss.str(), SubImageLoader::load, &rl)); -} - -#ifdef USE_OPENGL -struct AtlasLoader final -{ - const std::string name; - const StringVect *files; - - static Resource *load(const void *const v) - { - if (!v) - return nullptr; - - const AtlasLoader *const rl = static_cast(v); - AtlasResource *const resource = AtlasManager::loadTextureAtlas( - rl->name, *rl->files); - if (!resource) - reportAlways("Atlas creation error: %s", rl->name.c_str()); - return resource; - } -}; - -Resource *ResourceManager::getAtlas(const std::string &name, - const StringVect &files) -{ - AtlasLoader rl = { name, &files }; - return get("atlas_" + name, AtlasLoader::load, &rl); -} - -struct ShaderLoader final -{ - const std::string name; - const unsigned int type; - - static Resource *load(const void *const v) - { - if (!v) - return nullptr; - - const ShaderLoader *const rl - = static_cast(v); - Shader *const resource = shaders.createShader(rl->type, rl->name); - if (!resource) - reportAlways("Shader creation error: %s", rl->name.c_str()); - return resource; - } -}; - -Resource *ResourceManager::getShader(const unsigned int type, - const std::string &name) -{ - ShaderLoader rl = { name, type }; - return get("shader_" + name, ShaderLoader::load, &rl); -} - -struct ShaderProgramLoader final -{ - const std::string vertex; - const std::string fragment; - const bool isNewShader; - - static Resource *load(const void *const v) - { - if (!v) - return nullptr; - - const ShaderProgramLoader *const rl - = static_cast(v); - ShaderProgram *const resource = shaders.createProgram( - rl->vertex, - rl->fragment, - rl->isNewShader); - if (!resource) - reportAlways("Shader program creation error"); - return resource; - } -}; - -Resource *ResourceManager::getShaderProgram(const std::string &vertex, - const std::string &fragment, - const bool isNewShader) -{ - ShaderProgramLoader rl = { vertex, fragment, isNewShader }; - return get("program_" + vertex + " + " + fragment, - ShaderProgramLoader::load, &rl); -} -#endif - -#ifndef DYECMD -struct WalkLayerLoader final -{ - const std::string name; - Map *map; - - static Resource *load(const void *const v) - { - if (!v) - return nullptr; - - const WalkLayerLoader *const rl = static_cast(v); - Resource *const resource = NavigationManager::loadWalkLayer(rl->map); - if (!resource) - reportAlways("WalkLayer creation error"); - return resource; - } -}; -#endif - -#ifndef DYECMD -WalkLayer *ResourceManager::getWalkLayer(const std::string &name, - Map *const map) -{ - WalkLayerLoader rl = {name, map}; - return static_cast(get("map_" + name, - WalkLayerLoader::load, &rl)); -} -#else -WalkLayer *ResourceManager::getWalkLayer(const std::string &name A_UNUSED, - Map *const map A_UNUSED) -{ - return nullptr; -} -#endif - -struct SpriteDefLoader final -{ - std::string path; - int variant; - bool useLongLiveSprites; - static Resource *load(const void *const v) - { - if (!v) - return nullptr; - - const SpriteDefLoader *const - rl = static_cast(v); - return SpriteDef::load(rl->path, rl->variant, rl->useLongLiveSprites); - } -}; - -SpriteDef *ResourceManager::getSprite(const std::string &path, - const int variant) -{ - SpriteDefLoader rl = { path, variant, mUseLongLiveSprites }; - std::stringstream ss; - ss << path << "[" << variant << "]"; - return static_cast(get(ss.str(), SpriteDefLoader::load, &rl)); -} - -void ResourceManager::release(Resource *const res) -{ - if (!res || mDestruction) - return; - -#ifndef DISABLE_RESOURCE_CACHING - std::set::iterator resDelIter = mDeletedResources.find(res); - if (resDelIter != mDeletedResources.end()) - { - // we found zero counted image in deleted list. deleting it and exit. - mDeletedResources.erase(resDelIter); - delete res; - return; - } - - ResourceIterator resIter = mResources.find(res->mIdPath); - - if (resIter == mResources.end()) - { - reportAlways("no resource in cache: %s", - res->mIdPath.c_str()); - delete res; - return; - } - if (resIter->second != res) - { - reportAlways("in cache other image: %s", - res->mIdPath.c_str()); - delete res; - return; - } - - timeval tv; - gettimeofday(&tv, nullptr); - const time_t timestamp = static_cast(tv.tv_sec); - - res->mTimeStamp = timestamp; - if (mOrphanedResources.empty()) - mOldestOrphan = timestamp; - - mOrphanedResources.insert(*resIter); - mResources.erase(resIter); -#else - delete res; -#endif -} - -void ResourceManager::moveToDeleted(Resource *const res) -{ - if (!res) - return; - - bool found(false); - const int count = res->getRefCount(); - if (count == 1) - logResource(res); - res->decRef(); - ResourceIterator resIter = mResources.find(res->mIdPath); - if (resIter != mResources.end() && resIter->second == res) - { - mResources.erase(resIter); - found = true; - } - else - { - resIter = mOrphanedResources.find(res->mIdPath); - if (resIter != mOrphanedResources.end() && resIter->second == res) - { - mOrphanedResources.erase(resIter); - found = true; - } - } - if (found) - { - if (count > 1) - mDeletedResources.insert(res); - else - delete res; - } -} - -void ResourceManager::decRefDelete(Resource *const res) -{ - if (!res) - return; - - const int count = res->getRefCount(); - if (count == 1) - { - logResource(res); - - ResourceIterator resIter = mResources.find(res->mIdPath); - if (resIter != mResources.end() && resIter->second == res) - { - mResources.erase(resIter); - } - else - { - resIter = mOrphanedResources.find(res->mIdPath); - if (resIter != mOrphanedResources.end() && resIter->second == res) - mOrphanedResources.erase(resIter); - } - - delete res; - } - else - { - res->decRef(); - } -} - -void ResourceManager::deleteInstance() -{ -#ifdef DUMP_LEAKED_RESOURCES - if (instance) - { - logger->log1("clean orphans start"); - instance->cleanProtected(); - while (instance->cleanOrphans(true)) - continue; - logger->log1("clean orphans end"); - ResourceIterator iter = instance->mResources.begin(); - - while (iter != instance->mResources.end()) - { - const Resource *const res = iter->second; - if (res) - { - if (res->getRefCount()) - { - logger->log(std::string("ResourceLeak: ").append( - res->getIdPath()).append(" (").append(toString( - res->getRefCount())).append(")")); - } - } - ++iter; - } - } -#endif - delete2(instance); -} - -SDL_Surface *ResourceManager::loadSDLSurface(const std::string &filename) const -{ - if (SDL_RWops *const rw = MPHYSFSRWOPS_openRead(filename.c_str())) - { - if (!IMG_isPNG(rw)) - { - reportAlways("Error, image is not png: %s", filename.c_str()); - return nullptr; - } - SDL_Surface *const surface = MIMG_LoadPNG_RW(rw); - SDL_RWclose(rw); - return surface; - } - return nullptr; -} - -void ResourceManager::scheduleDelete(SDL_Surface *const surface) -{ - deletedSurfaces.insert(surface); -} - -void ResourceManager::clearScheduled() -{ - BLOCK_START("ResourceManager::clearScheduled") - FOR_EACH (std::set::iterator, i, deletedSurfaces) - MSDL_FreeSurface(*i); - deletedSurfaces.clear(); - BLOCK_END("ResourceManager::clearScheduled") -} - -struct RescaledLoader final -{ - ResourceManager *manager; - const Image *image; - int width; - int height; - static Resource *load(const void *const v) - { - if (!v) - return nullptr; - const RescaledLoader *const rl - = static_cast(v); - if (!rl->manager || !rl->image) - return nullptr; - Image *const rescaled = rl->image->SDLgetScaledImage( - rl->width, rl->height); - if (!rescaled) - { - reportAlways("Rescale image failed: %s", - rl->image->getIdPath().c_str()); - return nullptr; - } - return rescaled; - } -}; - -Image *ResourceManager::getRescaled(const Image *const image, - const int width, const int height) -{ - if (!image) - return nullptr; - - std::string idPath = image->getIdPath() + strprintf( - "_rescaled%dx%d", width, height); - const RescaledLoader rl = { this, image, width, height }; - Image *const img = static_cast( - get(idPath, RescaledLoader::load, &rl)); - return img; -} - -void ResourceManager::clearCache() -{ - cleanProtected(); - while (cleanOrphans(true)) - continue; -} - -int ResourceManager::calcMemoryLocal() const -{ - int sz = sizeof(ResourceManager); - FOR_EACH (std::set::iterator, it, deletedSurfaces) - { - sz += memoryManager.getSurfaceSize(*it); - } - return sz; -} - -int ResourceManager::calcMemoryChilds(const int level) const -{ - int sz = 0; - FOR_EACH (ResourceCIterator, it, mResources) - { - sz += static_cast((*it).first.capacity()); - sz += (*it).second->calcMemory(level + 1); - } - FOR_EACH (ResourceCIterator, it, mOrphanedResources) - { - sz += static_cast((*it).first.capacity()); - sz += (*it).second->calcMemory(level + 1); - } - FOR_EACH (std::set::const_iterator, it, mDeletedResources) - { - sz += (*it)->calcMemory(level + 1); - } - return sz; -} diff --git a/src/resources/resourcemanager.h b/src/resources/resourcemanager.h deleted file mode 100644 index eeda43b33..000000000 --- a/src/resources/resourcemanager.h +++ /dev/null @@ -1,277 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2016 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef RESOURCES_RESOURCEMANAGER_H -#define RESOURCES_RESOURCEMANAGER_H - -#include "resources/memorycounter.h" - -#include "enums/simpletypes/append.h" - -#include "utils/stringvector.h" - -#include -#include - -#include "localconsts.h" - -class Image; -class ImageSet; -class Map; -class SDLMusic; -class Resource; -class SoundEffect; -class SpriteDef; -class WalkLayer; - -struct SDL_Surface; -struct SDL_RWops; - -/** - * A class for loading and managing resources. - */ -class ResourceManager final : public MemoryCounter -{ - friend class Resource; - - public: - typedef Resource *(*loader)(SDL_RWops *rw, - const std::string &name); - typedef Resource *(&generator)(const void *const data); - - ResourceManager(); - - A_DELETE_COPY(ResourceManager) - - /** - * Destructor. Cleans up remaining resources, warning about resources - * that were still referenced. - */ - ~ResourceManager(); - - /** - * Sets the write directory. - * - * @param path The path of the directory to be added. - * @return true on success, false otherwise. - */ - bool setWriteDir(const std::string &path) const; - - /** - * Adds a directory or archive to the search path. If append is true - * then the directory is added to the end of the search path, otherwise - * it is added at the front. - * - * @return true on success, false otherwise. - */ - bool addToSearchPath(const std::string &path, - const Append append) const; - - /** - * Remove a directory or archive from the search path. - * - * @return true on success, false otherwise. - */ - bool removeFromSearchPath(const std::string &path) const; - - /** - * Searches for zip files and adds them to the search path. - */ - void searchAndAddArchives(const std::string &restrict path, - const std::string &restrict ext, - const Append append) const; - - /** - * Searches for zip files and remove them from the search path. - */ - void searchAndRemoveArchives(const std::string &restrict path, - const std::string &restrict ext) const; - - /** - * Creates a resource and adds it to the resource map. - * - * @param idPath The resource identifier path. - * @param fun A function for generating the resource. - * @param data Extra parameters for the generator. - * @return A valid resource or NULL if the resource could - * not be generated. - */ - Resource *get(const std::string &idPath, - generator fun, - const void *const data) A_WARN_UNUSED; - - Resource *getFromCache(const std::string &idPath) A_WARN_UNUSED; - - Resource *getFromCache(const std::string &filename, - const int variant) A_WARN_UNUSED; - - /** - * Adds a preformatted resource to the resource map. - * - * @param path The file name. - * @param Resource The Resource to add. - * @return true if successfull, false otherwise. - */ - bool addResource(const std::string &idPath, Resource *const resource); - - /** - * Convenience wrapper around ResourceManager::get for loading - * images. - */ - Image *getImage(const std::string &idPath) A_WARN_UNUSED; - - /** - * Convenience wrapper around ResourceManager::get for loading - * songs. - */ - SDLMusic *getMusic(const std::string &idPath) A_WARN_UNUSED; - - /** - * Convenience wrapper around ResourceManager::get for loading - * samples. - */ - SoundEffect *getSoundEffect(const std::string &idPath) A_WARN_UNUSED; - - /** - * Creates a image set based on the image referenced by the given - * path and the supplied sprite sizes - */ - ImageSet *getImageSet(const std::string &imagePath, - const int w, const int h) A_WARN_UNUSED; - - ImageSet *getSubImageSet(Image *const parent, - const int width, - const int height) A_WARN_UNUSED; - - Image *getSubImage(Image *const parent, const int x, const int y, - const int width, const int height) A_WARN_UNUSED; - -#ifdef USE_OPENGL - Resource *getAtlas(const std::string &name, - const StringVect &files) A_WARN_UNUSED; - - Resource *getShader(const unsigned int type, - const std::string &name) A_WARN_UNUSED; - - Resource *getShaderProgram(const std::string &vertex, - const std::string &fragment, - const bool isNewShader) A_WARN_UNUSED; -#endif - - WalkLayer *getWalkLayer(const std::string &name, Map *const map); - - /** - * Creates a sprite definition based on a given path and the supplied - * variant. - */ - SpriteDef *getSprite(const std::string &path, - const int variant = 0) A_WARN_UNUSED; - - /** - * Releases a resource, placing it in the set of orphaned resources. - */ - void release(Resource *const res); - - void clearDeleted(const bool full = true); - - void decRefDelete(Resource *const res); - - /** - * Move resource to deleted resources list. - */ - void moveToDeleted(Resource *const res); - - Image *getRescaled(const Image *const image, - const int width, - const int height) A_WARN_UNUSED; - - /** - * Loads the given filename as an SDL surface. The returned surface is - * expected to be freed by the caller using SDL_FreeSurface. - */ - SDL_Surface *loadSDLSurface(const std::string &filename) - const A_WARN_UNUSED; - - void scheduleDelete(SDL_Surface *const surface); - - void clearScheduled(); - - /** - * Deletes the class instance if it exists. - */ - static void deleteInstance(); - - int size() const A_WARN_UNUSED - { return CAST_S32(mResources.size()); } - - typedef std::map Resources; - typedef Resources::iterator ResourceIterator; - typedef Resources::const_iterator ResourceCIterator; - -#ifdef DEBUG_DUMP_LEAKS - Resources* getResources() A_WARN_UNUSED - { return &mResources; } - - Resources* getOrphanedResources() A_WARN_UNUSED - { return &mOrphanedResources; } -#endif - - bool cleanOrphans(const bool always = false); - - void cleanProtected(); - - bool isInCache(const std::string &idPath) const A_WARN_UNUSED; - - Resource *getTempResource(const std::string &idPath) A_WARN_UNUSED; - - void clearCache(); - - int calcMemoryLocal() const override final; - - int calcMemoryChilds(const int level) const override final; - - std::string getCounterName() const override final - { return "ResourceManager"; } - - static void init(); - - private: - /** - * Deletes the resource after logging a cleanup message. - */ - static void cleanUp(Resource *const resource); - - static void logResource(const Resource *const res); - - static ResourceManager *instance; - std::set deletedSurfaces; - Resources mResources; - Resources mOrphanedResources; - std::set mDeletedResources; - time_t mOldestOrphan; - bool mDestruction; - bool mUseLongLiveSprites; -}; - -extern ResourceManager *resourceManager; - -#endif // RESOURCES_RESOURCEMANAGER_H diff --git a/src/resources/resourcemanager/resourcemanager.cpp b/src/resources/resourcemanager/resourcemanager.cpp new file mode 100644 index 000000000..c59b09618 --- /dev/null +++ b/src/resources/resourcemanager/resourcemanager.cpp @@ -0,0 +1,1128 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2016 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "resources/resourcemanager/resourcemanager.h" + +#include "configuration.h" +#include "logger.h" +#include "navigationmanager.h" + +#include "resources/map/walklayer.h" + +#ifdef USE_OPENGL +#include "resources/atlas/atlasmanager.h" +#include "resources/atlas/atlasresource.h" +#else // USE_OPENGL +#include "resources/image.h" +#endif // USE_OPENGL +#include "resources/imagehelper.h" +#include "resources/imageset.h" +#include "resources/memorymanager.h" +#include "resources/sdlmusic.h" +#include "resources/soundeffect.h" + +#include "resources/dye/dye.h" + +#include "resources/sprite/spritedef.h" + +#include "utils/checkutils.h" +#include "utils/delete2.h" +#include "utils/physfscheckutils.h" +#include "utils/physfsrwops.h" +#include "utils/sdlcheckutils.h" + +#ifdef USE_OPENGL +#include "render/shaders/shader.h" +#include "render/shaders/shaderprogram.h" +#include "render/shaders/shadersmanager.h" +#endif + +#include +#include + +#include + +#include "debug.h" + +ResourceManager *resourceManager = nullptr; +ResourceManager *ResourceManager::instance = nullptr; + +ResourceManager::ResourceManager() : + deletedSurfaces(), + mResources(), + mOrphanedResources(), + mDeletedResources(), + mOldestOrphan(0), + mDestruction(0), + mUseLongLiveSprites(config.getBoolValue("uselonglivesprites")) +{ + logger->log1("Initializing resource manager..."); +} + +ResourceManager::~ResourceManager() +{ + mDestruction = true; + mResources.insert(mOrphanedResources.begin(), mOrphanedResources.end()); + + // Release any remaining spritedefs first because they depend on image sets + ResourceIterator iter = mResources.begin(); + +#ifdef DEBUG_LEAKS + while (iter != mResources.end()) + { + if (iter->second) + { + if (iter->second->getRefCount()) + { + logger->log(std::string("ResourceLeak: ").append( + iter->second->getIdPath()).append(" (").append( + toString(iter->second->getRefCount())).append(")")); + } + } + ++iter; + } + + iter = mResources.begin(); +#endif + + while (iter != mResources.end()) + { +#ifdef DEBUG_LEAKS + if (iter->second && iter->second->getRefCount()) + { + ++iter; + continue; + } +#endif + if (dynamic_cast(iter->second)) + { + cleanUp(iter->second); + const ResourceIterator toErase = iter; + ++iter; + mResources.erase(toErase); + } + else + { + ++iter; + } + } + + // Release any remaining image sets first because they depend on images + iter = mResources.begin(); + while (iter != mResources.end()) + { +#ifdef DEBUG_LEAKS + if (iter->second && iter->second->getRefCount()) + { + ++iter; + continue; + } +#endif + if (dynamic_cast(iter->second)) + { + cleanUp(iter->second); + const ResourceIterator toErase = iter; + ++iter; + mResources.erase(toErase); + } + else + { + ++iter; + } + } + + // Release remaining resources, logging the number of dangling references. + iter = mResources.begin(); + while (iter != mResources.end()) + { +#ifdef DEBUG_LEAKS + if (iter->second && iter->second->getRefCount()) + { + ++iter; + continue; + } +#endif + if (iter->second) + { + cleanUp(iter->second); + const ResourceIterator toErase = iter; + ++iter; + mResources.erase(toErase); + } + else + { + ++iter; + } + } + clearDeleted(); + clearScheduled(); +} + +void ResourceManager::init() +{ + if (!resourceManager) + resourceManager = new ResourceManager; +} + +void ResourceManager::cleanUp(Resource *const res) +{ + if (!res) + return; + + if (res->mRefCount > 0) + { + logger->log("ResourceManager::~ResourceManager() cleaning up %u " + "reference%s to %s", + res->mRefCount, + (res->mRefCount == 1) ? "" : "s", + res->mIdPath.c_str()); + } + + delete res; +#ifdef DEBUG_LEAKS + cleanOrphans(true); +#endif +} + +void ResourceManager::cleanProtected() +{ + ResourceIterator iter = mResources.begin(); + while (iter != mResources.end()) + { + Resource *const res = iter->second; + if (!res) + { + ++ iter; + continue; + } + if (res->isProtected()) + { + res->setProtected(false); + res->decRef(); + iter = mResources.begin(); + continue; + } + + ++ iter; + } +} + +bool ResourceManager::cleanOrphans(const bool always) +{ + timeval tv; + gettimeofday(&tv, nullptr); + // Delete orphaned resources after 30 seconds. + time_t oldest = static_cast(tv.tv_sec); + const time_t threshold = oldest - 30; + + if (mOrphanedResources.empty() || (!always && mOldestOrphan >= threshold)) + return false; + + bool status(false); + ResourceIterator iter = mOrphanedResources.begin(); + while (iter != mOrphanedResources.end()) + { + Resource *const res = iter->second; + if (!res) + { + ++iter; + continue; + } + const time_t t = res->mTimeStamp; + if (!always && t >= threshold) + { + if (t < oldest) + oldest = t; + ++ iter; + } + else + { + logResource(res); + const ResourceIterator toErase = iter; + ++iter; + mOrphanedResources.erase(toErase); + delete res; // delete only after removal from list, + // to avoid issues in recursion + status = true; + } + } + + mOldestOrphan = oldest; + return status; +} + +void ResourceManager::logResource(const Resource *const res) +{ + if (!res) + return; +#ifdef USE_OPENGL + const Image *const image = dynamic_cast(res); + if (image) + { + std::string src = image->getSource(); + const int count = image->getRefCount(); + if (count) + src.append(" ").append(toString(count)); + logger->log("resource(%s, %u) %s", res->mIdPath.c_str(), + image->getGLImage(), src.c_str()); + } + else + { + logger->log("resource(%s)", res->mIdPath.c_str()); + } +#else + logger->log("resource(%s)", res->mIdPath.c_str()); +#endif +} + +void ResourceManager::clearDeleted(const bool full) +{ + bool status(true); + logger->log1("clear deleted"); + while (status) + { + status = false; + std::set::iterator resDelIter = mDeletedResources.begin(); + while (resDelIter != mDeletedResources.end()) + { + if (!(*resDelIter)->getRefCount()) + { + status = true; + Resource *res = *resDelIter; + logResource(res); + mDeletedResources.erase(resDelIter); + delete res; + break; + } + ++ resDelIter; + } + } + if (full && !mDeletedResources.empty()) + { + logger->log1("leaks in deleted"); + std::set::iterator resDelIter = mDeletedResources.begin(); + while (resDelIter != mDeletedResources.end()) + { + logResource(*resDelIter); + + // for debug only +// delete *resDelIter; + // for debug only + + ++ resDelIter; + } + } +} +bool ResourceManager::setWriteDir(const std::string &path) const +{ + return static_cast(PhysFs::setWriteDir(path.c_str())); +} + +bool ResourceManager::addToSearchPath(const std::string &path, + const Append append) const +{ + logger->log("Adding to PhysicsFS: %s (%s)", path.c_str(), + append == Append_true ? "append" : "prepend"); + if (!PhysFs::addToSearchPath(path.c_str(), + append == Append_true ? 1 : 0)) + { + logger->log("Error: %s: addToSearchPath failed: %s", + path.c_str(), + PHYSFS_getLastError()); + return false; + } + return true; +} + +bool ResourceManager::removeFromSearchPath(const std::string &path) const +{ + logger->log("Removing from PhysicsFS: %s", path.c_str()); + if (!PhysFs::removeFromSearchPath(path.c_str())) + { + logger->log("Error: %s: removeFromSearchPath failed: %s", + path.c_str(), + PHYSFS_getLastError()); + return false; + } + return true; +} + +void ResourceManager::searchAndAddArchives(const std::string &restrict path, + const std::string &restrict ext, + const Append append) const +{ + const char *const dirSep = dirSeparator; + char **list = PhysFs::enumerateFiles(path.c_str()); + + for (char **i = list; *i; i++) + { + const size_t len = strlen(*i); + + if (len > ext.length() && !ext.compare((*i) + (len - ext.length()))) + { + const std::string file = path + (*i); + const std::string realPath = std::string( + PhysFs::getRealDir(file.c_str())); + addToSearchPath(std::string(realPath).append( + dirSep).append(file), append); + } + } + + PhysFs::freeList(list); +} + +void ResourceManager::searchAndRemoveArchives(const std::string &restrict path, + const std::string &restrict ext) + const +{ + const char *const dirSep = dirSeparator; + char **list = PhysFs::enumerateFiles(path.c_str()); + + for (char **i = list; *i; i++) + { + const size_t len = strlen(*i); + if (len > ext.length() && !ext.compare((*i) + (len - ext.length()))) + { + const std::string file = path + (*i); + const std::string realPath = std::string( + PhysFs::getRealDir(file.c_str())); + removeFromSearchPath(std::string(realPath).append( + dirSep).append(file)); + } + } + + PhysFs::freeList(list); +} + +bool ResourceManager::addResource(const std::string &idPath, + Resource *const resource) +{ + if (resource) + { + resource->incRef(); + resource->mIdPath = idPath; +#ifdef DEBUG_IMAGES + logger->log("set name %p, %s", static_cast(resource), + resource->mIdPath.c_str()); +#endif + mResources[idPath] = resource; + return true; + } + return false; +} + +Resource *ResourceManager::getFromCache(const std::string &filename, + const int variant) +{ + std::stringstream ss; + ss << filename << "[" << variant << "]"; + return getFromCache(ss.str()); +} + +bool ResourceManager::isInCache(const std::string &idPath) const +{ + const ResourceCIterator &resIter = mResources.find(idPath); + return (resIter != mResources.end() && resIter->second); +} + +Resource *ResourceManager::getTempResource(const std::string &idPath) +{ + const ResourceCIterator &resIter = mResources.find(idPath); + if (resIter != mResources.end()) + { + Resource *const res = resIter->second; + if (resIter->second) + return res; + } + return nullptr; +} + +Resource *ResourceManager::getFromCache(const std::string &idPath) +{ + // Check if the id exists, and return the value if it does. + ResourceIterator resIter = mResources.find(idPath); + if (resIter != mResources.end()) + { + if (resIter->second) + resIter->second->incRef(); + return resIter->second; + } + + resIter = mOrphanedResources.find(idPath); + if (resIter != mOrphanedResources.end()) + { + Resource *const res = resIter->second; + mResources.insert(*resIter); + mOrphanedResources.erase(resIter); + if (res) + res->incRef(); + return res; + } + return nullptr; +} + +Resource *ResourceManager::get(const std::string &idPath, + generator fun, + const void *const data) +{ +#ifndef DISABLE_RESOURCE_CACHING + Resource *resource = getFromCache(idPath); + if (resource) + return resource; + resource = fun(data); + + if (resource) + { + resource->incRef(); + resource->mIdPath = idPath; +#ifdef DEBUG_IMAGES + logger->log("set name %p, %s", static_cast(resource), + resource->mIdPath.c_str()); +#endif + mResources[idPath] = resource; + cleanOrphans(); + } + else + { + reportAlways("Error loading image: %s", idPath.c_str()); + } +#else + Resource *resource = fun(data, idPath); + + if (resource) + { + resource->incRef(); + resource->mIdPath = idPath; +#ifdef DEBUG_IMAGES + logger->log("set name %p, %s", static_cast(resource), + resource->mIdPath.c_str()); +#endif + } + else + { + reportAlways("Error loading image: " + idPath); + } +#endif + + // Returns nullptr if the object could not be created. + return resource; +} + +struct ResourceLoader final +{ + ResourceManager *manager; + std::string path; + ResourceManager::loader fun; + + static Resource *load(const void *const v) + { + if (!v) + return nullptr; + const ResourceLoader *const + rl = static_cast(v); + SDL_RWops *const rw = MPHYSFSRWOPS_openRead(rl->path.c_str()); + if (!rw) + { + reportAlways("Error loading resource: %s", + rl->path.c_str()); + return nullptr; + } + Resource *const res = rl->fun(rw, rl->path); + return res; + } +}; + +SDLMusic *ResourceManager::getMusic(const std::string &idPath) +{ + ResourceLoader rl = { this, idPath, &SDLMusic::load }; + return static_cast(get(idPath, ResourceLoader::load, &rl)); +} + +SoundEffect *ResourceManager::getSoundEffect(const std::string &idPath) +{ + ResourceLoader rl = { this, idPath, &SoundEffect::load }; + return static_cast(get(idPath, ResourceLoader::load, &rl)); +} + +struct DyedImageLoader final +{ + ResourceManager *manager; + std::string path; + static Resource *load(const void *const v) + { + BLOCK_START("DyedImageLoader::load") + if (!v) + { + BLOCK_END("DyedImageLoader::load") + return nullptr; + } + + const DyedImageLoader *const rl + = static_cast(v); + if (!rl->manager) + { + BLOCK_END("DyedImageLoader::load") + return nullptr; + } + + std::string path1 = rl->path; + const size_t p = path1.find('|'); + Dye *d = nullptr; + if (p != std::string::npos) + { + d = new Dye(path1.substr(p + 1)); + path1 = path1.substr(0, p); + } + SDL_RWops *const rw = MPHYSFSRWOPS_openRead(path1.c_str()); + if (!rw) + { + delete d; + reportAlways("Image loading error: %s", path1.c_str()); + BLOCK_END("DyedImageLoader::load") + return nullptr; + } + Resource *const res = d ? imageHelper->load(rw, *d) + : imageHelper->load(rw); + delete d; + if (!res) + reportAlways("Image loading error: %s", path1.c_str()); + BLOCK_END("DyedImageLoader::load") + return res; + } +}; + +Image *ResourceManager::getImage(const std::string &idPath) +{ + DyedImageLoader rl = { this, idPath }; + return static_cast(get(idPath, DyedImageLoader::load, &rl)); +} + +struct ImageSetLoader final +{ + ResourceManager *manager; + std::string path; + int w, h; + static Resource *load(const void *const v) + { + if (!v) + return nullptr; + + const ImageSetLoader *const + rl = static_cast(v); + if (!rl->manager) + return nullptr; + + Image *const img = rl->manager->getImage(rl->path); + if (!img) + { + reportAlways("Image loading error: %s", rl->path.c_str()); + return nullptr; + } + ImageSet *const res = new ImageSet(img, rl->w, rl->h); + img->decRef(); + return res; + } +}; + +ImageSet *ResourceManager::getImageSet(const std::string &imagePath, + const int w, const int h) +{ + ImageSetLoader rl = { this, imagePath, w, h }; + std::stringstream ss; + ss << imagePath << "[" << w << "x" << h << "]"; + return static_cast(get(ss.str(), ImageSetLoader::load, &rl)); +} + + +struct SubImageSetLoader final +{ + ResourceManager *manager; + Image *parent; + int width, height; + static Resource *load(const void *const v) + { + if (!v) + return nullptr; + + const SubImageSetLoader *const + rl = static_cast(v); + if (!rl->manager) + return nullptr; + + if (!rl->parent) + return nullptr; + ImageSet *const res = new ImageSet(rl->parent, rl->width, rl->height); + return res; + } +}; + +ImageSet *ResourceManager::getSubImageSet(Image *const parent, + const int width, const int height) +{ + if (!parent) + return nullptr; + + const SubImageSetLoader rl = { this, parent, width, height }; + std::stringstream ss; + ss << parent->getIdPath() << ", set[" << width << "x" << height << "]"; + return static_cast(get(ss.str(), + SubImageSetLoader::load, &rl)); +} + +struct SubImageLoader final +{ + ResourceManager *manager; + Image *parent; + int x, y; + int width, height; + static Resource *load(const void *const v) + { + if (!v) + return nullptr; + + const SubImageLoader *const + rl = static_cast(v); + if (!rl->manager || !rl->parent) + return nullptr; + + Image *const res = rl->parent->getSubImage(rl->x, rl->y, + rl->width, rl->height); + if (!res) + { + reportAlways("SubImage loading error: %s", + rl->parent->getSource().c_str()); + } + return res; + } +}; + +Image *ResourceManager::getSubImage(Image *const parent, + const int x, const int y, + const int width, const int height) +{ + if (!parent) + return nullptr; + + const SubImageLoader rl = { this, parent, x, y, width, height}; + + std::stringstream ss; + ss << parent->getIdPath() << ",[" << x << "," << y << "," + << width << "x" << height << "]"; + return static_cast(get(ss.str(), SubImageLoader::load, &rl)); +} + +#ifdef USE_OPENGL +struct AtlasLoader final +{ + const std::string name; + const StringVect *files; + + static Resource *load(const void *const v) + { + if (!v) + return nullptr; + + const AtlasLoader *const rl = static_cast(v); + AtlasResource *const resource = AtlasManager::loadTextureAtlas( + rl->name, *rl->files); + if (!resource) + reportAlways("Atlas creation error: %s", rl->name.c_str()); + return resource; + } +}; + +Resource *ResourceManager::getAtlas(const std::string &name, + const StringVect &files) +{ + AtlasLoader rl = { name, &files }; + return get("atlas_" + name, AtlasLoader::load, &rl); +} + +struct ShaderLoader final +{ + const std::string name; + const unsigned int type; + + static Resource *load(const void *const v) + { + if (!v) + return nullptr; + + const ShaderLoader *const rl + = static_cast(v); + Shader *const resource = shaders.createShader(rl->type, rl->name); + if (!resource) + reportAlways("Shader creation error: %s", rl->name.c_str()); + return resource; + } +}; + +Resource *ResourceManager::getShader(const unsigned int type, + const std::string &name) +{ + ShaderLoader rl = { name, type }; + return get("shader_" + name, ShaderLoader::load, &rl); +} + +struct ShaderProgramLoader final +{ + const std::string vertex; + const std::string fragment; + const bool isNewShader; + + static Resource *load(const void *const v) + { + if (!v) + return nullptr; + + const ShaderProgramLoader *const rl + = static_cast(v); + ShaderProgram *const resource = shaders.createProgram( + rl->vertex, + rl->fragment, + rl->isNewShader); + if (!resource) + reportAlways("Shader program creation error"); + return resource; + } +}; + +Resource *ResourceManager::getShaderProgram(const std::string &vertex, + const std::string &fragment, + const bool isNewShader) +{ + ShaderProgramLoader rl = { vertex, fragment, isNewShader }; + return get("program_" + vertex + " + " + fragment, + ShaderProgramLoader::load, &rl); +} +#endif + +#ifndef DYECMD +struct WalkLayerLoader final +{ + const std::string name; + Map *map; + + static Resource *load(const void *const v) + { + if (!v) + return nullptr; + + const WalkLayerLoader *const rl = static_cast(v); + Resource *const resource = NavigationManager::loadWalkLayer(rl->map); + if (!resource) + reportAlways("WalkLayer creation error"); + return resource; + } +}; +#endif + +#ifndef DYECMD +WalkLayer *ResourceManager::getWalkLayer(const std::string &name, + Map *const map) +{ + WalkLayerLoader rl = {name, map}; + return static_cast(get("map_" + name, + WalkLayerLoader::load, &rl)); +} +#else +WalkLayer *ResourceManager::getWalkLayer(const std::string &name A_UNUSED, + Map *const map A_UNUSED) +{ + return nullptr; +} +#endif + +struct SpriteDefLoader final +{ + std::string path; + int variant; + bool useLongLiveSprites; + static Resource *load(const void *const v) + { + if (!v) + return nullptr; + + const SpriteDefLoader *const + rl = static_cast(v); + return SpriteDef::load(rl->path, rl->variant, rl->useLongLiveSprites); + } +}; + +SpriteDef *ResourceManager::getSprite(const std::string &path, + const int variant) +{ + SpriteDefLoader rl = { path, variant, mUseLongLiveSprites }; + std::stringstream ss; + ss << path << "[" << variant << "]"; + return static_cast(get(ss.str(), SpriteDefLoader::load, &rl)); +} + +void ResourceManager::release(Resource *const res) +{ + if (!res || mDestruction) + return; + +#ifndef DISABLE_RESOURCE_CACHING + std::set::iterator resDelIter = mDeletedResources.find(res); + if (resDelIter != mDeletedResources.end()) + { + // we found zero counted image in deleted list. deleting it and exit. + mDeletedResources.erase(resDelIter); + delete res; + return; + } + + ResourceIterator resIter = mResources.find(res->mIdPath); + + if (resIter == mResources.end()) + { + reportAlways("no resource in cache: %s", + res->mIdPath.c_str()); + delete res; + return; + } + if (resIter->second != res) + { + reportAlways("in cache other image: %s", + res->mIdPath.c_str()); + delete res; + return; + } + + timeval tv; + gettimeofday(&tv, nullptr); + const time_t timestamp = static_cast(tv.tv_sec); + + res->mTimeStamp = timestamp; + if (mOrphanedResources.empty()) + mOldestOrphan = timestamp; + + mOrphanedResources.insert(*resIter); + mResources.erase(resIter); +#else + delete res; +#endif +} + +void ResourceManager::moveToDeleted(Resource *const res) +{ + if (!res) + return; + + bool found(false); + const int count = res->getRefCount(); + if (count == 1) + logResource(res); + res->decRef(); + ResourceIterator resIter = mResources.find(res->mIdPath); + if (resIter != mResources.end() && resIter->second == res) + { + mResources.erase(resIter); + found = true; + } + else + { + resIter = mOrphanedResources.find(res->mIdPath); + if (resIter != mOrphanedResources.end() && resIter->second == res) + { + mOrphanedResources.erase(resIter); + found = true; + } + } + if (found) + { + if (count > 1) + mDeletedResources.insert(res); + else + delete res; + } +} + +void ResourceManager::decRefDelete(Resource *const res) +{ + if (!res) + return; + + const int count = res->getRefCount(); + if (count == 1) + { + logResource(res); + + ResourceIterator resIter = mResources.find(res->mIdPath); + if (resIter != mResources.end() && resIter->second == res) + { + mResources.erase(resIter); + } + else + { + resIter = mOrphanedResources.find(res->mIdPath); + if (resIter != mOrphanedResources.end() && resIter->second == res) + mOrphanedResources.erase(resIter); + } + + delete res; + } + else + { + res->decRef(); + } +} + +void ResourceManager::deleteInstance() +{ +#ifdef DUMP_LEAKED_RESOURCES + if (instance) + { + logger->log1("clean orphans start"); + instance->cleanProtected(); + while (instance->cleanOrphans(true)) + continue; + logger->log1("clean orphans end"); + ResourceIterator iter = instance->mResources.begin(); + + while (iter != instance->mResources.end()) + { + const Resource *const res = iter->second; + if (res) + { + if (res->getRefCount()) + { + logger->log(std::string("ResourceLeak: ").append( + res->getIdPath()).append(" (").append(toString( + res->getRefCount())).append(")")); + } + } + ++iter; + } + } +#endif + delete2(instance); +} + +SDL_Surface *ResourceManager::loadSDLSurface(const std::string &filename) const +{ + if (SDL_RWops *const rw = MPHYSFSRWOPS_openRead(filename.c_str())) + { + if (!IMG_isPNG(rw)) + { + reportAlways("Error, image is not png: %s", filename.c_str()); + return nullptr; + } + SDL_Surface *const surface = MIMG_LoadPNG_RW(rw); + SDL_RWclose(rw); + return surface; + } + return nullptr; +} + +void ResourceManager::scheduleDelete(SDL_Surface *const surface) +{ + deletedSurfaces.insert(surface); +} + +void ResourceManager::clearScheduled() +{ + BLOCK_START("ResourceManager::clearScheduled") + FOR_EACH (std::set::iterator, i, deletedSurfaces) + MSDL_FreeSurface(*i); + deletedSurfaces.clear(); + BLOCK_END("ResourceManager::clearScheduled") +} + +struct RescaledLoader final +{ + ResourceManager *manager; + const Image *image; + int width; + int height; + static Resource *load(const void *const v) + { + if (!v) + return nullptr; + const RescaledLoader *const rl + = static_cast(v); + if (!rl->manager || !rl->image) + return nullptr; + Image *const rescaled = rl->image->SDLgetScaledImage( + rl->width, rl->height); + if (!rescaled) + { + reportAlways("Rescale image failed: %s", + rl->image->getIdPath().c_str()); + return nullptr; + } + return rescaled; + } +}; + +Image *ResourceManager::getRescaled(const Image *const image, + const int width, const int height) +{ + if (!image) + return nullptr; + + std::string idPath = image->getIdPath() + strprintf( + "_rescaled%dx%d", width, height); + const RescaledLoader rl = { this, image, width, height }; + Image *const img = static_cast( + get(idPath, RescaledLoader::load, &rl)); + return img; +} + +void ResourceManager::clearCache() +{ + cleanProtected(); + while (cleanOrphans(true)) + continue; +} + +int ResourceManager::calcMemoryLocal() const +{ + int sz = sizeof(ResourceManager); + FOR_EACH (std::set::iterator, it, deletedSurfaces) + { + sz += memoryManager.getSurfaceSize(*it); + } + return sz; +} + +int ResourceManager::calcMemoryChilds(const int level) const +{ + int sz = 0; + FOR_EACH (ResourceCIterator, it, mResources) + { + sz += static_cast((*it).first.capacity()); + sz += (*it).second->calcMemory(level + 1); + } + FOR_EACH (ResourceCIterator, it, mOrphanedResources) + { + sz += static_cast((*it).first.capacity()); + sz += (*it).second->calcMemory(level + 1); + } + FOR_EACH (std::set::const_iterator, it, mDeletedResources) + { + sz += (*it)->calcMemory(level + 1); + } + return sz; +} diff --git a/src/resources/resourcemanager/resourcemanager.h b/src/resources/resourcemanager/resourcemanager.h new file mode 100644 index 000000000..2c2caabce --- /dev/null +++ b/src/resources/resourcemanager/resourcemanager.h @@ -0,0 +1,277 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2016 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef RESOURCES_RESOURCEMANAGER_RESOURCEMANAGER_H +#define RESOURCES_RESOURCEMANAGER_RESOURCEMANAGER_H + +#include "resources/memorycounter.h" + +#include "enums/simpletypes/append.h" + +#include "utils/stringvector.h" + +#include +#include + +#include "localconsts.h" + +class Image; +class ImageSet; +class Map; +class SDLMusic; +class Resource; +class SoundEffect; +class SpriteDef; +class WalkLayer; + +struct SDL_Surface; +struct SDL_RWops; + +/** + * A class for loading and managing resources. + */ +class ResourceManager final : public MemoryCounter +{ + friend class Resource; + + public: + typedef Resource *(*loader)(SDL_RWops *rw, + const std::string &name); + typedef Resource *(&generator)(const void *const data); + + ResourceManager(); + + A_DELETE_COPY(ResourceManager) + + /** + * Destructor. Cleans up remaining resources, warning about resources + * that were still referenced. + */ + ~ResourceManager(); + + /** + * Sets the write directory. + * + * @param path The path of the directory to be added. + * @return true on success, false otherwise. + */ + bool setWriteDir(const std::string &path) const; + + /** + * Adds a directory or archive to the search path. If append is true + * then the directory is added to the end of the search path, otherwise + * it is added at the front. + * + * @return true on success, false otherwise. + */ + bool addToSearchPath(const std::string &path, + const Append append) const; + + /** + * Remove a directory or archive from the search path. + * + * @return true on success, false otherwise. + */ + bool removeFromSearchPath(const std::string &path) const; + + /** + * Searches for zip files and adds them to the search path. + */ + void searchAndAddArchives(const std::string &restrict path, + const std::string &restrict ext, + const Append append) const; + + /** + * Searches for zip files and remove them from the search path. + */ + void searchAndRemoveArchives(const std::string &restrict path, + const std::string &restrict ext) const; + + /** + * Creates a resource and adds it to the resource map. + * + * @param idPath The resource identifier path. + * @param fun A function for generating the resource. + * @param data Extra parameters for the generator. + * @return A valid resource or NULL if the resource could + * not be generated. + */ + Resource *get(const std::string &idPath, + generator fun, + const void *const data) A_WARN_UNUSED; + + Resource *getFromCache(const std::string &idPath) A_WARN_UNUSED; + + Resource *getFromCache(const std::string &filename, + const int variant) A_WARN_UNUSED; + + /** + * Adds a preformatted resource to the resource map. + * + * @param path The file name. + * @param Resource The Resource to add. + * @return true if successfull, false otherwise. + */ + bool addResource(const std::string &idPath, Resource *const resource); + + /** + * Convenience wrapper around ResourceManager::get for loading + * images. + */ + Image *getImage(const std::string &idPath) A_WARN_UNUSED; + + /** + * Convenience wrapper around ResourceManager::get for loading + * songs. + */ + SDLMusic *getMusic(const std::string &idPath) A_WARN_UNUSED; + + /** + * Convenience wrapper around ResourceManager::get for loading + * samples. + */ + SoundEffect *getSoundEffect(const std::string &idPath) A_WARN_UNUSED; + + /** + * Creates a image set based on the image referenced by the given + * path and the supplied sprite sizes + */ + ImageSet *getImageSet(const std::string &imagePath, + const int w, const int h) A_WARN_UNUSED; + + ImageSet *getSubImageSet(Image *const parent, + const int width, + const int height) A_WARN_UNUSED; + + Image *getSubImage(Image *const parent, const int x, const int y, + const int width, const int height) A_WARN_UNUSED; + +#ifdef USE_OPENGL + Resource *getAtlas(const std::string &name, + const StringVect &files) A_WARN_UNUSED; + + Resource *getShader(const unsigned int type, + const std::string &name) A_WARN_UNUSED; + + Resource *getShaderProgram(const std::string &vertex, + const std::string &fragment, + const bool isNewShader) A_WARN_UNUSED; +#endif + + WalkLayer *getWalkLayer(const std::string &name, Map *const map); + + /** + * Creates a sprite definition based on a given path and the supplied + * variant. + */ + SpriteDef *getSprite(const std::string &path, + const int variant = 0) A_WARN_UNUSED; + + /** + * Releases a resource, placing it in the set of orphaned resources. + */ + void release(Resource *const res); + + void clearDeleted(const bool full = true); + + void decRefDelete(Resource *const res); + + /** + * Move resource to deleted resources list. + */ + void moveToDeleted(Resource *const res); + + Image *getRescaled(const Image *const image, + const int width, + const int height) A_WARN_UNUSED; + + /** + * Loads the given filename as an SDL surface. The returned surface is + * expected to be freed by the caller using SDL_FreeSurface. + */ + SDL_Surface *loadSDLSurface(const std::string &filename) + const A_WARN_UNUSED; + + void scheduleDelete(SDL_Surface *const surface); + + void clearScheduled(); + + /** + * Deletes the class instance if it exists. + */ + static void deleteInstance(); + + int size() const A_WARN_UNUSED + { return CAST_S32(mResources.size()); } + + typedef std::map Resources; + typedef Resources::iterator ResourceIterator; + typedef Resources::const_iterator ResourceCIterator; + +#ifdef DEBUG_DUMP_LEAKS + Resources* getResources() A_WARN_UNUSED + { return &mResources; } + + Resources* getOrphanedResources() A_WARN_UNUSED + { return &mOrphanedResources; } +#endif + + bool cleanOrphans(const bool always = false); + + void cleanProtected(); + + bool isInCache(const std::string &idPath) const A_WARN_UNUSED; + + Resource *getTempResource(const std::string &idPath) A_WARN_UNUSED; + + void clearCache(); + + int calcMemoryLocal() const override final; + + int calcMemoryChilds(const int level) const override final; + + std::string getCounterName() const override final + { return "ResourceManager"; } + + static void init(); + + private: + /** + * Deletes the resource after logging a cleanup message. + */ + static void cleanUp(Resource *const resource); + + static void logResource(const Resource *const res); + + static ResourceManager *instance; + std::set deletedSurfaces; + Resources mResources; + Resources mOrphanedResources; + std::set mDeletedResources; + time_t mOldestOrphan; + bool mDestruction; + bool mUseLongLiveSprites; +}; + +extern ResourceManager *resourceManager; + +#endif // RESOURCES_RESOURCEMANAGER_RESOURCEMANAGER_H diff --git a/src/resources/sdl2imagehelper.cpp b/src/resources/sdl2imagehelper.cpp index 9cca68e21..9bd66c3e4 100644 --- a/src/resources/sdl2imagehelper.cpp +++ b/src/resources/sdl2imagehelper.cpp @@ -24,16 +24,16 @@ #include "resources/sdl2imagehelper.h" -#include "resources/resourcemanager.h" - -#include "resources/dye/dye.h" -#include "resources/dye/dyepalette.h" - #include "logger.h" #include "main.h" #include "resources/image.h" +#include "resources/dye/dye.h" +#include "resources/dye/dyepalette.h" + +#include "resources/resourcemanager/resourcemanager.h" + #include "utils/sdlcheckutils.h" #include diff --git a/src/resources/sdl2softwareimagehelper.cpp b/src/resources/sdl2softwareimagehelper.cpp index 5b9ffce14..375f08cc5 100644 --- a/src/resources/sdl2softwareimagehelper.cpp +++ b/src/resources/sdl2softwareimagehelper.cpp @@ -24,15 +24,15 @@ #include "resources/sdl2softwareimagehelper.h" -#include "resources/resourcemanager.h" - -#include "resources/dye/dye.h" - #include "logger.h" #include "main.h" +#include "resources/dye/dye.h" + #include "resources/image.h" +#include "resources/resourcemanager/resourcemanager.h" + #include "utils/sdlcheckutils.h" #include diff --git a/src/resources/sprite/animatedsprite.cpp b/src/resources/sprite/animatedsprite.cpp index 87fe72a7b..6ada9c394 100644 --- a/src/resources/sprite/animatedsprite.cpp +++ b/src/resources/sprite/animatedsprite.cpp @@ -29,10 +29,11 @@ #include "resources/action.h" #include "resources/delayedmanager.h" #include "resources/image.h" -#include "resources/resourcemanager.h" #include "resources/animation/animation.h" +#include "resources/resourcemanager/resourcemanager.h" + #include "resources/sprite/animationdelayload.h" #include "utils/delete2.h" diff --git a/src/resources/sprite/animatedsprite_unittest.cc b/src/resources/sprite/animatedsprite_unittest.cc index f9b6e65a9..1a77ea38f 100644 --- a/src/resources/sprite/animatedsprite_unittest.cc +++ b/src/resources/sprite/animatedsprite_unittest.cc @@ -30,11 +30,12 @@ #include "gui/theme.h" -#include "resources/resourcemanager.h" #include "resources/sdlimagehelper.h" #include "resources/animation/animation.h" +#include "resources/resourcemanager/resourcemanager.h" + #include "utils/env.h" #include "utils/mrand.h" #include "utils/physfstools.h" diff --git a/src/resources/sprite/animationdelayload.cpp b/src/resources/sprite/animationdelayload.cpp index ab0362337..fa33ff5f5 100644 --- a/src/resources/sprite/animationdelayload.cpp +++ b/src/resources/sprite/animationdelayload.cpp @@ -22,7 +22,7 @@ #include "const/resources/spriteaction.h" -#include "resources/resourcemanager.h" +#include "resources/resourcemanager/resourcemanager.h" #include "resources/sprite/animatedsprite.h" diff --git a/src/resources/sprite/spritedef.cpp b/src/resources/sprite/spritedef.cpp index 01651bd80..25c5952e3 100644 --- a/src/resources/sprite/spritedef.cpp +++ b/src/resources/sprite/spritedef.cpp @@ -34,12 +34,13 @@ #include "resources/action.h" #include "resources/imageset.h" -#include "resources/resourcemanager.h" #include "resources/animation/animation.h" #include "resources/dye/dye.h" +#include "resources/resourcemanager/resourcemanager.h" + #include "resources/sprite/spritereference.h" #include "debug.h" diff --git a/src/resources/surfaceimagehelper.cpp b/src/resources/surfaceimagehelper.cpp index 69e011219..effba4abd 100644 --- a/src/resources/surfaceimagehelper.cpp +++ b/src/resources/surfaceimagehelper.cpp @@ -24,15 +24,15 @@ #include "resources/surfaceimagehelper.h" -#include "resources/resourcemanager.h" - -#include "resources/dye/dye.h" - #include "logger.h" #include "main.h" #include "resources/image.h" +#include "resources/dye/dye.h" + +#include "resources/resourcemanager/resourcemanager.h" + #include "utils/sdlcheckutils.h" #include -- cgit v1.2.3-70-g09d2