ResourceManager.h

00001 /***************************************************************************
00002  *                                                                         *
00003  *   (c) Art Tevs, MPI Informatik Saarbruecken                             *
00004  *       mailto: <tevs@mpi-sb.mpg.de>                                      *
00005  *                                                                         *
00006  *   This program is free software; you can redistribute it and/or modify  *
00007  *   it under the terms of the GNU General Public License as published by  *
00008  *   the Free Software Foundation; either version 2 of the License, or     *
00009  *   (at your option) any later version.                                   *
00010  *                                                                         *
00011  ***************************************************************************/
00012 
00013 
00014 #ifndef _NR_RESOURCE_MANAGER_H_
00015 #define _NR_RESOURCE_MANAGER_H_
00016 
00017 
00018 //----------------------------------------------------------------------------------
00019 // Includes
00020 //----------------------------------------------------------------------------------
00021 #include "Prerequisities.h"
00022 #include "ResourceSystem.h"
00023 #include "ScriptEngine.h"
00024 
00025 namespace nrEngine {
00026 
00027         //! General pointer/handle based resource management system
00028         /**
00029         * This class is a manger for every kind of resource used in our games.
00030         * Textures, sounds, meshes, ... - all things that can be loaded from disk
00031         * are resources managed by this module. You can derive your own classes
00032         * to write own storing algorithms for different kind of resources. This class
00033         * will use standard implementation and will try to be as efficient as possible.
00034         * This manager can index resources, look them up, load and destroy them, and
00035         * temporaly unload resources from memory to use only allowd size of memory.
00036         *
00037         * We will use a priority system to determine which resources can be unloaded
00038         * and for two resources of the same priority the most used will stay in memory.
00039         *
00040         * This code and idea was get from Game Programming Gems 4. <a href="http://www.ogre3d.org">
00041         * Ogre3D-Library</a> was also used to get an idea how to get the resource manager
00042         * working without using a whole library behind.
00043         *
00044         *
00045         * <b>-</b> Meaning of resource groups:
00046         *               @par - Each resource can exists in a group.
00047         *                        - Each group has got it's unique names.
00048         *                        - You can access to whole groups either to single resources.
00049         *                        - E.g: you can split your level in patches and each resource in such a patch is
00050         *                          in patch's resource group. So if the player go to far away from such a patch,
00051         *                          it can be disabled or unloaded from the memory. You have now just to call one
00052         *                          unload function for the whole group.
00053         *                        - Groups must not be disjoint, so you can have same resource in different groups.
00054         *
00055         * \ingroup resource
00056         **/
00057         class _NRExport ResourceManager{
00058                 public:
00059         
00060                         /**
00061                          * Release all used memory and also mark all loaded resources to unload. After
00062                          * you calling the destructor of ResourceManager class all created resources
00063                          * and loaders will be removed from the memory.
00064                         **/
00065                         virtual ~ResourceManager();
00066 
00067 #if 0
00068                         /**
00069                         * Set amount of memory that can be used by the manager. Set this value to 80-90%
00070                         * of your physical memory if you do not have any virtual memory in your system
00071                         * available. The manager will try to stay in the budget you given for him.
00072                         * Resources that are least used and has got lowest priority will be unloaded
00073                         * to free the memory to stay in the given budget of memory.
00074                         *
00075                         * @param bytes Count of bytes which can be used for resource storing
00076                         * @return either OK or error code.
00077                         *
00078                         * @note You can set this value to ca 80-90% of your memory available.
00079                         *                Before resource manager unload least used resources it will allocate
00080                         *                memory for the new resource to check how much it needs. So we still need
00081                         *                some free memory for this temporary allocation. So 80-90% are good
00082                         *                values for memory budget.
00083                         *                If you want to be very precisious you can set this value to memory
00084                         *                size minus biggest resource size. Which will use maximal available
00085                         *                memory space.
00086                         **/
00087                         Result setMemoryBudget(size_t bytes);
00088         
00089         
00090                         /**
00091                         * Get the memory budget resource manager have got.
00092                         **/
00093                         size_t   getMemoryBudget() const;
00094         
00095         
00096                         /**
00097                         * Returns the usage of memory in bytes.
00098                         **/
00099                         size_t   getMemoryUsage() const;
00100 #endif
00101         
00102                         /**
00103                         * Here you can register any loader by the manager. Loader are used to load resources
00104                         * from files/memory and to store resources in the memory. By registration of
00105                         * a loader you have to specify his unique name. This name will be used to access
00106                         * to stored loader (for example to remove it).
00107                         *
00108                         * @param name Unique loader name
00109                         * @param loader Smart pointer containing the loader
00110                         *
00111                         * @return either OK or error code:
00112                         *                       - RES_LOADER_ALREADY_EXISTS
00113                         *                       - BAD_PARAMETERS
00114                         *
00115                         * @note If there is two loaders which do support loading of file of the same filetype,
00116                         *                so the behavior of getting appropriate loader is undefined.
00117                         **/
00118                         Result  registerLoader  (const std::string& name, ResourceLoader loader);
00119         
00120         
00121                         /**
00122                         * Removes the loader from the loader list. All bounded filetypes
00123                         * registrations will also be removed. So after you calling this you have
00124                         * to check whenever you still able to load filetypes you want to use.
00125                         *
00126                         * @param name Unique name of the loader
00127                         * @return either OK or error code:
00128                         *               - RES_LOADER_NOT_REGISTERED
00129                         *               - RES_ERROR
00130                         **/
00131                         Result  removeLoader    (const std::string& name);
00132         
00133         
00134                         /**
00135                         * Return the loader by given filetype. If there is no loader which can load
00136                         * such a filetype NULL will be returned
00137                         * @param fileType File type for which one the loader should be found
00138                         **/
00139                         ResourceLoader getLoaderByFile  (const std::string& fileType);
00140         
00141         
00142                         /**
00143                         * Get a loader that support creating of resource instances of the given resource type
00144                         * @param resType Unique name of the resource type
00145                         * @return either NULL or resource loader
00146                         **/
00147                         ResourceLoader getLoaderByResource(const std::string& resType);
00148         
00149         
00150                         /**
00151                         * Return the loader by given name. If the loader with this name does not
00152                         * exists, so NULL will be given back
00153                         **/
00154                         ResourceLoader getLoader                        (const std::string& name);
00155         
00156         
00157                         /**
00158                         * Create a resource object of a certain type. An according resource loader has
00159                         * to be registered before to provide manager with creating function.
00160                         * If no loader was registered NULL will be returned.
00161                         * 
00162                         * After you created a resource you will still not be able to use it. You have
00163                         * to load a resource from a file. You have also to load it, because we are using
00164                         * concept of empty resources. So loader has to get access on the resource to
00165                         * initialize it with empty data.
00166                         *
00167                         * @param name Unique name of that resource. The name must be specified !!!
00168                         * @param group Name of the group to which this resource belongs.
00169                         * @param resourceType Unique type name of the resource type
00170                         * @param params Here you can specify parameter which will be send to the loader/creator
00171                         *                               so that he can setup resource parameters. Default is NULL, so no parameters.
00172                         **/
00173                         IResourcePtr    createResource  (const std::string& name,
00174                                                                                         const std::string& group,
00175                                                                                         const std::string& resourceType,
00176                                                                                         PropertyList* params = NULL);
00177         
00178                         /**
00179                         * Load a resource from a file. For loading of a resource the registered
00180                         * loader will be used. The filetype is defined by the last
00181                         * characters of the file name. If we can not find this characters
00182                         * so the manual loader will be used if such one is specified. Manual loader
00183                         * will also be used if it is specified and filetype is detected.
00184                         * You can assign your resource to special group. The group names
00185                         * has to be unique.
00186                         *
00187                         * If such a resource could not load, NULL will be returned.
00188                         *
00189                         * If you do not specify any resource type, so the loader which has to be used
00190                         * will be detected by the file name. If no such found error will be  given back.
00191                         * 
00192                         * @param name Unique name fo the resource
00193                         * @param group Group name to which this resource should be assigned
00194                         * @param resourceType Unique type name of the resource
00195                         * @param fileName File name of the file to be loaded
00196                         * @param params Here you can specify parameter which will be send to the loader/creator
00197                         *                               so that he can setup resource parameters. Default is NULL, so no parameters.
00198                         * @param manualLoader Loader which should be used if you want to overload
00199                         *                               all registered loader.
00200                         *
00201                         **/
00202                         IResourcePtr    loadResource    (const std::string& name,
00203                                                                                         const std::string& group,
00204                                                                                         const std::string& fileName,
00205                                                                                         const std::string& resourceType = std::string(),
00206                                                                                         PropertyList* params = NULL,
00207                                                                                         ResourceLoader manualLoader = ResourceLoader());
00208 
00209 #if 0
00210                         /**
00211                         * This function will add a given resource to the resource management system.
00212                         * From now one resource management get the rights for unloading/reloading and
00213                         * removing resources from the memory.
00214                         *
00215                         * @param res  Resource pointer to the resource. (Be careful this is not a smart pointer)
00216                         * @param name Unique name of the resource that should be used in the database
00217                         * @param group Name of the group to which the resource belongs. If no name specified,
00218                         *                               then use name stored in the resource.
00219                         * @return either OK or error code
00220                         *
00221                         * @note The resource should already know which loader does loading
00222                         *                of it from files. So database will not assign any loader to
00223                         *                that resource. You should do it before calling this method.
00224                         **/
00225                         Result          add(IResource* res, const std::string& name, const std::string& group = "");
00226 #endif
00227 
00228                         /**
00229                         * This method is used to lock the resource with the given name for using.
00230                         * Locking of pure resource means here, that we want now to access to real resource
00231                         * either to empty resource. Because of our transparent functionality of changing
00232                         * between real and empty resource (if real resource is unloaded), we must have a possibility
00233                         * to access to real resources bypassing this changing mechanism. You will need this for
00234                         * example if you want to change some properties of a resource (for example texture flags).
00235                         * If your resource is currently unloaded from the memory and you will try to change properties,
00236                         * so there would be now effect because settings get changed in empty resource which would
00237                         * not change anything (Assumption: resources handles correctly).
00238                         *
00239                         * Assume the resource is not loaded and you want to access it.
00240                         * <code>
00241                         *       resource->setPropertyOne(...);
00242                         * </code>
00243                         * Affect to empty resource, because the resource is unloaded.<br>
00244                         * <code>
00245                         *       ResourceMgr.lockResource("resource");<br>
00246                         *       resource->setPropertyOne(...);<br>
00247                         *       ResourceMgr.unlockResource("resource");<br>
00248                         * </code>
00249                         * Affect to the resource you probably means. You will set the property of the real
00250                         * resource and not the empty one.
00251                         *
00252                         * @param name Unique name of the resource
00253                         * @return either OK or error code
00254                         *
00255                         * @note You have to decide whenever you want to lock your resource or just work as it is. It is safer
00256                         * to do locking if you have something like write function and do not lock anything for read only functions.
00257                         * e.g:
00258                         *       - ReadOnly by textures : getting of a ID, drawing, ...
00259                         *       - Write by texture: set new size, get name (it has also to be locked, because empty texture will return
00260                         *               a name according to empty texture), load, ...
00261                         **/
00262                         virtual Result          lockResource(const std::string& name);
00263         
00264                         /**
00265                         * Overloaded function to allow locking through pointer directly
00266                         * @param res Pointer to the resource
00267                         **/
00268                         virtual Result          lockResource(IResourcePtr& res);
00269         
00270                         /**
00271                         * Overloaded function to allow locking through handle.
00272                         * @param handle Unique handle of the resource
00273                         **/
00274                         virtual Result          lockResource(ResourceHandle& handle);
00275         
00276                         /**
00277                         * This function is complement to the lockResource(...) methods. This will unlock the
00278                         * real resource from using
00279                         * @param name Unique name of the resource to be unlocked
00280                         **/
00281                         virtual Result          unlockResource(const std::string& name);
00282         
00283                         /**
00284                         * Overloaded function to allow unlocking through pointer directly
00285                         * @param res Pointer to the resource
00286                         **/
00287                         virtual Result          unlockResource(IResourcePtr& res);
00288         
00289                         /**
00290                         * Overloaded function to allow unlocking through handle.
00291                         * @param handle Unique handle of the resource
00292                         **/
00293                         virtual Result          unlockResource(ResourceHandle& handle);
00294 
00295                         /**
00296                         * Unload the resource from the memory.
00297                         * After this call all the resource pointers assigned within the resource
00298                         * will point to an empty resource.
00299                         *
00300                         * @param name Unique name of the resource
00301                         * @return either OK or error code:
00302                         *               - RES_NOT_FOUND
00303                         * @see IResourceLoader
00304                         **/
00305                         Result          unload(const std::string& name);
00306         
00307                         //! @see unload(name)
00308                         Result          unload(IResourcePtr& res);
00309         
00310                         //! @see unload(name)
00311                         Result          unload(ResourceHandle& handle);
00312         
00313         
00314                         /**
00315                         * Reload the resource, so it will now contain it's real data.
00316                         * Call this function if want to get your resource back after
00317                         * it was unloaded.
00318                         *
00319                         * @param name Unique name of the resource
00320                         * @return either OK or error code:
00321                         *               - RES_NOT_FOUND
00322                         **/
00323                         Result          reload(const std::string& name);
00324         
00325                         //! @see reload(name)
00326                         Result          reload(IResourcePtr& res);
00327         
00328                         //! @see reload(name)
00329                         Result          reload(ResourceHandle& handle);
00330         
00331         
00332                         /**
00333                         * This will remove the resource from the database.
00334                         * After you removed the resource and would try to access to it through the
00335                         * manager NULL will be returned.
00336                         *
00337                         * If you remove the resource from the database all resource pointers
00338                         * for this resource will now point to the empty resource object.
00339                         * @param name Unique name of the resource
00340                         * @return either OK or error code:
00341                         *               - RES_NOT_FOUND
00342                         * @see IResourcePtr
00343                         **/
00344                         Result          remove(const std::string& name);
00345         
00346                         //! @see remove(name)
00347                         Result          remove(IResourcePtr& res);
00348         
00349                         //! @see remove(name)
00350                         Result          remove(ResourceHandle& handle);
00351                 
00352                         /**
00353                         * Get the pointer to a resource by it's name.
00354                         * If there is no resource with this name, so NULL pointer will be returned
00355                         *
00356                         * @param name Unique name of the resource
00357                         *
00358                         **/
00359                         IResourcePtr    getByName(const std::string& name);
00360         
00361                         /**
00362                         * Same as getByName(), but here you get the resource by handle.
00363                         **/
00364                         IResourcePtr    getByHandle(const ResourceHandle& handle);
00365         
00366                         /**
00367                         * Unload all elements from the group.
00368                         * @param group Unique name of the group
00369                         * @return either OK or RES_GROUP_NOT_FOUND or an error code from unload(...) - method
00370                         **/
00371                         Result          unloadGroup(const std::string& group);
00372         
00373                         /**
00374                         * Reload all elements in the group
00375                         * @param group Unique name of the group
00376                         * @return either OK or RES_GROUP_NOT_FOUND or an error code from reload(...) - method
00377                         **/
00378                         Result          reloadGroup(const std::string& group);
00379         
00380                         /**
00381                         * Remove all elements in the group
00382                         * @param group Unique name of the group
00383                         * @return either OK or RES_GROUP_NOT_FOUND or an error code from remove(...) - method
00384                         **/
00385                         Result          removeGroup(const std::string& group);
00386         
00387                         /**
00388                          * Get a list of all resource handles for a specified group. The list can be
00389                          * iterated to get the resource handles which are in this group. Use the handles to 
00390                          * get a resource according to it.
00391                          *
00392                          * @param name Unique name of the group 
00393                          * @return List of resource handles containing in this group 
00394                          **/
00395                         const std::list<ResourceHandle>& getGroupHandles(const std::string& name);
00396                         
00397                         
00398                         //! Typedef for the resource map returned by the getResourceMap() method
00399                         typedef std::map< std::string, std::list<ResourceHandle> > ResourceGroupMap;
00400                         
00401                         /**
00402                          * Return the map containing group names and according resource list.
00403                          **/
00404                         const ResourceGroupMap& getResourceMap() { return mResourceGroup; }
00405                         
00406                 private:
00407                 
00408                         /**
00409                         * Release all resources. This will unload and then remove all 
00410                         * resources from the manager. Use this to clean used memory.
00411                         **/
00412                         void removeAllRes();
00413         
00414                         /**
00415                         * Remove all loaders from the manager
00416                         **/
00417                         void removeAllLoaders();
00418         
00419         
00420                         //! Only engine can create the instance
00421                         friend class Engine;
00422         
00423                         /**
00424                         * The constructor is protected, so only friends (engine's core)
00425                         * are able to create the instance
00426                         **/
00427                         ResourceManager();
00428         
00429         
00430                         //------------------------------------------
00431                         // Variables
00432                         //------------------------------------------
00433                         //size_t                mMemBudget;
00434                         //size_t                mMemUsage;
00435         
00436                         ResourceHandle  mLastHandle;
00437         
00438                         typedef std::map< std::string, ResourceLoader> loader_map;
00439                         typedef std::map<ResourceHandle, SharedPtr<ResourceHolder> >   res_hdl_map;
00440                         typedef std::map< std::string, ResourceHandle>               res_str_map;
00441                         typedef std::map< std::string, SharedPtr<IResource> >        res_empty_map;
00442         
00443                         loader_map      mLoader;
00444         
00445                 
00446                         res_hdl_map        mResource;
00447                         res_str_map        mResourceName;
00448                         ResourceGroupMap   mResourceGroup;
00449                         res_empty_map      mEmptyResource;
00450         
00451                         // this list shouldn't be filled. it will be returned if no group were found in getGroupHandles() method 
00452                         std::list<ResourceHandle>       mEmptyResourceGroupHandleList;
00453                         
00454                         //------------------------------------------
00455                         // Methods
00456                         //------------------------------------------
00457         
00458 #if 0
00459                         /**
00460                         * Check if we have now memory available.
00461                         * If we need to remove some resources from the memory to get free place
00462                         * so do it.
00463                         **/
00464                         virtual Result checkMemoryUsage();
00465                         /**
00466                         * This will remove the resource from the database.
00467                         * After you removed the resource and would try to access to it through the
00468                         * manager NULL will be returned.
00469                         *
00470                         * However if you remove the resource it is not just deleted from the memory
00471                         * because of shared pointer system. So the parts of application, wich gets
00472                         * pointers to it, are still able to access to it.
00473                         *
00474                         * @param resPtr Remove the resource whithin this pointer
00475                         * @return either OK or error code:
00476                         *               - RES_NOT_FOUND
00477                         **/
00478                         Result removeImpl(IResourcePtr& resPtr);
00479 #endif
00480         
00481         
00482                         /**
00483                         * Get the appropriate holder for the given resource name.
00484                         * This is a internal function, so it will return a pointer to a smart pointer
00485                         * pointing to the holder. This is done because of performance reasons.
00486                         * If nothing found NULL will be returned.
00487                         **/
00488                         SharedPtr<ResourceHolder>*      getHolderByName(const std::string& name);
00489         
00490                         /**
00491                         * Same as getHolderByName(...) but now get the holder through a handle
00492                         **/
00493                         SharedPtr<ResourceHolder>*      getHolderByHandle(const ResourceHandle& handle);
00494 
00495 #if 0
00496                         /**
00497                         * This function will check if there is already an empty resource for the given resource
00498                         * type and will create such one if it is not exists
00499                         * @param resourceType Unique name of a resource type
00500                         * @param empty Reference to smart pointer containing an empty resource after
00501                         * @param loader Appropritate loader for that resource type
00502                         **/
00503                         virtual Result checkEmptyResource(const std::string resourceType,
00504                                                                                                 SharedPtr<IResource>& empty,
00505                                                                                                 ResourceLoader loader);
00506 #endif
00507 
00508                 private:
00509                         
00510                         //! Resource loader have access to certain functions
00511                         friend class IResourceLoader;
00512 
00513                         //! Resource object hast got access to certain objects
00514                         friend class IResource;
00515                         
00516                         /**
00517                         * Get an empty resource of given type.
00518                         *
00519                         * @param type Type of the resource for which one the empty object should be returned
00520                         **/
00521                         SharedPtr<IResource> getEmpty(const std::string& type);
00522                 
00523                         /**
00524                          * Setup a new empty resource for the given resource type.
00525                          **/
00526                         void setEmpty(const std::string& type, SharedPtr<IResource> empty);
00527                         
00528                         /**
00529                          * Check if a resource with the given name already registered in
00530                          * the database.
00531                          **/
00532                         bool isResourceRegistered(const std::string& name);
00533 
00534                         /**
00535                          * Notify the manager about newly created resource.
00536                          * Manager will create a holder for this
00537                          * and store the things in the database
00538                          **/
00539                         void notifyCreated(IResource*);
00540                         
00541                         /**
00542                          * This method is called by the loaders to notify the database,
00543                          * that the according resource was loaded
00544                          **/
00545                         void notifyLoaded(IResource*);
00546 
00547                         /**
00548                          * Notify the database, that a certain resource was unloaded.
00549                          **/
00550                         void notifyUnloaded(IResource*);
00551 
00552                         /**
00553                          * Notify the database that a certain resource was removed from the
00554                          * memory. After this method returns the resource will be deleted.
00555                          **/
00556                         void notifyRemove(IResource*);
00557 
00558                         /**
00559                          * Get a new handle for the resource object. Handles are unique.
00560                          **/
00561                         NR_FORCEINLINE ResourceHandle getNewHandle() { return ++mLastHandle; }
00562 
00563                         //! Load any resource from the script
00564                         ScriptFunctionDef(scriptLoadResource);
00565                         
00566                         //! Unload any resource from scripts
00567                         ScriptFunctionDef(scriptUnloadResource);
00568                         
00569         };
00570 
00571 };
00572 
00573 #endif

Generated on Wed Sep 12 23:19:42 2007 for nrEngine by  doxygen 1.5.1