Przeglądaj źródła

Merge branch 'master' into renderer-evo

Daniele Bartolini 12 lat temu
rodzic
commit
9d3413cede
100 zmienionych plików z 4324 dodań i 2176 usunięć
  1. 21 5
      BUILD.txt
  2. 55 11
      CMakeLists.txt
  3. 5 13
      engine/Android.mk
  4. 68 43
      engine/CMakeLists.txt
  5. 2 0
      engine/Config.h.in
  6. 1 2
      engine/Crown.h
  7. 200 160
      engine/Device.cpp
  8. 20 20
      engine/Device.h
  9. 157 0
      engine/compilers/BundleCompiler.cpp
  10. 24 12
      engine/compilers/BundleCompiler.h
  11. 13 17
      engine/compilers/Compiler.cpp
  12. 5 5
      engine/compilers/Compiler.h
  13. 0 0
      engine/compilers/dae/DAECompiler.cpp
  14. 34 0
      engine/compilers/dae/DAECompiler.h
  15. 0 0
      engine/compilers/dae/tinyxml2.cpp
  16. 0 0
      engine/compilers/dae/tinyxml2.h
  17. 55 36
      engine/compilers/lua/LuaCompiler.cpp
  18. 8 8
      engine/compilers/lua/LuaCompiler.h
  19. 132 0
      engine/compilers/package/PackageCompiler.cpp
  20. 17 14
      engine/compilers/package/PackageCompiler.h
  21. 36 38
      engine/compilers/texture/TextureCompiler.cpp
  22. 8 8
      engine/compilers/texture/TextureCompiler.h
  23. 1 1
      engine/core/Assert.h
  24. 16 24
      engine/core/containers/List.h
  25. 426 0
      engine/core/containers/Vector.h
  26. 66 10
      engine/core/filesystem/BinaryReader.h
  27. 50 10
      engine/core/filesystem/BinaryWriter.h
  28. 2 2
      engine/core/filesystem/DiskFile.cpp
  29. 168 0
      engine/core/filesystem/DiskFilesystem.cpp
  30. 91 0
      engine/core/filesystem/DiskFilesystem.h
  31. 0 205
      engine/core/filesystem/Filesystem.cpp
  32. 26 67
      engine/core/filesystem/Filesystem.h
  33. 0 64
      engine/core/filesystem/TextReader.cpp
  34. 27 3
      engine/core/filesystem/TextReader.h
  35. 10 4
      engine/core/filesystem/TextWriter.h
  36. 52 20
      engine/core/json/JSONParser.cpp
  37. 9 5
      engine/core/json/JSONParser.h
  38. 17 18
      engine/core/mem/Memory.h
  39. 229 0
      engine/core/strings/DynamicString.h
  40. 56 1
      engine/core/strings/Hash.h
  41. 1 0
      engine/core/strings/StringStream.h
  42. 7 12
      engine/core/strings/StringUtils.h
  43. 29 4
      engine/lua/LuaDevice.cpp
  44. 104 129
      engine/lua/LuaEnvironment.cpp
  45. 21 41
      engine/lua/LuaEnvironment.h
  46. 32 32
      engine/lua/LuaResourcePackage.cpp
  47. 48 150
      engine/lua/LuaStack.cpp
  48. 104 43
      engine/lua/LuaStack.h
  49. 58 15
      engine/os/OS.h
  50. 7 7
      engine/os/android/AndroidDevice.cpp
  51. 82 10
      engine/os/android/AndroidOS.cpp
  52. 57 48
      engine/os/android/ApkFile.cpp
  53. 44 39
      engine/os/android/ApkFile.h
  54. 53 35
      engine/os/android/ApkFilesystem.cpp
  55. 78 0
      engine/os/android/ApkFilesystem.h
  56. 12 18
      engine/os/android/Config.h
  57. 1 1
      engine/os/android/CrownActivity.java
  58. 0 89
      engine/os/android/OsFile2.h
  59. 11 11
      engine/os/android/OsWindow.cpp
  60. 20 0
      engine/os/android/OsWindow.h
  61. 89 38
      engine/os/linux/LinuxOS.cpp
  62. 51 5
      engine/os/win/Thread.cpp
  63. 19 2
      engine/os/win/Thread.h
  64. 95 14
      engine/os/win/WinOS.cpp
  65. 305 0
      engine/os/win/inttypes.h
  66. 1 1
      engine/renderers/gl/GLRenderer.cpp
  67. 99 56
      engine/resource/ArchiveBundle.cpp
  68. 7 4
      engine/resource/Bundle.h
  69. 58 28
      engine/resource/FileBundle.cpp
  70. 0 71
      engine/resource/FileBundle.h
  71. 0 57
      engine/resource/FontResource.cpp
  72. 23 7
      engine/resource/FontResource.h
  73. 98 0
      engine/resource/LuaResource.h
  74. 0 60
      engine/resource/MaterialResource.cpp
  75. 26 6
      engine/resource/MaterialResource.h
  76. 0 80
      engine/resource/MeshResource.cpp
  77. 40 7
      engine/resource/MeshResource.h
  78. 122 0
      engine/resource/PackageResource.h
  79. 16 13
      engine/resource/Resource.h
  80. 0 0
      engine/resource/ResourceFormat.h
  81. 4 2
      engine/resource/ResourceLoader.cpp
  82. 3 1
      engine/resource/ResourceLoader.h
  83. 22 15
      engine/resource/ResourceManager.cpp
  84. 5 2
      engine/resource/ResourceManager.h
  85. 107 0
      engine/resource/ResourcePackage.h
  86. 4 0
      engine/resource/ResourceRegistry.cpp
  87. 0 81
      engine/resource/SoundResource.cpp
  88. 42 7
      engine/resource/SoundResource.h
  89. 0 82
      engine/resource/TextureResource.cpp
  90. 62 11
      engine/resource/TextureResource.h
  91. 6 0
      engine/tests/CMakeLists.txt
  92. 3 3
      engine/tests/allocators.cpp
  93. 3 3
      engine/tests/compressors.cpp
  94. 81 0
      engine/tests/dynamic-strings.cpp
  95. 42 0
      engine/tests/json.cpp
  96. 2 2
      engine/third/win32/CMakeLists.txt
  97. 2 2
      engine/third/win64/CMakeLists.txt
  98. 3 3
      engine/third/x86/CMakeLists.txt
  99. 3 3
      engine/third/x86_64/CMakeLists.txt
  100. 5 0
      samples/01.hello-world/crown.config

+ 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

+ 55 - 11
CMakeLists.txt

@@ -4,30 +4,74 @@ 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)
 option (CROWN_BUILD_TESTS "Whether to build unit tests" ON)
 
-# always debug mode for now
-set (CROWN_DEBUG 1)
-
-# detect operating system
-if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+# build configuration variables
+if (CROWN_BUILD MATCHES "linux-debug-32")
+	set (LINUX 1)
+	set (CROWN_DEBUG 1)
+	set (CROWN_ARCH "x86")
+elseif (CROWN_BUILD MATCHES "linux-development-32")
+	set (LINUX 1)
+	set (CROWN_DEVELOPMENT 1)
+	set (CROWN_ARCH "x86")
+elseif (CROWN_BUILD MATCHES "linux-release-32")
+	set (LINUX 1)
+	set (CROWN_RELEASE 1)
+	set (CROWN_ARCH "x86")
+elseif (CROWN_BUILD MATCHES "linux-debug-64")
+	set (LINUX 1)
+	set (CROWN_DEBUG 1)
+	set (CROWN_ARCH "x86_64")
+elseif (CROWN_BUILD MATCHES "linux-development-64")
+	set (LINUX 1)
+	set (CROWN_DEVELOPMENT 1)
+	set (CROWN_ARCH "x86_64")
+elseif (CROWN_BUILD MATCHES "linux-release-64")
 	set (LINUX 1)
-endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+	set (CROWN_RELEASE 1)
+	set (CROWN_ARCH "x86_64")
+elseif (CROWN_BUILD MATCHES "windows-debug-32")
+	set (WINDOWS 1)
+	set (CROWN_DEBUG 1)
+	set (CROWN_ARCH "win32")
+elseif (CROWN_BUILD MATCHES "windows-development-32")
+	set (WINDOWS 1)
+	set (CROWN_DEVELOPMENT 1)
+	set (CROWN_ARCH "win32")
+elseif (CROWN_BUILD MATCHES "windows-release-32")
+	set (WINDOWS 1)
+	set (CROWN_RELEASE 1)
+	set (CROWN_ARCH "win32")
+elseif (CROWN_BUILD MATCHES "windows-debug-64")
+	set (WINDOWS 1)
+	set (CROWN_DEBUG 1)
+	set (CROWN_ARCH "win64")
+elseif (CROWN_BUILD MATCHES "windows-development-64")
+	set (WINDOWS 1)
+	set (CROWN_DEVELOPMENT 1)
+	set (CROWN_ARCH "win64")
+elseif (CROWN_BUILD MATCHES "windows-release-64")
+	set (WINDOWS 1)
+	set (CROWN_RELEASE 1)
+	set (CROWN_ARCH "win64")
+else ()
+	message (FATAL_ERROR "Wrong build configuration")
+endif (CROWN_BUILD MATCHES "linux-debug-32")
 
