瀏覽代碼

New compiler architecture

Daniele Bartolini 12 年之前
父節點
當前提交
0f8d7febfd

+ 13 - 1
tools/compilers/CMakeLists.txt

@@ -2,10 +2,22 @@ cmake_minimum_required(VERSION 2.8)
 
 set (SRC
 	Compiler.cpp
+
+	tga/TGACompiler.cpp
+	txt/TXTCompiler.cpp
+	lua/LuaCompiler.cpp
+	ps/PSCompiler.cpp
+	vs/VSCompiler.cpp
 )
 
 set (HEADERS
 	Compiler.h
+
+	tga/TGACompiler.h
+	txt/TXTCompiler.h
+	lua/LuaCompiler.h
+	ps/PSCompiler.h
+	vs/VSCompiler.h
 )
 
 # utils
@@ -22,7 +34,7 @@ target_link_libraries(resource-hash crown)
 
 # resource-compiler
 add_executable(resource-compiler resource-compiler.cpp)
-target_link_libraries(resource-compiler crown)
+target_link_libraries(resource-compiler crown crown-compiler-utils)
 
 install (TARGETS crown-compiler-utils DESTINATION lib/${CMAKE_PROJECT_NAME})
 

+ 67 - 89
tools/compilers/Compiler.cpp

@@ -35,153 +35,131 @@ namespace crown
 {
 
 //-----------------------------------------------------------------------------
-Compiler::Compiler(const char* root_path, const char* dest_path, const char* resource, uint32_t type_expected, uint32_t seed) :
-	m_name_hash(0),
-	m_type_hash(0),
-	m_seed(seed),
-
+Compiler::Compiler(const char* root_path, const char* dest_path, uint32_t type_expected) :
 	m_root_fs(root_path),
 	m_dest_fs(dest_path),
-	m_src_file(NULL),
-	m_dest_file(NULL),
+	m_type_expected(type_expected)
+{
+	memset(m_resource_name, 0, MAX_RESOURCE_NAME_LENGTH);
+}
 
-	m_prepared(false),
+//-----------------------------------------------------------------------------
+Compiler::~Compiler()
+{
+}
 
-	m_verbose(false)
+//-----------------------------------------------------------------------------
+size_t Compiler::compile(const char* resource, uint32_t name, uint32_t type)
 {
-	// Init structures
-	memset(m_root_path, 0, MAX_RESOURCE_PATH_LENGTH);
-	memset(m_dest_path, 0, MAX_RESOURCE_PATH_LENGTH);
-	memset(m_resource, 0, MAX_RESOURCE_PATH_LENGTH);
+	string::strncpy(m_resource_name, resource, MAX_RESOURCE_NAME_LENGTH);
 
-	memset(&m_compiled_header, 0, sizeof(CompiledHeader));
-	memset(m_name, 0, MAX_RESOURCE_NAME_LENGTH);
-	memset(m_type, 0, MAX_RESOURCE_TYPE_LENGTH);
+	char resource_name[MAX_RESOURCE_NAME_LENGTH];
+	char resource_type[MAX_RESOURCE_TYPE_LENGTH];
 
-	string::strncpy(m_root_path, root_path, MAX_RESOURCE_PATH_LENGTH);
-	string::strncpy(m_dest_path, dest_path, MAX_RESOURCE_PATH_LENGTH);
-	string::strncpy(m_resource, resource, MAX_RESOURCE_PATH_LENGTH);
+	path::filename_without_extension(resource, resource_name, MAX_RESOURCE_NAME_LENGTH);
+	path::extension(resource, resource_type, MAX_RESOURCE_TYPE_LENGTH);
 
-	// Extract resource name and type
-	path::filename_without_extension(m_resource, m_name, MAX_RESOURCE_NAME_LENGTH);
-	path::extension(m_resource, m_type, MAX_RESOURCE_TYPE_LENGTH);
+	char output_name[17];
+	snprintf(output_name, 17, "%.8X%.8X", name, type);
 
-	// Compute the resource hashes
-	m_name_hash = hash::murmur2_32(m_name, string::strlen(m_name), m_seed);
+	Log::i("%s => %s", resource, output_name);
 
-	// NOTE: The type hash _MUST_ be generated with seed = 0
-	m_type_hash = hash::murmur2_32(m_type, string::strlen(m_type), 0);
+	if (type != m_type_expected)
+	{
+		Log::e("'%s': resource type does not match expected type.", resource);
+		return 0;
+	}
 
-	if (m_type_hash != type_expected)
+	if (!m_root_fs.exists(resource))
 	{
-		Log::e("Compiler: Trying to compile '%s' with the wrong compiler. Aborting.", resource_path());
-		exit(-1);
+		Log::e("'%s': resource does not exist.");
+		return 0;
 	}
 
-	char dest_name[17];
-	memset(dest_name, 0, 17);
+	// Read source file
+	FileStream* input_file = m_root_fs.open(resource, SOM_READ);
 
-	snprintf(dest_name, 17, "%.8X%.8X", m_name_hash, m_type_hash);
+	size_t header_size = read_header(input_file);
+	size_t resource_size = read_resource(input_file);
 
-	// Open streams
-	m_src_file = (FileStream*)m_root_fs.open(m_resource, SOM_READ);
+	// Write compiled file
+	FileStream* output_file;
 
-	if (!m_dest_fs.exists(dest_name))
+	if (m_dest_fs.exists(output_name))
 	{
-		m_dest_fs.create_file(dest_name);
+		m_dest_fs.delete_file(output_name);
 	}
 
-	m_dest_file = (FileStream*)m_dest_fs.open(dest_name, SOM_WRITE);
-}
+	m_dest_fs.create_file(output_name);
+	output_file = m_dest_fs.open(output_name, SOM_WRITE);
 
-//-----------------------------------------------------------------------------
-Compiler::~Compiler()
-{
-	if (m_src_file != NULL)
-	{
-		m_root_fs.close(m_src_file);
-	}
+	write_header(output_file, name, type, resource_size);
+	write_resource(output_file);
 
-	if (m_dest_file != NULL)
-	{
-		m_dest_fs.close(m_dest_file);
-	}
-}
+	m_root_fs.close(input_file);
+	m_dest_fs.close(output_file);
 
-//-----------------------------------------------------------------------------
-const char* Compiler::root_path() const
-{
-	return m_root_path;
+	// Cleanup
+	cleanup();
 }
 
 //-----------------------------------------------------------------------------
-const char* Compiler::dest_path() const
+size_t Compiler::read_header(FileStream* in_file)
 {
-	return m_dest_path;
+	return read_header_impl(in_file);
 }
 
 //-----------------------------------------------------------------------------
-const char* Compiler::resource_path() const
+size_t Compiler::read_resource(FileStream* in_file)
 {
-	return m_resource;
+	return read_resource_impl(in_file);
 }
 
 //-----------------------------------------------------------------------------
-uint32_t Compiler::resource_name_hash() const
+void Compiler::write_header(FileStream* out_file, uint32_t name, uint32_t type, uint32_t resource_size)
 {
-	return m_name_hash;
-}
+	CompiledHeader header;
+	header.magic = COMPILED_HEADER_MAGIC_NUMBER;
+	header.version = COMPILER_VERSION;
+	header.name = name;
+	header.type = type;
+	header.size = resource_size;
 
-//-----------------------------------------------------------------------------
-uint32_t Compiler::resource_type_hash() const
-{
-	return m_type_hash;
-}
+	out_file->write(&header, sizeof(CompiledHeader));
 
-//-----------------------------------------------------------------------------
-uint32_t Compiler::seed() const
-{
-	return m_seed;
+	write_header_impl(out_file);
 }
 
 //-----------------------------------------------------------------------------
-const char* Compiler::resource_name() const
+void Compiler::write_resource(FileStream* out_file)
 {
-	return m_name;
+	write_resource_impl(out_file);
 }
 
 //-----------------------------------------------------------------------------
-const char* Compiler::resource_type() const
+void Compiler::cleanup()
 {
-	return m_type;
-}
+	cleanup_impl();
 
-//-----------------------------------------------------------------------------
-FileStream* Compiler::source_file()
-{
-	return m_src_file;
+	string::strncpy(m_resource_name, "", MAX_RESOURCE_NAME_LENGTH);
 }
 
 //-----------------------------------------------------------------------------
-FileStream* Compiler::destination_file()
+const char* Compiler::root_path() const
 {
-	return m_dest_file;
+	return m_root_fs.root_path();
 }
 
 //-----------------------------------------------------------------------------
-void Compiler::prepare_header(uint32_t size)
+const char* Compiler::dest_path() const
 {
-	m_compiled_header.magic = COMPILED_HEADER_MAGIC_NUMBER;
-	m_compiled_header.version = COMPILER_VERSION;
-	m_compiled_header.name = m_name_hash;
-	m_compiled_header.type = m_type_hash;
-	m_compiled_header.size = size;
+	return m_dest_fs.root_path();
 }
 
 //-----------------------------------------------------------------------------
-void Compiler::write_header()
+const char* Compiler::resource_name() const
 {
-	m_dest_file->write(&m_compiled_header, sizeof(CompiledHeader));
+	return m_resource_name;
 }
 
 } // namespace crown

