Moved to class-individualized static gets for resources.

See issue #95 for discussion.
This commit is contained in:
Aloshi 2013-07-09 00:44:24 -05:00
parent c99324060b
commit c8900f4099
20 changed files with 246 additions and 178 deletions

View file

@ -151,7 +151,6 @@ set(ES_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/src/pugiXML/pugiconfig.hpp ${CMAKE_CURRENT_SOURCE_DIR}/src/pugiXML/pugiconfig.hpp
${CMAKE_CURRENT_SOURCE_DIR}/src/pugiXML/pugixml.hpp ${CMAKE_CURRENT_SOURCE_DIR}/src/pugiXML/pugixml.hpp
${CMAKE_CURRENT_SOURCE_DIR}/src/resources/ResourceManager.h ${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}/src/resources/TextureResource.h
${CMAKE_CURRENT_SOURCE_DIR}/data/Resources.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/components/GuiSettingsMenu.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/pugiXML/pugixml.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/pugiXML/pugixml.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/resources/ResourceManager.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}/src/resources/TextureResource.cpp
${CMAKE_CURRENT_SOURCE_DIR}/data/logo/ES_logo_16.cpp ${CMAKE_CURRENT_SOURCE_DIR}/data/logo/ES_logo_16.cpp
${CMAKE_CURRENT_SOURCE_DIR}/data/logo/ES_logo_32.cpp ${CMAKE_CURRENT_SOURCE_DIR}/data/logo/ES_logo_32.cpp

View file

@ -14,6 +14,8 @@ int Font::getDpiY() { return 96; }
int Font::getSize() { return mSize; } int Font::getSize() { return mSize; }
std::map< std::pair<std::string, int>, std::weak_ptr<Font> > Font::sFontMap;
std::string Font::getDefaultPath() std::string Font::getDefaultPath()
{ {
const int fontCount = 4; 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() Font::~Font()
@ -78,6 +81,38 @@ Font::~Font()
deinit(); deinit();
} }
void Font::reload(const ResourceManager& rm)
{
init(rm.getFileData(mPath));
}
void Font::unload(const ResourceManager& rm)
{
deinit();
}
std::shared_ptr<Font> 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<Font>();
}
std::pair<std::string, int> def(path, size);
auto foundFont = sFontMap.find(def);
if(foundFont != sFontMap.end())
{
if(!foundFont->second.expired())
return foundFont->second.lock();
}
std::shared_ptr<Font> font = std::shared_ptr<Font>(new Font(rm, path, size));
sFontMap[def] = std::weak_ptr<Font>(font);
rm.addReloadable(font);
return font;
}
void Font::init(ResourceData data) void Font::init(ResourceData data)
{ {
if(!libraryInitialized) if(!libraryInitialized)
@ -96,7 +131,7 @@ void Font::deinit()
void Font::buildAtlas(ResourceData data) 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!"; LOG(LogError) << "Error creating font face!";
return; return;
@ -206,9 +241,8 @@ void Font::buildAtlas(ResourceData data)
mSize = (int)(mSize * (1.0f / fontScale)); mSize = (int)(mSize * (1.0f / fontScale));
deinit(); deinit();
init(data); init(data);
} }else{
else { LOG(LogInfo) << "Created font with size " << mSize << ".";
//LOG(LogInfo) << "Created font with size " << mSize << ".";
} }
} }

View file

@ -7,7 +7,7 @@
#include <ft2build.h> #include <ft2build.h>
#include FT_FREETYPE_H #include FT_FREETYPE_H
#include "Vector2.h" #include "Vector2.h"
#include "resources/Resource.h" #include "resources/ResourceManager.h"
class TextCache; class TextCache;
@ -17,12 +17,13 @@ class TextCache;
//A TrueType Font renderer that uses FreeType and OpenGL. //A TrueType Font renderer that uses FreeType and OpenGL.
//The library is automatically initialized when it's needed. //The library is automatically initialized when it's needed.
class Font : public Resource class Font : public IReloadable
{ {
public: public:
static void initLibrary(); static void initLibrary();
Font(int size); static std::shared_ptr<Font> get(ResourceManager& rm, const std::string& path, int size);
~Font(); ~Font();
FT_Face face; FT_Face face;
@ -56,11 +57,10 @@ public:
void sizeWrappedText(std::string text, int xLen, int* xOut, int* yOut); void sizeWrappedText(std::string text, int xLen, int* xOut, int* yOut);
void drawCenteredText(std::string text, int xOffset, int y, unsigned int color); void drawCenteredText(std::string text, int xOffset, int y, unsigned int color);
int getHeight(); int getHeight();
void init(ResourceData data) override; void unload(const ResourceManager& rm) override;
void deinit() override; void reload(const ResourceManager& rm) override;
int getSize(); int getSize();
@ -72,6 +72,13 @@ private:
static FT_Library sLibrary; static FT_Library sLibrary;
static bool libraryInitialized; static bool libraryInitialized;
static std::map< std::pair<std::string, int>, std::weak_ptr<Font> > 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. void buildAtlas(ResourceData data); //Builds a "texture atlas," one big OpenGL texture with glyphs 32 to 128.
int textureWidth; //OpenGL texture width int textureWidth; //OpenGL texture width
@ -80,6 +87,7 @@ private:
float fontScale; //!<Font scale factor. It is > 1.0 if the font would be to big for the texture float fontScale; //!<Font scale factor. It is > 1.0 if the font would be to big for the texture
int mSize; int mSize;
const std::string mPath;
}; };
class TextCache class TextCache

