]> Dogcows Code - chaz/yoink/blob - src/moof/resource.hh
fixed documentation about where to find licenses
[chaz/yoink] / src / moof / resource.hh
1
2 /*] Copyright (c) 2009-2011, Charles McGarvey [*****************************
3 **] All rights reserved.
4 *
5 * Distributable under the terms and conditions of the 2-clause BSD license;
6 * see the file COPYING for a complete text of the license.
7 *
8 *****************************************************************************/
9
10 #ifndef _MOOF_RESOURCE_HH_
11 #define _MOOF_RESOURCE_HH_
12
13 #include <map>
14 #include <stdexcept>
15 #include <string>
16 #include <vector>
17
18 #include <boost/shared_ptr.hpp>
19 #include <boost/function.hpp>
20
21
22 /**
23 * \file resource.hh
24 * Interface for textures, sounds, and other types of resources.
25 */
26
27 namespace moof {
28
29
30 class resource;
31 typedef boost::shared_ptr<resource> resource_ptr;
32
33 /**
34 * Generic resource class capable of containing any type of resource,
35 * providing a type-safe interface.
36 */
37 class resource
38 {
39 public:
40
41 /**
42 * Add a directory to search when looking for resource files.
43 * \param paths A colon-separated list of directory paths.
44 */
45 static void set_search_paths(const std::string& paths);
46
47 /**
48 * Get the path to a resource of a given name. This uses the search
49 * path(s) and resources prefixes to locate resource files.
50 * \param name The name or partial path of the resource to find.
51 * \return The full path of the resource.
52 */
53 static std::string find_file(const std::string& name);
54
55 /**
56 * Get the path to a resource of a given name and explicit type. This
57 * uses the search path(s) and resources prefixes to locate resource
58 * files.
59 * \param name The name or partial path of the resource to find.
60 * \param ext The extension is appended to the name if the same
61 * extension is not already a part of name.
62 * \return The full path of the resource.
63 */
64 static std::string
65 find_file(const std::string& name, const std::string& ext);
66
67 /**
68 * Register a type with the extension of files which this type can
69 * load. If any type has already been registered with the given file
70 * extension, it will be replaced.
71 * \param extension The file extension.
72 */
73 template <class T>
74 static void register_type(const std::string& extension,
75 const std::string& prefix = "")
76 {
77 loader_ptr loader(new specific_loader<T>(prefix));
78 call_registry(extension, loader, set);
79 }
80
81 /**
82 * Unregister the type associated with a file extension. Resources of
83 * this type will no longer be loadable, although resources which are
84 * already loaded will remain loaded.
85 * \param extension The file extension.
86 */
87 static void unregister_type(const std::string& extension)
88 {
89 loader_ptr loader;
90 call_registry(extension, loader, set);
91 }
92
93 /**
94 * Find and load a resource by name or path.
95 * \param name The name or partial path of the resource. This should
96 * include the extension so that the correct loader can be chosen.
97 * \return The resource.
98 */
99 static resource_ptr load(const std::string& name);
100
101 /**
102 * Find and load a resource by name or path.
103 * \param name The name or partial path of the resource. This should
104 * include the extension so that the correct loader can be chosen.
105 * \param
106 * \return The resource.
107 */
108 static resource_ptr
109 load(const std::string& name, const std::string& ext);
110
111 /**
112 * Reload the resource data. This will cause the resource file to be
113 * reread, and the underlying resource data will change.
114 */
115 void reload();
116
117 /**
118 * Get the path of file from which this resource was loaded.
119 * \return The path.
120 */
121 std::string path() const
122 {
123 return path_;
124 }
125
126 /**
127 * Reloads some resources which have been modified on disk since they
128 * were loaded. Hotloading must have been enabled at compile-time.
129 * \return The number of resources reloaded.
130 */
131 static int reload_as_needed();
132
133 /**
134 * Get whether or not the type of the underlying resource data matches
135 * an expected type.
136 * \return True if the types match, false otherwise.
137 */
138 template <class T>
139 bool check() const
140 {
141 return *typeinfo_ == typeid(T);
142 }
143
144 /**
145 * Get a pointer to the underlying resource data as long as the type of
146 * the resource data matches the expected type.
147 * \return The resource data, or null if there is a type mismatch.
148 */
149 template <class T>
150 T* get() const
151 {
152 if (check<T>()) return (T*)resource_;
153 return 0;
154 }
155
156 /**
157 * Deconstruct a resource container.
158 */
159 virtual ~resource();
160
161 private:
162
163 template <class T>
164 explicit resource(T* ptr) :
165 resource_(ptr),
166 typeinfo_(const_cast<std::type_info*>(&typeid(T))),
167 unloader_(new specific_unloader<T>(ptr)),
168 wd_(-1) {}
169
170 static resource_ptr
171 load_with_path(const std::string& path, const std::string& extension);
172
173 class loader
174 {
175 public:
176
177 loader(const std::string& prefix) :
178 prefix_(prefix) {}
179
180 virtual ~loader() {}
181
182 virtual resource* load(const std::string& path)
183 {
184 return 0;
185 }
186
187 const std::string& prefix() const
188 {
189 return prefix_;
190 }
191
192 private:
193
194 std::string prefix_;
195 };
196
197 typedef boost::shared_ptr<loader> loader_ptr;
198
199 template <class T>
200 class specific_loader : public loader
201 {
202 public:
203
204 specific_loader(const std::string& prefix) :
205 loader(prefix) {}
206
207 virtual resource* load(const std::string& path)
208 {
209 return new resource(new T(path));
210 }
211 };
212
213 class unloader
214 {
215 public:
216
217 virtual ~unloader() {};
218 };
219
220 typedef boost::shared_ptr<unloader> unloader_ptr;
221
222 template <class T>
223 class specific_unloader : public unloader
224 {
225 public:
226
227 specific_unloader(T* object = 0) :
228 object_(object) {}
229
230 virtual ~specific_unloader()
231 {
232 delete object_;
233 }
234
235 private:
236
237 T* object_;
238 };
239
240 enum registry_action
241 {
242 lookup,
243 set
244 };
245
246 static bool call_registry(const std::string& extension,
247 loader_ptr& loader, registry_action action);
248
249 void* resource_;
250 std::type_info* typeinfo_;
251 unloader_ptr unloader_;
252 int wd_;
253 std::string path_;
254 std::string type_;
255 };
256
257
258 /**
259 * The resource handle class provides a nicer way to work with resources.
260 * It allows you to work with a resource pointer as if you already know the
261 * type of the resource.
262 */
263 template <class T>
264 class resource_handle
265 {
266 public:
267
268 /**
269 * Construct a null resource handle.
270 */
271 resource_handle() {}
272
273 /**
274 * Construct a resource handle.
275 * \param ptr The resource pointer to reference.
276 */
277 resource_handle(resource_ptr ptr) :
278 resource_(ptr) {}
279
280 explicit resource_handle(const std::string& name) :
281 resource_(resource::load(name)) {}
282
283 resource_handle(const std::string& name, const std::string& ext) :
284 resource_(resource::load(name, ext)) {}
285
286 /**
287 * Get whether or not the handle is dereferenceable to the type of this
288 * handle. A resource handle is dereferenceable if it is not a null
289 * handle and if its underlying resource is in fact the same type as is
290 * expected by the handle.
291 * \return True if the handle is dereferenceable, false otherwise.
292 */
293 operator bool () const
294 {
295 if (!resource_) return false;
296 return resource_->check<T>();
297 }
298
299 /**
300 * Get a pointer to the underlying resource.
301 * \return The pointer, or null if this handle is not dereferenceable.
302 */
303 T* get() const
304 {
305 if (!*this) return 0;
306 return resource_->get<T>();
307 }
308
309 /**
310 * Dereference the handle all the way to the underlying resource.
311 * \return A reference to the resource.
312 * \throws std::runtime_error If this is a null handle.
313 */
314 T& get_reference() const
315 {
316 if (!*this) throw std::runtime_error("dereference null handle");
317 return *(resource_->get<T>());
318 }
319
320 /**
321 * Same as get() for getting a pointer to the underlying resources.
322 * \return The pointer, or null if this handle is not dereferenceable.
323 */
324 T* operator -> () const
325 {
326 return get();
327 }
328
329 /**
330 * Same a get_reference() for dereferencing the handle.
331 * \return A reference to the resource.
332 * \throws std::runtime_error If this is a null handle.
333 */
334 T& operator * () const
335 {
336 return get_reference();
337 }
338
339 /**
340 * Unload the resource associated with this handle.
341 */
342 void unload()
343 {
344 resource_ = resource_ptr();
345 }
346
347 private:
348
349 resource_ptr resource_;
350 };
351
352 /**
353 * This macro easily registers types to act as resources. It should be
354 * used in a module file in global scope.
355 * \param TYPE The type (class), qualified as needed for the scope.
356 * \param EXT The file extension the resource uses.
357 * \param PREFIX The path prefix where a resource of this type could be.
358 */
359 #define MOOF_REGISTER_RESOURCE(TYPE, EXT, PREFIX) \
360 namespace { \
361 struct EXT { \
362 EXT() { moof::resource::register_type<TYPE>(#EXT, #PREFIX); } \
363 ~EXT() { moof::resource::unregister_type(#EXT); } \
364 }; \
365 static EXT EXT; \
366 }
367
368
369 } // namespace moof
370
371 #endif // _MOOF_RESOURCE_HH_
372
This page took 0.043979 seconds and 4 git commands to generate.