Created
April 19, 2010 04:06
-
-
Save zachelko/370741 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ResourceManager.cpp | |
// | |
// Zach Elko | |
// 2010 | |
// | |
// Functions as a garbage collector for allocating and releasing SDL resources. | |
// | |
// Supports: SDL_Surface, Mix_Music, and Mix_Chunk. | |
// | |
// It improves program efficiency by only allocating one copy for each | |
// resource required, and then frees the resource once all clients have | |
// released the resource. | |
// | |
// Could be extended using templates, but the results could range from | |
// negligible to detrimental because each resource needs to be | |
// allocated and released in their own way, so the resources would most | |
// likely need to be wrapped in an object with some virtual function(s) | |
// to handle the acquisition and release of the resources. | |
// | |
#include "ResourceManager.h" | |
#include "../utils/SDL_Utils.h" | |
#include "SDL/SDL.h" | |
#include "SDL/SDL_mixer.h" | |
#include "SDL/SDL_ttf.h" | |
#include <map> | |
#include <string> | |
#include <iostream> | |
#include <stdexcept> | |
// Exception class included here for brevity only | |
class Exception : public std::runtime_error | |
{ | |
public: | |
Exception(const std::string& msg) : std::runtime_error(msg.c_str()) { } | |
}; | |
// Initialize our static instance | |
// Note: Because it is static, we MUST do this in *exactly* 1 file | |
ResourceManager* ResourceManager::instance = 0; | |
SDL_Surface* ResourceManager::acquireSurface(const std::string& fileName, | |
const bool alpha) | |
{ | |
SurfaceIterator surfaceElement = surfaces.find(fileName); | |
// If we've already loaded this resource, simply increment the counter | |
// in the tracker and return the surface | |
// | |
// Otherwise, load it and add it to the tracker with an initial count of 1 | |
if (surfaceElement != surfaces.end()) | |
{ | |
TrackerIterator trackerElement = tracker.find(fileName); | |
++trackerElement->second; | |
return surfaceElement->second; | |
} | |
else | |
{ | |
SDL_Surface* surface = load_image(fileName, alpha); | |
if (surface != 0) | |
{ | |
tracker.insert(make_pair(fileName, 1)); | |
surfaces.insert(make_pair(fileName, surface)); | |
return surface; | |
} | |
else | |
{ | |
throw Exception("Failed to load file: " + fileName); | |
} | |
} | |
} | |
void ResourceManager::releaseSurface(const std::string& fileName) | |
{ | |
// If the resource already exists, check its tracker count. | |
// If it is currently 1, we are removing the last handle to it | |
// so we need to free the resource and remove it from our map. | |
// | |
// Otherwise, just decrease the count in the tracker | |
SurfaceIterator surfaceElement = surfaces.find(fileName); | |
if (surfaceElement != surfaces.end()) | |
{ | |
TrackerIterator trackerElement = tracker.find(fileName); | |
if (trackerElement->second == 1) | |
{ | |
trackerElement->second = 0; | |
SDL_FreeSurface(surfaceElement->second); | |
surfaceElement->second = 0; | |
surfaces.erase(surfaceElement); | |
} | |
else | |
{ | |
--trackerElement->second; | |
} | |
} | |
} | |
Mix_Music* ResourceManager::acquireMusic(const std::string& fileName) | |
{ | |
MusicIterator musicElement = musics.find(fileName); | |
// If we've already loaded this resource, simply increment the counter | |
// in the tracker and return the surface | |
// | |
// Otherwise, load it and add it to the tracker with an initial count of 1 | |
if (musicElement != musics.end()) | |
{ | |
TrackerIterator trackerElement = tracker.find(fileName); | |
if (trackerElement != tracker.end()) | |
{ | |
trackerElement->second += 1; | |
} | |
return musicElement->second; | |
} | |
else | |
{ | |
Mix_Music* music = Mix_LoadMUS(fileName.c_str()); | |
if (music != 0) | |
{ | |
tracker.insert(make_pair(fileName, 1)); | |
musics.insert(make_pair(fileName, music)); | |
return music; | |
} | |
else | |
{ | |
throw Exception("Failed to load file: " + fileName); | |
} | |
} | |
} | |
void ResourceManager::releaseMusic(const std::string& fileName) | |
{ | |
// If the resource already exists, check its tracker count. | |
// If it is currently 1, we are removing the last handle to it | |
// so we need to free the resource and remove it from our map. | |
// | |
// Otherwise, just decrease the count in the tracker | |
TrackerIterator trackerElement = tracker.find(fileName); | |
if (trackerElement != tracker.end()) | |
{ | |
if (trackerElement->second == 1) | |
{ | |
trackerElement->second = 0; | |
std::map<std::string, Mix_Music*>::iterator musicElement = | |
musics.find(fileName); | |
if (musicElement != musics.end()) | |
{ | |
Mix_FreeMusic(musicElement->second); | |
musics.erase(musicElement); | |
} | |
} | |
else | |
{ | |
trackerElement->second -= 1; | |
} | |
} | |
} | |
Mix_Chunk* ResourceManager::acquireSFX(const std::string& fileName) | |
{ | |
SfxIterator sfxElement = sfx.find(fileName); | |
// If we've already loaded this resource, simply increment the counter | |
// in the tracker and return the surface | |
// | |
// Otherwise, load it and add it to the tracker with an initial count of 1 | |
if (sfxElement != sfx.end()) | |
{ | |
TrackerIterator trackerElement = tracker.find(fileName); | |
if (trackerElement != tracker.end()) | |
{ | |
trackerElement->second += 1; | |
} | |
// return surface | |
return sfxElement->second; | |
} | |
else | |
{ | |
Mix_Chunk* sfxChunk = Mix_LoadWAV(fileName.c_str()); | |
if (sfxChunk != 0) | |
{ | |
tracker.insert(make_pair(fileName, 1)); | |
sfx.insert(make_pair(fileName, sfxChunk)); | |
return sfxChunk; | |
} | |
else | |
{ | |
throw Exception("Failed to load file: " + fileName); | |
} | |
} | |
} | |
void ResourceManager::releaseSFX(const std::string& fileName) | |
{ | |
// If the resource already exists, check its tracker count. | |
// If it is currently 1, we are removing the last handle to it | |
// so we need to free the resource and remove it from our map. | |
// | |
// Otherwise, just decrease the count in the tracker | |
TrackerIterator trackerElement = tracker.find(fileName); | |
if (trackerElement != tracker.end()) | |
{ | |
if (trackerElement->second == 1) | |
{ | |
trackerElement->second = 0; | |
std::map<std::string, Mix_Chunk*>::iterator sfxElement = | |
sfx.find(fileName); | |
if (sfxElement != sfx.end()) | |
{ | |
Mix_FreeChunk(sfxElement->second); | |
sfx.erase(sfxElement); | |
} | |
} | |
else | |
{ | |
trackerElement->second -= 1; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ResourceManager.hpp | |
// | |
// Zach Elko | |
// 2010 | |
// | |
// Functions as a garbage collector for allocating and releasing SDL resources. | |
// | |
// Supports: SDL_Surface, Mix_Music, and Mix_Chunk. | |
// | |
// It improves program efficiency by only allocating one copy for each | |
// resource required, and then frees the resource once all clients have | |
// released the resource. | |
// | |
// Could be extended using templates, but the results could range from | |
// negligible to detrimental because each resource needs to be | |
// allocated and released in their own way, so the resources would most | |
// likely need to be wrapped in an object with some virtual function(s) | |
// to handle the acquisition and release of the resources. | |
// | |
#ifndef RESOURCE_MANAGER_H | |
#define RESOURCE_MANAGER_H | |
#include "SDL/SDL.h" | |
#include "SDL/SDL_mixer.h" | |
#include "SDL/SDL_ttf.h" | |
#include <map> | |
#include <string> | |
#include <iostream> | |
typedef std::map<std::string, SDL_Surface*>::iterator SurfaceIterator; | |
typedef std::map<std::string, Mix_Music*>::iterator MusicIterator; | |
typedef std::map<std::string, Mix_Chunk*>::iterator SfxIterator; | |
typedef std::map<std::string, int>::iterator TrackerIterator; | |
class ResourceManager | |
{ | |
public: | |
static ResourceManager* getInstance() | |
{ | |
if (instance == 0) | |
{ | |
instance = new ResourceManager; | |
} | |
return instance; | |
} | |
SDL_Surface* acquireSurface(const std::string& fileName, const bool alpha); | |
void releaseSurface(const std::string& fileName); | |
Mix_Music* acquireMusic(const std::string& fileName); | |
void releaseMusic(const std::string& fileName); | |
Mix_Chunk* acquireSFX(const std::string& fileName); | |
void releaseSFX(const std::string& fileName); | |
private: | |
// The instance | |
static ResourceManager* instance; | |
// Surfaces | |
std::map<std::string, SDL_Surface*> surfaces; | |
// Music | |
std::map<std::string, Mix_Music*> musics; | |
// SFX | |
std::map<std::string, Mix_Chunk*> sfx; | |
// Tracker | |
std::map<std::string, int> tracker; | |
// All of these are private due to the Singleton pattern | |
ResourceManager() | |
{ | |
} | |
ResourceManager(const ResourceManager&) | |
{ | |
} | |
~ResourceManager() | |
{ | |
} | |
ResourceManager & operator=(const ResourceManager&) | |
{ | |
} | |
}; | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment