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