From c8900f40998c1ededb8aaf1a799a75b7f9965a47 Mon Sep 17 00:00:00 2001 From: Aloshi Date: Tue, 9 Jul 2013 00:44:24 -0500 Subject: [PATCH] Moved to class-individualized static gets for resources. See issue #95 for discussion. --- CMakeLists.txt | 2 - src/Font.cpp | 44 +++++++-- src/Font.h | 20 +++-- src/Window.cpp | 10 +-- src/Window.h | 1 + src/components/GuiDetectDevice.cpp | 2 +- src/components/GuiGameList.cpp | 4 +- src/components/GuiInputConfig.cpp | 2 +- src/components/GuiMenu.cpp | 2 +- src/components/ImageComponent.cpp | 8 +- src/components/SwitchComponent.cpp | 4 +- src/components/TextComponent.cpp | 2 +- src/components/ThemeComponent.cpp | 8 +- src/main.cpp | 2 +- src/resources/Resource.cpp | 0 src/resources/Resource.h | 14 --- src/resources/ResourceManager.cpp | 140 +++++++++++++---------------- src/resources/ResourceManager.h | 47 +++++----- src/resources/TextureResource.cpp | 84 ++++++++++++----- src/resources/TextureResource.h | 28 ++++-- 20 files changed, 246 insertions(+), 178 deletions(-) delete mode 100644 src/resources/Resource.cpp delete mode 100644 src/resources/Resource.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d0dd734f5..ad702e745 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -151,7 +151,6 @@ set(ES_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/pugiXML/pugiconfig.hpp ${CMAKE_CURRENT_SOURCE_DIR}/src/pugiXML/pugixml.hpp ${CMAKE_CURRENT_SOURCE_DIR}/src/resources/ResourceManager.h - ${CMAKE_CURRENT_SOURCE_DIR}/src/resources/Resource.h ${CMAKE_CURRENT_SOURCE_DIR}/src/resources/TextureResource.h ${CMAKE_CURRENT_SOURCE_DIR}/data/Resources.h ) @@ -193,7 +192,6 @@ set(ES_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiSettingsMenu.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/pugiXML/pugixml.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/resources/ResourceManager.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/resources/Resource.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/resources/TextureResource.cpp ${CMAKE_CURRENT_SOURCE_DIR}/data/logo/ES_logo_16.cpp ${CMAKE_CURRENT_SOURCE_DIR}/data/logo/ES_logo_32.cpp diff --git a/src/Font.cpp b/src/Font.cpp index 1645134db..dc139ee89 100644 --- a/src/Font.cpp +++ b/src/Font.cpp @@ -14,6 +14,8 @@ int Font::getDpiY() { return 96; } int Font::getSize() { return mSize; } +std::map< std::pair, std::weak_ptr > Font::sFontMap; + std::string Font::getDefaultPath() { const int fontCount = 4; @@ -69,8 +71,9 @@ void Font::initLibrary() } } -Font::Font(int size) : fontScale(1.0f), mSize(size) +Font::Font(const ResourceManager& rm, const std::string& path, int size) : fontScale(1.0f), mSize(size), mPath(path) { + reload(rm); } Font::~Font() @@ -78,6 +81,38 @@ Font::~Font() deinit(); } +void Font::reload(const ResourceManager& rm) +{ + init(rm.getFileData(mPath)); +} + +void Font::unload(const ResourceManager& rm) +{ + deinit(); +} + +std::shared_ptr Font::get(ResourceManager& rm, const std::string& path, int size) +{ + if(path.empty()) + { + LOG(LogError) << "Tried to get font with no path!"; + return std::shared_ptr(); + } + + std::pair def(path, size); + auto foundFont = sFontMap.find(def); + if(foundFont != sFontMap.end()) + { + if(!foundFont->second.expired()) + return foundFont->second.lock(); + } + + std::shared_ptr font = std::shared_ptr(new Font(rm, path, size)); + sFontMap[def] = std::weak_ptr(font); + rm.addReloadable(font); + return font; +} + void Font::init(ResourceData data) { if(!libraryInitialized) @@ -96,7 +131,7 @@ void Font::deinit() void Font::buildAtlas(ResourceData data) { - if(FT_New_Memory_Face(sLibrary, data.ptr, data.length, 0, &face)) + if(FT_New_Memory_Face(sLibrary, data.ptr.get(), data.length, 0, &face)) { LOG(LogError) << "Error creating font face!"; return; @@ -206,9 +241,8 @@ void Font::buildAtlas(ResourceData data) mSize = (int)(mSize * (1.0f / fontScale)); deinit(); init(data); - } - else { - //LOG(LogInfo) << "Created font with size " << mSize << "."; + }else{ + LOG(LogInfo) << "Created font with size " << mSize << "."; } } diff --git a/src/Font.h b/src/Font.h index 5da296dfc..61c054031 100644 --- a/src/Font.h +++ b/src/Font.h @@ -7,7 +7,7 @@ #include #include FT_FREETYPE_H #include "Vector2.h" -#include "resources/Resource.h" +#include "resources/ResourceManager.h" class TextCache; @@ -17,12 +17,13 @@ class TextCache; //A TrueType Font renderer that uses FreeType and OpenGL. //The library is automatically initialized when it's needed. -class Font : public Resource +class Font : public IReloadable { public: static void initLibrary(); - Font(int size); + static std::shared_ptr get(ResourceManager& rm, const std::string& path, int size); + ~Font(); FT_Face face; @@ -55,12 +56,11 @@ public: void drawWrappedText(std::string text, int xStart, int yStart, int xLen, unsigned int color); void sizeWrappedText(std::string text, int xLen, int* xOut, int* yOut); void drawCenteredText(std::string text, int xOffset, int y, unsigned int color); - int getHeight(); - void init(ResourceData data) override; - void deinit() override; + void unload(const ResourceManager& rm) override; + void reload(const ResourceManager& rm) override; int getSize(); @@ -72,6 +72,13 @@ private: static FT_Library sLibrary; static bool libraryInitialized; + static std::map< std::pair, std::weak_ptr > sFontMap; + + Font(const ResourceManager& rm, const std::string& path, int size); + + void init(ResourceData data); + void deinit(); + void buildAtlas(ResourceData data); //Builds a "texture atlas," one big OpenGL texture with glyphs 32 to 128. int textureWidth; //OpenGL texture width @@ -80,6 +87,7 @@ private: float fontScale; //! 1.0 if the font would be to big for the texture int mSize; + const std::string mPath; }; class TextCache diff --git a/src/Window.cpp b/src/Window.cpp index 1fdfc1b14..d1a789939 100644 --- a/src/Window.cpp +++ b/src/Window.cpp @@ -8,9 +8,9 @@ Window::Window() { mInputManager = new InputManager(this); - mDefaultFonts.push_back(mResourceManager.getFont(Font::getDefaultPath(), FONT_SIZE_SMALL)); - mDefaultFonts.push_back(mResourceManager.getFont(Font::getDefaultPath(), FONT_SIZE_MEDIUM)); - mDefaultFonts.push_back(mResourceManager.getFont(Font::getDefaultPath(), FONT_SIZE_LARGE)); + mDefaultFonts.push_back(Font::get(mResourceManager, Font::getDefaultPath(), FONT_SIZE_SMALL)); + mDefaultFonts.push_back(Font::get(mResourceManager, Font::getDefaultPath(), FONT_SIZE_MEDIUM)); + mDefaultFonts.push_back(Font::get(mResourceManager, Font::getDefaultPath(), FONT_SIZE_LARGE)); } Window::~Window() @@ -59,7 +59,7 @@ void Window::init() { mInputManager->init(); //shouldn't this go AFTER renderer initialization? Renderer::init(0, 0); - mResourceManager.init(); + mResourceManager.reloadAll(); for(unsigned int i = 0; i < mGuiStack.size(); i++) { @@ -75,7 +75,7 @@ void Window::deinit() } mInputManager->deinit(); - mResourceManager.deinit(); + mResourceManager.unloadAll(); Renderer::deinit(); } diff --git a/src/Window.h b/src/Window.h index 399f971e8..400f868ae 100644 --- a/src/Window.h +++ b/src/Window.h @@ -5,6 +5,7 @@ #include "InputManager.h" #include "resources/ResourceManager.h" #include +#include "Font.h" class Window { diff --git a/src/components/GuiDetectDevice.cpp b/src/components/GuiDetectDevice.cpp index af4a61472..a2b7f5fce 100644 --- a/src/components/GuiDetectDevice.cpp +++ b/src/components/GuiDetectDevice.cpp @@ -83,7 +83,7 @@ void GuiDetectDevice::update(int deltaTime) void GuiDetectDevice::render() { - std::shared_ptr font = mWindow->getResourceManager()->getFont(Font::getDefaultPath(), FONT_SIZE_MEDIUM); + std::shared_ptr font = Font::get(*mWindow->getResourceManager(), Font::getDefaultPath(), FONT_SIZE_MEDIUM); std::string playerString; std::stringstream stream; diff --git a/src/components/GuiGameList.cpp b/src/components/GuiGameList.cpp index 404f5a7f9..170c1394c 100644 --- a/src/components/GuiGameList.cpp +++ b/src/components/GuiGameList.cpp @@ -26,7 +26,7 @@ bool GuiGameList::isDetailed() const GuiGameList::GuiGameList(Window* window) : GuiComponent(window), mTheme(new ThemeComponent(mWindow)), - mList(window, 0, 0, window->getResourceManager()->getFont(Font::getDefaultPath(), FONT_SIZE_MEDIUM)), + mList(window, 0, 0, Font::get(*window->getResourceManager(), Font::getDefaultPath(), FONT_SIZE_MEDIUM)), mScreenshot(window), mDescription(window), mDescContainer(window), @@ -114,7 +114,7 @@ void GuiGameList::render() if(mTheme) mTheme->render(); - std::shared_ptr headerFont = mWindow->getResourceManager()->getFont(Font::getDefaultPath(), FONT_SIZE_LARGE); + std::shared_ptr headerFont = Font::get(*mWindow->getResourceManager(), Font::getDefaultPath(), FONT_SIZE_LARGE); //header if(!mTheme->getBool("hideHeader")) diff --git a/src/components/GuiInputConfig.cpp b/src/components/GuiInputConfig.cpp index 0c84ae83b..9ca26bf88 100644 --- a/src/components/GuiInputConfig.cpp +++ b/src/components/GuiInputConfig.cpp @@ -77,7 +77,7 @@ bool GuiInputConfig::input(InputConfig* config, Input input) void GuiInputConfig::render() { - std::shared_ptr font = mWindow->getResourceManager()->getFont(Font::getDefaultPath(), FONT_SIZE_MEDIUM); + std::shared_ptr font = Font::get(*mWindow->getResourceManager(), Font::getDefaultPath(), FONT_SIZE_MEDIUM); std::stringstream stream; stream << "PLAYER " << mTargetConfig->getPlayerNum() + 1 << ", press..."; diff --git a/src/components/GuiMenu.cpp b/src/components/GuiMenu.cpp index df18029b1..ad02bdd01 100644 --- a/src/components/GuiMenu.cpp +++ b/src/components/GuiMenu.cpp @@ -11,7 +11,7 @@ GuiMenu::GuiMenu(Window* window, GuiGameList* parent) : GuiComponent(window) { mParent = parent; - std::shared_ptr font = mWindow->getResourceManager()->getFont(Font::getDefaultPath(), FONT_SIZE_LARGE); + std::shared_ptr font = Font::get(*mWindow->getResourceManager(), Font::getDefaultPath(), FONT_SIZE_LARGE); mList = new TextListComponent(mWindow, 0, font->getHeight() + 2, font); mList->setSelectedTextColor(0x0000FFFF); populateList(); diff --git a/src/components/ImageComponent.cpp b/src/components/ImageComponent.cpp index 3aa689839..22e8d1bfc 100644 --- a/src/components/ImageComponent.cpp +++ b/src/components/ImageComponent.cpp @@ -86,7 +86,11 @@ void ImageComponent::setImage(std::string path) mPath = path; - mTexture = mWindow->getResourceManager()->getTexture(path); + if(mPath.empty() || !mWindow->getResourceManager()->fileExists(mPath)) + mTexture.reset(); + else + mTexture = TextureResource::get(*mWindow->getResourceManager(), mPath); + resize(); } @@ -229,7 +233,7 @@ void ImageComponent::copyScreen() { mTexture.reset(); - mTexture = std::make_shared(); + mTexture = TextureResource::get(*mWindow->getResourceManager(), ""); mTexture->initFromScreen(); resize(); diff --git a/src/components/SwitchComponent.cpp b/src/components/SwitchComponent.cpp index ac0bc58ef..c6f9c9c11 100644 --- a/src/components/SwitchComponent.cpp +++ b/src/components/SwitchComponent.cpp @@ -8,7 +8,7 @@ SwitchComponent::SwitchComponent(Window* window, bool state) : GuiComponent(wind //mSize = Vector2u((unsigned int)(Renderer::getScreenWidth() * 0.05), // (unsigned int)(Renderer::getScreenHeight() * 0.05)); - mWindow->getResourceManager()->getFont(Font::getDefaultPath(), FONT_SIZE_MEDIUM)->sizeText("OFF", (int*)&mSize.x, (int*)&mSize.y); + Font::get(*mWindow->getResourceManager(), Font::getDefaultPath(), FONT_SIZE_MEDIUM)->sizeText("OFF", (int*)&mSize.x, (int*)&mSize.y); } bool SwitchComponent::input(InputConfig* config, Input input) @@ -26,7 +26,7 @@ void SwitchComponent::onRender() { Renderer::pushClipRect(getGlobalOffset(), getSize()); - mWindow->getResourceManager()->getFont(Font::getDefaultPath(), FONT_SIZE_MEDIUM)->drawText(mState ? "ON" : "OFF", 0, 0, mState ? 0x00FF00FF : 0xFF0000FF); + Font::get(*mWindow->getResourceManager(), Font::getDefaultPath(), FONT_SIZE_MEDIUM)->drawText(mState ? "ON" : "OFF", 0, 0, mState ? 0x00FF00FF : 0xFF0000FF); Renderer::popClipRect(); diff --git a/src/components/TextComponent.cpp b/src/components/TextComponent.cpp index 5f6dd10a4..76ff12443 100644 --- a/src/components/TextComponent.cpp +++ b/src/components/TextComponent.cpp @@ -53,7 +53,7 @@ std::shared_ptr TextComponent::getFont() const if(mFont) return mFont; else - return mWindow->getResourceManager()->getFont(Font::getDefaultPath(), FONT_SIZE_MEDIUM); + return Font::get(*mWindow->getResourceManager(), Font::getDefaultPath(), FONT_SIZE_MEDIUM); } void TextComponent::onRender() diff --git a/src/components/ThemeComponent.cpp b/src/components/ThemeComponent.cpp index 0a9453dee..9643f3dbf 100644 --- a/src/components/ThemeComponent.cpp +++ b/src/components/ThemeComponent.cpp @@ -40,7 +40,7 @@ std::shared_ptr ThemeComponent::getListFont() if(mListFont) return mListFont; else - return mWindow->getResourceManager()->getFont(Font::getDefaultPath(), FONT_SIZE_MEDIUM); + return Font::get(*mWindow->getResourceManager(), Font::getDefaultPath(), FONT_SIZE_MEDIUM); } std::shared_ptr ThemeComponent::getDescriptionFont() @@ -48,7 +48,7 @@ std::shared_ptr ThemeComponent::getDescriptionFont() if(mDescFont) return mDescFont; else - return mWindow->getResourceManager()->getFont(Font::getDefaultPath(), FONT_SIZE_SMALL); + return Font::get(*mWindow->getResourceManager(), Font::getDefaultPath(), FONT_SIZE_SMALL); } std::shared_ptr ThemeComponent::getFastSelectFont() @@ -56,7 +56,7 @@ std::shared_ptr ThemeComponent::getFastSelectFont() if(mFastSelectFont == NULL) return mFastSelectFont; else - return mWindow->getResourceManager()->getFont(Font::getDefaultPath(), FONT_SIZE_LARGE); + return Font::get(*mWindow->getResourceManager(), Font::getDefaultPath(), FONT_SIZE_LARGE); } ThemeComponent::ThemeComponent(Window* window) : GuiComponent(window) @@ -410,5 +410,5 @@ std::shared_ptr ThemeComponent::resolveFont(pugi::xml_node node, std::stri size = defaultSize; } - return mWindow->getResourceManager()->getFont(path, size); + return Font::get(*mWindow->getResourceManager(), path, size); } diff --git a/src/main.cpp b/src/main.cpp index e5cacd5fb..d4ff84d7d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -211,7 +211,7 @@ int main(int argc, char* argv[]) nrOfFrames = 0; timeElapsed = 0; } - window.getResourceManager()->getFont(Font::getDefaultPath(), FONT_SIZE_MEDIUM)->drawText(fpsString, 50, 50, 0x00FF00FF); + Font::get(*window.getResourceManager(), Font::getDefaultPath(), FONT_SIZE_MEDIUM)->drawText(fpsString, 50, 50, 0x00FF00FF); } //sleep if we're past our threshold diff --git a/src/resources/Resource.cpp b/src/resources/Resource.cpp deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/resources/Resource.h b/src/resources/Resource.h deleted file mode 100644 index 178453a0c..000000000 --- a/src/resources/Resource.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -struct ResourceData -{ - const unsigned char* ptr; - const size_t length; -}; - -class Resource -{ -public: - virtual void init(ResourceData data) = 0; - virtual void deinit() = 0; -}; diff --git a/src/resources/ResourceManager.cpp b/src/resources/ResourceManager.cpp index 7b0b7d768..1141a78c3 100644 --- a/src/resources/ResourceManager.cpp +++ b/src/resources/ResourceManager.cpp @@ -1,6 +1,13 @@ #include "ResourceManager.h" #include "../Log.h" #include +#include + +namespace fs = boost::filesystem; + +auto array_deleter = [](unsigned char* p) { delete[] p; }; +auto nop_deleter = [](unsigned char* p) { }; + //from ES_logo_16.cpp extern const size_t es_logo_16_data_len; @@ -18,96 +25,35 @@ struct EmbeddedResource static const int embedded_resource_count = 2; static const EmbeddedResource embedded_resources[embedded_resource_count] = { - { "internal://es_logo_16.png", {es_logo_16_data, es_logo_16_data_len} }, - { "internal://es_logo_32.png", {es_logo_32_data, es_logo_32_data_len} } + { "internal://es_logo_16.png", {std::shared_ptr((unsigned char*)es_logo_16_data, nop_deleter), es_logo_16_data_len} }, + { "internal://es_logo_32.png", {std::shared_ptr((unsigned char*)es_logo_32_data, nop_deleter), es_logo_32_data_len} } }; -std::shared_ptr ResourceManager::getTexture(const std::string& path) -{ - if(path.empty()) - return std::shared_ptr(); //NULL pointer - if(mTextureMap[path].expired()) - { - std::shared_ptr ret(new TextureResource()); - mTextureMap[path] = std::weak_ptr(ret); - - initializeResource(path, ret); - - return ret; - } - - return mTextureMap[path].lock(); -} - -std::shared_ptr ResourceManager::getFont(const std::string& path, int size) -{ - if(path.empty() || size == 0) - return std::shared_ptr(); //NULL pointer - - std::pair fontDef(path, size); - if(mFontMap[fontDef].expired()) - { - std::shared_ptr ret(new Font(size)); - mFontMap[fontDef] = std::weak_ptr(ret); - - initializeResource(path, ret); - - return ret; - } - - return mFontMap[fontDef].lock(); -} - -void ResourceManager::init() -{ - for(auto iter = mTextureMap.begin(); iter != mTextureMap.end(); iter++) - { - if(!iter->second.expired()) - initializeResource(iter->first, iter->second.lock()); - } - - for(auto iter = mFontMap.begin(); iter != mFontMap.end(); iter++) - { - if(!iter->second.expired()) - initializeResource(iter->first.first, iter->second.lock()); - } -} - -void ResourceManager::deinit() -{ - for(auto iter = mTextureMap.begin(); iter != mTextureMap.end(); iter++) - { - if(!iter->second.expired()) - iter->second.lock()->deinit(); - } - - for(auto iter = mFontMap.begin(); iter != mFontMap.end(); iter++) - { - if(!iter->second.expired()) - iter->second.lock()->deinit(); - } -} - -void ResourceManager::initializeResource(const std::string& path, std::shared_ptr resource) +const ResourceData ResourceManager::getFileData(const std::string& path) const { for(int i = 0; i < embedded_resource_count; i++) { if(strcmp(embedded_resources[i].internal_path, path.c_str()) == 0) { //this embedded resource matches the filepath; use it - resource->init(embedded_resources[i].resourceData); - return; + return embedded_resources[i].resourceData; } } - //it's not embedded; load the file, initialize with it, then free the file - ResourceData data = loadFile(path); - resource->init(data); - delete[] data.ptr; + //it's not embedded; load the file + if(!fs::exists(path)) + { + //if the file doesn't exist, return an "empty" ResourceData + ResourceData data = {NULL, 0}; + return data; + }else{ + ResourceData data = loadFile(path); + return data; + } } -ResourceData ResourceManager::loadFile(const std::string& path) +ResourceData ResourceManager::loadFile(const std::string& path) const { std::ifstream stream(path, std::ios::binary); @@ -115,10 +61,48 @@ ResourceData ResourceManager::loadFile(const std::string& path) size_t size = (size_t)stream.tellg(); stream.seekg(0, stream.beg); - unsigned char* data = new unsigned char[size]; - stream.read((char*)data, size); + //supply custom deleter to properly free array + std::shared_ptr data(new unsigned char[size], array_deleter); + stream.read((char*)data.get(), size); stream.close(); ResourceData ret = {data, size}; return ret; } + +bool ResourceManager::fileExists(const std::string& path) const +{ + for(int i = 0; i < embedded_resource_count; i++) + { + if(strcmp(embedded_resources[i].internal_path, path.c_str()) == 0) + { + //this embedded resource matches the filepath + return true; + } + } + + return fs::exists(path); +} + +void ResourceManager::unloadAll() +{ + for(auto iter = mReloadables.begin(); iter != mReloadables.end(); iter++) + { + if(!iter->expired()) + iter->lock()->unload(*this); + } +} + +void ResourceManager::reloadAll() +{ + for(auto iter = mReloadables.begin(); iter != mReloadables.end(); iter++) + { + if(!iter->expired()) + iter->lock()->reload(*this); + } +} + +void ResourceManager::addReloadable(std::weak_ptr reloadable) +{ + mReloadables.push_back(reloadable); +} diff --git a/src/resources/ResourceManager.h b/src/resources/ResourceManager.h index eecb73ddb..b293c55e2 100644 --- a/src/resources/ResourceManager.h +++ b/src/resources/ResourceManager.h @@ -3,35 +3,40 @@ #include #include #include -#include "Resource.h" -#include "TextureResource.h" -#include "../Font.h" +#include -//The ResourceManager exists to: -//1. Automatically deal with initializing/deinitializing various resources (OpenGL textures, SDL audio) -//2. Allow loading resources embedded into the executable like an actual file. -// a. Allow embedded resources to be optionally remapped to actual files for further customization. -//3. Keep from creating duplicate resources. +//The ResourceManager exists to... +//Allow loading resources embedded into the executable like an actual file. +//Allow embedded resources to be optionally remapped to actual files for further customization. -//The ResourceManager returns resources as std::shared_ptrs. -//When the resource no longer has any references, it will be automatically freed. -//If ES launches a game, all resources will have deinit() called on them and SDL will deinitialize. -//Once the game exits and ES returns, resources will have init() called on them. +struct ResourceData +{ + const std::shared_ptr ptr; + const size_t length; +}; + +class ResourceManager; + +class IReloadable +{ +public: + virtual void unload(const ResourceManager& rm) = 0; + virtual void reload(const ResourceManager& rm) = 0; +}; class ResourceManager { public: - std::shared_ptr getTexture(const std::string& path); - std::shared_ptr getFont(const std::string& path, int size); + void addReloadable(std::weak_ptr reloadable); - void init(); - void deinit(); + void unloadAll(); + void reloadAll(); + + const ResourceData getFileData(const std::string& path) const; + bool fileExists(const std::string& path) const; private: - void initializeResource(const std::string& path, std::shared_ptr resource); - ResourceData loadFile(const std::string& path); + ResourceData loadFile(const std::string& path) const; - std::map< std::string, std::weak_ptr > mTextureMap; - - std::map< std::pair, std::weak_ptr > mFontMap; + std::vector< std::weak_ptr > mReloadables; }; diff --git a/src/resources/TextureResource.cpp b/src/resources/TextureResource.cpp index 13bf7c593..075d70326 100644 --- a/src/resources/TextureResource.cpp +++ b/src/resources/TextureResource.cpp @@ -5,8 +5,11 @@ #include "../ImageIO.h" #include "../Renderer.h" -TextureResource::TextureResource() : mTextureID(0) +std::map< std::string, std::weak_ptr > TextureResource::sTextureMap; + +TextureResource::TextureResource(const ResourceManager& rm, const std::string& path) : mTextureID(0), mPath(path) { + reload(rm); } TextureResource::~TextureResource() @@ -14,17 +17,28 @@ TextureResource::~TextureResource() deinit(); } -void TextureResource::init(ResourceData data) +void TextureResource::unload(const ResourceManager& rm) +{ + deinit(); +} + +void TextureResource::reload(const ResourceManager& rm) +{ + if(!mPath.empty()) + initFromResource(rm.getFileData(mPath)); +} + +void TextureResource::initFromResource(const ResourceData data) { //make sure we aren't going to leak an old texture deinit(); size_t width, height; - std::vector imageRGBA = ImageIO::loadFromMemoryRGBA32(data.ptr, data.length, width, height); + std::vector imageRGBA = ImageIO::loadFromMemoryRGBA32(const_cast(data.ptr.get()), data.length, width, height); if(imageRGBA.size() == 0) { - LOG(LogError) << "Could not initialize texture!"; + LOG(LogError) << "Could not initialize texture (invalid resource data)!"; return; } @@ -44,25 +58,6 @@ void TextureResource::init(ResourceData data) mTextureSize.y = height; } -void TextureResource::deinit() -{ - if(mTextureID != 0) - { - glDeleteTextures(1, &mTextureID); - mTextureID = 0; - } -} - -Vector2u TextureResource::getSize() -{ - return mTextureSize; -} - -void TextureResource::bind() -{ - glBindTexture(GL_TEXTURE_2D, mTextureID); -} - void TextureResource::initFromScreen() { deinit(); @@ -84,3 +79,46 @@ void TextureResource::initFromScreen() mTextureSize.x = height; mTextureSize.y = height; } + +void TextureResource::deinit() +{ + if(mTextureID != 0) + { + glDeleteTextures(1, &mTextureID); + mTextureID = 0; + } +} + +Vector2u TextureResource::getSize() const +{ + return mTextureSize; +} + +void TextureResource::bind() const +{ + if(mTextureID != 0) + glBindTexture(GL_TEXTURE_2D, mTextureID); + else + LOG(LogError) << "Tried to bind uninitialized texture!"; +} + + +std::shared_ptr TextureResource::get(ResourceManager& rm, const std::string& path) +{ + if(path.empty()) + return std::shared_ptr(new TextureResource(rm, path)); + + auto foundTexture = sTextureMap.find(path); + if(foundTexture != sTextureMap.end()) + { + if(!foundTexture->second.expired()) + { + return foundTexture->second.lock(); + } + } + + std::shared_ptr tex = std::shared_ptr(new TextureResource(rm, path)); + sTextureMap[path] = std::weak_ptr(tex); + rm.addReloadable(tex); + return tex; +} diff --git a/src/resources/TextureResource.h b/src/resources/TextureResource.h index 5137fb80c..723808c80 100644 --- a/src/resources/TextureResource.h +++ b/src/resources/TextureResource.h @@ -1,27 +1,37 @@ #pragma once -#include "Resource.h" +#include "ResourceManager.h" #include #include "../Vector2.h" #include "../platform.h" #include GLHEADER -class TextureResource : public Resource +class TextureResource : public IReloadable { public: - TextureResource(); - ~TextureResource(); + static std::shared_ptr get(ResourceManager& rm, const std::string& path); - void init(ResourceData data) override; - void deinit() override; - - Vector2u getSize(); - void bind(); + virtual ~TextureResource(); + void unload(const ResourceManager& rm) override; + void reload(const ResourceManager& rm) override; + + Vector2u getSize() const; + void bind() const; + void initFromScreen(); private: + TextureResource(const ResourceManager& rm, const std::string& path); + + void initFromPath(); + void initFromResource(const ResourceData data); + void deinit(); + Vector2u mTextureSize; GLuint mTextureID; + const std::string mPath; + + static std::map< std::string, std::weak_ptr > sTextureMap; };