source: nrEngine/include/ResourceManager.h @ 15

Revision 15, 21.9 KB checked in by art, 12 years ago (diff)
Line 
1/***************************************************************************
2 *                                                                         *
3 *   (c) Art Tevs, MPI Informatik Saarbruecken                             *
4 *       mailto: <tevs@mpi-sb.mpg.de>                                      *
5 *                                                                         *
6 *   This program is free software; you can redistribute it and/or modify  *
7 *   it under the terms of the GNU General Public License as published by  *
8 *   the Free Software Foundation; either version 2 of the License, or     *
9 *   (at your option) any later version.                                   *
10 *                                                                         *
11 ***************************************************************************/
12
13
14#ifndef _NR_RESOURCE_MANAGER_H_
15#define _NR_RESOURCE_MANAGER_H_
16
17
18//----------------------------------------------------------------------------------
19// Includes
20//----------------------------------------------------------------------------------
21#include "Prerequisities.h"
22#include "ResourceSystem.h"
23#include "ScriptEngine.h"
24
25namespace nrEngine {
26
27        //! General pointer/handle based resource management system
28        /**
29        * This class is a manger for every kind of resource used in our games.
30        * Textures, sounds, meshes, ... - all things that can be loaded from disk
31        * are resources managed by this module. You can derive your own classes
32        * to write own storing algorithms for different kind of resources. This class
33        * will use standard implementation and will try to be as efficient as possible.
34        * This manager can index resources, look them up, load and destroy them, and
35        * temporaly unload resources from memory to use only allowd size of memory.
36        *
37        * We will use a priority system to determine which resources can be unloaded
38        * and for two resources of the same priority the most used will stay in memory.
39        *
40        * This code and idea was get from Game Programming Gems 4. <a href="http://www.ogre3d.org">
41        * Ogre3D-Library</a> was also used to get an idea how to get the resource manager
42        * working without using a whole library behind.
43        *
44        * The member functions createEmptyResource(), loadResource() are build by templates
45        * that allows us to create new kind of resource by storing it under standrd nrIResourcePtr.
46        * For example if you have a class A derived from nrCResource and this class is don't known
47        * by our engine, so you can just load the resource object of this class by calling:
48        * <code>nrResource.loadResource<A>(...)</code>. This allows us to create/load resources
49        * of specified types and not just to create standard nrCResource object which do not always
50        * can be casted to derived objects.
51        *
52        * <b>-</b> Meaning of resource groups:
53        *               @par - Each resource can exists in a group.
54        *                        - Each group has got it's unique names.
55        *                        - You can access to whole groups either to single resources.
56        *                        - E.g: you can split your level in patches and each resource in such a patch is
57        *                          in patch's resource group. So if the player go to far away from such a patch,
58        *                          it can be disabled or unloaded from the memory. You have now just to call one
59        *                          unload function for the whole group.
60        *                        - Groups must not be disjoint, so you can have same resource in different groups.
61        *
62        * \ingroup resource
63        **/
64        class _NRExport ResourceManager{
65                public:
66       
67                        /**
68                         * Release all used memory and also mark all loaded resources to unload. After
69                         * you calling the destructor of ResourceManager class all created resources
70                         * and loaders will be removed from the memory.
71                        **/
72                        virtual ~ResourceManager();
73
74#if 0
75                        /**
76                        * Set amount of memory that can be used by the manager. Set this value to 80-90%
77                        * of your physical memory if you do not have any virtual memory in your system
78                        * available. The manager will try to stay in the budget you given for him.
79                        * Resources that are least used and has got lowest priority will be unloaded
80                        * to free the memory to stay in the given budget of memory.
81                        *
82                        * @param bytes Count of bytes which can be used for resource storing
83                        * @return either OK or error code.
84                        *
85                        * @note You can set this value to ca 80-90% of your memory available.
86                        *                Before resource manager unload least used resources it will allocate
87                        *                memory for the new resource to check how much it needs. So we still need
88                        *                some free memory for this temporary allocation. So 80-90% are good
89                        *                values for memory budget.
90                        *                If you want to be very precisious you can set this value to memory
91                        *                size minus biggest resource size. Which will use maximal available
92                        *                memory space.
93                        **/
94                        Result setMemoryBudget(size_t bytes);
95       
96       
97                        /**
98                        * Get the memory budget resource manager have got.
99                        **/
100                        size_t   getMemoryBudget() const;
101       
102       
103                        /**
104                        * Returns the usage of memory in bytes.
105                        **/
106                        size_t   getMemoryUsage() const;
107#endif
108       
109                        /**
110                        * Here you can register any loader by the manager. Loader are used to load resources
111                        * from files/memory and to store resources in the memory. By registration of
112                        * a loader you have to specify his unique name. This name will be used to access
113                        * to stored loader (for example to remove it).
114                        *
115                        * @param name Unique loader name
116                        * @param loader Smart pointer containing the loader
117                        *
118                        * @return either OK or error code:
119                        *                       - RES_LOADER_ALREADY_EXISTS
120                        *                       - BAD_PARAMETERS
121                        *
122                        * @note If there is two loaders which do support loading of file of the same filetype,
123                        *                so the behavior of getting appropriate loader is undefined.
124                        **/
125                        Result  registerLoader  (const ::std::string& name, ResourceLoader loader);
126       
127       
128                        /**
129                        * Removes the loader from the loader list. All bounded filetypes
130                        * registrations will also be removed. So after you calling this you have
131                        * to check whenever you still able to load filetypes you want to use.
132                        *
133                        * @param name Unique name of the loader
134                        * @return either OK or error code:
135                        *               - RES_LOADER_NOT_REGISTERED
136                        *               - RES_ERROR
137                        **/
138                        Result  removeLoader    (const ::std::string& name);
139       
140       
141                        /**
142                        * Return the loader by given filetype. If there is no loader which can load
143                        * such a filetype NULL will be returned
144                        * @param fileType File type for which one the loader should be found
145                        **/
146                        ResourceLoader getLoaderByFile  (const ::std::string& fileType);
147       
148       
149                        /**
150                        * Get a loader that support creating of resource instances of the given resource type
151                        * @param resType Unique name of the resource type
152                        * @return either NULL or resource loader
153                        **/
154                        ResourceLoader getLoaderByResource(const ::std::string& resType);
155       
156       
157                        /**
158                        * Return the loader by given name. If the loader with this name does not
159                        * exists, so NULL will be given back
160                        **/
161                        ResourceLoader getLoader                        (const ::std::string& name);
162       
163       
164                        /**
165                        * Create a resource object of a certain type. An according resource loader has
166                        * to be registered before to provide manager with creating function.
167                        * If no loader was registered NULL will be returned.
168                        *
169                        * After you created a resource you will still not be able to use it. You have
170                        * to load a resource from a file. You have also to load it, because we are using
171                        * concept of empty resources. So loader has to get access on the resource to
172                        * initialize it with empty data.
173                        *
174                        * @param name Unique name of that resource. The name must be specified !!!
175                        * @param group Name of the group to which this resource belongs.
176                        * @param resourceType Unique type name of the resource type
177                        * @param params Here you can specify parameter which will be send to the loader/creator
178                        *                               so that he can setup resource parameters. Default is NULL, so no parameters.
179                        **/
180                        IResourcePtr    createResource  (const std::string& name,
181                                                                                        const std::string& group,
182                                                                                        const std::string& resourceType,
183                                                                                        PropertyList* params = NULL);
184       
185                        /**
186                        * Load a resource from a file. For loading of a resource the registered
187                        * loader will be used. The filetype is defined by the last
188                        * characters of the file name. If we can not find this characters
189                        * so the manual loader will be used if such one is specified. Manual loader
190                        * will also be used if it is specified and filetype is detected.
191                        * You can assign your resource to special group. The group names
192                        * has to be unique.
193                        *
194                        * If such a resource could not load, NULL will be returned.
195                        *
196                        * If you do not specify any resource type, so the loader which has to be used
197                        * will be detected by the file name. If no such found error will be  given back.
198                        *
199                        * @param name Unique name fo the resource
200                        * @param group Group name to which this resource should be assigned
201                        * @param resourceType Unique type name of the resource
202                        * @param fileName File name of the file to be loaded
203                        * @param params Here you can specify parameter which will be send to the loader/creator
204                        *                               so that he can setup resource parameters. Default is NULL, so no parameters.
205                        * @param manualLoader Loader which should be used if you want to overload
206                        *                               all registered loader.
207                        *
208                        **/
209                        IResourcePtr    loadResource    (const std::string& name,
210                                                                                        const std::string& group,
211                                                                                        const std::string& fileName,
212                                                                                        const std::string& resourceType = std::string(),
213                                                                                        PropertyList* params = NULL,
214                                                                                        ResourceLoader manualLoader = ResourceLoader());
215
216#if 0
217                        /**
218                        * This function will add a given resource to the resource management system.
219                        * From now one resource management get the rights for unloading/reloading and
220                        * removing resources from the memory.
221                        *
222                        * @param res  Resource pointer to the resource. (Be careful this is not a smart pointer)
223                        * @param name Unique name of the resource that should be used in the database
224                        * @param group Name of the group to which the resource belongs. If no name specified,
225                        *                               then use name stored in the resource.
226                        * @return either OK or error code
227                        *
228                        * @note The resource should already know which loader does loading
229                        *                of it from files. So database will not assign any loader to
230                        *                that resource. You should do it before calling this method.
231                        **/
232                        Result          add(IResource* res, const std::string& name, const std::string& group = "");
233#endif
234       
235                        /**
236                        * This method is used to lock the resource with the given name for using.
237                        * Locking of pure resource means here, that we want now to access to real resource
238                        * either to empty resource. Because of our transparent functionality of changing
239                        * between real and empty resource (if real resource is unloaded), we must have a possibility
240                        * to access to real resources bypassing this changing mechanism. You will need this for
241                        * example if you want to change some properties of a resource (for example texture flags).
242                        * If your resource is currently unloaded from the memory and you will try to change properties,
243                        * so there would be now effect because settings get changed in empty resource which would
244                        * not change anything (Assumption: resources handles correctly).
245                        *
246                        * Assume the resource is not loaded and you want to access it.
247                        * <code>
248                        *       resource->setPropertyOne(...);
249                        * </code>
250                        * Affect to empty resource, because the resource is unloaded.<br>
251                        * <code>
252                        *       ResourceMgr.lockPure("resource");<br>
253                        *       resource->setPropertyOne(...);<br>
254                        *       ResourceMgr.unlockPure("resource");<br>
255                        * </code>
256                        * Affect to the resource you probably means. You will set the property of the real
257                        * resource and not the empty one.
258                        *
259                        * @param name Unique name of the resource
260                        * @return either OK or error code
261                        *
262                        * @note You have to decide whenever you want to lock your resource or just work as it is. It is safer
263                        * to do locking if you have something like write function and do not lock anything for read only functions.
264                        * e.g:
265                        *       - ReadOnly by textures : getting of a ID, drawing, ...
266                        *       - Write by texture: set new size, get name (it has also to be locked, because empty texture will return
267                        *               a name acoording to empty texture), load, ...
268                        **/
269                        virtual Result          lockPure(const std::string& name);
270       
271                        /**
272                        * Overloaded function to allow locking through pointer directly
273                        * @param res Pointer to the resource
274                        **/
275                        virtual Result          lockPure(IResourcePtr& res);
276       
277                        /**
278                        * Overloaded function to allow locking through handle.
279                        * @param handle Unique handle of the resource
280                        **/
281                        virtual Result          lockPure(ResourceHandle& handle);
282       
283                        /**
284                        * This function is complement to the lockPure(...) methods. This will unlock the
285                        * real resource from using
286                        * @param name Unique name of the resource to be unlocked
287                        **/
288                        virtual Result          unlockPure(const std::string& name);
289       
290                        /**
291                        * Overloaded function to allow unlocking through pointer directly
292                        * @param res Pointer to the resource
293                        **/
294                        virtual Result          unlockPure(IResourcePtr& res);
295       
296                        /**
297                        * Overloaded function to allow unlocking through handle.
298                        * @param handle Unique handle of the resource
299                        **/
300                        virtual Result          unlockPure(ResourceHandle& handle);
301       
302       
303                        /**
304                        * Unload the resource from the memory.
305                        * The registered resource loader will be used to unload the
306                        * resource. After this call all the resource pointers
307                        * will point to an empty resource.
308                        *
309                        * @param name Unique name of the resource
310                        * @return either OK or error code:
311                        *               - RES_NOT_FOUND
312                        * @see IResourceLoader
313                        **/
314                        Result          unload(const std::string& name);
315       
316                        //! @see unload(name)
317                        Result          unload(IResourcePtr& res);
318       
319                        //! @see unload(name)
320                        Result          unload(ResourceHandle& handle);
321       
322       
323                        /**
324                        * Reload the resource, so it will now contain it's real data.
325                        * Call this function if want to get your resource back after
326                        * it was unloaded.
327                        *
328                        * @param name Unique name of the resource
329                        * @return either OK or error code:
330                        *               - RES_NOT_FOUND
331                        *
332                        * @note Reloading of resource will cost time. The resource will
333                        *                try to access to it's file through the loader with which
334                        *                one it was created. So try to implement very intellegent
335                        *                algorithm to prevent reloading/unloading as much as possible
336                        **/
337                        Result          reload(const std::string& name);
338       
339                        //! @see reload(name)
340                        Result          reload(IResourcePtr& res);
341       
342                        //! @see reload(name)
343                        Result          reload(ResourceHandle& handle);
344       
345       
346                        /**
347                        * This will remove the resource from the database.
348                        * After you removed the resource and would try to access to it through the
349                        * manager NULL will be returned.
350                        *
351                        * If you remove the resource from the database all resource pointers
352                        * for this resource will now point to the empty resource object.
353                        * @param name Unique name of the resource
354                        * @return either OK or error code:
355                        *               - RES_NOT_FOUND
356                        * @see IResourcePtr
357                        **/
358                        Result          remove(const std::string& name);
359       
360                        //! @see remove(name)
361                        Result          remove(IResourcePtr& res);
362       
363                        //! @see remove(name)
364                        Result          remove(ResourceHandle& handle);
365       
366       
367                        /**
368                        * Get the pointer to a resource by it's name.
369                        * If there is no resource with this name, so NULL pointer will be returned
370                        *
371                        * @param name Unique name of the resource
372                        *
373                        **/
374                        IResourcePtr    getByName(const std::string& name);
375       
376                        /**
377                        * Same as getByName(), but here you get the resource by handle.
378                        **/
379                        IResourcePtr    getByHandle(const ResourceHandle& handle);
380       
381                        /**
382                        * Unload all elements from the group.
383                        * @param group Unique name of the group
384                        * @return either OK or RES_GROUP_NOT_FOUND or an error code from unload(...) - method
385                        **/
386                        Result          unloadGroup(const std::string& group);
387       
388                        /**
389                        * Reload all elements in the group
390                        * @param group Unique name of the group
391                        * @return either OK or RES_GROUP_NOT_FOUND or an error code from reload(...) - method
392                        **/
393                        Result          reloadGroup(const std::string& group);
394       
395                        /**
396                        * Remove all elements in the group
397                        * @param group Unique name of the group
398                        * @return either OK or RES_GROUP_NOT_FOUND or an error code from remove(...) - method
399                        **/
400                        Result          removeGroup(const std::string& group);
401       
402                        /**
403                        * Release all resources. This will unload and then remove all
404                        * resources from the manager. Use this to clean used memory.
405                        **/
406                        void removeAllRes();
407       
408                        /**
409                        * Remove all loaders from the manager
410                        **/
411                        void removeAllLoaders();
412       
413       
414                protected:
415       
416                        //! Only engine can create the instance
417                        friend class Engine;
418       
419                        /**
420                        * The constructor is protected, so only friends (engine's core)
421                        * are able to create the instance
422                        **/
423                        ResourceManager();
424       
425       
426                        //------------------------------------------
427                        // Variables
428                        //------------------------------------------
429                        //size_t                mMemBudget;
430                        //size_t                mMemUsage;
431       
432                        ResourceHandle  mLastHandle;
433       
434                        typedef ::std::map< ::std::string, ResourceLoader> loader_map;
435       
436                        loader_map      mLoader;
437       
438       
439                        typedef ::std::map<ResourceHandle, SharedPtr<ResourceHolder> >   res_hdl_map;
440                        typedef ::std::map< ::std::string, ResourceHandle>               res_str_map;
441                        typedef ::std::map< ::std::string, ::std::list<ResourceHandle> > res_grp_map;
442                        typedef ::std::map< ::std::string, SharedPtr<IResource> >        res_empty_map;
443       
444                        res_hdl_map     mResource;
445                        res_str_map mResourceName;
446                        res_grp_map mResourceGroup;
447                        res_empty_map mEmptyResource;
448       
449       
450                        //------------------------------------------
451                        // Methods
452                        //------------------------------------------
453       
454#if 0
455                        /**
456                        * Check if we have now memory available.
457                        * If we need to remove some resources from the memory to get free place
458                        * so do it.
459                        **/
460                        virtual Result checkMemoryUsage();
461                        /**
462                        * This will remove the resource from the database.
463                        * After you removed the resource and would try to access to it through the
464                        * manager NULL will be returned.
465                        *
466                        * However if you remove the resource it is not just deleted from the memory
467                        * because of shared pointer system. So the parts of application, wich gets
468                        * pointers to it, are still able to access to it.
469                        *
470                        * @param resPtr Remove the resource whithin this pointer
471                        * @return either OK or error code:
472                        *               - RES_NOT_FOUND
473                        **/
474                        Result removeImpl(IResourcePtr& resPtr);
475#endif
476       
477       
478                        /**
479                        * Get the appropriate holder for the given resource name.
480                        * This is a internal function, so it will return a pointer to a smart pointer
481                        * pointing to the holder. This is done because of performance reasons.
482                        * If nothing found NULL will be returned.
483                        **/
484                        SharedPtr<ResourceHolder>*      getHolderByName(const ::std::string& name);
485       
486                        /**
487                        * Same as getHolderByName(...) but now get the holder through a handle
488                        **/
489                        SharedPtr<ResourceHolder>*      getHolderByHandle(const ResourceHandle& handle);
490
491#if 0
492                        /**
493                        * This function should create a empty resource and give a pointer to it back.
494                        * This is a virtual function which returns NULL in the base class. So if you
495                        * want to derive other resource manager classes and you want to have very
496                        * special creating function you should write out this function.
497                        *
498                        * If this method is returns NULL, so we will use the resource object
499                        * created createEmptyResource() function.
500                        * @see createEmptyResource()
501                        **/
502                        virtual IResource* createEmptyImpl(ResourceHandle hdl,
503                                                                                                const ::std::string& name,
504                                                                                                const ::std::string& group,
505                                                                                                const ::std::string& resourceType,
506                                                                                                NameValuePairs* params = NULL){return NULL;}
507       
508                        /**
509                        * This function should load a resource from a file. This function is declared
510                        * as virtual so it can be overloaded through functions from dirived classes.
511                        * This is not needed but if you want to have your own loading functions, you
512                        * can do it here
513                        * @see loadResource()
514                        **/
515                        virtual IResource* loadResourceImpl(ResourceHandle hdl,
516                                                                                                const ::std::string& name,
517                                                                                                const ::std::string& group,
518                                                                                                const ::std::string& resourceType,
519                                                                                                const ::std::string& fileName,
520                                                                                                NameValuePairs* params = NULL,
521                                                                                                ResourceLoader manualLoader = ResourceLoader()){return NULL;}
522       
523       
524                        /**
525                        * This function will check if there is already an empty resource for the given resource
526                        * type and will create such one if it is not exists
527                        * @param resourceType Unique name of a resource type
528                        * @param empty Reference to smart pointer containing an empty resource after
529                        * @param loader Appropritate loader for that resource type
530                        **/
531                        virtual Result checkEmptyResource(const ::std::string resourceType,
532                                                                                                SharedPtr<IResource>& empty,
533                                                                                                ResourceLoader loader);
534#endif
535
536                private:
537                       
538                        //! Resource loader have access to certain functions
539                        friend class IResourceLoader;
540                       
541                        /**
542                        * Get an empty resource of given type.
543                        *
544                        * @param type Type of the resource for which one the empty object should be returned
545                        **/
546                        SharedPtr<IResource> getEmpty(const std::string& type);
547               
548                        /**
549                         * Setup a new empty resource for the given resource type.
550                         **/
551                        void setEmpty(const std::string& type, SharedPtr<IResource> empty);
552                       
553                        /**
554                         * Check if a resource with the given name already registered in
555                         * the database.
556                         **/
557                        bool isResourceRegistered(const std::string& name);
558
559                        /**
560                         * Notify the manager about newly created resource.
561                         * Manager will create a holder for this
562                         * and store the things in the database
563                         **/
564                        void notifyCreated(IResource*);
565                       
566                        /**
567                         * This method is called by the loaders to notify the database,
568                         * that the according resource was loaded
569                         **/
570                        void notifyLoaded(IResource*);
571
572                        /**
573                         * Notify the database, that a certain resource was unloaded.
574                         **/
575                        void notifyUnloaded(IResource*);
576
577                        /**
578                         * Notify the database that a certain resource was removed from the
579                         * memory. After this method returns the resource will be deleted.
580                         **/
581                        void notifyRemove(IResource*);
582
583                        /**
584                         * Get a new handle for the resource object. Handles are unique.
585                         **/
586                        NR_FORCEINLINE ResourceHandle getNewHandle() { return ++mLastHandle; }
587
588                        //! Load any resource from the script
589                        ScriptFunctionDef(scriptLoadResource);
590                       
591                        //! Unload any resource from scripts
592                        ScriptFunctionDef(scriptUnloadResource);
593                       
594        };
595
596};
597
598#endif
Note: See TracBrowser for help on using the repository browser.