View file

@ -8,9 +8,9 @@ Window::Window()
{ {
mInputManager = new InputManager(this); mInputManager = new InputManager(this);
mDefaultFonts.push_back(mResourceManager.getFont(Font::getDefaultPath(), FONT_SIZE_SMALL)); mDefaultFonts.push_back(Font::get(mResourceManager, Font::getDefaultPath(), FONT_SIZE_SMALL));
mDefaultFonts.push_back(mResourceManager.getFont(Font::getDefaultPath(), FONT_SIZE_MEDIUM)); mDefaultFonts.push_back(Font::get(mResourceManager, 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_LARGE));
} }
Window::~Window() Window::~Window()
@ -59,7 +59,7 @@ void Window::init()
{ {
mInputManager->init(); //shouldn't this go AFTER renderer initialization? mInputManager->init(); //shouldn't this go AFTER renderer initialization?
Renderer::init(0, 0); Renderer::init(0, 0);
mResourceManager.init(); mResourceManager.reloadAll();
for(unsigned int i = 0; i < mGuiStack.size(); i++) for(unsigned int i = 0; i < mGuiStack.size(); i++)
{ {
@ -75,7 +75,7 @@ void Window::deinit()
} }
mInputManager->deinit(); mInputManager->deinit();
mResourceManager.deinit(); mResourceManager.unloadAll();
Renderer::deinit(); Renderer::deinit();
} }

View file

@ -5,6 +5,7 @@
#include "InputManager.h" #include "InputManager.h"
#include "resources/ResourceManager.h" #include "resources/ResourceManager.h"
#include <vector> #include <vector>
#include "Font.h"
class Window class Window
{ {

View file

@ -83,7 +83,7 @@ void GuiDetectDevice::update(int deltaTime)
void GuiDetectDevice::render() void GuiDetectDevice::render()
{ {
std::shared_ptr<Font> font = mWindow->getResourceManager()->getFont(Font::getDefaultPath(), FONT_SIZE_MEDIUM); std::shared_ptr<Font> font = Font::get(*mWindow->getResourceManager(), Font::getDefaultPath(), FONT_SIZE_MEDIUM);
std::string playerString; std::string playerString;
std::stringstream stream; std::stringstream stream;

View file

@ -26,7 +26,7 @@ bool GuiGameList::isDetailed() const
GuiGameList::GuiGameList(Window* window) : GuiComponent(window), GuiGameList::GuiGameList(Window* window) : GuiComponent(window),
mTheme(new ThemeComponent(mWindow)), 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), mScreenshot(window),
mDescription(window), mDescription(window),
mDescContainer(window), mDescContainer(window),
@ -114,7 +114,7 @@ void GuiGameList::render()
if(mTheme) if(mTheme)
mTheme->render(); mTheme->render();
std::shared_ptr<Font> headerFont = mWindow->getResourceManager()->getFont(Font::getDefaultPath(), FONT_SIZE_LARGE); std::shared_ptr<Font> headerFont = Font::get(*mWindow->getResourceManager(), Font::getDefaultPath(), FONT_SIZE_LARGE);
//header //header
if(!mTheme->getBool("hideHeader")) if(!mTheme->getBool("hideHeader"))

View file

@ -77,7 +77,7 @@ bool GuiInputConfig::input(InputConfig* config, Input input)
void GuiInputConfig::render() void GuiInputConfig::render()
{ {
std::shared_ptr<Font> font = mWindow->getResourceManager()->getFont(Font::getDefaultPath(), FONT_SIZE_MEDIUM); std::shared_ptr<Font> font = Font::get(*mWindow->getResourceManager(), Font::getDefaultPath(), FONT_SIZE_MEDIUM);
std::stringstream stream; std::stringstream stream;
stream << "PLAYER " << mTargetConfig->getPlayerNum() + 1 << ", press..."; stream << "PLAYER " << mTargetConfig->getPlayerNum() + 1 << ", press...";

View file

@ -11,7 +11,7 @@ GuiMenu::GuiMenu(Window* window, GuiGameList* parent) : GuiComponent(window)
{ {
mParent = parent; mParent = parent;
std::shared_ptr<Font> font = mWindow->getResourceManager()->getFont(Font::getDefaultPath(), FONT_SIZE_LARGE); std::shared_ptr<Font> font = Font::get(*mWindow->getResourceManager(), Font::getDefaultPath(), FONT_SIZE_LARGE);
mList = new TextListComponent<std::string>(mWindow, 0, font->getHeight() + 2, font); mList = new TextListComponent<std::string>(mWindow, 0, font->getHeight() + 2, font);
mList->setSelectedTextColor(0x0000FFFF); mList->setSelectedTextColor(0x0000FFFF);
populateList(); populateList();

View file

@ -86,7 +86,11 @@ void ImageComponent::setImage(std::string path)
mPath = 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(); resize();
} }
@ -229,7 +233,7 @@ void ImageComponent::copyScreen()
{ {
mTexture.reset(); mTexture.reset();
mTexture = std::make_shared<TextureResource>(); mTexture = TextureResource::get(*mWindow->getResourceManager(), "");
mTexture->initFromScreen(); mTexture->initFromScreen();
resize(); resize();

View file

@ -8,7 +8,7 @@ SwitchComponent::SwitchComponent(Window* window, bool state) : GuiComponent(wind
//mSize = Vector2u((unsigned int)(Renderer::getScreenWidth() * 0.05), //mSize = Vector2u((unsigned int)(Renderer::getScreenWidth() * 0.05),
// (unsigned int)(Renderer::getScreenHeight() * 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) bool SwitchComponent::input(InputConfig* config, Input input)
@ -26,7 +26,7 @@ void SwitchComponent::onRender()
{ {
Renderer::pushClipRect(getGlobalOffset(), getSize()); 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(); Renderer::popClipRect();

View file

@ -53,7 +53,7 @@ std::shared_ptr<Font> TextComponent::getFont() const
if(mFont) if(mFont)
return mFont; return mFont;
else else
return mWindow->getResourceManager()->getFont(Font::getDefaultPath(), FONT_SIZE_MEDIUM); return Font::get(*mWindow->getResourceManager(), Font::getDefaultPath(), FONT_SIZE_MEDIUM);
} }
void TextComponent::onRender() void TextComponent::onRender()

View file

@ -40,7 +40,7 @@ std::shared_ptr<Font> ThemeComponent::getListFont()
if(mListFont) if(mListFont)
return mListFont; return mListFont;
else else
return mWindow->getResourceManager()->getFont(Font::getDefaultPath(), FONT_SIZE_MEDIUM); return Font::get(*mWindow->getResourceManager(), Font::getDefaultPath(), FONT_SIZE_MEDIUM);
} }
std::shared_ptr<Font> ThemeComponent::getDescriptionFont() std::shared_ptr<Font> ThemeComponent::getDescriptionFont()
@ -48,7 +48,7 @@ std::shared_ptr<Font> ThemeComponent::getDescriptionFont()
if(mDescFont) if(mDescFont)
return mDescFont; return mDescFont;
else else
return mWindow->getResourceManager()->getFont(Font::getDefaultPath(), FONT_SIZE_SMALL); return Font::get(*mWindow->getResourceManager(), Font::getDefaultPath(), FONT_SIZE_SMALL);
} }
std::shared_ptr<Font> ThemeComponent::getFastSelectFont() std::shared_ptr<Font> ThemeComponent::getFastSelectFont()
@ -56,7 +56,7 @@ std::shared_ptr<Font> ThemeComponent::getFastSelectFont()
if(mFastSelectFont == NULL) if(mFastSelectFont == NULL)
return mFastSelectFont; return mFastSelectFont;
else 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) ThemeComponent::ThemeComponent(Window* window) : GuiComponent(window)
@ -410,5 +410,5 @@ std::shared_ptr<Font> ThemeComponent::resolveFont(pugi::xml_node node, std::stri
size = defaultSize; size = defaultSize;
} }
return mWindow->getResourceManager()->getFont(path, size); return Font::get(*mWindow->getResourceManager(), path, size);
} }

