Contrary to what I wrote in the previous post I'll be talking about a Resource Manager I wrote in a recent game jam. I built it to be simple and fast to implement. This is by no means a great or even good Resource Manager, but it is a good way to quickly get up and running with resource management. But first some background information.
What is a Resource Manager and why do I need one.
The principal problem which a resource manager solves is that of resource duplication. For example you may have several models in your game which use the same texture. If you choose to create one version of this texture for each model you are wasting a lot of memory, the smart way of doing this is to reuse the same texture for all models. But how?
The basic idea is that you keep track over which files you've already loaded. To do this you need to store the information and search through it and if you can find it you just return a pointer/reference to that resource. To do this quickly while maximizing re-usability we'll be using std::map and templates.
The Standard Template Library - Map<Key, T>
The standard template library provides a ton of different predefined types, now the Map class stores a pair of a key type and a resource type. The key is what the map uses to sort the pairs, and this lets it return the pair faster. I'm not sure but I assume it a simple binary search that returns the pair with a time complexity of log(N).
In our resource manager the key type will be a std::string which is the name of the file in question. The name in the map is going to exclude the directory since the root will be the same for all resources of the same type. Comparing of two strings will take longer than necessary if it's comparing the root which will always be the same. The resource type will be a pointer to the resource.
The Code
Here follows the code for the Resource Manager, remember this isn't the fastest or best way of making a resource manager but it is the quickest way I've found so far.
One point of interest is the use of templates, this is done to create a protocol that the resources must follow without creating a v-table.
One point of interest is the use of templates, this is done to create a protocol that the resources must follow without creating a v-table.
ResourceManager.h
#ifndef RESOURCEMANAGER_H
#define RESOURCEMANAGER_H
template<typename T>
class CResourceManager
{
public:
T* Load(std::string name)
{
ResourceMap::iterator it = m_Resources.find(name);
if (it != m_Resources.end())
{
return it->second;
}
else // Resource not found
{
T* t = T::Load(name);
if(t)
m_Resources[name] = t;
return t;
}
return nullptr;
}
void Unload(std::string name)
{ /* Unloading here, left as an exercise for the student */ }
public:
T* Load(std::string name)
{
ResourceMap::iterator it = m_Resources.find(name);
if (it != m_Resources.end())
{
return it->second;
}
else // Resource not found
{
T* t = T::Load(name);
if(t)
m_Resources[name] = t;
return t;
}
return nullptr;
}
void Unload(std::string name)
{ /* Unloading here, left as an exercise for the student */ }
};
#endif // RESOURCEMANAGER_H
Resource.h
#ifndef RESOURCE_H
#define RESOURCE_H
template<typename T>
class CResource
{
public:
std::string GetDirectory();
std::string GetExtension();
T* Load(std::string name);
}
#define RESOURCE_H
template<typename T>
class CResource
{
public:
std::string GetDirectory();
std::string GetExtension();
T* Load(std::string name);
}
Texture.h
#ifndef TEXTURE_H
#define TEXTURE_H
#include "Resource.h"
#include "ResourceManager.h"
class CTexture : public CResource<CTexture>
{
// Texture stuff here
};
extern CResourceManager<CTexture> g_TextureManager;
#define TEXTURE_H
#include "Resource.h"
#include "ResourceManager.h"
class CTexture : public CResource<CTexture>
{
// Texture stuff here
};
extern CResourceManager<CTexture> g_TextureManager;
Texture.cpp
#include "Texture.h"
CResourceManager<CTexture> g_TextureManager;
std::string CResource<CTexture>::GetDirectory()
{ return "./Resources/Textures/"; }
std::string CResource<CTexture>::GetExtension()
{ return ".png"; }
T* CResource<CTexture>::Load(std::string name)
{
std::string FullPath = GetDirectory() + name + GetExtension();
// Load texture using the full path.
}
CResourceManager<CTexture> g_TextureManager;
std::string CResource<CTexture>::GetDirectory()
{ return "./Resources/Textures/"; }
std::string CResource<CTexture>::GetExtension()
{ return ".png"; }
T* CResource<CTexture>::Load(std::string name)
{
std::string FullPath = GetDirectory() + name + GetExtension();
// Load texture using the full path.
}