-if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
-	set(WINDOWS 1)
-endif (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
+# executable name
+set (CROWN_EXECUTABLE_NAME crown-${CROWN_BUILD})
 
 # always build the engine
 add_subdirectory(engine)
 
 # select optional projects to build
 if (CROWN_BUILD_TOOLS)
-	add_subdirectory(tools)
+	#add_subdirectory(tools)
 endif (CROWN_BUILD_TOOLS)
 
 if (CROWN_BUILD_SAMPLES)

+ 5 - 13
engine/Android.mk

@@ -24,13 +24,9 @@ LOCAL_SRC_FILES :=\
 	core/compressors/ZipCompressor.cpp\
 	core/containers/Generic.cpp\
 \
-	core/filesystem/BinaryReader.cpp\
-	core/filesystem/BinaryWriter.cpp\
-	core/filesystem/DiskFile.cpp\
 	core/filesystem/File.cpp\
-	core/filesystem/Filesystem.cpp\
-	core/filesystem/TextReader.cpp\
-	core/filesystem/TextWriter.cpp\
+	core/filesystem/DiskFile.cpp\
+	core/filesystem/DiskFilesystem.cpp\
 \
 	core/json/JSONParser.cpp\
 \
@@ -70,6 +66,8 @@ LOCAL_SRC_FILES :=\
 	os/android/AndroidOS.cpp\
 	os/android/AndroidDevice.cpp\
 	os/android/OsWindow.cpp\
+	os/android/ApkFile.cpp\
+	os/android/ApkFilesystem.cpp\
 	os/posix/OsFile.cpp\
 	os/posix/Thread.cpp\
 	os/posix/Mutex.cpp\
@@ -84,21 +82,14 @@ LOCAL_SRC_FILES :=\
 	renderers/PixelFormat.cpp\
 	renderers/VertexFormat.cpp\
 \
-	resource/ArchiveBundle.cpp\
 	resource/FileBundle.cpp\
-	resource/FontResource.cpp\
-	resource/MaterialResource.cpp\
-	resource/MeshResource.cpp\
 	resource/ResourceLoader.cpp\
 	resource/ResourceManager.cpp\
 	resource/ResourceRegistry.cpp\
-	resource/TextureResource.cpp\
-	resource/SoundResource.cpp\
 \
 	lua/LuaStack.cpp\
 	lua/LuaEnvironment.cpp\
 	lua/LuaAccelerometer.cpp\
-	lua/LuaCamera.cpp\
 	lua/LuaDevice.cpp\
 	lua/LuaKeyboard.cpp\
 	lua/LuaMat4.cpp\
@@ -112,6 +103,7 @@ LOCAL_SRC_FILES :=\
 	lua/LuaIntSetting.cpp\
 	lua/LuaFloatSetting.cpp\
 	lua/LuaStringSetting.cpp\
+	lua/LuaResourcePackage.cpp\
 \
 	Camera.cpp\
 	Device.cpp\

+ 68 - 43
engine/CMakeLists.txt

@@ -56,6 +56,11 @@ set (CROWN_INCLUDES
 	${CMAKE_SOURCE_DIR}/engine/resource
 	${CMAKE_SOURCE_DIR}/engine/network
 	${CMAKE_SOURCE_DIR}/engine/lua
+	${CMAKE_SOURCE_DIR}/engine/compilers
+	${CMAKE_SOURCE_DIR}/engine/compilers/lua
+	${CMAKE_SOURCE_DIR}/engine/compilers/texture
+	${CMAKE_SOURCE_DIR}/engine/compilers/mesh
+	${CMAKE_SOURCE_DIR}/engine/compilers/package
 )
 
 set (SRC
@@ -110,6 +115,7 @@ set (CONTAINERS_HEADERS
 	core/containers/Map.h
 	core/containers/Generic.h
 	core/containers/List.h
+	core/containers/Vector.h
 	core/containers/RBTree.h
 	core/containers/IdTable.h
 )
@@ -145,28 +151,21 @@ set (MATH_HEADERS
 )
 
 set (FILESYSTEM_SRC
-	core/filesystem/DiskFile.cpp
 	core/filesystem/File.cpp
-	
-	core/filesystem/BinaryReader.cpp
-	core/filesystem/BinaryWriter.cpp
-	core/filesystem/TextReader.cpp
-	core/filesystem/TextWriter.cpp
-
-	core/filesystem/Filesystem.cpp
+	core/filesystem/DiskFile.cpp
+	core/filesystem/DiskFilesystem.cpp
 )
 
 set (FILESYSTEM_HEADERS
-	core/filesystem/DiskFile.h
-	core/filesystem/NullFile.h
 	core/filesystem/File.h
-
+	core/filesystem/NullFile.h
+	core/filesystem/DiskFile.h
 	core/filesystem/BinaryReader.h
 	core/filesystem/BinaryWriter.h
 	core/filesystem/TextReader.h
 	core/filesystem/TextWriter.h
-
 	core/filesystem/Filesystem.h
+	core/filesystem/DiskFilesystem.h
 )
 
 set (JSON_SRC
@@ -185,6 +184,7 @@ set (STRINGS_HEADERS
 	core/strings/StringUtils.h
 	core/strings/StringStream.h
 	core/strings/Hash.h
+	core/strings/DynamicString.h
 )
 
 set (MEM_SRC
@@ -267,31 +267,34 @@ set (RENDERERS_HEADERS
 )
 
 set (RESOURCE_SRC
-	resource/MaterialResource.cpp
 	resource/ResourceLoader.cpp
 	resource/ResourceManager.cpp
 	resource/ResourceRegistry.cpp
-	resource/TextureResource.cpp
-	resource/MeshResource.cpp
-	resource/FontResource.cpp
-	resource/SoundResource.cpp
-	resource/ArchiveBundle.cpp
-	resource/FileBundle.cpp
 )
 
+if (CROWN_DEBUG OR CROWN_DEVELOPMENT)
+	list (APPEND RESOURCE_SRC resource/FileBundle.cpp)
+elseif (CROWN_RELEASE)
+	list (APPEND RESOURCE_SRC resource/ArchiveBundle.cpp)
+else ()
+	message (FATAL_ERROR "Oops, you should not be here")
+endif (CROWN_DEBUG OR CROWN_DEVELOPMENT)
+
 set (RESOURCE_HEADERS
-	resource/MaterialResource.h
 	resource/Resource.h
+	resource/ResourceFormat.h
 	resource/ResourceLoader.h
 	resource/ResourceManager.h
 	resource/ResourceRegistry.h
 	resource/Bundle.h
+	resource/LuaResource.h
 	resource/TextureResource.h
 	resource/MeshResource.h
 	resource/FontResource.h
 	resource/SoundResource.h
-	resource/ArchiveBundle.h
-	resource/FileBundle.h
+	resource/MaterialResource.h
+	resource/PackageResource.h
+	resource/ResourcePackage.h
 )
 
 set (OS_SRC
@@ -303,7 +306,7 @@ set (OS_HEADERS
 	os/NetAddress.h
 )
 
-set(LUA_SRC
+set (LUA_SRC
 	lua/LuaStack.cpp
 	lua/LuaEnvironment.cpp
 	lua/LuaIntSetting.cpp
@@ -319,13 +322,30 @@ set(LUA_SRC
 	lua/LuaAccelerometer.cpp
 	lua/LuaDevice.cpp
 	lua/LuaWindow.cpp
+	lua/LuaResourcePackage.cpp
 )
 
-set(LUA_HEADERS
+set (LUA_HEADERS
 	lua/LuaStack.h
 	lua/LuaEnvironment.h
 )
 
+set (COMPILER_SRC
+	compilers/Compiler.cpp
+	compilers/BundleCompiler.cpp
+	compilers/lua/LuaCompiler.cpp
+	compilers/texture/TextureCompiler.cpp
+	compilers/package/PackageCompiler.cpp
+)
+
+set (COMPILER_HEADER
+	compilers/Compiler.h
+	compilers/BundleCompiler.h
+	compilers/lua/LuaCompiler.h
+	compilers/texture/TextureCompiler.h
+	compilers/package/PackageCompiler.h
+)
+
 set (CROWN_LIBRARIES)
 
 # Platform specific stuff
@@ -390,13 +410,27 @@ if (LINUX)
 		-Werror
 		-Wno-long-long
 		-Wno-variadic-macros
-		-g
-		-pg
 		-fPIC
 		#-fvisibility=hidden
 	)
 
-	set (CROWN_EXECUTABLE_NAME crown-linux)
+	if (CROWN_DEBUG)
+		list (APPEND COMPILER_FLAGS -g -pg)
+	elseif (CROWN_DEVELOPMENT)
+		list (APPEND COMPILER_FLAGS -O2)
+	elseif (CROWN_RELEASE)
+		list (APPEND COMPILER_FLAGS
+			-O2
+			-Wno-unused-variable
+			-Wno-unused-parameter
+			-Wno-maybe-uninitialized
+			-Wno-unused-but-set-variable
+			-Wno-unused-function
+		)
+	else ()
+		message (FATAL_ERROR "Oops, you should not be here")
+	endif (CROWN_DEBUG)
+
 	set (CROWN_MAIN_SRC os/linux/main.cpp)
 endif (LINUX)
 
@@ -412,6 +446,7 @@ if (WINDOWS)
 		os/win/Thread.h
 		os/win/Mutex.h
 		os/win/Cond.h
+		os/win/inttypes.h
 	)
 
 	list (APPEND OS_SRC
@@ -442,9 +477,10 @@ if (WINDOWS)
 		lua51
 	)
 
-	set (COMPILER_FLAGS)
-	
-	set (CROWN_EXECUTABLE_NAME crown-win)
+	set (COMPILER_FLAGS
+		/Wall
+	)
+
 	set (CROWN_MAIN_SRC os/win/main.cpp)
 endif(WINDOWS)
 
@@ -459,18 +495,13 @@ set (CROWN_SOURCES
 	${MEM_SRC}
 	${COMPRESSORS_SRC}
 	${SETTINGS_SRC}
-
 	${INPUT_SRC}
-
 	${RENDERERS_SRC}
-
 	${RESOURCE_SRC}
-
 #	${NETWORK_SRC}
-
 	${OS_SRC}
-
 	${LUA_SRC}
+	${COMPILER_SRC}
 )
 
 set (CROWN_HEADERS
@@ -484,20 +515,14 @@ set (CROWN_HEADERS
 	${MEM_HEADERS}
 	${COMPRESSORS_HEADERS}
 	${SETTINGS_HEADERS}
-
 	${INPUT_HEADERS}
-
 	${RENDERERS_HEADERS}
-
 	${RESOURCE_HEADERS}
-
 	${RPC_HEADERS}
-
 #	${NETWORK_HEADERS}
-
 	${OS_HEADERS}
-
 	${LUA_HEADERS}
+	${COMPILER_HEADERS}
 )
 
 configure_file (${CMAKE_CURRENT_SOURCE_DIR}/Config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/Config.h)

+ 2 - 0
engine/Config.h.in

@@ -32,3 +32,5 @@ OTHER DEALINGS IN THE SOFTWARE.
 #cmakedefine WINDOWS
 
 #cmakedefine CROWN_DEBUG
+#cmakedefine CROWN_DEVELOPMENT
+#cmakedefine CROWN_RELEASE

+ 1 - 2
engine/Crown.h

@@ -60,6 +60,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "Map.h"
 #include "RBTree.h"
 #include "List.h"
+#include "Vector.h"
 #include "Generic.h"
 #include "Queue.h"
 #include "PriorityQueue.h"
@@ -133,8 +134,6 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 // Engine/Resource
 #include "Bundle.h"
-#include "ArchiveBundle.h"
-#include "FileBundle.h"
 #include "ResourceLoader.h"
 #include "ResourceManager.h"
 #include "TextureResource.h"

+ 200 - 160
engine/Device.cpp

@@ -22,49 +22,60 @@ 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.
+OTHER DEALINGS IN THE SOFTWARE.
 */
 
 #include <cstdlib>
 
 #include "Config.h"
 #include "Device.h"
-#include "Filesystem.h"
+#include "Accelerometer.h"
+#include "Args.h"
+#include "ConsoleServer.h"
+#include "DebugRenderer.h"
+#include "DiskFile.h"
+#include "DiskFilesystem.h"
 #include "InputManager.h"
+#include "JSONParser.h"
+#include "Keyboard.h"
 #include "Log.h"
+#include "LuaEnvironment.h"
+#include "Memory.h"
+#include "Mouse.h"
 #include "OS.h"
+#include "OsWindow.h"
 #include "Renderer.h"
-#include "DebugRenderer.h"
-#include "Types.h"
-#include "StringUtils.h"
-#include "Args.h"
-#include "ArchiveBundle.h"
-#include "FileBundle.h"
 #include "ResourceManager.h"
-#include "TextureResource.h"
-#include "Keyboard.h"
-#include "Mouse.h"
-#include "Touch.h"
-#include "Accelerometer.h"
-#include "OsWindow.h"
-#include "JSONParser.h"
-#include "DiskFile.h"
-#include "Memory.h"
-#include "LuaEnvironment.h"
-#include "ConsoleServer.h"
+#include "StringSetting.h"
+#include "StringUtils.h"
 #include "TextReader.h"
+#include "Touch.h"
+#include "Types.h"
+#include "Bundle.h"
+#include "TempAllocator.h"
+#include "ResourcePackage.h"
+
+#if defined(LINUX) || defined(WINDOWS)
+	#include "BundleCompiler.h"
+#endif
+
+#if defined(ANDROID)
+	#include "ApkFilesystem.h"
+#endif
 
 namespace crown
 {
 
 //-----------------------------------------------------------------------------
-Device::Device() :
+Device::Device() : 
 	m_allocator(m_subsystems_heap, MAX_SUBSYSTEMS_HEAP),
 
 	m_preferred_window_width(1000),
 	m_preferred_window_height(625),
 	m_preferred_window_fullscreen(0),
 	m_parent_window_handle(0),
-	m_preferred_mode(MODE_RELEASE),
+	m_compile(0),
+	m_continue(0),
 
 	m_quit_after_init(0),
 
@@ -88,8 +99,10 @@ Device::Device() :
 
 	m_console_server(NULL)
 {
-	// Select executable dir by default
-	string::strncpy(m_preferred_root_path, os::get_cwd(), MAX_PATH_LENGTH);
+	// 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);
 }
 
 //-----------------------------------------------------------------------------
@@ -100,66 +113,121 @@ Device::~Device()
 //-----------------------------------------------------------------------------
 bool Device::init(int argc, char** argv)
 {
-	if (is_init())
-	{
-		Log::e("Crown Engine is already initialized.");
-		return false;
-	}
+	CE_ASSERT(!is_init(), "Engine already initialized");
 
 	parse_command_line(argc, argv);
 	check_preferred_settings();
 
+	// Resource compilation only in debug or development mode and only on linux or windows builds
+	#if (defined(LINUX) || defined(WINDOWS)) && (defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT))
+		if (m_compile == 1)
+		{
+			m_bundle_compiler = CE_NEW(m_allocator, BundleCompiler);
+			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);
+			}
+
+			if (!m_continue)
+			{
+				CE_DELETE(m_allocator, m_bundle_compiler);
+				m_allocator.clear();
+				exit(EXIT_SUCCESS);
+			}
+		}
+	#endif
+
 	// Initialize
 	Log::i("Initializing Crown Engine %d.%d.%d...", CROWN_VERSION_MAJOR, CROWN_VERSION_MINOR, CROWN_VERSION_MICRO);
 
-	create_filesystem();
+	// Default bundle filesystem
+	#if defined (LINUX) || defined(WINDOWS)
+		m_filesystem = CE_NEW(m_allocator, DiskFilesystem)(m_bundle_dir);
+	#elif defined(ANDROID)
+		m_filesystem = CE_NEW(m_allocator, ApkFilesystem)();
+	#endif
+	Log::d("Filesystem created.");
 
-	create_resource_manager();
+	// Read settings from crown.config
+	read_engine_settings();
 
-	create_input_manager();
+	m_resource_bundle = Bundle::create(m_allocator, *m_filesystem);
 
-	create_window();
+	// // Read resource seed
+	// DiskFile* seed_file = (DiskFile*)filesystem()->open(g_default_mountpoint.value(), "seed.ini", FOM_READ);
+	// TextReader reader(*seed_file);
 
-	create_renderer();
+	// char tmp_buf[32];
+	// reader.read_string(tmp_buf, 32);
 
-	create_debug_renderer();
+	// filesystem()->close(seed_file);
 
-	create_lua_environment();
+	// uint32_t seed = string::parse_uint(tmp_buf);
 
-	create_console_server();
+	// Create resource manager
+	m_resource_manager = CE_NEW(m_allocator, ResourceManager)(*m_resource_bundle, 0);
+	Log::d("Resource manager created.");
+	Log::d("Resource seed: %d", m_resource_manager->seed());
 
-	read_engine_settings();
+	// Create input manager
+	m_input_manager = CE_NEW(m_allocator, InputManager)();
+	Log::d("Input manager created.");
 
-	Log::i("Crown Engine initialized.");
+	m_window = CE_NEW(m_allocator, OsWindow)(m_preferred_window_width, m_preferred_window_height, m_parent_window_handle);
 
-	Log::i("Initializing Game...");
+	CE_ASSERT(m_window != NULL, "Unable to create the window");
 
-	// Initialize the game through init game function
-	m_lua_environment->game_init();
+	// Create main window
+	m_window->set_title("Crown Game Engine");
+	Log::d("Window created.");
 
-	m_is_init = true;
+	// Create renderer
+	m_renderer = Renderer::create(m_allocator);
+	m_renderer->init();
+	Log::d("Renderer created.");
 
+	// Create debug renderer
+	m_debug_renderer = CE_NEW(m_allocator, DebugRenderer)(*m_renderer);
+	Log::d("Debug renderer created.");
+
+	m_lua_environment = CE_NEW(m_allocator, LuaEnvironment)();
+	m_lua_environment->init();
+	Log::d("Lua environment created.");
+
+	Log::i("Crown Engine initialized.");
+	Log::i("Initializing Game...");
+
+	m_is_init = true;
 	start();
 
+	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)
 	{
+		stop();
 		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->game_shutdown();
+	m_lua_environment->call_global("shutdown", 0);
 
 	Log::i("Releasing ConsoleServer...");
 	if (m_console_server)
@@ -204,14 +272,14 @@ void Device::shutdown()
 	}
 
 	Log::i("Releasing ResourceManager...");
-	if (m_resource_bundle)
+	if (m_resource_manager)
 	{
-		CE_DELETE(m_allocator, m_resource_bundle);
+		CE_DELETE(m_allocator, m_resource_manager);
 	}
 
-	if (m_resource_manager)
+	if (m_resource_bundle)
 	{
-		CE_DELETE(m_allocator, m_resource_manager);
+		Bundle::destroy(m_allocator, m_resource_bundle);
 	}
 
 	Log::i("Releasing Filesystem...");
@@ -304,25 +372,16 @@ ConsoleServer* Device::console_server()
 //-----------------------------------------------------------------------------
 void Device::start()
 {
-	if (is_init() == false)
-	{
-		Log::e("Cannot start uninitialized engine.");
-		return;
-	}
+	CE_ASSERT(m_is_init, "Cannot start uninitialized engine.");
 
 	m_is_running = true;
-
 	m_last_time = os::milliseconds();
 }
 
 //-----------------------------------------------------------------------------
 void Device::stop()
 {
-	if (is_init() == false)
-	{
-		Log::e("Cannot stop uninitialized engine.");
-		return;
-	}
+	CE_ASSERT(m_is_init, "Cannot stop uninitialized engine.");
 
 	m_is_running = false;
 }
@@ -356,10 +415,9 @@ void Device::frame()
 
 	m_window->frame();
 	m_input_manager->frame(frame_count());
+	m_lua_environment->call_global("frame", 1, ARGUMENT_FLOAT, last_delta_time());
 
-	m_lua_environment->game_frame(last_delta_time());
-
-	//m_console_server->execute();
+	// m_console_server->execute();
 
 	m_debug_renderer->draw_all();
 	m_renderer->frame();
@@ -368,108 +426,37 @@ void Device::frame()
 }
 
 //-----------------------------------------------------------------------------
-void Device::reload(ResourceId name)
-{
-	(void)name;
-}
-
-//-----------------------------------------------------------------------------
-void Device::create_filesystem()
-{
-	m_filesystem = CE_NEW(m_allocator, Filesystem)(m_preferred_root_path);
-
-	Log::d("Filesystem created.");
-	Log::d("Filesystem root path: %s", m_filesystem->root_path());
-}
-
-//-----------------------------------------------------------------------------
-void Device::create_resource_manager()
+ResourcePackage* Device::create_resource_package(const char* name)
 {
-	// Select appropriate resource archive
-	if (m_preferred_mode == MODE_DEVELOPMENT)
-	{
-		m_resource_bundle = CE_NEW(m_allocator, FileBundle)(*m_filesystem);
-	}
-	else
-	{
-		m_resource_bundle = CE_NEW(m_allocator, ArchiveBundle)(*m_filesystem);
-	}
-
-	// Read resource seed
-	DiskFile* seed_file = filesystem()->open("seed.ini", FOM_READ);
-	TextReader reader(*seed_file);
-
-	char tmp_buf[32];
-	reader.read_string(tmp_buf, 32);
-
-	filesystem()->close(seed_file);
+	CE_ASSERT_NOT_NULL(name);
 
-	uint32_t seed = string::parse_uint(tmp_buf);
+	ResourceId package_id = m_resource_manager->load("package", name);
+	m_resource_manager->flush();
 
-	// Create resource manager
-	m_resource_manager = CE_NEW(m_allocator, ResourceManager)(*m_resource_bundle, seed);
-
-	Log::d("Resource manager created.");
-	Log::d("Resource seed: %d", m_resource_manager->seed());
-}
-
-//-----------------------------------------------------------------------------
-void Device::create_input_manager()
-{
-	// Create input manager
-	m_input_manager = CE_NEW(m_allocator, InputManager)();
-
-	Log::d("Input manager created.");
-}
-
-//-----------------------------------------------------------------------------
-void Device::create_window()
-{
-	m_window = CE_NEW(m_allocator, OsWindow)(m_preferred_window_width, m_preferred_window_height, m_parent_window_handle);
-
-	CE_ASSERT(m_window != NULL, "Unable to create the window");
-
-	m_window->set_title("Crown Game Engine");
-	m_window->show();
+	PackageResource* package_res = (PackageResource*) m_resource_manager->data(package_id);
+	ResourcePackage* package = CE_NEW(m_allocator, ResourcePackage)(*m_resource_manager, package_id, package_res);
 
-	Log::d("Window created.");
+	return package;
 }
 
 //-----------------------------------------------------------------------------
-void Device::create_renderer()
+void Device::destroy_resource_package(ResourcePackage* package)
 {
-	m_renderer = Renderer::create(m_allocator);
-	m_renderer->init();
+	CE_ASSERT_NOT_NULL(package);
 
-	Log::d("Renderer created.");
+	m_resource_manager->unload(package->resource_id());
+	CE_DELETE(m_allocator, package);
 }
 
 //-----------------------------------------------------------------------------
-void Device::create_debug_renderer()
+void Device::compile(const char* , const char* , const char* )
 {
-	// Create debug renderer
-	m_debug_renderer = CE_NEW(m_allocator, DebugRenderer)(*m_renderer);
-
-	Log::d("Debug renderer created.");
 }
 
 //-----------------------------------------------------------------------------
-void Device::create_lua_environment()
-{
-	m_lua_environment = CE_NEW(m_allocator, LuaEnvironment)();
-
-	m_lua_environment->init();
-
-	Log::d("Lua environment created.");
-}
-
-void Device::create_console_server()
+void Device::reload(ResourceId name)
 {
-	m_console_server = NULL;//CE_NEW(m_allocator, ConsoleServer)();
-
-	//m_console_server->init();
-
-	Log::d("Console server created.");
+	(void)name;
 }
 
 //-----------------------------------------------------------------------------
@@ -478,12 +465,14 @@ void Device::parse_command_line(int argc, char** argv)
 	static ArgsOption options[] = 
 	{
 		{ "help",             AOA_NO_ARGUMENT,       NULL,        'i' },
-		{ "root-path",        AOA_REQUIRED_ARGUMENT, NULL,        'r' },
+		{ "source-dir",       AOA_REQUIRED_ARGUMENT, NULL,        's' },
+		{ "bundle-dir",       AOA_REQUIRED_ARGUMENT, NULL,        'b' },
+		{ "compile",          AOA_NO_ARGUMENT,       &m_compile,   1 },
+		{ "continue",         AOA_NO_ARGUMENT,       &m_continue,  1 },
 		{ "width",            AOA_REQUIRED_ARGUMENT, NULL,        'w' },
 		{ "height",           AOA_REQUIRED_ARGUMENT, NULL,        'h' },
 		{ "fullscreen",       AOA_NO_ARGUMENT,       &m_preferred_window_fullscreen, 1 },
 		{ "parent-window",    AOA_REQUIRED_ARGUMENT, NULL,        'p' },
-		{ "dev",              AOA_NO_ARGUMENT,       &m_preferred_mode, MODE_DEVELOPMENT },
 		{ "quit-after-init",  AOA_NO_ARGUMENT,       &m_quit_after_init, 1 },
 		{ NULL, 0, NULL, 0 }
 	};
@@ -500,10 +489,16 @@ void Device::parse_command_line(int argc, char** argv)
 			{
 				break;
 			}
-			// Root path
-			case 'r':
+			// Source directory
+			case 's':
 			{
-				string::strncpy(m_preferred_root_path, args.optarg(), MAX_PATH_LENGTH);
+				string::strncpy(m_source_dir, args.optarg(), MAX_PATH_LENGTH);
+				break;
+			}
+			// Bundle directory
+			case 'b':
+			{
+				string::strncpy(m_bundle_dir, args.optarg(), MAX_PATH_LENGTH);
 				break;
 			}
 			// Window width
@@ -538,7 +533,7 @@ void Device::parse_command_line(int argc, char** argv)
 //-----------------------------------------------------------------------------
 void Device::check_preferred_settings()
 {
-	if (!os::is_absolute_path(m_preferred_root_path))
+	if (!os::is_absolute_path(m_bundle_dir))
 	{
 		Log::e("The root path must be absolute.");
 		exit(EXIT_FAILURE);
@@ -554,6 +549,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");
 }
 
 //-----------------------------------------------------------------------------
@@ -567,15 +603,19 @@ void Device::print_help_message()
 	"environment variables and configuration files.\n\n"
 
 	"  --help                     Show this help.\n"
-	"  --root-path <path>         Use <path> as the filesystem root path.\n"
+	"  --bundle-dir <path>        Use <path> as the source directory for compiled resources.\n"
 	"  --width <width>            Set the <width> of the main window.\n"
 	"  --height <width>           Set the <height> of the main window.\n"
 	"  --fullscreen               Start in fullscreen.\n"
 	"  --parent-window <handle>   Set the parent window <handle> of the main window.\n"
 	"                             Used only by tools.\n"
-	"  --dev                      Run the engine in development mode\n"
-	"  --quit-after-init          Quit the engine immediately after the initialization.\n"
-	"                             Used only for debugging.\n");
+
+	"\nAvailable only in debug and development builds:\n\n"
+
+	"  --source-dir <path>        Use <path> as the source directory for resource compilation.\n"
+	"  --compile                  Run the engine as resource compiler.\n"
+	"  --continue                 Do a full compile of the resources and continue the execution.\n"
+	"  --quit-after-init          Quit the engine immediately after the initialization.\n");
 }
 
 Device g_device;

+ 20 - 20
engine/Device.h

@@ -50,6 +50,8 @@ class Touch;
 class Accelerometer;
 class LuaEnvironment;
 class ConsoleServer;
+class BundleCompiler;
+class ResourcePackage;
 
 /// The Engine.
 /// It is the place where to look for accessing all of
@@ -93,6 +95,17 @@ public:
 	/// Updates all the subsystems
 	void					frame();
 
+	/// Returns the resource package with the given @a package_name name.
+	ResourcePackage*		create_resource_package(const char* name);
+
+	/// Destroy a previously created resource @a package.
+	/// @note
+	/// To unload the resources loaded by the package, you have to call
+	/// ResourcePackage::unload() first.
+	void					destroy_resource_package(ResourcePackage* package);
+
+	void					compile(const char* bundle_dir, const char* source_dir, const char* resource);
+
 	void					reload(ResourceId name);
 
 	Filesystem*				filesystem();
@@ -113,17 +126,6 @@ public:
 
 private:
 
-	void					create_filesystem();
-	void					create_resource_manager();
-	void					create_input_manager();
-	void 					create_lua_environment();
-
-	void					create_window();
-	void					create_renderer();
-	void					create_debug_renderer();
-
-	void					create_console_server();
-
 	void					parse_command_line(int argc, char** argv);
 	void					check_preferred_settings();
 	void					read_engine_settings();
@@ -135,13 +137,16 @@ 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;
-	int32_t					m_preferred_mode;
-	char					m_preferred_root_path[MAX_PATH_LENGTH];
+	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;
 
 	int32_t					m_quit_after_init;
 
@@ -164,6 +169,7 @@ private:
 	DebugRenderer*			m_debug_renderer;
 
 	// Private subsystems
+	BundleCompiler*			m_bundle_compiler;
 	ResourceManager*		m_resource_manager;
 	Bundle*					m_resource_bundle;
 
@@ -172,12 +178,6 @@ private:
 
 private:
 
-	enum
-	{
-		MODE_RELEASE,
-		MODE_DEVELOPMENT
-	};
-
 	// Disable copying
 	Device(const Device&);
 	Device& operator=(const Device&);

+ 157 - 0
engine/compilers/BundleCompiler.cpp

@@ -0,0 +1,157 @@
+/*
+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 <inttypes.h>
+#include "BundleCompiler.h"
+#include "Vector.h"
+#include "DynamicString.h"
+#include "Allocator.h"
+#include "OS.h"
+#include "Log.h"
+#include "Resource.h"
+#include "Path.h"
+#include "DiskFilesystem.h"
+#include "TempAllocator.h"
+
+namespace crown
+{
+
+//-----------------------------------------------------------------------------
+BundleCompiler::BundleCompiler()
+{
+}
+
+//-----------------------------------------------------------------------------
+bool BundleCompiler::compile(const char* bundle_dir, const char* source_dir)
+{
+	Vector<DynamicString> files(default_allocator());
+	BundleCompiler::scan(source_dir, "", files);
+
+	// Create bundle dir if does not exist
+	DiskFilesystem temp;
+	if (!temp.is_directory(bundle_dir) || !temp.is_file(bundle_dir))
+	{
+		temp.create_directory(bundle_dir);
+	}
+
+	// Copy crown.config to bundle dir
+	DiskFilesystem src_fs(source_dir);
+	DiskFilesystem dst_fs(bundle_dir);
+
+	if (src_fs.is_file("crown.config"))
+	{
+		File* src = src_fs.open("crown.config", FOM_READ);
+		File* dst = dst_fs.open("crown.config", FOM_WRITE);
+		src->copy_to(*dst, src->size());
+		src_fs.close(src);
+		dst_fs.close(dst);
+	}
+	else
+	{
+		Log::d("'crown.config' does not exist.");
+		return false;
+	}
+
+	// Compile all resources
+	for (uint32_t i = 0; i < files.size(); 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);
+
+		char out_name[65];
+		snprintf(out_name, 65, "%"PRIx64"", filename_hash);
+
+		// Skip crown.config file
+		if (resource_type_hash == CONFIG_TYPE)
+		{
+			continue;
+		}
+
+		Log::i("%s <= %s", out_name, filename);
+
+		bool result = false;
+		if (resource_type_hash == TEXTURE_TYPE)
+		{
+			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, out_name);
+		}
+		else if (resource_type_hash == PACKAGE_TYPE)
+		{
+			result = m_package.compile(source_dir, bundle_dir, filename, out_name);
+		}
+		else
+		{
+			Log::e("Oops, unknown resource type!");
+			return false;
+		}
+
+		if (!result)
+		{
+			return false;
+		}
+	}
+
+	return true;
+}
+
+void BundleCompiler::scan(const char* source_dir, const char* cur_dir, Vector<DynamicString>& files)
+{
+	Vector<DynamicString> my_files(default_allocator());
+
+	DiskFilesystem fs(source_dir);
+	fs.list_files(cur_dir, my_files);
+
+	for (uint32_t i = 0; i < my_files.size(); i++)
+	{
+		DynamicString file_i(default_allocator());
+
+		if (string::strcmp(cur_dir, "") != 0)
+		{
+			file_i += cur_dir;
+			file_i += '/';
+		}
+		file_i += my_files[i];
+
+		if (fs.is_directory(file_i.c_str()))
+		{
+			BundleCompiler::scan(source_dir, file_i.c_str(), files);
+		}
+		else // Assume a regular file
+		{
+			files.push_back(file_i);
+		}
+	}
+}
+
+} // namespace crown

+ 24 - 12
engine/core/filesystem/TextWriter.cpp → engine/compilers/BundleCompiler.h

@@ -24,23 +24,35 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
 */
 
-#include "TextWriter.h"
-#include "File.h"
-#include "StringUtils.h"
+#pragma once
+
+#include "TextureCompiler.h"
+#include "LuaCompiler.h"
+#include "PackageCompiler.h"
+#include "DynamicString.h"
+#include "Vector.h"
+#include "DiskFilesystem.h"
 
 namespace crown
 {
 
-//-----------------------------------------------------------------------------
-TextWriter::TextWriter(File& file) : m_file(file)
+class BundleCompiler
 {
-}
+public:
 
-//-----------------------------------------------------------------------------
-void TextWriter::write_string(const char* string)
-{
-	m_file.write(string, string::strlen(string));
-}
+	BundleCompiler();
 
-} // namespace crown
+	bool compile(const char* bundle_dir, const char* source_dir);
+
+private:
 
+	static void scan(const char* source_dir, const char* cur_dir, Vector<DynamicString>& files);
+
+private:
+
+	TextureCompiler	m_texture;
+	LuaCompiler 	m_lua;
+	PackageCompiler m_package;
+};
+
+} // namespace crown

+ 13 - 17
tools/compilers/Compiler.cpp → engine/compilers/Compiler.cpp

@@ -24,15 +24,11 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
 */
 
-#include <cstring>
-#include <cstdlib>
-#include <iostream>
-
 #include "Compiler.h"
+#include "Filesystem.h"
+#include "DiskFilesystem.h"
 #include "ResourceFormat.h"
-
-using std::cout;
-using std::endl;
+#include "File.h"
 
 namespace crown
 {
@@ -40,14 +36,14 @@ namespace crown
 //-----------------------------------------------------------------------------
 bool Compiler::compile(const char* root_path, const char* dest_path, const char* name_in, const char* name_out)
 {
-	std::string path_in = std::string(root_path) + "/" + std::string(name_in);
-	std::string path_out = std::string(dest_path) + "/" + std::string(name_out);
+	DiskFilesystem root_fs(root_path);
+	DiskFilesystem dest_fs(dest_path);
 
 	// The compilation fails when returned size is zero
 	size_t resource_size = 0;
-	if ((resource_size = compile_impl(path_in.c_str())) == 0)
+	if ((resource_size = compile_impl(root_fs, name_in)) == 0)
 	{
-		cout << "Compilation failed." << endl;
+		Log::e("Compilation failed");
 		return false;
 	}
 
@@ -58,23 +54,23 @@ bool Compiler::compile(const char* root_path, const char* dest_path, const char*
 	resource_header.size = resource_size;
 
 	// Open destination file and write the header
-	std::fstream out_file;
-	out_file.open(path_out.c_str(), std::fstream::out | std::fstream::binary);
+	File* out_file = dest_fs.open(name_out, FOM_WRITE);
 
-	if (out_file.is_open())
+	if (out_file)
 	{
 		// Write header
-		out_file.write((char*)&resource_header, sizeof(ResourceHeader));
+		out_file->write((char*)&resource_header, sizeof(ResourceHeader));
 
 		// Write resource-specific data
 		write_impl(out_file);
-		out_file.close();
+
+		dest_fs.close(out_file);
 
 		cleanup();
 		return true;
 	}
 
-	cout << "Unable to write compiled file." << endl;
+	Log::e("Unable to write compiled file.");
 	return false;
 }
 

+ 5 - 5
tools/compilers/Compiler.h → engine/compilers/Compiler.h

@@ -26,14 +26,14 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 #pragma once
 
-#include <string>
-#include <fstream>
-
 #include "Types.h"
 
 namespace crown
 {
 
+class Filesystem;
+class File;
+
 /// Resource compiler interface.
 /// Every specific resource compiler must inherith from this
 /// interface and implement its methods accordingly.
@@ -48,8 +48,8 @@ public:
 
 protected:
 
-	virtual size_t			compile_impl(const char* resource_path) = 0;
-	virtual void			write_impl(std::fstream& out_file) = 0;
+	virtual size_t			compile_impl(Filesystem& fs, const char* resource_path) = 0;
+	virtual void			write_impl(File* out_file) = 0;
 };
 
 } // namespace crown

+ 0 - 0
tools/compilers/dae/DAECompiler.cpp → engine/compilers/dae/DAECompiler.cpp


+ 34 - 0
tools/compilers/dae/DAECompiler.h → engine/compilers/dae/DAECompiler.h

@@ -40,6 +40,40 @@ using std::vector;
 namespace crown
 {
 
+//
+// STRUCT
+// {
+//     FIELD             : SIZE                    COMMENT
+// }
+//
+// MeshHeader [1]
+// {
+//     version           : uint32_t                Version identifier
+//     mesh_count        : uint32_t                Number of meshes in the file
+//     joint_count       : uint32_t                Number of joints in the file
+//     padding           : uint32_t * 16           Reserved
+// }
+// MeshChunk [1, 2, ..., n]
+// {
+//     vertex_count      : uint32_t                Number of vertices in the mesh
+//     vertices          : float * vertex_count    Vertex data
+//
+//     tri_count         : uint32_t                Number of triangles in the mesh
+//     tris              : uint16_t * tri_count    Triangle data as indices into 'vertices'
+// }
+//
+
+// Bump the version whenever a change in the format is made.
+const uint32_t MESH_VERSION = 1;
+
+struct MeshHeader
+{
+	uint32_t	version;
+	uint32_t	mesh_count;
+	uint32_t	joint_count;
+	uint32_t	padding[16];
+};
+
 //-----------------------------------------------------------------------------
 struct DAEFloatArray
 {

+ 0 - 0
tools/compilers/dae/tinyxml2.cpp → engine/compilers/dae/tinyxml2.cpp


+ 0 - 0
tools/compilers/dae/tinyxml2.h → engine/compilers/dae/tinyxml2.h


+ 55 - 36
tools/compilers/wav/WAVCompiler.cpp → engine/compilers/lua/LuaCompiler.cpp

@@ -24,67 +24,86 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
 */
 
-#include <cstdio>
-
-#include "WAVCompiler.h"
+#include "LuaCompiler.h"
+#include "LuaResource.h"
+#include "TempAllocator.h"
+#include "DynamicString.h"
+#include "Filesystem.h"
+#include "OS.h"
 
 namespace crown
 {
 
+#ifdef WINDOWS
+	#define LUAJIT "luajit.exe"
+#else
+	#define LUAJIT "./luajit"
+#endif
+
+
 //-----------------------------------------------------------------------------
-WAVCompiler::WAVCompiler() :
-	m_sound_data_size(0),
-	m_sound_data(NULL)
+LuaCompiler::LuaCompiler()
+	: m_luajit_blob_size(0), m_luajit_blob(NULL)
 {
-
 }
 
 //-----------------------------------------------------------------------------
-WAVCompiler::~WAVCompiler()
+LuaCompiler::~LuaCompiler()
 {
-	if (m_sound_data)
-	{
-		delete[] m_sound_data;
-	}
 }
 
 //-----------------------------------------------------------------------------
-size_t WAVCompiler::compile_impl(const char* resource_path)
+size_t LuaCompiler::compile_impl(Filesystem& fs, const char* resource_path)
 {
-	std::fstream in_file;
-	in_file.open(resource_path, std::fstream::in | std::fstream::binary);
+	TempAllocator1024 alloc;
+	DynamicString res_abs_path(alloc);
+	TempAllocator1024 alloc2;
+	DynamicString bc_abs_path(alloc2);
+	fs.get_absolute_path(resource_path, res_abs_path);
+	fs.get_absolute_path("bc.tmp", bc_abs_path);
+
+	const char* luajit[] =
+	{
+		LUAJIT,
+		"-b",
+		res_abs_path.c_str(),
+		bc_abs_path.c_str(),
+		NULL
+	};
+
+	os::execute_process(luajit);
 
-	if (!in_file.is_open())
+	File* bc = fs.open(bc_abs_path.c_str(), FOM_READ);
+	if (bc != NULL)
 	{
-		printf("Unable to open file: %s\n", resource_path);
-		return 0;
+		m_luajit_blob_size = bc->size();
+		m_luajit_blob = (char*) default_allocator().allocate(m_luajit_blob_size);
+		bc->read(m_luajit_blob, m_luajit_blob_size);
+		fs.close(bc);
+		fs.delete_file(bc_abs_path.c_str());
 	}
-
-	// Read the header
-	if (!in_file.read((char*)(char*)&m_wav_header, sizeof(WAVHeader)))
+	else
 	{
-		printf("Unable to read the WAV header.");
+		Log::e("Error while reading luajit bytecode");
 		return 0;
 	}
 
-	m_sound_header.version = SOUND_VERSION;
-	m_sound_header.size = m_wav_header.data_size;
-	m_sound_header.channels = m_wav_header.fmt_channels;
-	m_sound_header.bits_per_sample = m_wav_header.fmt_bits_per_sample;
-
-	m_sound_data_size = m_wav_header.data_size;
-	m_sound_data = new uint8_t[m_sound_data_size];
-
-	in_file.read((char*)m_sound_data, m_sound_data_size);
-
-	return sizeof(SoundHeader) + m_sound_data_size;
+	return sizeof(LuaHeader) + m_luajit_blob_size;
 }
 
 //-----------------------------------------------------------------------------
-void WAVCompiler::write_impl(std::fstream& out_file)
+void LuaCompiler::write_impl(File* out_file)
 {
-	out_file.write((char*)&m_sound_header, sizeof(SoundHeader));
-	out_file.write((char*)m_sound_data, m_sound_data_size);
+	LuaHeader header;
+	header.version = LUA_RESOURCE_VERSION;
+	header.size = m_luajit_blob_size;
+
+	out_file->write((char*)&header, sizeof(LuaHeader));
+	out_file->write((char*)m_luajit_blob, m_luajit_blob_size);
+
+	default_allocator().deallocate(m_luajit_blob);
+	m_luajit_blob_size = 0;
+	m_luajit_blob = NULL;
 }
 
 } // namespace crown

+ 8 - 8
tools/compilers/mat/MATCompiler.h → engine/compilers/lua/LuaCompiler.h

@@ -27,24 +27,24 @@ OTHER DEALINGS IN THE SOFTWARE.
 #pragma once
 
 #include "Compiler.h"
-#include "FileStream.h"
-#include "Resource.h"
 
 namespace crown
 {
 
-class MATCompiler : public Compiler
+class LuaCompiler : public Compiler
 {
 public:
 
-					MATCompiler(const char* root_path, const char* dest_path, const char* resource, uint32_t seed);
-					~MATCompiler();
+					LuaCompiler();
+					~LuaCompiler();
 
-	bool			compile();
-	void			write();
+	size_t			compile_impl(Filesystem& fs, const char* resource_path);
+	void			write_impl(File* out_file);
 
 private:
+
+	size_t			m_luajit_blob_size;
+	char*			m_luajit_blob;
 };
 
 } // namespace crown
-

+ 132 - 0
engine/compilers/package/PackageCompiler.cpp

@@ -0,0 +1,132 @@
+/*
+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 "Allocator.h"
+#include "File.h"
+#include "Filesystem.h"
+#include "Hash.h"
+#include "JSONParser.h"
+#include "PackageCompiler.h"
+#include "PackageResource.h"
+#include "TempAllocator.h"
+
+namespace crown
+{
+
+//-----------------------------------------------------------------------------
+PackageCompiler::PackageCompiler()
+	: m_has_texture(false), m_has_lua(false), m_textures(default_allocator()), m_scripts(default_allocator())
+{
+}
+
+//-----------------------------------------------------------------------------
+size_t PackageCompiler::compile_impl(Filesystem& fs, const char* resource_path)
+{
+	File* file = fs.open(resource_path, FOM_READ);
+
+	char file_buf[4096];
+	file->read(file_buf, file->size());
+	fs.close(file);
+
+	JSONParser json(file_buf);
+	JSONElement root = json.root();
+
+	// Check for resource types
+	if (root.has_key("texture"))
+	{
+		JSONElement texture_array = root.key("texture");
+		uint32_t texture_array_size = texture_array.size();
+
+		for (uint32_t i = 0; i < texture_array_size; i++)
+		{
+			TempAllocator256 alloc;
+			DynamicString texture_name(alloc);
+			texture_name += texture_array[i].string_value();
+			texture_name += ".texture";
+
+			if (!fs.is_file(texture_name.c_str()))
+			{
+				Log::e("Texture '%s' does not exist.", texture_name.c_str());
+				return 0;
+			}
+
+			ResourceId id;
+			id.id = hash::murmur2_64(texture_name.c_str(), string::strlen(texture_name.c_str()), 0);
+			m_textures.push_back(id);
+		}
+	}
+
+	// Check for scripts
+	if (root.has_key("lua"))
+	{
+		JSONElement lua_array = root.key("lua");
+		//lua_array = root.key("lua");
+		uint32_t lua_array_size = lua_array.size();
+
+		for (uint32_t i = 0; i < lua_array_size; i++)
+		{
+			TempAllocator256 alloc;
+			DynamicString lua_name(alloc);
+			lua_name += lua_array[i].string_value();
+			lua_name += ".lua";
+
+			if (!fs.is_file(lua_name.c_str()))
+			{
+				Log::e("Lua script '%s' does not exist.", lua_name.c_str());
+				return 0;
+			}
+
+			ResourceId id;
+			id.id = hash::murmur2_64(lua_name.c_str(), string::strlen(lua_name.c_str()), 0);
+			m_scripts.push_back(id);
+		}
+	}
+
+	return sizeof(PackageHeader) +
+			m_textures.size() * sizeof(ResourceId) +
+			m_scripts.size() * sizeof(ResourceId);
+}
+
+//-----------------------------------------------------------------------------
+void PackageCompiler::write_impl(File* out_file)
+{
+	PackageHeader header;
+	header.num_textures = m_textures.size();
+	header.num_scripts = m_scripts.size();
+
+	header.textures_offset = sizeof(PackageHeader);
+	header.scripts_offset  = header.textures_offset + sizeof(ResourceId) * header.num_textures;
+
+	out_file->write((char*) &header, sizeof(PackageHeader));
+	out_file->write((char*) m_textures.begin(), sizeof(ResourceId) * header.num_textures);
+	out_file->write((char*) m_scripts.begin(), sizeof(ResourceId) * header.num_scripts);
+
+	// Cleanup
+	m_textures.clear();
+	m_scripts.clear();
+}
+
+} // namespace crown

+ 17 - 14
tools/core/formats/TextureFormat.h → engine/compilers/package/PackageCompiler.h

@@ -26,26 +26,29 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 #pragma once
 
-#include "Types.h"
+#include "Compiler.h"
+#include "Resource.h"
+#include "List.h"
 
 namespace crown
 {
 
-// Texture format
-//
-// [ResourceHeader]
-// [TextureHeader]
-// [TextureData]
+class PackageCompiler : public Compiler
+{
+public:
 
-// Bump the version whenever a change in the header is made
-const uint32_t TEXTURE_VERSION = 1;
+	PackageCompiler();
 
-struct TextureHeader
-{
-	uint32_t	version;	// Texture file version
-	uint32_t	format;		// Format of the pixels
-	uint32_t	width;		// Width in pixels
-	uint32_t	height;		// Height in pixels
+	size_t compile_impl(Filesystem& fs, const char* resource_path);
+	void write_impl(File* out_file);
+
+private:
+
+	bool m_has_texture;
+	bool m_has_lua;
+
+	List<ResourceId> m_textures;
+	List<ResourceId> m_scripts;
 };
 
 } // namespace crown

+ 36 - 38
tools/compilers/tga/TGACompiler.cpp → engine/compilers/texture/TextureCompiler.cpp

@@ -24,53 +24,42 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
 */
 
-#include <fstream>
-#include <iostream>
-
-#include "TGACompiler.h"
+#include "TextureCompiler.h"
 #include "PixelFormat.h"
-#include "TextureFormat.h"
+#include "Allocator.h"
+#include "Filesystem.h"
 
 namespace crown
 {
 
 //-----------------------------------------------------------------------------
-TGACompiler::TGACompiler() :
+TextureCompiler::TextureCompiler() :
 	m_texture_data_size(0),
 	m_texture_data(NULL)
 {
 }
 
 //-----------------------------------------------------------------------------
-TGACompiler::~TGACompiler()
+TextureCompiler::~TextureCompiler()
 {
-	if (m_texture_data)
-	{
-		delete[] m_texture_data;
-	}
 }
 
 //-----------------------------------------------------------------------------
-size_t TGACompiler::compile_impl(const char* resource_path)
+size_t TextureCompiler::compile_impl(Filesystem& fs, const char* resource_path)
 {
-	std::fstream in_file;
-	in_file.open(resource_path, std::fstream::in | std::fstream::binary);
+	File* in_file = fs.open(resource_path, FOM_READ);
 
-	if (!in_file.is_open())
+	if (!in_file)
 	{
-		std::cout << "Unable to open file: " << resource_path << std::endl;
+		Log::e("Unable to open file: %s", resource_path);
 		return 0;
 	}
 
 	// Read the header
-	if (!in_file.read((char*)(char*)&m_tga_header, sizeof(TGAHeader)))
-	{
-		std::cout << "Unable to read the TGA header." << std::endl;
-		return 0;
-	}
+	in_file->read((char*)(char*)&m_tga_header, sizeof(TGAHeader));
 
 	// Skip TGA ID
-	in_file.seekg(m_tga_header.id_length);
+	in_file->skip(m_tga_header.id_length);
 
 	// Compute color channels
 	m_tga_channels = m_tga_header.pixel_depth / 8;
@@ -90,7 +79,7 @@ size_t TGACompiler::compile_impl(const char* resource_path)
 			m_texture_header.format = PF_RGB_8;
 
 			m_texture_data_size = m_tga_size * 3;
-			m_texture_data = new uint8_t[m_texture_data_size];
+			m_texture_data = (uint8_t*)default_allocator().allocate(m_texture_data_size);
 
 			break;
 		}
@@ -99,13 +88,13 @@ size_t TGACompiler::compile_impl(const char* resource_path)
 			m_texture_header.format = PF_RGBA_8;
 
 			m_texture_data_size = m_tga_size * m_tga_channels;
-			m_texture_data = new uint8_t[m_texture_data_size];
+			m_texture_data = (uint8_t*)default_allocator().allocate(m_texture_data_size);
 			
 			break;
 		}
 		default:
 		{
-			std::cout << "Unable to determine TGA channels." << std::endl;
+			Log::e("Unable to determine TGA channels.");
 			return 0;
 		}
 	}
@@ -115,7 +104,7 @@ size_t TGACompiler::compile_impl(const char* resource_path)
 	{
 		case 0:
 		{
-			std::cout << "The file does not contain image data: " << resource_path << std::endl;
+			Log::e("The file does not contain image data: %s", resource_path);
 			return 0;
 		}
 		case 2:
@@ -132,24 +121,33 @@ size_t TGACompiler::compile_impl(const char* resource_path)
 
 		default:
 		{
-			std::cout << "Image type not supported." << std::endl;
+			Log::e("Image type not supported.");
 			return 0;
 		}
 	}
 
+	fs.close(in_file);
+
 	// Return the total resource size
 	return sizeof(TextureHeader) + m_texture_data_size;
 }
 
 //-----------------------------------------------------------------------------
-void TGACompiler::write_impl(std::fstream& 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);
+	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(std::fstream& in_file)
+void TextureCompiler::load_uncompressed(File* in_file)
 {
 	uint64_t size = m_tga_header.width * m_tga_header.height;
 
@@ -161,7 +159,7 @@ void TGACompiler::load_uncompressed(std::fstream& in_file)
 		{
 			uint16_t pixel_data;
 			
-			in_file.read((char*)&pixel_data, sizeof(pixel_data));
+			in_file->read((char*)&pixel_data, sizeof(pixel_data));
 			
 			m_texture_data[j + 0] = (pixel_data & 0x7c) >> 10;
 			m_texture_data[j + 1] = (pixel_data & 0x3e) >> 5;
@@ -172,14 +170,14 @@ void TGACompiler::load_uncompressed(std::fstream& in_file)
 	}
 	else
 	{
-		in_file.read((char*)m_texture_data, (size_t)(size * m_tga_channels));
+		in_file->read((char*)m_texture_data, (size_t)(size * m_tga_channels));
 
 		swap_red_blue();
 	}
 }
 
 //-----------------------------------------------------------------------------
-void TGACompiler::load_compressed(std::fstream& in_file)
+void TextureCompiler::load_compressed(File* in_file)
 {
 	uint8_t rle_id = 0;
 	uint32_t i = 0;
@@ -191,14 +189,14 @@ void TGACompiler::load_compressed(std::fstream& in_file)
 
 	while (i < size)
 	{
-		in_file.read((char*)&rle_id, sizeof(uint8_t));
+		in_file->read((char*)&rle_id, sizeof(uint8_t));
 
 		// If MSB == 1
 		if (rle_id & 0x80)
 		{
 			rle_id -= 127;
 			
-			in_file.read((char*)&colors, m_tga_channels);
+			in_file->read((char*)&colors, m_tga_channels);
 
 			while (rle_id)
 			{
@@ -222,7 +220,7 @@ void TGACompiler::load_compressed(std::fstream& in_file)
 
 			while (rle_id)
 			{
-				in_file.read((char*)colors, m_tga_channels);
+				in_file->read((char*)colors, m_tga_channels);
 				
 				m_texture_data[colors_read + 0] = colors[2];
 				m_texture_data[colors_read + 1] = colors[1];
@@ -242,7 +240,7 @@ void TGACompiler::load_compressed(std::fstream& 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)
 	{

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

@@ -27,7 +27,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #pragma once
 
 #include "Compiler.h"
-#include "TextureFormat.h"
+#include "TextureResource.h"
 
 namespace crown
 {
@@ -47,20 +47,20 @@ 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(const char* resource_path);
-	void			write_impl(std::fstream& out_file);
+	size_t			compile_impl(Filesystem& fs, const char* resource_path);
+	void			write_impl(File* out_file);
 
 private:
 
-	void			load_uncompressed(std::fstream& in_file);
-	void			load_compressed(std::fstream& in_file);
+	void			load_uncompressed(File* in_file);
+	void			load_compressed(File* in_file);
 	void			swap_red_blue();
 
 private:

+ 1 - 1
engine/core/Assert.h

@@ -31,7 +31,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "Config.h"
 #include "Log.h"
 
-#ifdef CROWN_DEBUG
+#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
 	#define CE_ASSERT(condition, ...) do { if (!(condition)) {\
 		crown::Log::e("Assertion failed: %s", #condition);\
 		crown::Log::e("\t" __VA_ARGS__);\

+ 16 - 24
engine/core/containers/List.h

@@ -47,7 +47,7 @@ public:
 
 	/// Allocates capacity * sizeof(T) bytes.
 						List(Allocator& allocator, uint32_t capacity);
-						List(const List<T>& list);
+						List(const List<T>& other);
 						~List();
 
 	/// Random access by index
@@ -116,7 +116,7 @@ public:
 
 private:
 
-	Allocator&			m_allocator;
+	Allocator*			m_allocator;
 	uint32_t			m_capacity;
 	uint32_t			m_size;
 	T*					m_array;
@@ -124,33 +124,25 @@ private:
 
 //-----------------------------------------------------------------------------
 template <typename T>
-inline List<T>::List(Allocator& allocator) :
-	m_allocator(allocator),
-	m_capacity(0),
-	m_size(0),
-	m_array(NULL)
+inline List<T>::List(Allocator& allocator)
+	: m_allocator(&allocator), m_capacity(0), m_size(0), m_array(NULL)
 {
 }
 
 //-----------------------------------------------------------------------------
 template <typename T>
-inline List<T>::List(Allocator& allocator, uint32_t capacity) :
-	m_allocator(allocator),
-	m_capacity(0),
-	m_size(0),
-	m_array(NULL)
+inline List<T>::List(Allocator& allocator, uint32_t capacity)
+	: m_allocator(&allocator), m_capacity(0), m_size(0), m_array(NULL)
 {
 	resize(capacity);
 }
 
 //-----------------------------------------------------------------------------
 template <typename T>
-inline List<T>::List(const List<T>& list) :
-	m_capacity(0),
-	m_size(0),
-	m_array(NULL)
+inline List<T>::List(const List<T>& other)
+	: m_allocator(other.m_allocator), m_capacity(0), m_size(0), m_array(NULL)
 {
-	*this = list;
+	*this = other;
 }
 
 //-----------------------------------------------------------------------------
@@ -159,7 +151,7 @@ inline List<T>::~List()
 {
 	if (m_array)
 	{
-		m_allocator.deallocate(m_array);
+		m_allocator->deallocate(m_array);
 	}
 }
 
@@ -167,7 +159,7 @@ inline List<T>::~List()
 template <typename T>
 inline T& List<T>::operator[](uint32_t index)
 {
-	//CE_ASSERT(index < m_size);
+	CE_ASSERT(index < m_size, "Index out of bounds");
 
 	return m_array[index];
 }
@@ -176,7 +168,7 @@ inline T& List<T>::operator[](uint32_t index)
 template <typename T>
 inline const T& List<T>::operator[](uint32_t index) const
 {
-	//CE_ASSERT(index < m_size);
+	CE_ASSERT(index < m_size, "Index out of bounds");
 
 	return m_array[index];
 }
@@ -243,13 +235,13 @@ inline void List<T>::set_capacity(uint32_t capacity)
 		T* tmp = m_array;
 		m_capacity = capacity;
 
-		m_array = (T*)m_allocator.allocate(capacity * sizeof(T));
+		m_array = (T*)m_allocator->allocate(capacity * sizeof(T), CE_ALIGNOF(T));
 
 		memcpy(m_array, tmp, m_size * sizeof(T));
 
 		if (tmp)
 		{
-			m_allocator.deallocate(tmp);
+			m_allocator->deallocate(tmp);
 		}
 	}
 }
@@ -326,7 +318,7 @@ inline const List<T>& List<T>::operator=(const List<T>& other)
 {
 	if (m_array)
 	{
-		m_allocator.deallocate(m_array);
+		m_allocator->deallocate(m_array);
 	}
 
 	m_size = other.m_size;
@@ -334,7 +326,7 @@ inline const List<T>& List<T>::operator=(const List<T>& other)
 
 	if (m_capacity)
 	{
-		m_array = (T*)m_allocator.allocate(m_capacity * sizeof(T));
+		m_array = (T*)m_allocator->allocate(m_capacity * sizeof(T), CE_ALIGNOF(T));
 
 		memcpy(m_array, other.m_array, m_size * sizeof(T));
 	}

+ 426 - 0
engine/core/containers/Vector.h

@@ -0,0 +1,426 @@
+/*
+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.
+*/
+
+#pragma once
+
+#include "Allocator.h"
+#include "Types.h"
+#include "Assert.h"
+
+namespace crown
+{
+
+/// Dynamic array of objects.
+/// @note
+/// Calls constructors and destructors, not suitable for performance-critical stuff.
+/// If your data is POD, use List<T> instead.
+template <typename T>
+class Vector
+{
+public:
+
+	/// Does not allocate memory.
+						Vector(Allocator& allocator);
+
+	/// Allocates capacity * sizeof(T) bytes.
+						Vector(Allocator& allocator, uint32_t capacity);
+						Vector(const Vector<T>& other);
+						~Vector();
+
+	/// Random access by index
+	T&					operator[](uint32_t index);
+
+	/// Random access by index
+	const T&			operator[](uint32_t index) const;
+
+	/// Returns whether the vector is empty
+	bool				empty() const;
+
+	/// Returns the number of items in the vector
+	uint32_t			size() const;
+
+	/// Returns the maximum number of items the array can hold
+	uint32_t			capacity() const;
+
+	/// Resizes the vector to the given @a size.
+	/// @note
+	/// Old items will be copied to the newly created vector.
+	/// If the new capacity is smaller than the previous one, the
+	/// vector will be truncated.
+	void				resize(uint32_t size);
+
+	/// Reserves space in the vector for at least @a capacity items.
+	void				reserve(uint32_t capacity);
+
+	/// Sets the vector capacity
+	void				set_capacity(uint32_t capacity);
+
+	/// Grows the vector to contain at least @a min_capacity items
+	void				grow(uint32_t min_capacity);
+
+	/// Condenses the array so that the capacity matches the actual number
+	/// of items in the vector.
+	void				condense();
+
+	/// Appends an item to the vector and returns its index.
+	uint32_t			push_back(const T& item);
+
+	/// Removes the last item from the vector.
+	void				pop_back();
+
+	/// Appends @a count @a items to the vector and returns the number
+	/// of items in the vector after the append operation.
+	uint32_t			push(const T* items, uint32_t count);
+
+	/// Clears the content of the vector.
+	/// @note
+	/// Does not free memory nor call destructors, it only zeroes
+	/// the number of items in the vector for efficiency.
+	void				clear();
+
+	/// Copies the content of the @a other vector into this one.
+	const Vector<T>&		operator=(const Vector<T>& other);
+
+	T*					begin();
+	const T*			begin() const;
+	T*					end();
+	const T*			end() const;
+
+	T&					front();
+	const T&			front() const;
+	T&					back();
+	const T&			back() const;
+
+private:
+
+	Allocator*			m_allocator;
+	uint32_t			m_capacity;
+	uint32_t			m_size;
+	T*					m_array;
+};
+
+//-----------------------------------------------------------------------------
+template <typename T>
+inline Vector<T>::Vector(Allocator& allocator)
+	: m_allocator(&allocator), m_capacity(0), m_size(0), m_array(NULL)
+{
+}
+
+//-----------------------------------------------------------------------------
+template <typename T>
+inline Vector<T>::Vector(Allocator& allocator, uint32_t capacity)
+	: m_allocator(&allocator), m_capacity(0), m_size(0), m_array(NULL)
+{
+	resize(capacity);
+}
+
+//-----------------------------------------------------------------------------
+template <typename T>
+inline Vector<T>::Vector(const Vector<T>& other)
+	: m_allocator(other.m_allocator), m_capacity(0), m_size(0), m_array(NULL)
+{
+	*this = other;
+}
+
+//-----------------------------------------------------------------------------
+template <typename T>
+inline Vector<T>::~Vector()
+{
+	if (m_array)
+	{
+		for (uint32_t i = 0; i < m_size; i++)
+		{
+			m_array[i].~T();
+		}
+		m_allocator->deallocate(m_array);
+	}
+}
+
+//-----------------------------------------------------------------------------
+template <typename T>
+inline T& Vector<T>::operator[](uint32_t index)
+{
+	CE_ASSERT(index < m_size, "Index out of bounds");
+
+	return m_array[index];
+}
+
+//-----------------------------------------------------------------------------
+template <typename T>
+inline const T& Vector<T>::operator[](uint32_t index) const
+{
+	CE_ASSERT(index < m_size, "Index out of bounds");
+
+	return m_array[index];
+}
+
+//-----------------------------------------------------------------------------
+template <typename T>
+inline bool Vector<T>::empty() const
+{
+	return m_size == 0;
+}
+
+//-----------------------------------------------------------------------------
+template <typename T>
+inline uint32_t Vector<T>::size() const
+{
+	return m_size;
+}
+
+//-----------------------------------------------------------------------------
+template <typename T>
+inline uint32_t Vector<T>::capacity() const
+{
+	return m_capacity;
+}
+
+//-----------------------------------------------------------------------------
+template <typename T>
+inline void Vector<T>::resize(uint32_t size)
+{
+	if (size > m_capacity)
+	{
+		set_capacity(size);
+	}
+
+	m_size = size;
+}
+
+//-----------------------------------------------------------------------------
+template <typename T>
+inline void Vector<T>::reserve(uint32_t capacity)
+{
+	if (capacity > m_capacity)
+	{
+		grow(capacity);
+	}
+}
+
+//-----------------------------------------------------------------------------
+template <typename T>
+inline void Vector<T>::set_capacity(uint32_t capacity)
+{
+	if (capacity == m_capacity)
+	{
+		return;
+	}
+
+	if (capacity < m_size)
+	{
+		resize(capacity);
+	}
+
+	if (capacity > 0)
+	{
+		T* tmp = m_array;
+		m_capacity = capacity;
+
+		m_array = (T*)m_allocator->allocate(capacity * sizeof(T));
+
+		for (uint32_t i = 0; i < m_size; i++)
+		{
+			new (m_array + i) T(tmp[i]);
+		}
+
+		if (tmp)
+		{
+			for (uint32_t i = 0; i < m_size; i++)
+			{
+				tmp[i].~T();
+			}
+			m_allocator->deallocate(tmp);
+		}
+	}
+}
+
+//-----------------------------------------------------------------------------
+template <typename T>
+inline void Vector<T>::grow(uint32_t min_capacity)
+{
+	uint32_t new_capacity = m_capacity * 2 + 1;
+
+	if (new_capacity < min_capacity)
+	{
+		new_capacity = min_capacity;
+	}
+
+	set_capacity(new_capacity);
+}
+
+//-----------------------------------------------------------------------------
+template <typename T>
+inline void Vector<T>::condense()
+{
+	resize(m_size);
+}
+
+//-----------------------------------------------------------------------------
+template <typename T>
+inline uint32_t Vector<T>::push_back(const T& item)
+{
+	if (m_capacity == m_size)
+	{
+		grow(0);
+	}
+
+	new (m_array + m_size) T(item);
+
+	return m_size++;
+}
+
+//-----------------------------------------------------------------------------
+template <typename T>
+inline void Vector<T>::pop_back()
+{
+	CE_ASSERT(m_size > 0, "The vector is empty");
+
+	m_size--;
+}
+
+//-----------------------------------------------------------------------------
+template <typename T>
+inline uint32_t Vector<T>::push(const T* items, uint32_t count)
+{
+	if (m_capacity <= m_size + count)
+	{
+		grow(m_size + count);
+	}
+
+	T* arr = &m_array[m_size];
+	for (uint32_t i = 0; i < count; i++)
+	{
+		arr[i] = items[i];
+	}
+
+	m_size += count;
+
+	return m_size;
+}
+
+//-----------------------------------------------------------------------------
+template <typename T>
+inline void Vector<T>::clear()
+{
+	for (uint32_t i = 0; i < m_size; i++)
+	{
+		m_array[i].~T();
+	}
+
+	m_size = 0;
+}
+
+//-----------------------------------------------------------------------------
+template <typename T>
+inline const Vector<T>& Vector<T>::operator=(const Vector<T>& other)
+{
+	if (m_array)
+	{
+		m_allocator->deallocate(m_array);
+	}
+
+	m_size = other.m_size;
+	m_capacity = other.m_capacity;
+
+	if (m_capacity)
+	{
+		m_array = (T*)m_allocator->allocate(m_capacity * sizeof(T));
+
+		for (uint32_t i = 0; i < m_size; i++)
+		{
+			m_array[i] = other.m_array[i];
+		}
+	}
+
+	return *this;
+}
+
+//-----------------------------------------------------------------------------
+template <typename T>
+inline const T* Vector<T>::begin() const
+{
+	return m_array;
+}
+
+//-----------------------------------------------------------------------------
+template <typename T>
+inline T* Vector<T>::begin()
+{
+	return m_array;
+}
+
+//-----------------------------------------------------------------------------
+template <typename T>
+inline const T* Vector<T>::end() const
+{
+	return m_array + m_size;
+}
+
+//-----------------------------------------------------------------------------
+template <typename T>
+inline T* Vector<T>::end()
+{
+	return m_array + m_size;
+}
+
+//-----------------------------------------------------------------------------
+template <typename T>
+inline T& Vector<T>::front()
+{
+	CE_ASSERT(m_size > 0, "The vector is empty");
+
+	return m_array[0];
+}
+
+//-----------------------------------------------------------------------------
+template <typename T>
+inline const T& Vector<T>::front() const
+{
+	CE_ASSERT(m_size > 0, "The vector is empty");
+
+	return m_array[0];
+}
+
+//-----------------------------------------------------------------------------
+template <typename T>
+inline T& Vector<T>::back()
+{
+	CE_ASSERT(m_size > 0, "The vector is empty");
+
+	return m_array[m_size - 1];
+}
+
+//-----------------------------------------------------------------------------
+template <typename T>
+inline const T& Vector<T>::back() const
+{
+	CE_ASSERT(m_size > 0, "The vector is empty");
+
+	return m_array[m_size - 1];
+}
+
+} // namespace crown
+

+ 66 - 10
engine/core/filesystem/BinaryReader.h

@@ -36,20 +36,76 @@ class BinaryReader
 {
 public:
 
-						BinaryReader(File& file);
+	//-----------------------------------------------------------------------------
+	BinaryReader(File& file) : m_file(file) {}
 
-	int8_t				read_byte();
-	int16_t				read_int16();
-	uint16_t			read_uint16();
-	int32_t				read_int32();
-	uint32_t			read_uint32();
-	int64_t				read_int64();
-	float				read_float();
-	double				read_double();
+	//-----------------------------------------------------------------------------
+	int8_t read_byte()
+	{
+		int8_t buffer;
+		m_file.read(&buffer, sizeof(int8_t));
+		return buffer;
+	}
+
+	//-----------------------------------------------------------------------------
+	int16_t read_int16()
+	{
+		int16_t buffer;
+		m_file.read(&buffer, sizeof(int16_t));
+		return buffer;
+	}
+
+	//-----------------------------------------------------------------------------
+	uint16_t read_uint16()
+	{
+		uint16_t buffer;
+		m_file.read(&buffer, sizeof(uint16_t));
+		return buffer;
+	}
+
+	//-----------------------------------------------------------------------------
+	int32_t read_int32()
+	{
+		int32_t buffer;
+		m_file.read(&buffer, sizeof(int32_t));
+		return buffer;
+	}
+
+	//-----------------------------------------------------------------------------
+	uint32_t read_uint32()
+	{
+		uint32_t buffer;
+		m_file.read(&buffer, sizeof(uint32_t));
+		return buffer;
+	}
+
+	//-----------------------------------------------------------------------------
+	int64_t read_int64()
+	{
+		int64_t buffer;
+		m_file.read(&buffer, sizeof(int64_t));
+		return buffer;
+	}
+
+	//-----------------------------------------------------------------------------
+	double read_double()
+	{
+		double buffer;
+		m_file.read(&buffer, sizeof(double));
+		return buffer;
+	}
+
+	//-----------------------------------------------------------------------------
+	float read_float()
+	{
+		float buffer;
+		m_file.read(&buffer, sizeof(float));
+		return buffer;
+	}
 
 private:
 
-	File&				m_file;
+	File& m_file;
 };
 
 } // namespace crown

+ 50 - 10
engine/core/filesystem/BinaryWriter.h

@@ -36,20 +36,60 @@ class BinaryWriter
 {
 public:
 
-						BinaryWriter(File& file);
+	//-----------------------------------------------------------------------------
+	BinaryWriter(File& file) : m_file(file) {}
 
-	void				write_byte(int8_t);
-	void				write_int16(int16_t);
-	void				write_uint16(uint16_t);
-	void				write_int32(int32_t);
-	void				write_uint32(uint32_t);
-	void				write_int64(int64_t);
-	void				write_double(double);
-	void				write_float(float);
+	//-----------------------------------------------------------------------------
+	void write_byte(int8_t buffer)
+	{
+		m_file.write(&buffer, sizeof(int8_t));
+	}
+
+	//-----------------------------------------------------------------------------
+	void write_int16(int16_t buffer)
+	{
+		m_file.write(&buffer, sizeof(int16_t));
+	}
+
+	//-----------------------------------------------------------------------------
+	void write_uint16(uint16_t buffer)
+	{
+		m_file.write(&buffer, sizeof(uint16_t));
+	}
+
+	//-----------------------------------------------------------------------------
+	void write_int32(int32_t buffer)
+	{
+		m_file.write(&buffer, sizeof(int32_t));
+	}
+
+	//-----------------------------------------------------------------------------
+	void write_uint32(uint32_t buffer)
+	{
+		m_file.write(&buffer, sizeof(uint32_t));
+	}
+
+	//-----------------------------------------------------------------------------
+	void write_int64(int64_t buffer)
+	{
+		m_file.write(&buffer, sizeof(int64_t));
+	}
+
+	//-----------------------------------------------------------------------------
+	void write_double(double buffer)
+	{
+		m_file.write(&buffer, sizeof(double));
+	}
+
+	//-----------------------------------------------------------------------------
+	void write_float(float buffer)
+	{
+		m_file.write(&buffer, sizeof(float));
+	}
 
 private:
 
-	File&				m_file;
+	File& m_file;
 };
 
 } // namespace crown

+ 2 - 2
engine/core/filesystem/DiskFile.cpp

@@ -83,7 +83,7 @@ void DiskFile::read(void* buffer, size_t size)
 	}
 
 	size_t bytes_read = m_file.read(buffer, size);
-	CE_ASSERT(bytes_read == size, "Failed to read from file");
+	CE_ASSERT(bytes_read == size, "Failed to read from file: requested: %lu, read: %lu", size, bytes_read);
 }
 
 //-----------------------------------------------------------------------------
@@ -98,7 +98,7 @@ void DiskFile::write(const void* buffer, size_t size)
 	}
 
 	size_t bytes_written = m_file.write(buffer, size);
-	CE_ASSERT(bytes_written == size, "Failed to write to file");
+	CE_ASSERT(bytes_written == size, "Failed to write to file: requested: %lu, written: %lu", size, bytes_written);
 }
 
 //-----------------------------------------------------------------------------

+ 168 - 0
engine/core/filesystem/DiskFilesystem.cpp

@@ -0,0 +1,168 @@
+/*
+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 "DiskFilesystem.h"
+#include "StringUtils.h"
+#include "TempAllocator.h"
+#include "DiskFile.h"
+#include "OS.h"
+
+namespace crown
+{
+
+//-----------------------------------------------------------------------------
+DiskFilesystem::DiskFilesystem()
+{
+	string::strncpy(m_root_path, os::get_cwd(), MAX_PATH_LENGTH);
+}
+
+//-----------------------------------------------------------------------------
+DiskFilesystem::DiskFilesystem(const char* root_path)
+{
+	CE_ASSERT_NOT_NULL(root_path);
+
+	string::strncpy(m_root_path, root_path, MAX_PATH_LENGTH);
+}
+
+//-----------------------------------------------------------------------------
+File* DiskFilesystem::open(const char* path, FileOpenMode mode)
+{
+	CE_ASSERT_NOT_NULL(path);
+
+	TempAllocator256 alloc;
+	DynamicString abs_path(alloc);
+	get_absolute_path(path, abs_path);
+
+	return CE_NEW(default_allocator(), DiskFile)(mode, abs_path.c_str());
+}
+
+//-----------------------------------------------------------------------------
+void DiskFilesystem::close(File* file)
+{
+	CE_ASSERT_NOT_NULL(file);
+
+	CE_DELETE(default_allocator(), file);
+}
+
+//-----------------------------------------------------------------------------
+bool DiskFilesystem::is_directory(const char* path)
+{
+	CE_ASSERT_NOT_NULL(path);
+
+	TempAllocator256 alloc;
+	DynamicString abs_path(alloc);
+	get_absolute_path(path, abs_path);
+
+	return os::is_directory(abs_path.c_str());
+}
+
+//-----------------------------------------------------------------------------
+bool DiskFilesystem::is_file(const char* path)
+{
+	CE_ASSERT_NOT_NULL(path);
+
+	TempAllocator256 alloc;
+	DynamicString abs_path(alloc);
+	get_absolute_path(path, abs_path);
+
+	return os::is_file(abs_path.c_str());
+}
+
+//-----------------------------------------------------------------------------
+void DiskFilesystem::create_directory(const char* path)
+{
+	CE_ASSERT_NOT_NULL(path);
+
+	TempAllocator256 alloc;
+	DynamicString abs_path(alloc);
+	get_absolute_path(path, abs_path);
+
+	os::create_directory(abs_path.c_str());
+}
+
+//-----------------------------------------------------------------------------
+void DiskFilesystem::delete_directory(const char* path)
+{
+	CE_ASSERT_NOT_NULL(path);
+
+	TempAllocator256 alloc;
+	DynamicString abs_path(alloc);
+	get_absolute_path(path, abs_path);
+
+	os::delete_directory(abs_path.c_str());
+}
+
+//-----------------------------------------------------------------------------
+void DiskFilesystem::create_file(const char* path)
+{
+	CE_ASSERT_NOT_NULL(path);
+
+	TempAllocator256 alloc;
+	DynamicString abs_path(alloc);
+	get_absolute_path(path, abs_path);
+
+	os::create_file(abs_path.c_str());
+}
+
+//-----------------------------------------------------------------------------
+void DiskFilesystem::delete_file(const char* path)
+{
+	CE_ASSERT_NOT_NULL(path);
+
+	TempAllocator256 alloc;
+	DynamicString abs_path(alloc);
+	get_absolute_path(path, abs_path);
+
+	os::delete_file(abs_path.c_str());
+}
+
+//-----------------------------------------------------------------------------
+void DiskFilesystem::list_files(const char* path, Vector<DynamicString>& files)
+{
+	CE_ASSERT_NOT_NULL(path);
+
+	TempAllocator256 alloc;
+	DynamicString abs_path(alloc);
+	get_absolute_path(path, abs_path);
+
+	os::list_files(abs_path.c_str(), files);
+}
+
+//-----------------------------------------------------------------------------
+void DiskFilesystem::get_absolute_path(const char* path, DynamicString& os_path)
+{
+	if (os::is_absolute_path(path))
+	{
+		os_path = path;
+		return;
+	}
+
+	os_path += m_root_path;
+	os_path += PATH_SEPARATOR;
+	os_path += path;
+}
+
+} // namespace crown

+ 91 - 0
engine/core/filesystem/DiskFilesystem.h

@@ -0,0 +1,91 @@
+/*
+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.
+*/
+
+#pragma once
+
+#include "Filesystem.h"
+#include "OS.h" // For MAX_PATH_LENGTH
+
+namespace crown
+{
+
+/// Access files on disk.
+/// All the file paths can be either relative or absolute.
+/// When a relative path is given, it is automatically translated
+/// to its absolute counterpart based on the file source's root path.
+/// Accessing files using absolute path directly is also possible,
+/// but platform-specific and thus generally not recommended.
+class DiskFilesystem : public Filesystem
+{
+public:
+
+	/// Sets the root path to the current working directory of
+	/// the engine executable.
+	DiskFilesystem();
+
+	/// Sets the root path to the given @a root_path.
+	/// @note
+	/// The @a root_path must be absolute.
+	DiskFilesystem(const char* root_path);
+
+	/// Opens the file at the given @a path with the given @a mode.
+	File* open(const char* path, FileOpenMode mode);
+
+	/// Closes the given @a file.
+	void close(File* file);
+
+	/// Returns true if @a path is a directory.
+	bool is_directory(const char* path);
+
+	/// Returns true if @a path is a regular file.
+	bool is_file(const char* path);
+
+	/// Creates the directory at the given @a path.
+	void create_directory(const char* path);
+
+	/// Deletes the directory at the given @a path.
+	void delete_directory(const char* path);
+
+	/// Creates the file at the given @a path.
+	void create_file(const char* path);
+
+	/// Deletes the file at the given @a path.
+	void delete_file(const char* path);
+
+	/// Returns the relative file names in the given @a path.
+	void list_files(const char* path, Vector<DynamicString>& files);
+
+	/// Returns the absolute path of the given @a path based on
+	/// the root path of the file source. If @a path is absolute,
+	/// the given path is returned.
+	void get_absolute_path(const char* path, DynamicString& os_path);
+
+private:
+
+	char m_root_path[MAX_PATH_LENGTH];
+};
+
+} // namespace crown

+ 0 - 205
engine/core/filesystem/Filesystem.cpp

@@ -1,205 +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 "Filesystem.h"
-#include "Log.h"
-#include "OS.h"
-#include "DiskFile.h"
-#include "Memory.h"
-
-namespace crown
-{
-
-//-----------------------------------------------------------------------------
-Filesystem::Filesystem(const char* root_path)
-{
-	CE_ASSERT(root_path != NULL, "Root path must be != NULL");
-	CE_ASSERT(os::is_absolute_path(root_path), "Root path must be absolute");
-
-	string::strncpy(m_root_path, root_path, MAX_PATH_LENGTH);
-}
-
-//-----------------------------------------------------------------------------
-Filesystem::~Filesystem()
-{
-}
-
-//-----------------------------------------------------------------------------
-const char* Filesystem::root_path() const
-{
-	return m_root_path;
-}
-
-//-----------------------------------------------------------------------------
-const char* Filesystem::build_os_path(const char* base_path, const char* relative_path)
-{
-	static char os_path[MAX_PATH_LENGTH];
-
-	string::strncpy(os_path, base_path, MAX_PATH_LENGTH);
-
-	size_t base_path_len = string::strlen(base_path);
-
-	os_path[base_path_len] = PATH_SEPARATOR;
-	os_path[base_path_len + 1] = '\0';
-
-	string::strcat(os_path, relative_path);
-
-	// FIXME FIXME FIXME Replace Crown-specific path separator with OS-speficic one
-	for (size_t j = 0; j < string::strlen(os_path); j++)
-	{
-		if (os_path[j] == '/')
-		{
-			os_path[j] = PATH_SEPARATOR;
-		}
-	}
-
-	return os_path;
-}
-
-//-----------------------------------------------------------------------------
-bool Filesystem::get_info(const char* relative_path, FilesystemEntry& info)
-{
-	// Entering OS-DEPENDENT-PATH-MODE
-	// (i.e. os_path is of the form: C:\foo\relative_path or /foo/relative_path)
-
-	const char* os_path = build_os_path(m_root_path, relative_path);
-	
-	string::strncpy(info.os_path, os_path, MAX_PATH_LENGTH);
-	string::strncpy(info.relative_path, relative_path, MAX_PATH_LENGTH);
-
-	if (os::is_reg(os_path))
-	{
-		info.type = FilesystemEntry::FILE;
-		return true;
-	}
-	else if (os::is_dir(os_path))
-	{
-		info.type = FilesystemEntry::DIRECTORY;
-		return true;
-	}
-	
-	info.type = FilesystemEntry::UNKNOWN;
-
-	return false;
-}
-
-//-----------------------------------------------------------------------------
-bool Filesystem::exists(const char* relative_path)
-{
-	FilesystemEntry dummy;
-
-	return get_info(relative_path, dummy);
-}
-
-//-----------------------------------------------------------------------------
-bool Filesystem::is_file(const char* relative_path)
-{
-	FilesystemEntry info;
-
-	if (get_info(relative_path, info))
-	{
-		return info.type == FilesystemEntry::FILE;
-	}
-
-	return false;
-}
-
-//-----------------------------------------------------------------------------
-bool Filesystem::is_dir(const char* relative_path)
-{
-	FilesystemEntry info;
-
-	if (get_info(relative_path, info))
-	{
-		return info.type == FilesystemEntry::DIRECTORY;
-	}
-
-	return false;
-}
-
-//-----------------------------------------------------------------------------
-bool Filesystem::create_file(const char* relative_path)
-{
-	const char* os_path = build_os_path(m_root_path, relative_path);
-
-	return os::mknod(os_path);
-}
-
-//-----------------------------------------------------------------------------
-bool Filesystem::create_dir(const char* relative_path)
-{
-	const char* os_path = build_os_path(m_root_path, relative_path);
-
-	return os::mkdir(os_path);
-}
-
-//-----------------------------------------------------------------------------
-bool Filesystem::delete_file(const char* relative_path)
-{
-	const char* os_path = build_os_path(m_root_path, relative_path);
-
-	return os::unlink(os_path);
-}
-
-//-----------------------------------------------------------------------------
-bool Filesystem::delete_dir(const char* relative_path)
-{
-	const char* os_path = build_os_path(m_root_path, relative_path);
-
-	return os::rmdir(os_path);
-}
-
-//-----------------------------------------------------------------------------
-const char* Filesystem::os_path(const char* relative_path)
-{
-	static char os_path[MAX_PATH_LENGTH];
-
-	FilesystemEntry entry;
-
-	get_info(relative_path, entry);
-
-	string::strncpy(os_path, entry.os_path, MAX_PATH_LENGTH);
-
-	return os_path;
-}
-
-//-----------------------------------------------------------------------------
-DiskFile* Filesystem::open(const char* relative_path, FileOpenMode mode)
-{
-	CE_ASSERT(exists(relative_path), "File does not exist: %s", relative_path);
-	CE_ASSERT(is_file(relative_path), "File is not a regular file: %s", relative_path);
-
-	return CE_NEW(m_allocator, DiskFile)(mode, os_path(relative_path));
-}
-
-//-----------------------------------------------------------------------------
-void Filesystem::close(DiskFile* stream)
-{
-	CE_DELETE(m_allocator, stream);
-}
-
-} // namespace crown
-

+ 26 - 67
engine/core/filesystem/Filesystem.h

@@ -26,33 +26,13 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 #pragma once
 
-#include "StringUtils.h"
-#include "OS.h"
 #include "File.h"
-#include "HeapAllocator.h"
+#include "Vector.h"
+#include "DynamicString.h"
 
 namespace crown
 {
 
-struct FilesystemEntry
-{
-	enum Type
-	{
-		DIRECTORY = 0,		///< The entry is a directory
-		FILE,				///< The entry is a file
-		MEMORY,				///< The entry is a memory file (i.e. does not exist on the disk)
-		UNKNOWN				///< The entry type is unknown
-	};
-
-	FilesystemEntry() : type(UNKNOWN) {}
-
-	Type			type;								///< Type of the entry
-	char			os_path[MAX_PATH_LENGTH];			///< OS-specific path (use only for debug)
-	char			relative_path[MAX_PATH_LENGTH];		///< Relative path of the entry
-};
-
-class DiskFile;
-
 /// Provides a platform-independent way to access files and directories
 /// on the host filesystem.
 ///
@@ -102,67 +82,46 @@ class Filesystem
 {
 public:
 
-	/// The @a root_path must be absolute.
-						Filesystem(const char* root_path);
-						~Filesystem();
-
-	/// Returns the root path of the filesystem
-	const char*			root_path() const;
+						Filesystem() {};
+	virtual				~Filesystem() {};
 
-	/// Returns whether the @a relative_path exists and fills @a info with
-	/// with informations about the given @a relative_path path
-	bool				get_info(const char* relative_path, FilesystemEntry& info);
-	
-	/// Returns whether the @a relative_path exists on disk
-	bool				exists(const char* relative_path);
+	/// Opens the file at the given @a path with the given @a mode.
+	virtual File*		open(const char* path, FileOpenMode mode) = 0;
 
-	/// Returns whether @a relative_path is a regular file
-	bool				is_file(const char* relative_path);
+	/// Closes the given @a file.
+	virtual void		close(File* file) = 0;
 
-	/// Returns whether @a relative_path is a directory
-	bool				is_dir(const char* relative_path);
+	/// Returns true if @a path is a directory.
+	virtual bool		is_directory(const char* path) = 0;
 
-	/// Creates a regular file named @a relative_path
-	bool				create_file(const char* relative_path);
+	/// Returns true if @a path is a regular file.
+	virtual bool		is_file(const char* path) = 0;
 
-	/// Creates a directory named @a relative_path
-	bool				create_dir(const char* relative_path);
+	/// Creates the directory at the given @a path.
+	virtual void		create_directory(const char* path) = 0;
 
-	/// Deletes the regular file @a relative_path
-	bool				delete_file(const char* relative_path);
+	/// Deletes the directory at the given @a path.
+	virtual void		delete_directory(const char* path) = 0;
 
-	/// Deletes the directory @a relative_path
-	bool				delete_dir(const char* relative_path);
+	/// Creates the file at the given @a path.
+	virtual void		create_file(const char* path) = 0;
 
-	/// Returns the os-specific path which @a relative_path refers to.
-	/// @note
-	/// In general, you typically do not want to use it for normal
-	/// file interactions. Prefer using the other methods whenever possible.
-	const char*			os_path(const char* relative_path);
+	/// Deletes the file at the given @a path.
+	virtual void		delete_file(const char* path) = 0;
 
-	/// Opens the file @a relative_path with the specified access @a mode
-	DiskFile*			open(const char* relative_path, FileOpenMode mode);
+	/// Returns the relative file names in the given @a path.
+	virtual void		list_files(const char* path, Vector<DynamicString>& files) = 0;
 
-	/// Closes a previously opened file @a stream
-	void				close(DiskFile* stream);
+	/// Returns the absolute path of the given @a path based on
+	/// the root path of the file source. If @a path is absolute,
+	/// the given path is returned.
+	virtual void		get_absolute_path(const char* path, DynamicString& os_path) = 0;
 
 private:
 
-	// Builds the OS-dependent path from base_path and relative_path
-	const char*			build_os_path(const char* base_path, const char* relative_path);
-	
-private:
-
-	HeapAllocator		m_allocator;
-
-	char				m_root_path[MAX_PATH_LENGTH];
-
 	// Disable copying
 						Filesystem(const Filesystem&);
 	Filesystem&			operator=(const Filesystem&);
-
-	friend class		Device;
 };
 
 } // namespace crown
-

+ 0 - 64
engine/core/filesystem/TextReader.cpp

@@ -1,64 +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 "TextReader.h"
-#include "File.h"
-#include "Types.h"
-
-namespace crown
-{
-
-//-----------------------------------------------------------------------------
-TextReader::TextReader(File& file) : m_file(file)
-{
-}
-
-//-----------------------------------------------------------------------------
-size_t TextReader::read_string(char* string, size_t size)
-{
-	char current_char;
-	size_t bytes_read = 0;
-
-	while(!m_file.end_of_file() && bytes_read < size - 1)
-	{
-		m_file.read(&current_char, 1);
-		string[bytes_read] = current_char;
-
-		bytes_read++;
-
-		if (current_char == '\n')
-		{
-			break;
-		}
-	}
-
-	string[bytes_read] = '\0';
-
-	return bytes_read;
-}
-
-} // namespace crown
-

+ 27 - 3
engine/core/filesystem/TextReader.h

@@ -36,7 +36,10 @@ class TextReader
 {
 public:
 
-						TextReader(File& file);
+	//-----------------------------------------------------------------------------
+	TextReader(File& file) : m_file(file)
+	{
+	}
 
 	/// Reads characters from file and stores them as a C string
 	/// into string until (size-1) characters have been read or
@@ -46,11 +49,32 @@ public:
 	/// a valid character and therefore it is included in the string copied to string.
 	/// A null character is automatically appended in str after the characters read to
 	/// signal the end of the C string.
-	size_t				read_string(char* string, size_t size);
+	size_t read_string(char* string, size_t size)
+	{
+		char current_char;
+		size_t bytes_read = 0;
+
+		while(!m_file.end_of_file() && bytes_read < size - 1)
+		{
+			m_file.read(&current_char, 1);
+			string[bytes_read] = current_char;
+
+			bytes_read++;
+
+			if (current_char == '\n')
+			{
+				break;
+			}
+		}
+
+		string[bytes_read] = '\0';
+
+		return bytes_read;
+	}
 
 private:
 
-	File&				m_file;
+	File& m_file;
 };
 
 } // namespace crown

+ 10 - 4
engine/core/filesystem/TextWriter.h

@@ -34,17 +34,23 @@ class TextWriter
 {
 public:
 
-						TextWriter(File& file);
-	
+	//-----------------------------------------------------------------------------
+	TextWriter(File& file) : m_file(file)
+	{
+	}
+
 	/// Writes the string pointed by string to the file.
 	/// The function begins copying from the address specified (string)
 	/// until it reaches the terminating null character ('\0').
 	/// The final null character is not copied to the file.
-	void				write_string(const char* string);
+	void write_string(const char* string)
+	{
+		m_file.write(string, string::strlen(string));
+	}
 
 private:
 
-	File&				m_file;
+	File& m_file;
 };
 
 } // namespace crown

+ 52 - 20
engine/core/json/JSONParser.cpp

@@ -192,26 +192,42 @@ static bool is_escapee(char c)
 }
 
 //--------------------------------------------------------------------------
