Procházet zdrojové kódy

Add basic compilation framework

Daniele Bartolini před 12 roky
rodič
revize
7fce4f3b0b

+ 9 - 22
tools/CMakeLists.txt

@@ -4,35 +4,22 @@ project(crown-tools)
 
 include(FindFreetype)
 
-link_directories(${CROWN_BINARY_DIR})
-
 if (FREETYPE_FOUND)
-include_directories(${FREETYPE_INCLUDE_DIRS})
-link_libraries(${FREETYPE_LIBRARIES})
+	include_directories(${FREETYPE_INCLUDE_DIRS})
+	link_libraries(${FREETYPE_LIBRARIES})
 endif (FREETYPE_FOUND)
 
 find_package(PkgConfig)
 
 pkg_check_modules(GTKMM gtkmm-3.0)
 
-link_directories(${GTKMM_LIBRARY_DIRS})
-include_directories(${GTKMM_INCLUDE_DIRS})
-
-add_executable(resource-hash resource-compilers/resource-hash.cpp)
-
-add_executable(txt-compiler resource-compilers/txt-compiler.cpp)
-add_executable(tga-compiler resource-compilers/tga-compiler.cpp)
-add_executable(lua-compiler resource-compilers/lua-compiler.cpp)
-
-add_executable(resource-linker resource-compilers/resource-linker.cpp)
-
-target_link_libraries(resource-hash crown)
-
-target_link_libraries(txt-compiler crown)
-target_link_libraries(tga-compiler crown)
-target_link_libraries(lua-compiler crown)
+set (INCLUDES
+	resource-compilers
+)
 
-target_link_libraries(resource-linker crown)
+link_directories(${CROWN_BINARY_DIR} ${GTKMM_LIBRARY_DIRS})
+include_directories(${INCLUDES} ${GTKMM_INCLUDE_DIRS})
 
-add_subdirectory(gtk)
+add_subdirectory(resource-compilers)
+add_subdirectory(world-editor)
 

+ 25 - 0
tools/resource-compilers/CMakeLists.txt

@@ -0,0 +1,25 @@
+cmake_minimum_required(VERSION 2.8)
+
+set (SRC
+	Compiler.cpp
+)
+
+set (HEADERS
+	Compiler.h
+)
+
+# utils
+add_library(crown-compiler-utils ${SRC} ${HEADERS})
+target_link_libraries(crown-compiler-utils crown)
+
+# resource-linker
+add_executable(resource-linker resource-linker.cpp)
+target_link_libraries(resource-linker crown)
+
+# resource-hash
+add_executable(resource-hash resource-hash.cpp)
+target_link_libraries(resource-hash crown)
+
+add_subdirectory(txt)
+add_subdirectory(tga)
+#add_subdirectory(lua)

+ 170 - 0
tools/resource-compilers/Compiler.cpp