+ 19 - 47
tools/compilers/Compiler.h

@@ -59,70 +59,42 @@ class Compiler
 {
 public:
 
-	/// Looks for the @resource int the @root_path and prepares it to
-	/// compilation using @seed to generate hashes for the resource name.
-	/// Implementation must declare the type of resource they are expecting
-	/// to work on by setting @type_expected appropriately.
-						Compiler(const char* root_path, const char* dest_path, const char* resource,
-								 uint32_t type_expected, uint32_t seed);
-	virtual				~Compiler();
+							Compiler(const char* root_path, const char* dest_path, uint32_t type_expected);
+	virtual					~Compiler();
 
-	/// Actually compiles the resource.
-	virtual bool		compile() = 0;
+	size_t					compile(const char* resource, uint32_t name, uint32_t type);
 
-	virtual void		write() = 0;
+	size_t					read_header(FileStream* in_file);
+	size_t					read_resource(FileStream* in_file);
 
-	const char*			root_path() const;
-	const char*			dest_path() const;
-	const char*			resource_path() const;
+	void					write_header(FileStream* out_file, uint32_t name, uint32_t type, uint32_t resource_size);
+	void					write_resource(FileStream* out_file);
 
-	uint32_t			resource_name_hash() const;
-	uint32_t			resource_type_hash() const;
-	uint32_t			seed() const;
+	void					cleanup();
 
-	const char*			resource_name() const;
-	const char*			resource_type() const;
-
-	FileStream*			source_file();
-	FileStream*			destination_file();
+	const char*				root_path() const;
+	const char*				dest_path() const;
+	const char*				resource_name() const;
 
 protected:
 
-	void				prepare_header(uint32_t size);
-	void				write_header();
-
-private:
-
-	// These memebers are private to prevent
-	// derived classes from manipulating them.
+	virtual size_t			read_header_impl(FileStream* in_file) = 0;
+	virtual size_t			read_resource_impl(FileStream* in_file) = 0;
 
-	// Generic informations
-	char				m_root_path[MAX_RESOURCE_PATH_LENGTH];
-	char				m_dest_path[MAX_RESOURCE_PATH_LENGTH];
-	char				m_resource[MAX_RESOURCE_PATH_LENGTH];
+	virtual void			write_header_impl(FileStream* out_file) = 0;
+	virtual void			write_resource_impl(FileStream* out_file) = 0;
 
-	uint32_t			m_name_hash;
-	uint32_t			m_type_hash;
-	uint32_t			m_seed;
+	virtual void			cleanup_impl() = 0;
 
-	char				m_name[MAX_RESOURCE_NAME_LENGTH];
-	char				m_type[MAX_RESOURCE_TYPE_LENGTH];
+private:
 
 	// Filesystems
 	Filesystem			m_root_fs;
 	Filesystem			m_dest_fs;
 
-	FileStream*			m_src_file;
-	FileStream*			m_dest_file;
-
-	// Compilation stage
-	CompiledHeader		m_compiled_header;
+	uint32_t			m_type_expected;
 
-	bool				m_prepared;
-
-	// Global compiler settings
-	bool				m_verbose;
+	char				m_resource_name[MAX_RESOURCE_NAME_LENGTH];
 };
 
 } // namespace crown
