resource.h
Classes:
class
class
class
class
class
class
This template may be used to register a load signal as follows: static ResourceRegisterLoadSignal
Detailed Description
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#ifndef __RESOURCE_H__ 25#define __RESOURCE_H__ 26 27#ifndef _DATACHUNKER_H_ 28#include "core/dataChunker.h" 29#endif 30 31#ifndef _PATH_H_ 32#include "core/util/path.h" 33#endif 34 35#ifndef _REFBASE_H_ 36#include "core/util/refBase.h" 37#endif 38 39#ifndef _TIMECLASS_H_ 40#include "core/util/timeClass.h" 41#endif 42 43#ifndef _TSIGNAL_H_ 44#include "core/util/tSignal.h" 45#endif 46 47#ifndef _PLATFORMASSERT_H_ 48#include "platform/platformAssert.h" 49#endif 50 51class ResourceManager; 52 53// This is a utility class used by the resource manager. 54// The prime responsibility of this class is to delete 55// a resource. The base type is never used, but a template 56// version is always derived that knows how to delete the 57// particular type of resource. Normally, one needs not 58// worry about this class. However, if one wants to delete 59// a particular resource in a special manner, one may 60// override the ResourceHolder<T>::~ResourceHolder method. 61class ResourceHolderBase 62{ 63public: 64 static FreeListChunker<ResourceHolderBase> smHolderFactory; 65 66 virtual ~ResourceHolderBase() {} 67 68 // Return void pointer to resource data. 69 void *getResource() const { return mRes; } 70 71protected: 72 // Construct a resource holder pointing at 'p'. 73 ResourceHolderBase(void *p) : mRes(p) {} 74 75 void *mRes; 76}; 77 78// All resources are derived from this type. The base type 79// is only instantiated by the resource manager 80// (the resource manager will return a base resource which a 81// derived resource, Resource<T>, will construct itself 82// with). Base class handles locking and unlocking and 83// provides several virtual functions to be defined by 84// derived resource. 85class ResourceBase 86{ 87 friend class ResourceManager; 88 89protected: 90 class Header; 91 92public: 93 typedef U32 Signature; 94 95public: 96 ResourceBase(Header *header) { mResourceHeader = (header ? header : &smBlank); } 97 virtual ~ResourceBase() {} 98 99 const Torque::Path &getPath() const 100 { 101 AssertFatal(mResourceHeader != NULL,"ResourceBase::getPath called on invalid resource"); 102 return mResourceHeader->getPath(); 103 } 104 105 U32 getChecksum() const 106 { 107 AssertFatal(mResourceHeader != NULL,"ResourceBase::getChecksum called on invalid resource"); 108 return mResourceHeader->getChecksum(); 109 } 110 111protected: 112 113 typedef void ( *NotifyUnloadFn )( const Torque::Path& path, void* resource ); 114 115 class Header : public StrongRefBase 116 { 117 public: 118 Header() 119 : mSignature(0), 120 mResource(NULL), 121 mNotifyUnload( NULL ) 122 { 123 } 124 125 const Torque::Path &getPath() const { return mPath; } 126 127 Signature getSignature() const { return mSignature; } 128 void *getResource() const { return (mResource ? mResource->getResource() : NULL); } 129 U32 getChecksum() const; 130 131 virtual void destroySelf(); 132 133 private: 134 135 friend class ResourceBase; 136 friend class ResourceManager; 137 138 Signature mSignature; 139 ResourceHolderBase* mResource; 140 Torque::Path mPath; 141 NotifyUnloadFn mNotifyUnload; 142 }; 143 144protected: 145 static Header smBlank; 146 ResourceBase() : mResourceHeader(&smBlank) {} 147 148 StrongRefPtr<Header> mResourceHeader; 149 150 void assign(const ResourceBase &inResource, void* resource = NULL); 151 152 // The following functions are virtual, but cannot be pure-virtual 153 // because we need to be able to instantiate this class. 154 155 // To be defined by derived class. Creates a resource 156 // holder of the desired type. Resource template handles 157 // this, so one should never need to override. 158 virtual ResourceHolderBase *createHolder(void *) 159 { 160 AssertFatal(0,"ResourceBase::createHolder: should not be called"); 161 return NULL; 162 } 163 164 // Create a Resource of desired type using passed path. Derived 165 // resource class must define this. 166 virtual void *create(const Torque::Path &path) 167 { 168 AssertFatal(0,"ResourceBase::create: should not be called"); 169 return NULL; 170 } 171 172 // Return signature for desired type. 173 virtual Signature getSignature() const 174 { 175 return mResourceHeader->getSignature(); 176 } 177 178 virtual Signal<bool(const Torque::Path &, void**)> &getStaticLoadSignal() 179 { 180 AssertFatal(0,"ResourceBase::getStaticLoadSignal: should not be called"); 181 static Signal<bool(const Torque::Path &, void**)> sLoadSignal; 182 183 return sLoadSignal; 184 } 185 186 virtual void _triggerPostLoadSignal() {} 187 virtual NotifyUnloadFn _getNotifyUnloadFn() { return ( NotifyUnloadFn ) NULL; } 188}; 189 190// This is a utility class used by resource manager. Classes derived 191// from this template pretty much just know how to delete the template's 192// type. 193template<class T> class ResourceHolder : public ResourceHolderBase 194{ 195public: 196 ResourceHolder(T *t) : ResourceHolderBase(t) {} 197 virtual ~ResourceHolder() { delete ((T*)mRes); } 198}; 199 200// Resource template. When dealing with resources, this is the 201// class that will be used. One creates resources by opening or 202// creating them via the resource manager. The resource manager 203// returns ResourceBases, which can be used to construct any 204// type of resource (see the constructors for this template). 205// When instantiating classes using this template, it is always 206// necessary to define the create and getSignature methods. 207// The createMethod will be responsible for loading a resource 208// from disk using passed path. 209template<class T> class Resource : public ResourceBase 210{ 211public: 212 Resource() {} 213 Resource(const ResourceBase &base) { assign(base); } 214 215 void operator=(const ResourceBase & base) { assign(base); } 216 T* operator->() { return getResource(); } 217 T& operator*() { return *getResource(); } 218 operator T*() { return getResource(); } 219 const T* operator->() const { return getResource(); } 220 const T& operator*() const { return *getResource(); } 221 operator const T*() const { return getResource(); } 222 223 void setResource(const ResourceBase & base, void* resource) { assign(base, resource); } 224 225 static Signature signature(); 226 227 /// Registering with this signal will give an opportunity to handle resource 228 /// creation before calling the create() function. This may be used to handle 229 /// file extensions differently and allow a more plugin-like approach to 230 /// adding resources. Using this mechanism, one could, for example, override 231 /// the default methods for loading DTS without touching the main source. 232 static Signal<bool(const Torque::Path &, void**)> &getLoadSignal() 233 { 234 static Signal<bool(const Torque::Path &, void**)> sLoadSignal; 235 return sLoadSignal; 236 } 237 238 /// Register with this signal to get notified when resources of this type 239 /// have been loaded. 240 static Signal< void( Resource< T>& ) >& getPostLoadSignal() 241 { 242 static Signal< void( Resource< T>& ) > sPostLoadSignal; 243 return sPostLoadSignal; 244 } 245 246 /// Register with this signal to get notified when resources of this type 247 /// are about to get unloaded. 248 static Signal< void( const Torque::Path&, T* ) >& getUnloadSignal() 249 { 250 static Signal< void( const Torque::Path&, T* ) > sUnloadSignal; 251 return sUnloadSignal; 252 } 253 254private: 255 T *getResource() { return (T*)mResourceHeader->getResource(); } 256 const T *getResource() const { return (T*)mResourceHeader->getResource(); } 257 258 Signature getSignature() const { return Resource<T>::signature(); } 259 260 ResourceHolderBase *createHolder(void *); 261 262 Signal<bool(const Torque::Path &, void**)> &getStaticLoadSignal() { return getLoadSignal(); } 263 264 static void _notifyUnload( const Torque::Path& path, void* resource ) { getUnloadSignal().trigger( path, ( T* ) resource ); } 265 266 virtual void _triggerPostLoadSignal() { getPostLoadSignal().trigger( *this ); } 267 virtual NotifyUnloadFn _getNotifyUnloadFn() { return ( NotifyUnloadFn ) &_notifyUnload; } 268 269 // These are to be define by instantiated resources 270 // No generic version is provided...however, since 271 // base resources are instantiated by resource manager, 272 // these are not pure virtuals if undefined (but will assert)... 273 void *create(const Torque::Path &path); 274}; 275 276 277template<class T> inline ResourceHolderBase *Resource<T>::createHolder(void *ptr) 278{ 279 ResourceHolder<T> *resHolder = (ResourceHolder<T>*)(ResourceHolderBase::smHolderFactory.alloc()); 280 281 resHolder = constructInPlace(resHolder,(T*)ptr); 282 283 return resHolder; 284} 285 286//----------------------------------------------------------------------------- 287// Load Signal Hooks. 288//----------------------------------------------------------------------------- 289 290/// This template may be used to register a load signal as follows: 291/// static ResourceRegisterLoadSignal<T> sgAuto( staticLoadFunction ); 292template <class T> 293class ResourceRegisterLoadSignal 294{ 295public: 296 ResourceRegisterLoadSignal( Delegate<bool(const Torque::Path &, void **)> func ) 297 { 298 Resource<T>::getLoadSignal().notify( func ); 299 } 300}; 301 302template< class T > 303class ResourceRegisterPostLoadSignal 304{ 305 public: 306 307 ResourceRegisterPostLoadSignal( Delegate< void( Resource< T>& ) > func ) 308 { 309 Resource< T >::getPostLoadSignal().notify( func ); 310 } 311}; 312 313template< class T > 314class ResourceRegisterUnloadSignal 315{ 316 public: 317 318 ResourceRegisterUnloadSignal( Delegate< void( const Torque::Path&, T* ) > func ) 319 { 320 Resource< T >::getUnloadSignal().notify( func ); 321 } 322}; 323 324#endif // __RESOURCE_H__ 325