View file

@ -211,7 +211,7 @@ int main(int argc, char* argv[])
nrOfFrames = 0; nrOfFrames = 0;
timeElapsed = 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 //sleep if we're past our threshold

View file

@ -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;
};

View file

@ -1,6 +1,13 @@
#include "ResourceManager.h" #include "ResourceManager.h"
#include "../Log.h" #include "../Log.h"
#include <fstream> #include <fstream>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
auto array_deleter = [](unsigned char* p) { delete[] p; };
auto nop_deleter = [](unsigned char* p) { };
//from ES_logo_16.cpp //from ES_logo_16.cpp
extern const size_t es_logo_16_data_len; extern const size_t es_logo_16_data_len;
@ -18,96 +25,35 @@ struct EmbeddedResource
static const int embedded_resource_count = 2; static const int embedded_resource_count = 2;
static const EmbeddedResource embedded_resources[embedded_resource_count] = { 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_16.png", {std::shared_ptr<unsigned char>((unsigned char*)es_logo_16_data, nop_deleter), es_logo_16_data_len} },
{ "internal://es_logo_32.png", {es_logo_32_data, es_logo_32_data_len} } { "internal://es_logo_32.png", {std::shared_ptr<unsigned char>((unsigned char*)es_logo_32_data, nop_deleter), es_logo_32_data_len} }
}; };
std::shared_ptr<TextureResource> ResourceManager::getTexture(const std::string& path)
{
if(path.empty())
return std::shared_ptr<TextureResource>(); //NULL pointer
if(mTextureMap[path].expired()) const ResourceData ResourceManager::getFileData(const std::string& path) const
{
std::shared_ptr<TextureResource> ret(new TextureResource());
mTextureMap[path] = std::weak_ptr<TextureResource>(ret);
initializeResource(path, ret);
return ret;
}
return mTextureMap[path].lock();
}
std::shared_ptr<Font> ResourceManager::getFont(const std::string& path, int size)
{
if(path.empty() || size == 0)
return std::shared_ptr<Font>(); //NULL pointer
std::pair<std::string, int> fontDef(path, size);
if(mFontMap[fontDef].expired())
{
std::shared_ptr<Font> ret(new Font(size));
mFontMap[fontDef] = std::weak_ptr<Font>(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> resource)
{ {
for(int i = 0; i < embedded_resource_count; i++) for(int i = 0; i < embedded_resource_count; i++)
{ {
if(strcmp(embedded_resources[i].internal_path, path.c_str()) == 0) if(strcmp(embedded_resources[i].internal_path, path.c_str()) == 0)
{ {
//this embedded resource matches the filepath; use it //this embedded resource matches the filepath; use it
resource->init(embedded_resources[i].resourceData); return embedded_resources[i].resourceData;
return;
} }
} }
//it's not embedded; load the file, initialize with it, then free the file //it's not embedded; load the file
ResourceData data = loadFile(path); if(!fs::exists(path))
resource->init(data); {
delete[] data.ptr; //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); 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(); size_t size = (size_t)stream.tellg();
stream.seekg(0, stream.beg); stream.seekg(0, stream.beg);
unsigned char* data = new unsigned char[size]; //supply custom deleter to properly free array
stream.read((char*)data, size); std::shared_ptr<unsigned char> data(new unsigned char[size], array_deleter);
stream.read((char*)data.get(), size);
stream.close(); stream.close();
ResourceData ret = {data, size}; ResourceData ret = {data, size};
return ret; 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<IReloadable> reloadable)
{
mReloadables.push_back(reloadable);
}

View file

@ -3,35 +3,40 @@
#include <stddef.h> #include <stddef.h>
#include <memory> #include <memory>
#include <map> #include <map>
#include "Resource.h" #include <vector>
#include "TextureResource.h"
#include "../Font.h"
//The ResourceManager exists to: //The ResourceManager exists to...
//1. Automatically deal with initializing/deinitializing various resources (OpenGL textures, SDL audio) //Allow loading resources embedded into the executable like an actual file.
//2. Allow loading resources embedded into the executable like an actual file. //Allow embedded resources to be optionally remapped to actual files for further customization.
// a. Allow embedded resources to be optionally remapped to actual files for further customization.
//3. Keep from creating duplicate resources.
//The ResourceManager returns resources as std::shared_ptrs. struct ResourceData
//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. const std::shared_ptr<unsigned char> ptr;
//Once the game exits and ES returns, resources will have init() called on them. 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 class ResourceManager
{ {
public: public:
std::shared_ptr<TextureResource> getTexture(const std::string& path); void addReloadable(std::weak_ptr<IReloadable> reloadable);
std::shared_ptr<Font> getFont(const std::string& path, int size);
void init(); void unloadAll();
void deinit(); void reloadAll();
const ResourceData getFileData(const std::string& path) const;
bool fileExists(const std::string& path) const;
private: private:
void initializeResource(const std::string& path, std::shared_ptr<Resource> resource); ResourceData loadFile(const std::string& path) const;
ResourceData loadFile(const std::string& path);
std::map< std::string, std::weak_ptr<TextureResource> > mTextureMap; std::vector< std::weak_ptr<IReloadable> > mReloadables;
std::map< std::pair<std::string, int>, std::weak_ptr<Font> > mFontMap;
}; };

View file

@ -5,8 +5,11 @@
#include "../ImageIO.h" #include "../ImageIO.h"
#include "../Renderer.h" #include "../Renderer.h"
TextureResource::TextureResource() : mTextureID(0) std::map< std::string, std::weak_ptr<TextureResource> > TextureResource::sTextureMap;
TextureResource::TextureResource(const ResourceManager& rm, const std::string& path) : mTextureID(0), mPath(path)
{ {
reload(rm);
} }
TextureResource::~TextureResource() TextureResource::~TextureResource()
@ -14,17 +17,28 @@ TextureResource::~TextureResource()
deinit(); 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 //make sure we aren't going to leak an old texture
deinit(); deinit();
size_t width, height; size_t width, height;
std::vector<unsigned char> imageRGBA = ImageIO::loadFromMemoryRGBA32(data.ptr, data.length, width, height); std::vector<unsigned char> imageRGBA = ImageIO::loadFromMemoryRGBA32(const_cast<unsigned char*>(data.ptr.get()), data.length, width, height);
if(imageRGBA.size() == 0) if(imageRGBA.size() == 0)
{ {
LOG(LogError) << "Could not initialize texture!"; LOG(LogError) << "Could not initialize texture (invalid resource data)!";
return; return;
} }
@ -44,25 +58,6 @@ void TextureResource::init(ResourceData data)
mTextureSize.y = height; 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() void TextureResource::initFromScreen()
{ {
deinit(); deinit();
@ -84,3 +79,46 @@ void TextureResource::initFromScreen()
mTextureSize.x = height; mTextureSize.x = height;
mTextureSize.y = 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> TextureResource::get(ResourceManager& rm, const std::string& path)
{
if(path.empty())
return std::shared_ptr<TextureResource>(new TextureResource(rm, path));
auto foundTexture = sTextureMap.find(path);
if(foundTexture != sTextureMap.end())
{
if(!foundTexture->second.expired())
{
return foundTexture->second.lock();
}
}
std::shared_ptr<TextureResource> tex = std::shared_ptr<TextureResource>(new TextureResource(rm, path));
sTextureMap[path] = std::weak_ptr<TextureResource>(tex);
rm.addReloadable(tex);
return tex;
}

View file

@ -1,27 +1,37 @@
#pragma once #pragma once
#include "Resource.h" #include "ResourceManager.h"
#include <string> #include <string>
#include "../Vector2.h" #include "../Vector2.h"
#include "../platform.h" #include "../platform.h"
#include GLHEADER #include GLHEADER
class TextureResource : public Resource class TextureResource : public IReloadable
{ {
public: public:
TextureResource(); static std::shared_ptr<TextureResource> get(ResourceManager& rm, const std::string& path);
~TextureResource();
void init(ResourceData data) override; virtual ~TextureResource();
void deinit() override;
Vector2u getSize(); void unload(const ResourceManager& rm) override;
void bind(); void reload(const ResourceManager& rm) override;
Vector2u getSize() const;
void bind() const;
void initFromScreen(); void initFromScreen();
private: private:
TextureResource(const ResourceManager& rm, const std::string& path);
void initFromPath();
void initFromResource(const ResourceData data);
void deinit();
Vector2u mTextureSize; Vector2u mTextureSize;
GLuint mTextureID; GLuint mTextureID;
const std::string mPath;
static std::map< std::string, std::weak_ptr<TextureResource> > sTextureMap;
}; };