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