-JSONElement::JSONElement() :
-	m_parser(NULL),
-	m_at(NULL)
+JSONElement::JSONElement()
+	: m_parser(NULL), m_begin(NULL), m_at(NULL)
 {
 }
 
 //--------------------------------------------------------------------------
-JSONElement::JSONElement(JSONParser& parser, const char* at) :
-	m_parser(&parser),
-	m_at(at)
+JSONElement::JSONElement(JSONParser& parser, const char* at)
+	: m_parser(&parser), m_begin(at), m_at(at)
 {
 }
 
+//--------------------------------------------------------------------------
+JSONElement::JSONElement(const JSONElement& other)
+	: m_parser(other.m_parser), m_begin(other.m_at), m_at(other.m_at)
+{
+}
+
+//--------------------------------------------------------------------------
+JSONElement& JSONElement::operator=(const JSONElement& other)
+{
+	m_parser = other.m_parser;
+
+	// Our begin is the other's at
+	m_begin = other.m_at;
+	m_at = other.m_at;
+
+	return *this;
+}
+
 //--------------------------------------------------------------------------
 JSONElement& JSONElement::operator[](uint32_t i)
 {
 	TempAllocator1024 alloc;
 	List<const char*> array(alloc);
 
-	JSONParser::parse_array(m_at, array);
+	JSONParser::parse_array(m_begin, array);
 
 	CE_ASSERT(i < array.size(), "Index out of bounds");
 
@@ -232,7 +248,7 @@ JSONElement& JSONElement::key(const char* k)
 	TempAllocator1024 alloc;
 	List<JSONPair> object(alloc);
 
-	JSONParser::parse_object(m_at, object);
+	JSONParser::parse_object(m_begin, object);
 
 	bool found = false;
 
@@ -260,7 +276,7 @@ bool JSONElement::has_key(const char* k) const
 {
 	TempAllocator1024 alloc;
 	List<JSONPair> object(alloc);
-	JSONParser::parse_object(m_at, object);
+	JSONParser::parse_object(m_begin, object);
 
 	for (uint32_t i = 0; i < object.size(); i++)
 	{
@@ -283,7 +299,7 @@ bool JSONElement::is_key_unique(const char* k) const
 {
 	TempAllocator1024 alloc;
 	List<JSONPair> object(alloc);
-	JSONParser::parse_object(m_at, object);
+	JSONParser::parse_object(m_begin, object);
 
 	bool found = false;
 
@@ -309,25 +325,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 +364,8 @@ const char* JSONElement::string_value() const
 
 	JSONParser::parse_string(m_at, string);
 
+	m_at = m_begin;
+
 	return string.begin();
 }
 
@@ -577,10 +607,12 @@ bool JSONParser::parse_bool(const char* s)
 			ch = next(ch, 'e');
 			return false;
 		}
-		default: break;
+		default:
+		{
+			CE_ASSERT(false, "Bad boolean");
+			return false;
+		}
 	}
-
-	CE_ASSERT(false, "Bad boolean");
 }
 
 //-----------------------------------------------------------------------------

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

