ソースを参照

Add autoload to ResourceManager

Daniele Bartolini 11 年 前
コミット
b4a61c84ce

+ 9 - 0
engine/lua/lua_device.cpp

@@ -34,6 +34,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "array.h"
 #include "string_stream.h"
 #include "console_server.h"
+#include "resource_manager.h"
 
 namespace crown
 {
@@ -151,6 +152,13 @@ static int device_can_get(lua_State* L)
 	return 1;
 }
 
+static int device_enable_resource_autoload(lua_State* L)
+{
+	LuaStack stack(L);
+	device()->resource_manager()->enable_autoload(stack.get_bool(1));
+	return 0;
+}
+
 void load_device(LuaEnvironment& env)
 {
 	env.load_module_function("Device", "platform",                 device_platform);
@@ -166,6 +174,7 @@ void load_device(LuaEnvironment& env)
 	env.load_module_function("Device", "destroy_resource_package", device_destroy_resource_package);
 	env.load_module_function("Device", "console_send",             device_console_send);
 	env.load_module_function("Device", "can_get",                  device_can_get);
+	env.load_module_function("Device", "enable_resource_autoload", device_enable_resource_autoload);
 }
 
 } // namespace crown

+ 2 - 0
engine/resource/resource.h

@@ -86,9 +86,11 @@ namespace crown
 struct ResourceId
 {
 	ResourceId() : type(0), name(0) {}
+	ResourceId(uint64_t type, uint64_t name) : type(type), name(name) {}
 	ResourceId(const char* type, const char* name);
 
 	bool operator==(const ResourceId& a) const { return type == a.type && name == a.name; }
+	bool operator<(const ResourceId& a) const { return type < a.type || (type == a.type && name < a.name); }
 
 	uint64_t type;
 	uint64_t name;

+ 54 - 74
engine/resource/resource_manager.cpp

@@ -34,7 +34,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "temp_allocator.h"
 #include "dynamic_string.h"
 #include "queue.h"
-#include "log.h"
+#include "sort_map.h"
 
 namespace crown
 {
@@ -46,126 +46,105 @@ ResourceId::ResourceId(const char* type, const char* name)
 }
 
 ResourceManager::ResourceManager(Bundle& bundle)
-	: m_resource_heap("resource", default_allocator())
-	, m_loader(bundle, m_resource_heap)
-	, m_resources(default_allocator())
+	: _resource_heap("resource", default_allocator())
+	, _loader(bundle, _resource_heap)
+	, _rm(default_allocator())
+	, _autoload(false)
 {
 }
 
-void ResourceManager::load(StringId64 type, StringId64 name)
+const ResourceManager::ResourceEntry ResourceManager::NOT_FOUND = { 0xffffffffu, NULL };
+
+ResourceManager::~ResourceManager()
 {
-	ResourceId id;
-	id.type = type;
-	id.name = name;
-	load(id);
+	const ResourceMap::Entry* begin = sort_map::begin(_rm);
+	const ResourceMap::Entry* end = sort_map::end(_rm);
+
+	for (; begin != end; begin++)
+	{
+		resource_on_offline(begin->key.type, begin->key.name, *this);
+		resource_on_unload(begin->key.type, _resource_heap, begin->value.data);
+	}
 }
 
-void ResourceManager::load(ResourceId id)
+void ResourceManager::load(StringId64 type, StringId64 name)
 {
-	// Search for an already existent resource
-	ResourceEntry* entry = find(id);
+	ResourceId id(type, name);
+	ResourceEntry& entry = sort_map::get(_rm, id, NOT_FOUND);
 
-	// If resource not found, post load request
-	if (entry == NULL)
+	if (entry == NOT_FOUND)
 	{
-		m_loader.load(id);
+		_loader.load(id);
 		return;
 	}
 
-	// Else, increment its reference count
-	entry->references++;
-}
-
-bool ResourceManager::can_get(StringId64 type, StringId64 name)
-{
-	ResourceId id;
-	id.type = type;
-	id.name = name;
-	return can_get(id);
+	entry.references++;
 }
 
 void ResourceManager::unload(StringId64 type, StringId64 name)
 {
-	ResourceId id;
-	id.type = type;
-	id.name = name;
-	unload(id);
-}
-
-void ResourceManager::unload(ResourceId id)
-{
-	CE_ASSERT(find(id) != NULL, "Resource not loaded: ""%.16"PRIx64"-%.16"PRIx64, id.type, id.name);
-
 	flush();
-	ResourceEntry* entry = find(id);
-	entry->references--;
 
-	if (entry->references == 0)
+	ResourceId id(type, name);
+	ResourceEntry& entry = sort_map::get(_rm, id, NOT_FOUND);
+
+	if (--entry.references == 0)
 	{
-		resource_on_offline(id.type, id.name, *this);
-		resource_on_unload(id.type, m_resource_heap, entry->resource);
+		resource_on_offline(type, name, *this);
+		resource_on_unload(type, _resource_heap, entry.data);
 
-		// Swap with last
-		ResourceEntry temp = m_resources[array::size(m_resources) - 1];
-		(*entry) = temp;
-		array::pop_back(m_resources);
+		sort_map::remove(_rm, id);
+		sort_map::sort(_rm);
 	}
 }
 
 bool ResourceManager::can_get(const char* type, const char* name)
 {
-	return can_get(ResourceId(type, name));
+	ResourceId id(type, name);
+	return can_get(id.type, id.name);
 }
 
-bool ResourceManager::can_get(ResourceId id) const
+bool ResourceManager::can_get(StringId64 type, StringId64 name)
 {
-	return find(id) != NULL;
+	return _autoload ? true : sort_map::has(_rm, ResourceId(type, name));
 }
 
-const void* ResourceManager::get(const char* type, const char* name) const
+const void* ResourceManager::get(const char* type, const char* name)
 {
-	ResourceEntry* entry = find(ResourceId(type, name));
-	CE_ASSERT(entry != NULL, "Resource not loaded: %s.%s", name, type);
-	return entry->resource;
+	ResourceId id(type, name);
+	return get(id.type, id.name);
 }
 
 const void* ResourceManager::get(StringId64 type, StringId64 name)
 {
-	ResourceId id;
-	id.type = type;
-	id.name = name;
-	return get(id);
-}
+	ResourceId id(type, name);
 
-const void* ResourceManager::get(ResourceId id) const
-{
-	CE_ASSERT(find(id) != NULL, "Resource not loaded: ""%.16"PRIx64"-%.16"PRIx64, id.type, id.name);
-	return find(id)->resource;
+	if (_autoload && !sort_map::has(_rm, id))
+	{
+		load(type, name);
+		flush();
+	}
+
+	const ResourceEntry& entry = sort_map::get(_rm, id, NOT_FOUND);
+	return entry.data;
 }
 
-uint32_t ResourceManager::references(ResourceId id) const
+void ResourceManager::enable_autoload(bool enable)
 {
-	CE_ASSERT(find(id) != NULL, "Resource not loaded: ""%.16"PRIx64"-%.16"PRIx64, id.type, id.name);
-	return find(id)->references;
+	_autoload = enable;
 }
 
 void ResourceManager::flush()
 {
-	m_loader.flush();
+	_loader.flush();
 	complete_requests();
 }
 
-ResourceEntry* ResourceManager::find(ResourceId id) const
-{
-	const ResourceEntry* entry = std::find(array::begin(m_resources), array::end(m_resources), id);
-	return entry != array::end(m_resources) ? const_cast<ResourceEntry*>(entry) : NULL;
-}
-
 void ResourceManager::complete_requests()
 {
 	TempAllocator1024 ta;
 	Array<ResourceData> loaded(ta);
-	m_loader.get_loaded(loaded);
+	_loader.get_loaded(loaded);
 
 	for (uint32_t i = 0; i < array::size(loaded); i++)
 		complete_request(loaded[i].id, loaded[i].data);
@@ -174,10 +153,11 @@ void ResourceManager::complete_requests()
 void ResourceManager::complete_request(ResourceId id, void* data)
 {
 	ResourceEntry entry;
-	entry.id = id;
 	entry.references = 1;
-	entry.resource = data;
-	array::push_back(m_resources, entry);
+	entry.data = data;
+
+	sort_map::set(_rm, id, entry);
+	sort_map::sort(_rm);
 
 	resource_on_online(id.type, id.name, *this);
 }

+ 29 - 28
engine/resource/resource_manager.h

@@ -35,16 +35,6 @@ OTHER DEALINGS IN THE SOFTWARE.
 namespace crown
 {
 
-struct ResourceEntry
-{
-	bool operator==(const ResourceId& res) const { return id == res; }
-	bool operator==(const ResourceEntry& b) const { return id == b.id; }
-
-	ResourceId id;
-	uint32_t references;
-	void* resource;
-};
-
 class Bundle;
 
 /// @defgroup Resource Resource
@@ -58,28 +48,29 @@ public:
 
 	/// The resources will be loaded from @a bundle.
 	ResourceManager(Bundle& bundle);
+	~ResourceManager();
 
-	/// Loads the resource @a type @a name.
-	/// You can check whether the resource is loaded with can_get().
+	/// Loads the resource (@a type, @a name).
+	/// You can check whether the resource is available with can_get().
 	void load(StringId64 type, StringId64 name);
 
 	/// Unloads the resource @a type @a name.
 	void unload(StringId64 type, StringId64 name);
 
-	/// Returns whether the manager has the given resource. 
+	/// Returns whether the manager has the resource (@a type, @a name).
 	bool can_get(const char* type, const char* name);
 
-	/// Returns whether the manager has the resource @a id.
+	/// Returns whether the manager has the resource (@a type, @a name).
 	bool can_get(StringId64 type, StringId64 name);
 
-	/// Returns the resource data by @a type and @a name.
-	const void* get(const char* type, const char* name) const;
+	/// Returns the data of the resource (@a type, @a name).
+	const void* get(const char* type, const char* name);
 
-	/// Returns the resource data by @a id.
+	/// Returns the data of the resource (@a type, @a name).
 	const void* get(StringId64 type, StringId64 name);
 
-	/// Returns the number of references to resource @a id;
-	uint32_t references(ResourceId id) const;
+	/// Sets whether resources should be automatically loaded when accessed.
+	void enable_autoload(bool enable);
 
 	/// Blocks until all load() requests have been completed.
 	void flush();
@@ -89,19 +80,29 @@ public:
 
 private:
 
-	void load(ResourceId id);
-	void unload(ResourceId id);
-	bool can_get(ResourceId id) const;
-	const void* get(ResourceId id) const;
-
-	ResourceEntry* find(ResourceId id) const;
 	void complete_request(ResourceId id, void* data);
 
 private:
 
-	ProxyAllocator m_resource_heap;
-	ResourceLoader m_loader;
-	Array<ResourceEntry> m_resources;
+	struct ResourceEntry
+	{
+		bool operator==(const ResourceEntry& e)
+		{
+			return references == e.references && data == e.data;
+		}
+
+		uint32_t references;
+		void* data;
+	};
+
+	typedef SortMap<ResourceId, ResourceEntry> ResourceMap;
+
+	ProxyAllocator _resource_heap;
+	ResourceLoader _loader;
+	ResourceMap _rm;
+	bool _autoload;
+
+	static const ResourceEntry NOT_FOUND;
 };
 
 } // namespace crown