X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2Fmoof%2Fresource.hh;h=d4f416227ee1f9b3985ce8579cf7ab4ac44dfbc1;hp=ed8a7d06f8fd9a8c420d9fab59c0c54de60a0658;hb=HEAD;hpb=831f04d4bc19a390415ac0bbac4331c7a65509bc diff --git a/src/moof/resource.hh b/src/moof/resource.hh index ed8a7d0..d4f4162 100644 --- a/src/moof/resource.hh +++ b/src/moof/resource.hh @@ -1,87 +1,370 @@ -/*] Copyright (c) 2009-2010, Charles McGarvey [************************** +/*] Copyright (c) 2009-2011, Charles McGarvey [***************************** **] All rights reserved. * -* vi:ts=4 sw=4 tw=75 -* * Distributable under the terms and conditions of the 2-clause BSD license; * see the file COPYING for a complete text of the license. * -**************************************************************************/ +*****************************************************************************/ #ifndef _MOOF_RESOURCE_HH_ #define _MOOF_RESOURCE_HH_ +#include +#include +#include +#include + +#include +#include + + /** * \file resource.hh * Interface for textures, sounds, and other types of resources. */ -#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() {} - - /** * Add a directory to search when looking for resource files. * \param paths A colon-separated list of directory paths. */ - static void add_search_paths(const std::string& paths); + static void set_search_paths(const std::string& paths); /** - * Add directories to search when looking for resource files. - * \param pathList The list of directory paths. + * Get the path to a resource of a given name. This uses the search + * path(s) and resources prefixes to locate resource files. + * \param name The name or partial path of the resource to find. + * \return The full path of the resource. */ - static void add_search_paths(const std::vector& pathList); + static std::string find_file(const std::string& name); + /** + * Get the path to a resource of a given name and explicit type. This + * uses the search path(s) and resources prefixes to locate resource + * files. + * \param name The name or partial path of the resource to find. + * \param ext The extension is appended to the name if the same + * extension is not already a part of name. + * \return The full path of the resource. + */ + static std::string + find_file(const std::string& name, const std::string& ext); /** - * 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. + * 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. */ - static bool find_path(std::string& path, - const std::string& prefix = "", - const std::string& 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); + } /** - * 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. + * 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 FILE* open_file(std::string& path, - const std::string& prefix = "", - const std::string& extension = "", - const std::string& mode = "rb"); + static void unregister_type(const std::string& extension) + { + loader_ptr loader; + call_registry(extension, loader, set); + } + /** + * Find and load a resource by name or path. + * \param name The name or partial path of the resource. This should + * include the extension so that the correct loader can be chosen. + * \return The resource. + */ + static resource_ptr load(const std::string& name); + + /** + * Find and load a resource by name or path. + * \param name The name or partial path of the resource. This should + * include the extension so that the correct loader can be chosen. + * \param + * \return The resource. + */ + static resource_ptr + load(const std::string& name, const std::string& ext); + + /** + * Reload the resource data. This will cause the resource file to be + * reread, and the underlying resource data will change. + */ + void reload(); + + /** + * Get the path of file from which this resource was loaded. + * \return The path. + */ + std::string path() const + { + return path_; + } + + /** + * 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(); + + /** + * 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; + } + + /** + * Deconstruct a resource container. + */ + virtual ~resource(); private: - static std::vector search_paths_; + template + explicit resource(T* ptr) : + resource_(ptr), + typeinfo_(const_cast(&typeid(T))), + unloader_(new specific_unloader(ptr)), + wd_(-1) {} + + static resource_ptr + load_with_path(const std::string& path, const std::string& extension); + + class loader + { + public: + + 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(const std::string& prefix) : + loader(prefix) {} + + virtual resource* load(const std::string& path) + { + 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() + { + delete object_; + } + + private: + + T* object_; + }; + + enum registry_action + { + lookup, + set + }; + + static bool call_registry(const std::string& extension, + loader_ptr& loader, registry_action action); + + void* resource_; + std::type_info* typeinfo_; + unloader_ptr unloader_; + int wd_; + std::string path_; + std::string type_; +}; + + +/** + * 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. + */ + void unload() + { + resource_ = resource_ptr(); + } + +private: + + resource_ptr resource_; }; +/** + * This macro easily registers types to act as resources. It should be + * used in a module file in global scope. + * \param TYPE The type (class), qualified as needed for the scope. + * \param EXT The file extension the resource uses. + * \param PREFIX The path prefix where a resource of this type could be. + */ +#define MOOF_REGISTER_RESOURCE(TYPE, EXT, PREFIX) \ +namespace { \ + struct EXT { \ + EXT() { moof::resource::register_type(#EXT, #PREFIX); } \ + ~EXT() { moof::resource::unregister_type(#EXT); } \ + }; \ + static EXT EXT; \ +} + } // namespace moof