Преглед изворни кода

Now, ResourceArchive can read a resource file and obtain resources from it

Daniele Bartolini пре 13 година
родитељ
комит
222755452a
7 измењених фајлова са 187 додато и 24 уклоњено
  1. 4 4
      src/Resource.h
  2. 68 5
      src/ResourceArchive.cpp
  3. 53 6
      src/ResourceArchive.h
  4. 12 4
      src/ResourceLoader.cpp
  5. 1 0
      src/ResourceLoader.h
  6. 23 4
      src/ResourceManager.cpp
  7. 26 1
      src/ResourceManager.h

+ 4 - 4
src/Resource.h

@@ -30,7 +30,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 namespace crown
 {
 
-/// Enumerates the loading state of a resource
+/// Enumerates the loading states of a resource
 enum ResourceState
 {
 	RS_UNLOADED		= 0,		//< The resource is not loaded, so it cannot be used
@@ -43,9 +43,9 @@ enum ResourceState
 /// the index to the resource list where it is stored.
 struct ResourceId
 {
-	uint32_t		name;
-	uint32_t		type;
-	uint32_t		index;
+	uint32_t		name;		// Hashed resource name
+	uint32_t		type;		// Hashed resource type
+	uint32_t		index;		// Index into the ResourceManager internal list
 };
 
 } // namespace crown

+ 68 - 5
src/ResourceArchive.cpp

@@ -24,33 +24,96 @@ OTHER DEALINGS IN THE SOFTWARE.
 */
 
 #include "ResourceArchive.h"
-#include <stdio.h>
 #include "Filesystem.h"
 #include "Resource.h"
+#include "FileStream.h"
+#include "Log.h"
 
 namespace crown
 {
 
-ResourceArchive::ResourceArchive()
+//-----------------------------------------------------------------------------
+ResourceArchive::ResourceArchive(Filesystem* filesystem) :
+	m_filesystem(filesystem),
+	m_archive_file(NULL),
+	m_entries(NULL),
+	m_entries_count(0)
 {
+	// FIXME Default archive name
+	open("archive.bin");
 }
 
+//-----------------------------------------------------------------------------
 ResourceArchive::~ResourceArchive()
 {
+	close();
 }
 
+//-----------------------------------------------------------------------------
 void ResourceArchive::open(const char* archive)
 {
+	assert(archive != NULL);
+	
+	m_archive_file = (FileStream*)m_filesystem->open(archive, SOM_READ);
+	
+	Log::I("Opened archive file: ", archive);
+	
+	ArchiveHeader header;
+	
+	// Read the header of the archive
+	m_archive_file->read(&header, sizeof(ArchiveHeader));
+	
+	Log::D("Found %d resources into it.", header.entries_count);
+	
+	Log::D("Version: %d", header.version);
+	Log::D("Entries: %d", header.entries_count);
+	Log::D("Checksum: %d", header.checksum);
+	
+	m_entries = new ArchiveEntry[header.entries_count];
+	m_entries_count = header.entries_count;
+	
+	// Read the entries
+	m_archive_file->read(m_entries, m_entries_count * sizeof(ArchiveEntry));
+
+	Log::I("Successfully read %d entries.", m_entries_count);
 }
 
+//-----------------------------------------------------------------------------
 void ResourceArchive::close()
 {
+	if (m_filesystem != NULL)
+	{
+		if (m_archive_file != NULL)
+		{
+			m_filesystem->close(m_archive_file);
+		}
+	}
+	
+	if (m_entries != NULL)
+	{
+		delete m_entries;
+	}
+	
+	m_entries = NULL;
+	m_entries_count = 0;
 }
 
-void ResourceArchive::find(ResourceId name)
+//-----------------------------------------------------------------------------
+FileStream* ResourceArchive::find(ResourceId name)
 {
-	char ascii_name[16];
-	snprintf(ascii_name, 16, "%x", name.name);
+	// Search the resource in the archive
+	for (uint32_t i = 0; i < m_entries_count; i++)
+	{		
+		if (m_entries[i].name == name.name && m_entries[i].type == name.type)
+		{
+			// If found, seek to the first byte of the resource data
+			m_archive_file->seek(m_entries[i].offset);
+
+			return (FileStream*)m_archive_file;
+		}
+	}
+
+	return NULL;
 }
 
 } // namespace crown

+ 53 - 6
src/ResourceArchive.h

@@ -30,20 +30,67 @@ OTHER DEALINGS IN THE SOFTWARE.
 namespace crown
 {
 
+class Filesystem;
+class FileStream;
+
+const uint32_t ARCHIVE_VERSION	= 1;	// Version of the archive
+
+struct ArchiveHeader
+{
+	uint32_t	version;			// The version number of the archive
+	uint32_t	entries_count;		// Number of resource entries in the archive
+	uint32_t	checksum;			// MD5 checksum of the archive
+	uint8_t		padding[64];		// Padding for additional data
+};
+
+struct ArchiveEntry
+{
+	uint32_t	name;				// Name of the resource (fnv1a hash)
+	uint32_t	type;				// Type of the resource (fnv1a hash)
+	uint64_t	offset;				// First byte of the resource (as absolute offset)
+	uint32_t	size;				// Size of the resource data (in bytes)
+};
+
+/// Structure of the archive
+///
+/// [ArchiveHeader]
+/// [ArchiveEntry]
+/// [ArchiveEntry]
+/// ...
+/// [ArchiveEntry]
+/// [ResourceData]
+/// [ResourceData]
+/// ...
+/// [ResourceData]
+///
+/// A valid archive must always have at least the archive header,
+/// starting at byte 0 of the archive file.
+///
+/// Newer archive versions must be totally backward compatible
+/// across minor engine releases, in order to be able to use
+/// recent version of the engine with older game archives.
+
 /// Source of resources
 class ResourceArchive
 {
 public:
 
-						ResourceArchive();
-						~ResourceArchive();
+							ResourceArchive(Filesystem* filesystem);
+							~ResourceArchive();
 
-	void				open(const char* archive);
-	void				close();
+	void					open(const char* archive);
+	void					close();
+
+	FileStream*				find(ResourceId name);
 
-	void				find(ResourceId name);
-	
 private:
+
+	Filesystem*				m_filesystem;
+	
+	FileStream*				m_archive_file;
+
+	ArchiveEntry*			m_entries;
+	uint32_t				m_entries_count;
 };
 
 } // namespace crown

+ 12 - 4
src/ResourceLoader.cpp

@@ -28,6 +28,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "String.h"
 #include "Hash.h"
 #include "TextureResource.h"
+#include "TextResource.h"
 #include <stdio.h>
 #include <unistd.h>
 
@@ -38,11 +39,13 @@ namespace crown
 ResourceLoader::ResourceLoader(ResourceManager* resource_manager, Filesystem* filesystem) :
 	m_resource_manager(resource_manager),
 	m_filesystem(filesystem),
+	m_resource_archive(filesystem),
 	m_resources(m_allocator)
 {
 	m_config_hash = hash::fnv1a_32("config", string::strlen("config"));
 	m_texture_hash = hash::fnv1a_32("tga", string::strlen("tga"));
 	m_mesh_hash = hash::fnv1a_32("mesh", string::strlen("mesh"));
+	m_txt_hash = hash::fnv1a_32("txt", 3);
 }
 
 //-----------------------------------------------------------------------------
@@ -83,16 +86,21 @@ void ResourceLoader::flush()
 //-----------------------------------------------------------------------------
 void* ResourceLoader::load_by_type(ResourceId name)
 {
-	if (name.name == m_config_hash)
+	if (name.type == m_config_hash)
 	{
 		return NULL;
 	}
 
-	if (name.name == m_texture_hash)
+	if (name.type == m_texture_hash)
 	{
-		return TextureResource::load(&m_resource_archive, name.name);
+		return TextureResource::load(&m_resource_archive, name);
 	}
-	
+
+	if (name.type == m_txt_hash)
+	{
+		return TextResource::load(&m_resource_archive, name);
+	}
+
 	return NULL;
 }
 

+ 1 - 0
src/ResourceLoader.h

@@ -65,6 +65,7 @@ private:
 	uint32_t			m_config_hash;
 	uint32_t			m_texture_hash;
 	uint32_t			m_mesh_hash;
+	uint32_t			m_txt_hash;
 };
 
 } // namespace crown

+ 23 - 4
src/ResourceManager.cpp

@@ -28,6 +28,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "ResourceLoader.h"
 #include "String.h"
 #include "Hash.h"
+#include "Path.h"
 #include <algorithm>
 
 namespace crown
@@ -48,22 +49,30 @@ ResourceManager::~ResourceManager()
 //-----------------------------------------------------------------------------
 ResourceId ResourceManager::load(const char* name)
 {
-	uint32_t name_hash = hash::fnv1a_32(name, string::strlen(name));
+	char basename[512];
+	char extension[512];
+	
+	path::basename(name, basename, 512);
+	path::extension(name, extension, 512);
+
+	uint32_t name_hash = hash::fnv1a_32(basename, string::strlen(basename));
+	uint32_t type_hash = hash::fnv1a_32(extension, string::strlen(extension));
 
-	return load(name_hash);
+	return load(name_hash, type_hash);
 }
 
 //-----------------------------------------------------------------------------
-ResourceId ResourceManager::load(uint32_t name)
+ResourceId ResourceManager::load(uint32_t name, uint32_t type)
 {
 	// Search for an already existent resource
 	ResourceEntry* entry = std::find(m_resources.begin(), m_resources.end(), name);
 
-	// If resource not found
+	// If resource not found, create a new one
 	if (entry == m_resources.end())
 	{
 		ResourceId id;
 		id.name = name;
+		id.type = type;
 		id.index = m_resources.size();
 
 		ResourceEntry entry;
@@ -79,7 +88,9 @@ ResourceId ResourceManager::load(uint32_t name)
 		return id;
 	}
 
+	// Else, increment its reference count
 	entry->references++;
+	
 	return entry->id;
 }
 
@@ -125,6 +136,14 @@ bool ResourceManager::has(ResourceId name)
 	return false;
 }
 
+//-----------------------------------------------------------------------------
+void* ResourceManager::data(ResourceId name)
+{
+	assert(has(name));
+	
+	return m_resources[name.index].resource;
+}
+
 //-----------------------------------------------------------------------------
 bool ResourceManager::is_loaded(ResourceId name)
 {

+ 26 - 1
src/ResourceManager.h

@@ -66,15 +66,40 @@ public:
 							ResourceManager(Filesystem* filesystem);
 							~ResourceManager();
 
+	/// Loads the resource by string @name and returns its resource id.
+	/// Note that the resource data is not immediately available,
+	/// the resource gets pushed in a queue of load requests and loadead as
+	/// soon as possible by the ResourceLoader.
+	/// You have to explicitly call is_loaded() method to check if the
+	/// loading process is actually completed.
 	ResourceId				load(const char* name);
-	ResourceId				load(uint32_t name);
+	
+	/// Loads the resource by hashed @name and @type and returns its resource id.
+	/// See ResourceManager::load(const char* name) for details.
+	ResourceId				load(uint32_t name, uint32_t type);
 
 	void					unload(ResourceId name);
 
 	void					reload(ResourceId name);
 
+	/// Returns whether the manager has the specified @name into
+	/// its list of resources.
+	/// Note that having a resource does not mean that the resource is
+	/// available for using; instead, you have to check is_loaded() to
+	/// obtain the resource availability.
 	bool					has(ResourceId name);
+
+	/// Returns the data associated with the resource @name.
+	/// The resource data contains resource-specific metadata
+	/// and the actual resource data. In order to correctly use
+	/// it, you have to know which type of data the @name refers to.
+	void*					data(ResourceId name);
+	
+	/// Returns whether the resource @name is loaded (i.e. whether
+	/// you can use the data associated with it).
 	bool					is_loaded(ResourceId name);
+	
+	/// Forces the loading of all of the queued resource load requests.
 	void					flush() { m_resource_loader.flush(); }
 
 private: