Просмотр исходного кода

Merge branch 'master' into audio

Conflicts:
	engine/resource/Resource.h
	engine/resource/ResourceManager.cpp
mikymod 12 лет назад
Родитель
Сommit
34784a4ffb

+ 21 - 5
BUILD.txt

@@ -40,23 +40,39 @@ engine on the currently supported platforms.
 
 		1. $ mkdir build
 		2. $ cd build
-		3. $ cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/your/install/dir -DCROWN_ARCH=<arch>
-		   (read below for valid architecture strings)
+		3. $ cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/your/install/dir -DCROWN_BUILD=<build>
+		   (read below for valid build strings)
 		4. $ make
 		5. $ make install
 
-		'CROWN_ARCH' valid values right now are:
+		'CROWN_BUILD' valid values right now are:
+
+ 			* linux-debug-32
+ 			* linux-development-32
+ 			* linux-release-32
+ 			* linux-debug-64
+ 			* linux-development-64
+ 			* linux-release-64
 
-	 		* Linux: "x86" or "x86_64"
 
 	- Windows
 
 		1. Create a folder named 'build'
 		2. Open a terminal and:
 		3. cd build
-		4. cmake.exe .. -DCMAKE_INSTALL_PREFIX=C:/your/install/dir -DCROWN_ARCH=win64
+		4. cmake.exe .. -DCMAKE_INSTALL_PREFIX=C:/your/install/dir -DCROWN_BUILD=<build>
 		5. Open the generated Visual Studio solution and build/install from there
 
+		'CROWN_BUILD' valid values right now are:
+
+ 			* windows-debug-32
+ 			* windows-development-32
+ 			* windows-release-32
+ 			* windows-debug-64
+ 			* windows-development-64
+ 			* windows-release-64
+
+
 	- Android
 
 		1. $ cd utils

+ 1 - 1
CMakeLists.txt

@@ -4,7 +4,7 @@ project(crown)
 
 set (CROWN_VERSION_MAJOR 0)
 set (CROWN_VERSION_MINOR 1)
-set (CROWN_VERSION_MICRO 10)
+set (CROWN_VERSION_MICRO 11)
 
 option (CROWN_BUILD_SAMPLES "Whether to build the samples" ON)
 option (CROWN_BUILD_TOOLS "Whether to build the tools" ON)

+ 4 - 3
engine/CMakeLists.txt

@@ -58,7 +58,8 @@ set (CROWN_INCLUDES
 	${CMAKE_SOURCE_DIR}/engine/lua
 	${CMAKE_SOURCE_DIR}/engine/compilers
 	${CMAKE_SOURCE_DIR}/engine/compilers/lua
-	${CMAKE_SOURCE_DIR}/engine/compilers/tga
+	${CMAKE_SOURCE_DIR}/engine/compilers/texture
+	${CMAKE_SOURCE_DIR}/engine/compilers/mesh
 )
 
 set (SRC
@@ -334,14 +335,14 @@ set (COMPILER_SRC
 	compilers/Compiler.cpp
 	compilers/BundleCompiler.cpp
 	compilers/lua/LuaCompiler.cpp
-	compilers/tga/TGACompiler.cpp
+	compilers/texture/TextureCompiler.cpp
 )
 
 set (COMPILER_HEADER
 	compilers/Compiler.h
 	compilers/BundleCompiler.h
 	compilers/lua/LuaCompiler.h
-	compilers/tga/TGACompiler.h
+	compilers/texture/TextureCompiler.h
 )
 
 set (CROWN_LIBRARIES)

+ 56 - 7
engine/Device.cpp

@@ -53,6 +53,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "Touch.h"
 #include "Types.h"
 #include "Bundle.h"
+#include "TempAllocator.h"
 
 #if defined(LINUX) || defined(WINDOWS)
 	#include "BundleCompiler.h"
@@ -101,6 +102,7 @@ Device::Device() :
 	// Bundle dir is current dir by default.
 	string::strncpy(m_bundle_dir, os::get_cwd(), MAX_PATH_LENGTH);
 	string::strncpy(m_source_dir, "", MAX_PATH_LENGTH);
+	string::strncpy(m_boot_file, "lua/game", MAX_PATH_LENGTH);
 }
 
 //-----------------------------------------------------------------------------
@@ -124,6 +126,7 @@ bool Device::init(int argc, char** argv)
 			if (!m_bundle_compiler->compile(m_bundle_dir, m_source_dir))
 			{
 				CE_DELETE(m_allocator, m_bundle_compiler);
+				m_allocator.clear();
 				Log::e("Exiting.");
 				exit(EXIT_FAILURE);
 			}
@@ -131,6 +134,7 @@ bool Device::init(int argc, char** argv)
 			if (!m_continue)
 			{
 				CE_DELETE(m_allocator, m_bundle_compiler);
+				m_allocator.clear();
 				exit(EXIT_SUCCESS);
 			}
 		}
@@ -147,6 +151,9 @@ bool Device::init(int argc, char** argv)
 	#endif
 	Log::d("Filesystem created.");
 
+	// Read settings from crown.config
+	read_engine_settings();
+
 	m_resource_bundle = Bundle::create(m_allocator, *m_filesystem);
 
 	// // Read resource seed
@@ -173,10 +180,11 @@ bool Device::init(int argc, char** argv)
 
 	CE_ASSERT(m_window != NULL, "Unable to create the window");
 
+	// Create main window
 	m_window->set_title("Crown Game Engine");
-	m_window->show();
 	Log::d("Window created.");
 
+	// Create renderer
 	m_renderer = Renderer::create(m_allocator);
 	m_renderer->init();
 	Log::d("Renderer created.");
@@ -195,10 +203,11 @@ bool Device::init(int argc, char** argv)
 	m_is_init = true;
 	start();
 
-	ResourceId luagame_id = m_resource_manager->load("lua", "lua/game");
+	ResourceId luagame_id = m_resource_manager->load("lua", m_boot_file);
 	m_resource_manager->flush();
 	m_lua_environment->load((LuaResource*) m_resource_manager->data(luagame_id));
 	m_lua_environment->call_global("init", 0);
+	m_resource_manager->unload(luagame_id);
 
 	if (m_quit_after_init == 1)
 	{
@@ -206,17 +215,16 @@ bool Device::init(int argc, char** argv)
 		shutdown();
 	}
 
+	// Show main window
+	m_window->show();
+
 	return true;
 }
 
 //-----------------------------------------------------------------------------
 void Device::shutdown()
 {
-	if (is_init() == false)
-	{
-		Log::e("Crown Engine is not initialized.");	
-		return;
-	}
+	CE_ASSERT(is_init(), "Engine is not initialized");
 
 	// Shutdowns the game
 	m_lua_environment->call_global("shutdown", 0);
@@ -521,6 +529,47 @@ void Device::check_preferred_settings()
 //-----------------------------------------------------------------------------
 void Device::read_engine_settings()
 {
+	// Check crown.config existance
+	CE_ASSERT(m_filesystem->is_file("crown.config"), "Unable to open crown.config");
+
+	// Copy crown config in a buffer
+	TempAllocator4096 allocator;
+
+	File* config_file = m_filesystem->open("crown.config", FOM_READ);
+
+	char* json_string = (char*)allocator.allocate(config_file->size());
+
+	config_file->read(json_string, config_file->size());
+
+	m_filesystem->close(config_file);
+
+	// Parse crown.config
+	JSONParser parser(json_string);
+
+	JSONElement root = parser.root();
+
+	// Boot
+	if (root.has_key("boot"))
+	{
+		const char* boot = root.key("boot").string_value();
+		const size_t boot_length = string::strlen(boot) + 1;
+
+		string::strncpy(m_boot_file, boot, boot_length);
+	}
+	// Window width
+	if (root.has_key("window_width"))
+	{
+		m_preferred_window_width = root.key("window_width").int_value();
+	}
+	// Window height
+	if (root.has_key("window_height"))
+	{
+		m_preferred_window_height = root.key("window_height").int_value();
+	}
+
+	allocator.deallocate(json_string);
+
+	Log::i("Configuration set");
 }
 
 //-----------------------------------------------------------------------------

+ 2 - 1
engine/Device.h

@@ -127,13 +127,14 @@ private:
 	uint8_t					m_subsystems_heap[MAX_SUBSYSTEMS_HEAP];
 	LinearAllocator			m_allocator;
 
-	// Preferred settings from command line
+	// Preferred settings
 	int32_t					m_preferred_window_width;
 	int32_t					m_preferred_window_height;
 	int32_t					m_preferred_window_fullscreen;
 	uint32_t				m_parent_window_handle;
 	char					m_source_dir[MAX_PATH_LENGTH];
 	char 					m_bundle_dir[MAX_PATH_LENGTH];
+	char 					m_boot_file[MAX_PATH_LENGTH];
 	int32_t					m_compile;
 	int32_t					m_continue;
 

+ 29 - 12
engine/compilers/BundleCompiler.cpp

@@ -24,6 +24,7 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
 */
 
+#include <inttypes.h>
 #include "BundleCompiler.h"
 #include "Vector.h"
 #include "DynamicString.h"
@@ -56,31 +57,47 @@ bool BundleCompiler::compile(const char* bundle_dir, const char* source_dir)
 		temp.create_directory(bundle_dir);
 	}
 
+	DiskFilesystem src_fs(source_dir);
+	DiskFilesystem dst_fs(bundle_dir);
+
 	// Compile all resources
 	for (uint32_t i = 0; i < files.size(); i++)
 	{
-		DynamicString& filename = files[i];
+		const char* filename = files[i].c_str();
+
+		uint64_t filename_hash = hash::murmur2_64(filename, string::strlen(filename), 0);
+
+		char filename_extension[32];
+		path::extension(filename, filename_extension, 32);
+		uint32_t resource_type_hash = hash::murmur2_32(filename_extension, string::strlen(filename_extension), 0);
+
+		// Do not compile if curr resource is a config file
+		if (resource_type_hash == CONFIG_TYPE)
+		{
+			File* src = src_fs.open(filename, FOM_READ);
+			File* dst = dst_fs.open(filename, FOM_WRITE);
+
+			src->copy_to(*dst, src->size());
 
-		char resource_name[1024];
-		char resource_type[1024];
-		path::filename_without_extension(filename.c_str(), resource_name, 1024);
-		path::extension(filename.c_str(), resource_type, 1024);
+			src_fs.close(src);
+			dst_fs.close(dst);
+
+			continue;
+		}
 
-		uint32_t resource_name_hash = hash::murmur2_32(resource_name, string::strlen(resource_name), 0);
-		uint32_t resource_type_hash = hash::murmur2_32(resource_type, string::strlen(resource_type), 0);
+		char out_name[65];
+		snprintf(out_name, 65, "%"PRIx64"", filename_hash);
 
-		char out_name[1024];
-		snprintf(out_name, 1024, "%.8X%.8X", resource_name_hash, resource_type_hash);
-		Log::i("%s <= %s", out_name, filename.c_str());
+		Log::i("%s <= %s", out_name, filename);
 
 		bool result = false;
 		if (resource_type_hash == TEXTURE_TYPE)
 		{
-			result = m_tga.compile(source_dir, bundle_dir, filename.c_str(), out_name);
+			result = m_texture.compile(source_dir, bundle_dir, filename, out_name);
 		}
 		else if (resource_type_hash == LUA_TYPE)
 		{
-			result = m_lua.compile(source_dir, bundle_dir, filename.c_str(), out_name);
+			result = m_lua.compile(source_dir, bundle_dir, filename, out_name);
 		}
 		else
 		{

+ 3 - 3
engine/compilers/BundleCompiler.h

@@ -26,7 +26,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 #pragma once
 
-#include "TGACompiler.h"
+#include "TextureCompiler.h"
 #include "LuaCompiler.h"
 #include "DynamicString.h"
 #include "Vector.h"
@@ -49,8 +49,8 @@ private:
 
 private:
 
-	TGACompiler	m_tga;
-	LuaCompiler m_lua;
+	TextureCompiler	m_texture;
+	LuaCompiler 	m_lua;
 };
 
 } // namespace crown

+ 0 - 163
engine/compilers/sound/OggDecoder.cpp

@@ -1,163 +0,0 @@
-/*
-Copyright (c) 2013 Daniele Bartolini, Michele Rossi
-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 "OggDecoder.h"
-
-namespace crown
-{
-
-//-----------------------------------------------------------------------------
-typedef map<int, OggStream*> StreamMap;
-
-//-----------------------------------------------------------------------------
-OggDecoder::OggDecoder()
-{
-}
-
-//-----------------------------------------------------------------------------
-OggDecoder::~OggDecoder()
-{
-}
-
-//-----------------------------------------------------------------------------
-bool OggDecoder::read_page(istream& file, ogg_sync_state* state, ogg_page* page)
-{
-	int32_t ret = 0;
-
-  // If we've hit end of file we still need to continue processing
-  // any remaining pages that we've got buffered.
-	if (!file.good())
-	{
-		return ogg_sync_pageout(state, page) == 1;
-	}
-
-	int i = 0;
-
-	while((ret = ogg_sync_pageout(state, page)) != 1) 
-	{
-		// Returns a buffer that can be written too
-		// with the given size. This buffer is stored
-		// in the ogg synchronisation structure.
-		char* buffer = ogg_sync_buffer(state, 4096);
-		assert(buffer);
-
-		// Read from the file into the buffer
-		file.read(buffer, 4096);
-
-		int bytes = file.gcount();
-
-		if (bytes == 0) 
-		{
-		  // End of file. 
-		  return false;
-    	}
-
-    	// Update the synchronisation layer with the number
-    	// of bytes written to the buffer
-    	ret = ogg_sync_wrote(state, bytes);
-    	assert(ret == 0/*, "Unable to update OGG sync layer"*/);
-  	}
-
-  	return true;
-}
-
-//-----------------------------------------------------------------------------
-void OggDecoder::play(istream& file)
-{
-	ogg_sync_state state;
-	ogg_page page;
-
-	int ret = ogg_sync_init(&state);
-	assert(ret == 0/*, "Unable to OGG state"*/);
-  
-	while (read_page(file, &state, &page))
-	{
-		int serial = ogg_page_serialno(&page);
-		OggStream* stream;
-
-		// If we are at the beginning of logical stream
-		if(ogg_page_bos(&page))
-		{
-			// Read headers and Initialize the stream, giving it the serial
-			// number of the stream for this page.
-			stream = new OggStream(serial);
-			ret = ogg_stream_init(&stream->m_state, serial);
-			assert(ret == 0/*, "Unable to init stream"*/);
-			m_streams[serial] = stream;
-		}
-
-		assert(m_streams.find(serial) != m_streams.end());
-		stream = m_streams[serial];
-
-		// Add a complete page to the bitstream
-		ret = ogg_stream_pagein(&stream->m_state, &page);
-		assert(ret == 0);
-
-		// Return a complete packet of data from the stream
-		ogg_packet packet;
-		ret = ogg_stream_packetout(&stream->m_state, &packet);
-		assert(ret == 0 || ret == 1/*, "Unable to take out a stream packet"*/);
-		if (ret == 0) 
-		{
-			// Need more data to be able to complete the packet
-			continue;
-		}
-
-	    // A packet is available, this is what we pass to the vorbis or
-	    // theora libraries to decode.
-	    stream->m_num_packet++;
-  }
-
-  // Cleanup
-  ret = ogg_sync_clear(&state);
-  assert(ret == 0);
-}
-
-} // namespace crown
-
-using namespace crown;
-
-//-----------------------------------------------------------------------------
-int main(int argc, char** argv)
-{
-
-	ifstream file(argv[1], ios::in | ios::binary);
-
-	if (file)
-	{
-		OggDecoder decoder;
-		decoder.play(file);
-		file.close();
-
-		for (StreamMap::iterator it = decoder.m_streams.begin(); it != decoder.m_streams.end(); ++it)
-		{
-			OggStream* stream = (*it).second;
-      		printf("stream %.4X has %d packets", stream->m_serial, stream->m_num_packet);
-      		delete stream;
-		}
-	}
-	return 0;
-}

+ 15 - 12
engine/compilers/tga/TGACompiler.cpp → engine/compilers/texture/TextureCompiler.cpp

@@ -24,7 +24,7 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
 */
 
-#include "TGACompiler.h"
+#include "TextureCompiler.h"
 #include "PixelFormat.h"
 #include "Allocator.h"
 #include "Filesystem.h"
@@ -33,23 +33,19 @@ namespace crown
 {
 
 //-----------------------------------------------------------------------------
-TGACompiler::TGACompiler() :
+TextureCompiler::TextureCompiler() :
 	m_texture_data_size(0),
 	m_texture_data(NULL)
 {
 }
 
 //-----------------------------------------------------------------------------
-TGACompiler::~TGACompiler()
+TextureCompiler::~TextureCompiler()
 {
-	if (m_texture_data)
-	{
-		default_allocator().deallocate(m_texture_data);
-	}
 }
 
 //-----------------------------------------------------------------------------
-size_t TGACompiler::compile_impl(Filesystem& fs, const char* resource_path)
+size_t TextureCompiler::compile_impl(Filesystem& fs, const char* resource_path)
 {
 	File* in_file = fs.open(resource_path, FOM_READ);
 
@@ -137,14 +133,21 @@ size_t TGACompiler::compile_impl(Filesystem& fs, const char* resource_path)
 }
 
 //-----------------------------------------------------------------------------
-void TGACompiler::write_impl(File* out_file)
+void TextureCompiler::write_impl(File* out_file)
 {
 	out_file->write((char*)&m_texture_header, sizeof(TextureHeader));
 	out_file->write((char*)m_texture_data, m_texture_data_size);
+
+	if (m_texture_data)
+	{
+		default_allocator().deallocate(m_texture_data);
+		m_texture_data_size = 0;
+		m_texture_data = NULL;
+	}
 }
 
 //-----------------------------------------------------------------------------
-void TGACompiler::load_uncompressed(File* in_file)
+void TextureCompiler::load_uncompressed(File* in_file)
 {
 	uint64_t size = m_tga_header.width * m_tga_header.height;
 
@@ -174,7 +177,7 @@ void TGACompiler::load_uncompressed(File* in_file)
 }
 
 //-----------------------------------------------------------------------------
-void TGACompiler::load_compressed(File* in_file)
+void TextureCompiler::load_compressed(File* in_file)
 {
 	uint8_t rle_id = 0;
 	uint32_t i = 0;
@@ -237,7 +240,7 @@ void TGACompiler::load_compressed(File* in_file)
 }
 
 //-----------------------------------------------------------------------------
-void TGACompiler::swap_red_blue()
+void TextureCompiler::swap_red_blue()
 {
 	for (uint64_t i = 0; i < m_tga_size * m_tga_channels; i += m_tga_channels)
 	{

+ 3 - 3
engine/compilers/tga/TGACompiler.h → engine/compilers/texture/TextureCompiler.h

@@ -47,12 +47,12 @@ struct TGAHeader
 	char		image_descriptor;	// 11h  Image descriptor byte
 };
 
-class TGACompiler : public Compiler
+class TextureCompiler : public Compiler
 {
 public:
 
-					TGACompiler();
-					~TGACompiler();
+					TextureCompiler();
+					~TextureCompiler();
 
 	size_t			compile_impl(Filesystem& fs, const char* resource_path);
 	void			write_impl(File* out_file);

+ 25 - 9
engine/core/json/JSONParser.cpp

@@ -194,14 +194,16 @@ static bool is_escapee(char c)
 //--------------------------------------------------------------------------
 JSONElement::JSONElement() :
 	m_parser(NULL),
-	m_at(NULL)
+	m_at(NULL),
+	m_begin(NULL)
 {
 }
 
 //--------------------------------------------------------------------------
 JSONElement::JSONElement(JSONParser& parser, const char* at) :
 	m_parser(&parser),
-	m_at(at)
+	m_at(at),
+	m_begin(at)
 {
 }
 
@@ -309,25 +311,37 @@ bool JSONElement::is_key_unique(const char* k) const
 }
 
 //--------------------------------------------------------------------------
-bool JSONElement::bool_value() const
+bool JSONElement::bool_value()
 {
-	return JSONParser::parse_bool(m_at);
+	const bool value = JSONParser::parse_bool(m_at);
+
+	m_at = m_begin;
+
+	return value;
 }
 
 //--------------------------------------------------------------------------
-int32_t JSONElement::int_value() const
+int32_t JSONElement::int_value()
 {
-	return JSONParser::parse_int(m_at);
+	const int32_t value = JSONParser::parse_int(m_at);
+
+	m_at = m_begin;
+
+	return value;
 }
 
 //--------------------------------------------------------------------------
-float JSONElement::float_value() const
+float JSONElement::float_value()
 {
-	return JSONParser::parse_float(m_at);
+	const float value = JSONParser::parse_float(m_at);
+
+	m_at = m_begin;
+
+	return value;
 }
 
 //--------------------------------------------------------------------------
-const char* JSONElement::string_value() const
+const char* JSONElement::string_value()
 {
 	static TempAllocator1024 alloc;
 	static List<char> string(alloc);
@@ -336,6 +350,8 @@ const char* JSONElement::string_value() const
 
 	JSONParser::parse_string(m_at, string);
 
+	m_at = m_begin;
+
 	return string.begin();
 }
 

+ 5 - 4
engine/core/json/JSONParser.h

@@ -111,20 +111,20 @@ public:
 	uint32_t			size() const;
 
 	/// Returns the boolean value of the element.
-	bool				bool_value() const;
+	bool				bool_value();
 
 	/// Returns the integer value of the element.
-	int32_t				int_value() const;
+	int32_t				int_value();
 
 	/// Returns the float value of the element.
-	float				float_value() const;
+	float				float_value();
 
 	/// Returns the string value of the element.
 	/// @warning
 	/// The returned string is kept internally until the next call to
 	/// this function, so it is highly unsafe to just keep the pointer
 	/// instead of copying its content somewhere else.
-	const char*			string_value() const;
+	const char*			string_value();
 
 private:
 
@@ -132,6 +132,7 @@ private:
 
 	JSONParser*			m_parser;
 	const char*			m_at;
+	const char*			m_begin;
 
 	friend class 		JSONParser;
 };

+ 56 - 1
engine/core/strings/Hash.h

@@ -44,6 +44,7 @@ const uint64_t FNV1A_PRIME_64				= 1099511628211ull;
 
 // Functions
 uint32_t murmur2_32(const void* key, size_t len, uint32_t seed);
+uint64_t murmur2_64(const void* key, size_t len, unsigned int seed);
 uint32_t fnv1a_32(const void* key, size_t len);
 uint64_t fnv1a_64(const void* key, size_t len);
 
@@ -63,7 +64,7 @@ uint64_t fnv1a_64(const void* key, size_t len);
 ///    machines.
 inline uint32_t murmur2_32(const void* key, size_t len, uint32_t seed)
 {
-	CE_ASSERT(key != NULL, "Key must be != NULL");
+	CE_ASSERT_NOT_NULL(key);
 
 	// 'm' and 'r' are mixing constants generated offline.
 	// They're not really 'magic', they just happen to work well.
@@ -109,6 +110,60 @@ inline uint32_t murmur2_32(const void* key, size_t len, uint32_t seed)
 	return h;
 }
 
+//-----------------------------------------------------------------------------
+inline uint64_t murmur2_64(const void* key, size_t len, unsigned int seed)
+{
+	CE_ASSERT_NOT_NULL(key);
+
+	const unsigned int m = 0x5bd1e995;
+	const int r = 24;
+
+	unsigned int h1 = seed ^ len;
+	unsigned int h2 = 0;
+
+	const unsigned int * data = (const unsigned int *)key;
+
+	while(len >= 8)
+	{
+		unsigned int k1 = *data++;
+		k1 *= m; k1 ^= k1 >> r; k1 *= m;
+		h1 *= m; h1 ^= k1;
+		len -= 4;
+
+		unsigned int k2 = *data++;
+		k2 *= m; k2 ^= k2 >> r; k2 *= m;
+		h2 *= m; h2 ^= k2;
+		len -= 4;
+	}
+
+	if(len >= 4)
+	{
+		unsigned int k1 = *data++;
+		k1 *= m; k1 ^= k1 >> r; k1 *= m;
+		h1 *= m; h1 ^= k1;
+		len -= 4;
+	}
+
+	switch(len)
+	{
+	case 3: h2 ^= ((unsigned char*)data)[2] << 16;
+	case 2: h2 ^= ((unsigned char*)data)[1] << 8;
+	case 1: h2 ^= ((unsigned char*)data)[0];
+			h2 *= m;
+	};
+
+	h1 ^= h2 >> 18; h1 *= m;
+	h2 ^= h1 >> 22; h2 *= m;
+	h1 ^= h2 >> 17; h1 *= m;
+	h2 ^= h1 >> 19; h2 *= m;
+
+	uint64_t h = h1;
+
+	h = (h << 32) | h2;
+
+	return h;
+} 
+
 //-----------------------------------------------------------------------------
 /// FNV-1a hash, 32 bit
 inline uint32_t fnv1a_32(const void* key, size_t len)

+ 39 - 1
engine/lua/LuaEnvironment.cpp

@@ -31,6 +31,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "LuaStack.h"
 #include "Device.h"
 #include "LuaResource.h"
+#include "ResourceManager.h"
 
 namespace crown
 {
@@ -61,6 +62,24 @@ CE_EXPORT int luaopen_libcrown(lua_State* /*L*/)
 	return 1;
 }
 
+//-----------------------------------------------------------------------------
+static int crown_lua_require(lua_State* L)
+{
+	LuaStack stack(L);
+
+	const char* filename = stack.get_string(1);
+
+	const ResourceId lua_res = device()->resource_manager()->load("lua", filename);
+	device()->resource_manager()->flush();
+
+	const LuaResource* lr = (LuaResource*) device()->resource_manager()->data(lua_res);
+	luaL_loadbuffer(L, (const char*) lr->code(), lr->size(), "");
+
+	device()->resource_manager()->unload(lua_res);
+
+	return 1;
+}
+
 //-----------------------------------------------------------------------------
 LuaEnvironment::LuaEnvironment() :
 	m_state(luaL_newstate()),
@@ -79,6 +98,25 @@ void LuaEnvironment::init()
 	// Open Crown library
 	lua_cpcall(m_state, luaopen_libcrown, NULL);
 
+	// Register custom loader
+	lua_getfield(m_state, LUA_GLOBALSINDEX, "package");
+	lua_getfield(m_state, -1, "loaders");
+	lua_remove(m_state, -2);
+
+	int num_loaders = 0;
+	lua_pushnil(m_state);
+	while (lua_next(m_state, -2) != 0)
+	{
+		lua_pop(m_state, 1);
+		num_loaders++;
+	}
+
+	lua_pushinteger(m_state, num_loaders + 1);
+	lua_pushcfunction(m_state, crown_lua_require);
+	lua_rawset(m_state, -3);
+
+	lua_pop(m_state, 1);
+
 	// load_buffer(class_system, string::strlen(class_system));
 	// execute(0, 0);
 	// load_buffer(commands_list, string::strlen(commands_list));
@@ -117,7 +155,7 @@ void LuaEnvironment::load(const LuaResource* lr)
 
 	if (luaL_loadbuffer(m_state, (const char*) lr->code(), lr->size(), "") != 0)
 	{
-		lua_error();		
+		lua_error();
 	}
 
 	if (lua_pcall(m_state, 0, 0, 0) != 0)

+ 12 - 0
engine/os/android/ApkFilesystem.cpp

@@ -56,6 +56,18 @@ void ApkFilesystem::close(File* file)
 	CE_DELETE(default_allocator(), file);
 }
 
+//-----------------------------------------------------------------------------
+bool ApkFilesystem::is_directory(const char* path)
+{
+	return false;
+}
+
+//-----------------------------------------------------------------------------
+bool ApkFilesystem::is_file(const char* path)
+{
+	return false;
+}
+
 //-----------------------------------------------------------------------------
 void ApkFilesystem::create_directory(const char* /*path*/)
 {

+ 6 - 0
engine/os/android/ApkFilesystem.h

@@ -47,6 +47,12 @@ public:
 	/// @copydoc Filesystem::close()
 	void close(File* file);
 
+	/// Returns always false under Android.
+	bool is_directory(const char* path);
+
+	/// Returns always false under Android.
+	bool is_file(const char* path);
+
 	/// Stub method, assets folder is read-only.
 	void create_directory(const char* path);
 

+ 12 - 47
engine/compilers/sound/OggDecoder.h → engine/os/android/Config.h

@@ -24,50 +24,15 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
 */
 
-#pragma once
-
-#include <iostream>
-#include <fstream>
-#include <ogg/ogg.h>
-#include <vorbis/codec.h>
-#include <map>
-#include <cassert>
-#include <stdint.h>
-
-using namespace std;
-
-namespace crown
-{
-
-//-----------------------------------------------------------------------------
-struct OggStream
-{
-	int					m_serial;
-	int					m_num_packet;
-	ogg_stream_state 	m_state;
-
-	inline OggStream(int serial = -1) : m_serial(serial), m_num_packet(0) {}
-
-	inline ~OggStream() { int ret = ogg_stream_clear(&m_state);	//CE_ASSERT(ret == 0, "Cannot clear OGG stream");	}
-};
-
-//-----------------------------------------------------------------------------
-typedef map<int, OggStream*> StreamMap;
-
-//-----------------------------------------------------------------------------
-class OggDecoder
-{
-public:
-
-					OggDecoder();
-					~OggDecoder();
-
-	bool 			read_page(istream& file, ogg_sync_state* state, ogg_page* page);
-
-	void 			play(istream& file);
-
-public:
-	StreamMap		m_streams;
-};
-
-} // namespace crown
+#define CROWN_VERSION_MAJOR 0 
+#define CROWN_VERSION_MINOR 1 
+#define CROWN_VERSION_MICRO 11 
+
+#define ANDROID
+
+#ifdef ANDROID
+	#define PRId64 "lld"
+	#define PRIu64 "llu"
+	#define PRIi64 "lli"
+	#define PRIx64 "llx"
+#endif

+ 4 - 1
engine/resource/FileBundle.cpp

@@ -25,6 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 */
 
 #include <stdio.h>
+#include <inttypes.h>
 
 #include "Allocator.h"
 #include "Bundle.h"
@@ -62,7 +63,7 @@ public:
 	{
 		// Convert name/type into strings
 		char resource_name[512];
-		snprintf(resource_name, 512, "%.8X%.8X", name.name, name.type);
+		snprintf(resource_name, 512, "%"PRIx64"", name.id);
 		
 		// Search the resource in the filesystem
 		// bool exists = m_filesystem.exists(resource_name);
@@ -71,6 +72,8 @@ public:
 		// Open the resource and check magic number/version
 		File* file = m_filesystem.open(resource_name, FOM_READ);
 
+		CE_ASSERT(file != NULL, "Resource %s does not exist", resource_name);
+
 		ResourceHeader header;
 		file->read(&header, sizeof(ResourceHeader));
 

+ 2 - 1
engine/resource/LuaResource.h

@@ -53,13 +53,14 @@ public:
 	static void* load(Allocator& allocator, Bundle& bundle, ResourceId id)
 	{
 		File* file = bundle.open(id);
-		CE_ASSERT(file != NULL, "Resource does not exist: %.8X%.8X", id.name, id.type);
 
 		const size_t file_size = file->size() - 12;
 		LuaResource* res = (LuaResource*) allocator.allocate(sizeof(LuaResource));
 		res->m_data = (uint8_t*) allocator.allocate(file_size);
 		file->read(res->m_data, file_size);
 
+		bundle.close(file);
+
 		return res;
 	}
 

+ 0 - 2
engine/resource/MeshResource.h

@@ -56,8 +56,6 @@ public:
 	{
 		File* file = bundle.open(id);
 
-		CE_ASSERT(file != NULL, "Resource does not exist: %.8X%.8X", id.name, id.type);
-
 		MeshResource* resource = (MeshResource*)allocator.allocate(sizeof(MeshResource));
 		file->read(&resource->m_header, sizeof(MeshHeader));
 

+ 11 - 9
engine/resource/Resource.h

@@ -34,29 +34,31 @@ namespace crown
 {
 
 /// Hashed values for supported resource types
-const char* const TEXTURE_EXTENSION			= "tga";
-const char* const MESH_EXTENSION			= "dae";
+const char* const TEXTURE_EXTENSION			= "texture";
+const char* const MESH_EXTENSION			= "mesh";
 const char* const LUA_EXTENSION				= "lua";
-const char* const TEXT_EXTENSION			= "txt";
+const char* const TEXT_EXTENSION			= "text";
 const char* const MATERIAL_EXTENSION		= "material";
 const char* const SOUND_EXTENSION			= "sound";
+const char* const CONFIG_EXTENSION			= "config";
 
-const uint32_t TEXTURE_TYPE					= 0x1410A16A;
-const uint32_t MESH_TYPE					= 0xE8239EEC;
+const uint32_t TEXTURE_TYPE					= 0xDEED4F7;
+const uint32_t MESH_TYPE					= 0xA6E48B29;
 const uint32_t LUA_TYPE						= 0xD96E7C37;
-const uint32_t TEXT_TYPE					= 0x9000BF0B;
+const uint32_t TEXT_TYPE					= 0x45CC650;
 const uint32_t MATERIAL_TYPE				= 0x46807A92;
 const uint32_t SOUND_TYPE					= 0xD196AB6E;
+const uint32_t CONFIG_TYPE					= 0x17DEA5E1;
+
 
 /// ResourceId uniquely identifies a resource by its name and type.
 /// In order to speed up the lookup by the manager, it also keeps
 /// the index to the resource list where it is stored.
 struct ResourceId
 {
-	bool operator==(const ResourceId& b) const { return name == b.name && type == b.type; }
+	bool operator==(const ResourceId& b) const { return id == b.id; }
 
-	uint32_t		name;
-	uint32_t		type;
+	uint64_t id;
 };
 
 class Allocator;

+ 3 - 2
engine/resource/ResourceLoader.cpp

@@ -47,7 +47,7 @@ ResourceLoader::ResourceLoader(Bundle& bundle, Allocator& resource_heap) :
 }
 
 //-----------------------------------------------------------------------------
-LoadResourceId ResourceLoader::load_resource(ResourceId resource)
+LoadResourceId ResourceLoader::load_resource(uint32_t type, ResourceId resource)
 {
 
 	m_requests_mutex.lock();
@@ -55,6 +55,7 @@ LoadResourceId ResourceLoader::load_resource(ResourceId resource)
 	LoadResourceId lr_id = m_num_requests++;
 	LoadResource lr;
 	lr.id = lr_id;
+	lr.type = type;
 	lr.resource = resource;
 
 	m_requests.push_back(lr);
@@ -108,7 +109,7 @@ int32_t ResourceLoader::run()
 
 		m_results[request.id % MAX_LOAD_REQUESTS].status = LRS_LOADING;
 
-		void* data = resource_on_load(request.resource.type, m_resource_heap, m_bundle, request.resource);
+		void* data = resource_on_load(request.type, m_resource_heap, m_bundle, request.resource);
 
 		m_results[request.id % MAX_LOAD_REQUESTS].data = data;
 		m_results[request.id % MAX_LOAD_REQUESTS].status = LRS_LOADED;

+ 2 - 1
engine/resource/ResourceLoader.h

@@ -54,6 +54,7 @@ enum LoadResourceStatus
 struct LoadResource
 {
 	LoadResourceId id;
+	uint32_t type;
 	ResourceId resource;
 };
 
@@ -73,7 +74,7 @@ public:
 							ResourceLoader(Bundle& bundle, Allocator& resource_heap);
 
 	/// Loads the @a resource in a background thread.
-	LoadResourceId			load_resource(ResourceId resource);
+	LoadResourceId			load_resource(uint32_t type, ResourceId resource);
 
 	/// Returns the status of the given load request @a id.
 	LoadResourceStatus		load_resource_status(LoadResourceId id) const;

+ 22 - 16
engine/resource/ResourceManager.cpp

@@ -25,13 +25,14 @@ OTHER DEALINGS IN THE SOFTWARE.
 */
 
 #include <algorithm>
-
+#include <inttypes.h>
 #include "Types.h"
 #include "ResourceManager.h"
 #include "ResourceRegistry.h"
 #include "StringUtils.h"
 #include "Hash.h"
 #include "TempAllocator.h"
+#include "DynamicString.h"
 
 namespace crown
 {
@@ -56,14 +57,13 @@ ResourceManager::~ResourceManager()
 //-----------------------------------------------------------------------------
 ResourceId ResourceManager::load(const char* type, const char* name)
 {
-
-	return load(resource_id(type, name));
+	return load(hash::murmur2_32(type, string::strlen(type), 0), resource_id(type, name));
 }
 
 //-----------------------------------------------------------------------------
 void ResourceManager::unload(ResourceId name)
 {
-	CE_ASSERT(has(name), "Resource not loaded: %.8X%.8X", name.name, name.type);
+	CE_ASSERT(has(name), "Resource not loaded:" "%"PRIx64"", name.id);
 
 	ResourceEntry* entry = find(name);
 
@@ -71,7 +71,7 @@ void ResourceManager::unload(ResourceId name)
 	
 	if (entry->references == 0)
 	{
-		resource_on_unload(name.type, m_resource_heap, entry->resource);
+		resource_on_unload(entry->type, m_resource_heap, entry->resource);
 		entry->resource = NULL;
 	}
 }
@@ -87,7 +87,7 @@ bool ResourceManager::has(ResourceId name) const
 //-----------------------------------------------------------------------------
 const void* ResourceManager::data(ResourceId name) const
 {
-	CE_ASSERT(has(name), "Resource not loaded: %.8X%.8X", name.name, name.type);
+	CE_ASSERT(has(name), "Resource not loaded:" "%"PRIx64"", name.id);
 
 	return find(name)->resource;
 }
@@ -95,7 +95,7 @@ const void* ResourceManager::data(ResourceId name) const
 //-----------------------------------------------------------------------------
 bool ResourceManager::is_loaded(ResourceId name) const
 {
-	CE_ASSERT(has(name), "Resource not loaded: %.8X%.8X", name.name, name.type);
+	CE_ASSERT(has(name), "Resource not loaded:" "%"PRIx64"", name.id);
 
 	return find(name)->resource != NULL;
 }
@@ -103,7 +103,7 @@ bool ResourceManager::is_loaded(ResourceId name) const
 //-----------------------------------------------------------------------------
 uint32_t ResourceManager::references(ResourceId name) const
 {
-	CE_ASSERT(has(name), "Resource not loaded: %.8X%.8X", name.name, name.type);
+	CE_ASSERT(has(name), "Resource not loaded:" "%"PRIx64"", name.id);
 
 	return find(name)->references;
 }
@@ -126,11 +126,16 @@ uint32_t ResourceManager::seed() const
 //-----------------------------------------------------------------------------
 ResourceId ResourceManager::resource_id(const char* type, const char* name) const
 {
-	ResourceId id;
-	id.type = hash::murmur2_32(type, string::strlen(type), 0);
-	id.name = hash::murmur2_32(name, string::strlen(name), m_seed);
+	TempAllocator256 alloc;
+	DynamicString res_name(alloc);
+	res_name += name;
+	res_name += '.';
+	res_name += type;
+
+	ResourceId res_id;
+	res_id.id = hash::murmur2_64(res_name.c_str(), string::strlen(res_name.c_str()), m_seed);
 
-	return id;
+	return res_id;
 }
 
 //-----------------------------------------------------------------------------
@@ -159,7 +164,7 @@ void ResourceManager::poll_resource_loader()
 }
 
 //-----------------------------------------------------------------------------
-ResourceId ResourceManager::load(ResourceId name)
+ResourceId ResourceManager::load(uint32_t type, ResourceId name)
 {
 	// Search for an already existent resource
 	ResourceEntry* entry = find(name);
@@ -170,6 +175,7 @@ ResourceId ResourceManager::load(ResourceId name)
 		ResourceEntry entry;
 
 		entry.id = name;
+		entry.type = type;
 		entry.references = 1;
 		entry.resource = NULL;
 
@@ -178,7 +184,7 @@ ResourceId ResourceManager::load(ResourceId name)
 		// Issue request to resource loader
 		PendingRequest pr;
 		pr.resource = name;
-		pr.id = m_loader.load_resource(name);
+		pr.id = m_loader.load_resource(type, name);
 
 		m_pendings.push_back(pr);
 
@@ -194,9 +200,9 @@ ResourceId ResourceManager::load(ResourceId name)
 //-----------------------------------------------------------------------------
 void ResourceManager::online(ResourceId name, void* resource)
 {
-	resource_on_online(name.type, resource);
-
 	ResourceEntry* entry = find(name);
+	resource_on_online(entry->type, resource);
+
 	entry->resource = resource;
 }
 

+ 4 - 2
engine/resource/ResourceManager.h

@@ -41,14 +41,16 @@ struct ResourceEntry
 	bool operator==(const ResourceEntry& b) const { return id == b.id; }
 
 	ResourceId		id;
+	uint32_t		type;
 	uint32_t		references;
 	void*			resource;
 };
 
 struct PendingRequest
 {
-	ResourceId resource;
 	LoadResourceId id;
+	ResourceId resource;
+	uint32_t type;
 };
 
 class Bundle;
@@ -106,7 +108,7 @@ private:
 	void					poll_resource_loader();
 
 	// Loads the resource by name and type and returns its ResourceId.
-	ResourceId				load(ResourceId name);
+	ResourceId				load(uint32_t type, ResourceId name);
 	void					online(ResourceId name, void* resource);
 
 private:

+ 0 - 2
engine/resource/SoundResource.h

@@ -65,8 +65,6 @@ public:
 	{
 		File* file = bundle.open(id);
 
-		CE_ASSERT(file != NULL, "Resource does not exist: %.8X%.8X", id.name, id.type);
-
 		SoundResource* resource = (SoundResource*)allocator.allocate(sizeof(SoundResource));
 
 		file->read(&resource->m_header, sizeof(SoundHeader));

+ 0 - 2
engine/resource/TextureResource.h

@@ -57,8 +57,6 @@ public:
 	{
 		File* file = bundle.open(id);
 
-		CE_ASSERT(file != NULL, "Resource does not exist: %.8X%.8X", id.name, id.type);
-
 		TextureResource* resource = (TextureResource*)allocator.allocate(sizeof(TextureResource));
 
 		file->read(&resource->m_header, sizeof(TextureHeader));

+ 6 - 4
engine/tests/CMakeLists.txt

@@ -9,20 +9,22 @@ add_executable(containers containers.cpp)
 add_executable(compressors compressors.cpp)
 add_executable(strings strings.cpp)
 add_executable(paths paths.cpp)
-add_executable(dynamic_strings dynamic_strings.cpp)
+add_executable(dynamic-strings dynamic-strings.cpp)
+add_executable(json json.cpp)
 
 target_link_libraries(allocators crown)
 target_link_libraries(containers crown)
 target_link_libraries(compressors crown)
 target_link_libraries(strings crown)
 target_link_libraries(paths crown)
-target_link_libraries(dynamic_strings crown)
+target_link_libraries(dynamic-strings crown)
+target_link_libraries(json crown)
 
 add_test(allocators-test ${EXECUTABLE_OUTPUT_PATH}/allocators)
 add_test(containers-test ${EXECUTABLE_OUTPUT_PATH}/containers)
 add_test(compressors-test ${EXECUTABLE_OUTPUT_PATH}/compressors)
 add_test(strings-test ${EXECUTABLE_OUTPUT_PATH}/strings)
 add_test(paths-test ${EXECUTABLE_OUTPUT_PATH}/paths)
-add_test(dynamic_string-test ${EXECUTABLE_OUTPUT_PATH}/dynamic_string)
-
+add_test(dynamic-string-test ${EXECUTABLE_OUTPUT_PATH}/dynamic-strings)
+add_test(json-test ${EXECUTABLE_OUTPUT_PATH}/json)
 

+ 0 - 0
engine/tests/dynamic_strings.cpp → engine/tests/dynamic-strings.cpp


+ 42 - 0
engine/tests/json.cpp

@@ -0,0 +1,42 @@
+#include "Crown.h"
+
+using namespace crown;
+
+int main()
+{
+	const char* json_string = 	"{"
+    							"\"glossary\": { "
+        						"	\"title\": \"example glossary\", "
+								"	\"GlossDiv\": { "
+            					"		\"title\": \"S\", "
+								"		\"GlossList\": { "
+                				"			\"GlossEntry\": { "
+                    			"				\"ID\": \"SGML\", "
+								"				\"SortAs\": \"SGML\", "
+								"				\"GlossTerm\": \"Standard Generalized Markup Language\", "
+								"				\"Acronym\": \"SGML\", "
+								"				\"Abbrev\": \"ISO 8879:1986\", "
+								"				\"GlossDef\": { "
+                        		"					\"para\": \"A meta-markup language, used to create markup languages such as DocBook.\", "
+								"					\"GlossSeeAlso\": [\"GML\", \"XML\"] "
+                    			"				  }, "
+								"				\"GlossSee\": \"markup\" "
+                				"			 } "
+            					"		  } "
+        						"	   } "
+    							"  } "
+    							"}";
+
+    JSONParser parser(json_string);
+
+    JSONElement root = parser.root();
+
+    CE_ASSERT(root.has_key("glossary"), "'glossary' not found!");
+
+    Log::i("%s", root.key("glossary").key("GlossDiv").key("title").string_value());
+    Log::i("%s", root.key("glossary").key("title").string_value());
+    Log::i("%s", root.key("glossary").key("GlossDiv").key("GlossList").key("GlossEntry").key("GlossTerm").string_value());
+
+
+	return 0;
+}

+ 36 - 5
utils/crown-android.rb

@@ -1,4 +1,26 @@
-#!/usr/bin/ruby
+# Copyright (c) 2013 Daniele Bartolini, Michele Rossi
+# 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.
 
 require 'optparse'
 require 'ostruct'
@@ -11,6 +33,7 @@ $package			= "crown.android"
 
 $engine_src 		= "../engine/."
 $android_src		= "../engine/os/android/*.java"
+$config_src			= "../engine/os/android/Config.h"
 $manifest			= "../engine/os/android/AndroidManifest.xml"
 
 $luajit				= "../engine/third/ARMv7/luajit"
@@ -118,6 +141,10 @@ def fill_android_project(path)
 	FileUtils.cp_r($engine_src, engine_dest, :remove_destination => true)
 	print "Copied Engine to " + engine_dest + "\n"
 
+	# Copy android Config.h
+	FileUtils.cp($config_src, engine_dest)
+	print "Copied Config.h to " + engine_dest + "\n"
+
 	# Copy luajit dir
 	FileUtils.cp_r($luajit, engine_dest, :remove_destination => true)
 	print "Copied luajit dir to " + engine_dest + "\n"
@@ -139,12 +166,16 @@ end
 def build_android_project(path)
 	# Move to root directory of Android project
 	Dir.chdir(path)
-
 	# Build libraries
-	system("ndk-build")
-
+	if not system("ndk-build")
+		print "Critical error: Unable to build crown libraries"
+		return
+	end
 	# Build apk
-	system("ant debug")
+	if not system("ant debug")
+		print "Critical error: Unable to build crown project"
+		return
+	end
 end
 
 #------------------------------------------------------------------------------

+ 80 - 0
utils/murmur2-32-hash.rb

@@ -0,0 +1,80 @@
+# Copyright (c) 2013 Daniele Bartolini, Michele Rossi
+# 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.
+
+# MurmurHash2, by Austin Appleby
+def murmur2_32(string, seed)
+
+    m = 0x5bd1e995
+    r = 24
+    len = string.length
+
+    h = seed ^ len
+
+    data = string.bytes.to_a
+
+    while len >= 4
+      	k = data[0]
+      	k |= data[1] << 8
+      	k |= data[2] << 16
+      	k |= data[3] << 24
+
+      	k = ( k * m ) % 0x100000000
+      	k ^= k >> r
+      	k = ( k * m ) % 0x100000000
+
+      	h = ( h * m ) % 0x100000000
+      	h ^= k
+
+      	len -= 4
+    end
+
+    if len == 3 then
+      h ^= data[-1] << 16
+      h ^= data[-2] << 8
+      h ^= data[-3]
+    end
+    if len == 2 then
+      h ^= data[-1] << 8
+      h ^= data[-2]
+    end
+    if len == 1 then
+      h ^= data[-1]
+    end
+
+    h = ( h * m ) % 0x100000000
+    h ^= h >> 13
+    h = ( h * m ) % 0x100000000
+    h ^= h >> 15
+
+    return h
+end
+
+if ARGV.length != 2
+	print "Usage: ruby murmur2-hash.rb <string> <seed>\n"
+	exit
+end
+
+result = murmur2_32(ARGV[0], ARGV[1].to_i)
+
+print result.to_s(16) + "\n";