@@ -63,6 +63,9 @@ public:
 	/// obtained from JSONParser::root() or copied from an
 	/// already existent and valid element.
 						JSONElement();
+						JSONElement(const JSONElement& other);
+
+	JSONElement&		operator=(const JSONElement& other);
 
 	/// Returns the @a i -th item of the current array.
 	JSONElement&		operator[](uint32_t i);
@@ -111,26 +114,27 @@ 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:
 
-						JSONElement(JSONParser& parser, const char* at);
+	explicit			JSONElement(JSONParser& parser, const char* at);
 
 	JSONParser*			m_parser;
+	const char*			m_begin;
 	const char*			m_at;
 
 	friend class 		JSONParser;

+ 17 - 18
engine/core/mem/Memory.h

@@ -28,7 +28,6 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 #include "Types.h"
 #include "Assert.h"
-#include "OS.h"
 
 namespace crown
 {
@@ -41,8 +40,8 @@ const size_t	DEFAULT_ALIGN	= 4;			//!< Default memory alignment in bytes
 /// Returns the pointer @a p aligned to the desired @a align byte
 inline void* align_top(void* p, size_t align)
 {
-	CE_ASSERT(align > 1, "Alignment must be > 1");
-	CE_ASSERT(align % 2 == 0, "Alignment must be a power of two");
+	CE_ASSERT(align >= 1, "Alignment must be > 1");
+	CE_ASSERT(align % 2 == 0 || align == 1, "Alignment must be a power of two");
 
 	uintptr_t ptr = (uintptr_t)p;
 
@@ -56,24 +55,24 @@ inline void* align_top(void* p, size_t align)
 	return (void*) ptr;
 }
 
-/// Dumps the memory content pointed by @a p
-inline void dump(void* p, size_t size, size_t word_size)
-{
-	uint8_t* mem = (uint8_t*) p;
+// /// Dumps the memory content pointed by @a p
+// inline void dump(void* p, size_t size, size_t word_size)
+// {
+// 	uint8_t* mem = (uint8_t*) p;
 
-	for (size_t i = 0; i < size; i++, mem++)
-	{
-		if (i % word_size == 0)
-		{
-			os::printf("\n");
-			os::printf("[.. %.4X] ", (size_t)mem);
-		}
+// 	for (size_t i = 0; i < size; i++, mem++)
+// 	{
+// 		if (i % word_size == 0)
+// 		{
+// 			os::printf("\n");
+// 			os::printf("[.. %.4X] ", (size_t)mem);
+// 		}
 
-		os::printf("%.2X ", *mem);
-	}
+// 		os::printf("%.2X ", *mem);
+// 	}
 
-	os::printf("\n");
-}
+// 	os::printf("\n");
+// }
 
 #ifdef _MSC_VER
 	#define CE_ALIGNOF(x) __alignof(x)

+ 229 - 0
engine/core/strings/DynamicString.h

@@ -0,0 +1,229 @@
+/*
+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.
+*/
+
+#pragma once
+
+#include <algorithm>
+#include <cstring>
+
+#include "Assert.h"
+#include "Allocator.h"
+#include "StringUtils.h"
+#include "List.h"
+
+namespace crown
+{
+
+///
+class DynamicString
+{
+public:
+
+						DynamicString(Allocator& allocator);
+						DynamicString(Allocator& allocator, const char* s);
+
+						~DynamicString();
+
+	DynamicString&		operator+=(DynamicString& s);
+	DynamicString&		operator+=(const char* s);
+	DynamicString&		operator+=(const char c);
+	///
+	DynamicString&		operator=(DynamicString& s);
+	DynamicString&		operator=(const char* s);
+	DynamicString&		operator=(const char c);
+
+	bool				operator==(DynamicString& s);
+	bool				operator==(const char* s);
+
+	/// Removes the leading string @a s.
+	/// @note
+	/// The string must start with @a s.
+	void				strip_leading(const char* s);
+
+	/// Removes the trailing string @a s.
+	/// @note
+	/// The string must end with @a s.
+	void				strip_trailing(const char* s);
+
+	/// Returns whether the string starts with the given @a s string.
+	bool				starts_with(const char* s);
+
+	/// Returns wheterh the string ends with the given @æ s string.
+	bool				ends_with(const char* s);
+
+	///
+	const char*			c_str();
+
+private:
+
+	List<char>			m_string;
+};
+
+//-----------------------------------------------------------------------------
+inline DynamicString::DynamicString(Allocator& allocator) :
+	m_string(allocator)
+{
+}
+
+//-----------------------------------------------------------------------------
+inline DynamicString::DynamicString(Allocator& allocator, const char* s) :
+	m_string(allocator)
+{
+	m_string.push(s, string::strlen(s));
+}
+
+//-----------------------------------------------------------------------------
+inline DynamicString::~DynamicString()
+{
+}
+
+//-----------------------------------------------------------------------------
+inline DynamicString& DynamicString::operator+=(DynamicString& s)
+{
+	const char* tmp = s.c_str();
+
+	return *this += tmp;
+}
+
+//-----------------------------------------------------------------------------
+inline DynamicString& DynamicString::operator+=(const char* s)
+{
+	CE_ASSERT_NOT_NULL(s);
+
+	m_string.push(s, string::strlen(s));
+
+	return *this;
+}
+
+//-----------------------------------------------------------------------------
+inline DynamicString& DynamicString::operator+=(const char c)
+{
+	m_string.push_back(c);
+
+	return *this;
+}
+
+//-----------------------------------------------------------------------------
+inline DynamicString& DynamicString::operator=(DynamicString& s)
+{
+	const char* tmp = s.c_str();
+
+	return *this = tmp;
+}
+
+//-----------------------------------------------------------------------------
+inline DynamicString& DynamicString::operator=(const char* s)
+{
+	CE_ASSERT_NOT_NULL(s);
+
+	m_string.clear();
+	m_string.push(s, string::strlen(s));
+
+	return *this;
+}
+
+//-----------------------------------------------------------------------------
+inline DynamicString& DynamicString::operator=(const char c)
+{
+	m_string.clear();
+	m_string.push_back(c);
+
+	return *this;
+}
+
+//-----------------------------------------------------------------------------
+inline bool DynamicString::operator==(DynamicString& s)
+{
+	return string::strcmp(c_str(), s.c_str()) == 0;
+}
+
+//-----------------------------------------------------------------------------
+inline bool DynamicString::operator==(const char* s)
+{
+	CE_ASSERT_NOT_NULL(s);
+
+	return string::strcmp(c_str(), s) == 0;
+}
+
+//-----------------------------------------------------------------------------
+inline void DynamicString::strip_leading(const char* s)
+{
+	CE_ASSERT_NOT_NULL(s);
+	CE_ASSERT(starts_with(s), "String does not start with %s", s);
+
+	const size_t my_len = string::strlen(c_str());
+	const size_t s_len = string::strlen(s);
+
+	memmove(m_string.begin(), m_string.begin() + s_len, (my_len - s_len));
+	m_string.resize(my_len - s_len);
+}
+
+//-----------------------------------------------------------------------------
+inline void DynamicString::strip_trailing(const char* s)
+{
+	CE_ASSERT_NOT_NULL(s);
+	CE_ASSERT(ends_with(s), "String does not end with %s", s);
+
+	const size_t my_len = string::strlen(c_str());
+	const size_t s_len = string::strlen(s);
+
+	m_string.resize(my_len - s_len);
+}
+
+//-----------------------------------------------------------------------------
+inline bool DynamicString::starts_with(const char* s)
+{
+	CE_ASSERT_NOT_NULL(s);
+
+	return string::strncmp(c_str(), s, string::strlen(s)) == 0;
+}
+
+//-----------------------------------------------------------------------------
+inline bool DynamicString::ends_with(const char* s)
+{
+	CE_ASSERT_NOT_NULL(s);
+
+	const size_t my_len = string::strlen(c_str());
+	const size_t s_len = string::strlen(s);
+
+	if (my_len >= s_len)
+	{
+		return string::strncmp(m_string.begin() + (my_len - s_len), s, s_len) == 0;
+	}
+
+	return false;
+}
+
+//-----------------------------------------------------------------------------
+inline const char* DynamicString::c_str()
+{
+	m_string.push_back('\0');
+	m_string.pop_back();
+
+	return m_string.begin();
+}
+
+} // namespace crown

+ 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)

+ 1 - 0
engine/core/strings/StringStream.h

@@ -29,6 +29,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include <stdio.h>
 #include "List.h"
 #include "StringUtils.h"
+#include "OS.h"
 
 namespace crown
 {

+ 7 - 12
engine/core/strings/StringUtils.h

@@ -72,18 +72,7 @@ inline bool is_whitespace(char c)
 //-----------------------------------------------------------------------------
 inline size_t strlen(const char* str)
 {
-	size_t chars = 0;
-
-	while(*str)
-	{
-		if ((*str & 0xC0) != 0x80)
-		{
-			chars++;
-		}
-		str++;
-	}
-
-	return chars;
+	return ::strlen(str);
 }
 
 //-----------------------------------------------------------------------------
@@ -98,6 +87,12 @@ inline int32_t strcmp(const char* str1, const char* str2)
 	return ::strcmp(str1, str2);
 }
 
+//-----------------------------------------------------------------------------
+inline int32_t strncmp(const char* s1, const char* s2, size_t len)
+{
+	return ::strncmp(s1, s2, len);
+}
+
 //-----------------------------------------------------------------------------
 inline char* strncpy(char* dest, const char* src, size_t len)
 {

+ 29 - 4
engine/lua/LuaDevice.cpp

@@ -25,6 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 */
 
 #include "Device.h"
+#include "ResourcePackage.h"
 #include "LuaEnvironment.h"
 #include "LuaStack.h"
 
@@ -71,13 +72,37 @@ CE_EXPORT int device_stop(lua_State* /*L*/)
 	return 0;
 }
 
+//-----------------------------------------------------------------------------
+CE_EXPORT int device_create_resource_package(lua_State* L)
+{
+	LuaStack stack(L);
+
+	const char* package = stack.get_string(1);
+	stack.push_lightdata(device()->create_resource_package(package));
+
+	return 1;
+}
+
+//-----------------------------------------------------------------------------
+CE_EXPORT int device_destroy_resource_package(lua_State* L)
+{
+	LuaStack stack(L);
+
+	ResourcePackage* package = (ResourcePackage*) stack.get_lightdata(1);
+	device()->destroy_resource_package(package);
+
+	return 0;
+}
+
 //-----------------------------------------------------------------------------
 void load_device(LuaEnvironment& env)
 {
-	env.load_module_function("Device", "frame_count", device_frame_count);
-	env.load_module_function("Device", "last_delta_time", device_last_delta_time);
-	env.load_module_function("Device", "start", device_start);
-	env.load_module_function("Device", "stop", device_stop);
+	env.load_module_function("Device", "frame_count",              device_frame_count);
+	env.load_module_function("Device", "last_delta_time",          device_last_delta_time);
+	env.load_module_function("Device", "start",                    device_start);
+	env.load_module_function("Device", "stop",                     device_stop);
+	env.load_module_function("Device", "create_resource_package",  device_create_resource_package);
+	env.load_module_function("Device", "destroy_resource_package", device_destroy_resource_package);
 }
 
 } // namespace crown

+ 104 - 129
engine/lua/LuaEnvironment.cpp

@@ -24,33 +24,66 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
 */
 
-
-#include "Device.h"
-#include "OS.h"
+#include <stdarg.h>
 #include "Assert.h"
-#include "Log.h"
 #include "LuaEnvironment.h"
-#include "StringSetting.h"
-#include "Filesystem.h"
+#include "StringUtils.h"
+#include "LuaStack.h"
+#include "Device.h"
+#include "LuaResource.h"
+#include "ResourceManager.h"
 
 namespace crown
 {
 
-StringSetting g_boot("boot_file", "lua main file", "lua/game.raw");
+//-----------------------------------------------------------------------------
+CE_EXPORT int luaopen_libcrown(lua_State* /*L*/)
+{
+	LuaEnvironment* env = device()->lua_environment();
 
-/*
-*N.B: Lua garbage collection is actually disabled
-*/
+	load_int_setting(*env);
+	load_float_setting(*env);
+	load_string_setting(*env);
+	load_vec2(*env);
+	load_vec3(*env);
+	load_mat4(*env);
+	load_quat(*env);
+	load_math(*env);
+	load_mouse(*env);
+	load_keyboard(*env);
+	load_accelerometer(*env);
+	load_device(*env);
+	load_window(*env);
+	load_resource_package(*env);
+
+	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()),
 	m_is_used(false)
-	//m_thread(LuaEnvironment::background_thread, (void*)this, "lua-environment-thread")
 {
 	// Open Lua default libraries
 	string::strncpy(m_error_buffer, "", 1024);
-
 	string::strncpy(m_tmp_buffer, "", 1024);
 }
 
@@ -62,16 +95,35 @@ void LuaEnvironment::init()
 	// Open Crown library
 	lua_cpcall(m_state, luaopen_libcrown, NULL);
 
-	load_buffer(class_system, string::strlen(class_system));
-	execute(0, 0);
-	load_buffer(commands_list, string::strlen(commands_list));
-	execute(0, 0);
-	load_buffer(get_cmd_by_name, string::strlen(get_cmd_by_name));
-	execute(0, 0);
-	load_buffer(tmp_print_table, string::strlen(tmp_print_table));
-	execute(0, 0);
-	load_buffer(count_all, string::strlen(count_all));
-	execute(0, 0);
+	// 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));
+	// execute(0, 0);
+	// load_buffer(get_cmd_by_name, string::strlen(get_cmd_by_name));
+	// execute(0, 0);
+	// load_buffer(tmp_print_table, string::strlen(tmp_print_table));
+	// execute(0, 0);
+	// load_buffer(count_all, string::strlen(count_all));
+	// execute(0, 0);
 
 	m_is_used = true;
 }
@@ -84,123 +136,73 @@ void LuaEnvironment::shutdown()
 	m_is_used = false;
 }
 
-//-----------------------------------------------------------------------------
-lua_State* LuaEnvironment::state()
-{
-	return m_state;
-}
-
 //-----------------------------------------------------------------------------
 const char* LuaEnvironment::error()
 {	
 	string::strncpy(m_tmp_buffer, m_error_buffer, 1024);
-
 	string::strncpy(m_error_buffer, "", 1024);
 
 	return m_tmp_buffer;
 }
 
 //-----------------------------------------------------------------------------
-void LuaEnvironment::load_buffer(const char* buffer, size_t len)
+void LuaEnvironment::load(const LuaResource* lr)
 {
-	int32_t loaded = luaL_loadbuffer(m_state, buffer, len, "");
+	CE_ASSERT_NOT_NULL(lr);
 
-	if (loaded != 0)
+	if (luaL_loadbuffer(m_state, (const char*) lr->code(), lr->size(), "") != 0)
 	{
 		lua_error();
 	}
-}
 
-//-----------------------------------------------------------------------------
-void LuaEnvironment::load_file(const char* file)
-{
-	int32_t loaded = luaL_loadfile(m_state, file);
-
-	if (loaded != 0)
+	if (lua_pcall(m_state, 0, 0, 0) != 0)
 	{
 		lua_error();
 	}
 }
 
 //-----------------------------------------------------------------------------
-void LuaEnvironment::load_string(const char* str)
+void LuaEnvironment::call_global(const char* func, uint8_t argc, ...)
 {
-	int32_t loaded = luaL_loadstring(m_state, str);
+	CE_ASSERT_NOT_NULL(func);
 
-	if (loaded != 0)
-	{
-		lua_error();
-	}
-}
+	LuaStack stack(m_state);
 
-//-----------------------------------------------------------------------------
-void LuaEnvironment::get_global_symbol(const char* symbol)
-{
-	lua_getglobal(m_state, symbol);
-}
+	va_list vl;
+	va_start(vl, argc);
 
-//-----------------------------------------------------------------------------
-void LuaEnvironment::execute(int32_t args, int32_t results)
-{
-	int32_t executed = lua_pcall(m_state, args, results, 0);
+	lua_getglobal(m_state, func);
 
-	if (executed != 0)
+	for (uint8_t i = 0; i < argc; i++)
 	{
-		lua_error();
+		const int type = va_arg(vl, int);
+		switch (type)
+		{
+			case ARGUMENT_FLOAT:
+			{
+				stack.push_float(va_arg(vl, double));
+				break;
+			}
+			default:
+			{
+				CE_ASSERT(false, "Oops, lua argument unknown");
+				break;
+			}
+		}
 	}
-}
-
-// //-----------------------------------------------------------------------------
-// void LuaEnvironment::collect_garbage()
-// {
-// 	uint64_t start = os::milliseconds();
-
-// 	while ((os::milliseconds() - start) < device()->last_delta_time() && !m_is_used)
-// 	{
-// 		lua_gc(m_state, LUA_GCSTEP, 0);
-// 	}
-// }
-
-// //-----------------------------------------------------------------------------
-// void* LuaEnvironment::background_thread(void* thiz)
-// {
-// 	((LuaEnvironment*)thiz)->collect_garbage();	
-// }
-
-//-----------------------------------------------------------------------------
-void LuaEnvironment::game_init()
-{
-	const char* path = device()->filesystem()->os_path(g_boot.value());
 
-	load_file(path);
-	execute(0, 0);
+	va_end(vl);
 
-	get_global_symbol("init");
-	execute(0, 0);
-}
-
-//-----------------------------------------------------------------------------
-void LuaEnvironment::game_shutdown()
-{
-	get_global_symbol("shutdown");
-	execute(0, 0);
-}
-
-//-----------------------------------------------------------------------------
-void LuaEnvironment::game_frame(float dt)
-{
-	LuaStack stack(m_state);
-
-	get_global_symbol("frame");
-	stack.push_float(dt);
-	execute(1, 0);
+	if (lua_pcall(m_state, argc, 0, 0) != 0)
+	{
+		lua_error();
+	}
 }
 
 //-----------------------------------------------------------------------------
 void LuaEnvironment::lua_error()
 {
 	string::strncpy(m_error_buffer, "", 1024);
-
 	string::strncpy(m_error_buffer, lua_tostring(m_state, -1), 1024);
 }
 
@@ -211,7 +213,6 @@ void LuaEnvironment::load_module_function(const char* module, const char* name,
 
 	entry[0].name = name;
 	entry[0].func = func;
-
 	entry[1].name = NULL;
 	entry[1].func = NULL;
 
@@ -225,32 +226,6 @@ void LuaEnvironment::load_module_enum(const char* /*module*/, const char* name,
 	lua_setfield(m_state, -2, name);
 }
 
-//-----------------------------------------------------------------------------
-CE_EXPORT int32_t luaopen_libcrown(lua_State* /*L*/)
-{
-	LuaEnvironment* env = device()->lua_environment();
-
-	load_int_setting(*env);
-	load_float_setting(*env);
-	load_string_setting(*env);
-
-	load_vec2(*env);
-	load_vec3(*env);
-	load_mat4(*env);
-	load_quat(*env);
-	load_math(*env);
-
-	load_mouse(*env);
-	load_keyboard(*env);
-	load_accelerometer(*env);
-
-	load_device(*env);
-
-	load_window(*env);
-
-	return 1;
-}
-
 const char* LuaEnvironment::class_system =  "function class(klass, super) "
     										"	if not klass then "
         									"		klass = {} "

+ 21 - 41
engine/lua/LuaEnvironment.h

@@ -27,15 +27,19 @@ OTHER DEALINGS IN THE SOFTWARE.
 #pragma once
 
 #include "lua.hpp"
-#include "Types.h"
 #include "Config.h"
-#include "LuaStack.h"
-#include "LinearAllocator.h"
-#include "Thread.h"
+#include "Types.h"
 
 namespace crown
 {
 
+enum LuaArgumentType
+{
+	ARGUMENT_FLOAT
+};
+
+class LuaResource;
+
 /// LuaEnvironment is a wrapper of a subset of Lua functions and 
 /// provides utilities for extending Lua
 class LuaEnvironment
@@ -48,41 +52,29 @@ public:
 	void					init();
 	/// Close Lua state and shutdown LuaEnvironment
 	void					shutdown();
-	/// Return the __lua_State__ pointer required by each Lua function
-	lua_State*				state();
 
 	const char*				error();
-	/// Load Lua chunk as buffer. @a buffer contains lua chunk, @len is length of buffer
-	void					load_buffer(const char* buffer, size_t len);
-	/// Load Lua chunk as file. @a file is path to lua file
-	void					load_file(const char* file);
-	/// Load Lua chunk as string
-	void 					load_string(const char* str);
-	/// Get global symbol from Lua stack. @symbol is the name of required symbol
-	void					get_global_symbol(const char* symbol);
-	/// Execute Lua chunk. @a args is the number of arguments required
-	/// @a results is the number of results returned
-	void					execute(int32_t args, int32_t results);
-	/// Collect garbage generated by Lua
-	void					collect_garbage();
-	/// Call init function in the Lua game file
-	void					game_init();
-	/// Call shutdown function in the Lua game file
-	void					game_shutdown();
-	/// Call frame function in the Lua game file
-	void					game_frame(float dt);
+
+	/// Loads and execute the given @a lr lua script resource.
+	void					load(const LuaResource* lr);
+
+	/// Calls the global function @a func with @a argc argument number.
+	/// Each argument is a pair (type, value).
+	/// Example call:
+	/// call_global("myfunc", 1, ARGUMENT_FLOAT, 3.14f)
+	void					call_global(const char* func, uint8_t argc, ...);
+
 	/// Load a function which will be used in Lua. @a module is the name of table contenitor,
 	/// @a name is the name of function in module and @func is the pointer to the function.
 	/// _func_ must be a C/lua function (__int32_t function_name(lua_State* L)__)
 	void					load_module_function(const char* module, const char* name, const lua_CFunction func);
+
 	/// Load a enum's value which will be used in Lua. 
 	/// @a module is the name of table contenitor, generally take  enum's name
 	/// @a name is module's name that refears _value_ and @value is an unsigned integer
 	void					load_module_enum(const char* module, const char* name, uint32_t value);
 
 private:
-	/// Thread used for garbage collection. It calls __collect_garbage()__
-	static void*			background_thread(void* thiz);
 
 	void					lua_error();
 	// Disable copying
@@ -92,28 +84,17 @@ private:
 private:
 	/// Required by each Lua function
 	lua_State*				m_state;
+
 	/// LuaEnvironment is used right now?
 	bool					m_is_used;
-	/// Thread used for garbage collection
-	// os::Thread 				m_thread;
 
 	char					m_error_buffer[1024];
-
 	char					m_tmp_buffer[1024];
-
 	static const char* 		class_system;
-
 	static const char*		commands_list;
-
 	static const char*		get_cmd_by_name;
-
 	static const char*		tmp_print_table;
-
 	static const char*		count_all;
-
-	// static const char*		type_name;
-
-	// static const char*		type_count;
 };
 
 
@@ -133,7 +114,6 @@ void load_accelerometer(LuaEnvironment& env);
 void load_camera(LuaEnvironment& env);
 void load_device(LuaEnvironment& env);
 void load_window(LuaEnvironment& env);
-
-CE_EXPORT int32_t luaopen_libcrown(lua_State* L);
+void load_resource_package(LuaEnvironment& env);
 
 } // namespace crown

+ 32 - 32
engine/core/filesystem/BinaryWriter.cpp → engine/lua/LuaResourcePackage.cpp

@@ -24,64 +24,64 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
 */
 
-#include "BinaryWriter.h"
-#include "File.h"
+#include "ResourcePackage.h"
+#include "LuaStack.h"
+#include "LuaEnvironment.h"
 
 namespace crown
 {
 
 //-----------------------------------------------------------------------------
-BinaryWriter::BinaryWriter(File& file) : m_file(file)
+CE_EXPORT int resource_package_load(lua_State* L)
 {
-}
+	LuaStack stack(L);
 
-//-----------------------------------------------------------------------------
-void BinaryWriter::write_byte(int8_t buffer)
-{
-	m_file.write(&buffer, sizeof(int8_t));
-}
+	ResourcePackage* package = (ResourcePackage*) stack.get_lightdata(1);
+	package->load();
 
-//-----------------------------------------------------------------------------
-void BinaryWriter::write_int16(int16_t buffer)
-{
-	m_file.write(&buffer, sizeof(int16_t));
+	return 0;
 }
 
 //-----------------------------------------------------------------------------
-void BinaryWriter::write_uint16(uint16_t buffer)
+CE_EXPORT int resource_package_unload(lua_State* L)
 {
-	m_file.write(&buffer, sizeof(uint16_t));
-}
+	LuaStack stack(L);
 
-//-----------------------------------------------------------------------------
-void BinaryWriter::write_int32(int32_t buffer)
-{
-	m_file.write(&buffer, sizeof(int32_t));
-}
+	ResourcePackage* package = (ResourcePackage*) stack.get_lightdata(1);
+	package->unload();
 
-//-----------------------------------------------------------------------------
-void BinaryWriter::write_uint32(uint32_t buffer)
-{
-	m_file.write(&buffer, sizeof(uint32_t));
+	return 0;
 }
 
 //-----------------------------------------------------------------------------
-void BinaryWriter::write_int64(int64_t buffer)
+CE_EXPORT int resource_package_flush(lua_State* L)
 {
-	m_file.write(&buffer, sizeof(int64_t));
+	LuaStack stack(L);
+
+	ResourcePackage* package = (ResourcePackage*) stack.get_lightdata(1);
+	package->flush();
+
+	return 0;
 }
 
 //-----------------------------------------------------------------------------
-void BinaryWriter::write_double(double buffer)
+CE_EXPORT int resource_package_has_loaded(lua_State* L)
 {
-	m_file.write(&buffer, sizeof(double));
+	LuaStack stack(L);
+
+	ResourcePackage* package = (ResourcePackage*) stack.get_lightdata(1);
+	stack.push_bool(package->has_loaded());
+
+	return 1;
 }
 
 //-----------------------------------------------------------------------------
-void BinaryWriter::write_float(float buffer)
+void load_resource_package(LuaEnvironment& env)
 {
-	m_file.write(&buffer, sizeof(float));
+	env.load_module_function("ResourcePackage", "load",       resource_package_load);
+	env.load_module_function("ResourcePackage", "unload",     resource_package_unload);
+	env.load_module_function("ResourcePackage", "flush",      resource_package_flush);
+	env.load_module_function("ResourcePackage", "has_loaded", resource_package_has_loaded);
 }
 
 } // namespace crown
-

+ 48 - 150
engine/lua/LuaStack.cpp

