Some basic documentation of the resource manager. It could probably be improved a lot.
This commit is contained in:
@@ -17,29 +17,44 @@
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <functional>
|
||||
|
||||
// Will handle loading, retaining, and releasing of resources.
|
||||
// Resources include sounds, images, fonts, and cursors.
|
||||
/// A simple resource manager.
|
||||
/// Handles loading, retaining, and releasing of resources as necessary.
|
||||
/// Resources include sounds, images, fonts, and cursors.
|
||||
///
|
||||
/// To implement a new resource type, all you have to do is specialize
|
||||
/// @a ResMgr::resLoader::operator() for the desired resource type.
|
||||
namespace ResMgr {
|
||||
namespace fs = boost::filesystem;
|
||||
/// The signature of an ID map function.
|
||||
using idMapFn = std::function<std::string(int)>;
|
||||
|
||||
/// A resource pool.
|
||||
/// @tparam type The type of resource that this pool manages.
|
||||
template<typename type> struct resPool {
|
||||
/// Get the map of all currently-loaded resources from this resource pool.
|
||||
static std::map<std::string,std::shared_ptr<type> >& resources() {
|
||||
static std::map<std::string,std::shared_ptr<type> > data;
|
||||
return data;
|
||||
}
|
||||
/// Get the current search path stack for this resource pool.
|
||||
static std::stack<fs::path>& resPaths() {
|
||||
static std::stack<fs::path> data;
|
||||
return data;
|
||||
}
|
||||
/// Get the current function used to map numerical IDs to string keys (filenames).
|
||||
static idMapFn& mapFn() {
|
||||
static idMapFn data;
|
||||
return data;
|
||||
}
|
||||
/// Get the map of past path resolutions.
|
||||
/// @return A map of relative paths to the absolute path they most recently resolved to.
|
||||
static std::map<fs::path,fs::path>& pathFound() {
|
||||
static std::map<fs::path,fs::path> data;
|
||||
return data;
|
||||
}
|
||||
/// Convert a relative path to an absolute path by checking the current search path stack.
|
||||
/// @param path The path to resolve.
|
||||
/// @return The resolved absolute path, or the relative path unchanged if resolution failed.
|
||||
static fs::path rel2abs(fs::path path) {
|
||||
std::stack<fs::path> tmpPaths = resPaths();
|
||||
while(!tmpPaths.empty()) {
|
||||
@@ -58,35 +73,61 @@ namespace ResMgr {
|
||||
}
|
||||
};
|
||||
|
||||
/// Handles all the legwork of loading a specific resource.
|
||||
/// Must be implemented for each resource you want to manage.
|
||||
/// @tparam type The type of resource.
|
||||
template<typename type> struct resLoader {
|
||||
/// Load a resource of this type from the given file.
|
||||
/// @param fname The path to the resource; this will be an absolute path unless resolution failed.
|
||||
/// @return A pointer to the loaded resource. The resource manager takes responsibility for freeing it,
|
||||
/// so it must be a pointer allocated with `new` rather than `new[]`.
|
||||
type* operator() (std::string fname);
|
||||
};
|
||||
|
||||
/// Thrown if an error occurs while loading a resource.
|
||||
class xResMgrErr : public std::exception {
|
||||
std::string msg;
|
||||
public:
|
||||
xResMgrErr() throw() {}
|
||||
xResMgrErr(const std::string& str) throw() : msg(str) {}
|
||||
~xResMgrErr() throw() {}
|
||||
/// @return The error message.
|
||||
virtual const char* what() const throw() {
|
||||
return msg.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
/// Free a single resource.
|
||||
/// @tparam type The type of resource to free.
|
||||
/// @param name The key of the resource to free (usually the filename without an extension).
|
||||
template<typename type> void free(std::string name) {
|
||||
if(resPool<type>::resources().find(name) != resPool<type>::resources().end())
|
||||
resPool<type>::resources().erase(name);
|
||||
}
|
||||
|
||||
/// Free a single resource by numerical ID.
|
||||
/// In order for this to work, an ID map function must have first been set with setIdMapFn().
|
||||
/// @tparam type The type of resource to free.
|
||||
/// @param id The numerical ID of the resource to free.
|
||||
/// @throw std::bad_function_call if the ID map function was not set.
|
||||
template<typename type> void free(int id) {
|
||||
std::string name = resPool<type>::mapFn()(id);
|
||||
if(name != "") free<type>(name);
|
||||
}
|
||||
|
||||
/// Free all resources of a particular type.
|
||||
/// @tparam type The type of resource to free.
|
||||
template<typename type> void freeAll() {
|
||||
resPool<type>::resources().clear();
|
||||
}
|
||||
|
||||
/// Fetch a single resource, loading it into memory if necessary.
|
||||
/// If the resource already exists in memory, it first checks to see if the path resolution has changed,
|
||||
/// which could happen if a new path has been pushed on the stack, or a path has been removed.
|
||||
/// If it would resolve to a different file than the one currently loaded, the resource is reloaded.
|
||||
/// @tparam type The type of the resource to fetch.
|
||||
/// @param name The key of the resource to fetch (usually the filename without an extension).
|
||||
/// @return A smart pointer to the fetched resource.
|
||||
template<typename type> std::shared_ptr<type> get(std::string name) {
|
||||
if(resPool<type>::resources().find(name) != resPool<type>::resources().end()) {
|
||||
if(resPool<type>::pathFound().find(name) != resPool<type>::pathFound().end()) {
|
||||
@@ -107,18 +148,31 @@ namespace ResMgr {
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch a single resource by numerical ID.
|
||||
/// In order for this to work, an ID map function must have first been set with setIdMapFn().
|
||||
/// @tparam type The type of the resource to fetch.
|
||||
/// @param id The numerical ID of the resource to fetch.
|
||||
/// @return A smart pointer to the fetched resource.
|
||||
/// @throw xResMgrErr if the ID map function returned an empty string.
|
||||
/// @throw std::bad_function_call if the ID map function was not set.
|
||||
template<typename type> std::shared_ptr<type> get(int id) {
|
||||
std::string name = resPool<type>::mapFn()(id);
|
||||
if(name == "") throw xResMgrErr("Invalid resource ID.");
|
||||
return get<type>(name);
|
||||
}
|
||||
|
||||
/// Push a new path onto the path resolution stack
|
||||
/// @tparam type The type of resource the path applies to.
|
||||
/// @param path The path at which resources of this type may be found.
|
||||
template<typename type> void pushPath(fs::path path) {
|
||||
printf("Pushing path %s in %s...\n",path.c_str(),__FUNCTION__);
|
||||
resPool<type>::resPaths().push(path);
|
||||
if(resPool<type>::resPaths().empty()) printf("A problem occurred.\n");
|
||||
}
|
||||
|
||||
/// Pop a path from the path resolution stack.
|
||||
/// @tparam type The type of resource the path applies to.
|
||||
/// @return The removed path from the top of the stack.
|
||||
template<typename type> fs::path popPath() {
|
||||
fs::path path = resPool<type>::resPaths.top();
|
||||
// std::map<std::string,std::string>::iterator mapiter;
|
||||
@@ -135,10 +189,16 @@ namespace ResMgr {
|
||||
return path;
|
||||
}
|
||||
|
||||
/// Set an ID map function.
|
||||
/// @tparam type The type of resource for which an ID map function should be set.
|
||||
/// @param f The new ID map function.
|
||||
template<typename type> void setIdMapFn(idMapFn f) {
|
||||
resPool<type>::mapFn() = f;
|
||||
}
|
||||
|
||||
/// Get the ID map function for a resource type.
|
||||
/// @tparam type The type of resource to fetch the ID map function for.
|
||||
/// @return The currend ID map function for this resource type.
|
||||
template<typename type> idMapFn getIdMapFn() {
|
||||
return resPool<type>::mapFn();
|
||||
}
|
||||
|
@@ -28,6 +28,7 @@ using StringRsrc = std::vector<std::string>;
|
||||
using SoundRsrc = sf::SoundBuffer;
|
||||
|
||||
namespace ResMgr {
|
||||
/// Load an image from a PNG file.
|
||||
template<> inline ImageRsrc* resLoader<ImageRsrc>::operator() (std::string fname) {
|
||||
fs::path fpath = resPool<ImageRsrc>::rel2abs(fname + ".png");
|
||||
ImageRsrc* img = new ImageRsrc();
|
||||
@@ -36,6 +37,9 @@ namespace ResMgr {
|
||||
throw xResMgrErr("Failed to load PNG image: " + fpath.string());
|
||||
}
|
||||
|
||||
/// Load a cursor from a GIF file.
|
||||
/// The cursor's hotspot location is stored in a .hot file, as plaintext:
|
||||
/// simply the X value followed by the Y value, separated by whitespace.
|
||||
template<> inline CursorRsrc* resLoader<CursorRsrc>::operator() (std::string fname) {
|
||||
// TODO: Store the hotspots on disk instead of hardcoded here
|
||||
static const std::map<std::string,location> cursor_hs = {
|
||||
@@ -70,6 +74,7 @@ namespace ResMgr {
|
||||
throw xResMgrErr("Failed to load GIF cursor: " + fname);
|
||||
}
|
||||
|
||||
/// Load a font form a TTF file.
|
||||
template<> inline FontRsrc* resLoader<FontRsrc>::operator() (std::string fname) {
|
||||
fs::path fpath = resPool<FontRsrc>::rel2abs(fname + ".ttf");
|
||||
FontRsrc* theFont = new FontRsrc;
|
||||
@@ -80,6 +85,9 @@ namespace ResMgr {
|
||||
throw xResMgrErr("Failed to find font: " + fpath.string());
|
||||
}
|
||||
|
||||
/// Load a list of strings from a TXT file.
|
||||
/// Each line in the file becomes one string in the resulting list.
|
||||
/// (Empty lines are included too.)
|
||||
template<> inline StringRsrc* resLoader<StringRsrc>::operator() (std::string fname) {
|
||||
fs::path fpath = resPool<StringRsrc>::rel2abs(fname + ".txt");
|
||||
std::ifstream fin(fpath.c_str());
|
||||
@@ -96,6 +104,7 @@ namespace ResMgr {
|
||||
return strlist;
|
||||
}
|
||||
|
||||
/// Load a sound from a WAV file.
|
||||
template<> inline SoundRsrc* resLoader<SoundRsrc>::operator() (std::string fname) {
|
||||
fs::path fpath = resPool<SoundRsrc>::rel2abs(fname + ".wav");
|
||||
SoundRsrc* snd = new SoundRsrc;
|
||||
|
Reference in New Issue
Block a user