X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2Fmoof%2Fresource.hh;h=9d991053c21b841be3ebc164e6b538244c80bb82;hp=ed8a7d06f8fd9a8c420d9fab59c0c54de60a0658;hb=151f60a78d5e45c8d46c3e793fdefee306c6dc4c;hpb=831f04d4bc19a390415ac0bbac4331c7a65509bc diff --git a/src/moof/resource.hh b/src/moof/resource.hh index ed8a7d0..9d99105 100644 --- a/src/moof/resource.hh +++ b/src/moof/resource.hh @@ -17,24 +17,37 @@ * Interface for textures, sounds, and other types of resources. */ -#include +#include "config.h" + +#include +#include #include #include +#include +#include + +#include + namespace moof { +class resource; +typedef boost::shared_ptr resource_ptr; + + /** - * Generic resource class. + * Generic resource class capable of containing any type of resource, + * providing a type-safe interface. */ - class resource { public: - virtual ~resource() {} - + // XXX: this won't be necessary once the existing code is modified to + // use the resource handles + resource() {} /** * Add a directory to search when looking for resource files. @@ -42,44 +55,324 @@ public: */ static void add_search_paths(const std::string& paths); - /** - * Add directories to search when looking for resource files. - * \param pathList The list of directory paths. - */ - static void add_search_paths(const std::vector& pathList); - /** * Get the path to a resource of a given name. * \param path The name of the resource to find. Upon successful * return, this is changed to an absolute path to the resource. - * \param prefix A colon-separated list of subdirectories to search. - * \param extension A colon-separated list of possible extensions. * \return True if a path to a resource was found, false otherwise. */ - static bool find_path(std::string& path, - const std::string& prefix = "", - const std::string& extension = ""); + static std::string find_file(const std::string& name); + + static std::string find_file(const std::string& name, + const std::string& ext); /** - * Get the path to a resource of a given name and open it if a resource - * was found. - * \param path The name of the resource to find. Upon successful - * return, this is changed to an absolute path to the resource. - * \param prefix A colon-separated list of subdirectories to search. - * \param extension A colon-separated list of possible extensions. - * \param mode The open mode. - * \return The FILE* if the resource was found, 0 otherwise. + * Register a type with the extension of files which this type can + * load. If any type has already been registered with the given file + * extension, it will be replaced. + * \param extension The file extension. + */ + template + static void register_type(const std::string& extension, + const std::string& prefix = "") + { + loader_ptr loader(new specific_loader(prefix)); + call_registry(extension, loader, set); + } + + /** + * Unregister the type associated with a file extension. Resources of + * this type will no longer be loadable, although resources which are + * already loaded will remain loaded. + * \param extension The file extension + */ + static void unregister_type(const std::string& extension) + { + loader_ptr loader; + call_registry(extension, loader, set); + } + + + static resource_ptr load(const std::string& name); + static resource_ptr load(const std::string& name, + const std::string& ext); + + static resource_ptr reload(std::string& path); + + + /** + * Construct a resource container. + * \param ptr A pointer to the underlying resource data. + */ + template + explicit resource(T* ptr) : + resource_(ptr), + typeinfo_(const_cast(&typeid(T))), + unloader_(new specific_unloader(ptr)) {} + + /** + * Deconstruct a resource container. + */ + virtual ~resource(); + + + /** + * Reload the resource data. This will cause the resource file to be + * reread, and the underlying resource data will change. + */ + void reload(); + + + /** + * Get whether or not the type of the underlying resource data matches + * an expected type. + * \return True if the types match, false otherwise. + */ + template + bool check() const + { + return *typeinfo_ == typeid(T); + } + + /** + * Get a pointer to the underlying resource data as long as the type of + * the resource data matches the expected type. + * \return The resource data, or null if there is a type mismatch. + */ + template + T* get() const + { + if (check()) return (T*)resource_; + return 0; + } + + + /** + * Reloads some resources which have been modified on disk since they + * were loaded. Hotloading must have been enabled at compile-time. + * \return The number of resources reloaded. + */ + static int reload_as_needed(); + + +private: + + static resource_ptr load_with_path(const std::string& path); + + class loader + { + public: + + //loader() {} + loader(const std::string& prefix) : + prefix_(prefix) {} + + virtual ~loader() {} + + virtual resource* load(const std::string& path) + { + return 0; + } + + const std::string& prefix() const + { + return prefix_; + } + + + private: + + std::string prefix_; + }; + + typedef boost::shared_ptr loader_ptr; + + template + class specific_loader : public loader + { + public: + + //specific_loader() {} + specific_loader(const std::string& prefix) : + loader(prefix) {} + + virtual resource* load(const std::string& path) + { + log_info("loading resource of type ", typeid(T).name()); + return new resource(new T(path)); + } + }; + + + class unloader + { + public: + + virtual ~unloader() {}; + }; + + typedef boost::shared_ptr unloader_ptr; + + template + class specific_unloader : public unloader + { + public: + + specific_unloader(T* object = 0) : + object_(object) {} + + virtual ~specific_unloader() + { + log_info("unloading resource of type ", typeid(T).name()); + delete object_; + } + + + private: + + T* object_; + }; + + + void set_loader(const std::string& path, loader_ptr loader) + { + path_ = path; + loader_ = loader; + } + + + void* resource_; + std::type_info* typeinfo_; + unloader_ptr unloader_; + + std::string path_; + loader_ptr loader_; + + typedef std::map type_lookup; + //typedef boost::shared_ptr type_lookup_ptr; + //static type_lookup_ptr type_lookup_; + //static type_lookup type_lookup_; + + enum registry_action + { + lookup, + set + }; + + static bool call_registry(const std::string& extension, + loader_ptr& loader, + registry_action action); + +#ifdef USE_HOTLOADING + int wd_; + + void set_watch_descriptor(int wd) + { + wd_ = wd; + } +#endif +}; + + +/** + * The resource handle class provides a nicer way to work with resources. + * It allows you to work with a resource pointer as if you already know the + * type of the resource. + */ +template +class resource_handle +{ +public: + + /** + * Construct a null resource handle. + */ + resource_handle() {} + + /** + * Construct a resource handle. + * \param ptr The resource pointer to reference. + */ + resource_handle(resource_ptr ptr) : + resource_(ptr) {} + + explicit resource_handle(const std::string& name) : + resource_(resource::load(name)) {} + + resource_handle(const std::string& name, const std::string& ext) : + resource_(resource::load(name, ext)) {} + + + + /** + * Get whether or not the handle is dereferenceable to the type of this + * handle. A resource handle is dereferenceable if it is not a null + * handle and if its underlying resource is in fact the same type as is + * expected by the handle. + * \return True if the handle is dereferenceable, false otherwise. + */ + operator bool () const + { + if (!resource_) return false; + return resource_->check(); + } + + + /** + * Get a pointer to the underlying resource. + * \return The pointer, or null if this handle is not dereferenceable. + */ + T* get() const + { + if (!*this) return 0; + return resource_->get(); + } + + /** + * Dereference the handle all the way to the underlying resource. + * \return A reference to the resource. + * \throws std::runtime_error If this is a null handle. + */ + T& get_reference() const + { + if (!*this) throw std::runtime_error("dereference null handle"); + return *(resource_->get()); + } + + + /** + * Same as get() for getting a pointer to the underlying resources. + * \return The pointer, or null if this handle is not dereferenceable. + */ + T* operator -> () const + { + return get(); + } + + /** + * Same a get_reference() for dereferencing the handle. + * \return A reference to the resource. + * \throws std::runtime_error If this is a null handle. + */ + T& operator * () const + { + return get_reference(); + } + + + /** + * Unload the resource associated with this handle. */ - static FILE* open_file(std::string& path, - const std::string& prefix = "", - const std::string& extension = "", - const std::string& mode = "rb"); + void unload() + { + resource_ = resource_ptr(); + } private: - static std::vector search_paths_; + resource_ptr resource_; };