@@ -34,178 +34,52 @@ OTHER DEALINGS IN THE SOFTWARE.
 namespace crown
 {
 
-static const int32_t 	LUA_VEC2_BUFFER_SIZE = 4096;
-static Vec2 			vec2_buffer[LUA_VEC2_BUFFER_SIZE];
-static uint32_t 		vec2_used = 0;
+static const uint32_t 	LUA_VEC2_BUFFER_SIZE = 4096;
+static Vec2 			g_vec2_buffer[LUA_VEC2_BUFFER_SIZE];
+static uint32_t 		g_vec2_used = 0;
 
-static const int32_t 	LUA_VEC3_BUFFER_SIZE = 4096;
-static Vec3 			vec3_buffer[LUA_VEC3_BUFFER_SIZE];
-static uint32_t 		vec3_used = 0;
+static const uint32_t 	LUA_VEC3_BUFFER_SIZE = 4096;
+static Vec3 			g_vec3_buffer[LUA_VEC3_BUFFER_SIZE];
+static uint32_t 		g_vec3_used = 0;
 
-static const int32_t 	LUA_MAT4_BUFFER_SIZE = 4096;
-static Mat4 			mat4_buffer[LUA_MAT4_BUFFER_SIZE];
-static uint32_t 		mat4_used = 0;
+static const uint32_t 	LUA_MAT4_BUFFER_SIZE = 4096;
+static Mat4 			g_mat4_buffer[LUA_MAT4_BUFFER_SIZE];
+static uint32_t 		g_mat4_used = 0;
 
-static const int32_t 	LUA_QUAT_BUFFER_SIZE = 4096;
-static Quat 			quat_buffer[LUA_QUAT_BUFFER_SIZE];
-static uint32_t 		quat_used = 0;
+static const uint32_t 	LUA_QUAT_BUFFER_SIZE = 4096;
+static Quat 			g_quat_buffer[LUA_QUAT_BUFFER_SIZE];
+static uint32_t 		g_quat_used = 0;
 
 //-----------------------------------------------------------------------------
 static Vec2* next_vec2(const Vec2& v)
 {
-	CE_ASSERT(vec2_used < LUA_VEC2_BUFFER_SIZE, "Maximum number of Vec2 reached");
+	CE_ASSERT(g_vec2_used < LUA_VEC2_BUFFER_SIZE, "Maximum number of Vec2 reached");
 
-	return &(vec2_buffer[vec2_used++] = v);
+	return &(g_vec2_buffer[g_vec2_used++] = v);
 }
 
 //-----------------------------------------------------------------------------
 static Vec3* next_vec3(const Vec3& v)
 {
-	CE_ASSERT(vec3_used < LUA_VEC3_BUFFER_SIZE, "Maximum number of Vec3 reached");
+	CE_ASSERT(g_vec3_used < LUA_VEC3_BUFFER_SIZE, "Maximum number of Vec3 reached");
 
-	return &(vec3_buffer[vec3_used++] = v);
+	return &(g_vec3_buffer[g_vec3_used++] = v);
 }
 
 //-----------------------------------------------------------------------------
 static Mat4* next_mat4(const Mat4& m)
 {
-	CE_ASSERT(mat4_used < LUA_MAT4_BUFFER_SIZE, "Maximum number of Mat4 reached");
+	CE_ASSERT(g_mat4_used < LUA_MAT4_BUFFER_SIZE, "Maximum number of Mat4 reached");
 
-	return &(mat4_buffer[mat4_used++] = m);
+	return &(g_mat4_buffer[g_mat4_used++] = m);
 }
 
 //-----------------------------------------------------------------------------
 static Quat* next_quat(const Quat& q)
 {
-	CE_ASSERT(quat_used < LUA_QUAT_BUFFER_SIZE, "Maximum number of Quat reached");
+	CE_ASSERT(g_quat_used < LUA_QUAT_BUFFER_SIZE, "Maximum number of Quat reached");
 
-	return &(quat_buffer[quat_used++] = q);
-}
-
-//-----------------------------------------------------------------------------	
-LuaStack::LuaStack(lua_State* L)
-{
-	m_state = L;
-}
-
-//-----------------------------------------------------------------------------
-lua_State* LuaStack::state()
-{
-	return m_state;
-}
-
-//-----------------------------------------------------------------------------
-int32_t LuaStack::num_args()
-{
-	return lua_gettop(m_state);
-}
-
-//-----------------------------------------------------------------------------
-void LuaStack::push_bool(bool value)
-{
-	lua_pushboolean(m_state, value);
-}
-
-//-----------------------------------------------------------------------------
-void LuaStack::push_int32(int32_t value)
-{
-	lua_pushinteger(m_state, value);
-}
-
-//-----------------------------------------------------------------------------
-void LuaStack::push_uint32(uint32_t value)
-{
-	lua_pushinteger(m_state, value);
-}
-
-//-----------------------------------------------------------------------------
-void LuaStack::push_int64(int64_t value)
-{
-	lua_pushinteger(m_state, value);
-}
-
-//-----------------------------------------------------------------------------
-void LuaStack::push_uint64(uint64_t value)
-{
-	lua_pushinteger(m_state, value);
-}
-
-//-----------------------------------------------------------------------------
-void LuaStack::push_float(float value)
-{
-	lua_pushnumber(m_state, value);
-}
-
-//-----------------------------------------------------------------------------
-void LuaStack::push_string(const char* s)
-{
-	lua_pushstring(m_state, s);
-}
-
-//-----------------------------------------------------------------------------
-void LuaStack::push_literal(const char* s, size_t len)
-{
-	lua_pushlstring(m_state, s, len);
-}
-
-//-----------------------------------------------------------------------------
-void LuaStack::push_lightdata(void* data)
-{
-	lua_pushlightuserdata(m_state, data);
-}
-
-//-----------------------------------------------------------------------------
-void LuaStack::push_vec2(const Vec2& v)
-{
-	lua_pushlightuserdata(m_state, next_vec2(v));
-}
-
-//-----------------------------------------------------------------------------
-void LuaStack::push_vec3(const Vec3& v)
-{
-	lua_pushlightuserdata(m_state, next_vec3(v));
-}
-
-//-----------------------------------------------------------------------------
-void LuaStack::push_mat4(const Mat4& m)
-{
-	lua_pushlightuserdata(m_state, next_mat4(m));
-}
-
-//-----------------------------------------------------------------------------
-void LuaStack::push_quat(const Quat& q)
-{
-	lua_pushlightuserdata(m_state, next_quat(q));
-}
-
-//-----------------------------------------------------------------------------
-bool LuaStack::get_bool(int32_t index)
-{
-	return (bool) luaL_checkinteger(m_state, index);
-}
-
-//-----------------------------------------------------------------------------
-int32_t LuaStack::get_int(int32_t index)
-{
-	return luaL_checkinteger(m_state, index);
-}
-
-//-----------------------------------------------------------------------------
-float LuaStack::get_float(int32_t index)
-{
-	return luaL_checknumber(m_state, index);
-}
-
-//-----------------------------------------------------------------------------
-const char* LuaStack::get_string(int32_t index)
-{
-	return luaL_checkstring(m_state, index);
-}
-
-//-----------------------------------------------------------------------------
-void* LuaStack::get_lightdata(int32_t index)
-{
-	return lua_touserdata(m_state, index);	
+	return &(g_quat_buffer[g_quat_used++] = q);
 }
 
 //-----------------------------------------------------------------------------
@@ -213,7 +87,7 @@ Vec2& LuaStack::get_vec2(int32_t index)
 {
 	void* v = lua_touserdata(m_state, index);
 
-	if (v < &vec2_buffer[0] || v > &vec2_buffer[LUA_VEC2_BUFFER_SIZE-1])
+	if (v < &g_vec2_buffer[0] || v > &g_vec2_buffer[LUA_VEC2_BUFFER_SIZE-1])
 	{
 		luaL_typerror(m_state, index, "Vec2");
 	}
@@ -226,7 +100,7 @@ Vec3& LuaStack::get_vec3(int32_t index)
 {
 	void* v = lua_touserdata(m_state, index);
 
-	if (v < &vec3_buffer[0] || v > &vec3_buffer[LUA_VEC3_BUFFER_SIZE-1])
+	if (v < &g_vec3_buffer[0] || v > &g_vec3_buffer[LUA_VEC3_BUFFER_SIZE-1])
 	{
 		luaL_typerror(m_state, index, "Vec3");
 	}
@@ -239,7 +113,7 @@ Mat4& LuaStack::get_mat4(int32_t index)
 {
 	void* m = lua_touserdata(m_state, index);
 
-	if (m < &mat4_buffer[0] || m > &mat4_buffer[LUA_MAT4_BUFFER_SIZE-1])
+	if (m < &g_mat4_buffer[0] || m > &g_mat4_buffer[LUA_MAT4_BUFFER_SIZE-1])
 	{
 		luaL_typerror(m_state, index, "Mat4");
 	}
@@ -252,7 +126,7 @@ Quat& LuaStack::get_quat(int32_t index)
 {
 	void* q = lua_touserdata(m_state, index);
 
-	if (q < &quat_buffer[0] || q > &quat_buffer[LUA_QUAT_BUFFER_SIZE-1])
+	if (q < &g_quat_buffer[0] || q > &g_quat_buffer[LUA_QUAT_BUFFER_SIZE-1])
 	{
 		luaL_typerror(m_state, index, "Quat");
 	}
@@ -260,4 +134,28 @@ Quat& LuaStack::get_quat(int32_t index)
 	return *(Quat*)q;
 }
 
+//-----------------------------------------------------------------------------
+void LuaStack::push_vec2(const Vec2& v)
+{
+	lua_pushlightuserdata(m_state, next_vec2(v));
+}
+
+//-----------------------------------------------------------------------------
+void LuaStack::push_vec3(const Vec3& v)
+{
+	lua_pushlightuserdata(m_state, next_vec3(v));
+}
+
+//-----------------------------------------------------------------------------
+void LuaStack::push_mat4(const Mat4& m)
+{
+	lua_pushlightuserdata(m_state, next_mat4(m));
+}
+
+//-----------------------------------------------------------------------------
+void LuaStack::push_quat(const Quat& q)
+{
+	lua_pushlightuserdata(m_state, next_quat(q));
+}
+
 } // namespace crown

+ 104 - 43
engine/lua/LuaStack.h

@@ -41,54 +41,115 @@ class LuaStack
 {
 public:
 
-							LuaStack(lua_State* L);
+	//-----------------------------------------------------------------------------	
+	LuaStack(lua_State* L) : m_state(L) {}
 
-	lua_State*				state();
+	//-----------------------------------------------------------------------------
+	lua_State* state()
+	{
+		return m_state;
+	}
 
 	/// Returns the number of elements in the stack.
 	/// When called inside a function, it can be used to count
 	/// the number of arguments passed to the function itself.
-	int32_t					num_args();
-
-	void					push_bool(bool value);
-
-	void					push_int32(int32_t value);
-
-	void					push_uint32(uint32_t value);
-
-	void					push_int64(int64_t value);
-
-	void					push_uint64(uint64_t value);
-
-	void 					push_float(float value);
-
-	void 					push_string(const char* s);
-	void					push_literal(const char* s, size_t len);
-
-	void					push_lightdata(void* data);
-
-	void					push_vec2(const Vec2& v);
-
-	void					push_vec3(const Vec3& v);
-
-	void					push_mat4(const Mat4& m);
-
-	void					push_quat(const Quat& q);
-
-	bool 					get_bool(int32_t index);
-
-	int32_t					get_int(int32_t index);
-
-	float 					get_float(int32_t index);
-
-	const char*				get_string(int32_t index);
-
-	void*					get_lightdata(int32_t index);
-
-	Vec2&					get_vec2(int32_t index);
-	Vec3&					get_vec3(int32_t index);
-	Mat4&					get_mat4(int32_t index);
-	Quat&					get_quat(int32_t index);
+	int32_t num_args()
+	{
+		return lua_gettop(m_state);
+	}
+
+	//-----------------------------------------------------------------------------
+	void push_bool(bool value)
+	{
+		lua_pushboolean(m_state, value);
+	}
+
+	//-----------------------------------------------------------------------------
+	void push_int32(int32_t value)
+	{
+		lua_pushinteger(m_state, value);
+	}
+
+	//-----------------------------------------------------------------------------
+	void push_uint32(uint32_t value)
+	{
+		lua_pushinteger(m_state, value);
+	}
+
+	//-----------------------------------------------------------------------------
+	void push_int64(int64_t value)
+	{
+		lua_pushinteger(m_state, value);
+	}
+
+	//-----------------------------------------------------------------------------
+	void push_uint64(uint64_t value)
+	{
+		lua_pushinteger(m_state, value);
+	}
+
+	//-----------------------------------------------------------------------------
+	void push_float(float value)
+	{
+		lua_pushnumber(m_state, value);
+	}
+
+	//-----------------------------------------------------------------------------
+	void push_string(const char* s)
+	{
+		lua_pushstring(m_state, s);
+	}
+
+	//-----------------------------------------------------------------------------
+	void push_literal(const char* s, size_t len)
+	{
+		lua_pushlstring(m_state, s, len);
+	}
+
+	//-----------------------------------------------------------------------------
+	void push_lightdata(void* data)
+	{
+		lua_pushlightuserdata(m_state, data);
+	}
+
+	//-----------------------------------------------------------------------------
+	bool get_bool(int32_t index)
+	{
+		return (bool) luaL_checkinteger(m_state, index);
+	}
+
+	//-----------------------------------------------------------------------------
+	int32_t get_int(int32_t index)
+	{
+		return luaL_checkinteger(m_state, index);
+	}
+
+	//-----------------------------------------------------------------------------
+	float get_float(int32_t index)
+	{
+		return luaL_checknumber(m_state, index);
+	}
+
+	//-----------------------------------------------------------------------------
+	const char* get_string(int32_t index)
+	{
+		return luaL_checkstring(m_state, index);
+	}
+
+	//-----------------------------------------------------------------------------
+	void* get_lightdata(int32_t index)
+	{
+		return lua_touserdata(m_state, index);	
+	}
+
+	Vec2& get_vec2(int32_t index);
+	Vec3& get_vec3(int32_t index);
+	Mat4& get_mat4(int32_t index);
+	Quat& get_quat(int32_t index);
+	void push_vec2(const Vec2& v);
+	void push_vec3(const Vec3& v);
+	void push_mat4(const Mat4& m);
+	void push_quat(const Quat& q);
 
 private:
 

+ 58 - 15
engine/os/OS.h

@@ -30,24 +30,31 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 #include "Config.h"
 #include "Types.h"
+#include "Vector.h"
+#include "DynamicString.h"
 
 namespace crown
 {
 
 //-----------------------------------------------------------------------------
-#ifdef LINUX
+#if defined(LINUX)
 	const size_t	MAX_PATH_LENGTH = 1024;
 	const char		PATH_SEPARATOR = '/';
-#endif
-
-#ifdef WINDOWS
+#elif defined(WINDOWS)
 	const size_t	MAX_PATH_LENGTH = 1024;
 	const char		PATH_SEPARATOR = '\\';
 
 	#define snprintf _snprintf
 
+	#define Thread os::Thread
+
 	#undef MK_SHIFT
 	#undef MK_ALT
+#elif defined(ANDROID)
+	const size_t	MAX_PATH_LENGTH = 1024;
+	const char		PATH_SEPARATOR = '/';
+#else
+	#error "Oops, invalid platform!"
 #endif
 
 namespace os
@@ -72,24 +79,49 @@ bool			is_absolute_path(const char* path);
 //-----------------------------------------------------------------------------
 // File management
 //-----------------------------------------------------------------------------
-bool			exists(const char* path);		//!< Returns whether the path is a file or directory on the disk
 
-bool			is_dir(const char* path);		//!< Returns whether the path is a directory. (May not resolve symlinks.)
-bool			is_reg(const char* path);		//!< Returns whether the path is a regular file. (May not resolve symlinks.)
+/// Returns whether the path is a file or directory on the disk
+bool			exists(const char* path);
+
+/// Returns whether the path is a directory. (May not resolve symlinks.)
+bool			is_directory(const char* path);
+
+/// Returns whether the path is a regular file. (May not resolve symlinks.)
+bool			is_file(const char* path);
+
+/// Creates a regular file. Returns true if success, false if not
+bool			create_file(const char* path);
+
+/// Deletes a regular file. Returns true if success, false if not
+bool			delete_file(const char* path);
 
-bool			mknod(const char* path);		//! Creates a regular file. Returns true if success, false if not
-bool			unlink(const char* path);		//! Deletes a regular file. Returns true if success, false if not
-bool			mkdir(const char* path);		//! Creates a directory. Returns true if success, false if not
-bool			rmdir(const char* path);		//! Deletes a directory. Returns true if success, false if not
+/// Creates a directory. Returns true if success, false if not
+bool			create_directory(const char* path);
+
+/// Deletes a directory. Returns true if success, false if not
+bool			delete_directory(const char* path);
+
+/// Returns the list of @a files in the given @a dir directory. Optionally walks into
+/// subdirectories whether @a recursive is true.
+/// @note
+/// Does not follow symbolic links.
+void			list_files(const char* path, Vector<DynamicString>& files);
+
+/// Returns os-dependent path from os-indipendent @a path
+const char*		normalize_path(const char* path);
 
 //-----------------------------------------------------------------------------
 // OS ambient variables
 //-----------------------------------------------------------------------------
-const char*		get_cwd();						//! Fills ret with the path of the current working directory. Returns true if success, false if not 
-const char*		get_home();						//! Fills ret with the path of the user home directory
-const char*		get_env(const char* env);		//! Returns the content of the 'env' environment variable or the empty string
 
-//bool			ls(const char* path, List<Str>& fileList);	//! Returns the list of filenames in a directory.
+/// Fills ret with the path of the current working directory. Returns true if success, false if not 
+const char*		get_cwd();
+
+/// Fills ret with the path of the user home directory
+const char*		get_home();
+
+/// Returns the content of the 'env' environment variable or the empty string
+const char*		get_env(const char* env);
 
 //-----------------------------------------------------------------------------
 // Render window and input management
@@ -112,6 +144,17 @@ void*			open_library(const char* path);
 void			close_library(void* library);
 void*			lookup_symbol(void* library, const char* name);
 
+//-----------------------------------------------------------------------------
+// Process execution
+//-----------------------------------------------------------------------------
+
+/// Executes a process.
+/// @a args is an array of arguments where:
+/// @a args[0] is the path to the program executable,
+/// @a args[1, 2, ..., n-1] is a list of arguments to pass to the executable,
+/// @a args[n] is NULL.
+void			execute_process(const char* args[]);
+
 } // namespace os
 
 //-----------------------------------------------------------------------------

+ 7 - 7
engine/os/android/AndroidDevice.cpp

@@ -31,33 +31,33 @@ namespace crown
 {
 
 //-----------------------------------------------------------------------------
-extern "C" JNIEXPORT void JNICALL Java_crown_android_CrownLib_init(JNIEnv* env, jobject obj)
+extern "C" JNIEXPORT void JNICALL Java_crown_android_CrownLib_init(JNIEnv* /*env*/, jobject /*obj*/)
 {
-	const char* argv[] = { "crown-android", "--root-path", "/sdcard/crown-android-project", "--dev" };
+	const char* argv[] = { "crown-android" };
 
-	device()->init(4, (char**)argv);
+	device()->init(1, (char**)argv);
 }
 
 //-----------------------------------------------------------------------------
-extern "C" JNIEXPORT void JNICALL Java_crown_android_CrownLib_shutdown(JNIEnv* env, jobject obj)
+extern "C" JNIEXPORT void JNICALL Java_crown_android_CrownLib_shutdown(JNIEnv* /*env*/, jobject /*obj*/)
 {
 	device()->shutdown();
 }
 
 //-----------------------------------------------------------------------------
-extern "C" JNIEXPORT void JNICALL Java_crown_android_CrownLib_frame(JNIEnv* env, jobject obj)
+extern "C" JNIEXPORT void JNICALL Java_crown_android_CrownLib_frame(JNIEnv* /*env*/, jobject /*obj*/)
 {
 	device()->frame();
 }
 
 //-----------------------------------------------------------------------------
-extern "C" JNIEXPORT bool JNICALL Java_crown_android_CrownLib_isInit(JNIEnv* env, jobject obj)
+extern "C" JNIEXPORT bool JNICALL Java_crown_android_CrownLib_isInit(JNIEnv* /*env*/, jobject /*obj*/)
 {
 	return device()->is_init();
 }
 
 //-----------------------------------------------------------------------------
-extern "C" JNIEXPORT bool JNICALL Java_crown_android_CrownLib_isRunning(JNIEnv* env, jobject obj)
+extern "C" JNIEXPORT bool JNICALL Java_crown_android_CrownLib_isRunning(JNIEnv* /*env*/, jobject /*obj*/)
 {
 	return device()->is_running();
 }

+ 82 - 10
engine/os/android/AndroidOS.cpp

@@ -30,8 +30,11 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include <cstdio>
 #include <cstdlib>
 #include <dirent.h>
+#include <dlfcn.h>
 #include <sys/stat.h>
 #include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
 #include <time.h>
 #include <unistd.h>
 
@@ -45,8 +48,6 @@ namespace os
 {
 
 static timespec			base_time;
-static uint32_t			window_width;
-static uint32_t			window_height;
 
 //-----------------------------------------------------------------------------
 void printf(const char* string, ...)
@@ -128,7 +129,7 @@ bool exists(const char* path)
 }
 
 //-----------------------------------------------------------------------------
-bool is_dir(const char* path)
+bool is_directory(const char* path)
 {
 	struct stat info;
 	memset(&info, 0, sizeof(struct stat));
@@ -137,7 +138,7 @@ bool is_dir(const char* path)
 }
 
 //-----------------------------------------------------------------------------
-bool is_reg(const char* path)
+bool is_file(const char* path)
 {
 	struct stat info;
 	memset(&info, 0, sizeof(struct stat));
@@ -146,31 +147,82 @@ bool is_reg(const char* path)
 }
 
 //-----------------------------------------------------------------------------
-bool mknod(const char* path)
+bool create_file(const char* path)
 {
 	// Permission mask: rw-r--r--
 	return ::mknod(path, S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, 0) == 0;
 }
 
 //-----------------------------------------------------------------------------
-bool unlink(const char* path)
+bool delete_file(const char* path)
 {
 	return (::unlink(path) == 0);
 }
 
 //-----------------------------------------------------------------------------
-bool mkdir(const char* path)
+bool create_directory(const char* path)
 {
 	// rwxr-xr-x permission mask
 	return (::mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0);
 }
 
 //-----------------------------------------------------------------------------
-bool rmdir(const char* path)
+bool delete_directory(const char* path)
 {
 	return (::rmdir(path) == 0);
 }
 
+//-----------------------------------------------------------------------------
+void list_files(const char* path, Vector<DynamicString>& files)
+{
+	DIR *dir;
+	struct dirent *entry;
+
+	if (!(dir = opendir(path)))
+	{
+		return;
+	}
+
+	while ((entry = readdir(dir)))
+	{
+		if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
+		{
+			continue;
+		}
+
+		DynamicString filename(default_allocator());
+
+		filename = entry->d_name;
+		files.push_back(filename);
+	}
+
+	closedir(dir);
+}
+
+//-----------------------------------------------------------------------------
+const char* normalize_path(const char* path)
+{
+	static char norm[MAX_PATH_LENGTH];
+	char* cur = norm;
+
+	while ((*path) != '\0')
+	{
+		if ((*path) == '\\')
+		{
+			(*cur) = PATH_SEPARATOR;
+		}
+		else
+		{
+			(*cur) = (*path);
+		}
+
+		path++;
+		cur++;
+	}
+
+	return norm;
+}
+
 //-----------------------------------------------------------------------------
 const char* get_cwd()
 {
@@ -236,10 +288,30 @@ uint64_t microseconds()
 	return (tmp.tv_sec - base_time.tv_sec) * 1000000 + (tmp.tv_nsec - base_time.tv_nsec) / 1000;
 }
 
+//-----------------------------------------------------------------------------
+void execute_process(const char* args[])
+{
+	pid_t pid = fork();
+	CE_ASSERT(pid != -1, "Unable to fork");
+
+	if (pid)
+	{
+		int32_t dummy;
+		wait(&dummy);
+	}
+	else
+	{
+		int res = execv(args[0], (char* const*)args);
+		CE_ASSERT(res != -1, "Unable to exec '%s'. errno %d", args[0], res);
+		exit(EXIT_SUCCESS);
+	}
+}
+
+
 } // namespace os
 
 //-----------------------------------------------------------------------------
-extern "C" JNIEXPORT void JNICALL Java_crown_android_CrownLib_pushIntEvent(JNIEnv * env, jobject obj, jint type, jint a, jint b, jint c, jint d)
+extern "C" JNIEXPORT void JNICALL Java_crown_android_CrownLib_pushIntEvent(JNIEnv * /*env*/, jobject /*obj*/, jint type, jint a, jint b, jint c, jint d)
 {	
 	OsEventParameter values[4];
 
@@ -252,7 +324,7 @@ extern "C" JNIEXPORT void JNICALL Java_crown_android_CrownLib_pushIntEvent(JNIEn
 }
 
 //-----------------------------------------------------------------------------
-extern "C" JNIEXPORT void JNICALL Java_crown_android_CrownLib_pushFloatEvent(JNIEnv * env, jobject obj, jint type, jfloat a, jfloat b, jfloat c, jfloat d)
+extern "C" JNIEXPORT void JNICALL Java_crown_android_CrownLib_pushFloatEvent(JNIEnv * /*env*/, jobject /*obj*/, jint type, jfloat a, jfloat b, jfloat c, jfloat d)
 {
 	OsEventParameter values[4];
 

+ 57 - 48
engine/os/android/OsFile2.cpp → engine/os/android/ApkFile.cpp

@@ -25,36 +25,36 @@ OTHER DEALINGS IN THE SOFTWARE.
 */
 
 #include <android/asset_manager_jni.h>
-
+#include "ApkFile.h"
 #include "Assert.h"
-#include "OS.h"
-#include "OsFile.h"
-#include "AndroidOS.h"
-
-namespace crown
-{
 
-static AAssetManager*	g_android_asset_manager = NULL;
+static AAssetManager* g_android_asset_manager = NULL;
 
 //-----------------------------------------------------------------------------
-OsFile::OsFile(const char* path, FileOpenMode mode)
+AAssetManager* get_android_asset_manager()
 {
-	// Android assets are always read-only
-	(void) mode;
-	m_mode = FOM_READ;
-	m_asset = AAssetManager_open(get_android_asset_manager(), path, AASSET_MODE_RANDOM);
+	return g_android_asset_manager;
+}
 
-	CE_ASSERT(m_asset != NULL, "Unable to open file: %s", path);
+//-----------------------------------------------------------------------------
+extern "C" JNIEXPORT void JNICALL Java_crown_android_CrownLib_initAssetManager(JNIEnv* env, jobject obj, jobject assetManager)
+{
+	g_android_asset_manager = AAssetManager_fromJava(env, assetManager);
 }
 
+namespace crown
+{
+
 //-----------------------------------------------------------------------------
-OsFile::~OsFile()
+ApkFile::ApkFile(const char* path)
+	: File(FOM_READ), m_asset(NULL)
 {
-	close();
+	m_asset = AAssetManager_open(get_android_asset_manager(), path, AASSET_MODE_RANDOM);
+	CE_ASSERT(m_asset != NULL, "Unable to open file: %s", path);
 }
 
 //-----------------------------------------------------------------------------
-void OsFile::close()
+ApkFile::~ApkFile()
 {
 	if (m_asset != NULL)
 	{
@@ -64,85 +64,94 @@ void OsFile::close()
 }
 
 //-----------------------------------------------------------------------------
-bool OsFile::is_open() const
+void ApkFile::seek(size_t position)
 {
-	return m_asset != NULL;
+	off_t seek_result = AAsset_seek(m_asset, (off_t)position, SEEK_SET);
+	CE_ASSERT(seek_result != (off_t) -1, "Failed to seek");
 }
 
 //-----------------------------------------------------------------------------
-FileOpenMode OsFile::mode() const
+void ApkFile::seek_to_end()
 {
-	return m_mode;
+	off_t seek_result = AAsset_seek(m_asset, 0, SEEK_END);
+	CE_ASSERT(seek_result != (off_t) -1, "Failed to seek to end");
 }
 
 //-----------------------------------------------------------------------------
-size_t OsFile::size() const
+void ApkFile::skip(size_t bytes)
 {
-	return AAsset_getLength(m_asset);
+	off_t seek_result = AAsset_seek(m_asset, (off_t) bytes, SEEK_CUR);
+	CE_ASSERT(seek_result != (off_t) -1, "Failed to skip");
 }
 
 //-----------------------------------------------------------------------------
-size_t OsFile::read(void* data, size_t size)
+void ApkFile::read(void* buffer, size_t size)
 {
-	CE_ASSERT(data != NULL, "Data must be != NULL");
+	CE_ASSERT_NOT_NULL(buffer);
 
-	return (size_t)AAsset_read(m_asset, data, size);
+	size_t bytes_read = (size_t) AAsset_read(m_asset, buffer, size);
+	CE_ASSERT(bytes_read == size, "Failed to read from file: requested: %lu, read: %lu", size, bytes_read);
 }
 
 //-----------------------------------------------------------------------------
-size_t OsFile::write(const void* data, size_t size)
+void ApkFile::write(const void* /*buffer*/, size_t /*size*/)
 {
-	CE_ASSERT(data != NULL, "Data must be != NULL");
+	CE_ASSERT(false, "Attempt to write to android assets folder!");
+}
 
-	os::printf("Android asset directory is read-only!");
+//-----------------------------------------------------------------------------
+bool ApkFile::copy_to(File& /*file*/, size_t /*size = 0*/)
+{
+	CE_ASSERT(false, "Not implemented yet :(");
+	return false;
+}
 
-	return 0;
+//-----------------------------------------------------------------------------
+void ApkFile::flush()
+{
+	// Not needed
 }
 
 //-----------------------------------------------------------------------------
-void OsFile::seek(size_t position)
+bool ApkFile::is_valid() const
 {
-	off_t seek_result = AAsset_seek(m_asset, (off_t)position, SEEK_SET);
-	CE_ASSERT(seek_result != (off_t) -1, "Failed to seek");
+	return m_asset != NULL;
 }
 
 //-----------------------------------------------------------------------------
-void OsFile::seek_to_end()
+bool ApkFile::end_of_file() const
 {
-	off_t seek_result = AAsset_seek(m_asset, 0, SEEK_END);
-	CE_ASSERT(seek_result != (off_t) -1, "Failed to seek");
+	return AAsset_getRemainingLength(m_asset) == 0;
 }
 
 //-----------------------------------------------------------------------------
-void OsFile::skip(size_t bytes)
+size_t ApkFile::size() const
 {
-	off_t seek_result = AAsset_seek(m_asset, (off_t) bytes, SEEK_CUR);
-	CE_ASSERT(seek_result != (off_t) -1, "Failed to seek");
+	return AAsset_getLength(m_asset);
 }
 
 //-----------------------------------------------------------------------------
-size_t OsFile::position() const
+size_t ApkFile::position() const
 {
 	return (size_t) (AAsset_getLength(m_asset) - AAsset_getRemainingLength(m_asset));
 }
 
 //-----------------------------------------------------------------------------
-bool OsFile::eof() const
+bool ApkFile::can_read() const
 {
-	return AAsset_getRemainingLength(m_asset) == 0;
+	return true;
 }
 
 //-----------------------------------------------------------------------------
-AAssetManager* get_android_asset_manager()
+bool ApkFile::can_write() const
 {
-	return g_android_asset_manager;
+	return false;
 }
 
 //-----------------------------------------------------------------------------
-extern "C" JNIEXPORT void JNICALL Java_crown_android_CrownLib_initAssetManager(JNIEnv* env, jobject obj, jobject assetManager)
+bool ApkFile::can_seek() const
 {
-	g_android_asset_manager = AAssetManager_fromJava(env, assetManager);
+	return true;
 }
 
-} // namespace crown
-
+} // namespace crown

+ 44 - 39
engine/resource/ArchiveBundle.h → engine/os/android/ApkFile.h

@@ -26,59 +26,64 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 #pragma once
 
-#include "Types.h"
-#include "Bundle.h"
-#include "HeapAllocator.h"
+#include "File.h"
 
 namespace crown
 {
 
-class Filesystem;
-class DiskFile;
-
-/// Structure of the archive
-///
-/// [ArchiveHeader]
-/// [ArchiveEntry]
-/// [ArchiveEntry]
-/// ...
-/// [ArchiveEntry]
-/// [ResourceData]
-/// [ResourceData]
-/// ...
-/// [ResourceData]
-///
-/// A valid archive must always have at least the archive header,
-/// starting at byte 0 of the archive file.
-///
-/// Newer archive versions must be totally backward compatible
-/// across minor engine releases, in order to be able to use
-/// recent version of the engine with older game archives.
-
-/// Source of resources
-class ArchiveBundle : public Bundle
+class ApkFile : public File 
 {
 public:
 
-					ArchiveBundle(Filesystem& fs);
-					~ArchiveBundle();
+	/// Opens the given @a filename.
+				ApkFile(const char* filename);
+				~ApkFile();
 
-	/// @copydoc Bundle::open()
-	DiskFile*		open(ResourceId name);
+	/// @copydoc File::seek()
+	void		seek(size_t position);
 
-	/// @copydoc Bundle::close()
-	void			close(DiskFile* resource);
+	/// @copydoc File::seek_to_end()
+	void		seek_to_end();
 
-private:
+	/// @copydoc File::skip()
+	void		skip(size_t bytes);
+
+	/// @copydoc File::read()
+	void		read(void* buffer, size_t size);
+
+	/// @copydoc File::write()
+	void		write(const void* buffer, size_t size);
+
+	/// @copydoc File::copy_to()
+	bool		copy_to(File& file, size_t size = 0);
+
+	/// @copydoc File::flush()
+	void		flush();
+
+	/// @copydoc File::is_valid()
+	bool		is_valid() const;
 
-	HeapAllocator	m_allocator;
+	/// @copydoc File::end_of_file()
+	bool		end_of_file() const;
 
-	Filesystem&		m_filesystem;
+	/// @copydoc File::size()
+	size_t		size() const;
 
-	DiskFile*		m_archive_file;
+	/// @copydoc File::position()
+	size_t		position() const;
+
+	/// @copydoc File::can_read()
+	bool		can_read() const;
+
+	/// @copydoc File::can_write()
+	bool		can_write() const;
+
+	/// @copydoc File::can_seek()
+	bool		can_seek() const;
+
+private:
 
-	uint32_t		m_entries_count;
-	ArchiveEntry*	m_entries;
+	AAsset*		m_asset;
 };
 
 } // namespace crown

+ 53 - 35
engine/core/filesystem/BinaryReader.cpp → engine/os/android/ApkFilesystem.cpp

@@ -24,79 +24,97 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
 */
 
-#include "BinaryReader.h"
-#include "File.h"
+#include <android/asset_manager.h>
+#include "ApkFilesystem.h"
+#include "TempAllocator.h"
+#include "ApkFile.h"
+#include "OS.h"
+
+extern AAssetManager* get_android_asset_manager();
 
 namespace crown
 {
 
 //-----------------------------------------------------------------------------
-BinaryReader::BinaryReader(File& file) : m_file(file)
+ApkFilesystem::ApkFilesystem()
 {
 }
 
 //-----------------------------------------------------------------------------
-int8_t BinaryReader::read_byte()
+File* ApkFilesystem::open(const char* path, FileOpenMode mode)
 {
-	int8_t buffer;
-	m_file.read(&buffer, sizeof(int8_t));
-	return buffer;
+	CE_ASSERT_NOT_NULL(path);
+	CE_ASSERT(mode == FOM_READ, "Cannot open for writing in Android assets folder");
+
+	return CE_NEW(default_allocator(), ApkFile)(path);
 }
 
 //-----------------------------------------------------------------------------
-int16_t BinaryReader::read_int16()
+void ApkFilesystem::close(File* file)
 {
-	int16_t buffer;
-	m_file.read(&buffer, sizeof(int16_t));
-	return buffer;
+	CE_ASSERT_NOT_NULL(file);
+	CE_DELETE(default_allocator(), file);
 }
 
 //-----------------------------------------------------------------------------
-uint16_t BinaryReader::read_uint16()
+bool ApkFilesystem::is_directory(const char* path)
 {
-	uint16_t buffer;
-	m_file.read(&buffer, sizeof(uint16_t));
-	return buffer;
+	return false;
 }
 
 //-----------------------------------------------------------------------------
-int32_t BinaryReader::read_int32()
+bool ApkFilesystem::is_file(const char* path)
 {
-	int32_t buffer;
-	m_file.read(&buffer, sizeof(int32_t));
-	return buffer;
+	return false;
 }
 
 //-----------------------------------------------------------------------------
-uint32_t BinaryReader::read_uint32()
+void ApkFilesystem::create_directory(const char* /*path*/)
 {
-	uint32_t buffer;
-	m_file.read(&buffer, sizeof(uint32_t));
-	return buffer;
+	CE_ASSERT(false, "Attempt to create directory in Android assets folder");
 }
 
 //-----------------------------------------------------------------------------
-int64_t BinaryReader::read_int64()
+void ApkFilesystem::delete_directory(const char* /*path*/)
 {
-	int64_t buffer;
-	m_file.read(&buffer, sizeof(int64_t));
-	return buffer;
+	CE_ASSERT(false, "Attempt to delete directory in Android assets folder");
 }
 
 //-----------------------------------------------------------------------------
-double BinaryReader::read_double()
+void ApkFilesystem::create_file(const char* /*path*/)
 {
-	double buffer;
-	m_file.read(&buffer, sizeof(double));
-	return buffer;
+	CE_ASSERT(false, "Attempt to create file in Android assets folder");
+}
+
+//-----------------------------------------------------------------------------
+void ApkFilesystem::delete_file(const char* /*path*/)
+{
+	CE_ASSERT(false, "Attempt to delete file in Android assets folder");
+}
+
+//-----------------------------------------------------------------------------
+void ApkFilesystem::list_files(const char* path, Vector<DynamicString>& files)
+{
+	CE_ASSERT_NOT_NULL(path);
+
+	AAssetDir* root_dir = AAssetManager_openDir(get_android_asset_manager(), path);
+	CE_ASSERT(root_dir != NULL, "Failed to open Android assets folder");
+
+	const char* filename = NULL;
+	while ((filename = AAssetDir_getNextFileName(root_dir)) != NULL)
+	{
+		DynamicString name(default_allocator());
+		name = filename;
+		files.push_back(name);
+	}
+
+	AAssetDir_close(root_dir);
 }
 
 //-----------------------------------------------------------------------------
-float BinaryReader::read_float()
+void ApkFilesystem::get_absolute_path(const char* path, DynamicString& os_path)
 {
-	float buffer;
-	m_file.read(&buffer, sizeof(float));
-	return buffer;
+	os_path = path;
 }
 
 } // namespace crown

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

@@ -0,0 +1,78 @@
+/*
+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.
+*/
+
+#pragma once
+
+#include "Filesystem.h"
+
+namespace crown
+{
+
+/// Access files on Android's assets folder.
+/// The assets folder is read-only and all the paths are relative.
+class ApkFilesystem : public Filesystem
+{
+public:
+
+	ApkFilesystem();
+
+	/// @copydoc Filesystem::open()
+	/// @note
+	/// @a mode can only be FOM_READ
+	File* open(const char* rel_path, FileOpenMode mode);
+
+	/// @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);
+
+	/// Stub method, assets folder is read-only.
+	void delete_directory(const char* path);
+
+	/// Stub method, assets folder is read-only.
+	void create_file(const char* path);
+
+	/// Stub method, assets folder is read-only.
+	void delete_file(const char* path);
+
+	/// @copydoc Filesystem::list_files().
+	void list_files(const char* path, Vector<DynamicString>& files);
+
+	/// Returns the absolute path of the given @a path.
+	/// @note
+	/// Assets folder has no concept of "absolute path", all paths are
+	/// relative to the assets folder itself, so, all paths are returned unchanged.
+	void get_absolute_path(const char* path, DynamicString& os_path);
+};
+
+} // namespace crown

+ 12 - 18
tools/core/formats/SoundFormat.h → engine/os/android/Config.h

@@ -24,21 +24,15 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
 */
 
-#pragma once
-
-#include "Types.h"
-
-namespace crown
-{
-
-const uint32_t SOUND_VERSION = 1;
-
-struct SoundHeader
-{
-	uint32_t	version;	// Sound file version
-	uint32_t	size;
-	uint32_t	channels;
-	uint32_t 	bits_per_sample;
-};
-
-}
+#define CROWN_VERSION_MAJOR 0 
+#define CROWN_VERSION_MINOR 1 
+#define CROWN_VERSION_MICRO 11
+
+#define CROWN_DEVELOPMENT
+
+#ifdef ANDROID
+	#define PRId64 "lld"
+	#define PRIu64 "llu"
+	#define PRIi64 "lli"
+	#define PRIx64 "llx"
+#endif

+ 1 - 1
engine/os/android/CrownActivity.java

@@ -70,7 +70,7 @@ public class CrownActivity extends Activity
 
 		// init AssetManager
 		mAssetManager = getAssets();
-		//CrownLib.initAssetManager(mAssetManager);
+		CrownLib.initAssetManager(mAssetManager);
 
 		// init Native Window
         mWindow = new CrownSurfaceView(this);

+ 0 - 89
engine/os/android/OsFile2.h

@@ -1,89 +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.
-*/
-
-#pragma once
-
-#include <sys/types.h>
-#include <android/asset_manager.h>
-
-#include "Types.h"
-#include "File.h"
-
-namespace crown
-{
-
-/// Android assets wrapper
-class OsFile
-{
-public:
-
-	/// Opens the file located at @a path with the given @a mode.
-							OsFile(const char* path, FileOpenMode mode);
-							~OsFile();
-
-	/// Closes the file.
-	void					close();
-
-	bool					is_open() const;
-
-	/// Return the size of the file in bytes.
-	size_t					size() const;
-
-	/// Returs the mode used to open the file.
-	FileOpenMode			mode() const;
-
-	/// Reads @a size bytes from the file and stores it into @a data.
-	/// Returns the number of bytes read.
-	size_t					read(void* data, size_t size);
-
-	/// Writes @a size bytes of data stored in @a data and returns the
-	/// number of bytes written.
-	size_t					write(const void* data, size_t size);
-
-	/// Moves the file pointer to the given @a position.
-	void					seek(size_t position);
-
-	/// Moves the file pointer to the end of the file.
-	void					seek_to_end();
-
-	/// Moves the file pointer @a bytes bytes ahead the current
-	/// file pointer position.
-	void					skip(size_t bytes);
-
-	/// Returns the position of the file pointer from the
-	/// start of the file in bytes.
-	size_t					position() const;
-
-	/// Returns whether the file pointer is at the end of the file.
-	bool					eof() const;
-
-private:
-
-	AAsset*					m_asset;
-	FileOpenMode			m_mode;
-};
-
-} // namespace crown

+ 11 - 11
engine/os/android/OsWindow.cpp

@@ -36,12 +36,12 @@ namespace crown
 static ANativeWindow* window = NULL;
 
 //-----------------------------------------------------------------------------
-OsWindow::OsWindow(uint32_t width, uint32_t height, uint32_t /*parent*/) :
+OsWindow::OsWindow(uint32_t /*width*/, uint32_t /*height*/, uint32_t /*parent*/) :
 	m_window(NULL),
-	m_width(0),
-	m_height(0),
 	m_x(0),
-	m_y(0)
+	m_y(0),
+	m_width(0),
+	m_height(0)
 {
 	m_window = window;
 
@@ -86,12 +86,12 @@ void OsWindow::get_position(uint32_t& x, uint32_t& y)
 }
 
 //-----------------------------------------------------------------------------
-void OsWindow::resize(uint32_t width, uint32_t height)
+void OsWindow::resize(uint32_t /*width*/, uint32_t /*height*/)
 {
 }
 
 //-----------------------------------------------------------------------------
-void OsWindow::move(uint32_t x, uint32_t y)
+void OsWindow::move(uint32_t /*x*/, uint32_t /*y*/)
 {
 }
 
@@ -106,12 +106,12 @@ void OsWindow::hide_cursor()
 }
 
 //-----------------------------------------------------------------------------
-void OsWindow::get_cursor_xy(int32_t& x, int32_t& y)
+void OsWindow::get_cursor_xy(int32_t& /*x*/, int32_t& /*y*/)
 {
 }
 
 //-----------------------------------------------------------------------------
-void OsWindow::set_cursor_xy(int32_t x, int32_t y)
+void OsWindow::set_cursor_xy(int32_t /*x*/, int32_t /*y*/)
 {
 }
 
@@ -122,18 +122,18 @@ char* OsWindow::title()
 }
 
 //-----------------------------------------------------------------------------
-void OsWindow::set_title(const char* title)
+void OsWindow::set_title(const char* /*title*/)
 {
 }
 
 //-----------------------------------------------------------------------------
 void OsWindow::frame()
 {
-	// implemented on Java-side
+	// Implemented Java-side
 }
 
 //-----------------------------------------------------------------------------
-extern "C" void Java_crown_android_CrownLib_setWindow(JNIEnv *env, jclass clazz, jobject surface)
+extern "C" void Java_crown_android_CrownLib_setWindow(JNIEnv *env, jclass /*clazz*/, jobject surface)
 {
     // obtain a native window from a Java surface
 	CE_ASSERT(surface != 0, "Unable to get Android window");

+ 20 - 0
engine/os/android/OsWindow.h

@@ -36,27 +36,47 @@ class OsWindow
 {
 public:
 
+	/// Stub method, does nothing under Android.
 					OsWindow(uint32_t width, uint32_t height, uint32_t parent);
 					~OsWindow();
 
+	/// Stub method, does nothing under Android.
 	void			show();
+
+	/// Stub method, does nothing under Android.
 	void			hide();
 
+	/// Returns the size in pixel of the window.
 	void			get_size(uint32_t& width, uint32_t& height);
+
+	/// Returns always (0, 0) under Android.
 	void			get_position(uint32_t& x, uint32_t& y);
 
+	/// Stub method, does nothing under Android.
 	void			resize(uint32_t width, uint32_t height);
+
+	/// Stub method, does nothing under Android.
 	void			move(uint32_t x, uint32_t y);
 
+	/// Stub method, does nothing under Android.
 	void			show_cursor();
+
+	/// Stub method, does nothing under Android.
 	void			hide_cursor();
 
+	/// Stub method, does nothing under Android.
 	void			get_cursor_xy(int32_t& x, int32_t& y);
+
+	/// Stub method, does nothing under Android.
 	void			set_cursor_xy(int32_t x, int32_t y);
 
+	/// Returns always NULL under Android.
 	char*			title();
+
+	/// Stub method, does nothing under Android.
 	void			set_title(const char* title);
 
+	/// Stub method, does nothing under Android.
 	void			frame();
 
 private:

+ 89 - 38
engine/os/linux/LinuxOS.cpp

@@ -24,19 +24,22 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
 */
 
-#include "OS.h"
-#include "StringUtils.h"
-#include <cstdio>
+#include "Assert.h"
 #include <cstdarg>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <dirent.h>
+#include <cstdio>
 #include <cstdlib>
+#include <dirent.h>
+#include <dlfcn.h>
+#include <sys/stat.h>
 #include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
 #include <time.h>
-#include <pthread.h>
-#include <dlfcn.h>
+#include <unistd.h>
+
+#include "OS.h"
+#include "StringUtils.h"
+#include "TempAllocator.h"
 
 namespace crown
 {
@@ -133,7 +136,7 @@ bool exists(const char* path)
 }
 
 //-----------------------------------------------------------------------------
-bool is_dir(const char* path)
+bool is_directory(const char* path)
 {
 	struct stat info;
 	memset(&info, 0, sizeof(struct stat));
@@ -142,7 +145,7 @@ bool is_dir(const char* path)
 }
 
 //-----------------------------------------------------------------------------
-bool is_reg(const char* path)
+bool is_file(const char* path)
 {
 	struct stat info;
 	memset(&info, 0, sizeof(struct stat));
@@ -151,31 +154,82 @@ bool is_reg(const char* path)
 }
 
 //-----------------------------------------------------------------------------
-bool mknod(const char* path)
+bool create_file(const char* path)
 {
 	// Permission mask: rw-r--r--
 	return ::mknod(path, S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, 0) == 0;
 }
 
 //-----------------------------------------------------------------------------
-bool unlink(const char* path)
+bool delete_file(const char* path)
 {
 	return (::unlink(path) == 0);
 }
 
 //-----------------------------------------------------------------------------
-bool mkdir(const char* path)
+bool create_directory(const char* path)
 {
 	// rwxr-xr-x permission mask
 	return (::mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0);
 }
 
 //-----------------------------------------------------------------------------
-bool rmdir(const char* path)
+bool delete_directory(const char* path)
 {
 	return (::rmdir(path) == 0);
 }
 
+//-----------------------------------------------------------------------------
+void list_files(const char* path, Vector<DynamicString>& files)
+{
+	DIR *dir;
+	struct dirent *entry;
+
+	if (!(dir = opendir(path)))
+	{
+		return;
+	}
+
+	while ((entry = readdir(dir)))
+	{
+		if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
+		{
+			continue;
+		}
+
+		DynamicString filename(default_allocator());
+
+		filename = entry->d_name;
+		files.push_back(filename);
+	}
+
+	closedir(dir);
+}
+
+//-----------------------------------------------------------------------------
+const char* normalize_path(const char* path)
+{
+	static char norm[MAX_PATH_LENGTH];
+	char* cur = norm;
+
+	while ((*path) != '\0')
+	{
+		if ((*path) == '\\')
+		{
+			(*cur) = PATH_SEPARATOR;
+		}
+		else
+		{
+			(*cur) = (*path);
+		}
+
+		path++;
+		cur++;
+	}
+
+	return norm;
+}
+
 //-----------------------------------------------------------------------------
 const char* get_cwd()
 {
@@ -216,29 +270,6 @@ const char* get_env(const char* env)
 	return envDevel;
 }
 
-////-----------------------------------------------------------------------------
-//bool ls(const char* path, List<Str>& fileList)
-//{
-//	DIR *dir;
-//	struct dirent *ent;
-
-//	dir = opendir(path);
-
-//	if (dir == NULL)
-//	{
-//		return false;
-//	}
-
-//	while ((ent = readdir (dir)) != NULL)
-//	{
-//		fileList.push_back(Str(ent->d_name));
-//	}
-
-//	closedir (dir);
-
-//	return true;
-//}
-
 //-----------------------------------------------------------------------------
 void init_os()
 {
@@ -302,5 +333,25 @@ void* lookup_symbol(void* library, const char* name)
 	return symbol;
 }
 
+//-----------------------------------------------------------------------------
+void execute_process(const char* args[])
+{
+	pid_t pid = fork();
+	CE_ASSERT(pid != -1, "Unable to fork");
+
+	if (pid)
+	{
+		int32_t dummy;
+		wait(&dummy);
+	}
+	else
+	{
+		int res = execv(args[0], (char* const*)args);
+		CE_ASSERT(res != -1, "Unable to exec '%s'. errno %d", args[0], res);
+		exit(EXIT_SUCCESS);
+	}
+}
+
+
 } // namespace os
 } // namespace crown

+ 51 - 5
engine/os/win/Thread.cpp

@@ -34,18 +34,52 @@ namespace os
 {
 
 //-----------------------------------------------------------------------------
-Thread::Thread(os::ThreadFunction f, LPVOID params, const char* name)
+Thread::Thread(const char* name) :
+	m_name(name),
+	m_is_running(false),
+	m_is_terminating(false)
 {
-	m_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) f, params, 0, NULL);
+}
 
-	CE_ASSERT(m_thread != NULL, "Unable to create thread");
+//-----------------------------------------------------------------------------
+Thread::~Thread()
+{
+}
 
-	m_name = name;
+//-----------------------------------------------------------------------------
+bool Thread::is_running() const
+{
+	return m_is_running;
 }
 
 //-----------------------------------------------------------------------------
-Thread::~Thread()
+bool Thread::is_terminating() const
+{
+	return m_is_terminating;
+}
+
+//-----------------------------------------------------------------------------
+void Thread::start()
+{
+	m_is_terminating = false;
+
+	m_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) Thread::background_proc, this, 0, NULL);
+
+	CE_ASSERT(m_thread != NULL, "Failed to create the thread '%s'", m_name);
+
+	m_is_running = true;
+}
+
+//-----------------------------------------------------------------------------
+void Thread::stop()
+{
+	m_is_terminating = true;
+}
+
+//-----------------------------------------------------------------------------
+int32_t	Thread::run()
 {
+	return 0;
 }
 
 //-----------------------------------------------------------------------------
@@ -62,5 +96,17 @@ void Thread::detach()
 	CE_ASSERT(closed, "Unable to close thread");
 }
 
+void* Thread::background_proc(void* thiz)
+{
+	Thread* thread  = (Thread*)thiz;
+
+	thread->run();
+
+	thread->m_is_running = false;
+
+	return NULL;
+}
+
+
 } // namespace os
 } // namespace crown

+ 19 - 2
engine/os/win/Thread.h

@@ -29,6 +29,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include <windows.h>
 #include <process.h>
 #include <WinBase.h>
+
 #include "Types.h"
 #include "OS.h"
 
@@ -43,16 +44,32 @@ class Thread
 {
 public:
 
-					Thread(os::ThreadFunction f, LPVOID params, const char* name);
+					Thread(const char* name);
 					~Thread();
 
+	const char*		name() const;
+
 	void			join();
 	void			detach();
 
+	bool			is_running() const;
+	bool			is_terminating() const;
+
+	void			start();
+	void			stop();
+
+	virtual int32_t	run();
+
 private:
 
-	HANDLE			m_thread;
+	static void*	background_proc(void* thiz);
+
+private:
+	
 	const char*		m_name;
+	bool			m_is_running;
+	bool			m_is_terminating;
+	HANDLE			m_thread;
 };
 
 } // namespace os

+ 95 - 14
engine/os/win/WinOS.cpp

@@ -111,9 +111,12 @@ bool is_absolute_path(const char* path)
 
 	if (string::strlen(path) > 0)
 	{
-		if ((path[0] >= 65 && path[0] <= 90) || (path[0] >= 97 && path[0] <= 122))
+		if ((path[0] >= 'c' && path[0] <= 'z') || (path[0] >= 'C' && path[0] <= 'Z'))
 		{
-			return true;
+			if (path[1] == ':')
+			{
+				return true;
+			}
 		}
 	}
 
@@ -129,7 +132,7 @@ bool exists(const char* path)
 }
 
 //-----------------------------------------------------------------------------
-bool is_dir(const char* path)
+bool is_directory(const char* path)
 {
 	DWORD fileAttr;
 	fileAttr = GetFileAttributes(path);
@@ -137,13 +140,13 @@ bool is_dir(const char* path)
 }
 
 //-----------------------------------------------------------------------------
-bool is_reg(const char* path)
+bool is_file(const char* path)
 {
-	return !is_dir(path);
+	return !is_directory(path);
 }
 
 //-----------------------------------------------------------------------------
-bool mknod(const char* path)
+bool create_file(const char* path)
 {
 	HANDLE hFile = CreateFile(path, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
 	if (hFile == INVALID_HANDLE_VALUE)
@@ -154,19 +157,19 @@ bool mknod(const char* path)
 }
 
 //-----------------------------------------------------------------------------
-bool unlink(const char* path)
+bool delete_file(const char* path)
 {
 	return DeleteFile(path) == TRUE;
 }
 
 //-----------------------------------------------------------------------------
-bool mkdir(const char* path)
+bool create_directory(const char* path)
 {
 	return CreateDirectory(path, NULL) == TRUE;
 }
 
 //-----------------------------------------------------------------------------
-bool rmdir(const char* path)
+bool delete_directory(const char* path)
 {
 	return RemoveDirectory(path) == TRUE;
 }
@@ -207,11 +210,56 @@ const char* get_env(const char* env)
 }
 
 //-----------------------------------------------------------------------------
-// bool ls(const char* path, List<Str>& fileList)
-// {
-//	// TODO
-//	return false; 
-//}
+void list_files(const char* path, Vector<DynamicString>& files)
+{
+	HANDLE file = INVALID_HANDLE_VALUE;
+	WIN32_FIND_DATA ffd;
+
+	char cur_path[MAX_PATH_LENGTH];
+
+	string::strncpy(cur_path, path, string::strlen(path) + 1);
+	string::strncat(cur_path, "\\*", 2);
+
+	file = FindFirstFile(cur_path, &ffd);
+
+	do
+	{
+		CE_ASSERT(file != INVALID_HANDLE_VALUE, "Unable to list files. errono %d", GetLastError());
+
+		if ((string::strcmp(ffd.cFileName, ".") == 0) || (string::strcmp(ffd.cFileName, "..") == 0))
+		{
+			continue;
+		}
+	
+		DynamicString filename(default_allocator());
+
+		filename = ffd.cFileName;
+		files.push_back(filename);
+	}
+	while (FindNextFile(file, &ffd) != 0);
+
+	FindClose(file);
+}
+
+//-----------------------------------------------------------------------------
+const char* normalize_path(const char* path)
+{
+	static char norm[MAX_PATH_LENGTH];
+
+	for (uint32_t i = 0; i < string::strlen(path)+1; i++)
+	{
+		if (path[i] == '/')
+		{
+			norm[i] = '\\';
+		}
+		else
+		{
+			norm[i] = path[i];
+		}
+	}
+
+	return norm;
+}
 
 //-----------------------------------------------------------------------------
 void init_os()
@@ -271,5 +319,38 @@ void* lookup_symbol(void* library, const char* name)
 	return symbol;
 }
 
+//-----------------------------------------------------------------------------
+void execute_process(const char* args[])
+{
+	STARTUPINFO info;
+	memset(&info, 0, sizeof(info));
+	info.cb = sizeof(info);
+
+	PROCESS_INFORMATION process;
+	memset(&process, 0, sizeof(process));
+
+	DynamicString cmds(default_allocator());
+
+	for (uint32_t i = 0; args[i] != NULL; i++)
+	{
+		cmds += args[i];
+		cmds += ' ';
+	}
+
+	// Necessary because CreateProcess second argument must be non-const
+	char tmp[1024];
+	string::strncpy(tmp, normalize_path(cmds.c_str()), string::strlen(cmds.c_str()));
+
+	int32_t res;
+	if (res = CreateProcess(args[0], tmp, NULL, NULL, TRUE, 0, NULL, NULL, &info, &process))
+	{
+	    ::WaitForSingleObject(process.hProcess, INFINITE);
+   		CloseHandle(process.hProcess);
+    	CloseHandle(process.hThread);
+	}
+
+	CE_ASSERT(res != 0, "Unable to create process for %s, errno: %d\n", args[0], GetLastError());
+}
+
 } // namespace os
 } // namespace crown

+ 305 - 0
engine/os/win/inttypes.h

@@ -0,0 +1,305 @@
+// ISO C9x  compliant inttypes.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 
+// 
+//  Copyright (c) 2006 Alexander Chemeris
+// 
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+// 
+//   1. Redistributions of source code must retain the above copyright notice,
+//      this list of conditions and the following disclaimer.
+// 
+//   2. Redistributions in binary form must reproduce the above copyright
+//      notice, this list of conditions and the following disclaimer in the
+//      documentation and/or other materials provided with the distribution.
+// 
+//   3. The name of the author may be used to endorse or promote products
+//      derived from this software without specific prior written permission.
+// 
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// 
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_INTTYPES_H_ // [
+#define _MSC_INTTYPES_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include "stdint.h"
+
+// 7.8 Format conversion of integer types
+
+typedef struct {
+   intmax_t quot;
+   intmax_t rem;
+} imaxdiv_t;
+
+// 7.8.1 Macros for format specifiers
+
+//#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [   See footnote 185 at page 198
+
+// The fprintf macros for signed integers are:
+#define PRId8       "d"
+#define PRIi8       "i"
+#define PRIdLEAST8  "d"
+#define PRIiLEAST8  "i"
+#define PRIdFAST8   "d"
+#define PRIiFAST8   "i"
+
+#define PRId16       "hd"
+#define PRIi16       "hi"
+#define PRIdLEAST16  "hd"
+#define PRIiLEAST16  "hi"
+#define PRIdFAST16   "hd"
+#define PRIiFAST16   "hi"
+
+#define PRId32       "I32d"
+#define PRIi32       "I32i"
+#define PRIdLEAST32  "I32d"
+#define PRIiLEAST32  "I32i"
+#define PRIdFAST32   "I32d"
+#define PRIiFAST32   "I32i"
+
+#define PRId64       "I64d"
+#define PRIi64       "I64i"
+#define PRIdLEAST64  "I64d"
+#define PRIiLEAST64  "I64i"
+#define PRIdFAST64   "I64d"
+#define PRIiFAST64   "I64i"
+
+#define PRIdMAX     "I64d"
+#define PRIiMAX     "I64i"
+
+#define PRIdPTR     "Id"
+#define PRIiPTR     "Ii"
+
+// The fprintf macros for unsigned integers are:
+#define PRIo8       "o"
+#define PRIu8       "u"
+#define PRIx8       "x"
+#define PRIX8       "X"
+#define PRIoLEAST8  "o"
+#define PRIuLEAST8  "u"
+#define PRIxLEAST8  "x"
+#define PRIXLEAST8  "X"
+#define PRIoFAST8   "o"
+#define PRIuFAST8   "u"
+#define PRIxFAST8   "x"
+#define PRIXFAST8   "X"
+
+#define PRIo16       "ho"
+#define PRIu16       "hu"
+#define PRIx16       "hx"
+#define PRIX16       "hX"
+#define PRIoLEAST16  "ho"
+#define PRIuLEAST16  "hu"
+#define PRIxLEAST16  "hx"
+#define PRIXLEAST16  "hX"
+#define PRIoFAST16   "ho"
+#define PRIuFAST16   "hu"
+#define PRIxFAST16   "hx"
+#define PRIXFAST16   "hX"
+
+#define PRIo32       "I32o"
+#define PRIu32       "I32u"
+#define PRIx32       "I32x"
+#define PRIX32       "I32X"
+#define PRIoLEAST32  "I32o"
+#define PRIuLEAST32  "I32u"
+#define PRIxLEAST32  "I32x"
+#define PRIXLEAST32  "I32X"
+#define PRIoFAST32   "I32o"
+#define PRIuFAST32   "I32u"
+#define PRIxFAST32   "I32x"
+#define PRIXFAST32   "I32X"
+
+#define PRIo64       "I64o"
+#define PRIu64       "I64u"
+#define PRIx64       "I64x"
+#define PRIX64       "I64X"
+#define PRIoLEAST64  "I64o"
+#define PRIuLEAST64  "I64u"
+#define PRIxLEAST64  "I64x"
+#define PRIXLEAST64  "I64X"
+#define PRIoFAST64   "I64o"
+#define PRIuFAST64   "I64u"
+#define PRIxFAST64   "I64x"
+#define PRIXFAST64   "I64X"
+
+#define PRIoMAX     "I64o"
+#define PRIuMAX     "I64u"
+#define PRIxMAX     "I64x"
+#define PRIXMAX     "I64X"
+
+#define PRIoPTR     "Io"
+#define PRIuPTR     "Iu"
+#define PRIxPTR     "Ix"
+#define PRIXPTR     "IX"
+
+// The fscanf macros for signed integers are:
+#define SCNd8       "d"
+#define SCNi8       "i"
+#define SCNdLEAST8  "d"
+#define SCNiLEAST8  "i"
+#define SCNdFAST8   "d"
+#define SCNiFAST8   "i"
+
+#define SCNd16       "hd"
+#define SCNi16       "hi"
+#define SCNdLEAST16  "hd"
+#define SCNiLEAST16  "hi"
+#define SCNdFAST16   "hd"
+#define SCNiFAST16   "hi"
+
+#define SCNd32       "ld"
+#define SCNi32       "li"
+#define SCNdLEAST32  "ld"
+#define SCNiLEAST32  "li"
+#define SCNdFAST32   "ld"
+#define SCNiFAST32   "li"
+
+#define SCNd64       "I64d"
+#define SCNi64       "I64i"
+#define SCNdLEAST64  "I64d"
+#define SCNiLEAST64  "I64i"
+#define SCNdFAST64   "I64d"
+#define SCNiFAST64   "I64i"
+
+#define SCNdMAX     "I64d"
+#define SCNiMAX     "I64i"
+
+#ifdef _WIN64 // [
+#  define SCNdPTR     "I64d"
+#  define SCNiPTR     "I64i"
+#else  // _WIN64 ][
+#  define SCNdPTR     "ld"
+#  define SCNiPTR     "li"
+#endif  // _WIN64 ]
+
+// The fscanf macros for unsigned integers are:
+#define SCNo8       "o"
+#define SCNu8       "u"
+#define SCNx8       "x"
+#define SCNX8       "X"
+#define SCNoLEAST8  "o"
+#define SCNuLEAST8  "u"
+#define SCNxLEAST8  "x"
+#define SCNXLEAST8  "X"
+#define SCNoFAST8   "o"
+#define SCNuFAST8   "u"
+#define SCNxFAST8   "x"
+#define SCNXFAST8   "X"
+
+#define SCNo16       "ho"
+#define SCNu16       "hu"
+#define SCNx16       "hx"
+#define SCNX16       "hX"
+#define SCNoLEAST16  "ho"
+#define SCNuLEAST16  "hu"
+#define SCNxLEAST16  "hx"
+#define SCNXLEAST16  "hX"
+#define SCNoFAST16   "ho"
+#define SCNuFAST16   "hu"
+#define SCNxFAST16   "hx"
+#define SCNXFAST16   "hX"
+
+#define SCNo32       "lo"
+#define SCNu32       "lu"
+#define SCNx32       "lx"
+#define SCNX32       "lX"
+#define SCNoLEAST32  "lo"
+#define SCNuLEAST32  "lu"
+#define SCNxLEAST32  "lx"
+#define SCNXLEAST32  "lX"
+#define SCNoFAST32   "lo"
+#define SCNuFAST32   "lu"
+#define SCNxFAST32   "lx"
+#define SCNXFAST32   "lX"
+
+#define SCNo64       "I64o"
+#define SCNu64       "I64u"
+#define SCNx64       "I64x"
+#define SCNX64       "I64X"
+#define SCNoLEAST64  "I64o"
+#define SCNuLEAST64  "I64u"
+#define SCNxLEAST64  "I64x"
+#define SCNXLEAST64  "I64X"
+#define SCNoFAST64   "I64o"
+#define SCNuFAST64   "I64u"
+#define SCNxFAST64   "I64x"
+#define SCNXFAST64   "I64X"
+
+#define SCNoMAX     "I64o"
+#define SCNuMAX     "I64u"
+#define SCNxMAX     "I64x"
+#define SCNXMAX     "I64X"
+
+#ifdef _WIN64 // [
+#  define SCNoPTR     "I64o"
+#  define SCNuPTR     "I64u"
+#  define SCNxPTR     "I64x"
+#  define SCNXPTR     "I64X"
+#else  // _WIN64 ][
+#  define SCNoPTR     "lo"
+#  define SCNuPTR     "lu"
+#  define SCNxPTR     "lx"
+#  define SCNXPTR     "lX"
+#endif  // _WIN64 ]
+
+//#endif // __STDC_FORMAT_MACROS ]
+
+// 7.8.2 Functions for greatest-width integer types
+
+// 7.8.2.1 The imaxabs function
+#define imaxabs _abs64
+
+// 7.8.2.2 The imaxdiv function
+
+// This is modified version of div() function from Microsoft's div.c found
+// in %MSVC.NET%\crt\src\div.c
+#ifdef STATIC_IMAXDIV // [
+static
+#else // STATIC_IMAXDIV ][
+_inline
+#endif // STATIC_IMAXDIV ]
+imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
+{
+   imaxdiv_t result;
+
+   result.quot = numer / denom;
+   result.rem = numer % denom;
+
+   if (numer < 0 && result.rem > 0) {
+      // did division wrong; must fix up
+      ++result.quot;
+      result.rem -= denom;
+   }
+
+   return result;
+}
+
+// 7.8.2.3 The strtoimax and strtoumax functions
+#define strtoimax _strtoi64
+#define strtoumax _strtoui64
+
+// 7.8.2.4 The wcstoimax and wcstoumax functions
+#define wcstoimax _wcstoi64
+#define wcstoumax _wcstoui64
+
+
+#endif // _MSC_INTTYPES_H_ ]

+ 1 - 1
engine/renderers/gl/GLRenderer.cpp

@@ -60,7 +60,7 @@ static const char* gl_error_to_string(GLenum error)
 }
 
 //-----------------------------------------------------------------------------
-#ifdef CROWN_DEBUG
+#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
 	#define GL_CHECK(function)\
 		function;\
 		do { GLenum error; CE_ASSERT((error = glGetError()) == GL_NO_ERROR,\

+ 99 - 56
engine/resource/ArchiveBundle.cpp

@@ -24,84 +24,127 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
 */
 
-#include "ArchiveBundle.h"
+#include "Bundle.h"
 #include "Filesystem.h"
-#include "Resource.h"
-#include "DiskFile.h"
+#include "HeapAllocator.h"
 #include "Log.h"
 #include "Memory.h"
+#include "Resource.h"
+#include "Types.h"
 
 namespace crown
 {
 
-//-----------------------------------------------------------------------------
-ArchiveBundle::ArchiveBundle(Filesystem& fs) :
-	m_filesystem(fs),
-	m_archive_file(NULL),
-	m_entries_count(0),
-	m_entries(NULL)
-{
-	// FIXME Default archive name
-	m_archive_file = (DiskFile*)m_filesystem.open("archive.bin", FOM_READ);
-	
-	ArchiveHeader header;
-	
-	// Read the header of the archive
-	m_archive_file->read(&header, sizeof(ArchiveHeader));
-	
-	Log::d("Version: %d", header.version);
-	Log::d("Entries: %d", header.entries_count);
-	Log::d("Checksum: %d", header.checksum);
-	
-	// No need to initialize memory
-	m_entries = (ArchiveEntry*)m_allocator.allocate(header.entries_count * sizeof(ArchiveEntry));
-
-	m_entries_count = header.entries_count;
-
-	// Read the entries
-	m_archive_file->read(m_entries, m_entries_count * sizeof(ArchiveEntry));
-}
+/// Structure of the archive
+///
+/// [ArchiveHeader]
+/// [ArchiveEntry]
+/// [ArchiveEntry]
+/// ...
+/// [ArchiveEntry]
+/// [ResourceData]
+/// [ResourceData]
+/// ...
+/// [ResourceData]
+///
+/// A valid archive must always have at least the archive header,
+/// starting at byte 0 of the archive file.
+///
+/// Newer archive versions must be totally backward compatible
+/// across minor engine releases, in order to be able to use
+/// recent version of the engine with older game archives.
 
-//-----------------------------------------------------------------------------
-ArchiveBundle::~ArchiveBundle()
+/// Source of resources
+class ArchiveBundle : public Bundle
 {
-	if (m_archive_file != NULL)
+public:
+
+	//-----------------------------------------------------------------------------
+	ArchiveBundle(Filesystem& fs) :
+		m_filesystem(fs), m_archive_file(NULL), m_entries_count(0), m_entries(NULL)
 	{
-		m_filesystem.close(m_archive_file);
+		// FIXME Default archive name
+		m_archive_file = m_filesystem.open( "archive.bin", FOM_READ);
+		
+		ArchiveHeader header;
+		
+		// Read the header of the archive
+		m_archive_file->read(&header, sizeof(ArchiveHeader));
+		
+		Log::d("Version: %d", header.version);
+		Log::d("Entries: %d", header.entries_count);
+		Log::d("Checksum: %d", header.checksum);
+		
+		// No need to initialize memory
+		m_entries = (ArchiveEntry*)m_allocator.allocate(header.entries_count * sizeof(ArchiveEntry));
+
+		m_entries_count = header.entries_count;
+
+		// Read the entries
+		m_archive_file->read(m_entries, m_entries_count * sizeof(ArchiveEntry));
 	}
-	
-	if (m_entries != NULL)
+
+	//-----------------------------------------------------------------------------
+	~ArchiveBundle()
 	{
-		m_allocator.deallocate(m_entries);
+		if (m_archive_file != NULL)
+		{
+			m_filesystem.close(m_archive_file);
+		}
+		
+		if (m_entries != NULL)
+		{
+			m_allocator.deallocate(m_entries);
+		}
+		
+		m_entries = NULL;
+		m_entries_count = 0;
 	}
-	
-	m_entries = NULL;
-	m_entries_count = 0;
-}
 
-//-----------------------------------------------------------------------------
-DiskFile* ArchiveBundle::open(ResourceId name)
-{
-	// Search the resource in the archive
-	for (uint32_t i = 0; i < m_entries_count; i++)
-	{		
-		if (m_entries[i].name == name.name && m_entries[i].type == name.type)
-		{
-			// If found, seek to the first byte of the resource data
-			m_archive_file->seek(m_entries[i].offset);
+	//-----------------------------------------------------------------------------
+	File* open(ResourceId name)
+	{
+		// Search the resource in the archive
+		for (uint32_t i = 0; i < m_entries_count; i++)
+		{		
+			if (m_entries[i].name == name.name && m_entries[i].type == name.type)
+			{
+				// If found, seek to the first byte of the resource data
+				m_archive_file->seek(m_entries[i].offset);
 
-			return (DiskFile*)m_archive_file;
+				return m_archive_file;
+			}
 		}
+
+		return NULL;
 	}
 
-	return NULL;
+	//-----------------------------------------------------------------------------
+	void close(File* resource)
+	{
+		// Does nothing, the stream is automatically closed at exit.
+		(void)resource;
+	}
+
+private:
+
+	HeapAllocator	m_allocator;
+	Filesystem&		m_filesystem;
+	File*			m_archive_file;
+	uint32_t		m_entries_count;
+	ArchiveEntry*	m_entries;
+};
+
+//-----------------------------------------------------------------------------
+Bundle* Bundle::create(Allocator& a, Filesystem& fs)
+{
+	return CE_NEW(a, ArchiveBundle)(fs);
 }
 
 //-----------------------------------------------------------------------------
-void ArchiveBundle::close(DiskFile* resource)
+void Bundle::destroy(Allocator& a, Bundle* bundle)
 {
-	// Does nothing, the stream is automatically closed at exit.
-	(void)resource;
+	CE_DELETE(a, bundle);
 }
 
 } // namespace crown

+ 7 - 4
engine/resource/Bundle.h

@@ -50,13 +50,16 @@ struct ArchiveEntry
 };
 
 class Filesystem;
-class DiskFile;
+class File;
 
 class Bundle
 {
 public:
 
-	virtual					~Bundle() {}
+	static Bundle* create(Allocator& a, Filesystem& fs);
+	static void destroy(Allocator& a, Bundle* bundle);
+
+	virtual ~Bundle() {}
 
 	/// Opens the resource file containing @a name resource
 	/// and returns a stream from which read the data from.
@@ -64,10 +67,10 @@ public:
 	/// The resource stream points exactly at the start
 	/// of the useful resource data, so you do not have to
 	/// care about skipping headers, metadatas and so on.
-	virtual DiskFile*		open(ResourceId name) = 0;
+	virtual File* open(ResourceId name) = 0;
 
 	/// Closes the resource file.
-	virtual void			close(DiskFile* resource) = 0;
+	virtual void close(File* resource) = 0;
 };
 
 } // namespace crown

+ 58 - 28
engine/resource/FileBundle.cpp

@@ -25,55 +25,85 @@ OTHER DEALINGS IN THE SOFTWARE.
 */
 
 #include <stdio.h>
-#include "FileBundle.h"
+#include <inttypes.h>
+
+#include "Allocator.h"
+#include "Bundle.h"
 #include "Filesystem.h"
 #include "Resource.h"
-#include "DiskFile.h"
-#include "Log.h"
 #include "StringUtils.h" 
+#include "Types.h"
 #include "OS.h"
 
 namespace crown
 {
 
-//-----------------------------------------------------------------------------
-FileBundle::FileBundle(Filesystem& fs) :
-	m_filesystem(fs)
-{
-}
+const uint32_t	RESOURCE_MAGIC_NUMBER		= 0xCE010101;
+const uint32_t	RESOURCE_VERSION			= 2;
 
-//-----------------------------------------------------------------------------
-FileBundle::~FileBundle()
+/// Contains the header data common to all
+/// types of resources passing through the
+/// standard Compiler mechanics.
+struct ResourceHeader
 {
-}
+	uint32_t	magic;		// Magic number used to identify the file
+	uint32_t	version;	// Version of the compiler used to compile the resource
+	uint32_t	size;		// Size of the resource data _not_ including this header in bytes
+};
 
-//-----------------------------------------------------------------------------
-DiskFile* FileBundle::open(ResourceId name)
+class FileBundle : public Bundle
 {
-	// Convert name/type into strings
-	char resource_name[512];
-	snprintf(resource_name, 512, "%.8X%.8X", name.name, name.type);
+public:
+
+	//-----------------------------------------------------------------------------
+	FileBundle(Filesystem& fs) : m_filesystem(fs) {}
 
-	// Search the resource in the filesystem
-	bool exists = m_filesystem.exists(resource_name);
-	CE_ASSERT(exists == true, "Resource does not exist: %s", resource_name);
+	//-----------------------------------------------------------------------------
+	File* open(ResourceId name)
+	{
+		// Convert name/type into strings
+		char resource_name[512];
+		snprintf(resource_name, 512, "%"PRIx64"", name.id);
+		
+		// Search the resource in the filesystem
+		// bool exists = m_filesystem.exists(resource_name);
+		// CE_ASSERT(exists == true, "Resource does not exist: %s", resource_name);
 
-	// Open the resource and check magic number/version
-	DiskFile* file = (DiskFile*)m_filesystem.open(resource_name, FOM_READ);
+		// Open the resource and check magic number/version
+		File* file = m_filesystem.open(resource_name, FOM_READ);
 
-	ResourceHeader header;
-	file->read(&header, sizeof(ResourceHeader));
+		CE_ASSERT(file != NULL, "Resource %s does not exist", resource_name);
 
-	CE_ASSERT(header.magic == RESOURCE_MAGIC_NUMBER, "Resource is not valid: %s", resource_name);
-	CE_ASSERT(header.version == RESOURCE_VERSION, "Resource version mismatch: %s", resource_name);
+		ResourceHeader header;
+		file->read(&header, sizeof(ResourceHeader));
 
-	return file;
+		CE_ASSERT(header.magic == RESOURCE_MAGIC_NUMBER, "Resource is not valid: %s", resource_name);
+		CE_ASSERT(header.version == RESOURCE_VERSION, "Resource version mismatch: %s", resource_name);
+
+		return file;
+	}
+
+	//-----------------------------------------------------------------------------
+	void close(File* resource)
+	{
+		m_filesystem.close(resource);
+	}
+
+private:
+
+	Filesystem& m_filesystem;
+};
+
+//-----------------------------------------------------------------------------
+Bundle* Bundle::create(Allocator& a, Filesystem& fs)
+{
+	return CE_NEW(a, FileBundle)(fs);
 }
 
 //-----------------------------------------------------------------------------
-void FileBundle::close(DiskFile* resource)
+void Bundle::destroy(Allocator& a, Bundle* bundle)
 {
-	m_filesystem.close(resource);
+	CE_DELETE(a, bundle);
 }
 
 } // namespace crown

+ 0 - 71
engine/resource/FileBundle.h

@@ -1,71 +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.
-*/
-
-#pragma once
-
-#include "Types.h"
-#include "Bundle.h"
-
-namespace crown
-{
-
-class Filesystem;
-class DiskFile;
-
-const uint32_t	RESOURCE_MAGIC_NUMBER		= 0xCE010101;
-const uint32_t	RESOURCE_VERSION			= 2;
-
-/// Contains the header data common to all
-/// types of resources passing through the
-/// standard Compiler mechanics.
-struct ResourceHeader
-{
-	uint32_t	magic;		// Magic number used to identify the file
-	uint32_t	version;	// Version of the compiler used to compile the resource
-	uint32_t	size;		// Size of the resource data _not_ including this header in bytes
-};
-
-/// Source of resources
-class FileBundle : public Bundle
-{
-public:
-
-					FileBundle(Filesystem& fs);
-					~FileBundle();
-
-	/// @copydoc Bundle::open()
-	DiskFile*		open(ResourceId name);
-
-	/// @copydoc Bundle::close()
-	void			close(DiskFile* resource);
-
-
-private:
-
-	Filesystem&		m_filesystem;
-};
-
-} // namespace crown

+ 0 - 57
engine/resource/FontResource.cpp

@@ -1,57 +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 "Types.h"
-#include "FontResource.h"
-#include "Bundle.h"
-
-namespace crown
-{
-
-//-----------------------------------------------------------------------------
-void* FontResource::load(Allocator& /*allocator*/, Bundle& /*bundle*/, ResourceId /*id*/)
-{
-	return NULL;
-}
-
-//-----------------------------------------------------------------------------
-void FontResource::online(void* resource)
-{
-	(void)resource;
-}
-
-//-----------------------------------------------------------------------------
-void FontResource::unload(Allocator& /*allocator*/, void* /*resource*/)
-{
-}
-
-//-----------------------------------------------------------------------------
-void FontResource::offline(void* /*resource*/)
-{
-}
-
-} // namespace crown
-

+ 23 - 7
engine/resource/FontResource.h

@@ -28,21 +28,37 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 #include "Types.h"
 #include "Resource.h"
+#include "Bundle.h"
+#include "Allocator.h"
 
 namespace crown
 {
 
-class Allocator;
-class Bundle;
-
 class FontResource
 {
 public:
 
-	static void*		load(Allocator& allocator, Bundle& bundle, ResourceId id);
-	static void			unload(Allocator& allocator, void* resource);
-	static void			online(void* resource);
-	static void			offline(void* resource);
+	//-----------------------------------------------------------------------------
+	static void* load(Allocator& /*allocator*/, Bundle& /*bundle*/, ResourceId /*id*/)
+	{
+		return NULL;
+	}
+
+	//-----------------------------------------------------------------------------
+	static void online(void* resource)
+	{
+		(void)resource;
+	}
+
+	//-----------------------------------------------------------------------------
+	static void unload(Allocator& /*allocator*/, void* /*resource*/)
+	{
+	}
+
+	//-----------------------------------------------------------------------------
+	static void offline(void* /*resource*/)
+	{
+	}
 
 public:
 

+ 98 - 0
engine/resource/LuaResource.h

@@ -0,0 +1,98 @@
+/*
+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.
+*/
+
+#pragma once
+
+#include "Types.h"
+#include "Resource.h"
+#include "Bundle.h"
+#include "Allocator.h"
+#include "File.h"
+
+namespace crown
+{
+
+// Bump the version whenever a change in the header is made
+const uint32_t LUA_RESOURCE_VERSION = 1;
+
+struct LuaHeader
+{
+	uint32_t	version;	// Lua resource version
+	uint32_t	size;		// Size of lua code
+};
+
+class LuaResource
+{
+public:
+
+	//-----------------------------------------------------------------------------
+	static void* load(Allocator& allocator, Bundle& bundle, ResourceId id)
+	{
+		File* file = bundle.open(id);
+
+		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;
+	}
+
+	//-----------------------------------------------------------------------------
+	static void online(void* /*resource*/) {}
+
+	//-----------------------------------------------------------------------------
+	static void unload(Allocator& allocator, void* resource)
+	{
+		CE_ASSERT_NOT_NULL(resource);
+
+		allocator.deallocate(((LuaResource*)resource)->m_data);
+		allocator.deallocate(resource);
+	}
+
+	//-----------------------------------------------------------------------------
+	static void offline(void* /*resource*/) {}
+
+public:
+
+	uint32_t size() const
+	{
+		return ((LuaHeader*) m_data)->size;
+	}
+
+	const uint8_t* code() const
+	{
+		return m_data + sizeof(LuaHeader);
+	}
+
+private:
+
+	uint8_t* m_data;
+};
+
+} // namespace crown

+ 0 - 60
engine/resource/MaterialResource.cpp

@@ -1,60 +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 "Types.h"
-#include "MaterialResource.h"
-#include "Bundle.h"
-
-namespace crown
-{
-
-//-----------------------------------------------------------------------------
-void* MaterialResource::load(Allocator& /*allocator*/, Bundle& /*bundle*/, ResourceId /*id*/)
-{
-	return NULL;
-}
-
-//-----------------------------------------------------------------------------
-void MaterialResource::online(void* material)
-{
-	(void)material;
-	// TODO
-}
-
-//-----------------------------------------------------------------------------
-void MaterialResource::unload(Allocator& /*allocator*/, void* /*material*/)
-{
-	// TODO
-}
-
-//-----------------------------------------------------------------------------
-void MaterialResource::offline(void* /*resource*/)
-{
-	// TODO
-}
-
-} // namespace crown
-

+ 26 - 6
engine/resource/MaterialResource.h

@@ -33,6 +33,8 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "Color4.h"
 #include "Material.h"
 #include "Texture.h"
+#include "Bundle.h"
+#include "Allocator.h"
 
 namespace crown
 {
@@ -41,8 +43,6 @@ namespace crown
 /// @note The maximum number of usable layers depends on the graphic card/Renderer config.
 const uint32_t MAX_TEXTURE_LAYERS = 8;
 
-class Bundle;
-class Allocator;
 
 /// A material describes the visual properties of a surface.
 /// It is primarly intended for rendering purposes but can
@@ -51,10 +51,30 @@ class MaterialResource
 {
 public:
 
-	static void*		load(Allocator& allocator, Bundle& bundle, ResourceId id);
-	static void			unload(Allocator& allocator, void* resource);
-	static void			online(void* resource);
-	static void			offline(void* resource);
+	//-----------------------------------------------------------------------------
+	static void* load(Allocator& /*allocator*/, Bundle& /*bundle*/, ResourceId /*id*/)
+	{
+		return NULL;
+	}
+
+	//-----------------------------------------------------------------------------
+	static void online(void* material)
+	{
+		(void)material;
+		// TODO
+	}
+
+	//-----------------------------------------------------------------------------
+	static void unload(Allocator& /*allocator*/, void* /*material*/)
+	{
+		// TODO
+	}
+
+	//-----------------------------------------------------------------------------
+	static void offline(void* /*resource*/)
+	{
+		// TODO
+	}
 
 private:
 

+ 0 - 80
engine/resource/MeshResource.cpp

@@ -1,80 +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 "MeshResource.h"
-#include "Bundle.h"
-#include "Log.h"
-#include "DiskFile.h"
-#include "Assert.h"
-#include "Allocator.h"
-#include "Device.h"
-#include "Renderer.h"
-
-namespace crown
-{
-
-//-----------------------------------------------------------------------------
-void* MeshResource::load(Allocator& allocator, Bundle& bundle, ResourceId id)
-{
-	DiskFile* 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));
-
-	// Read vertices
-	file->read(&resource->m_vertex_count, sizeof(uint32_t));
-	resource->m_vertices = (float*) allocator.allocate(sizeof(float) * resource->m_vertex_count);
-	file->read(resource->m_vertices, sizeof(float) * resource->m_vertex_count);
-
-	// Read triangles
-	file->read(&resource->m_index_count, sizeof(uint32_t));
-	resource->m_indices = (uint16_t*) allocator.allocate(sizeof(uint16_t) * resource->m_index_count);
-	file->read(resource->m_indices, sizeof(uint16_t) * resource->m_index_count);
-
-	bundle.close(file);
-
-	return resource;
-}
-
-//-----------------------------------------------------------------------------
-void MeshResource::online(void* )
-{
-}
-
-//-----------------------------------------------------------------------------
-void MeshResource::unload(Allocator& , void* )
-{
-}
-
-//-----------------------------------------------------------------------------
-void MeshResource::offline(void* /*resource*/)
-{
-
-}
-
-} // namespace crown

+ 40 - 7
engine/resource/MeshResource.h

@@ -30,6 +30,8 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "Resource.h"
 #include "PixelFormat.h"
 #include "Texture.h"
+#include "Allocator.h"
+#include "Bundle.h"
 
 namespace crown
 {
@@ -45,17 +47,48 @@ struct MeshHeader
 	uint32_t	padding[16];
 };
 
-class Bundle;
-class Allocator;
-
 class MeshResource
 {
 public:
 
-	static void*		load(Allocator& allocator, Bundle& bundle, ResourceId id);
-	static void			unload(Allocator& allocator, void* resource);
-	static void			online(void* resource);
-	static void			offline(void* resource);
+	//-----------------------------------------------------------------------------
+	static void* load(Allocator& allocator, Bundle& bundle, ResourceId id)
+	{
+		File* file = bundle.open(id);
+
+		MeshResource* resource = (MeshResource*)allocator.allocate(sizeof(MeshResource));
+		file->read(&resource->m_header, sizeof(MeshHeader));
+
+		// Read vertices
+		file->read(&resource->m_vertex_count, sizeof(uint32_t));
+		resource->m_vertices = (float*) allocator.allocate(sizeof(float) * resource->m_vertex_count);
+		file->read(resource->m_vertices, sizeof(float) * resource->m_vertex_count);
+
+		// Read triangles
+		file->read(&resource->m_index_count, sizeof(uint32_t));
+		resource->m_indices = (uint16_t*) allocator.allocate(sizeof(uint16_t) * resource->m_index_count);
+		file->read(resource->m_indices, sizeof(uint16_t) * resource->m_index_count);
+
+		bundle.close(file);
+
+		return resource;
+	}
+
+	//-----------------------------------------------------------------------------
+	static void online(void* )
+	{
+	}
+
+	//-----------------------------------------------------------------------------
+	static void unload(Allocator& , void* )
+	{
+	}
+
+	//-----------------------------------------------------------------------------
+	static void offline(void* /*resource*/)
+	{
+
+	}
 
 public:
 

+ 122 - 0
engine/resource/PackageResource.h

@@ -0,0 +1,122 @@
+/*
+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.
+*/
+
+#pragma once
+
+#include "Types.h"
+#include "Resource.h"
+#include "Bundle.h"
+#include "Allocator.h"
+#include "File.h"
+
+namespace crown
+{
+
+// All offsets are absolute
+struct PackageHeader
+{
+	uint32_t num_textures;
+	uint32_t textures_offset;
+	uint32_t num_scripts;
+	uint32_t scripts_offset;
+};
+
+class PackageResource
+{
+public:
+
+	//-----------------------------------------------------------------------------
+	static void* load(Allocator& allocator, Bundle& bundle, ResourceId id)
+	{
+		File* file = bundle.open(id);
+
+		const size_t file_size = file->size() - 12;
+		PackageResource* res = (PackageResource*) allocator.allocate(sizeof(PackageResource));
+		res->m_data = (char*) allocator.allocate(file_size);
+		file->read(res->m_data, file_size);
+
+		bundle.close(file);
+
+		return res;
+	}
+
+	//-----------------------------------------------------------------------------
+	static void online(void* /*resource*/) {}
+
+	//-----------------------------------------------------------------------------
+	static void unload(Allocator& allocator, void* resource)
+	{
+		CE_ASSERT_NOT_NULL(resource);
+
+		allocator.deallocate(((PackageResource*)resource)->m_data);
+		allocator.deallocate(resource);
+	}
+
+	//-----------------------------------------------------------------------------
+	static void offline(void* /*resource*/) {}
+
+public:
+
+	//-----------------------------------------------------------------------------
+	uint32_t num_textures() const
+	{
+		CE_ASSERT_NOT_NULL(m_data);
+
+		return ((PackageHeader*)m_data)->num_textures;
+	}
+
+	//-----------------------------------------------------------------------------
+	uint32_t num_scripts() const
+	{
+		CE_ASSERT_NOT_NULL(m_data);
+
+		return ((PackageHeader*)m_data)->num_scripts;
+	}
+
+	//-----------------------------------------------------------------------------
+	ResourceId get_texture_id(uint32_t i) const
+	{
+		CE_ASSERT(i < num_textures(), "Index out of bounds");
+
+		ResourceId* begin = (ResourceId*) (m_data + ((PackageHeader*)m_data)->textures_offset);
+		return begin[i];
+	}
+
+	//-----------------------------------------------------------------------------
+	ResourceId get_script_id(uint32_t i) const
+	{
+		CE_ASSERT(i < num_scripts(), "Index out of bounds");
+
+		ResourceId* begin = (ResourceId*) (m_data + ((PackageHeader*)m_data)->scripts_offset);
+		return begin[i];
+	}
+
+private:
+
+	char* m_data;
+};
+
+} // namespace crown

+ 16 - 13
engine/resource/Resource.h

@@ -34,29 +34,32 @@ namespace crown
 {
 
 /// Hashed values for supported resource types
-const char* const TEXTURE_EXTENSION			= "tga";
-const char* const MESH_EXTENSION			= "dae";
-const char* const SCRIPT_EXTENSION			= "lua";
-const char* const TEXT_EXTENSION			= "txt";
+const char* const TEXTURE_EXTENSION			= "texture";
+const char* const MESH_EXTENSION			= "mesh";
+const char* const LUA_EXTENSION				= "lua";
+const char* const TEXT_EXTENSION			= "text";
 const char* const MATERIAL_EXTENSION		= "material";
-const char* const SOUND_EXTENSION			= "wav";
+const char* const SOUND_EXTENSION			= "sound";
+const char* const CONFIG_EXTENSION			= "config";
+const char* const PACKAGE_EXTENSION			= "package";
 
-const uint32_t TEXTURE_TYPE					= 0x1410A16A;
-const uint32_t MESH_TYPE					= 0xE8239EEC;
-const uint32_t SCRIPT_TYPE					= 0xD96E7C37;
-const uint32_t TEXT_TYPE					= 0x9000BF0B;
+const uint32_t TEXTURE_TYPE					= 0xDEED4F7;
+const uint32_t MESH_TYPE					= 0xA6E48B29;
+const uint32_t LUA_TYPE						= 0xD96E7C37;
+const uint32_t TEXT_TYPE					= 0x45CC650;
 const uint32_t MATERIAL_TYPE				= 0x46807A92;
-const uint32_t SOUND_TYPE					= 0x8E128AA1;
+const uint32_t SOUND_TYPE					= 0xD196AB6E;
+const uint32_t CONFIG_TYPE					= 0x17DEA5E1;
+const uint32_t PACKAGE_TYPE					= 0xC0A2212C;
 
 /// 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;

+ 0 - 0
tools/core/formats/ResourceFormat.h → engine/resource/ResourceFormat.h


+ 4 - 2
engine/resource/ResourceLoader.cpp

@@ -47,13 +47,15 @@ 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();
 
 	LoadResourceId lr_id = m_num_requests++;
 	LoadResource lr;
 	lr.id = lr_id;
+	lr.type = type;
 	lr.resource = resource;
 
 	m_requests.push_back(lr);
@@ -107,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;

+ 3 - 1
engine/resource/ResourceLoader.h

@@ -33,6 +33,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "List.h"
 #include "Mutex.h"
 #include "Cond.h"
+#include "OS.h"
 
 namespace crown
 {
@@ -54,6 +55,7 @@ enum LoadResourceStatus
 struct LoadResource
 {
 	LoadResourceId id;
+	uint32_t type;
 	ResourceId resource;
 };
 
@@ -73,7 +75,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 - 15
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,13 +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);
 
@@ -70,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;
 	}
 }
@@ -86,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;
 }
@@ -94,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;
 }
@@ -102,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;
 }
@@ -125,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;
 }
 
 //-----------------------------------------------------------------------------
@@ -158,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);
@@ -169,6 +175,7 @@ ResourceId ResourceManager::load(ResourceId name)
 		ResourceEntry entry;
 
 		entry.id = name;
+		entry.type = type;
 		entry.references = 1;
 		entry.resource = NULL;
 
@@ -177,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);
 
@@ -193,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;
 }
 

+ 5 - 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:
@@ -120,6 +122,7 @@ private:
 
 private:
 
+	friend class			ResourcePackage;
 	friend class			Device;
 };
 

+ 107 - 0
engine/resource/ResourcePackage.h

@@ -0,0 +1,107 @@
+/*
+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.
+*/
+
+#pragma once
+
+#include "Types.h"
+#include "ResourceManager.h"
+#include "PackageResource.h"
+#include "Resource.h"
+
+namespace crown
+{
+
+/// Collection of resources to load in a batch.
+class ResourcePackage
+{
+public:
+
+	//-----------------------------------------------------------------------------
+	ResourcePackage(ResourceManager& resman, const ResourceId id, const PackageResource* package)
+		: m_resource_manager(&resman), m_package_id(id), m_package(package), m_has_loaded(false)
+	{
+		CE_ASSERT_NOT_NULL(package);
+	}
+
+	/// Loads all the resources in the package.
+	/// @note
+	/// The resources are not immediately available after the call is made,
+	/// instead, you have to poll for completion with has_loaded()
+	void load()
+	{
+		for (uint32_t i = 0; i < m_package->num_textures(); i++)
+		{
+			m_resource_manager->load(TEXTURE_TYPE, m_package->get_texture_id(i));
+		}
+
+		for (uint32_t i = 0; i < m_package->num_scripts(); i++)
+		{
+			m_resource_manager->load(LUA_TYPE, m_package->get_script_id(i));
+		}
+	}
+
+	/// Unloads all the resources in the package.
+	void unload()
+	{
+		for (uint32_t i = 0; i < m_package->num_textures(); i++)
+		{
+			m_resource_manager->unload(m_package->get_texture_id(i));
+		}
+
+		for (uint32_t i = 0; i < m_package->num_scripts(); i++)
+		{
+			m_resource_manager->unload(m_package->get_script_id(i));
+		}		
+	}
+
+	/// Waits until the package has been loaded. 
+	void flush()
+	{
+		m_resource_manager->flush();
+		m_has_loaded = true;
+	}
+
+	/// Returns whether the package has been loaded.
+	bool has_loaded() const
+	{
+		return m_has_loaded;
+	}
+
+	/// Returns the resource id of the package.
+	ResourceId resource_id() const
+	{
+		return m_package_id;
+	}
+
+private:
+
+	ResourceManager* m_resource_manager;
+	const ResourceId m_package_id;
+	const PackageResource* m_package;
+	bool m_has_loaded;
+};
+
+} // namespace crown

+ 4 - 0
engine/resource/ResourceRegistry.cpp

@@ -25,18 +25,22 @@ OTHER DEALINGS IN THE SOFTWARE.
 */
 
 #include "ResourceRegistry.h"
+#include "LuaResource.h"
 #include "TextureResource.h"
 #include "MeshResource.h"
 #include "SoundResource.h"
+#include "PackageResource.h"
 
 namespace crown
 {
 
 static const ResourceCallback RESOURCE_CALLBACK_REGISTRY[] =
 {
+	{ LUA_TYPE, LuaResource::load, LuaResource::unload, LuaResource::online, LuaResource::offline },
 	{ TEXTURE_TYPE, TextureResource::load, TextureResource::unload, TextureResource::online, TextureResource::offline },
 	{ MESH_TYPE, MeshResource::load, MeshResource::unload, MeshResource::online, MeshResource::offline },
 	{ SOUND_TYPE, SoundResource::load, SoundResource::unload, SoundResource::online, SoundResource::offline },
+	{ PACKAGE_TYPE, PackageResource::load, PackageResource::unload, PackageResource::online, PackageResource::offline },	
 	{ 0, NULL, NULL, NULL, NULL }
 };
 

+ 0 - 81
engine/resource/SoundResource.cpp

@@ -1,81 +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 "SoundResource.h"
-#include "Bundle.h"
-#include "Log.h"
-#include "DiskFile.h"
-#include "Assert.h"
-#include "Allocator.h"
-#include "Device.h"
-
-namespace crown
-{
-
-//-----------------------------------------------------------------------------
-void* SoundResource::load(Allocator& allocator, Bundle& bundle, ResourceId id)
-{
-	DiskFile* 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));
-
-	size_t size = resource->size();
-
-	resource->m_data = (uint8_t*)allocator.allocate(sizeof(uint8_t) * size);
-
-	file->read(resource->m_data, size);
-
-	bundle.close(file);
-
-	return resource;
-}
-
-//-----------------------------------------------------------------------------
-void SoundResource::online(void* resource)
-{
-	CE_ASSERT(resource != NULL, "Resource not loaded");
-}
-
-//-----------------------------------------------------------------------------
-void SoundResource::unload(Allocator& allocator, void* resource)
-{
-	CE_ASSERT(resource != NULL, "Resource not loaded");
-
-	allocator.deallocate(((SoundResource*)resource)->m_data);
-	allocator.deallocate(resource);
-}
-
-//-----------------------------------------------------------------------------
-void SoundResource::offline(void* /*resource*/)
-{
-
-}
-
-} // namespace crown

+ 42 - 7
engine/resource/SoundResource.h

@@ -28,6 +28,8 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 #include "Types.h"
 #include "Resource.h"
+#include "Bundle.h"
+#include "Allocator.h"
 
 namespace crown
 {
@@ -42,17 +44,50 @@ struct SoundHeader
 	uint32_t 	bits_per_sample;
 };
 
-class Bundle;
-class Allocator;
-
 class SoundResource
 {
 public:
 
-	static void*		load(Allocator& allocator, Bundle& bundle, ResourceId id);
-	static void			unload(Allocator& allocator, void* resource);
-	static void			online(void* resource);
-	static void			offline(void* resource);
+	//-----------------------------------------------------------------------------
+	static void* load(Allocator& allocator, Bundle& bundle, ResourceId id)
+	{
+		File* file = bundle.open(id);
+
+		SoundResource* resource = (SoundResource*)allocator.allocate(sizeof(SoundResource));
+
+		file->read(&resource->m_header, sizeof(SoundHeader));
+
+		size_t size = resource->size();
+
+		resource->m_data = (uint8_t*)allocator.allocate(sizeof(uint8_t) * size);
+
+		file->read(resource->m_data, size);
+
+		bundle.close(file);
+
+		return resource;
+	}
+
+	//-----------------------------------------------------------------------------
+	static void online(void* resource)
+	{
+		CE_ASSERT(resource != NULL, "Resource not loaded");
+	}
+
+	//-----------------------------------------------------------------------------
+	static void unload(Allocator& allocator, void* resource)
+	{
+		CE_ASSERT(resource != NULL, "Resource not loaded");
+
+		allocator.deallocate(((SoundResource*)resource)->m_data);
+		allocator.deallocate(resource);
+	}
+
+	//-----------------------------------------------------------------------------
+	static void offline(void* /*resource*/)
+	{
+
+	}
 
 public:
 

+ 0 - 82
engine/resource/TextureResource.cpp

@@ -1,82 +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 "TextureResource.h"
-#include "Bundle.h"
-#include "Log.h"
-#include "DiskFile.h"
-#include "Assert.h"
-#include "Allocator.h"
-#include "Device.h"
-#include "Renderer.h"
-
-namespace crown
-{
-
-//-----------------------------------------------------------------------------
-void* TextureResource::load(Allocator& allocator, Bundle& bundle, ResourceId id)
-{
-	DiskFile* 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));
-
-	size_t size = resource->width() * resource->height() * Pixel::bytes_per_pixel(resource->format());
-
-	resource->m_data = (uint8_t*)allocator.allocate(sizeof(uint8_t) * size);
-
-	file->read(resource->m_data, size);
-
-	bundle.close(file);
-
-	return resource;
-}
-
-//-----------------------------------------------------------------------------
-void TextureResource::online(void* resource)
-{
-	CE_ASSERT(resource != NULL, "Resource not loaded");
-}
-
-//-----------------------------------------------------------------------------
-void TextureResource::unload(Allocator& allocator, void* resource)
-{
-	CE_ASSERT(resource != NULL, "Resource not loaded");
-
-	allocator.deallocate(((TextureResource*)resource)->m_data);
-	allocator.deallocate(resource);
-}
-
-//-----------------------------------------------------------------------------
-void TextureResource::offline(void* /*resource*/)
-{
-
-}
-
-} // namespace crown

+ 62 - 11
engine/resource/TextureResource.h

@@ -30,6 +30,9 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "Resource.h"
 #include "PixelFormat.h"
 #include "Texture.h"
+#include "Bundle.h"
+#include "Allocator.h"
+#include "File.h"
 
 namespace crown
 {
@@ -45,24 +48,72 @@ struct TextureHeader
 	uint32_t	height;		// Height in pixels
 };
 
-class Bundle;
-class Allocator;
-
 class TextureResource
 {
 public:
 
-	static void*		load(Allocator& allocator, Bundle& bundle, ResourceId id);
-	static void			unload(Allocator& allocator, void* resource);
-	static void			online(void* resource);
-	static void			offline(void* resource);
+	//-----------------------------------------------------------------------------
+	static void* load(Allocator& allocator, Bundle& bundle, ResourceId id)
+	{
+		File* file = bundle.open(id);
+
+		TextureResource* resource = (TextureResource*)allocator.allocate(sizeof(TextureResource));
+
+		file->read(&resource->m_header, sizeof(TextureHeader));
+
+		size_t size = resource->width() * resource->height() * Pixel::bytes_per_pixel(resource->format());
+
+		resource->m_data = (uint8_t*)allocator.allocate(sizeof(uint8_t) * size);
+
+		file->read(resource->m_data, size);
+
+		bundle.close(file);
+
+		return resource;
+	}
+
+	//-----------------------------------------------------------------------------
+	static void online(void* resource)
+	{
+		CE_ASSERT(resource != NULL, "Resource not loaded");
+	}
+
+	//-----------------------------------------------------------------------------
+	static void unload(Allocator& allocator, void* resource)
+	{
+		CE_ASSERT(resource != NULL, "Resource not loaded");
+
+		allocator.deallocate(((TextureResource*)resource)->m_data);
+		allocator.deallocate(resource);
+	}
+
+	//-----------------------------------------------------------------------------
+	static void offline(void* /*resource*/)
+	{
+
+	}
 
 public:
 
-	PixelFormat			format() const { return (PixelFormat) m_header.format; }
-	uint32_t			width() const { return m_header.width; }
-	uint32_t			height() const { return m_header.height; }
-	const uint8_t*		data() const { return m_data; }
+	PixelFormat format() const
+	{
+		return (PixelFormat) m_header.format;
+	}
+
+	uint32_t width() const
+	{
+		return m_header.width;
+	}
+
+	uint32_t height() const
+	{
+		return m_header.height;
+	}
+
+	const uint8_t* data() const
+	{
+		return m_data;
+	}
 
 private:
 

+ 6 - 0
engine/tests/CMakeLists.txt

@@ -9,16 +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(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(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-strings)
+add_test(json-test ${EXECUTABLE_OUTPUT_PATH}/json)
 

+ 3 - 3
engine/tests/allocators.cpp

@@ -13,11 +13,11 @@ int main()
 	char* char_buffer = (char*)malloc_allocator.allocate(128);
 	CE_ASSERT(malloc_allocator.allocated_size() >= 128, "Allocated size differs from requested size");
 
-	printf("HeapAllocator::get_allocated_size(): %d\n", malloc_allocator.allocated_size());
+	printf("HeapAllocator::get_allocated_size(): %d\n", (uint32_t)malloc_allocator.allocated_size());
 
 	malloc_allocator.deallocate(char_buffer);
 
-	printf("HeapAllocator::get_allocated_size(): %d\n", malloc_allocator.allocated_size());
+	printf("HeapAllocator::get_allocated_size(): %d\n", (uint32_t)malloc_allocator.allocated_size());
 	//CE_ASSERT(malloc_allocator.get_allocated_size() == 0);
 
 	uint8_t buffer[1024 * 1024];
@@ -27,6 +27,6 @@ int main()
 	stack.allocate(12);
 	stack.allocate(5);
 
-	memory::dump(buffer, stack.allocated_size(), 4);
+	//memory::dump(buffer, stack.allocated_size(), 4);
 }
 

+ 3 - 3
engine/tests/compressors.cpp

@@ -20,12 +20,12 @@ int main()
  	compressed_string = compressor.compress((void*)uncompressed_string, strlen(uncompressed_string), compr_size);
 	
 	printf("Uncompressed: ");
-	printf("Size: %d - ", strlen(uncompressed_string));
+	printf("Size: %d - ", (uint32_t)strlen(uncompressed_string));
 	printf(uncompressed_string);
 	printf("\n\n");
 
 	printf("Compressed: ");
-	printf("Size: %d - ", compr_size);
+	printf("Size: %d - ", (uint32_t)compr_size);
 	for (size_t i = 0; i < compr_size; i++)
 	{
 		printf("%c", compressed_string[i]);
@@ -35,7 +35,7 @@ int main()
 	result = compressor.uncompress((void*)compressed_string, compr_size, result_size);
 	
 	printf("Uncompressed again: ");
-	printf("Size: %d - ", result_size);
+	printf("Size: %d - ", (uint32_t)result_size);
 	for (size_t i = 0; i < result_size; i++)
 	{
 		printf("%c", result[i]);

+ 81 - 0
engine/tests/dynamic-strings.cpp

@@ -0,0 +1,81 @@
+#include "Crown.h"
+
+using namespace crown;
+
+//-----------------------------------------------------------------------------
+void creation_test()
+{
+	DynamicString string(default_allocator(), "Creation Test");
+	Log::i("%s", string.c_str());
+
+	string = "Creation Test OK!";
+	Log::i("%s", string.c_str());
+}
+
+//-----------------------------------------------------------------------------
+void equal_test()
+{
+	DynamicString string(default_allocator(), "Equal Test");
+	Log::i("%s", string.c_str());
+
+	DynamicString string1(default_allocator(), "DynamicString assigned!");	
+
+	string = string1;
+	Log::i("%s", string.c_str());
+
+	string = "C-string assigned";
+	Log::i("%s", string.c_str());
+
+	string = 'C';
+	Log::i("%s", string.c_str());
+
+	string = "Equal Test OK!";
+	Log::i("%s", string.c_str());
+}
+
+//-----------------------------------------------------------------------------
+void plus_equal_test()
+{
+	DynamicString string(default_allocator(), "PlusEqual Test");
+	DynamicString string1(default_allocator(), " DynamicString appended!");
+
+	string += string1;
+	Log::i("%s", string.c_str());
+
+	string += " C-string appended! ";
+	Log::i("%s", string.c_str());
+
+	string += 'C';
+	Log::i("%s", string.c_str());
+
+	string = "PlusEqual Test OK!";
+	Log::i("%s", string.c_str());
+}
+
+//-----------------------------------------------------------------------------
+void starts_ends_with_test()
+{
+	TempAllocator1024 alloc;
+
+	DynamicString string(alloc, "lua/game.lua");
+
+	CE_ASSERT(string.starts_with("lua"), "FAIL");
+	CE_ASSERT(string.starts_with("lua/game.lua"), "FAIL");
+	CE_ASSERT(!string.starts_with("game"), "FAIL");
+	CE_ASSERT(!string.starts_with("lua/game.lua/foo"), "FAIL");
+
+	CE_ASSERT(string.ends_with(".lua"), "FAIL");
+	CE_ASSERT(string.ends_with("lua/game.lua"), "FAIL");
+	CE_ASSERT(!string.ends_with("foo"), "FAIL");
+	CE_ASSERT(!string.ends_with("lua/game.lua/"), "FAIL");
+}
+
+int main()
+{
+	creation_test();
+	equal_test();
+	plus_equal_test();
+	starts_ends_with_test();
+
+	return 0;
+}

+ 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;
+}

+ 2 - 2
engine/third/win32/CMakeLists.txt

@@ -14,5 +14,5 @@ if (WINDOWS)
 	install (FILES luajit/lib/luajit-5.1.dll DESTINATION bin)	
 endif (WINDOWS)
 
-install (PROGRAMS luajit/bin/luajit.exe DESTINATION tools)
-install (DIRECTORY luajit/share/luajit-2.0.1/jit DESTINATION tools)
+install (PROGRAMS luajit/bin/luajit.exe DESTINATION bin)
+install (DIRECTORY luajit/share/luajit-2.0.1/jit DESTINATION bin)

+ 2 - 2
engine/third/win64/CMakeLists.txt

@@ -14,5 +14,5 @@ if (WINDOWS)
 	install (FILES luajit/lib/luajit-5.1.dll DESTINATION bin)	
 endif (WINDOWS)
 
-install (PROGRAMS luajit/bin/luajit.exe DESTINATION tools)
-install (DIRECTORY luajit/share/luajit-2.0.1/jit DESTINATION tools)
+install (PROGRAMS luajit/bin/luajit.exe DESTINATION bin)
+install (DIRECTORY luajit/share/luajit-2.0.1/jit DESTINATION bin)

+ 3 - 3
engine/third/x86/CMakeLists.txt

@@ -11,6 +11,6 @@ cmake_minimum_required(VERSION 2.8)
 install (FILES luajit/lib/libluajit-5.1.so.2.0.2
 			   luajit/lib/libluajit-5.1.so.2 DESTINATION bin)
 
-install (PROGRAMS luajit/bin/luajit-2.0.2 DESTINATION tools)
-install (FILES luajit/bin/luajit DESTINATION tools)
-install (DIRECTORY luajit/share/luajit-2.0.2/jit DESTINATION tools)
+install (PROGRAMS luajit/bin/luajit-2.0.2 DESTINATION bin)
+install (FILES luajit/bin/luajit DESTINATION bin)
+install (DIRECTORY luajit/share/luajit-2.0.2/jit DESTINATION bin)

+ 3 - 3
engine/third/x86_64/CMakeLists.txt

@@ -11,6 +11,6 @@ cmake_minimum_required(VERSION 2.8)
 install (FILES luajit/lib/libluajit-5.1.so.2.0.1 
 			   luajit/lib/libluajit-5.1.so.2 DESTINATION bin)
 
-install (PROGRAMS luajit/bin/luajit-2.0.1 DESTINATION tools)
-install (FILES luajit/bin/luajit DESTINATION tools)
-install (DIRECTORY luajit/share/luajit-2.0.1/jit DESTINATION tools)
+install (PROGRAMS luajit/bin/luajit-2.0.1 DESTINATION bin)
+install (FILES luajit/bin/luajit DESTINATION bin)
+install (DIRECTORY luajit/share/luajit-2.0.1/jit DESTINATION bin)

+ 5 - 0
samples/01.hello-world/crown.config

@@ -0,0 +1,5 @@
+{
+	"boot" : "lua/game",
+	"window_width" : 800,
+	"window_height" : 600
+}

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików