-
Notifications
You must be signed in to change notification settings - Fork 4
[Draft] Resource manager's architecture
The basic idea behind the resource manager's implementation is to provide simple yet extendable interface for interaction. For 0.3 and earlier versions of the engine's manager supports for a few built-in resource types (textures, localization packages, materials, shaders, etc). And its implementation became a quite annoying now because of concrete classes usage. For instance,
pResourceManager->Load<CBaseTexture>("...");
The same thing is for shaders, materials and rest types.
In current version (0.4) a new approach is considered. Shortly it's to use interfaces for work with resource types rather than concrete ones. The list of all available resources interfaces:
- IShader
- ITexture2D
- ICubemapTexture
- IRenderTarget
- IDepthBufferTarget
- IStaticMesh
- IMaterial
- IFont
- IParticleEffect
- IPostProcessingProfile
- ILocalizationPackage
Each of these types have their own loaders and factories. The default implementations of particular loader and factory corresponds to the only resource's concrete type. But it should be possible to extend this with plugins. For example,
auto texture = pResourceManager->Load<ITexture2D>("test"); /// \note This call uses the default factory and loader for ITexture2D
auto texture2 = pResourceManager->Load<ITexture2D, CustomTexture2DResourceProvider>("test2"); /// \note CustomTexture2DResourceProvider is a special type that defines which loader and factory should be used to load given resource
The default factories/loaders are registered within the engine's core. For this purpose IResourceManager::RegisterLoader and IResourceManager::RegisterFactory are used.
/*!
\brief The method registers specified resource loader within a manager
\param[in] pResourceLoader A pointer to IResourceLoader's implementation
\return The method returns an object, which contains a status of method's execution and
an identifier of the registred loader
*/
TDE2_API virtual TResult<TResourceLoaderId> RegisterLoader(const IResourceLoader* pResourceLoader) = 0;
/*!
\brief The method registers specified resource factory within a manager
\param[in] pResourceFactory A pointer to IResourceFactory's implementation
\return The method returns an object, which contains a status of method's execution and
an identifier of the registred factory
*/
TDE2_API virtual TResult<TResourceFactoryId> RegisterFactory(const IResourceFactory* pResourceFactory) = 0;
In details these factories and loaders provide a method GetResourceTypeId that defines for which type it can be used. And this value is used to register the factory or loader in the manager's table. That's why we can't register two factory for same resource's type. It's the constraint of the implementation. To solve this problem another overload of the Load method should be introduced
template <typename T, typename TResourceProvider> TResourceHandleId Load();
template <typename TFactory, typename TLoader>
struct TResourceProvider
{
static TypeId GetResourceFactoryId() { return TFactory::GetTypeId(); }
static TypeId GetResourceLoaderId() { return TLoader::GetTypeId(); }
};
So if the given resource provider's data is registered within the manager the resource can be created and loaded successfully.
From this moment all built-in resources interfaces should provide their own GetTypeId() static method. It's simple to do with the following macro
TDE2_REGISTER_RESOURCE(ResourceName)
that should be placed in public region of a class or struct type. And we have to possibilities to work with resources these are default ones and those implemented in plugins and registered in the resource manager.
There is a concept of default resources within the engine. They are used in a few cases:
- If some error's happened during loading of the resource.
- All loading resources from the moment of call Load until the loading will be finished use default values iternally.
So that's the reason why we need both factory type and loader in Load method's template arguments list.