@@ -0,0 +1,170 @@
+/*
+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 "Compiler.h"
+#include "Hash.h"
+#include "Path.h"
+#include "FileStream.h"
+#include <cstring>
+
+namespace crown
+{
+
+//-----------------------------------------------------------------------------
+Compiler::Compiler(const char* root_path, const char* dest_path, const char* resource, uint32_t seed) :
+	m_name_hash(0),
+	m_type_hash(0),
+	m_seed(seed),
+
+	m_root_fs(root_path),
+	m_dest_fs(dest_path),
+	m_src_file(NULL),
+	m_dest_file(NULL),
+
+	m_prepared(false),
+
+	m_verbose(false)
+{
+	// 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);
+
+	memset(&m_compiled_header, 0, sizeof(CompiledHeader));
+	memset(m_name, 0, MAX_RESOURCE_NAME_LENGTH);
+	memset(m_type, 0, 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);
+
+	// 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);
+
+	// Compute hashes
+	m_name_hash = hash::murmur2_32(m_name, string::strlen(m_name), m_seed);
+	m_type_hash = hash::murmur2_32(m_type, string::strlen(m_type), m_seed);
+
+	char dest_name[17];
+	memset(dest_name, 0, 17);
+
+	snprintf(dest_name, 17, "%X%X", m_name_hash, m_type_hash);
+
+	// Open streams
+	m_src_file = (FileStream*)m_root_fs.open(m_resource, SOM_READ);
+	m_dest_file = (FileStream*)m_dest_fs.open(dest_name, SOM_WRITE);
+}
+
+//-----------------------------------------------------------------------------
+Compiler::~Compiler()
+{
+	if (m_src_file != NULL)
+	{
+		m_root_fs.close(m_src_file);
+	}
+
+	if (m_dest_file != NULL)
+	{
+		m_dest_fs.close(m_dest_file);
+	}
+}
+
+//-----------------------------------------------------------------------------
+const char* Compiler::root_path() const
+{
+	return m_root_path;
+}
+
+//-----------------------------------------------------------------------------
+const char* Compiler::dest_path() const
+{
+	return m_dest_path;
+}
+
+//-----------------------------------------------------------------------------
+const char* Compiler::resource_path() const
+{
+	return m_resource;
+}
+
+//-----------------------------------------------------------------------------
+uint32_t Compiler::resource_name_hash() const
+{
+	return m_name_hash;
+}
+
+//-----------------------------------------------------------------------------
+uint32_t Compiler::resource_type_hash() const
+{
+	return m_type_hash;
+}
+
+//-----------------------------------------------------------------------------
+uint32_t Compiler::seed() const
+{
+	return m_seed;
+}
+
+//-----------------------------------------------------------------------------
+const char* Compiler::resource_name() const
+{
+	return m_name;
+}
+
+//-----------------------------------------------------------------------------
+const char* Compiler::resource_type() const
+{
+	return m_type;
+}
+
+//-----------------------------------------------------------------------------
+FileStream* Compiler::source_file()
+{
+	return m_src_file;
+}
+
+//-----------------------------------------------------------------------------
+FileStream* Compiler::destination_file()
+{
+	return m_dest_file;
+}
+
+//-----------------------------------------------------------------------------
+void Compiler::prepare_header(uint32_t size)
+{
+	m_compiled_header.name = m_name_hash;
+	m_compiled_header.type = m_type_hash;
+	m_compiled_header.size = size;
+}
+
+//-----------------------------------------------------------------------------
+void Compiler::write_header()
+{
+	m_dest_file->write(&m_compiled_header, sizeof(CompiledHeader));
+}
+
+} // namespace crown
+

+ 120 - 0
tools/resource-compilers/Compiler.h

@@ -0,0 +1,120 @@
+/*
+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 "Types.h"
+#include "Filesystem.h"
+
+namespace crown
+{
+
+const size_t MAX_RESOURCE_NAME_LENGTH = 1024;
+const size_t MAX_RESOURCE_TYPE_LENGTH = 64;
+const size_t MAX_RESOURCE_PATH_LENGTH = 1024;
+
+/// Contains the header data common to all
+/// types of resources passing through the
+/// standard Compiler mechanics.
+struct CompiledHeader
+{
+	uint32_t	name;	// Name of the resource (murmur2_32 hash)
+	uint32_t	type;	// Type of the resource (murmur2_32 hash)
+	uint32_t	size;	// Size of the resource data _not_ including header (in bytes)
+};
+
+class FileStream;
+
+/// Resource compiler interface.
+/// Every specific resource compiler must inherith from this
+/// interface and implement its methods accordingly.
+class Compiler
+{
+public:
+
+						/// Looks for the @resource int the @root_path and prepares it to
+						/// compilation using @seed to generate string hashes.
+						Compiler(const char* root_path, const char* dest_path, const char* resource, uint32_t seed);
+	virtual				~Compiler();
+
+						/// Actually compiles the resource.
+	virtual bool		compile() = 0;
+
+	virtual void		write() = 0;
+
+	const char*			root_path() const;
+	const char*			dest_path() const;
+	const char*			resource_path() const;
+
+	uint32_t			resource_name_hash() const;
+	uint32_t			resource_type_hash() const;
+	uint32_t			seed() const;
+
+	const char*			resource_name() const;
+	const char*			resource_type() const;
+
+	FileStream*			source_file();
+	FileStream*			destination_file();
+
+protected:
+
+	void				prepare_header(uint32_t size);
+	void				write_header();
+
+private:
+
+	// These memebers are private to prevent
+	// derived classes from manipulating them.
+
+	// 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];
+
+	uint32_t			m_name_hash;
+	uint32_t			m_type_hash;
+	uint32_t			m_seed;
+
+	char				m_name[MAX_RESOURCE_NAME_LENGTH];
+	char				m_type[MAX_RESOURCE_TYPE_LENGTH];
+
+	// Filesystems
+	Filesystem			m_root_fs;
+	Filesystem			m_dest_fs;
+
+	FileStream*			m_src_file;
+	FileStream*			m_dest_file;
+
+	// Compilation stage
+	CompiledHeader		m_compiled_header;
+
+	bool				m_prepared;
+
+	// Global compiler settings
+	bool				m_verbose;
+};
+
+} // namespace crown
+

+ 0 - 0
tools/resource-compilers/lua-compiler.cpp → tools/resource-compilers/lua/main.cpp


+ 0 - 396
tools/resource-compilers/tga-compiler.cpp

@@ -1,396 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "Crown.h"
-
-const char* root_path = NULL;
-const char* dest_path = NULL;
-const char* resource_in = NULL;
-const char* resource_out = NULL;
-uint32_t hash_seed = 0;
-
-using namespace crown;
-
-struct TGAHeader
-{
-
-	char		id_length;			// 00h  Size of Image ID field
-	char		color_map_type;		// 01h  Color map type
-	char		image_type;			// 02h  Image type code
-	char		c_map_spec[5];		// 03h  Color map origin 05h Color map length 07h Depth of color map entries
-	uint16_t	x_offset;			// 08h  X origin of image
-	uint16_t	y_offset;			// 0Ah  Y origin of image
-	uint16_t	width;				// 0Ch  Width of image
-	uint16_t	height;				// 0Eh  Height of image
-	char		pixel_depth;     	// 10h  Image pixel size
-	char		image_descriptor;	// 11h  Image descriptor byte
-};
-
-void print_help_message(const char* program_name);
-void parse_command_line(int argc, char** argv);
-
-void load_uncompressed(void* dest, Stream* stream, uint32_t width, uint32_t height, uint32_t channels);
-void load_compressed(void* dest, Stream* stream, uint32_t width, uint32_t height, uint32_t channels);
-void swap_red_blue(uint8_t* data, uint64_t size, uint32_t channels);
-
-/// TGA compiler for "tga" resource type
-/// TODO: Explain supported formats, usage etc.
-int main(int argc, char** argv)
-{
-	parse_command_line(argc, argv);
-	
-	// FIXME: validate input
-
-	Filesystem fs_root(root_path);
-	Filesystem fs_dest(dest_path);
-	
-	if (!fs_root.exists(resource_in))
-	{
-		printf("%s: ERROR: %s does not exist. Aborting.\n", argv[0], resource_in);
-		return -1;
-	}
-	
-	char resource_basename[256];
-	char resource_extension[256];
-	
-	path::filename_without_extension(resource_in, resource_basename, 256);
-	path::extension(resource_in, resource_extension, 256);
-	
-	uint32_t resource_basename_hash = hash::murmur2_32(resource_basename, string::strlen(resource_basename), hash_seed);
-	uint32_t resource_extension_hash = hash::murmur2_32(resource_extension, string::strlen(resource_extension), hash_seed);
-
-	char out_filename[512];
-	out_filename[0] = '\0';
-
-	snprintf(resource_basename, 256, "%X", resource_basename_hash);
-	snprintf(resource_extension, 256, "%X", resource_extension_hash);
-	
-	string::strncat(out_filename, resource_basename, 512);
-	string::strncat(out_filename, resource_extension, 512);
-
-	resource_out = out_filename;
-
-	printf("%s => %s\n", resource_in, resource_out);
-
-	FileStream* src_file = (FileStream*)fs_root.open(resource_in, SOM_READ);
-	
-	//-------------------------------------------------------------------------
-	// Read TGA Header
-	//-------------------------------------------------------------------------
-	
-	// The TGA header used throughout the code
-	TGAHeader header;
-	memset(&header, 0, sizeof(TGAHeader));
-	
-	// Read the header
-	src_file->read(&header, sizeof(TGAHeader));
-
-	// Skip TGA ID
-	src_file->skip(header.id_length);
-
-	// Pixel format currently unknown
-	PixelFormat format = PF_UNKNOWN;
-
-	// Compute color channels	
-	uint32_t channels = header.pixel_depth / 8;
-	
-	// Compute image size
-	uint64_t image_size = header.width * header.height;
-	
-	uint8_t* image_data = NULL;
-
-	// Select the appropriate pixel format and allocate resource data based on tga size and channels
-	switch (channels)
-	{
-		case 2:
-		case 3:
-		{
-			format = PF_RGB_8;
-			image_data = new uint8_t[(uint32_t)(image_size * 3)];
-			
-			break;
-		}
-		case 4:
-		{
-			format = PF_RGBA_8;
-			image_data = new uint8_t[(uint32_t)(image_size * channels)];
-			
-			break;
-		}
-		default:
-		{
-			printf("Fatal: Unable to determine TGA channels. Aborting.\n");
-			return -1;
-		}
-	}
-
-	// Determine image type (compressed/uncompressed) and call proper function to load TGA
-	switch (header.image_type)
-	{
-		case 0:
-		{
-			printf("Fatal: The resource does not contain image data. Aborting.");
-			exit(-1);
-		}
-		case 2:
-		{
-			load_uncompressed(image_data, src_file, header.width, header.height, channels);
-			break;
-		}
-
-		case 10:
-		{
-			load_compressed(image_data, src_file, header.width, header.height, channels);
-			break;
-		}
-
-		default:
-		{
-			printf("Fatal: Image type not supported. Aborting.");
-			exit(-1);
-		}
-	}
-	
-	// Open output file
-	FileStream* dest_file = (FileStream*)fs_dest.open(resource_out, SOM_WRITE);
-	
-	ArchiveEntry archive_entry;
-	archive_entry.name = resource_basename_hash;
-	archive_entry.type = resource_extension_hash;
-	archive_entry.offset = sizeof(ArchiveEntry);
-	archive_entry.size = image_size * channels + sizeof(PixelFormat) + sizeof(uint16_t) * 2;
-							
-	// Write out the archive entry
-	dest_file->write(&archive_entry, sizeof(ArchiveEntry));
-
-	// Write out the data
-	dest_file->write(&format, sizeof(PixelFormat));
-	dest_file->write(&header.width, sizeof(uint16_t));
-	dest_file->write(&header.height, sizeof(uint16_t));
-	
-	dest_file->write(image_data, image_size * channels);
-	
-	// Done, free the resources and exit
-	if (image_data != NULL)
-	{
-		delete[] image_data;
-	}
-	
-	fs_dest.close(dest_file);
-
-	return 0;
-}
-
-//-----------------------------------------------------------------------------
-void parse_command_line(int argc, char** argv)
-{
-	// Parse arguments
-	ArgsOption options[] = 
-	{
-		"help",         AOA_NO_ARGUMENT,       NULL,        'h',
-		"root-path",    AOA_REQUIRED_ARGUMENT, NULL,        'r',
-		"dest-path",    AOA_REQUIRED_ARGUMENT, NULL,        'd',
-		"resource-in",  AOA_REQUIRED_ARGUMENT, NULL,        'i',
-		"seed",         AOA_REQUIRED_ARGUMENT, NULL,        's',
-		NULL, 0, NULL, 0
-	};
-
-	Args args(argc, argv, "", options);
-
-	while (1)
-	{
-		int32_t ret = args.next_option();
-		
-		switch (ret)
-		{
-			case -1:
-			{
-				return;
-			}
-			// Help message
-			case 'h':
-			{
-				print_help_message(argv[0]);
-				exit(0);
-			}
-			// Root path
-			case 'r':
-			{
-				if (args.option_argument() == NULL)
-				{
-					printf("%s: ERROR: missing path after `--root-path`\n", argv[0]);
-					exit(-1);
-				}
-				
-				root_path = args.option_argument();
-				
-				break;
-			}
-			// Dest path
-			case 'd':
-			{
-				if (args.option_argument() == NULL)
-				{
-					printf("%s: ERROR: missing path after `--dest-path`\n", argv[0]);
-					exit(-1);
-				}
-				
-				dest_path = args.option_argument();
-				
-				break;
-			}
-			// Resource in
-			case 'i':
-			{
-				if (args.option_argument() == NULL)
-				{
-					printf("%s: ERROR: missing path after `--resource-in`\n", argv[0]);
-					exit(-1);
-				}
-				
-				resource_in = args.option_argument();
-				
-				break;
-			}
-			case 's':
-			{
-				if (args.option_argument() == NULL)
-				{
-					printf("%s: ERROR: missing seed value after `--seed`\n", argv[0]);
-					exit(-1);
-				}
-
-				hash_seed = atoi(args.option_argument());
-
-				break;
-			}
-			default:
-			{
-				break;
-			}
-		}
-	}
-}
-
-//-----------------------------------------------------------------------------
-void print_help_message(const char* program_name)
-{
-	printf("Usage: %s [options]\n", program_name);
-	printf("Options:\n\n");
-
-	printf("  --help                  Show this help.\n");
-	printf("  --root-path <path>      The _absolute_ <path> whether to look for the input resource.\n");
-	printf("  --dest-path <path>      The _absolute_ <path> whether to put the compiled resource.\n");
-	printf("  --resource-in <path>    The _relative_ <path> of the input resource.\n");
-	printf("  --seed <value>          The unsigned integer <value> of the hash seed.\n");
-}
-
-//-----------------------------------------------------------------------------
-void load_uncompressed(void* dest, Stream* stream, uint32_t width, uint32_t height, uint32_t channels)
-{
-	uint64_t size = width * height;
-	
-	uint8_t* data = (uint8_t*)dest;
-
-	if (channels == 2)
-	{
-		int32_t j = 0;
-
-		for (uint64_t i = 0; i < size * channels; i++)
-		{
-			uint16_t pixel_data;
-			
-			stream->read(&pixel_data, sizeof(pixel_data));
-			
-			data[j + 0] = (pixel_data & 0x7c) >> 10;
-			data[j + 1] = (pixel_data & 0x3e) >> 5;
-			data[j + 2] = (pixel_data & 0x1f);
-			
-			j += 3;
-		}
-	}
-	else
-	{
-		stream->read(data, (size_t)(size * channels));
-
-		swap_red_blue(data, size * channels, channels);
-	}
-}
-
-//-----------------------------------------------------------------------------
-void load_compressed(void* dest, Stream* stream, uint32_t width, uint32_t height, uint32_t channels)
-{
-	uint8_t rle_id = 0;
-	uint32_t i = 0;
-	uint32_t colors_read = 0;
-	uint64_t size = width * height;
-	
-	uint8_t* data = (uint8_t*)dest;
-
-	uint8_t* colors = new uint8_t[channels];
-
-	while (i < size)
-	{
-		stream->read(&rle_id, sizeof(uint8_t));
-
-		// If MSB == 1
-		if (rle_id & 0x80)
-		{
-			rle_id -= 127;
-			
-			stream->read(colors, channels);
-
-			while (rle_id)
-			{
-				data[colors_read + 0] = colors[2];
-				data[colors_read + 1] = colors[1];
-				data[colors_read + 2] = colors[0];
-
-				if (channels == 4)
-				{
-					data[colors_read + 3] = colors[3];
-				}
-
-				rle_id--;
-				colors_read += channels;
-				i++;
-			}
-		}
-		else
-		{
-			rle_id++;
-
-			while (rle_id)
-			{
-				stream->read(colors, channels);
-				
-				data[colors_read + 0] = colors[2];
-				data[colors_read + 1] = colors[1];
-				data[colors_read + 2] = colors[0];
-
-				if (channels == 4)
-				{
-					data[colors_read + 3] = colors[3];
-				}
-
-				rle_id--;
-				colors_read += channels;
-				i++;
-			}
-		}
-	}
-
-	delete[] colors;
-}
-
-//-----------------------------------------------------------------------------
-void swap_red_blue(uint8_t* data, uint64_t size, uint32_t channels)
-{
-	for (uint64_t i = 0; i < size; i += channels)
-	{
-		data[i] ^= data[i+2];
-		data[i+2] ^= data[i];
-		data[i] ^= data[i+2];
-	}
-}
-

+ 14 - 0
tools/resource-compilers/tga/CMakeLists.txt

@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 2.8)
+
+set (SRC
+	TGACompiler.cpp
+	main.cpp
+)
+
+set (HEADERS
+	TGACompiler.h
+)
+
+add_executable(tga-compiler ${SRC} ${HEADERS})
+target_link_libraries(tga-compiler crown-compiler-utils)
+

+ 244 - 0
tools/resource-compilers/tga/TGACompiler.cpp

@@ -0,0 +1,244 @@
+/*
+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 "TGACompiler.h"
+#include "FileStream.h"
+#include "Pixel.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, seed),
+	m_image_format(PF_UNKNOWN),
+	m_image_channels(0),
+	m_image_size(0),
+	m_image_data(NULL)
+{
+	memset(&m_tga_header, 0, sizeof(TGAHeader));
+}
+
+//-----------------------------------------------------------------------------
+bool TGACompiler::compile()
+{
+	FileStream* file = Compiler::source_file();
+
+	// Read the header
+	file->read(&m_tga_header, sizeof(TGAHeader));
+
+	// Skip TGA ID
+	file->skip(m_tga_header.id_length);
+
+	// Compute color channels	
+	m_image_channels = m_tga_header.pixel_depth / 8;
+	
+	// Compute image size
+	m_image_size = m_tga_header.width * m_tga_header.height;
+
+	// Select the appropriate pixel format and allocate
+	// resource data based on tga size and channels
+	switch (m_image_channels)
+	{
+		case 2:
+		case 3:
+		{
+			m_image_format = PF_RGB_8;
+			m_image_data = new uint8_t[(uint32_t)(m_image_size * 3)];
+			
+			break;
+		}
+		case 4:
+		{
+			m_image_format = PF_RGBA_8;
+			m_image_data = new uint8_t[(uint32_t)(m_image_size * m_image_channels)];
+			
+			break;
+		}
+		default:
+		{
+			printf("Fatal: Unable to determine TGA channels. Aborting.\n");
+			return false;
+		}
+	}
+
+	// Determine image type (compressed/uncompressed) and call proper function to load TGA
+	switch (m_tga_header.image_type)
+	{
+		case 0:
+		{
+			printf("Fatal: The resource does not contain image data. Aborting.\n");
+			return false;
+		}
+		case 2:
+		{
+			load_uncompressed();
+			break;
+		}
+
+		case 10:
+		{
+			load_compressed();
+			break;
+		}
+
+		default:
+		{
+			printf("Fatal: Image type not supported. Aborting.");
+			return false;
+		}
+	}
+
+	// Prepare for writing
+	Compiler::prepare_header(m_image_size * m_image_channels +
+							 sizeof(PixelFormat) + sizeof(uint16_t) * 2);
+
+	return true;
+}
+
+//-----------------------------------------------------------------------------
+void TGACompiler::write()
+{
+	Compiler::write_header();
+
+	FileStream* file = Compiler::destination_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);
+}
+
+//-----------------------------------------------------------------------------
+void TGACompiler::load_uncompressed()
+{
+	FileStream* file = Compiler::source_file();
+
+	uint64_t size = m_tga_header.width * m_tga_header.height;
+
+	if (m_image_channels == 2)
+	{
+		int32_t j = 0;
+
+		for (uint64_t i = 0; i < size * m_image_channels; i++)
+		{
+			uint16_t pixel_data;
+			
+			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;
+			m_image_data[j + 2] = (pixel_data & 0x1f);
+			
+			j += 3;
+		}
+	}
+	else
+	{
+		file->read(m_image_data, (size_t)(size * m_image_channels));
+
+		swap_red_blue();
+	}
+}
+
+//-----------------------------------------------------------------------------
+void TGACompiler::load_compressed()
+{
+	FileStream* file = Compiler::source_file();
+
+	uint8_t rle_id = 0;
+	uint32_t i = 0;
+	uint32_t colors_read = 0;
+	uint64_t size = m_tga_header.width * m_tga_header.height;
+
+	// Can't be more than 4 channels
+	uint8_t colors[4];
+
+	while (i < size)
+	{
+		file->read(&rle_id, sizeof(uint8_t));
+
+		// If MSB == 1
+		if (rle_id & 0x80)
+		{
+			rle_id -= 127;
+			
+			file->read(&colors, m_image_channels);
+
+			while (rle_id)
+			{
+				m_image_data[colors_read + 0] = colors[2];
+				m_image_data[colors_read + 1] = colors[1];
+				m_image_data[colors_read + 2] = colors[0];
+
+				if (m_image_channels == 4)
+				{
+					m_image_data[colors_read + 3] = colors[3];
+				}
+
+				rle_id--;
+				colors_read += m_image_channels;
+				i++;
+			}
+		}
+		else
+		{
+			rle_id++;
+
+			while (rle_id)
+			{
+				file->read(colors, m_image_channels);
+				
+				m_image_data[colors_read + 0] = colors[2];
+				m_image_data[colors_read + 1] = colors[1];
+				m_image_data[colors_read + 2] = colors[0];
+
+				if (m_image_channels == 4)
+				{
+					m_image_data[colors_read + 3] = colors[3];
+				}
+
+				rle_id--;
+				colors_read += m_image_channels;
+				i++;
+			}
+		}
+	}
+}
+
+//-----------------------------------------------------------------------------
+void TGACompiler::swap_red_blue()
+{
+	for (uint64_t i = 0; i < m_image_size; i += m_image_channels)
+	{
+		m_image_data[i + 0] ^= m_image_data[i + 2];
+		m_image_data[i + 2] ^= m_image_data[i + 0];
+		m_image_data[i + 0] ^= m_image_data[i + 2];
+	}
+}
+
+} // namespace crown
+

+ 76 - 0
tools/resource-compilers/tga/TGACompiler.h

@@ -0,0 +1,76 @@
+/*
+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"
+#include "FileStream.h"
+#include "Pixel.h"
+
+namespace crown
+{
+
+struct TGAHeader
+{
+
+	char		id_length;			// 00h  Size of Image ID field
+	char		color_map_type;		// 01h  Color map type
+	char		image_type;			// 02h  Image type code
+	char		c_map_spec[5];		// 03h  Color map origin 05h Color map length 07h Depth of color map entries
+	uint16_t	x_offset;			// 08h  X origin of image
+	uint16_t	y_offset;			// 0Ah  Y origin of image
+	uint16_t	width;				// 0Ch  Width of image
+	uint16_t	height;				// 0Eh  Height of image
+	char		pixel_depth;     	// 10h  Image pixel size
+	char		image_descriptor;	// 11h  Image descriptor byte
+};
+
+class TGACompiler : public Compiler
+{
+public:
+
+					TGACompiler(const char* root_path, const char* dest_path, const char* resource, uint32_t seed);
+
+	bool			compile();
+	void			write();
+
+private:
+
+	void			load_uncompressed();
+	void			load_compressed();
+	void			swap_red_blue();
+
+private:
+
+	TGAHeader		m_tga_header;
+
+	PixelFormat		m_image_format;
+	uint32_t		m_image_channels;
+	uint64_t		m_image_size;
+	uint8_t*		m_image_data;
+};
+
+} // namespace crown
+

+ 141 - 0
tools/resource-compilers/tga/main.cpp

@@ -0,0 +1,141 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "Crown.h"
+#include "TGACompiler.h"
+
+const char* root_path = NULL;
+const char* dest_path = NULL;
+const char* resource_in = NULL;
+uint32_t hash_seed = 0;
+
+using namespace crown;
+
+void print_help_message(const char* program_name);
+void parse_command_line(int argc, char** argv);
+
+/// TGA compiler for "tga" resource type
+/// TODO: Explain supported formats, usage etc.
+int main(int argc, char** argv)
+{
+	parse_command_line(argc, argv);
+	
+	// FIXME: validate input
+
+	TGACompiler compiler(root_path, dest_path, resource_in, hash_seed);
+
+	if (compiler.compile() == false)
+	{
+		printf("%s: ERROR: compilation failed for resource %s\n", argv[0], compiler.resource_path());
+		exit(-1);
+	}
+
+	compiler.write();
+
+	return 0;
+}
+
+//-----------------------------------------------------------------------------
+void parse_command_line(int argc, char** argv)
+{
+	// Parse arguments
+	ArgsOption options[] = 
+	{
+		"help",         AOA_NO_ARGUMENT,       NULL,        'h',
+		"root-path",    AOA_REQUIRED_ARGUMENT, NULL,        'r',
+		"dest-path",    AOA_REQUIRED_ARGUMENT, NULL,        'd',
+		"resource-in",  AOA_REQUIRED_ARGUMENT, NULL,        'i',
+		"seed",         AOA_REQUIRED_ARGUMENT, NULL,        's',
+		NULL, 0, NULL, 0
+	};
+
+	Args args(argc, argv, "", options);
+
+	while (1)
+	{
+		int32_t ret = args.next_option();
+		
+		switch (ret)
+		{
+			case -1:
+			{
+				return;
+			}
+			// Help message
+			case 'h':
+			{
+				print_help_message(argv[0]);
+				exit(0);
+			}
+			// Root path
+			case 'r':
+			{
+				if (args.option_argument() == NULL)
+				{
+					printf("%s: ERROR: missing path after `--root-path`\n", argv[0]);
+					exit(-1);
+				}
+				
+				root_path = args.option_argument();
+				
+				break;
+			}
+			// Dest path
+			case 'd':
+			{
+				if (args.option_argument() == NULL)
+				{
+					printf("%s: ERROR: missing path after `--dest-path`\n", argv[0]);
+					exit(-1);
+				}
+				
+				dest_path = args.option_argument();
+				
+				break;
+			}
+			// Resource in
+			case 'i':
+			{
+				if (args.option_argument() == NULL)
+				{
+					printf("%s: ERROR: missing path after `--resource-in`\n", argv[0]);
+					exit(-1);
+				}
+				
+				resource_in = args.option_argument();
+				
+				break;
+			}
+			case 's':
+			{
+				if (args.option_argument() == NULL)
+				{
+					printf("%s: ERROR: missing seed value after `--seed`\n", argv[0]);
+					exit(-1);
+				}
+
+				hash_seed = atoi(args.option_argument());
+
+				break;
+			}
+			default:
+			{
+				break;
+			}
+		}
+	}
+}
+
+//-----------------------------------------------------------------------------
+void print_help_message(const char* program_name)
+{
+	printf("Usage: %s [options]\n", program_name);
+	printf("Options:\n\n");
+
+	printf("  --help                  Show this help.\n");
+	printf("  --root-path <path>      The _absolute_ <path> whether to look for the input resource.\n");
+	printf("  --dest-path <path>      The _absolute_ <path> whether to put the compiled resource.\n");
+	printf("  --resource-in <path>    The _relative_ <path> of the input resource.\n");
+	printf("  --seed <value>          The unsigned integer <value> of the hash seed.\n");
+}
+

+ 15 - 0
tools/resource-compilers/txt/CMakeLists.txt

@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 2.8)
+
+# txt-compiler
+set (SRC
+	TXTCompiler.cpp
+	main.cpp
+)
+
+set (HEADERS
+	TXTCompiler.h
+)
+
+add_executable(txt-compiler ${SRC} ${HEADERS})
+target_link_libraries(txt-compiler crown-compiler-utils)
+

+ 84 - 0
tools/resource-compilers/txt/TXTCompiler.cpp

@@ -0,0 +1,84 @@
+/*
+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 "TXTCompiler.h"
+#include "FileStream.h"
+
+namespace crown
+{
+
+//-----------------------------------------------------------------------------
+TXTCompiler::TXTCompiler(const char* root_path, const char* dest_path, const char* resource, uint32_t seed) :
+	Compiler(root_path, dest_path, resource, seed),
+	m_file_size(0),
+	m_file_data(NULL)
+{
+}
+
+//-----------------------------------------------------------------------------
+TXTCompiler::~TXTCompiler()
+{
+	if (m_file_data)
+	{
+		delete[] m_file_data;
+	}
+}
+
+//-----------------------------------------------------------------------------
+bool TXTCompiler::compile()
+{
+	FileStream* file = Compiler::source_file();
+
+	m_file_size = file->size();
+
+	if (m_file_size == 0)
+	{
+		return false;
+	}
+
+	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));
+
+	return true;
+}
+
+//-----------------------------------------------------------------------------
+void TXTCompiler::write()
+{
+	Compiler::write_header();
+
+	FileStream* file = Compiler::destination_file();
+
+	file->write(&m_file_size, sizeof(uint32_t));
+	file->write(m_file_data, m_file_size);
+}
+
+} // namespace crown
+

+ 50 - 0
tools/resource-compilers/txt/TXTCompiler.h

@@ -0,0 +1,50 @@
+/*
+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"
+#include "FileStream.h"
+
+namespace crown
+{
+
+class TXTCompiler : public Compiler
+{
+public:
+
+					TXTCompiler(const char* root_path, const char* dest_path, const char* resource, uint32_t seed);
+
+	bool			compile();
+	void			write();
+
+private:
+
+	uint32_t		m_file_size;
+	char*			m_file_data;
+};
+
+} // namespace crown
+

+ 32 - 52
tools/resource-compilers/txt-compiler.cpp → tools/resource-compilers/txt/main.cpp

@@ -1,14 +1,39 @@
+/*
+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 <stdio.h>
 #include <stdlib.h>
 
 #include "Crown.h"
+#include "TXTCompiler.h"
 
 using namespace crown;
 
 const char* root_path = NULL;
 const char* dest_path = NULL;
 const char* resource_in = NULL;
-const char* resource_out = NULL;
 uint32_t hash_seed = 0;
 
 void print_help_message(const char* program_name);
@@ -21,60 +46,15 @@ int main(int argc, char** argv)
 	
 	// FIXME: validate input
 
-	Filesystem fs_root(root_path);
-	Filesystem fs_dest(dest_path);
-	
-	if (!fs_root.exists(resource_in))
+	TXTCompiler compiler(root_path, dest_path, resource_in, hash_seed);
+
+	if (compiler.compile() == false)
 	{
-		printf("%s: ERROR: %s does not exist. Aborting.\n", argv[0], resource_in);
-		return -1;
+		printf("%s: ERROR: compilation failed for resource %s\n", argv[0], compiler.resource_path());
+		exit(-1);
 	}
 
-	char resource_basename[256];
-	char resource_extension[256];
-	
-	path::filename_without_extension(resource_in, resource_basename, 256);
-	path::extension(resource_in, resource_extension, 256);
-	
-	uint32_t resource_basename_hash = hash::murmur2_32(resource_basename, string::strlen(resource_basename), hash_seed);
-	uint32_t resource_extension_hash = hash::murmur2_32(resource_extension, string::strlen(resource_extension), hash_seed);
-
-	char out_filename[512];
-	out_filename[0] = '\0';
-
-	snprintf(resource_basename, 256, "%X", resource_basename_hash);
-	snprintf(resource_extension, 256, "%X", resource_extension_hash);
-
-	string::strncat(out_filename, resource_basename, 512);
-	string::strncat(out_filename, resource_extension, 512);
-
-	resource_out = out_filename;
-
-	printf("%s => %s\n", resource_in, resource_out);
-
-	FileStream* src_file = (FileStream*)fs_root.open(resource_in, SOM_READ);
-	
-	size_t src_file_size = src_file->size();
-	
-	ArchiveEntry archive_entry;
-	archive_entry.name = resource_basename_hash;
-	archive_entry.type = resource_extension_hash;
-	archive_entry.offset = sizeof (ArchiveEntry);
-	archive_entry.size = src_file_size + sizeof(uint32_t);
-	
-	void* buffer = new uint8_t[src_file_size];
-	
-	src_file->read(buffer, src_file_size);
-	
-	fs_root.close(src_file);
-	
-	FileStream* dest_file = (FileStream*)fs_dest.open(resource_out, SOM_WRITE);
-
-	dest_file->write(&archive_entry, sizeof(ArchiveEntry));
-	dest_file->write(&src_file_size, sizeof(uint32_t));
-	dest_file->write(buffer, src_file_size);
-
-	fs_dest.close(dest_file);
+	compiler.write();
 
 	return 0;
 }