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