-

+ 78 - 29
tools/compilers/lua/LuaCompiler.cpp

@@ -1,63 +1,112 @@
+/*
+Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+*/
+
 #include "LuaCompiler.h"
 #include "FileStream.h"
 #include "Resource.h"
+#include "Log.h"
 
 namespace crown
 {
 
 //-----------------------------------------------------------------------------
-LuaCompiler::LuaCompiler(const char* root_path, const char* dest_path, const char* resource, uint32_t seed) :
-	Compiler(root_path, dest_path, resource, SCRIPT_TYPE, seed),
+LuaCompiler::LuaCompiler(const char* root_path, const char* dest_path) :
+	Compiler(root_path, dest_path, SCRIPT_TYPE),
 	m_file_size(0),
 	m_file_data(NULL)
 {
+}
 
+//-----------------------------------------------------------------------------
+LuaCompiler::~LuaCompiler()
+{
+	cleanup_impl();
+}
+
+//-----------------------------------------------------------------------------
+size_t LuaCompiler::read_header_impl(FileStream* in_file)
+{
+	(void) in_file;
+	return 0;
 }
 
 //-----------------------------------------------------------------------------
-bool LuaCompiler::compile()
+size_t LuaCompiler::read_resource_impl(FileStream* in_file)
 {
-    Filesystem fs(root_path());
+	Filesystem fs(root_path());
 
-    char tmp_resource[os::MAX_PATH_LENGTH];
+	char tmp_resource[os::MAX_PATH_LENGTH];
 
-    string::strcpy(tmp_resource, resource_path());
-    string::strcat(tmp_resource, ".script");
+	string::strcpy(tmp_resource, resource_name());
+	string::strcat(tmp_resource, ".script");
 
-    if (!fs.exists(tmp_resource))
-    {
-        os::printf("Resource cannot be found.\n");
-        return false;
-    }
+	if (!fs.exists(tmp_resource))
+	{
+		Log::e("'%s': resource cannot be found.");
+		return 0;
+	}
 
-    FileStream* file = (FileStream*)fs.open(tmp_resource, SOM_READ);
+	FileStream* tmp_file = (FileStream*)fs.open(tmp_resource, SOM_READ);
 
-    m_file_size = file->size();
+	m_file_size = tmp_file->size();
 
-    if (m_file_size == 0)
-    {
-        return false;
-    }
+	if (m_file_size == 0)
+	{
+		Log::e("'%s': resource is empty.");
+		return 0;
+	}
 
-    m_file_data = new char[m_file_size];
-    
-    // Copy the entire file into the buffer
-    file->read(m_file_data, m_file_size);
+	m_file_data = new char[m_file_size];
 
-    // Prepare for writing
-    Compiler::prepare_header(m_file_size);
+	// Copy the entire file into the buffer
+	tmp_file->read(m_file_data, m_file_size);
 
-    return true;
+	// Returns the total size of the resource
+	return m_file_size;
 }
 
 //-----------------------------------------------------------------------------
-void LuaCompiler::write()
+void LuaCompiler::write_header_impl(FileStream* out_file)
 {
-    Compiler::write_header();
+	(void) out_file;
+}
 
-    FileStream* file = Compiler::destination_file();
+//-----------------------------------------------------------------------------
+void LuaCompiler::write_resource_impl(FileStream* out_file)
+{
+	out_file->write(m_file_data, m_file_size);
+}
 
-    file->write(m_file_data, m_file_size);
+//-----------------------------------------------------------------------------
+void LuaCompiler::cleanup_impl()
+{
+	if (m_file_data)
+	{
+		delete[] m_file_data;
+		m_file_data = NULL;
+	}
 }
 
 } // namespace crown

+ 34 - 3
tools/compilers/lua/LuaCompiler.h

@@ -1,3 +1,28 @@
+/*
+Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+*/
+
 #pragma once
 
 #include "Compiler.h"
@@ -10,10 +35,16 @@ class LuaCompiler : public Compiler
 {
 
 public:
-					LuaCompiler(const char* root_path, const char* dest_path, const char* resource, uint32_t seed);
+					LuaCompiler(const char* root_path, const char* dest_path);
+					~LuaCompiler();
+
+	size_t			read_header_impl(FileStream* in_file);
+	size_t			read_resource_impl(FileStream* in_file);
+
+	void			write_header_impl(FileStream* out_file);
+	void			write_resource_impl(FileStream* out_file);
 
-	bool			compile();
-	void 			write();
+	void			cleanup_impl();
 
 private:
 

+ 23 - 0
tools/compilers/lua/bytecode-generator.lua

@@ -1,3 +1,26 @@
+-- Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto
+-- 
+-- Permission is hereby granted, free of charge, to any person
+-- obtaining a copy of this software and associated documentation
+-- files (the "Software"), to deal in the Software without
+-- restriction, including without limitation the rights to use,
+-- copy, modify, merge, publish, distribute, sublicense, and/or sell
+-- copies of the Software, and to permit persons to whom the
+-- Software is furnished to do so, subject to the following
+-- conditions:
+-- 
+-- The above copyright notice and this permission notice shall be
+-- included in all copies or substantial portions of the Software.
+-- 
+-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+-- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+-- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+-- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+-- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+-- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+-- OTHER DEALINGS IN THE SOFTWARE.
+
 local src = arg[1]
 local tmp = src .. ".script"
 

+ 30 - 24
tools/compilers/ps/PSCompiler.cpp

@@ -31,8 +31,8 @@ namespace crown
 {
 
 //-----------------------------------------------------------------------------
-PSCompiler::PSCompiler(const char* root_path, const char* dest_path, const char* resource, uint32_t seed) :
-	Compiler(root_path, dest_path, resource, PIXEL_SHADER_TYPE, seed),
+PSCompiler::PSCompiler(const char* root_path, const char* dest_path) :
+	Compiler(root_path, dest_path, PIXEL_SHADER_TYPE),
 	m_file_size(0),
 	m_file_data(NULL)
 {
@@ -41,44 +41,50 @@ PSCompiler::PSCompiler(const char* root_path, const char* dest_path, const char*
 //-----------------------------------------------------------------------------
 PSCompiler::~PSCompiler()
 {
-	if (m_file_data)
-	{
-		delete[] m_file_data;
-	}
+	cleanup_impl();
 }
 
 //-----------------------------------------------------------------------------
-bool PSCompiler::compile()
+size_t PSCompiler::read_header_impl(FileStream* in_file)
 {
-	FileStream* file = Compiler::source_file();
-
-	m_file_size = file->size();
+	(void) in_file;
+	return 0;
+}
 
-	if (m_file_size == 0)
-	{
-		return false;
-	}
+//-----------------------------------------------------------------------------
+size_t PSCompiler::read_resource_impl(FileStream* in_file)
+{
+	m_file_size = in_file->size();
 
 	m_file_data = new char[m_file_size];
 	
 	// Copy the entire file into the buffer
-	file->read(m_file_data, m_file_size);
-
-	// Prepare for writing
-	Compiler::prepare_header(m_file_size + sizeof(uint32_t));
+	in_file->read(m_file_data, m_file_size);
 
-	return true;
+	// Return total resource size
+	return m_file_size + sizeof(uint32_t);
 }
 
 //-----------------------------------------------------------------------------
-void PSCompiler::write()
+void PSCompiler::write_header_impl(FileStream* out_file)
 {
-	Compiler::write_header();
+	out_file->write(&m_file_size, sizeof(uint32_t));
+}
 
-	FileStream* file = Compiler::destination_file();
+//-----------------------------------------------------------------------------
+void PSCompiler::write_resource_impl(FileStream* out_file)
+{
+	out_file->write(m_file_data, m_file_size);
+}
 
-	file->write(&m_file_size, sizeof(uint32_t));
-	file->write(m_file_data, m_file_size);
+//-----------------------------------------------------------------------------
+void PSCompiler::cleanup_impl()
+{
+	if (m_file_data)
+	{
+		delete[] m_file_data;
+		m_file_data = NULL;
+	}
 }
 
 } // namespace crown

+ 8 - 3
tools/compilers/ps/PSCompiler.h

@@ -34,11 +34,16 @@ class PSCompiler : public Compiler
 {
 public:
 
-					PSCompiler(const char* root_path, const char* dest_path, const char* resource, uint32_t seed);
+					PSCompiler(const char* root_path, const char* dest_path);
 					~PSCompiler();
 
-	bool			compile();
-	void			write();
+	size_t			read_header_impl(FileStream* in_file);
+	size_t			read_resource_impl(FileStream* in_file);
+
+	void			write_header_impl(FileStream* out_file);
+	void			write_resource_impl(FileStream* out_file);
+
+	void			cleanup_impl();
 
 private:
 

+ 176 - 0
tools/compilers/resource-compiler.cpp

@@ -0,0 +1,176 @@
+#include "Crown.h"
+#include "tga/TGACompiler.h"
+#include "txt/TXTCompiler.h"
+#include "lua/LuaCompiler.h"
+#include "vs/VSCompiler.h"
+#include "ps/PSCompiler.h"
+
+using namespace crown;
+
+// Max number of requests per run
+const uint32_t MAX_COMPILE_REQUESTS = 512;
+
+const char*		root_path = NULL;
+const char*		dest_path = NULL;
+uint32_t		hash_seed = 0;
+
+// Help functions
+int32_t			parse_command_line(int argc, char* argv[]);
+void			print_help_message(const char* program_name);
+void			check_arguments(const char* root_path, const char* dest_path);
+void			compile_by_type(const char* resource);
+
+//-----------------------------------------------------------------------------
+int main(int argc, char** argv)
+{
+	int32_t first_resource = parse_command_line(argc, argv);
+
+	// Check if all the mandatory options are set
+	check_arguments(root_path, dest_path);
+
+	// If there are no resources
+	if (first_resource >= argc)
+	{
+		Log::e("you have to specify at least one resource.");
+		exit(EXIT_FAILURE);
+	}
+
+	TGACompiler tga(root_path, dest_path);
+	TXTCompiler txt(root_path, dest_path);
+	LuaCompiler lua(root_path, dest_path);
+	VSCompiler vs(root_path, dest_path);
+	PSCompiler ps(root_path, dest_path);
+
+	char resource_name[MAX_RESOURCE_NAME_LENGTH];
+	char resource_type[MAX_RESOURCE_TYPE_LENGTH];
+
+	// Dispatch requests to the appropriate compiler
+	for (int32_t res = first_resource; res < argc; res++)
+	{
+		char* resource = argv[res];
+
+		path::filename_without_extension(resource, resource_name, MAX_RESOURCE_NAME_LENGTH);
+		path::extension(resource, resource_type, MAX_RESOURCE_TYPE_LENGTH);
+
+		uint32_t resource_name_hash = hash::murmur2_32(resource_name, string::strlen(resource_name), hash_seed);
+		uint32_t resource_type_hash = hash::murmur2_32(resource_type, string::strlen(resource_type), 0);
+
+		switch (resource_type_hash)
+		{
+			case TEXTURE_TYPE:
+			{
+				tga.compile(resource, resource_name_hash, resource_type_hash);
+				break;
+			}
+			case TEXT_TYPE:
+			{
+				txt.compile(resource, resource_name_hash, resource_type_hash);
+				break;
+			}
+			case SCRIPT_TYPE:
+			{
+				lua.compile(resource, resource_name_hash, resource_type_hash);
+				break;
+			}
+			case VERTEX_SHADER_TYPE:
+			{
+				vs.compile(resource, resource_name_hash, resource_type_hash);
+				break;
+			}
+			case PIXEL_SHADER_TYPE:
+			{
+				ps.compile(resource, resource_name_hash, resource_type_hash);
+				break;	
+			}
+			default:
+			{
+				Log::e("Resource type not supported.");
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
+//-----------------------------------------------------------------------------
+int32_t parse_command_line(int argc, char* argv[])
+{
+	// Parse arguments
+	static ArgsOption options[] = 
+	{
+		"help",         AOA_NO_ARGUMENT,       NULL,        'h',
+		"root-path",    AOA_REQUIRED_ARGUMENT, NULL,        'r',
+		"dest-path",    AOA_REQUIRED_ARGUMENT, NULL,        'd',
+		"seed",         AOA_REQUIRED_ARGUMENT, NULL,        's',
+		NULL, 0, NULL, 0
+	};
+
+	Args args(argc, argv, "", options);
+
+	int32_t opt;
+
+	while ((opt = args.getopt()) != -1)
+	{
+		switch (opt)
+		{
+			// Root path
+			case 'r':
+			{
+				root_path = args.optarg();
+				break;
+			}
+			// Dest path
+			case 'd':
+			{
+				dest_path = args.optarg();
+				break;
+			}
+			case 's':
+			{
+				hash_seed = atoi(args.optarg());
+				break;
+			}
+			case 'h':
+			case '?':
+			default:
+			{
+				print_help_message(argv[0]);
+				exit(EXIT_FAILURE);
+			}
+		}
+	}
+
+	return args.optind();
+}
+
+//-----------------------------------------------------------------------------
+void print_help_message(const char* program_name)
+{
+	printf("Usage: %s [options] [resources]\n", program_name);
+	printf
+	(
+		"Options:\n\n"
+
+		"  --help                  Show this help.\n"
+		"  --root-path <path>      The absolute <path> whether to look for the input resources.\n"
+		"  --dest-path <path>      The absolute <path> whether to put the compiled resources.\n"
+		"  --seed <value>          The seed to use for generating output resource hashes.\n"
+	);
+}
+
+//-----------------------------------------------------------------------------
+void check_arguments(const char* root_path, const char* dest_path)
+{
+	if (root_path == NULL)
+	{
+		Log::e("you have to specify the root path with `--root-path`\n");
+		exit(EXIT_FAILURE);
+	}
+
+	if (dest_path == NULL)
+	{
+		Log::e("you have to specify the destination path with `--dest-path`\n");
+		exit(EXIT_FAILURE);
+	}
+}

+ 54 - 38
tools/compilers/tga/TGACompiler.cpp

@@ -27,13 +27,14 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "FileStream.h"
 #include "PixelFormat.h"
 #include "Resource.h"
+#include "Log.h"
 
 namespace crown
 {
 
 //-----------------------------------------------------------------------------
-TGACompiler::TGACompiler(const char* root_path, const char* dest_path, const char* resource, uint32_t seed) :
-	Compiler(root_path, dest_path, resource, TEXTURE_TYPE, seed),
+TGACompiler::TGACompiler(const char* root_path, const char* dest_path) :
+	Compiler(root_path, dest_path, TEXTURE_TYPE),
 	m_image_format(PF_UNKNOWN),
 	m_image_channels(0),
 	m_image_size(0),
@@ -43,16 +44,26 @@ TGACompiler::TGACompiler(const char* root_path, const char* dest_path, const cha
 }
 
 //-----------------------------------------------------------------------------
-bool TGACompiler::compile()
+TGACompiler::~TGACompiler()
 {
-	FileStream* file = Compiler::source_file();
+	cleanup_impl();
+}
 
+//-----------------------------------------------------------------------------
+size_t TGACompiler::read_header_impl(FileStream* in_file)
+{
 	// Read the header
-	file->read(&m_tga_header, sizeof(TGAHeader));
+	in_file->read(&m_tga_header, sizeof(TGAHeader));
 
 	// Skip TGA ID
-	file->skip(m_tga_header.id_length);
+	in_file->skip(m_tga_header.id_length);
+
+	return sizeof(TGAHeader) + m_tga_header.id_length;
+}
 
+//-----------------------------------------------------------------------------
+size_t TGACompiler::read_resource_impl(FileStream* in_file)
+{
 	// Compute color channels	
 	m_image_channels = m_tga_header.pixel_depth / 8;
 	
@@ -68,7 +79,7 @@ bool TGACompiler::compile()
 		{
 			m_image_format = PF_RGB_8;
 			m_image_data = new uint8_t[(uint32_t)(m_image_size * 3)];
-			
+
 			break;
 		}
 		case 4:
@@ -80,8 +91,8 @@ bool TGACompiler::compile()
 		}
 		default:
 		{
-			printf("Fatal: Unable to determine TGA channels. Aborting.\n");
-			return false;
+			Log::e("Unable to determine TGA channels.");
+			return 0;
 		}
 	}
 
@@ -90,54 +101,61 @@ bool TGACompiler::compile()
 	{
 		case 0:
 		{
-			printf("Fatal: The resource does not contain image data. Aborting.\n");
-			return false;
+			Log::e("Fatal: The resource does not contain image data.");
+			return 0;
 		}
 		case 2:
 		{
-			load_uncompressed();
+			load_uncompressed(in_file);
 			break;
 		}
 
 		case 10:
 		{
-			load_compressed();
+			load_compressed(in_file);
 			break;
 		}
 
 		default:
 		{
-			printf("Fatal: Image type not supported. Aborting.");
-			return false;
+			Log::e("Fatal: Image type not supported.");
+			return 0;
 		}
 	}
 
-	// Prepare for writing
-	Compiler::prepare_header(m_image_size * m_image_channels +
-							 sizeof(PixelFormat) + sizeof(uint16_t) * 2);
-
-	return true;
+	// Return the total resource size
+	return m_image_size * m_image_channels + sizeof(PixelFormat) + sizeof(uint16_t) + sizeof(uint16_t);
 }
 
 //-----------------------------------------------------------------------------
-void TGACompiler::write()
+void TGACompiler::write_header_impl(FileStream* out_file)
 {
-	Compiler::write_header();
-
-	FileStream* file = Compiler::destination_file();
+	// Write the texture header
+	out_file->write(&m_image_format, sizeof(PixelFormat));
+	out_file->write(&m_tga_header.width, sizeof(uint16_t));
+	out_file->write(&m_tga_header.height, sizeof(uint16_t));
+}
 
+//-----------------------------------------------------------------------------
+void TGACompiler::write_resource_impl(FileStream* out_file)
+{
 	// Write out the data
-	file->write(&m_image_format, sizeof(PixelFormat));
-	file->write(&m_tga_header.width, sizeof(uint16_t));
-	file->write(&m_tga_header.height, sizeof(uint16_t));
-	file->write(m_image_data, m_image_size * m_image_channels);
+	out_file->write(m_image_data, m_image_size * m_image_channels);
 }
 
 //-----------------------------------------------------------------------------
-void TGACompiler::load_uncompressed()
+void TGACompiler::cleanup_impl()
 {
-	FileStream* file = Compiler::source_file();
+	if (m_image_data)
+	{
+		delete[] m_image_data;
+		m_image_data = NULL;
+	}
+}
 
+//-----------------------------------------------------------------------------
+void TGACompiler::load_uncompressed(FileStream* in_file)
+{
 	uint64_t size = m_tga_header.width * m_tga_header.height;
 
 	if (m_image_channels == 2)
@@ -148,7 +166,7 @@ void TGACompiler::load_uncompressed()
 		{
 			uint16_t pixel_data;
 			
-			file->read(&pixel_data, sizeof(pixel_data));
+			in_file->read(&pixel_data, sizeof(pixel_data));
 			
 			m_image_data[j + 0] = (pixel_data & 0x7c) >> 10;
 			m_image_data[j + 1] = (pixel_data & 0x3e) >> 5;
@@ -159,17 +177,15 @@ void TGACompiler::load_uncompressed()
 	}
 	else
 	{
-		file->read(m_image_data, (size_t)(size * m_image_channels));
+		in_file->read(m_image_data, (size_t)(size * m_image_channels));
 
 		swap_red_blue();
 	}
 }
 
 //-----------------------------------------------------------------------------
-void TGACompiler::load_compressed()
+void TGACompiler::load_compressed(FileStream* in_file)
 {
-	FileStream* file = Compiler::source_file();
-
 	uint8_t rle_id = 0;
 	uint32_t i = 0;
 	uint32_t colors_read = 0;
@@ -180,14 +196,14 @@ void TGACompiler::load_compressed()
 
 	while (i < size)
 	{
-		file->read(&rle_id, sizeof(uint8_t));
+		in_file->read(&rle_id, sizeof(uint8_t));
 
 		// If MSB == 1
 		if (rle_id & 0x80)
 		{
 			rle_id -= 127;
 			
-			file->read(&colors, m_image_channels);
+			in_file->read(&colors, m_image_channels);
 
 			while (rle_id)
 			{
@@ -211,7 +227,7 @@ void TGACompiler::load_compressed()
 
 			while (rle_id)
 			{
-				file->read(colors, m_image_channels);
+				in_file->read(colors, m_image_channels);
 				
 				m_image_data[colors_read + 0] = colors[2];
 				m_image_data[colors_read + 1] = colors[1];

+ 11 - 5
tools/compilers/tga/TGACompiler.h

@@ -51,15 +51,21 @@ class TGACompiler : public Compiler
 {
 public:
 
-					TGACompiler(const char* root_path, const char* dest_path, const char* resource, uint32_t seed);
+					TGACompiler(const char* root_path, const char* dest_path);
+					~TGACompiler();
 
-	bool			compile();
-	void			write();
+	size_t			read_header_impl(FileStream* in_file);
+	size_t			read_resource_impl(FileStream* in_file);
+
+	void			write_header_impl(FileStream* out_file);
+	void			write_resource_impl(FileStream* out_file);
+
+	void			cleanup_impl();
 
 private:
 
-	void			load_uncompressed();
-	void			load_compressed();
+	void			load_uncompressed(FileStream* in_file);
+	void			load_compressed(FileStream* in_file);
 	void			swap_red_blue();
 
 private:

+ 29 - 25
tools/compilers/txt/TXTCompiler.cpp

@@ -31,8 +31,8 @@ namespace crown
 {
 
 //-----------------------------------------------------------------------------
-TXTCompiler::TXTCompiler(const char* root_path, const char* dest_path, const char* resource, uint32_t seed) :
-	Compiler(root_path, dest_path, resource, TEXT_TYPE, seed),
+TXTCompiler::TXTCompiler(const char* root_path, const char* dest_path) :
+	Compiler(root_path, dest_path, TEXT_TYPE),
 	m_file_size(0),
 	m_file_data(NULL)
 {
@@ -41,45 +41,49 @@ TXTCompiler::TXTCompiler(const char* root_path, const char* dest_path, const cha
 //-----------------------------------------------------------------------------
 TXTCompiler::~TXTCompiler()
 {
-	if (m_file_data)
-	{
-		delete[] m_file_data;
-	}
+	cleanup_impl();
 }
 
 //-----------------------------------------------------------------------------
-bool TXTCompiler::compile()
+size_t TXTCompiler::read_header_impl(FileStream* in_file)
 {
-	FileStream* file = Compiler::source_file();
-
-	m_file_size = file->size();
+	(void) in_file;
+	return 0;
+}
 
-	if (m_file_size == 0)
-	{
-		return false;
-	}
+//-----------------------------------------------------------------------------
+size_t TXTCompiler::read_resource_impl(FileStream* in_file)
+{
+	m_file_size = in_file->size();
 
 	m_file_data = new char[m_file_size];
 	
 	// Copy the entire file into the buffer
-	file->read(m_file_data, m_file_size);
-
-	// Prepare for writing
-	Compiler::prepare_header(m_file_size + sizeof(uint32_t));
+	in_file->read(m_file_data, m_file_size);
 
-	return true;
+	// Return the total resource size
+	return m_file_size + sizeof(uint32_t);
 }
 
 //-----------------------------------------------------------------------------
-void TXTCompiler::write()
+void TXTCompiler::write_header_impl(FileStream* out_file)
 {
-	Compiler::write_header();
+	out_file->write(&m_file_size, sizeof(uint32_t));
+}
 
-	FileStream* file = Compiler::destination_file();
+//-----------------------------------------------------------------------------
+void TXTCompiler::write_resource_impl(FileStream* out_file)
+{
+	out_file->write(m_file_data, m_file_size);
+}
 
-	file->write(&m_file_size, sizeof(uint32_t));
-	file->write(m_file_data, m_file_size);
+void TXTCompiler::cleanup_impl()
+{
+	if (m_file_data)
+	{
+		delete[] m_file_data;
+		m_file_data = NULL;
+	}
 }
 
 } // namespace crown
-

+ 8 - 3
tools/compilers/txt/TXTCompiler.h

@@ -35,11 +35,16 @@ class TXTCompiler : public Compiler
 {
 public:
 
-					TXTCompiler(const char* root_path, const char* dest_path, const char* resource, uint32_t seed);
+					TXTCompiler(const char* root_path, const char* dest_path);
 					~TXTCompiler();
 
-	bool			compile();
-	void			write();
+	size_t			read_header_impl(FileStream* in_file);
+	size_t			read_resource_impl(FileStream* in_file);
+
+	void			write_header_impl(FileStream* out_file);
+	void			write_resource_impl(FileStream* out_file);
+
+	void			cleanup_impl();
 
 private:
 

+ 30 - 24
tools/compilers/vs/VSCompiler.cpp

@@ -31,8 +31,8 @@ namespace crown
 {
 
 //-----------------------------------------------------------------------------
-VSCompiler::VSCompiler(const char* root_path, const char* dest_path, const char* resource, uint32_t seed) :
-	Compiler(root_path, dest_path, resource, VERTEX_SHADER_TYPE, seed),
+VSCompiler::VSCompiler(const char* root_path, const char* dest_path) :
+	Compiler(root_path, dest_path, VERTEX_SHADER_TYPE),
 	m_file_size(0),
 	m_file_data(NULL)
 {
@@ -41,44 +41,50 @@ VSCompiler::VSCompiler(const char* root_path, const char* dest_path, const char*
 //-----------------------------------------------------------------------------
 VSCompiler::~VSCompiler()
 {
-	if (m_file_data)
-	{
-		delete[] m_file_data;
-	}
+	cleanup_impl();
 }
 
 //-----------------------------------------------------------------------------
-bool VSCompiler::compile()
+size_t VSCompiler::read_header_impl(FileStream* in_file)
 {
-	FileStream* file = Compiler::source_file();
-
-	m_file_size = file->size();
+	(void) in_file;
+	return 0;
+}
 
-	if (m_file_size == 0)
-	{
-		return false;
-	}
+//-----------------------------------------------------------------------------
+size_t VSCompiler::read_resource_impl(FileStream* in_file)
+{
+	m_file_size = in_file->size();
 
 	m_file_data = new char[m_file_size];
 	
 	// Copy the entire file into the buffer
-	file->read(m_file_data, m_file_size);
-
-	// Prepare for writing
-	Compiler::prepare_header(m_file_size + sizeof(uint32_t));
+	in_file->read(m_file_data, m_file_size);
 
-	return true;
+	// Return total resource size
+	return m_file_size + sizeof(uint32_t);
 }
 
 //-----------------------------------------------------------------------------
-void VSCompiler::write()
+void VSCompiler::write_header_impl(FileStream* out_file)
 {
-	Compiler::write_header();
+	out_file->write(&m_file_size, sizeof(uint32_t));
+}
 
-	FileStream* file = Compiler::destination_file();
+//-----------------------------------------------------------------------------
+void VSCompiler::write_resource_impl(FileStream* out_file)
+{
+	out_file->write(m_file_data, m_file_size);
+}
 
-	file->write(&m_file_size, sizeof(uint32_t));
-	file->write(m_file_data, m_file_size);
+//-----------------------------------------------------------------------------
+void VSCompiler::cleanup_impl()
+{
+	if (m_file_data)
+	{
+		delete[] m_file_data;
+		m_file_data = NULL;
+	}
 }
 
 } // namespace crown

+ 8 - 3
tools/compilers/vs/VSCompiler.h

@@ -34,11 +34,16 @@ class VSCompiler : public Compiler
 {
 public:
 
-					VSCompiler(const char* root_path, const char* dest_path, const char* resource, uint32_t seed);
+					VSCompiler(const char* root_path, const char* dest_path);
 					~VSCompiler();
 
-	bool			compile();
-	void			write();
+	size_t			read_header_impl(FileStream* in_file);
+	size_t			read_resource_impl(FileStream* in_file);
+
+	void			write_header_impl(FileStream* out_file);
+	void			write_resource_impl(FileStream* out_file);
+
+	void			cleanup_impl();
 
 private:
 

+ 19 - 49
tools/pycrown/Compiler.py

@@ -27,11 +27,7 @@ import os
 
 LUAJIT = "luajit-2.0.1"
 BC_G = "bytecode-generator.lua"
-TXT_C = "txt-compiler"
-TGA_C = "tga-compiler"
-LUA_C = "lua-compiler"
-VS_C = "vs-compiler"
-PS_C = "ps-compiler"
+COMPILER_NAME = "resource-compiler"
 RES_H = "resource-hash"
 
 ROOT_P = "--root-path"
@@ -83,45 +79,27 @@ class Compiler:
 
 	# Compiles all the texture resources in the repository
 	def compile_textures(self):
-		textures = self.m_repository.texture_resources();
-
-		for res in textures:
-			self.compile(res)
+		self.compile(self.m_repository.texture_resources());
 
 	# Compiles all the mesh resources in the repository
 	def compile_meshes(self):
-		meshes = self.m_repository.mesh_resources();
-
-		for res in meshes:
-			self.compile(res)
+		self.compile(self.m_repository.mesh_resources());
 
 	# Compiles all the text resources in the repository
 	def compile_texts(self):
-		texts = self.m_repository.text_resources();
-
-		for res in texts:
-			self.compile(res)
+		self.compile(self.m_repository.text_resources());
 
 	# Compiles all the script resources in the repository
 	def compile_scripts(self):
-		scripts = self.m_repository.script_resources();
-
-		for res in scripts:
-			self.compile(res)
+		self.compile(self.m_repository.script_resources());
 
 	# Compiles all the vertex shader resources in the repository
 	def compile_vertex_shaders(self):
-		vss = self.m_repository.vertex_shader_resources();
-
-		for res in vss:
-			self.compile(res)
+		self.compile(self.m_repository.vertex_shader_resources());
 
 	# Compiles all the vertex shader resources in the repository
 	def compile_pixel_shaders(self):
-		pss = self.m_repository.pixel_shader_resources();
-
-		for res in pss:
-			self.compile(res)
+		self.compile(self.m_repository.pixel_shader_resources());
 
 	# Compiles all the resources in the repository
 	def compile_all(self):
@@ -144,31 +122,23 @@ class Compiler:
 		self.compile_pixel_shaders()
 
 	# Compile a single resource from the repository
-	def compile(self, resource):
+	def compile(self, resources):
+		if (len(resources) == 0):
+			return
+
 		# Compute perfect seed if necessary
 		if (self.m_perfect_seed == -1):
 			self.compute_perfect_seed()
 
 		root_path = self.m_repository.root_path()
+		resource_params = (' '.join(resources)).split();
+		compiler_params = [COMPILER_NAME, "--root-path", root_path, "--dest-path", self.m_dest_path, "--seed", str(self.m_perfect_seed)]
 
-		print(resource + " => ???")
-
-		# Call appropriate compiler based on resource extension
-		if resource.endswith('.txt'):
-			p = subprocess.call([TXT_C, ROOT_P, root_path, DEST_P, self.m_dest_path, RES_IN, resource, SEED, str(self.m_perfect_seed)]);
-		
-		if resource.endswith('.tga'):
-			p = subprocess.call([TGA_C, ROOT_P, root_path, DEST_P, self.m_dest_path, RES_IN, resource, SEED, str(self.m_perfect_seed)]);
-		
-		if resource.endswith('.lua'):
-			path = os.path.normpath(root_path + "/" + resource)
-			f = subprocess.call([LUAJIT, BC_G, path]);
-			p = subprocess.call([LUA_C, ROOT_P, root_path, DEST_P, self.m_dest_path, RES_IN, resource, SEED, str(self.m_perfect_seed)]);
-		
-		if resource.endswith('.vs'):
-			p = subprocess.call([VS_C, ROOT_P, root_path, DEST_P, self.m_dest_path, RES_IN, resource, SEED, str(self.m_perfect_seed)]);
-		
-		if resource.endswith('.ps'):
-			p = subprocess.call([PS_C, ROOT_P, root_path, DEST_P, self.m_dest_path, RES_IN, resource, SEED, str(self.m_perfect_seed)]);
+		p = subprocess.call(compiler_params + resource_params)
 
+		# if resource.endswith('.lua'):
+		# 	path = os.path.normpath(root_path + "/" + resource)
+		# 	f = subprocess.call([LUAJIT, BC_G, path]);
+		# 	p = subprocess.call([LUA_C, ROOT_P, root_path, DEST_P, self.m_dest_path, RES_IN, resource, SEED, str(self.m_perfect_seed)]);
+