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_HOLDER_H_ 00015 #define _NR_RESOURCE_HOLDER_H_ 00016 00017 00018 //---------------------------------------------------------------------------------- 00019 // Includes 00020 //---------------------------------------------------------------------------------- 00021 #include "Prerequisities.h" 00022 00023 namespace nrEngine{ 00024 00025 /** 00026 * This constant defines the size of the lock stack. 00027 * All locking states are stored in the stack, to allow nested lock/unlock calling. 00028 * \ingroup resource 00029 **/ 00030 const int32 NR_RESOURCE_LOCK_STACK = 128; 00031 00032 //! Interstage between manager and resources for more efficience and safety 00033 /** 00034 * This is a holder class which is holding a resource of different type. 00035 * Resource pointers are pointing to this holder, so by referencing the pointer 00036 * you do not have to ask the manager to get the resource, but directly to access 00037 * it through this holder. So actually resource manager manages holders and 00038 * not resources or pointers directly. 00039 * 00040 * We use such a system to be more efficient by dereferncing the resource pointer. 00041 * Other and more trivial way is to ask the manager for resource by giving him the 00042 * handle. This end in a look up of handle tables and returning the resource pointer. 00043 * If we use holders, pointers will directly access that holders and each holder 00044 * is showing to one resource. So we do not have to do any lookups. 00045 * 00046 * This class is working transparent to the whole resource management system, so 00047 * you actually do not have to know how this class works and you also do not have 00048 * to derive any classes from it. 00049 * 00050 * This system was get from Game Programming Gems 4, and was expanded to be more 00051 * flexible and more efficient. 00052 * 00053 * \ingroup resource 00054 */ 00055 class _NRExport ResourceHolder{ 00056 public: 00057 00058 /** 00059 * Remove the object from the memory and also delete the resource 00060 * which is holded by this holder. The destructor should be declared as 00061 * public so it can be used by smart pointers 00062 **/ 00063 ~ResourceHolder(); 00064 00065 private: 00066 00067 friend class IResourceLoader; 00068 friend class IResourcePtr; 00069 friend class ResourceManager; 00070 00071 /** 00072 * Create the object of this class 00073 **/ 00074 ResourceHolder(IResource* res, IResource* empty); 00075 00076 //! pointer that holds the resource 00077 IResource* mResource; 00078 00079 //! pointer that holds the empty resource object 00080 IResource* mEmptyResource; 00081 00082 //! Store number that represents how often the resource was in use 00083 uint32 countAccess; 00084 00085 //! Store the status if real resources lock stack 00086 bool mLockStack[NR_RESOURCE_LOCK_STACK]; 00087 00088 //! Current position in the stack 00089 int32 mLockStackTop; 00090 00091 //! Empty lock status 00092 bool mEmptyLockStack[NR_RESOURCE_LOCK_STACK]; 00093 00094 //! Position in empty locking state 00095 int32 mEmptyLockStackTop; 00096 00097 /** 00098 * Lock real resource for using. Locking has the effect that the getResource() method 00099 * will now return real resources also if it is unloaded. 00100 * 00101 * @return true if locking was successfull otherwise false 00102 * @note If the lock stack is full you are not able lock anymore 00103 **/ 00104 bool lockResource(); 00105 00106 /** 00107 * Unlock the real resurce. After unlocking you have standard behavior about using 00108 * of empty resources. If resource is unloaded, so empty resource will be used. 00109 * 00110 * @return true if unlocking was successfull otherwise false 00111 * @note In complement of the locking, you are always able to unlock. 00112 * If the lock state stack is empty and you are unlocking the resource, so this 00113 * do not affect anything. 00114 **/ 00115 void unlockResource(); 00116 00117 /** 00118 * Lock an empty resource to be used even if a real resource is loaded. 00119 * This method can be used to temporary point all pointers to 00120 * an empty resource instead of a real one. 00121 * 00122 * If you lock an empty and pure/real resource at the same time, 00123 * so warning will be generated and an empty resource will be given 00124 * @see lockPure(); 00125 **/ 00126 bool lockEmpty(); 00127 00128 /** 00129 * Unlock from an empty resource and switch to the case before the lock was done 00130 **/ 00131 void unlockEmpty(); 00132 00133 /** 00134 * Reset the stored resource to a new value 00135 **/ 00136 void resetResource(IResource* res); 00137 00138 /** 00139 * Returns true if this holder has a pointer to a empty resource 00140 **/ 00141 NR_FORCEINLINE bool hasEmpty() const{ 00142 return mEmptyResource == NULL; 00143 } 00144 00145 /** 00146 * Return the number of access to this resource 00147 **/ 00148 NR_FORCEINLINE uint32 getAccessCount() const{ 00149 return countAccess; 00150 } 00151 00152 /** 00153 * Each access to the resource will should call this function. Here 00154 * we do work that has to be done if a resource was used. 00155 **/ 00156 void touchResource(); 00157 00158 /** 00159 * Check whenever the resource is currently locked 00160 **/ 00161 NR_FORCEINLINE bool isLocked(){ 00162 if (mLockStackTop > 0) 00163 return mLockStack[mLockStackTop - 1]; 00164 else 00165 return false; 00166 } 00167 00168 /** 00169 * Check whenever the resource is currently locked to an empty resource 00170 **/ 00171 NR_FORCEINLINE bool isEmptyLocked() 00172 { 00173 if (mEmptyLockStackTop > 0) 00174 return mEmptyLockStack[mEmptyLockStackTop - 1]; 00175 else 00176 return false; 00177 } 00178 00179 /** 00180 * This will bind this holder to specific empty resource. 00181 * After loading of a resource from a file the manager will 00182 * create/load the empty resource according to the type of the resource. 00183 * Then it will generate a name for it and will bind the holder to that 00184 * empty resource. So if you will next load a resource of the same type, 00185 * so holder's empty resource pointer will still point to the same one. 00186 **/ 00187 void setEmptyResource(IResource* res); 00188 //void setEmptyResource(SharedPtr<IResource> res); 00189 00190 /** 00191 * Returns the empty resource of the resource type holded by this holder. 00192 **/ 00193 IResource* getEmpty(); 00194 00195 00196 /** 00197 * Get access to the stored resource. 00198 * We declare this function as private, so we cannot access to the resource 00199 * from outside either as from manager or a smart pointer to resources. 00200 * We need to do it in such a way, to prevent you from deleting the resources 00201 * from outside as from the resource management system. 00202 * 00203 * If the resource is temporary unloaded or if it is not exists, the holder will 00204 * give you the empty resource back, which still can be NULL or not 00205 * 00206 * Each call of getResource() method will count up the access number. 00207 **/ 00208 IResource* getResource(); 00209 00210 }; 00211 00212 }; 00213 #endif