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

Merge branch 'master' of https://github.com/taylor001/crown

Dexter89 11 лет назад
Родитель
Сommit
dce96a8d7d
100 измененных файлов с 5072 добавлено и 6037 удалено
  1. 10 10
      .gitignore
  2. 61 0
      CMakeLists.txt
  3. 1 1
      README.md
  4. 21 11
      engine/Android.mk
  5. 36 113
      engine/CMakeLists.txt
  6. 43 17
      engine/ConsoleServer.cpp
  7. 29 17
      engine/ConsoleServer.h
  8. 32 49
      engine/Device.cpp
  9. 91 66
      engine/Device.h
  10. 19 18
      engine/audio/OggDecoder.h
  11. 32 32
      engine/audio/backend/ALSoundWorld.cpp
  12. 35 35
      engine/audio/backend/SLESSoundWorld.cpp
  13. 8 3
      engine/compilers/BundleCompiler.cpp
  14. 0 211
      engine/core/Args.cpp
  15. 165 24
      engine/core/Args.h
  16. 11 11
      engine/core/Error.h
  17. 0 154
      engine/core/Log.cpp
  18. 14 53
      engine/core/Log.h
  19. 2 0
      engine/core/Macros.h
  20. 1 1
      engine/core/Profiler.h
  21. 48 30
      engine/core/containers/Blob.h
  22. 94 0
      engine/core/containers/DynamicBlob.h
  23. 24 24
      engine/core/containers/Hash.h
  24. 144 156
      engine/core/containers/IdArray.h
  25. 93 104
      engine/core/containers/IdTable.h
  26. 17 22
      engine/core/json/JSON.cpp
  27. 30 6
      engine/core/json/JSONParser.cpp
  28. 9 0
      engine/core/json/JSONParser.h
  29. 303 342
      engine/core/math/Color4.h
  30. 30 40
      engine/core/math/Frustum.h
  31. 60 8
      engine/core/math/MathTypes.h
  32. 0 650
      engine/core/math/Matrix3x3.cpp
  33. 367 103
      engine/core/math/Matrix3x3.h
  34. 0 1043
      engine/core/math/Matrix4x4.cpp
  35. 559 130
      engine/core/math/Matrix4x4.h
  36. 0 6
      engine/core/math/Plane.h
  37. 16 44
      engine/core/math/Quaternion.h
  38. 3 8
      engine/core/math/Vector2.h
  39. 3 8
      engine/core/math/Vector3.h
  40. 8 7
      engine/core/math/Vector4.h
  41. 1 1
      engine/core/mem/TempAllocator.h
  42. 5 0
      engine/core/strings/StringUtils.h
  43. 0 470
      engine/gui/Gui.cpp
  44. 0 122
      engine/gui/Gui.h
  45. 0 110
      engine/gui/GuiImage.h
  46. 0 100
      engine/gui/GuiRect.h
  47. 0 251
      engine/gui/GuiText.h
  48. 0 93
      engine/gui/GuiTriangle.h
  49. 63 0
      engine/lua/LuaColor4.cpp
  50. 11 0
      engine/lua/LuaDebugLine.cpp
  51. 45 0
      engine/lua/LuaDevice.cpp
  52. 2 2
      engine/lua/LuaEnvironment.cpp
  53. 15 206
      engine/lua/LuaGui.cpp
  54. 49 157
      engine/lua/LuaMatrix4x4.cpp
  55. 1 1
      engine/lua/LuaPhysicsWorld.cpp
  56. 11 0
      engine/lua/LuaSprite.cpp
  57. 49 18
      engine/lua/LuaStack.h
  58. 6 2
      engine/lua/LuaSystem.cpp
  59. 130 8
      engine/lua/LuaUnit.cpp
  60. 162 0
      engine/lua/LuaVector2Box.cpp
  61. 4 4
      engine/lua/LuaVector3Box.cpp
  62. 41 5
      engine/lua/LuaWorld.cpp
  63. 185 117
      engine/os/android/AndroidDevice.cpp
  64. 22 20
      engine/os/android/AndroidManifest.xml
  65. 11 11
      engine/os/android/ApkFile.cpp
  66. 18 17
      engine/os/android/ApkFile.h
  67. 2 2
      engine/os/android/ApkFilesystem.cpp
  68. 22 22
      engine/os/android/OsWindow.h
  69. 17 131
      engine/os/android/java/CrownActivity.java
  70. 105 17
      engine/os/linux/main.cpp
  71. 4 0
      engine/os/posix/Cond.h
  72. 4 0
      engine/os/posix/Mutex.h
  73. 4 0
      engine/os/posix/OsFile.cpp
  74. 2 0
      engine/os/posix/OsSocket.h
  75. 2 1
      engine/os/posix/OsThread.h
  76. 1 0
      engine/os/posix/Posix.cpp
  77. 53 18
      engine/os/win/main.cpp
  78. 16 8
      engine/physics/Actor.cpp
  79. 4 3
      engine/physics/Actor.h
  80. 72 33
      engine/physics/PhysicsWorld.cpp
  81. 22 13
      engine/physics/PhysicsWorld.h
  82. 7 7
      engine/renderers/DebugLine.cpp
  83. 2 7
      engine/renderers/DebugLine.h
  84. 376 0
      engine/renderers/Gui.cpp
  85. 77 0
      engine/renderers/Gui.h
  86. 1 1
      engine/renderers/Material.cpp
  87. 212 105
      engine/renderers/RenderWorld.cpp
  88. 51 31
      engine/renderers/RenderWorld.h
  89. 28 2
      engine/renderers/Sprite.cpp
  90. 24 14
      engine/renderers/Sprite.h
  91. 10 0
      engine/renderers/backend/ConstantBuffer.h
  92. 91 28
      engine/renderers/backend/RenderContext.h
  93. 95 40
      engine/renderers/backend/Renderer.h
  94. 13 11
      engine/renderers/backend/RendererTypes.h
  95. 322 215
      engine/renderers/backend/gl/GLRenderer.cpp
  96. 26 24
      engine/renderers/backend/gl/egl/GLContext.cpp
  97. 5 5
      engine/resource/FontResource.cpp
  98. 92 0
      engine/resource/LevelResource.cpp
  99. 59 26
      engine/resource/LevelResource.h
  100. 1 1
      engine/resource/LuaResource.cpp

+ 10 - 10
.gitignore

@@ -23,14 +23,14 @@ test-results
 *.pidb
 
 # Ignore some third party dirs
-/engine/third/ARMv7/physx/include
-/engine/third/ARMv7/physx/lib
-/engine/third/x86_64/physx/include
-/engine/third/x86_64/physx/lib
-/engine/third/win32/physx
-/engine/third/win32/zlib
-/engine/third/win32/freetype/include
-/engine/third/win32/freetype/lib
+/third/ARMv7/physx/include
+/third/ARMv7/physx/lib
+/third/x86_64/physx/include
+/third/x86_64/physx/lib
+/third/win32/physx
+/third/win32/zlib
+/third/win32/freetype/include
+/third/win32/freetype/lib
 
-/engine/third/win32/freetype-2.5.3
-/engine/third/win32/freetype-2.4.9
+/third/win32/freetype-2.5.3
+/third/win32/freetype-2.4.9

+ 61 - 0
CMakeLists.txt

@@ -68,6 +68,67 @@ endif (CROWN_BUILD MATCHES "linux-debug-32")
 set (CROWN_EXECUTABLE_NAME crown-${CROWN_BUILD})
 set (CROWN_LIBRARY_NAME crown-lib-${CROWN_BUILD})
 
+# detect architecture
+if (CROWN_ARCH MATCHES "x86")
+	set (CROWN_THIRD ${CMAKE_SOURCE_DIR}/third/x86)
+endif (CROWN_ARCH MATCHES "x86")
+
+if (CROWN_ARCH MATCHES "x86_64")
+	set (CROWN_THIRD ${CMAKE_SOURCE_DIR}/third/x86_64)
+endif (CROWN_ARCH MATCHES "x86_64")
+
+if (CROWN_ARCH MATCHES "win32")
+	set (CROWN_THIRD ${CMAKE_SOURCE_DIR}/third/win32)
+endif (CROWN_ARCH MATCHES "win32")
+
+if (CROWN_ARCH MATCHES "win64")
+	set (CROWN_THIRD ${CMAKE_SOURCE_DIR}/third/win64)
+endif (CROWN_ARCH MATCHES "win64")
+
+if (CROWN_ARCH MATCHES "ARMv7")
+	set (CROWN_THIRD ${CMAKE_SOURCE_DIR}/third/ARMv7)
+endif (CROWN_ARCH MATCHES "ARMv7")
+
+# architecture dependent includes
+set (CROWN_THIRD_INCLUDES
+	${CROWN_THIRD}/luajit/include/luajit-2.0
+	${CROWN_THIRD}/glew-1.9.0/include
+	${CROWN_THIRD}/zlib/include
+	${CROWN_THIRD}/oggvorbis/include
+	${CROWN_THIRD}/openAL/include
+	${CROWN_THIRD}/physx/include
+	${CROWN_THIRD}/physx/include/common
+	${CROWN_THIRD}/physx/include/characterkinematic
+	${CROWN_THIRD}/physx/include/cloth
+	${CROWN_THIRD}/physx/include/common
+	${CROWN_THIRD}/physx/include/cooking
+	${CROWN_THIRD}/physx/include/extensions
+	${CROWN_THIRD}/physx/include/foundation
+	${CROWN_THIRD}/physx/include/geometry
+	${CROWN_THIRD}/physx/include/particles
+	${CROWN_THIRD}/physx/include/physxprofilesdk
+	${CROWN_THIRD}/physx/include/physxvisualdebuggersdk
+	${CROWN_THIRD}/physx/include/pvd
+	${CROWN_THIRD}/physx/include/pxtask
+	${CROWN_THIRD}/physx/include/RepX
+	${CROWN_THIRD}/physx/include/RepXUpgrader
+	${CROWN_THIRD}/physx/include/vehicle
+	${CMAKE_SOURCE_DIR}/third/freetype
+	${CMAKE_SOURCE_DIR}/third/stb_image
+)
+
+# architecture dependent libraries
+set (CROWN_THIRD_LIBS
+	${CROWN_THIRD}/luajit/lib
+	${CROWN_THIRD}/glew-1.9.0/lib
+	${CROWN_THIRD}/zlib/lib
+	${CROWN_THIRD}/oggvorbis/lib
+	${CROWN_THIRD}/openAL/lib
+	${CROWN_THIRD}/physx/lib
+)
+
+add_subdirectory(${CROWN_THIRD})
+
 # always build the engine
 add_subdirectory(engine)
 

+ 1 - 1
README.md

@@ -1,4 +1,4 @@
-crown - Lightweight, cross-platform game engine that tries to Keep It Simple.
+Lightweight, cross-platform game engine that tries to Keep It Simple.
 =====
 
 ##What is it?

+ 21 - 11
engine/Android.mk

@@ -96,7 +96,7 @@ PhysX_libraries :=\
 ###############################################################################
 include $(CLEAR_VARS)
 
-LOCAL_MODULE    := crown
+LOCAL_MODULE := crown
 LOCAL_SRC_FILES :=\
 \
 	audio/backend/SLESSoundWorld.cpp\
@@ -113,8 +113,6 @@ LOCAL_SRC_FILES :=\
 	core/json/JSONParser.cpp\
 \
 	core/math/Color4.cpp\
-	core/math/Matrix3x3.cpp\
-	core/math/Matrix4x4.cpp\
 \
 	core/mem/LinearAllocator.cpp\
 	core/mem/Memory.cpp\
@@ -127,11 +125,6 @@ LOCAL_SRC_FILES :=\
 	core/settings/StringSetting.cpp\
 \
 	core/strings/Path.cpp\
-\
-	core/Args.cpp\
-	core/Log.cpp\
-\
-	gui/Gui.cpp\
 \
 	os/android/Android.cpp\
 	os/android/AndroidDevice.cpp\
@@ -155,15 +148,17 @@ LOCAL_SRC_FILES :=\
 	renderers/Mesh.cpp\
 	renderers/RenderWorld.cpp\
 	renderers/Sprite.cpp\
+	renderers/Gui.cpp\
 \
 	resource/FileBundle.cpp\
 	resource/ResourceLoader.cpp\
 	resource/ResourceManager.cpp\
 	resource/ResourceRegistry.cpp\
 \
-	lua/LuaAccelerometer.cpp\
+lua/LuaAccelerometer.cpp\
 	lua/LuaActor.cpp\
 	lua/LuaCamera.cpp\
+	lua/LuaColor4.cpp\
 	lua/LuaController.cpp\
 	lua/LuaDebugLine.cpp\
 	lua/LuaDevice.cpp\
@@ -174,6 +169,7 @@ LOCAL_SRC_FILES :=\
 	lua/LuaKeyboard.cpp\
 	lua/LuaMath.cpp\
 	lua/LuaMatrix4x4.cpp\
+	lua/LuaMatrix4x4Box.cpp\
 	lua/LuaMesh.cpp\
 	lua/LuaMouse.cpp\
 	lua/LuaPhysicsWorld.cpp\
@@ -188,11 +184,11 @@ LOCAL_SRC_FILES :=\
 	lua/LuaTouch.cpp\
 	lua/LuaUnit.cpp\
 	lua/LuaVector2.cpp\
+	lua/LuaVector2Box.cpp\
 	lua/LuaVector3.cpp\
 	lua/LuaVector3Box.cpp\
 	lua/LuaWindow.cpp\
 	lua/LuaWorld.cpp\
-	lua/LuaMatrix4x4Box.cpp\
 \
 	world/Camera.cpp\
 	world/SceneGraph.cpp\
@@ -254,7 +250,21 @@ LOCAL_C_INCLUDES	:=\
 	$(LOCAL_PATH)/third/ARMv7/physx/include/RepXUpgrader\
 	$(LOCAL_PATH)/third/ARMv7/physx/include/vehicle\
 	
-LOCAL_CPPFLAGS := -fno-rtti -fno-exceptions -std=c++03 -ansi -Wall -Wextra -Wno-long-long -Wno-variadic-macros -Wno-missing-braces -Wno-unused-parameter -Wno-unknown-pragmas -Wno-format
+LOCAL_CPPFLAGS :=\
+	-std=c++03\
+	-ansi\
+	-Wall\
+	-Wextra\
+	-Wno-long-long\
+	-Wno-variadic-macros\
+	-Wno-missing-braces\
+	-Wno-unused-parameter\
+	-Wno-unknown-pragmas\
+	-Wno-format\
+	-Wno-unused-but-set-variable\
+	-fno-rtti\
+	-fno-exceptions\
+
 LOCAL_LDLIBS := -L$(LOCAL_PATH) -Wl,--start-group $(addprefix -l, $(PhysX_libraries)) -Wl,--end-group -llog -landroid -lEGL -lGLESv2 -lz -lOpenSLES
 LOCAL_SHARED_LIBRARIES := luajit-5.1
 LOCAL_STATIC_LIBRARIES := android_native_app_glue ogg vorbis

+ 36 - 113
engine/CMakeLists.txt

@@ -1,64 +1,5 @@
 cmake_minimum_required(VERSION 2.8)
 
-# detect architecture
-if (CROWN_ARCH MATCHES "x86")
-	set (CROWN_THIRD ${CMAKE_SOURCE_DIR}/engine/third/x86)
-endif (CROWN_ARCH MATCHES "x86")
-
-if (CROWN_ARCH MATCHES "x86_64")
-	set (CROWN_THIRD ${CMAKE_SOURCE_DIR}/engine/third/x86_64)
-endif (CROWN_ARCH MATCHES "x86_64")
-
-if (CROWN_ARCH MATCHES "win32")
-	set (CROWN_THIRD ${CMAKE_SOURCE_DIR}/engine/third/win32)
-endif (CROWN_ARCH MATCHES "win32")
-
-if (CROWN_ARCH MATCHES "win64")
-	set (CROWN_THIRD ${CMAKE_SOURCE_DIR}/engine/third/win64)
-endif (CROWN_ARCH MATCHES "win64")
-
-if (CROWN_ARCH MATCHES "ARMv7")
-	set (CROWN_THIRD ${CMAKE_SOURCE_DIR}/engine/third/ARMv7)
-endif (CROWN_ARCH MATCHES "ARMv7")
-
-# architecture dependent includes
-set (CROWN_THIRD_INCLUDES
-	${CROWN_THIRD}/luajit/include/luajit-2.0
-	${CROWN_THIRD}/glew-1.9.0/include
-	${CROWN_THIRD}/zlib/include
-	${CROWN_THIRD}/oggvorbis/include
-	${CROWN_THIRD}/openAL/include
-	${CROWN_THIRD}/physx/include
-	${CROWN_THIRD}/physx/include/common
-	${CROWN_THIRD}/physx/include/characterkinematic
-	${CROWN_THIRD}/physx/include/cloth
-	${CROWN_THIRD}/physx/include/common
-	${CROWN_THIRD}/physx/include/cooking
-	${CROWN_THIRD}/physx/include/extensions
-	${CROWN_THIRD}/physx/include/foundation
-	${CROWN_THIRD}/physx/include/geometry
-	${CROWN_THIRD}/physx/include/particles
-	${CROWN_THIRD}/physx/include/physxprofilesdk
-	${CROWN_THIRD}/physx/include/physxvisualdebuggersdk
-	${CROWN_THIRD}/physx/include/pvd
-	${CROWN_THIRD}/physx/include/pxtask
-	${CROWN_THIRD}/physx/include/RepX
-	${CROWN_THIRD}/physx/include/RepXUpgrader
-	${CROWN_THIRD}/physx/include/vehicle
-)
-
-# architecture dependent libraries
-set (CROWN_THIRD_LIBS
-	${CROWN_THIRD}/luajit/lib
-	${CROWN_THIRD}/glew-1.9.0/lib
-	${CROWN_THIRD}/zlib/lib
-	${CROWN_THIRD}/oggvorbis/lib
-	${CROWN_THIRD}/openAL/lib
-	${CROWN_THIRD}/physx/lib
-)
-
-add_subdirectory(${CROWN_THIRD})
-
 # platform independent includes
 set (CROWN_INCLUDES
 	${CMAKE_SOURCE_DIR}/engine
@@ -84,7 +25,6 @@ set (CROWN_INCLUDES
 	${CMAKE_SOURCE_DIR}/engine/compilers
 	${CMAKE_SOURCE_DIR}/engine/physics
 	${CMAKE_SOURCE_DIR}/engine/world
-	${CMAKE_SOURCE_DIR}/engine/gui
 )
 
 set (SRC
@@ -100,8 +40,6 @@ set (HEADERS
 )
 
 set (CORE_SRC
-	core/Args.cpp
-	core/Log.cpp
 )
 
 set (CORE_HEADERS
@@ -131,8 +69,6 @@ set (CONTAINERS_HEADERS
 
 set (MATH_SRC
 	core/math/Color4.cpp
-	core/math/Matrix3x3.cpp
-	core/math/Matrix4x4.cpp
 )
 
 set (MATH_HEADERS
@@ -258,59 +194,63 @@ set (RENDERERS_BACKEND_HEADERS
 )
 
 set (RENDERERS_SRC
-	renderers/RenderWorld.cpp
+	renderers/DebugLine.cpp
+	renderers/Gui.cpp
+	renderers/Material.cpp
 	renderers/Mesh.cpp
+	renderers/RenderWorld.cpp
 	renderers/Sprite.cpp
-	renderers/Material.cpp
-	renderers/DebugLine.cpp
 )
 
 set (RENDERERS_HEADERS
+	renderers/DebugLine.h
+	renderers/Gui.h
+	renderers/Material.h
+	renderers/Mesh.h
 	renderers/RenderWorld.h
 	renderers/RenderWorldTypes.h
-	renderers/Mesh.h
 	renderers/Sprite.h
-	renderers/Material.h
-	renderers/DebugLine.h
 )
 
 set (RESOURCE_SRC
+	resource/FileBundle.cpp
+	resource/FontResource.cpp
+	resource/GuiResource.cpp
+	resource/LevelResource.cpp
+	resource/LuaResource.cpp
+	resource/MaterialResource.cpp
+	resource/MeshResource.cpp
+	resource/PackageResource.cpp
+	resource/PhysicsResource.cpp
 	resource/ResourceLoader.cpp
 	resource/ResourceManager.cpp
 	resource/ResourceRegistry.cpp
-	resource/UnitResource.cpp
-	resource/TextureResource.cpp
-	resource/SpriteResource.cpp
 	resource/SoundResource.cpp
-	resource/MaterialResource.cpp
-	resource/PhysicsResource.cpp
-	resource/PackageResource.cpp
-	resource/MeshResource.cpp
-	resource/LuaResource.cpp
-	resource/GuiResource.cpp
-	resource/FontResource.cpp
-	resource/FileBundle.cpp
+	resource/SpriteResource.cpp
+	resource/TextureResource.cpp
+	resource/UnitResource.cpp
 )
 
 set (RESOURCE_HEADERS
-	resource/Resource.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/FontResource.h
+	resource/GuiResource.h
+	resource/LevelResource.h
+	resource/LuaResource.h
 	resource/MaterialResource.h
+	resource/MeshResource.h
 	resource/PackageResource.h
-	resource/UnitResource.h
+	resource/PhysicsResource.h
+	resource/Resource.h
+	resource/ResourceLoader.h
+	resource/ResourceManager.h
 	resource/ResourcePackage.h
+	resource/ResourceRegistry.h
+	resource/SoundResource.h
 	resource/SpriteResource.h
-	resource/PhysicsResource.h
-	resource/GuiResource.h
-	resource/FontResource.h
+	resource/TextureResource.h
+	resource/UnitResource.h
 )
 
 set (OS_SRC
@@ -328,6 +268,7 @@ set (LUA_SRC
 	lua/LuaAccelerometer.cpp
 	lua/LuaActor.cpp
 	lua/LuaCamera.cpp
+	lua/LuaColor4.cpp
 	lua/LuaController.cpp
 	lua/LuaDebugLine.cpp
 	lua/LuaDevice.cpp
@@ -353,6 +294,7 @@ set (LUA_SRC
 	lua/LuaTouch.cpp
 	lua/LuaUnit.cpp
 	lua/LuaVector2.cpp
+	lua/LuaVector2Box.cpp
 	lua/LuaVector3.cpp
 	lua/LuaVector3Box.cpp
 	lua/LuaWindow.cpp
@@ -417,18 +359,6 @@ set (COMPILER_HEADER
 	compilers/BundleCompiler.h
 )
 
-set (GUI_SRC
-	gui/Gui.cpp
-)
-
-set (GUI_HEADERS
-	gui/Gui.h
-	gui/GuiRect.h
-	gui/GuiTriangle.h
-	gui/GuiImage.h
-	gui/GuiText.h
-)
-
 set (CROWN_LIBRARIES)
 
 # Platform specific stuff
@@ -497,6 +427,7 @@ if (LINUX)
 		-fPIC
 		#-fvisibility=hidden
 		-fno-exceptions
+		-fno-rtti
 	)
 
 	if (CROWN_DEBUG)
@@ -537,11 +468,8 @@ if (LINUX)
 		list (APPEND COMPILER_FLAGS
 			-DNDEBUG
 			-O2
-			-Wno-unused-variable
-			-Wno-unused-parameter
 			-Wno-maybe-uninitialized
 			-Wno-unused-but-set-variable
-			-Wno-unused-function
 		)
 		list (APPEND CROWN_LIBRARIES
 			LowLevel
@@ -663,11 +591,8 @@ if (WINDOWS)
 		list (APPEND COMPILER_FLAGS
 			#-DNDEBUG
 			#-O2
-			#-Wno-unused-variable
-			#-Wno-unused-parameter
 			#-Wno-maybe-uninitialized
 			#-Wno-unused-but-set-variable
-			#-Wno-unused-function
 		)
 		list (APPEND CROWN_LIBRARIES
 			#LowLevel
@@ -712,7 +637,6 @@ set (CROWN_SOURCES
 	${PHYSICS_SRC}
 	${WORLD_SRC}
 	${COMPILER_SRC}
-	${GUI_SRC}
 )
 
 set (CROWN_HEADERS
@@ -736,7 +660,6 @@ set (CROWN_HEADERS
 	${PHYSICS_HEADERS}
 	${WORLD_HEADERS}
 	${COMPILER_HEADERS}
-	${GUI_HEADERS}
 )
 
 configure_file (${CMAKE_CURRENT_SOURCE_DIR}/Config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/Config.h)

+ 43 - 17
engine/ConsoleServer.cpp

@@ -63,7 +63,7 @@ void ConsoleServer::init(uint16_t port, bool wait)
 //-----------------------------------------------------------------------------
 void ConsoleServer::shutdown()
 {
-	for (uint32_t i = 0; i < m_clients.size(); i++)
+	for (uint32_t i = 0; i < id_array::size(m_clients); i++)
 	{
 		m_clients[i].close();
 	}
@@ -72,26 +72,52 @@ void ConsoleServer::shutdown()
 }
 
 //-----------------------------------------------------------------------------
-void ConsoleServer::log_to_all(const char* message, LogSeverity::Enum severity)
+void ConsoleServer::log_to_all(LogSeverity::Enum severity, const char* message, ...)
 {
-	using namespace string_stream;
-
-	TempAllocator2048 alloc;
-	StringStream json(alloc);
+	va_list args;
+	va_start(args, message);
+	log_to_all(severity, message, args);
+	va_end(args);
+}
 
-	static const char* severity_to_text[] = { "info", "warning", "error", "debug" };
+//-----------------------------------------------------------------------------
+void ConsoleServer::log_to_all(LogSeverity::Enum severity, const char* message, ::va_list arg)
+{
+	using namespace string_stream;
+	static const char* stt[] = { "info", "warning", "error", "debug" };
 
-	json << "{\"type\":\"message\",";
-	json << "\"severity\":\"" << severity_to_text[severity] << "\",";
+	// Log to stdout
+	va_list arg_copy;
+	__va_copy(arg_copy, arg);
 
 	char buf[1024];
-	string::strncpy(buf, message, 1024);
+	int len = vsnprintf(buf, 1024 - 2, message, arg);
+	buf[len] = '\n';
+	buf[len + 1] = '\0';
+
 	for (uint32_t i = 0; i < string::strlen(message); i++)
 	{
 		if (buf[i] == '"')
 			buf[i] = '\'';
 	}
 
+	// Log on local device
+	switch (severity)
+	{
+		case LogSeverity::DEBUG: os::log_debug(message, arg_copy); break;
+		case LogSeverity::WARN: os::log_warning(message, arg_copy); break;
+		case LogSeverity::ERROR: os::log_error(message, arg_copy); break;
+		case LogSeverity::INFO: os::log_info(message, arg_copy); break;
+		default: break;
+	}
+	va_end(arg_copy);
+
+	// Build json message
+	TempAllocator2048 alloc;
+	StringStream json(alloc);
+
+	json << "{\"type\":\"message\",";
+	json << "\"severity\":\"" << stt[severity] << "\",";
 	json << "\"message\":\"" << buf << "\"}";
 
 	send_to_all(c_str(json));
@@ -108,7 +134,7 @@ void ConsoleServer::send(TCPSocket client, const char* message)
 //-----------------------------------------------------------------------------
 void ConsoleServer::send_to_all(const char* message)
 {
-	for (uint32_t i = 0; i < m_clients.size(); i++)
+	for (uint32_t i = 0; i < id_array::size(m_clients); i++)
 	{
 		send(m_clients[i].socket, message);
 	}
@@ -118,7 +144,7 @@ void ConsoleServer::send_to_all(const char* message)
 void ConsoleServer::update()
 {
 	// Check for new clients only if we have room for them
-	if (m_clients.size() < CE_MAX_CONSOLE_CLIENTS - 1)
+	if (id_array::size(m_clients) < CE_MAX_CONSOLE_CLIENTS - 1)
 	{
 		TCPSocket client;
 		AcceptResult result = m_server.accept_nonblock(client);
@@ -132,7 +158,7 @@ void ConsoleServer::update()
 	Array<Id> to_remove(alloc);
 
 	// Update all clients
-	for (uint32_t i = 0; i < m_clients.size(); i++)
+	for (uint32_t i = 0; i < id_array::size(m_clients); i++)
 	{
 		ReadResult rr = update_client(m_clients[i].socket);
 		if (rr.error != ReadResult::NO_ERROR) array::push_back(to_remove, m_clients[i].id);
@@ -141,8 +167,8 @@ void ConsoleServer::update()
 	// Remove clients
 	for (uint32_t i = 0; i < array::size(to_remove); i++)
 	{
-		m_clients.lookup(to_remove[i]).socket.close();
-		m_clients.destroy(to_remove[i]);
+		id_array::get(m_clients, to_remove[i]).socket.close();
+		id_array::destroy(m_clients, to_remove[i]);
 	}
 }
 
@@ -151,8 +177,8 @@ void ConsoleServer::add_client(TCPSocket socket)
 {
 	Client client;
 	client.socket = socket;
-	Id id = m_clients.create(client);
-	m_clients.lookup(id).id = id;
+	Id id = id_array::create(m_clients, client);
+	id_array::get(m_clients, id).id = id;
 }
 
 //-----------------------------------------------------------------------------

+ 29 - 17
engine/ConsoleServer.h

@@ -30,12 +30,23 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "ContainerTypes.h"
 #include "Queue.h"
 #include "IdArray.h"
-#include "Log.h"
 #include "Config.h"
 
 namespace crown
 {
 
+/// Enumerates log levels.
+struct LogSeverity
+{
+	enum Enum
+	{
+		INFO	= 0,
+		WARN	= 1,
+		ERROR	= 2,
+		DEBUG	= 3
+	};	
+};
+
 struct Client
 {
 	Id id;
@@ -55,33 +66,34 @@ public:
 
 	/// Listens on the given @a port. If @a wait is true, this function
 	/// blocks until a client is connected.
-	void						init(uint16_t port, bool wait);
-	void						shutdown();
+	void init(uint16_t port, bool wait);
+	void shutdown();
 
-	void						log_to_all(const char* message, LogSeverity::Enum severity);
+	void log_to_all(LogSeverity::Enum severity, const char* message, ...);
+	void log_to_all(LogSeverity::Enum severity, const char* message, ::va_list arg);
 
 	/// Collects requests from clients and processes them all.
-	void						update();
+	void update();
 
 private:
 
-	void						send(TCPSocket client, const char* message);
-	void						send_to_all(const char* message);
+	void send(TCPSocket client, const char* message);
+	void send_to_all(const char* message);
 
-	void						add_client(TCPSocket socket);
-	ReadResult					update_client(TCPSocket client);
-	void						process(TCPSocket client, const char* request);
+	void add_client(TCPSocket socket);
+	ReadResult update_client(TCPSocket client);
+	void process(TCPSocket client, const char* request);
 
-	void						process_ping(TCPSocket client, const char* msg);
-	void						process_script(TCPSocket client, const char* msg);
-	void						process_stats(TCPSocket client, const char* msg);
-	void						process_command(TCPSocket client, const char* msg);
-	void						processs_filesystem(TCPSocket client, const char* msg);
+	void process_ping(TCPSocket client, const char* msg);
+	void process_script(TCPSocket client, const char* msg);
+	void process_stats(TCPSocket client, const char* msg);
+	void process_command(TCPSocket client, const char* msg);
+	void processs_filesystem(TCPSocket client, const char* msg);
 
 private:
 
-	TCPServer					m_server;
-	ClientArray					m_clients;
+	TCPServer m_server;
+	ClientArray m_clients;
 };
 
 } // namespace crown

+ 32 - 49
engine/Device.cpp

@@ -117,15 +117,9 @@ Device::~Device()
 void Device::init()
 {
 	// Initialize
-	Log::i("Initializing Crown Engine %d.%d.%d...", CROWN_VERSION_MAJOR, CROWN_VERSION_MINOR, CROWN_VERSION_MICRO);
+	CE_LOGI("Initializing Crown Engine %d.%d.%d...", CROWN_VERSION_MAJOR, CROWN_VERSION_MINOR, CROWN_VERSION_MICRO);
 
-	// RPC only in debug or development builds
-	#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
-		m_console = CE_NEW(m_allocator, ConsoleServer)();
-		m_console->init(m_console_port, false);
-	#endif
-
-	Log::d("Creating filesystem...");
+	CE_LOGD("Creating filesystem...");
 	// Default bundle filesystem
 	#if defined (LINUX) || defined(WINDOWS)
 		if (m_fileserver == 1)
@@ -150,16 +144,15 @@ void Device::init()
 	m_resource_bundle = Bundle::create(m_allocator, *m_filesystem);
 
 	// Create resource manager
-	Log::d("Creating resource manager...");
-	m_resource_manager = CE_NEW(m_allocator, ResourceManager)(*m_resource_bundle, 0);
-	Log::d("Resource seed: %d", m_resource_manager->seed());
+	CE_LOGD("Creating resource manager...");
+	m_resource_manager = CE_NEW(m_allocator, ResourceManager)(*m_resource_bundle);
 
 	// Create world manager
-	Log::d("Creating world manager...");
+	CE_LOGD("Creating world manager...");
 	m_world_manager = CE_NEW(m_allocator, WorldManager)();
 
 	// Create window
-	Log::d("Creating main window...");
+	CE_LOGD("Creating main window...");
 	m_window = CE_NEW(m_allocator, OsWindow);
 
 	// Create input devices
@@ -168,22 +161,22 @@ void Device::init()
 	m_touch = CE_NEW(m_allocator, Touch);
 
 	// Create renderer
-	Log::d("Creating renderer...");
+	CE_LOGD("Creating renderer...");
 	m_renderer = CE_NEW(m_allocator, Renderer)(m_allocator);
 	m_renderer->init();
 
-	Log::d("Creating lua system...");
+	CE_LOGD("Creating lua system...");
 	lua_system::init();
 	m_lua_environment = CE_NEW(m_allocator, LuaEnvironment)(lua_system::state());
 
-	Log::d("Creating physics...");
+	CE_LOGD("Creating physics...");
 	physics_system::init();
 
-	Log::d("Creating audio...");
+	CE_LOGD("Creating audio...");
 	audio_system::init();
 
-	Log::d("Crown Engine initialized.");
-	Log::d("Initializing Game...");
+	CE_LOGD("Crown Engine initialized.");
+	CE_LOGD("Initializing Game...");
 
 	m_physics_config = m_resource_manager->load(PHYSICS_CONFIG_EXTENSION, "global");
 	m_resource_manager->flush();
@@ -195,7 +188,7 @@ void Device::init()
 	m_lua_environment->load_and_execute(m_boot_file);
 	m_lua_environment->call_global("init", 0);
 
-	Log::d("Total allocated size: %ld", m_allocator.allocated_size());
+	CE_LOGD("Total allocated size: %ld", m_allocator.allocated_size());
 }
 
 //-----------------------------------------------------------------------------
@@ -208,35 +201,35 @@ void Device::shutdown()
 
 	m_resource_manager->unload(m_physics_config);
 
-	Log::d("Releasing audio...");
+	CE_LOGD("Releasing audio...");
 	audio_system::shutdown();
 
-	Log::d("Releasing physics...");
+	CE_LOGD("Releasing physics...");
 	physics_system::shutdown();
 
-	Log::d("Releasing lua system...");
+	CE_LOGD("Releasing lua system...");
 	lua_system::shutdown();
 	if (m_lua_environment)
 	{
 		CE_DELETE(m_allocator, m_lua_environment);
 	}
 
-	Log::d("Releasing input devices...");
+	CE_LOGD("Releasing input devices...");
 	CE_DELETE(m_allocator, m_touch);
 	CE_DELETE(m_allocator, m_mouse);
 	CE_DELETE(m_allocator, m_keyboard);
 
-	Log::d("Releasing renderer...");
+	CE_LOGD("Releasing renderer...");
 	if (m_renderer)
 	{
 		m_renderer->shutdown();
 		CE_DELETE(m_allocator, m_renderer);
 	}
 
-	Log::d("Releasing world manager...");
+	CE_LOGD("Releasing world manager...");
 	CE_DELETE(m_allocator, m_world_manager);
 
-	Log::d("Releasing resource manager...");
+	CE_LOGD("Releasing resource manager...");
 	if (m_resource_manager)
 	{
 		CE_DELETE(m_allocator, m_resource_manager);
@@ -247,18 +240,12 @@ void Device::shutdown()
 		Bundle::destroy(m_allocator, m_resource_bundle);
 	}
 
-	Log::d("Releasing filesystem...");
+	CE_LOGD("Releasing filesystem...");
 	if (m_filesystem)
 	{
 		CE_DELETE(m_allocator, m_filesystem);
 	}
 
-	#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
-		m_console->shutdown();
-		CE_DELETE(m_allocator, m_console);
-		m_console = NULL;
-	#endif
-
 	m_allocator.clear();
 	m_is_init = false;
 }
@@ -350,14 +337,14 @@ void Device::stop()
 void Device::pause()
 {
 	m_is_paused = true;
-	Log::i("Engine paused.");
+	CE_LOGI("Engine paused.");
 }
 
 //-----------------------------------------------------------------------------
 void Device::unpause()
 {
 	m_is_paused = false;
-	Log::i("Engine unpaused.");
+	CE_LOGI("Engine unpaused.");
 }
 
 //-----------------------------------------------------------------------------
@@ -392,10 +379,6 @@ void Device::frame()
 	m_last_time = m_current_time;
 	m_time_since_start += m_last_delta_time;
 
-	#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
-	m_console->update();
-	#endif
-
 	if (!m_is_paused)
 	{
 		m_resource_manager->poll_resource_loader();
@@ -442,7 +425,7 @@ ResourcePackage* Device::create_resource_package(const char* name)
 	ResourceId package_id = m_resource_manager->load("package", name);
 	m_resource_manager->flush();
 
-	PackageResource* package_res = (PackageResource*) m_resource_manager->data(package_id);
+	PackageResource* package_res = (PackageResource*) m_resource_manager->get(package_id);
 	ResourcePackage* package = CE_NEW(default_allocator(), ResourcePackage)(*m_resource_manager, package_id, package_res);
 
 	return package;
@@ -475,17 +458,17 @@ void Device::reload(const char* type, const char* name)
 
 		if (!m_bundle_compiler->compile(m_bundle_dir, m_source_dir, filename.c_str()))
 		{
-			Log::d("Compilation failed.");
+			CE_LOGD("Compilation failed.");
 			return;
 		}
 
-		ResourceId old_res_id = m_resource_manager->resource_id(type, name);
-		const void* old_res = m_resource_manager->data(old_res_id);
+		ResourceId old_res_id(type, name);
+		const void* old_res = m_resource_manager->get(old_res_id);
 		m_resource_manager->unload(old_res_id, true);
 
 		ResourceId res_id = m_resource_manager->load(type, name);
 		m_resource_manager->flush();
-		const void* new_res = m_resource_manager->data(res_id);
+		const void* new_res = m_resource_manager->get(res_id);
 
 		uint32_t type_hash = string::murmur2_32(type, string::strlen(type), 0);
 
@@ -493,9 +476,9 @@ void Device::reload(const char* type, const char* name)
 		{
 			case UNIT_TYPE:
 			{
-				Log::d("Reloading unit: %s", name);
+				CE_LOGD("Reloading unit: %s", name);
 				/// Reload unit in all worlds
-				for (uint32_t i = 0; i < m_world_manager->worlds().size(); i++)
+				for (uint32_t i = 0; i < id_array::size(m_world_manager->worlds()); i++)
 				{
 					m_world_manager->worlds()[i]->reload_units((UnitResource*) old_res, (UnitResource*) new_res);
 				}
@@ -503,8 +486,8 @@ void Device::reload(const char* type, const char* name)
 			}
 			case SOUND_TYPE:
 			{
-				Log::d("Reloading sound: %s", name);
-				for (uint32_t i = 0; i < m_world_manager->worlds().size(); i++)
+				CE_LOGD("Reloading sound: %s", name);
+				for (uint32_t i = 0; i < id_array::size(m_world_manager->worlds()); i++)
 				{
 					m_world_manager->worlds()[i]->sound_world()->reload_sounds((SoundResource*) old_res, (SoundResource*) new_res);
 				}

+ 91 - 66
engine/Device.h

@@ -53,150 +53,175 @@ class World;
 class WorldManager;
 struct Camera;
 
+/// @defgroup Device Device
+
+/// Holds data for a display mode.
+///
+/// @ingroup Device
+struct DisplayMode
+{
+	uint32_t id;
+	uint16_t width;
+	uint16_t height;
+};
+
 /// This is the place where to look for accessing all of
 /// the engine subsystems and related stuff.
+///
+/// @ingroup Device
 class CE_EXPORT Device
 {
 public:
 
-							Device();
-							~Device();
+	Device();
+	~Device();
 
-	void					init();
+	void init();
 
 	/// Shutdowns the engine freeing all the allocated resources
-	void					shutdown();
+	void shutdown();
 
 	/// Returns the number of command line arguments passed to
 	/// the engine executable.
-	int32_t					argc() const { return m_argc; }
+	int32_t argc() const { return m_argc; }
 
 	/// Returns the string value of the command line arguments passed
 	/// to the engine executable.
 	/// The size of the returned array is given by Device::argc().
-	const char**			argv() const { return (const char**) m_argv; }
+	const char** argv() const { return (const char**) m_argv; }
 
 	/// Returns wheter the engine is running (i.e. it is actually
 	/// doing work).
-	bool					is_running() const;
+	bool is_running() const;
 
 	/// Returns whether the engine is correctly initialized
-	bool					is_init() const;
+	bool is_init() const;
 
 	/// Returns wheter the engine is paused
-	bool 					is_paused() const;
+	bool is_paused() const;
 
 	/// Return the number of frames rendered from the first
 	/// call to Device::start()
-	uint64_t				frame_count() const;
+	uint64_t frame_count() const;
 
 	/// Returns the time in seconds needed to render the last frame
-	float					last_delta_time() const;
+	float last_delta_time() const;
 
 	/// Returns the time in seconds since the first call to start().
-	double					time_since_start() const;
+	double time_since_start() const;
 
 	/// Forces the engine to actually start doing work.
-	void					start();
+	void start();
 
 	/// Forces the engine to stop all the work it is doing
 	/// and normally terminates the program.
-	void					stop();
+	void stop();
 
 	/// Pauses the engine
-	void					pause();
+	void pause();
 
 	/// Unpauses the engine
-	void					unpause();
+	void unpause();
+
+	virtual int32_t run(int argc, char** argv) = 0;
+
+	/// Returns an array of video @a modes.
+	/// Each DisplayMode has an id that can be passed to set_video_mode().
+	virtual void display_modes(Array<DisplayMode>& modes) = 0;
+
+	/// Sets the video mode @a id.
+	/// @note See video_modes().
+	virtual void set_display_mode(uint32_t id) = 0;
 
-	virtual int32_t			run(int argc, char** argv) = 0;
+	/// Sets whether in fullscreen or not.
+	virtual void set_fullscreen(bool full) = 0;
 
 	/// Updates all the subsystems
-	void					frame();
+	void frame();
 
 	/// Updates the given @a world and renders it from the given @a camera.
-	void					update_world(World* world, float dt);
+	void update_world(World* world, float dt);
 
 	/// Renders the given @a world from the point of view of the given @æ camera.
-	void					render_world(World* world, Camera* camera);
+	void render_world(World* world, Camera* camera);
 
-	WorldId					create_world();
-	void					destroy_world(WorldId world);
+	WorldId create_world();
+	void destroy_world(WorldId world);
 
 	/// Returns the resource package with the given @a package_name name.
-	ResourcePackage*		create_resource_package(const char* 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 destroy_resource_package(ResourcePackage* package);
 
-	void					compile(const char* bundle_dir, const char* source_dir, const char* resource);
+	void compile(const char* bundle_dir, const char* source_dir, const char* resource);
 
-	void					reload(const char* type, const char* name);
+	void reload(const char* type, const char* name);
 
-	Filesystem*				filesystem();
-	ResourceManager*		resource_manager();
-	LuaEnvironment*			lua_environment();
+	Filesystem* filesystem();
+	ResourceManager* resource_manager();
+	LuaEnvironment* lua_environment();
 
-	OsWindow*				window();
-	Renderer*				renderer();
+	OsWindow* window();
+	Renderer* renderer();
 
-	Keyboard*				keyboard();
-	Mouse*					mouse();
-	Touch*					touch();
-	Accelerometer*			accelerometer();
-	ConsoleServer*			console() { return m_console; }
-	WorldManager*			world_manager() { return m_world_manager; }
+	Keyboard* keyboard();
+	Mouse* mouse();
+	Touch* touch();
+	Accelerometer* accelerometer();
+	ConsoleServer* console() { return m_console; }
+	WorldManager* world_manager() { return m_world_manager; }
 
 protected:
 
 	// Used to allocate all subsystems
-	LinearAllocator			m_allocator;
+	LinearAllocator m_allocator;
 
-	int32_t					m_argc;
-	char**					m_argv;
+	int32_t m_argc;
+	char** m_argv;
 
 	// Preferred settings
-	char					m_source_dir[MAX_PATH_LENGTH];
-	char 					m_bundle_dir[MAX_PATH_LENGTH];
-	char 					m_boot_file[MAX_PATH_LENGTH];
-	int32_t					m_fileserver;
-	uint16_t				m_console_port;
+	char m_source_dir[MAX_PATH_LENGTH];
+	char m_bundle_dir[MAX_PATH_LENGTH];
+	char m_boot_file[MAX_PATH_LENGTH];
+	int32_t m_fileserver;
+	uint16_t m_console_port;
 
-	bool					m_is_init		: 1;
-	bool					m_is_running	: 1;
-	bool					m_is_paused		: 1;
+	bool m_is_init		: 1;
+	bool m_is_running	: 1;
+	bool m_is_paused	: 1;
 
-	uint64_t				m_frame_count;
+	uint64_t m_frame_count;
 
-	uint64_t				m_last_time;
-	uint64_t				m_current_time;
-	float					m_last_delta_time;
-	double					m_time_since_start;
+	uint64_t m_last_time;
+	uint64_t m_current_time;
+	float m_last_delta_time;
+	double m_time_since_start;
 
 	// Public subsystems
-	Filesystem*				m_filesystem;
+	Filesystem* m_filesystem;
 
-	OsWindow*				m_window;
+	OsWindow* m_window;
 
-	Keyboard*				m_keyboard;
-	Mouse*					m_mouse;
-	Touch*					m_touch;
+	Keyboard* m_keyboard;
+	Mouse* m_mouse;
+	Touch* m_touch;
 
-	LuaEnvironment*			m_lua_environment;
-	Renderer*				m_renderer;
+	LuaEnvironment* m_lua_environment;
+	Renderer* m_renderer;
 
 	// Private subsystems
-	BundleCompiler*			m_bundle_compiler;
-	ConsoleServer*			m_console;
-	ResourceManager*		m_resource_manager;
-	Bundle*					m_resource_bundle;
-	WorldManager*			m_world_manager;
+	BundleCompiler* m_bundle_compiler;
+	ConsoleServer* m_console;
+	ResourceManager* m_resource_manager;
+	Bundle* m_resource_bundle;
+	WorldManager* m_world_manager;
 
 	// Configuration resources
-	ResourceId				m_physics_config;
+	ResourceId m_physics_config;
 
 private:
 

+ 19 - 18
engine/audio/OggDecoder.h

@@ -133,26 +133,27 @@ long int ogg_buffer_tell(void* src)
     return ob->cur_ptr - ob->buffer_ptr;
 }
 
-//-----------------------------------------------------------------------------
-static const char* ov_error_to_string(int32_t error)
-{
-	Log::i("error: %d", error);
-	switch (error)
+#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
+	static const char* ov_error_to_string(int32_t error)
 	{
-	case OV_FALSE: return "OV_FALSE";
-	case OV_HOLE: return "OV_HOLE";
-	case OV_EREAD: return "OV_EREAD";
-	case OV_EFAULT: return "OV_EFAULT";
-	case OV_EIMPL: return "OV_EIMPL";
-	case OV_EINVAL: return "OV_EINVAL";
-	case OV_ENOTVORBIS: return "OV_ENOTVORBIS";
-	case OV_EBADHEADER: return "OV_EBADHEADER";
-	case OV_EVERSION: return "OV_EVERSION";
-	case OV_EBADLINK: return "OV_EBADLINK";
-	case OV_ENOSEEK: return "OV_ENOSEEK";
-	default: return "OV_UNKNOWN"; // this case is never reached
+		CE_LOGI("error: %d", error);
+		switch (error)
+		{
+		case OV_FALSE: return "OV_FALSE";
+		case OV_HOLE: return "OV_HOLE";
+		case OV_EREAD: return "OV_EREAD";
+		case OV_EFAULT: return "OV_EFAULT";
+		case OV_EIMPL: return "OV_EIMPL";
+		case OV_EINVAL: return "OV_EINVAL";
+		case OV_ENOTVORBIS: return "OV_ENOTVORBIS";
+		case OV_EBADHEADER: return "OV_EBADHEADER";
+		case OV_EVERSION: return "OV_EVERSION";
+		case OV_EBADLINK: return "OV_EBADLINK";
+		case OV_ENOSEEK: return "OV_ENOSEEK";
+		default: return "OV_UNKNOWN"; // this case is never reached
+		}
 	}
-}
+#endif
 
 //-----------------------------------------------------------------------------
 void check_ov_error(int32_t result)

+ 32 - 32
engine/audio/backend/ALSoundWorld.cpp

@@ -43,20 +43,20 @@ namespace crown
 {
 
 //-----------------------------------------------------------------------------
-static const char* al_error_to_string(ALenum error)
-{
-	switch (error)
+#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
+
+	static const char* al_error_to_string(ALenum error)
 	{
-		case AL_INVALID_ENUM: return "AL_INVALID_ENUM";
-		case AL_INVALID_VALUE: return "AL_INVALID_VALUE";
-		case AL_INVALID_OPERATION: return "AL_INVALID_OPERATION";
-		case AL_OUT_OF_MEMORY: return "AL_OUT_OF_MEMORY";
-		default: return "UNKNOWN_AL_ERROR";
+		switch (error)
+		{
+			case AL_INVALID_ENUM: return "AL_INVALID_ENUM";
+			case AL_INVALID_VALUE: return "AL_INVALID_VALUE";
+			case AL_INVALID_OPERATION: return "AL_INVALID_OPERATION";
+			case AL_OUT_OF_MEMORY: return "AL_OUT_OF_MEMORY";
+			default: return "UNKNOWN_AL_ERROR";
+		}
 	}
-}
 
-//-----------------------------------------------------------------------------
-#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
 	#define AL_CHECK(function)\
 		function;\
 		do { ALenum error; CE_ASSERT((error = alGetError()) == AL_NO_ERROR,\
@@ -81,9 +81,9 @@ namespace audio_system
 
 		AL_CHECK(alcMakeContextCurrent(s_al_context));
 
-		Log::d("OpenAL Vendor   : %s", alGetString(AL_VENDOR));
-		Log::d("OpenAL Version  : %s", alGetString(AL_VERSION));
-		Log::d("OpenAL Renderer : %s", alGetString(AL_RENDERER));
+		CE_LOGD("OpenAL Vendor   : %s", alGetString(AL_VENDOR));
+		CE_LOGD("OpenAL Version  : %s", alGetString(AL_VERSION));
+		CE_LOGD("OpenAL Renderer : %s", alGetString(AL_RENDERER));
 
 		AL_CHECK(alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED));
 		AL_CHECK(alDopplerFactor(1.0f));
@@ -227,7 +227,7 @@ public:
 
 	ALSoundWorld()
 	{
-		set_listener_pose(Matrix4x4::IDENTITY);
+		set_listener_pose(matrix4x4::IDENTITY);
 	}
 
 	virtual ~ALSoundWorld()
@@ -236,34 +236,34 @@ public:
 
 	virtual SoundInstanceId play(const char* name, bool loop, float volume, const Vector3& pos)
 	{
-		return play((SoundResource*) device()->resource_manager()->lookup(SOUND_EXTENSION, name), loop, volume, pos);
+		return play((SoundResource*) device()->resource_manager()->get(SOUND_EXTENSION, name), loop, volume, pos);
 	}
 
 	SoundInstanceId play(SoundResource* sr, bool loop, float volume, const Vector3& pos)
 	{
 		SoundInstance instance;
 		instance.create(sr, pos);
-		SoundInstanceId id = m_playing_sounds.create(instance);
-		m_playing_sounds.lookup(id).m_id = id;
+		SoundInstanceId id = id_array::create(m_playing_sounds, instance);
+		id_array::get(m_playing_sounds, id).m_id = id;
 		instance.play(loop, volume);
 		return id;
 	}
 
 	virtual void stop(SoundInstanceId id)
 	{
-		SoundInstance& instance = m_playing_sounds.lookup(id);
+		SoundInstance& instance = id_array::get(m_playing_sounds, id);
 		instance.destroy();
-		m_playing_sounds.destroy(id);
+		id_array::destroy(m_playing_sounds, id);
 	}
 
 	virtual bool is_playing(SoundInstanceId id)
 	{
-		return m_playing_sounds.has(id) && m_playing_sounds.lookup(id).is_playing();
+		return id_array::has(m_playing_sounds, id) && id_array::get(m_playing_sounds, id).is_playing();
 	}
 
 	virtual void stop_all()
 	{
-		for (uint32_t i = 0; i < m_playing_sounds.size(); i++)
+		for (uint32_t i = 0; i < id_array::size(m_playing_sounds); i++)
 		{
 			m_playing_sounds[i].stop();
 		}
@@ -271,7 +271,7 @@ public:
 
 	virtual void pause_all()
 	{
-		for (uint32_t i = 0; i < m_playing_sounds.size(); i++)
+		for (uint32_t i = 0; i < id_array::size(m_playing_sounds); i++)
 		{
 			m_playing_sounds[i].pause();
 		}
@@ -279,7 +279,7 @@ public:
 
 	virtual void resume_all()
 	{
-		for (uint32_t i = 0; i < m_playing_sounds.size(); i++)
+		for (uint32_t i = 0; i < id_array::size(m_playing_sounds); i++)
 		{
 			m_playing_sounds[i].resume();
 		}
@@ -287,7 +287,7 @@ public:
 
 	virtual void set_sound_positions(uint32_t count, const SoundInstanceId* ids, const Vector3* positions)
 	{
-		for (uint32_t i = 0; i < m_playing_sounds.size(); i++)
+		for (uint32_t i = 0; i < id_array::size(m_playing_sounds); i++)
 		{
 			m_playing_sounds[i].set_position(positions[i]);
 		}
@@ -295,7 +295,7 @@ public:
 
 	virtual void set_sound_ranges(uint32_t count, const SoundInstanceId* ids, const float* ranges)
 	{
-		for (uint32_t i = 0; i < m_playing_sounds.size(); i++)
+		for (uint32_t i = 0; i < id_array::size(m_playing_sounds); i++)
 		{
 			m_playing_sounds[i].set_range(ranges[i]);
 		}
@@ -303,7 +303,7 @@ public:
 
 	virtual void set_sound_volumes(uint32_t count, const SoundInstanceId* ids, const float* volumes)
 	{
-		for (uint32_t i = 0; i < m_playing_sounds.size(); i++)
+		for (uint32_t i = 0; i < id_array::size(m_playing_sounds); i++)
 		{
 			m_playing_sounds[i].set_volume(volumes[i]);
 		}		
@@ -311,7 +311,7 @@ public:
 
 	virtual void reload_sounds(SoundResource* old_sr, SoundResource* new_sr)
 	{
-		for (uint32_t i = 0; i < m_playing_sounds.size(); i++)
+		for (uint32_t i = 0; i < id_array::size(m_playing_sounds); i++)
 		{
 			if (m_playing_sounds[i].resource() == old_sr)
 			{
@@ -322,9 +322,9 @@ public:
 
 	virtual void set_listener_pose(const Matrix4x4& pose)
 	{
-		const Vector3 pos = pose.translation();
-		const Vector3 up = pose.y();
-		const Vector3 at = pose.z();
+		const Vector3 pos = matrix4x4::translation(pose);
+		const Vector3 up = matrix4x4::y(pose);
+		const Vector3 at = matrix4x4::z(pose);
 
 		AL_CHECK(alListener3f(AL_POSITION, pos.x, pos.y, pos.z));
 		//AL_CHECK(alListener3f(AL_VELOCITY, vel.x, vel.y, vel.z));
@@ -340,7 +340,7 @@ public:
 		Array<SoundInstanceId> to_delete(alloc);
 
 		// Check what sounds finished playing
-		for (uint32_t i = 0; i < m_playing_sounds.size(); i++)
+		for (uint32_t i = 0; i < id_array::size(m_playing_sounds); i++)
 		{
 			SoundInstance& instance = m_playing_sounds[i];
 			if (instance.finished())

+ 35 - 35
engine/audio/backend/SLESSoundWorld.cpp

@@ -44,28 +44,27 @@ namespace crown
 {
 
 //-----------------------------------------------------------------------------
-static const char* sles_error_to_string(SLresult result)
-{
-	switch (result)
-	{
-		case SL_RESULT_SUCCESS: return "SL_RESULT_SUCCESS";
-		case SL_RESULT_PARAMETER_INVALID: return "SL_RESULT_PARAMETER_INVALID";
-		case SL_RESULT_MEMORY_FAILURE: return "SL_RESULT_MEMORY_FAILURE";
-		case SL_RESULT_FEATURE_UNSUPPORTED: return "SL_RESULT_FEATURE_UNSUPPORTED";
-		case SL_RESULT_RESOURCE_ERROR: return "SL_RESULT_RESOURCE_ERROR";
-		case SL_RESULT_IO_ERROR: return "SL_RESULT_IO_ERROR";
-		case SL_RESULT_PRECONDITIONS_VIOLATED: return "SL_RESULT_PRECONDITIONS_VIOLATED";
-		case SL_RESULT_CONTENT_CORRUPTED: return "SL_RESULT_CONTENT_CORRUPTED";
-		case SL_RESULT_CONTENT_UNSUPPORTED: return "SL_RESULT_CONTENT_UNSUPPORTED";
-		case SL_RESULT_CONTENT_NOT_FOUND: return "SL_RESULT_CONTENT_NOT_FOUND";
-		case SL_RESULT_PERMISSION_DENIED: return "SL_RESULT_PERMISSION_DENIED";
-		case SL_RESULT_BUFFER_INSUFFICIENT: return "SL_RESULT_BUFFER_INSUFFICIENT";
-		default: return "UNKNOWN_SL_ERROR";
+#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
+	static const char* sles_error_to_string(SLresult result)
+	{
+		switch (result)
+		{
+			case SL_RESULT_SUCCESS: return "SL_RESULT_SUCCESS";
+			case SL_RESULT_PARAMETER_INVALID: return "SL_RESULT_PARAMETER_INVALID";
+			case SL_RESULT_MEMORY_FAILURE: return "SL_RESULT_MEMORY_FAILURE";
+			case SL_RESULT_FEATURE_UNSUPPORTED: return "SL_RESULT_FEATURE_UNSUPPORTED";
+			case SL_RESULT_RESOURCE_ERROR: return "SL_RESULT_RESOURCE_ERROR";
+			case SL_RESULT_IO_ERROR: return "SL_RESULT_IO_ERROR";
+			case SL_RESULT_PRECONDITIONS_VIOLATED: return "SL_RESULT_PRECONDITIONS_VIOLATED";
+			case SL_RESULT_CONTENT_CORRUPTED: return "SL_RESULT_CONTENT_CORRUPTED";
+			case SL_RESULT_CONTENT_UNSUPPORTED: return "SL_RESULT_CONTENT_UNSUPPORTED";
+			case SL_RESULT_CONTENT_NOT_FOUND: return "SL_RESULT_CONTENT_NOT_FOUND";
+			case SL_RESULT_PERMISSION_DENIED: return "SL_RESULT_PERMISSION_DENIED";
+			case SL_RESULT_BUFFER_INSUFFICIENT: return "SL_RESULT_BUFFER_INSUFFICIENT";
+			default: return "UNKNOWN_SL_ERROR";
+		}
 	}
-}
 
-//-----------------------------------------------------------------------------
-#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
 	#define SL_CHECK(function)\
 		do { SLresult result = function;\
 				CE_ASSERT(result == SL_RESULT_SUCCESS, "OpenSL|ES error: %s", sles_error_to_string(result)); } while (0)
@@ -379,34 +378,35 @@ public:
 
 	virtual SoundInstanceId play(const char* name, bool loop, float volume, const Vector3& /*pos*/)
 	{
-		return play((SoundResource*) device()->resource_manager()->lookup(SOUND_EXTENSION, name), loop, volume);
+		return play((SoundResource*) device()->resource_manager()->get(SOUND_EXTENSION, name), loop, volume);
 	}
 
 	SoundInstanceId play(SoundResource* sr, bool loop, float volume)
 	{
 		SoundInstance dummy;
-		SoundInstanceId id = m_playing_sounds.create(dummy);
+		SoundInstanceId id = id_array::create(m_playing_sounds, dummy);
 
-		SoundInstance& instance = m_playing_sounds.lookup(id);
+		SoundInstance& instance = id_array::get(m_playing_sounds, id);
 		instance.create(audio_system::s_sl_engine_itf, audio_system::s_sl_output_mix, id, sr);
 		instance.play(loop, volume);
+
+		return id;
 	}
 
 	virtual void stop(SoundInstanceId id)
 	{
-		SoundInstance& instance = m_playing_sounds.lookup(id);
-		instance.destroy();
-		m_playing_sounds.destroy(id);
+		id_array::get(m_playing_sounds, id).destroy();
+		id_array::destroy(m_playing_sounds, id);
 	}
 
 	virtual bool is_playing(SoundInstanceId id)
 	{
-		return m_playing_sounds.has(id) && m_playing_sounds.lookup(id).is_playing();
+		return id_array::has(m_playing_sounds, id) && id_array::get(m_playing_sounds, id).is_playing();
 	}
 
 	virtual void stop_all()
 	{
-		for (uint32_t i = 0; i < m_playing_sounds.size(); i++)
+		for (uint32_t i = 0; i < id_array::size(m_playing_sounds); i++)
 		{
 			m_playing_sounds[i].stop();
 		}
@@ -414,7 +414,7 @@ public:
 
 	virtual void pause_all()
 	{
-		for (uint32_t i = 0; i < m_playing_sounds.size(); i++)
+		for (uint32_t i = 0; i < id_array::size(m_playing_sounds); i++)
 		{
 			m_playing_sounds[i].pause();
 		}
@@ -422,7 +422,7 @@ public:
 
 	virtual void resume_all()
 	{
-		for (uint32_t i = 0; i < m_playing_sounds.size(); i++)
+		for (uint32_t i = 0; i < id_array::size(m_playing_sounds); i++)
 		{
 			m_playing_sounds[i].resume();
 		}
@@ -430,7 +430,7 @@ public:
 
 	virtual void set_sound_positions(uint32_t count, const SoundInstanceId* ids, const Vector3* positions)
 	{
-		for (uint32_t i = 0; i < m_playing_sounds.size(); i++)
+		for (uint32_t i = 0; i < id_array::size(m_playing_sounds); i++)
 		{
 			m_playing_sounds[i].set_position(positions[i]);
 		}
@@ -438,7 +438,7 @@ public:
 
 	virtual void set_sound_ranges(uint32_t count, const SoundInstanceId* ids, const float* ranges)
 	{
-		for (uint32_t i = 0; i < m_playing_sounds.size(); i++)
+		for (uint32_t i = 0; i < id_array::size(m_playing_sounds); i++)
 		{
 			m_playing_sounds[i].set_range(ranges[i]);
 		}
@@ -446,7 +446,7 @@ public:
 
 	virtual void set_sound_volumes(uint32_t count, const SoundInstanceId* ids, const float* volumes)
 	{
-		for (uint32_t i = 0; i < m_playing_sounds.size(); i++)
+		for (uint32_t i = 0; i < id_array::size(m_playing_sounds); i++)
 		{
 			m_playing_sounds[i].set_volume(volumes[i]);
 		}
@@ -454,7 +454,7 @@ public:
 
 	virtual void reload_sounds(SoundResource* old_sr, SoundResource* new_sr)
 	{
-		for (uint32_t i = 0; i < m_playing_sounds.size(); i++)
+		for (uint32_t i = 0; i < id_array::size(m_playing_sounds); i++)
 		{
 			if (m_playing_sounds[i].resource() == old_sr)
 			{
@@ -476,7 +476,7 @@ public:
 			const SoundInstanceId id = queue::front(*sles_sound_world::s_stop_queue);
 			queue::pop_front(*sles_sound_world::s_stop_queue);
 
-			if (!m_playing_sounds.has(id)) continue;
+			if (!id_array::has(m_playing_sounds, id)) continue;
 			stop(id);
 		}
 	}

+ 8 - 3
engine/compilers/BundleCompiler.cpp

@@ -51,6 +51,7 @@ namespace sprite_resource { extern void compile(Filesystem&, const char*, File*)
 namespace material_resource { extern void compile(Filesystem&, const char*, File*); }
 namespace gui_resource { extern void compile(Filesystem&, const char*, File*); }
 namespace font_resource { extern void compile(Filesystem&, const char*, File*); }
+namespace level_resource { extern void compile(Filesystem&, const char*, File*); }
 
 //-----------------------------------------------------------------------------
 BundleCompiler::BundleCompiler()
@@ -87,7 +88,7 @@ bool BundleCompiler::compile(const char* bundle_dir, const char* source_dir, con
 		}
 		else
 		{
-			Log::d("'crown.config' does not exist.");
+			CE_LOGD("'crown.config' does not exist.");
 			return false;
 		}
 	}
@@ -118,7 +119,7 @@ bool BundleCompiler::compile(const char* bundle_dir, const char* source_dir, con
 			continue;
 		}
 
-		Log::i("%s <= %s", out_name, filename);
+		CE_LOGI("%s <= %s", out_name, filename);
 
 		DiskFilesystem root_fs(source_dir);
 		DiskFilesystem dest_fs(bundle_dir);
@@ -176,9 +177,13 @@ bool BundleCompiler::compile(const char* bundle_dir, const char* source_dir, con
 			{
 				font_resource::compile(root_fs, filename, out_file);
 			}
+			else if (resource_type_hash == LEVEL_TYPE)
+			{
+				level_resource::compile(root_fs, filename, out_file);
+			}
 			else
 			{
-				Log::e("Oops, unknown resource type!");
+				CE_LOGE("Oops, unknown resource type!");
 				return false;
 			}
 

+ 0 - 211
engine/core/Args.cpp

@@ -1,211 +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 "Args.h"
-#include "Log.h"
-
-namespace crown
-{
-
-//-----------------------------------------------------------------------------
-Args::Args(int argc, char** argv, const char* shortopts, const ArgsOption* longopts)
-	: m_argc(argc)
-	, m_argv(argv)
-	, m_shortopts(shortopts)
-	, m_longopts(longopts)
-	, m_optind(1)				// Do not consider argv[0]
-	, m_scope(argc)
-	, m_optarg(NULL)
-{
-	CE_ASSERT(argv != NULL, "Argument vector must be != NULL");
-	CE_ASSERT(shortopts != NULL, "Short argument list must be != NULL");
-	// longopts could be NULL
-}
-
-//-----------------------------------------------------------------------------
-Args::~Args()
-{
-}
-
-//-----------------------------------------------------------------------------
-int32_t Args::getopt()
-{
-	// Always reset optarg
-	m_optarg = NULL;
-
-	// End of arguments
-	if (m_optind >= m_scope)
-	{
-		return -1;
-	}
-
-	switch (option_type(m_argv[m_optind]))
-	{
-		case AOT_SHORT:
-		{
-			return short_option(m_argv[m_optind]);
-		}
-		case AOT_LONG:
-		{
-			return long_option(m_argv[m_optind]);
-		}
-		case AOT_NOT_OPTION:
-		{
-			not_option();
-			return getopt();
-		}
-		default:
-		{
-			return '?';
-		}
-	}
-}
-
-//-----------------------------------------------------------------------------
-int32_t Args::optind() const
-{
-	return m_optind;
-}
-
-//-----------------------------------------------------------------------------
-const char* Args::optarg() const
-{
-	return m_optarg;
-}
-
-//-----------------------------------------------------------------------------
-void Args::set_optind(int32_t index)
-{
-	m_optind = index;
-}
-
-//-----------------------------------------------------------------------------
-ArgsOptionType Args::option_type(const char* option)
-{
-	const size_t option_len = string::strlen(option);
-
-	if (option_len == 2 && option[0] == '-' && option[1] != '-')
-	{
-		return AOT_SHORT;
-	}
-	else if (option_len > 2 && option[0] == '-' && option[1] == '-')
-	{
-		return AOT_LONG;
-	}
-
-	return AOT_NOT_OPTION;
-}
-
-//-----------------------------------------------------------------------------
-int32_t Args::long_option(const char* option)
-{
-	const ArgsOption* current_option = m_longopts;
-
-	// Loop through all the long options
-	while (!end_of_longopts(current_option))
-	{
-		if (string::strcmp(current_option->name, &option[2]) == 0)
-		{
-			// If the option requires an argument
-			if (current_option->has_arg == AOA_REQUIRED_ARGUMENT)
-			{
-				// Read the argument if it exists
-				if ((m_optind + 1) < m_scope)
-				{
-					// Read the argument and skip the following parameter
-					m_optarg = m_argv[m_optind + 1];
-					m_optind += 2;
-				}
-				else
-				{
-					Log::e("%s: option requires an argument -- '%s'", m_argv[0], current_option->name);
-
-					// Missing option
-					m_optind += 1;
-					return '?';
-				}
-			}
-			// If the option does not require an argument
-			else
-			{
-				m_optind++;
-			}
-
-			if (current_option->flag == NULL)
-			{
-				return current_option->val;
-			}
-			else
-			{
-				(*current_option->flag) = current_option->val;
-
-				return 0;
-			}
-		}
-
-		current_option++;
-	}
-
-	// Found a long option but was not included in longopts
-	Log::e("%s: invalid option -- '%s'", m_argv[0], &option[2]);
-	m_optind++;
-	return '?';
-}
-
-//-----------------------------------------------------------------------------
-int32_t Args::short_option(const char* option)
-{
-	(void)option;
-
-	Log::e("%s: invalid option -- '%s'", m_argv[0], &option[1]);
-	m_optind++;
-	return '?';
-}
-
-//-----------------------------------------------------------------------------
-void Args::not_option()
-{
-	char* current_option = m_argv[m_optind];
-
-	for (int32_t i = m_optind; i < (m_argc - 1); i++)
-	{
-		m_argv[i] = m_argv[i + 1];
-	}
-
-	m_argv[m_argc - 1] = current_option;
-
-	// Reduce the number of true arguments
-	m_scope--;
-}
-
-//-----------------------------------------------------------------------------
-bool Args::end_of_longopts(const ArgsOption* option) const
-{
-	return (option->name == NULL && option->has_arg == 0 && option->flag == NULL && option->val == 0);
-}
-
-
-} // namespace crown

+ 165 - 24
engine/core/Args.h

@@ -48,19 +48,30 @@ enum ArgsOptionArgument
 
 struct ArgsOption
 {
-	const char*				name;
-	int32_t					has_arg;
-	int32_t*				flag;
-	int32_t					val;
+	const char* name;
+	int32_t has_arg;
+	int32_t* flag;
+	int32_t val;
 };
 
 /// Parses the command line arguments in a way very similar to GNU getopt.
-class CE_EXPORT Args
+class Args
 {
 public:
 
-						Args(int argc, char** argv, const char* shortopts, const ArgsOption* longopts);
-						~Args();
+	Args(int argc, char** argv, const char* shortopts, const ArgsOption* longopts)
+		: m_argc(argc)
+		, m_argv(argv)
+		, m_shortopts(shortopts)
+		, m_longopts(longopts)
+		, m_optind(1)				// Do not consider argv[0]
+		, m_scope(argc)
+		, m_optarg(NULL)
+	{
+		CE_ASSERT(argv != NULL, "Argument vector must be != NULL");
+		CE_ASSERT(shortopts != NULL, "Short argument list must be != NULL");
+		// longopts could be NULL
+	}
 
 	/// Finds the next option character and returns it.
 	/// If there are no more option characters, it returns -1 and optind()
@@ -68,19 +79,59 @@ public:
 	/// an option.
 	/// If it finds an option that was not included in shortopts or longopts,
 	/// or if it finds a missing option argument, it returns '?' character.
-	int32_t				getopt();
+	int32_t getopt()
+	{
+		// Always reset optarg
+		m_optarg = NULL;
+
+		// End of arguments
+		if (m_optind >= m_scope)
+		{
+			return -1;
+		}
+
+		switch (option_type(m_argv[m_optind]))
+		{
+			case AOT_SHORT:
+			{
+				return short_option(m_argv[m_optind]);
+			}
+			case AOT_LONG:
+			{
+				return long_option(m_argv[m_optind]);
+			}
+			case AOT_NOT_OPTION:
+			{
+				not_option();
+				return getopt();
+			}
+			default:
+			{
+				return '?';
+			}
+		}
+	}
 
 	/// Returns the index of the next argument to be processed.
-	int32_t				optind() const;
+	int32_t optind() const
+	{
+		return m_optind;
+	}
 
 	/// Returns the text of the following argv-element in respect
 	/// to the current optind().
-	const char*			optarg() const;
+	const char* optarg() const
+	{
+		return m_optarg;
+	}
 
 
 	/// Sets the @a index into argv[] from where to start option scanning.
 	/// If @a index >= argc nothing will be scanned.
-	void				set_optind(int32_t index);
+	void set_optind(int32_t index)
+	{
+		m_optind = index;
+	}
 
 private:
 
@@ -88,36 +139,126 @@ private:
 	// Returns AOT_SHORT if option is of the form "-x" where 'x' is the option.
 	// Returns AOT_LONG if option is of the form "--option" where "option" is the option.
 	// Returns AOT_NOT_OPTION in all other cases.
-	ArgsOptionType		option_type(const char* option);
+	ArgsOptionType option_type(const char* option)
+	{
+		const size_t option_len = string::strlen(option);
+
+		if (option_len == 2 && option[0] == '-' && option[1] != '-')
+		{
+			return AOT_SHORT;
+		}
+		else if (option_len > 2 && option[0] == '-' && option[1] == '-')
+		{
+			return AOT_LONG;
+		}
+
+		return AOT_NOT_OPTION;
+	}
+
 
 	// Parses a long option
-	int32_t				long_option(const char* option);
+	int32_t long_option(const char* option)
+	{
+		const ArgsOption* current_option = m_longopts;
+
+		// Loop through all the long options
+		while (!end_of_longopts(current_option))
+		{
+			if (string::strcmp(current_option->name, &option[2]) == 0)
+			{
+				// If the option requires an argument
+				if (current_option->has_arg == AOA_REQUIRED_ARGUMENT)
+				{
+					// Read the argument if it exists
+					if ((m_optind + 1) < m_scope)
+					{
+						// Read the argument and skip the following parameter
+						m_optarg = m_argv[m_optind + 1];
+						m_optind += 2;
+					}
+					else
+					{
+						// CE_LOGE("%s: option requires an argument -- '%s'", m_argv[0], current_option->name);
+
+						// Missing option
+						m_optind += 1;
+						return '?';
+					}
+				}
+				// If the option does not require an argument
+				else
+				{
+					m_optind++;
+				}
+
+				if (current_option->flag == NULL)
+				{
+					return current_option->val;
+				}
+				else
+				{
+					(*current_option->flag) = current_option->val;
+
+					return 0;
+				}
+			}
+
+			current_option++;
+		}
+
+		// Found a long option but was not included in longopts
+		// CE_LOGE("%s: invalid option -- '%s'", m_argv[0], &option[2]);
+		m_optind++;
+		return '?';
+	}
 
 	// Parses a short option
-	int32_t				short_option(const char* option);
+	int32_t short_option(const char* option)
+	{
+		(void)option;
+
+		// CE_LOGE("%s: invalid option -- '%s'", m_argv[0], &option[1]);
+		m_optind++;
+		return '?';
+	}
 
-	void				not_option();
+	void not_option()
+	{
+		char* current_option = m_argv[m_optind];
+
+		for (int32_t i = m_optind; i < (m_argc - 1); i++)
+		{
+			m_argv[i] = m_argv[i + 1];
+		}
+
+		m_argv[m_argc - 1] = current_option;
+
+		// Reduce the number of true arguments
+		m_scope--;
+	}
 
 	// Returns whether the given option is the last one
-	bool				end_of_longopts(const ArgsOption* option) const;
+	bool end_of_longopts(const ArgsOption* option) const
+	{
+		return (option->name == NULL && option->has_arg == 0 && option->flag == NULL && option->val == 0);
+	}
 
 private:
 
-	int					m_argc;
-	char**				m_argv;
+	int m_argc;
+	char** m_argv;
 
-	const char*			m_shortopts;
-	const ArgsOption*	m_longopts;
+	const char* m_shortopts;
+	const ArgsOption* m_longopts;
 
 	// Index of the next argument to be processed
-	int32_t				m_optind;
+	int32_t m_optind;
 
 	// Number of "true" arguments
-	int32_t				m_scope;
+	int32_t m_scope;
 
 	// The text of the following argv-element to argv[optind]
-	char*				m_optarg;
+	char* m_optarg;
 };
 
 } // namespace crown
-

+ 11 - 11
engine/core/Error.h

@@ -24,7 +24,11 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
 */
 
-#include "Log.h"
+#pragma once
+
+#include "Config.h"
+#include "Types.h"
+#include "Macros.h"
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdarg.h>
@@ -34,10 +38,6 @@ OTHER DEALINGS IN THE SOFTWARE.
 	#include <execinfo.h>
 #endif
 
-#include "Config.h"
-
-#pragma once
-
 namespace crown
 {
 namespace error
@@ -84,13 +84,13 @@ inline void log_backtrace()
 			int status;
 			char* real_name = abi::__cxa_demangle(mangled_name, 0, 0, &status);
 
-			Log::e("\t[%d] %s: (%s)+%s %s", i, messages[i], (status == 0 ? real_name : mangled_name), offset_begin, offset_end);
+			printf("\t[%d] %s: (%s)+%s %s\n", i, messages[i], (status == 0 ? real_name : mangled_name), offset_begin, offset_end);
 			free(real_name);
 		}
 		// otherwise, print the whole line
 		else
 		{
-			Log::e("\t[%d] %s", i, messages[i]);
+			printf("\t[%d] %s\n", i, messages[i]);
 		}
 	}
 	free(messages);
@@ -103,14 +103,14 @@ inline void abort(const char* file, int line, const char* message, ...)
 {
 	va_list ap;
 	va_start(ap, message);
-	Log::e1(message, ap);
+	vprintf(message, ap);
 	va_end(ap);
-	Log::e("\tIn: %s:%d\n", file, line);
-	Log::e("Backtrace:");
+	printf("\tIn: %s:%d\n", file, line);
+	printf("Backtrace:\n");
 	//fflush(0);
 	log_backtrace();
 	exit(EXIT_FAILURE);
 }
 
 } // namespace error
-} // namespace crown
+} // namespace crown

+ 0 - 154
engine/core/Log.cpp

@@ -1,154 +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 "Log.h"
-#include "Device.h"
-#include "ConsoleServer.h"
-
-namespace crown
-{
-
-LogSeverity::Enum Log::m_threshold = LogSeverity::DEBUG;
-
-//-----------------------------------------------------------------------------
-LogSeverity::Enum Log::threshold()
-{
-	return m_threshold;
-}
-
-//-----------------------------------------------------------------------------
-void Log::set_threshold(LogSeverity::Enum threshold)
-{
-	m_threshold = threshold;
-}
-
-//-----------------------------------------------------------------------------
-void Log::log_message(LogSeverity::Enum severity, const char* message, ::va_list arg)
-{
-	if (severity > m_threshold)
-	{
-		return;
-	}
-
-	va_list arg_copy;
-	__va_copy(arg_copy, arg);
-
-	char buf[1024];
-	int len = vsnprintf(buf, 1024 - 2, message, arg);
-	buf[len] = '\n';
-	buf[len + 1] = '\0';
-
-	// Log on local device
-	switch (severity)
-	{
-		case LogSeverity::DEBUG: os::log_debug(message, arg_copy); break;
-		case LogSeverity::WARN: os::log_warning(message, arg_copy); break;
-		case LogSeverity::ERROR: os::log_error(message, arg_copy); break;
-		case LogSeverity::INFO: os::log_info(message, arg_copy); break;
-		default: break;
-	}
-	va_end(arg_copy);
-
-	// // Log to remote clients
-	// if (device()->console() != NULL && string::strlen(buf) > 0)
-	// {
-	// 	device()->console()->log_to_all(buf, severity);
-	// }
-}
-
-//-----------------------------------------------------------------------------
-void Log::d(const char* message, ...)
-{
-	va_list args;
-	va_start (args, message);
-	Log::d1(message, args);
-	va_end (args);
-}
-
-//-----------------------------------------------------------------------------
-void Log::e(const char* message, ...)
-{
-	va_list args;
-	va_start (args, message);
-	Log::e1(message, args);
-	va_end (args);
-}
-
-//-----------------------------------------------------------------------------
-void Log::w(const char* message, ...)
-{
-	va_list args;
-	va_start (args, message);
-	Log::w1(message, args);
-	va_end (args);
-}
-
-//-----------------------------------------------------------------------------
-void Log::i(const char* message, ...)
-{
-	va_list args;
-	va_start (args, message);
-	Log::i1(message, args);
-	va_end (args);
-}
-
-//-----------------------------------------------------------------------------
-void Log::d1(const char* message, ::va_list args)
-{
-	va_list arg_copy;
-	__va_copy(arg_copy, args);
-	log_message(LogSeverity::DEBUG, message, arg_copy);
-	va_end(arg_copy);
-}
-
-//-----------------------------------------------------------------------------
-void Log::e1(const char* message, ::va_list args)
-{
-	va_list arg_copy;
-	__va_copy(arg_copy, args);
-	log_message(LogSeverity::ERROR, message, arg_copy);
-	va_end(arg_copy);
-}
-
-//-----------------------------------------------------------------------------
-void Log::w1(const char* message, ::va_list args)
-{
-	va_list arg_copy;
-	__va_copy(arg_copy, args);
-	log_message(LogSeverity::WARN, message, arg_copy);
-	va_end(arg_copy);
-}
-
-//-----------------------------------------------------------------------------
-void Log::i1(const char* message, ::va_list args)
-{
-	va_list arg_copy;
-	__va_copy(arg_copy, args);
-	log_message(LogSeverity::INFO, message, arg_copy);
-	va_end(arg_copy);
-}
-
-} // namespace crown

+ 14 - 53
engine/core/Log.h

@@ -26,56 +26,17 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 #pragma once
 
-#include <cstdio>
-#include <cstdarg>
-#include "Types.h"
-#include "Macros.h"
-
-namespace crown
-{
-
-/// Enumerates log levels.
-struct LogSeverity
-{
-	enum Enum
-	{
-		INFO	= 0,
-		WARN	= 1,
-		ERROR	= 2,
-		DEBUG	= 3
-	};	
-};
-
-class RPCServer;
-
-/// Used to log messages.
-class CE_EXPORT Log
-{
-
-public:
-
-	/// Returns the threshold used to filter out log messages.
-	static LogSeverity::Enum threshold();
-
-	/// Sets the thresold used to filter out log messages
-	static void			set_threshold(LogSeverity::Enum threshold);
-
-	static void			log_message(LogSeverity::Enum severity, const char* message, ::va_list arg);
-
-	static void			d(const char* message, ...);
-	static void			e(const char* message, ...);
-	static void			w(const char* message, ...);
-	static void			i(const char* message, ...);
-	static void			d1(const char* message, ::va_list args);
-	static void			e1(const char* message, ::va_list args);
-	static void			w1(const char* message, ::va_list args);
-	static void			i1(const char* message, ::va_list args);
-
-private:
-
-
-	static LogSeverity::Enum m_threshold;
-};
-
-} // namespace crown
-
+#include "Device.h"
+#include "ConsoleServer.h"
+
+#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
+	#define CE_LOGI(msg, ...) crown::device()->console()->log_to_all(crown::LogSeverity::INFO, msg, ##__VA_ARGS__)
+	#define CE_LOGD(msg, ...) crown::device()->console()->log_to_all(crown::LogSeverity::DEBUG, msg, ##__VA_ARGS__)
+	#define CE_LOGE(msg, ...) crown::device()->console()->log_to_all(crown::LogSeverity::ERROR, msg, ##__VA_ARGS__)
+	#define CE_LOGW(msg, ...) crown::device()->console()->log_to_all(crown::LogSeverity::WARN, msg, ##__VA_ARGS__)
+#else
+	#define CE_LOGI(msg, ...) ((void)0)
+	#define CE_LOGD(msg, ...) ((void)0)
+	#define CE_LOGE(msg, ...) ((void)0)
+	#define CE_LOGW(msg, ...) ((void)0)
+#endif

+ 2 - 0
engine/core/Macros.h

@@ -39,3 +39,5 @@ OTHER DEALINGS IN THE SOFTWARE.
 #else
 	#error "Compiler not supported"
 #endif
+
+#define CE_UNUSED(x) do { (void)(x); } while (0)

+ 1 - 1
engine/core/Profiler.h

@@ -96,7 +96,7 @@ namespace profiler
 		// 	char* p = t_buffer + cur;
 		// 	uint32_t event_type = *(uint32_t*) p;
 		// 	RecordFloat event = *(RecordFloat*)(p + sizeof(uint32_t));
-		// 	Log::d("ev type = %d, name = %s, value = %f\n", event_type, event.name, 1.0 / event.value);
+		// 	CE_LOGD("ev type = %d, name = %s, value = %f\n", event_type, event.name, 1.0 / event.value);
 		// 	cur += sizeof(uint32_t) + sizeof(RecordFloat);
 		// }
 	}

+ 48 - 30
engine/os/android/java/CrownLib.java → engine/core/containers/Blob.h

@@ -24,39 +24,57 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
 */
 
-package crown.android;
+#pragma once
 
-import android.content.res.AssetManager;
-import android.view.Surface;
+#include "Types.h"
+#include "Assert.h"
 
-public class CrownLib
+namespace crown
 {
-	static 
+
+/// Block of raw memory.
+///
+/// @ingroup Containers
+struct Blob
+{
+	uint32_t m_size;
+	uintptr_t m_data;
+};
+
+/// Functions to manipulate Blob.
+///
+/// @ingroup Containers
+namespace blob
+{
+	/// Returns the size of the blob @a b.
+	uint32_t size(const Blob& b);
+
+	/// Retuns a pointer to the byte at the given absolute @a offset into the blob @a b.
+	template <typename T> const T* get(const Blob& b, uint32_t offset);
+
+	/// @copydoc blob::get<T>(const Blob&, uint32_t)
+	template <typename T> T* get(Blob& b, uint32_t offset);
+} // namespace blob
+
+namespace blob
+{
+	inline uint32_t size(const Blob& b)
+	{
+		return b.m_size;
+	}
+
+	template <typename T>
+	inline const T* get(const Blob& b, uint32_t offset)
 	{
-		System.loadLibrary("luajit-5.1");
-		System.loadLibrary("crown");
+		CE_ASSERT(offset < b.m_size, "Overflow (size = %d, offset = %d", b.m_size, offset);
+		return (T*) b.m_data + offset;
 	}
 
-	// Crown functions
-	public static native void		initCrown();
-	public static native void		shutdownCrown();
-
-	public static native int		run();
-
-	// AssetManager functions
-	public static native void 		initAssetManager(AssetManager assetManager);
-
-	// Window functions
-	public static native void		acquireWindow(Surface window);
-	public static native void		releaseWindow();
-
-	// Os events
-	public static native void		pushKeyboardEvent(int modifier, int b, int pressed);
-	public static native void 		pushTouchEventMove(int pointer_id, int x, int y);
-	public static native void		pushTouchEventPointer(int pointer_id, int x, int y, int pressed);
-	public static native void		pushMetricsEvent(int x, int y, int width, int height);
-	public static native void 		pushAccelerometerEvent(int type, float x, float y, float z);
-	public static native void		pushPauseEvent();
-	public static native void		pushResumeEvent();
-	public static native void		pushExitEvent(int code);
-}
+	template <typename T>
+	inline T* get(Blob& b, uint32_t offset)
+	{
+		CE_ASSERT(offset < b.m_size, "Overflow (size = %d, offset = %d", b.m_size, offset);
+		return (T*) b.m_data + offset;
+	}
+} // namespace blob
+} // namespace crown

+ 94 - 0
engine/core/containers/DynamicBlob.h

@@ -0,0 +1,94 @@
+/*
+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 "Array.h"
+
+namespace crown
+{
+
+/// Dynamic block of raw memory.
+///
+/// @ingroup Containers
+typedef Array<char> DynamicBlob;
+
+/// Functions to manipulate DynamicBlob.
+///
+/// @ingroup Containers
+namespace dynamic_blob
+{
+	/// Returns the size of the blob @a b.
+	uint32_t size(const DynamicBlob& b);
+
+	/// Retuns a pointer to the byte at the given absolute @a offset into the blob @a b.
+	template <typename T> const T* get(const DynamicBlob& b, uint32_t offset);
+
+	/// @copydoc blob::get<T>(const DynamicBlob&, uint32_t)
+	template <typename T> T* get(DynamicBlob& b, uint32_t offset);
+
+	/// Appends @a num @a items to the blob @a b and returns the size of the
+	/// blob after the append operation.
+	template <typename T> uint32_t push(DynamicBlob& b, const T* items, uint32_t num);
+
+	/// Appends @a blob to @a b and returns the size of the blob after the append operation.
+	uint32_t push_blob(DynamicBlob& b, const DynamicBlob& other);
+} // namespace dynamic_blob
+
+namespace dynamic_blob
+{
+	inline uint32_t size(const DynamicBlob& b)
+	{
+		return array::size(b);
+	}
+
+	template <typename T>
+	inline const T* get(const DynamicBlob& b, uint32_t offset)
+	{
+		CE_ASSERT(offset < size(b), "Overflow (size = %d, offset = %d", size(b), offset);
+		return (T*) array::begin(b) + offset;
+	}
+
+	template <typename T>
+	inline T* get(DynamicBlob& b, uint32_t offset)
+	{
+		CE_ASSERT(offset < size(b), "Overflow (size = %d, offset = %d", size(b), offset);
+		return (T*) array::begin(b) + offset;
+	}
+
+	template <typename T>
+	inline uint32_t push(DynamicBlob& b, const T* items, uint32_t num)
+	{
+		return array::push(b, (const char*) items, num);
+	}
+
+	inline uint32_t push_blob(DynamicBlob& b, const DynamicBlob& other)
+	{
+		return array::push(b, array::begin(other), size(other));
+	}
+} // namespace dynamic_blob
+} // namespace crown

+ 24 - 24
engine/core/containers/Hash.h

@@ -102,7 +102,7 @@ namespace crown {
 			uint32_t hash_i;
 			uint32_t data_prev;
 			uint32_t data_i;
-		};	
+		};
 
 		template<typename T> uint32_t add_entry(Hash<T> &h, uint64_t key)
 		{
@@ -114,27 +114,6 @@ namespace crown {
 			return ei;
 		}
 
-		template<typename T> void erase(Hash<T> &h, const FindResult &fr)
-		{
-			if (fr.data_prev == END_OF_LIST)
-				h._hash[fr.hash_i] = h._data[fr.data_i].next;
-			else
-				h._data[fr.data_prev].next = h._data[fr.data_i].next;
-
-			if (fr.data_i == array::size(h._data) - 1) {
-				array::pop_back(h._data);
-				return;
-			}
-
-			h._data[fr.data_i] = h._data[array::size(h._data) - 1];
-			FindResult last = find(h, h._data[fr.data_i].key);
-
-			if (last.data_prev != END_OF_LIST)
-				h._data[last.data_prev].next = fr.data_i;
-			else
-				h._hash[last.hash_i] = fr.data_i;
-		}
-
 		template<typename T> FindResult find(const Hash<T> &h, uint64_t key)
 		{
 			FindResult fr;
@@ -177,6 +156,27 @@ namespace crown {
 			return fr;
 		}
 
+		template<typename T> void erase(Hash<T> &h, const FindResult &fr)
+		{
+			if (fr.data_prev == END_OF_LIST)
+				h._hash[fr.hash_i] = h._data[fr.data_i].next;
+			else
+				h._data[fr.data_prev].next = h._data[fr.data_i].next;
+
+			if (fr.data_i == array::size(h._data) - 1) {
+				array::pop_back(h._data);
+				return;
+			}
+
+			h._data[fr.data_i] = h._data[array::size(h._data) - 1];
+			FindResult last = find(h, h._data[fr.data_i].key);
+
+			if (last.data_prev != END_OF_LIST)
+				h._data[last.data_prev].next = fr.data_i;
+			else
+				h._hash[last.hash_i] = fr.data_i;
+		}
+
 		template<typename T> uint32_t find_or_fail(const Hash<T> &h, uint64_t key)
 		{
 			return find(h, key).data_i;
@@ -219,7 +219,7 @@ namespace crown {
 
 		template<typename T> void rehash(Hash<T> &h, uint32_t new_size)
 		{
-			Hash<T> nh(*h._hash._allocator);
+			Hash<T> nh(*h._hash.m_allocator);
 			array::resize(nh._hash, new_size);
 			array::reserve(nh._data, array::size(h._data));
 			for (uint32_t i=0; i<new_size; ++i)
@@ -229,7 +229,7 @@ namespace crown {
 				multi_hash::insert(nh, e.key, e.value);
 			}
 
-			Hash<T> empty(*h._hash._allocator);
+			Hash<T> empty(*h._hash.m_allocator);
 			h.~Hash<T>();
 			memcpy(&h, &nh, sizeof(Hash<T>));
 			memcpy(&nh, &empty, sizeof(Hash<T>));

+ 144 - 156
engine/core/containers/IdArray.h

@@ -36,204 +36,192 @@ namespace crown
 /// Packed array of objects with lookup table.
 ///
 /// @ingroup Containers
-template <uint32_t MAX_NUM_ID, typename T>
-class IdArray
+template <uint32_t MAX, typename T>
+struct IdArray
 {
-public:
-
-	/// Creates the table for tracking exactly @a MAX_NUM_ID - 1 unique Ids.
-					IdArray();
+	/// Creates the table for tracking exactly @a MAX - 1 unique Ids.
+	IdArray();
 
 	/// Random access by index.
-	T&				operator[](uint32_t i);
+	T& operator[](uint32_t i);
 	/// Random access by index.
-	const T&		operator[](uint32_t i) const;
-
-	/// Returns a new Id.
-	Id				create(const T& object);
-
-	/// Destroys the object with the given @a id.
-	void			destroy(Id id);
-
-	/// Returns whether the table has the object with the given @a id
-	bool			has(Id id) const;
-
-	/// Returns the number of objects in the array.
-	uint32_t		size() const;
-
-	/// Returns the object with the given @a id.
-	T&				lookup(const Id& id);
-
-	T*				begin();
-	const T*		begin() const;
-	T*				end();
-	const T*		end() const;
-
-private:
-
-	// Returns the next available unique id.
-	uint16_t		next_id();
-
-public:
+	const T& operator[](uint32_t i) const;
 
 	// The index of the first unused id
-	uint16_t		m_freelist;
-
-	// The index of the last id in the id table
-	uint16_t		m_last_index;
+	uint16_t m_freelist;
 
 	// Next available unique id
-	uint16_t		m_next_id;
-	uint16_t		m_num_objects;
-
+	uint16_t m_next_id;
+	uint16_t m_size;
 
 	// The last valid id is reserved and cannot be used to
 	// refer to Ids from the outside
-	Id				m_sparse[MAX_NUM_ID];
-	uint16_t		m_sparse_to_dense[MAX_NUM_ID];
-	uint16_t		m_dense_to_sparse[MAX_NUM_ID];
-	T				m_objects[MAX_NUM_ID];
+	Id m_sparse[MAX];
+	uint16_t m_sparse_to_dense[MAX];
+	uint16_t m_dense_to_sparse[MAX];
+	T m_objects[MAX];
 };
 
-//-----------------------------------------------------------------------------
-template <uint32_t MAX_NUM_ID, typename T>
-inline IdArray<MAX_NUM_ID, T>::IdArray()
-	: m_freelist(INVALID_ID)
-	, m_last_index(0)
-	, m_next_id(0)
-	, m_num_objects(0)
+/// Functions to manipulate IdArray.
+///
+/// @ingroup Containers
+namespace id_array
 {
-	for (uint32_t i = 0; i < MAX_NUM_ID; i++)
-	{
-		m_sparse[i].id = INVALID_ID;
-	}
-}
+	/// Creates a new @a object in the array @a a and returns its id.
+	template <uint32_t MAX, typename T> Id create(IdArray<MAX, T>& a, const T& object);
 
-//-----------------------------------------------------------------------------
-template <uint32_t MAX_NUM_ID, typename T>
-inline T& IdArray<MAX_NUM_ID, T>::operator[](uint32_t i)
-{
-	CE_ASSERT(i < m_num_objects, "Index out of bounds");
-	return m_objects[i];
-}
+	/// Destroys the object with the given @a id.
+	template <uint32_t MAX, typename T> void destroy(IdArray<MAX, T>& a, Id id);
 
-//-----------------------------------------------------------------------------
-template <uint32_t MAX_NUM_ID, typename T>
-inline const T& IdArray<MAX_NUM_ID, T>::operator[](uint32_t i) const
-{
-	CE_ASSERT(i < m_num_objects, "Index out of bounds");
-	return m_objects[i];
-}
+	/// Returns whether the table has the object with the given @a id.
+	template <uint32_t MAX, typename T> bool has(const IdArray<MAX, T>& a, Id id);
 
-//-----------------------------------------------------------------------------
-template <uint32_t MAX_NUM_ID, typename T>
-inline Id IdArray<MAX_NUM_ID, T>::create(const T& object)
-{
-	CE_ASSERT(m_num_objects < MAX_NUM_ID, "Object list full");
+	/// Returns the number of objects in the array.
+	template <uint32_t MAX, typename T> uint32_t size(const IdArray<MAX, T>& a);
 
-	// Obtain a new id
-	Id id;
-	id.id = next_id();
+	/// Returns the object with the given @a id.
+	template <uint32_t MAX, typename T> T& get(const Id& id);
+
+	template <uint32_t MAX, typename T> T* begin(IdArray<MAX, T>& a);
+	template <uint32_t MAX, typename T> const T* begin(const IdArray<MAX, T>& a);
+	template <uint32_t MAX, typename T> T* end(IdArray<MAX, T>& a);
+	template <uint32_t MAX, typename T> const T* end(const IdArray<MAX, T>& a);
+} // namespace id_array
 
-	// Recycle slot if there are any
-	if (m_freelist != INVALID_ID)
+namespace id_array
+{
+	//-----------------------------------------------------------------------------
+	template <uint32_t MAX, typename T>
+	inline Id create(IdArray<MAX, T>& a, const T& object)
 	{
-		id.index = m_freelist;
-		m_freelist = m_sparse[m_freelist].index;
+		CE_ASSERT(a.m_size < MAX, "Object list full");
+
+		// Obtain a new id
+		Id id;
+		id.id = a.m_next_id++;
+
+		// Recycle slot if there are any
+		if (a.m_freelist != INVALID_ID)
+		{
+			id.index = a.m_freelist;
+			a.m_freelist = a.m_sparse[a.m_freelist].index;
+		}
+		else
+		{
+			id.index = a.m_size;
+		}
+
+		a.m_sparse[id.index] = id;
+		a.m_sparse_to_dense[id.index] = a.m_size;
+		a.m_dense_to_sparse[a.m_size] = id.index;
+		a.m_objects[a.m_size] = object;
+		a.m_size++;
+
+		return id;
 	}
-	else
+
+	//-----------------------------------------------------------------------------
+	template <uint32_t MAX, typename T>
+	inline void destroy(IdArray<MAX, T>& a, Id id)
 	{
-		id.index = m_last_index++;
+		CE_ASSERT(has(a, id), "IdArray does not have ID: %d,%d", id.id, id.index);
+
+		a.m_sparse[id.index].id = INVALID_ID;
+		a.m_sparse[id.index].index = a.m_freelist;
+		a.m_freelist = id.index;
+
+		// Swap with last element
+		const uint32_t last = a.m_size - 1;
+		CE_ASSERT(last >= a.m_sparse_to_dense[id.index], "Swapping with previous item");
+		a.m_objects[a.m_sparse_to_dense[id.index]] = a.m_objects[last];
+
+		// Update tables
+		uint16_t std = a.m_sparse_to_dense[id.index];
+		uint16_t dts = a.m_dense_to_sparse[last];
+		a.m_sparse_to_dense[dts] = std;
+		a.m_dense_to_sparse[std] = dts;
+		a.m_size--;
 	}
 
-	m_sparse[id.index] = id;
-	m_sparse_to_dense[id.index] = m_num_objects;
-	m_dense_to_sparse[m_num_objects] = id.index;
-	m_objects[m_num_objects] = object;
-	m_num_objects++;
-
-	return id;
-}
+	//-----------------------------------------------------------------------------
+	template <uint32_t MAX, typename T>
+	inline T& get(IdArray<MAX, T>& a, const Id& id)
+	{
+		CE_ASSERT(has(a, id), "IdArray does not have ID: %d,%d", id.id, id.index);
 
-//-----------------------------------------------------------------------------
-template <uint32_t MAX_NUM_ID, typename T>
-inline void IdArray<MAX_NUM_ID, T>::destroy(Id id)
-{
-	CE_ASSERT(has(id), "IdArray does not have ID: %d,%d", id.id, id.index);
-
-	m_sparse[id.index].id = INVALID_ID;
-	m_sparse[id.index].index = m_freelist;
-	m_freelist = id.index;
-
-	// Swap with last element
-	const uint32_t last = m_num_objects - 1;
-	CE_ASSERT(last >= m_sparse_to_dense[id.index], "Swapping with previous item");
-	m_objects[m_sparse_to_dense[id.index]] = m_objects[last];
-
-	// Update tables
-	uint16_t std = m_sparse_to_dense[id.index];
-	uint16_t dts = m_dense_to_sparse[last];
-	m_sparse_to_dense[dts] = std;
-	m_dense_to_sparse[std] = dts;
-	m_num_objects--;
-}
+		return a.m_objects[a.m_sparse_to_dense[id.index]];
+	}
 
-//-----------------------------------------------------------------------------
-template <uint32_t MAX_NUM_ID, typename T>
-inline T& IdArray<MAX_NUM_ID, T>::lookup(const Id& id)
-{
-	CE_ASSERT(has(id), "IdArray does not have ID: %d,%d", id.id, id.index);
+	//-----------------------------------------------------------------------------
+	template <uint32_t MAX, typename T>
+	inline bool has(const IdArray<MAX, T>& a, Id id)
+	{
+		return id.index < MAX && a.m_sparse[id.index].id == id.id;
+	}
 
-	return m_objects[m_sparse_to_dense[id.index]];
-}
+	//-----------------------------------------------------------------------------
+	template <uint32_t MAX, typename T>
+	inline uint32_t size(const IdArray<MAX, T>& a)
+	{
+		return a.m_size;
+	}
 
-//-----------------------------------------------------------------------------
-template <uint32_t MAX_NUM_ID, typename T>
-inline bool IdArray<MAX_NUM_ID, T>::has(Id id) const
-{
-	return id.index < MAX_NUM_ID && m_sparse[id.index].id == id.id;
-}
+	//-----------------------------------------------------------------------------
+	template <uint32_t MAX, typename T>
+	inline T* begin(IdArray<MAX, T>& a)
+	{
+		return a.m_objects;
+	}
 
-//-----------------------------------------------------------------------------
-template <uint32_t MAX_NUM_ID, typename T>
-inline uint32_t IdArray<MAX_NUM_ID, T>::size() const
-{
-	return m_num_objects;
-}
+	//-----------------------------------------------------------------------------
+	template <uint32_t MAX, typename T>
+	inline const T* begin(const IdArray<MAX, T>& a)
+	{
+		return a.m_objects;
+	}
 
-//-----------------------------------------------------------------------------
-template <uint32_t MAX_NUM_ID, typename T>
-inline uint16_t IdArray<MAX_NUM_ID, T>::next_id()
-{
-	return m_next_id++;
-}
+	//-----------------------------------------------------------------------------
+	template <uint32_t MAX, typename T>
+	inline T* end(IdArray<MAX, T>& a)
+	{
+		return a.m_objects + a.m_size;
+	}
 
-//-----------------------------------------------------------------------------
-template <uint32_t MAX_NUM_ID, typename T>
-inline T* IdArray<MAX_NUM_ID, T>::begin()
-{
-	return m_objects;
-}
+	//-----------------------------------------------------------------------------
+	template <uint32_t MAX, typename T>
+	inline const T* end(const IdArray<MAX, T>& a)
+	{
+		return a.m_objects + a.m_size;
+	}
+} // namespace id_array
 
 //-----------------------------------------------------------------------------
-template <uint32_t MAX_NUM_ID, typename T>
-inline const T* IdArray<MAX_NUM_ID, T>::begin() const
+template <uint32_t MAX, typename T>
+inline IdArray<MAX, T>::IdArray()
+	: m_freelist(INVALID_ID)
+	, m_next_id(0)
+	, m_size(0)
 {
-	return m_objects;
+	for (uint32_t i = 0; i < MAX; i++)
+	{
+		m_sparse[i].id = INVALID_ID;
+	}
 }
 
 //-----------------------------------------------------------------------------
-template <uint32_t MAX_NUM_ID, typename T>
-inline T* IdArray<MAX_NUM_ID, T>::end()
+template <uint32_t MAX, typename T>
+inline T& IdArray<MAX, T>::operator[](uint32_t i)
 {
-	return m_objects + m_num_objects;
+	CE_ASSERT(i < m_size, "Index out of bounds");
+	return m_objects[i];
 }
 
 //-----------------------------------------------------------------------------
-template <uint32_t MAX_NUM_ID, typename T>
-inline const T* IdArray<MAX_NUM_ID, T>::end() const
+template <uint32_t MAX, typename T>
+inline const T& IdArray<MAX, T>::operator[](uint32_t i) const
 {
-	return m_objects + m_num_objects;
+	CE_ASSERT(i < m_size, "Index out of bounds");
+	return m_objects[i];
 }
 
 } // namespace crown

+ 93 - 104
engine/core/containers/IdTable.h

@@ -36,136 +36,125 @@ namespace crown
 /// Table of Ids.
 ///
 /// @ingroup Containers
-template <uint32_t MAX_NUM_ID>
-class IdTable
+template <uint32_t MAX>
+struct IdTable
 {
-public:
-
-	/// Creates the table for tracking exactly @a MAX_NUM_ID - 1 unique Ids.
-					IdTable();
-
-	/// Returns a new Id.
-	Id				create();
-
-	/// Destroys the specified @a id.
-	void			destroy(Id id);
-
-	/// Returns whether the table has the specified @a id
-	bool			has(Id id) const;
-
-	uint16_t		size() const;
-
-	const Id*		begin() const;
-	const Id*		end() const;
-
-private:
-
-	// Returns the next available unique id.
-	uint16_t		next_id();
-
-private:
+	/// Creates the table for tracking exactly @a MAX - 1 unique Ids.
+	IdTable();
 
 	// The index of the first unused id.
-	uint16_t		m_freelist;
-
-	// The index of the last id in the id table.
-	uint16_t		m_last_index;
+	uint16_t m_freelist;
 
 	// Next available unique id.
-	uint16_t		m_next_id;
-	uint16_t		m_size;
+	uint16_t m_next_id;
+	uint16_t m_size;
 
 	// Table of ids.
 	// The last valid id is reserved and cannot be used to
 	// refer to Ids from the outside.
-	Id				m_ids[MAX_NUM_ID];
+	Id m_ids[MAX];
 };
 
-//-----------------------------------------------------------------------------
-template <uint32_t MAX_NUM_ID>
-inline IdTable<MAX_NUM_ID>::IdTable()
-	: m_freelist(INVALID_ID)
-	, m_last_index(0)
-	, m_next_id(0)
-	, m_size(0)
-{
-	for (uint32_t i = 0; i < MAX_NUM_ID; i++)
-	{
-		m_ids[i].id = INVALID_ID;
-	}
-}
-
-//-----------------------------------------------------------------------------
-template <uint32_t MAX_NUM_ID>
-inline Id IdTable<MAX_NUM_ID>::create()
+/// Functions to manipulate IdTable.
+///
+/// @ingroup Containers
+namespace id_table
 {
-	// Obtain a new id
-	Id id;
-	id.id = next_id();
+	/// Creates a new Id in the table @a a and returns its value.
+	template <uint32_t MAX> Id create(IdTable<MAX>& a);
 
-	// Recycle slot if there are any
-	if (m_freelist != INVALID_ID)
-	{
-		id.index = m_freelist;
-		m_freelist = m_ids[m_freelist].index;
-	}
-	else
-	{
-		id.index = m_last_index++;
-	}
+	/// Destroys the @a id in the table @a a.
+	template <uint32_t MAX> void destroy(IdTable<MAX>& a, Id id);
 
-	m_ids[id.index] = id;
+	/// Returns whether the table @a a has the given @a id.
+	template <uint32_t MAX> bool has(const IdTable<MAX>& a, Id id);
 
-	m_size++;
+	/// Returns the number of ids in the table @a a.
+	template <uint32_t MAX> uint16_t size(const IdTable<MAX>& a);
 
-	return id;
-}
+	template <uint32_t MAX> const Id* begin(const IdTable<MAX>& a);
+	template <uint32_t MAX> const Id* end(const IdTable<MAX>& a);
+} // namespace id_table
 
-//-----------------------------------------------------------------------------
-template <uint32_t MAX_NUM_ID>
-inline void IdTable<MAX_NUM_ID>::destroy(Id id)
+namespace id_table
 {
-	CE_ASSERT(has(id), "IdTable does not have ID: %d,%d", id.id, id.index);
+	//-----------------------------------------------------------------------------
+	template <uint32_t MAX>
+	inline Id create(IdTable<MAX>& a)
+	{
+		// Obtain a new id
+		Id id;
+		id.id = a.m_next_id++;
+
+		// Recycle slot if there are any
+		if (a.m_freelist != INVALID_ID)
+		{
+			id.index = a.m_freelist;
+			a.m_freelist = a.m_ids[a.m_freelist].index;
+		}
+		else
+		{
+			id.index = a.m_size;
+		}
+
+		a.m_ids[id.index] = id;
+		a.m_size++;
+
+		return id;
+	}
 
-	m_ids[id.index].id = INVALID_ID;
-	m_ids[id.index].index = m_freelist;
-	m_freelist = id.index;
-	m_size--;
-}
+	//-----------------------------------------------------------------------------
+	template <uint32_t MAX>
+	inline void destroy(IdTable<MAX>& a, Id id)
+	{
+		CE_ASSERT(has(a, id), "IdTable does not have ID: %d,%d", id.id, id.index);
 
-//-----------------------------------------------------------------------------
-template <uint32_t MAX_NUM_ID>
-inline bool IdTable<MAX_NUM_ID>::has(Id id) const
-{
-	return id.index < MAX_NUM_ID && m_ids[id.index].id == id.id;
-}
+		a.m_ids[id.index].id = INVALID_ID;
+		a.m_ids[id.index].index = a.m_freelist;
+		a.m_freelist = id.index;
+		a.m_size--;
+	}
 
-//-----------------------------------------------------------------------------
-template <uint32_t MAX_NUM_ID>
-inline uint16_t IdTable<MAX_NUM_ID>::size() const
-{
-	return m_size;
-}
+	//-----------------------------------------------------------------------------
+	template <uint32_t MAX>
+	inline bool has(const IdTable<MAX>& a, Id id)
+	{
+		return id.index < MAX && a.m_ids[id.index].id == id.id;
+	}
 
-//-----------------------------------------------------------------------------
-template <uint32_t MAX_NUM_ID>
-inline const Id* IdTable<MAX_NUM_ID>::begin() const
-{
-	return m_ids;
-}
+	//-----------------------------------------------------------------------------
+	template <uint32_t MAX>
+	inline uint16_t size(const IdTable<MAX>& a)
+	{
+		return a.m_size;
+	}
 
-//-----------------------------------------------------------------------------
-template <uint32_t MAX_NUM_ID>
-inline const Id* IdTable<MAX_NUM_ID>::end() const
-{
-	return m_ids + MAX_NUM_ID;
-}
+	//-----------------------------------------------------------------------------
+	template <uint32_t MAX>
+	inline const Id* begin(const IdTable<MAX>& a)
+	{
+		return a.m_ids;
+	}
+
+	//-----------------------------------------------------------------------------
+	template <uint32_t MAX>
+	inline const Id* end(const IdTable<MAX>& a)
+	{
+		return a.m_ids + MAX;
+	}
+} // namespace id_table
 
 //-----------------------------------------------------------------------------
-template <uint32_t MAX_NUM_ID>
-inline uint16_t IdTable<MAX_NUM_ID>::next_id()
+template <uint32_t MAX>
+inline IdTable<MAX>::IdTable()
+	: m_freelist(INVALID_ID)
+	, m_next_id(0)
+	, m_size(0)
 {
-	return m_next_id++;
+	for (uint32_t i = 0; i < MAX; i++)
+	{
+		m_ids[i].id = INVALID_ID;
+	}
 }
 
 } // namespace crown

+ 17 - 22
engine/core/json/JSON.cpp

@@ -204,6 +204,21 @@ namespace json
 		return ch;
 	}
 
+	static const char* skip_value(const char* s)
+	{
+		CE_ASSERT_NOT_NULL(s);
+
+		const char* ch = s;
+		ch = skip_array(ch);
+		ch = skip_object(ch);
+		ch = skip_number(ch);
+		ch = skip_string(ch);
+		ch = skip_bool(ch);
+		ch = skip_null(ch);
+
+		return ch;
+	}
+
 	//-----------------------------------------------------------------------------
 	static bool is_escapee(char c)
 	{
@@ -402,13 +417,7 @@ namespace json
 			{
 				array::push_back(array, ch);
 
-				ch = skip_array(ch);
-				ch = skip_object(ch);
-				ch = skip_number(ch);
-				ch = skip_string(ch);
-				ch = skip_bool(ch);
-				ch = skip_null(ch);
-
+				ch = skip_value(ch);
 				ch = skip_whites(ch);
 
 				// Closing bracket (top-most array)
@@ -453,28 +462,14 @@ namespace json
 				DynamicString key;
 				parse_string(ch, key);
 
-				// Skip any value
-				ch = skip_array(ch);
-				ch = skip_object(ch);
-				ch = skip_number(ch);
 				ch = skip_string(ch);
-				ch = skip_bool(ch);
-				ch = skip_null(ch);
-
 				ch = skip_whites(ch);
 				ch = next(ch, ':');
 				ch = skip_whites(ch);
 
 				map::set(object, key, ch);
 
-				// Skip any value
-				ch = skip_array(ch);
-				ch = skip_object(ch);
-				ch = skip_number(ch);
-				ch = skip_string(ch);
-				ch = skip_bool(ch);
-				ch = skip_null(ch);
-
+				ch = skip_value(ch);
 				ch = skip_whites(ch);
 
 				if ((*ch) == '}')

+ 30 - 6
engine/core/json/JSONParser.cpp

@@ -30,6 +30,8 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "StringUtils.h"
 #include "Vector.h"
 #include "Map.h"
+#include "Vector3.h"
+#include "Quaternion.h"
 
 namespace crown
 {
@@ -139,22 +141,19 @@ bool JSONElement::has_key(const char* k) const
 //--------------------------------------------------------------------------
 bool JSONElement::to_bool() const
 {
-	const bool value = json::parse_bool(m_at);
-	return value;
+	return json::parse_bool(m_at);
 }
 
 //--------------------------------------------------------------------------
 int32_t JSONElement::to_int() const
 {
-	const int32_t value = json::parse_int(m_at);
-	return value;
+	return json::parse_int(m_at);
 }
 
 //--------------------------------------------------------------------------
 float JSONElement::to_float() const
 {
-	const float value = json::parse_float(m_at);
-	return value;
+	return json::parse_float(m_at);
 }
 
 //--------------------------------------------------------------------------
@@ -163,6 +162,31 @@ void JSONElement::to_string(DynamicString& str) const
 	json::parse_string(m_at, str);
 }
 
+//--------------------------------------------------------------------------
+Vector3 JSONElement::to_vector3() const
+{
+	TempAllocator64 alloc;
+	Array<const char*> array(alloc);
+	json::parse_array(m_at, array);
+
+	return Vector3(json::parse_float(array[0]),
+					json::parse_float(array[1]),
+					json::parse_float(array[2]));
+}
+
+//--------------------------------------------------------------------------
+Quaternion JSONElement::to_quaternion() const
+{
+	TempAllocator64 alloc;
+	Array<const char*> array(alloc);
+	json::parse_array(m_at, array);
+
+	return Quaternion(json::parse_float(array[0]),
+					json::parse_float(array[1]),
+					json::parse_float(array[2]),
+					json::parse_float(array[3]));
+}
+
 //--------------------------------------------------------------------------
 StringId32 JSONElement::to_string_id() const
 {

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

@@ -28,6 +28,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 #include "Types.h"
 #include "ContainerTypes.h"
+#include "MathTypes.h"
 #include "Macros.h"
 
 namespace crown
@@ -116,6 +117,14 @@ public:
 	/// Returns the string value of the element.
 	void				to_string(DynamicString& str) const;
 
+	/// Rerutns the Vector3 value of the element.
+	/// @note Vector3 = [x, y, z]
+	Vector3				to_vector3() const;
+
+	/// Returns the Quaternion value of the element.
+	/// @note Quaternion = [x, y, z, w]
+	Quaternion			to_quaternion() const;
+
 	/// Returns the string id value hashed to string::murmur2_32() of the element.
 	StringId32			to_string_id() const;
 

+ 303 - 342
engine/core/math/Color4.h

@@ -32,359 +32,362 @@ OTHER DEALINGS IN THE SOFTWARE.
 namespace crown
 {
 
-/// RGBA color.
-/// 
-/// Maintains 3 float values each representing a primary
-/// color intensity. An extra component is used as transparency
-/// coefficient. Each component ranges from 0.0 to 1.0; the higher
-/// the value the brighter the color. An alpha value of 0.0 means
-/// totally transparent while a value of 1.0 means totally opaque.
-/// 
-/// It also offers a set of color name constants compliant with SVG 1.0.
+/// Holds RGBA color as four floats.
+///
+/// @ingroup Math
 struct Color4
 {
-public:
+	Color4();
+	Color4(float r, float g, float b);		
+	Color4(int r, int g, int b);
+	Color4(float r, float g, float b, float a);
+	Color4(int r, int g, int b, int a);		
+	explicit Color4(float c[4]);
 
-	float					r, g, b, a;
+	/// Construct from 32-bit integer (red at MSB, alpha at LSB)
+	explicit Color4(uint32_t rgba);
 
-public:
+	float& operator[](uint32_t i);				
+	const float& operator[](uint32_t i) const;
 
-	/// Does nothing for efficiency
-							Color4();					
-							~Color4();								
-							Color4(const Color4& c);				
-							Color4(float r, float g, float b);		
-							Color4(int r, int g, int b);			
-							Color4(float r, float g, float b, float a);
-							Color4(int r, int g, int b, int a);		
-	explicit				Color4(float c[4]);	
-
-	/// Construct from 32-bit integer (red at MSB, alpha at LSB)					
-	explicit				Color4(uint32_t rgba);
-
-	/// Returns the color as a packed 32-bit integer. (RGBA order, alpha assumed = 255)
-	uint32_t				to_rgb() const;		
-
-	/// Returns the color as a packed 32-bit integer. (ABGR order, alpha assumed = 255)
-	uint32_t				to_bgr() const;	
-
-	/// Returns the color as a packed 32-bit integer. (RGBA order)	
-	uint32_t				to_rgba() const;	
-
-	/// Returns the color as a packed 32-bit integer. (ABGR order)
-	uint32_t				to_abgr() const;	
-
-	/// Random access by index. (red = 0, alpha = 3)
-	float					operator[](uint32_t i) const;		
-
-	/// Random access by index. (red = 0, alpha = 3)		
-	float&					operator[](uint32_t i);				
-
-	Color4					operator+(const Color4& c) const;
-	Color4&					operator+=(const Color4& c);		
-	Color4					operator-(const Color4& c) const;		
-	Color4&					operator-=(const Color4& c);		
-	Color4					operator*(const Color4& c) const;		
-	Color4&					operator*=(const Color4& c);		
-	Color4					operator*(float scalar) const;				
-	Color4&					operator*=(float scalar);				
-
-	bool					operator==(const Color4& other) const;
-	bool					operator!=(const Color4& other) const;	
-
-	/// Returns the pointer to the color's data.
-	float*					to_float_ptr();		
-
-	/// Returns the pointer to the color's data.						
-	const float*			to_float_ptr() const;
+	Color4& operator+=(const Color4& c);
+	Color4& operator-=(const Color4& c);
+	Color4& operator*=(const Color4& c);
+	Color4& operator*=(float k);
 
 	// SVG 1.0 color names
-	static const Color4		ALICEBLUE;
-	static const Color4		ANTIQUEWHITE;
-	static const Color4		AQUA;
-	static const Color4		AQUAMARINE;
-	static const Color4		AZURE;
-	static const Color4		BEIGE;
-	static const Color4		BISQUE;
-	static const Color4		BLACK;
-	static const Color4		BLANCHEDALMOND;
-	static const Color4		BLUE;
-	static const Color4		BLUEVIOLET;
-	static const Color4		BROWN;
-	static const Color4		BURLYWOOD;
-	static const Color4		CADETBLUE;
-	static const Color4		CHARTREUSE;
-	static const Color4		CHOCOLATE;
-	static const Color4		CORAL;
-	static const Color4		CORNFLOWERBLUE;
-	static const Color4		CORNSILK;
-	static const Color4		CRIMSON;
-	static const Color4		CYAN;
-	static const Color4		DARKBLUE;
-	static const Color4		DARKCYAN;
-	static const Color4		DARKGOLDENROD;
-	static const Color4		DARKGRAY;
-	static const Color4		DARKGREEN;
-	static const Color4		DARKGREY;
-	static const Color4		DARKKHAKI;
-	static const Color4		DARKMAGENTA;
-	static const Color4		DARKOLIVEGREEN;
-	static const Color4		DARKORANGE;
-	static const Color4		DARKORCHID;
-	static const Color4		DARKRED;
-	static const Color4		DARKSALMON;
-	static const Color4		DARKSEAGREEN;
-	static const Color4		DARKSLATEBLUE;
-	static const Color4		DARKSLATEGRAY;
-	static const Color4		DARKSLATEGREY;
-	static const Color4		DARKTURQUOISE;
-	static const Color4		DARKVIOLET;
-	static const Color4		DEEPPINK;
-	static const Color4		DEEPSKYBLUE;
-	static const Color4		DIMGRAY;
-	static const Color4		DIMGREY;
-	static const Color4		DODGERBLUE;
-	static const Color4		FIREBRICK;
-	static const Color4		FLORALWHITE;
-	static const Color4		FORESTGREEN;
-	static const Color4		FUCHSIA;
-	static const Color4		GAINSBORO;
-	static const Color4		GHOSTWHITE;
-	static const Color4		GOLD;
-	static const Color4		GOLDENROD;
-	static const Color4		GRAY;
-	static const Color4		GREEN;
-	static const Color4		GREENYELLOW;
-	static const Color4		GREY;
-	static const Color4		HONEYDEW;
-	static const Color4		HOTPINK;
-	static const Color4		INDIANRED;
-	static const Color4		INDIGO;
-	static const Color4		IVORY;
-	static const Color4		KHAKI;
-	static const Color4		LAVENDER;
-	static const Color4		LAVENDERBLUSH;
-	static const Color4		LAWNGREEN;
-	static const Color4		LEMONCHIFFON;
-	static const Color4		LIGHTBLUE;
-	static const Color4		LIGHTCORAL;
-	static const Color4		LIGHTCYAN;
-	static const Color4		LIGHTGOLDENRODYELLOW;
-	static const Color4		LIGHTGRAY;
-	static const Color4		LIGHTGREEN;
-	static const Color4		LIGHTGREY;
-	static const Color4		LIGHTPINK;
-	static const Color4		LIGHTSALMON;
-	static const Color4		LIGHTSEAGREEN;
-	static const Color4		LIGHTSKYBLUE;
-	static const Color4		LIGHTSLATEGRAY;
-	static const Color4		LIGHTSLATEGREY;
-	static const Color4		LIGHTSTEELBLUE;
-	static const Color4		LIGHTYELLOW;
-	static const Color4		LIME;
-	static const Color4		LIMEGREEN;
-	static const Color4		LINEN;
-	static const Color4		MAGENTA;
-	static const Color4		MAROON;
-	static const Color4		MEDIUMAQUAMARINE;
-	static const Color4		MEDIUMBLUE;
-	static const Color4		MEDIUMORCHID;
-	static const Color4		MEDIUMPURPLE;
-	static const Color4		MEDIUMSEAGREEN;
-	static const Color4		MEDIUMSLATEBLUE;
-	static const Color4		MEDIUMSPRINGGREEN;
-	static const Color4		MEDIUMTURQUOISE;
-	static const Color4		MEDIUMVIOLETRED;
-	static const Color4		MIDNIGHTBLUE;
-	static const Color4		MINTCREAM;
-	static const Color4		MISTYROSE;
-	static const Color4		MOCCASIN;
-	static const Color4		NAVAJOWHITE;
-	static const Color4		NAVY;
-	static const Color4		OLDLACE;
-	static const Color4		OLIVE;
-	static const Color4		OLIVEDRAB;
-	static const Color4		ORANGE;
-	static const Color4		ORANGERED;
-	static const Color4		ORCHID;
-	static const Color4		PALEGOLDENROD;
-	static const Color4		PALEGREEN;
-	static const Color4		PALETURQUOISE;
-	static const Color4		PALEVIOLETRED;
-	static const Color4		PAPAYAWHIP;
-	static const Color4		PEACHPUFF;
-	static const Color4		PERU;
-	static const Color4		PINK;
-	static const Color4		PLUM;
-	static const Color4		POWDERBLUE;
-	static const Color4		PURPLE;
-	static const Color4		RED;
-	static const Color4		ROSYBROWN;
-	static const Color4		ROYALBLUE;
-	static const Color4		SADDLEBROWN;
-	static const Color4		SALMON;
-	static const Color4		SANDYBROWN;
-	static const Color4		SEAGREEN;
-	static const Color4		SEASHELL;
-	static const Color4		SIENNA;
-	static const Color4		SILVER;
-	static const Color4		SKYBLUE;
-	static const Color4		SLATEBLUE;
-	static const Color4		SLATEGRAY;
-	static const Color4		SLATEGREY;
-	static const Color4		SNOW;
-	static const Color4		SPRINGGREEN;
-	static const Color4		STEELBLUE;
-	static const Color4		TAN;
-	static const Color4		TEAL;
-	static const Color4		THISTLE;
-	static const Color4		TOMATO;
-	static const Color4		TURQUOISE;
-	static const Color4		VIOLET;
-	static const Color4		WHEAT;
-	static const Color4		WHITE;
-	static const Color4		WHITESMOKE;
-	static const Color4		YELLOW;
-	static const Color4		YELLOWGREEN;
+	static const Color4 ALICEBLUE;
+	static const Color4 ANTIQUEWHITE;
+	static const Color4 AQUA;
+	static const Color4 AQUAMARINE;
+	static const Color4 AZURE;
+	static const Color4 BEIGE;
+	static const Color4 BISQUE;
+	static const Color4 BLACK;
+	static const Color4 BLANCHEDALMOND;
+	static const Color4 BLUE;
+	static const Color4 BLUEVIOLET;
+	static const Color4 BROWN;
+	static const Color4 BURLYWOOD;
+	static const Color4 CADETBLUE;
+	static const Color4 CHARTREUSE;
+	static const Color4 CHOCOLATE;
+	static const Color4 CORAL;
+	static const Color4 CORNFLOWERBLUE;
+	static const Color4 CORNSILK;
+	static const Color4 CRIMSON;
+	static const Color4 CYAN;
+	static const Color4 DARKBLUE;
+	static const Color4 DARKCYAN;
+	static const Color4 DARKGOLDENROD;
+	static const Color4 DARKGRAY;
+	static const Color4 DARKGREEN;
+	static const Color4 DARKGREY;
+	static const Color4 DARKKHAKI;
+	static const Color4 DARKMAGENTA;
+	static const Color4 DARKOLIVEGREEN;
+	static const Color4 DARKORANGE;
+	static const Color4 DARKORCHID;
+	static const Color4 DARKRED;
+	static const Color4 DARKSALMON;
+	static const Color4 DARKSEAGREEN;
+	static const Color4 DARKSLATEBLUE;
+	static const Color4 DARKSLATEGRAY;
+	static const Color4 DARKSLATEGREY;
+	static const Color4 DARKTURQUOISE;
+	static const Color4 DARKVIOLET;
+	static const Color4 DEEPPINK;
+	static const Color4 DEEPSKYBLUE;
+	static const Color4 DIMGRAY;
+	static const Color4 DIMGREY;
+	static const Color4 DODGERBLUE;
+	static const Color4 FIREBRICK;
+	static const Color4 FLORALWHITE;
+	static const Color4 FORESTGREEN;
+	static const Color4 FUCHSIA;
+	static const Color4 GAINSBORO;
+	static const Color4 GHOSTWHITE;
+	static const Color4 GOLD;
+	static const Color4 GOLDENROD;
+	static const Color4 GRAY;
+	static const Color4 GREEN;
+	static const Color4 GREENYELLOW;
+	static const Color4 GREY;
+	static const Color4 HONEYDEW;
+	static const Color4 HOTPINK;
+	static const Color4 INDIANRED;
+	static const Color4 INDIGO;
+	static const Color4 IVORY;
+	static const Color4 KHAKI;
+	static const Color4 LAVENDER;
+	static const Color4 LAVENDERBLUSH;
+	static const Color4 LAWNGREEN;
+	static const Color4 LEMONCHIFFON;
+	static const Color4 LIGHTBLUE;
+	static const Color4 LIGHTCORAL;
+	static const Color4 LIGHTCYAN;
+	static const Color4 LIGHTGOLDENRODYELLOW;
+	static const Color4 LIGHTGRAY;
+	static const Color4 LIGHTGREEN;
+	static const Color4 LIGHTGREY;
+	static const Color4 LIGHTPINK;
+	static const Color4 LIGHTSALMON;
+	static const Color4 LIGHTSEAGREEN;
+	static const Color4 LIGHTSKYBLUE;
+	static const Color4 LIGHTSLATEGRAY;
+	static const Color4 LIGHTSLATEGREY;
+	static const Color4 LIGHTSTEELBLUE;
+	static const Color4 LIGHTYELLOW;
+	static const Color4 LIME;
+	static const Color4 LIMEGREEN;
+	static const Color4 LINEN;
+	static const Color4 MAGENTA;
+	static const Color4 MAROON;
+	static const Color4 MEDIUMAQUAMARINE;
+	static const Color4 MEDIUMBLUE;
+	static const Color4 MEDIUMORCHID;
+	static const Color4 MEDIUMPURPLE;
+	static const Color4 MEDIUMSEAGREEN;
+	static const Color4 MEDIUMSLATEBLUE;
+	static const Color4 MEDIUMSPRINGGREEN;
+	static const Color4 MEDIUMTURQUOISE;
+	static const Color4 MEDIUMVIOLETRED;
+	static const Color4 MIDNIGHTBLUE;
+	static const Color4 MINTCREAM;
+	static const Color4 MISTYROSE;
+	static const Color4 MOCCASIN;
+	static const Color4 NAVAJOWHITE;
+	static const Color4 NAVY;
+	static const Color4 OLDLACE;
+	static const Color4 OLIVE;
+	static const Color4 OLIVEDRAB;
+	static const Color4 ORANGE;
+	static const Color4 ORANGERED;
+	static const Color4 ORCHID;
+	static const Color4 PALEGOLDENROD;
+	static const Color4 PALEGREEN;
+	static const Color4 PALETURQUOISE;
+	static const Color4 PALEVIOLETRED;
+	static const Color4 PAPAYAWHIP;
+	static const Color4 PEACHPUFF;
+	static const Color4 PERU;
+	static const Color4 PINK;
+	static const Color4 PLUM;
+	static const Color4 POWDERBLUE;
+	static const Color4 PURPLE;
+	static const Color4 RED;
+	static const Color4 ROSYBROWN;
+	static const Color4 ROYALBLUE;
+	static const Color4 SADDLEBROWN;
+	static const Color4 SALMON;
+	static const Color4 SANDYBROWN;
+	static const Color4 SEAGREEN;
+	static const Color4 SEASHELL;
+	static const Color4 SIENNA;
+	static const Color4 SILVER;
+	static const Color4 SKYBLUE;
+	static const Color4 SLATEBLUE;
+	static const Color4 SLATEGRAY;
+	static const Color4 SLATEGREY;
+	static const Color4 SNOW;
+	static const Color4 SPRINGGREEN;
+	static const Color4 STEELBLUE;
+	static const Color4 TAN;
+	static const Color4 TEAL;
+	static const Color4 THISTLE;
+	static const Color4 TOMATO;
+	static const Color4 TURQUOISE;
+	static const Color4 VIOLET;
+	static const Color4 WHEAT;
+	static const Color4 WHITE;
+	static const Color4 WHITESMOKE;
+	static const Color4 YELLOW;
+	static const Color4 YELLOWGREEN;
+
+	float r, g, b, a;
 };
 
 //-----------------------------------------------------------------------------
-inline Color4::Color4()
+inline Color4 operator+(Color4 a, const Color4& b)
 {
+	a += b;
+	return a;
 }
 
 //-----------------------------------------------------------------------------
-inline Color4::~Color4()
+inline Color4 operator-(Color4 a, const Color4& b)
 {
+	a -= b;
+	return a;
 }
 
 //-----------------------------------------------------------------------------
-inline Color4::Color4(const Color4& c) : r(c.r), g(c.g), b(c.b), a(c.a)
+inline Color4 operator*(Color4 a, const Color4& b)
 {
+	a *= b;
+	return a;
 }
 
 //-----------------------------------------------------------------------------
-inline Color4::Color4(float r, float g, float b)
+inline Color4 operator*(Color4 a, float k)
 {
-	this->r = r;
-	this->g = g;
-	this->b = b;
-	this->a = 1.0f;
+	a *= k;
+	return a;
 }
 
 //-----------------------------------------------------------------------------
-inline Color4::Color4(int r, int g, int b)
+inline Color4 operator*(float k, Color4 a)
 {
-	this->r = r * math::ONE_OVER_255;
-	this->g = g * math::ONE_OVER_255;
-	this->b = b * math::ONE_OVER_255;
-	this->a = 1.0f;
+	a *= k;
+	return a;
 }
 
-//-----------------------------------------------------------------------------
-inline Color4::Color4(float r, float g, float b, float a)
+/// Functions to mamipulate Color4
+///
+/// @ingroup Math 
+namespace color4
 {
-	this->r = r;
-	this->g = g;
-	this->b = b;
-	this->a = a;
-}
+	/// Returns the color as a packed 32-bit integer. (RGBA order, alpha assumed = 255)
+	uint32_t to_rgb(const Color4& c);
 
-//-----------------------------------------------------------------------------
-inline Color4::Color4(int r, int g, int b, int a)
-{
-	this->r = r * math::ONE_OVER_255;
-	this->g = g * math::ONE_OVER_255;
-	this->b = b * math::ONE_OVER_255;
-	this->a = a * math::ONE_OVER_255;
-}
+	/// Returns the color as a packed 32-bit integer. (ABGR order, alpha assumed = 255)
+	uint32_t to_bgr(const Color4& c);
 
-//-----------------------------------------------------------------------------
-inline Color4::Color4(float c[4])
-{
-	r = c[0];
-	g = c[1];
-	b = c[2];
-	a = c[3];
-}
+	/// Returns the color as a packed 32-bit integer. (RGBA order)	
+	uint32_t to_rgba(const Color4& c);
 
-//-----------------------------------------------------------------------------
-inline Color4::Color4(uint32_t rgba)
+	/// Returns the color as a packed 32-bit integer. (ABGR order)
+	uint32_t to_abgr(const Color4& c);
+
+	/// Returns the pointer to the color's data.
+	float* to_float_ptr(Color4& c);
+
+	/// Returns the pointer to the color's data.						
+	const float* to_float_ptr(const Color4& c);
+} // namespace color4
+
+namespace color4
 {
-	r = math::ONE_OVER_255 * ((rgba & 0xFF000000) >> 24);
-	g = math::ONE_OVER_255 * ((rgba & 0x00FF0000) >> 16);
-	b = math::ONE_OVER_255 * ((rgba & 0x0000FF00) >> 8);
-	a = math::ONE_OVER_255 * (rgba & 0x000000FF);
-}
+	//-----------------------------------------------------------------------------
+	inline uint32_t to_rgb(const Color4& c)
+	{
+		uint32_t rgba;
+
+		rgba =	(uint32_t)(255.0f * c.r) << 24;
+		rgba |= (uint32_t)(255.0f * c.g) << 16;
+		rgba |= (uint32_t)(255.0f * c.b) << 8;
+		rgba |= 255;
+
+		return rgba;
+	}
+
+	//-----------------------------------------------------------------------------
+	inline uint32_t to_bgr(const Color4& c)
+	{
+		uint32_t abgr;
+
+		abgr =	255 << 24;
+		abgr |= (uint32_t)(255.0f * c.b) << 16;
+		abgr |= (uint32_t)(255.0f * c.g) << 8;
+		abgr |= (uint32_t)(255.0f * c.r);
+
+		return abgr;
+	}
+
+	//-----------------------------------------------------------------------------
+	inline uint32_t to_rgba(const Color4& c)
+	{
+		uint32_t rgba;
+
+		rgba =	(uint32_t)(255.0f * c.r) << 24;
+		rgba |= (uint32_t)(255.0f * c.g) << 16;
+		rgba |= (uint32_t)(255.0f * c.b) << 8;
+		rgba |= (uint32_t)(255.0f * c.a);
+
+		return rgba;
+	}
+
+	//-----------------------------------------------------------------------------
+	inline uint32_t to_abgr(const Color4& c)
+	{
+		uint32_t abgr;
+
+		abgr =	(uint32_t)(255.0f * c.a) << 24;
+		abgr |= (uint32_t)(255.0f * c.b) << 16;
+		abgr |= (uint32_t)(255.0f * c.g) << 8;
+		abgr |= (uint32_t)(255.0f * c.r);
+
+		return abgr;
+	}
+
+	//-----------------------------------------------------------------------------
+	inline float* to_float_ptr(Color4& c)
+	{
+		return &c.r;
+	}
+
+	//-----------------------------------------------------------------------------
+	inline const float* to_float_ptr(const Color4& c)
+	{
+		return &c.r;
+	}
+} // namespace color4
 
 //-----------------------------------------------------------------------------
-inline float* Color4::to_float_ptr()
+inline Color4::Color4()
 {
-	return &r;
+	// Do not initialize
 }
 
 //-----------------------------------------------------------------------------
-inline const float* Color4::to_float_ptr() const
+inline Color4::Color4(float r, float g, float b)
+	: r(r), g(g), b(b), a(1)
 {
-	return &r;
 }
 
 //-----------------------------------------------------------------------------
-inline uint32_t Color4::to_rgb() const
+inline Color4::Color4(int r, int g, int b)
+	: r(r * math::ONE_OVER_255)
+	, g(g * math::ONE_OVER_255)
+	, b(b * math::ONE_OVER_255)
+	, a(1)
 {
-	uint32_t rgba;
-
-	rgba =	(uint32_t)(255.0f * r) << 24;
-	rgba |= (uint32_t)(255.0f * g) << 16;
-	rgba |= (uint32_t)(255.0f * b) << 8;
-	rgba |= 255;
-
-	return rgba;
 }
 
 //-----------------------------------------------------------------------------
-inline uint32_t Color4::to_bgr() const
+inline Color4::Color4(float r, float g, float b, float a)
 {
-	uint32_t abgr;
-
-	abgr =	255 << 24;
-	abgr |= (uint32_t)(255.0f * b) << 16;
-	abgr |= (uint32_t)(255.0f * g) << 8;
-	abgr |= (uint32_t)(255.0f * r);
-
-	return abgr;
+	this->r = r;
+	this->g = g;
+	this->b = b;
+	this->a = a;
 }
 
 //-----------------------------------------------------------------------------
-inline uint32_t Color4::to_rgba() const
+inline Color4::Color4(int r, int g, int b, int a)
+	: r(r * math::ONE_OVER_255)
+	, g(g * math::ONE_OVER_255)
+	, b(b * math::ONE_OVER_255)
+	, a(a * math::ONE_OVER_255)
 {
-	uint32_t rgba;
-
-	rgba =	(uint32_t)(255.0f * r) << 24;
-	rgba |= (uint32_t)(255.0f * g) << 16;
-	rgba |= (uint32_t)(255.0f * b) << 8;
-	rgba |= (uint32_t)(255.0f * a);
-
-	return rgba;
 }
 
 //-----------------------------------------------------------------------------
-inline uint32_t Color4::to_abgr() const
+inline Color4::Color4(float c[4])
+	: r(c[0])
+	, g(c[1])
+	, b(c[2])
+	, a(c[3])
 {
-	uint32_t abgr;
-
-	abgr =	(uint32_t)(255.0f * a) << 24;
-	abgr |= (uint32_t)(255.0f * b) << 16;
-	abgr |= (uint32_t)(255.0f * g) << 8;
-	abgr |= (uint32_t)(255.0f * r);
-
-	return abgr;
 }
 
 //-----------------------------------------------------------------------------
-inline float Color4::operator[](uint32_t i) const
+inline Color4::Color4(uint32_t rgba)
+	: r(math::ONE_OVER_255 * ((rgba & 0xFF000000) >> 24))
+	, g(math::ONE_OVER_255 * ((rgba & 0x00FF0000) >> 16))
+	, b(math::ONE_OVER_255 * ((rgba & 0x0000FF00) >> 8))
+	, a(math::ONE_OVER_255 * (rgba & 0x000000FF))
 {
-	return (&r)[i];
 }
 
 //-----------------------------------------------------------------------------
@@ -394,9 +397,9 @@ inline float& Color4::operator[](uint32_t i)
 }
 
 //-----------------------------------------------------------------------------
-inline Color4 Color4::operator+(const Color4& c) const
+inline const float& Color4::operator[](uint32_t i) const
 {
-	return Color4(r + c.r, g + c.g, b + c.b, a + c.a);
+	return (&r)[i];
 }
 
 //-----------------------------------------------------------------------------
@@ -410,34 +413,17 @@ inline Color4& Color4::operator+=(const Color4& c)
 	return *this;
 }
 
-//-----------------------------------------------------------------------------
-inline Color4 Color4::operator-(const Color4& c) const
-{
-	Color4 tmp;
-
-	tmp.r = r - c.r;
-	tmp.g = g - c.g;
-	tmp.b = b - c.b;
-
-	return tmp;
-}
-
 //-----------------------------------------------------------------------------
 inline Color4& Color4::operator-=(const Color4& c)
 {
 	r -= c.r;
 	g -= c.g;
 	b -= c.b;
+	a -= c.a;
 
 	return *this;
 }
 
-//-----------------------------------------------------------------------------
-inline Color4 Color4::operator*(const Color4& c) const
-{
-	return Color4(r * c.r, g * c.g, b * c.b, a * c.a);
-}
-
 //-----------------------------------------------------------------------------
 inline Color4& Color4::operator*=(const Color4& c)
 {
@@ -450,39 +436,14 @@ inline Color4& Color4::operator*=(const Color4& c)
 }
 
 //-----------------------------------------------------------------------------
-inline Color4 Color4::operator*(float scalar) const
-{
-	return Color4(r * scalar, g * scalar, b * scalar, a * scalar);
-}
-
-//-----------------------------------------------------------------------------
-inline Color4& Color4::operator*=(float scalar)
+inline Color4& Color4::operator*=(float k)
 {
-	r *= scalar;
-	g *= scalar;
-	b *= scalar;
-	a *= scalar;
+	r *= k;
+	g *= k;
+	b *= k;
+	a *= k;
 
 	return *this;
 }
 
-//-----------------------------------------------------------------------------
-inline bool Color4::operator==(const Color4& other) const
-{
-	return (r == other.r && g == other.g && b == other.b && a == other.a);
-}
-
-//-----------------------------------------------------------------------------
-inline bool Color4::operator!=(const Color4& other) const
-{
-	return (r != other.r || g != other.g || b != other.b || a != other.a);
-}
-
-//-----------------------------------------------------------------------------
-inline Color4 operator*(float scalar, const Color4& color)
-{
-	return Color4(color.r * scalar, color.g * scalar, color.b * scalar, color.a * scalar);
-}
-
 } // namespace crown
-

+ 30 - 40
engine/core/math/Frustum.h

@@ -114,35 +114,35 @@ namespace frustum
 	//-----------------------------------------------------------------------------
 	inline void from_matrix(Frustum& f, const Matrix4x4& m)
 	{
-		f.left.n.x		= m.m[3] + m.m[0];
-		f.left.n.y		= m.m[7] + m.m[4];
-		f.left.n.z		= m.m[11] + m.m[8];
-		f.left.d		= m.m[15] + m.m[12];
-
-		f.right.n.x		= m.m[3] - m.m[0];
-		f.right.n.y		= m.m[7] - m.m[4];
-		f.right.n.z		= m.m[11] - m.m[8];
-		f.right.d		= m.m[15] - m.m[12];
-
-		f.bottom.n.x	= m.m[3] + m.m[1];
-		f.bottom.n.y	= m.m[7] + m.m[5];
-		f.bottom.n.z	= m.m[11] + m.m[9];
-		f.bottom.d		= m.m[15] + m.m[13];
-
-		f.top.n.x		= m.m[3] - m.m[1];
-		f.top.n.y		= m.m[7] - m.m[5];
-		f.top.n.z		= m.m[11] - m.m[9];
-		f.top.d			= m.m[15] - m.m[13];
-
-		f.near.n.x		= m.m[3] + m.m[2];
-		f.near.n.y		= m.m[7] + m.m[6];
-		f.near.n.z		= m.m[11] + m.m[10];
-		f.near.d		= m.m[15] + m.m[14];
-
-		f.far.n.x		= m.m[3] - m.m[2];
-		f.far.n.y		= m.m[7] - m.m[6];
-		f.far.n.z		= m.m[11] - m.m[10];
-		f.far.d			= m.m[15] - m.m[14];
+		f.left.n.x		= m[3] + m[0];
+		f.left.n.y		= m[7] + m[4];
+		f.left.n.z		= m[11] + m[8];
+		f.left.d		= m[15] + m[12];
+
+		f.right.n.x		= m[3] - m[0];
+		f.right.n.y		= m[7] - m[4];
+		f.right.n.z		= m[11] - m[8];
+		f.right.d		= m[15] - m[12];
+
+		f.bottom.n.x	= m[3] + m[1];
+		f.bottom.n.y	= m[7] + m[5];
+		f.bottom.n.z	= m[11] + m[9];
+		f.bottom.d		= m[15] + m[13];
+
+		f.top.n.x		= m[3] - m[1];
+		f.top.n.y		= m[7] - m[5];
+		f.top.n.z		= m[11] - m[9];
+		f.top.d			= m[15] - m[13];
+
+		f.near.n.x		= m[3] + m[2];
+		f.near.n.y		= m[7] + m[6];
+		f.near.n.z		= m[11] + m[10];
+		f.near.d		= m[15] + m[14];
+
+		f.far.n.x		= m[3] - m[2];
+		f.far.n.y		= m[7] - m[6];
+		f.far.n.z		= m[11] - m[10];
+		f.far.d			= m[15] - m[14];
 
 		plane::normalize(f.left);
 		plane::normalize(f.right);
@@ -177,17 +177,7 @@ namespace frustum
 //-----------------------------------------------------------------------------
 inline Frustum::Frustum()
 {
-}
-
-//-----------------------------------------------------------------------------
-inline Frustum::Frustum(const Frustum& f)
-{
-	left	= f.left;
-	right	= f.right;
-	bottom	= f.bottom;
-	top		= f.top;
-	near	= f.near;
-	far		= f.far;
+	// Do not initialize
 }
 
 } // namespace crown

+ 60 - 8
engine/core/math/MathTypes.h

@@ -26,6 +26,8 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 #pragma once
 
+#include "Types.h"
+
 namespace crown
 {
 
@@ -38,10 +40,9 @@ struct Vector2
 	Vector2(float val);
 	Vector2(float nx, float ny);
 	Vector2(const float v[2]);
-	Vector2(const Vector2& a);
 
-	float operator[](uint32_t i) const;
 	float& operator[](uint32_t i);
+	const float& operator[](uint32_t i) const;
 
 	Vector2& operator+=(const Vector2& a);
 	Vector2& operator-=(const Vector2& a);
@@ -58,10 +59,9 @@ struct Vector3
 	Vector3(float val);
 	Vector3(float nx, float ny, float nz);
 	Vector3(const float v[3]);
-	Vector3(const Vector3& a);
 
-	float operator[](uint32_t i) const;
 	float& operator[](uint32_t i);
+	const float& operator[](uint32_t i) const;
 
 	Vector3& operator+=(const Vector3& a);
 	Vector3& operator-=(const Vector3& a);
@@ -75,13 +75,13 @@ struct Vector3
 struct Vector4
 {
 	Vector4();
+	Vector4(const Vector3& a, float w);
 	Vector4(float val);
 	Vector4(float nx, float ny, float nz, float nw);
 	Vector4(const float v[3]);
-	Vector4(const Vector4& a);
 
-	float operator[](uint32_t i) const;
 	float& operator[](uint32_t i);
+	const float& operator[](uint32_t i) const;
 
 	Vector4& operator+=(const Vector4& a);
 	Vector4& operator-=(const Vector4& a);
@@ -98,11 +98,65 @@ struct Quaternion
 	Quaternion(float nx, float ny, float nz, float nw);
 	Quaternion(const Vector3& axis, float angle);
 
+	float& operator[](uint32_t i);
+	const float& operator[](uint32_t i) const;
+
 	Quaternion& operator*=(const Quaternion& a);
 
 	float x, y, z, w;
 };
 
+/// @ingroup Math
+struct Matrix3x3
+{
+	Matrix3x3();
+	Matrix3x3(const Vector3& x, const Vector3& y, const Vector3& z);
+	Matrix3x3(const Quaternion& r);
+
+	Matrix3x3(float r1c1, float r2c1, float r3c1, float r1c2, float r2c2, float r3c2,
+				float r1c3, float r2c3, float r3c3);
+
+	Matrix3x3(const float v[9]);
+
+	float& operator[](uint32_t i);
+	const float& operator[](uint32_t i) const;
+
+	Matrix3x3& operator+=(const Matrix3x3& a);
+	Matrix3x3& operator-=(const Matrix3x3& a);
+	Matrix3x3& operator*=(const Matrix3x3& a);
+	Matrix3x3& operator*=(float k);
+	Matrix3x3& operator/=(float k);
+
+	Vector3 x, y, z;
+};
+
+/// @ingroup Math
+struct Matrix4x4
+{
+	Matrix4x4();
+	Matrix4x4(const Vector3& x, const Vector3& y, const Vector3& z, const Vector3& t);
+	Matrix4x4(const Quaternion& r, const Vector3& p);
+	Matrix4x4(const Matrix3x3& m);
+
+	Matrix4x4(float r1c1, float r2c1, float r3c1, float r4c1,
+				float r1c2, float r2c2, float r3c2, float r4c2,
+				float r1c3, float r2c3, float r3c3, float r4c3,
+				float r1c4, float r2c4, float r3c4, float r4c4);
+
+	Matrix4x4(const float v[16]);
+
+	float& operator[](uint32_t i);
+	const float& operator[](uint32_t i) const;
+
+	Matrix4x4& operator+=(const Matrix4x4& a);
+	Matrix4x4& operator-=(const Matrix4x4& a);
+	Matrix4x4& operator*=(const Matrix4x4& a);
+	Matrix4x4& operator*=(float k);
+	Matrix4x4& operator/=(float k);
+
+	Vector4 x, y, z, t;
+};
+
 /// @ingroup Math
 struct AABB
 {
@@ -125,7 +179,6 @@ struct Plane
 	/// Does nothing for efficiency.
 	Plane();						
 	Plane(const Vector3& n, float d);
-	Plane(const Plane& p);
 
 	Vector3 n;
 	float d;
@@ -135,7 +188,6 @@ struct Plane
 struct Frustum
 {
 	Frustum();
-	Frustum(const Frustum& f);
 
 	Plane left;
 	Plane right;

+ 0 - 650
engine/core/math/Matrix3x3.cpp

@@ -1,650 +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 "Assert.h"
-#include "Matrix3x3.h"
-#include "Types.h"
-#include "Matrix4x4.h"
-#include "MathUtils.h"
-#include "Quaternion.h"
-#include "Vector3.h"
-
-namespace crown
-{
-
-const Matrix3x3 Matrix3x3::IDENTITY = Matrix3x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0);
-
-//-----------------------------------------------------------------------------
-Matrix3x3::Matrix3x3()
-{
-}
-
-//-----------------------------------------------------------------------------
-Matrix3x3::Matrix3x3(float r1c1, float r2c1, float r3c1, float r1c2, float r2c2, float r3c2,
-	float r1c3, float r2c3, float r3c3)
-{
-	m[0] = r1c1;
-	m[1] = r2c1;
-	m[2] = r3c1;
-	m[3] = r1c2;
-	m[4] = r2c2;
-	m[5] = r3c2;
-	m[6] = r1c3;
-	m[7] = r2c3;
-	m[8] = r3c3;
-}
-
-//-----------------------------------------------------------------------------
-Matrix3x3::Matrix3x3(const float v[9])
-{
-	m[0] = v[0];
-	m[1] = v[1];
-	m[2] = v[2];
-	m[3] = v[3];
-	m[4] = v[4];
-	m[5] = v[5];
-	m[6] = v[6];
-	m[7] = v[7];
-	m[8] = v[8];
-}
-
-//-----------------------------------------------------------------------------
-Matrix3x3::Matrix3x3(const Matrix3x3& a)
-{
-	m[0] = a.m[0];
-	m[1] = a.m[1];
-	m[2] = a.m[2];
-	m[3] = a.m[3];
-	m[4] = a.m[4];
-	m[5] = a.m[5];
-	m[6] = a.m[6];
-	m[7] = a.m[7];
-	m[8] = a.m[8];
-}
-
-//-----------------------------------------------------------------------------
-Matrix3x3& Matrix3x3::operator=(const Matrix3x3& a)
-{
-	m[0] = a.m[0];
-	m[1] = a.m[1];
-	m[2] = a.m[2];
-	m[3] = a.m[3];
-	m[4] = a.m[4];
-	m[5] = a.m[5];
-	m[6] = a.m[6];
-	m[7] = a.m[7];
-	m[8] = a.m[8];
-
-	return *this;
-}
-
-//-----------------------------------------------------------------------------
-float Matrix3x3::operator[](uint32_t i) const
-{
-	CE_ASSERT(i < 9, "Index must be < 9");
-
-	return m[i];
-}
-
-//-----------------------------------------------------------------------------
-float& Matrix3x3::operator[](uint32_t i)
-{
-	CE_ASSERT(i < 9, "Index must be < 9");
-
-	return m[i];
-}
-
-//-----------------------------------------------------------------------------
-float Matrix3x3::operator()(uint32_t row, uint32_t column) const
-{
-	CE_ASSERT(row < 3 && column < 3, "Row and column must be < 3");
-
-	return m[row + column * 3];
-}
-
-//-----------------------------------------------------------------------------
-Matrix3x3 Matrix3x3::operator+(const Matrix3x3& a) const
-{
-	Matrix3x3 tmp;
-
-	tmp.m[0] = m[0] + a.m[0];
-	tmp.m[1] = m[1] + a.m[1];
-	tmp.m[2] = m[2] + a.m[2];
-	tmp.m[3] = m[3] + a.m[3];
-	tmp.m[4] = m[4] + a.m[4];
-	tmp.m[5] = m[5] + a.m[5];
-	tmp.m[6] = m[6] + a.m[6];
-	tmp.m[7] = m[7] + a.m[7];
-	tmp.m[8] = m[8] + a.m[8];
-
-	return tmp;
-}
-
-//-----------------------------------------------------------------------------
-Matrix3x3& Matrix3x3::operator+=(const Matrix3x3& a)
-{
-	m[0] = m[0] + a.m[0];
-	m[1] = m[1] + a.m[1];
-	m[2] = m[2] + a.m[2];
-	m[3] = m[3] + a.m[3];
-	m[4] = m[4] + a.m[4];
-	m[5] = m[5] + a.m[5];
-	m[6] = m[6] + a.m[6];
-	m[7] = m[7] + a.m[7];
-	m[8] = m[8] + a.m[8];
-
-	return *this;
-}
-
-//-----------------------------------------------------------------------------
-Matrix3x3 Matrix3x3::operator-(const Matrix3x3& a) const
-{
-	Matrix3x3 tmp;
-
-	tmp.m[0] = m[0] - a.m[0];
-	tmp.m[1] = m[1] - a.m[1];
-	tmp.m[2] = m[2] - a.m[2];
-	tmp.m[3] = m[3] - a.m[3];
-	tmp.m[4] = m[4] - a.m[4];
-	tmp.m[5] = m[5] - a.m[5];
-	tmp.m[6] = m[6] - a.m[6];
-	tmp.m[7] = m[7] - a.m[7];
-	tmp.m[8] = m[8] - a.m[8];
-
-	return tmp;
-}
-
-//-----------------------------------------------------------------------------
-Matrix3x3& Matrix3x3::operator-=(const Matrix3x3& a)
-{
-	m[0] = m[0] - a.m[0];
-	m[1] = m[1] - a.m[1];
-	m[2] = m[2] - a.m[2];
-	m[3] = m[3] - a.m[3];
-	m[4] = m[4] - a.m[4];
-	m[5] = m[5] - a.m[5];
-	m[6] = m[6] - a.m[6];
-	m[7] = m[7] - a.m[7];
-	m[8] = m[8] - a.m[8];
-
-	return *this;
-}
-
-//-----------------------------------------------------------------------------
-Matrix3x3 Matrix3x3::operator*(float k) const
-{
-	Matrix3x3 tmp;
-
-	tmp.m[0] = m[0] * k;
-	tmp.m[1] = m[1] * k;
-	tmp.m[2] = m[2] * k;
-	tmp.m[3] = m[3] * k;
-	tmp.m[4] = m[4] * k;
-	tmp.m[5] = m[5] * k;
-	tmp.m[6] = m[6] * k;
-	tmp.m[7] = m[7] * k;
-	tmp.m[8] = m[8] * k;
-
-	return tmp;
-}
-
-//-----------------------------------------------------------------------------
-Matrix3x3& Matrix3x3::operator*=(float k)
-{
-	m[0] *= k;
-	m[1] *= k;
-	m[2] *= k;
-	m[3] *= k;
-	m[4] *= k;
-	m[5] *= k;
-	m[6] *= k;
-	m[7] *= k;
-	m[8] *= k;
-
-	return *this;
-}
-
-//-----------------------------------------------------------------------------
-Matrix3x3 Matrix3x3::operator/(float k) const
-{
-	Matrix3x3 tmp;
-
-	k = (float)1.0 / k;
-
-	tmp.m[0] = m[0] * k;
-	tmp.m[1] = m[1] * k;
-	tmp.m[2] = m[2] * k;
-	tmp.m[3] = m[3] * k;
-	tmp.m[4] = m[4] * k;
-	tmp.m[5] = m[5] * k;
-	tmp.m[6] = m[6] * k;
-	tmp.m[7] = m[7] * k;
-	tmp.m[8] = m[8] * k;
-
-	return tmp;
-}
-
-//-----------------------------------------------------------------------------
-Matrix3x3& Matrix3x3::operator/=(float k)
-{
-	k = (float)1.0 / k;
-
-	m[0] *= k;
-	m[1] *= k;
-	m[2] *= k;
-	m[3] *= k;
-	m[4] *= k;
-	m[5] *= k;
-	m[6] *= k;
-	m[7] *= k;
-	m[8] *= k;
-
-	return *this;
-}
-
-//-----------------------------------------------------------------------------
-Vector3 Matrix3x3::operator*(const Vector3& v) const
-{
-	Vector3 tmp;
-
-	tmp.x = m[0] * v.x + m[3] * v.y + m[6] * v.z;
-	tmp.y = m[1] * v.x + m[4] * v.y + m[7] * v.z;
-	tmp.z = m[2] * v.x + m[5] * v.y + m[8] * v.z;
-
-	return tmp;
-}
-
-//-----------------------------------------------------------------------------
-Matrix3x3 Matrix3x3::operator*(const Matrix3x3& a) const
-{
-	Matrix3x3 tmp;
-
-	tmp.m[0] = m[0] * a.m[0] + m[3] * a.m[1] + m[6] * a.m[2];
-	tmp.m[1] = m[1] * a.m[0] + m[4] * a.m[1] + m[7] * a.m[2];
-	tmp.m[2] = m[2] * a.m[0] + m[5] * a.m[1] + m[8] * a.m[2];
-
-	tmp.m[3] = m[0] * a.m[3] + m[3] * a.m[4] + m[6] * a.m[5];
-	tmp.m[4] = m[1] * a.m[3] + m[4] * a.m[4] + m[7] * a.m[5];
-	tmp.m[5] = m[2] * a.m[3] + m[5] * a.m[4] + m[8] * a.m[5];
-
-	tmp.m[6] = m[0] * a.m[6] + m[3] * a.m[7] + m[6] * a.m[8];
-	tmp.m[7] = m[1] * a.m[6] + m[4] * a.m[7] + m[7] * a.m[8];
-	tmp.m[8] = m[2] * a.m[6] + m[5] * a.m[7] + m[8] * a.m[8];
-
-	return tmp;
-}
-
-//-----------------------------------------------------------------------------
-Matrix3x3& Matrix3x3::operator*=(const Matrix3x3& a)
-{
-	Matrix3x3 tmp;
-
-	tmp.m[0] = m[0] * a.m[0] + m[3] * a.m[1] + m[6] * a.m[2];
-	tmp.m[1] = m[1] * a.m[0] + m[4] * a.m[1] + m[7] * a.m[2];
-	tmp.m[2] = m[2] * a.m[0] + m[5] * a.m[1] + m[8] * a.m[2];
-
-	tmp.m[3] = m[0] * a.m[3] + m[3] * a.m[4] + m[6] * a.m[5];
-	tmp.m[4] = m[1] * a.m[3] + m[4] * a.m[4] + m[7] * a.m[5];
-	tmp.m[5] = m[2] * a.m[3] + m[5] * a.m[4] + m[8] * a.m[5];
-
-	tmp.m[6] = m[0] * a.m[6] + m[3] * a.m[7] + m[6] * a.m[8];
-	tmp.m[7] = m[1] * a.m[6] + m[4] * a.m[7] + m[7] * a.m[8];
-	tmp.m[8] = m[2] * a.m[6] + m[5] * a.m[7] + m[8] * a.m[8];
-
-	*this = tmp;
-
-	return *this;
-}
-
-//-----------------------------------------------------------------------------
-Matrix3x3 operator*(float k, const Matrix3x3& a)
-{
-	return a * k;
-}
-
-//-----------------------------------------------------------------------------
-void Matrix3x3::build_rotation_x(float radians)
-{
-	m[0] = 1.0;
-	m[1] = 0.0;
-	m[2] = 0.0;
-	m[3] = 0.0;
-	m[4] = math::cos(radians);
-	m[5] = math::sin(radians);
-	m[6] = 0.0;
-	m[7] = -math::sin(radians);
-	m[8] = math::cos(radians);
-}
-
-//-----------------------------------------------------------------------------
-void Matrix3x3::build_rotation_y(float radians)
-{
-	m[0] = math::cos(radians);
-	m[1] = 0.0;
-	m[2] = -math::sin(radians);
-	m[3] = 0.0;
-	m[4] = 1.0;
-	m[5] = 0.0;
-	m[6] = math::sin(radians);
-	m[7] = 0.0;
-	m[8] = math::cos(radians);
-}
-
-//-----------------------------------------------------------------------------
-void Matrix3x3::build_rotation_z(float radians)
-{
-	m[0] = math::cos(radians);
-	m[1] = math::sin(radians);
-	m[2] = 0.0;
-	m[3] = -math::sin(radians);
-	m[4] = math::cos(radians);
-	m[5] = 0.0;
-	m[6] = 0.0;
-	m[7] = 0.0;
-	m[8] = 1.0;
-}
-
-//-----------------------------------------------------------------------------
-void Matrix3x3::build_rotation(const Vector3& n, float radians)
-{
-	float a = (float)1.0 - math::cos(radians);
-	float sin_a = math::sin(radians);
-	float cos_a = math::cos(radians);
-
-	m[0] = n.x * n.x * a + cos_a;
-	m[1] = n.x * n.y * a + n.z * sin_a;
-	m[2] = n.x * n.z * a - n.y * sin_a;
-	m[3] = n.x * n.y * a - n.z * sin_a;
-	m[4] = n.y * n.y * a + cos_a;
-	m[5] = n.y * n.z * a + n.x * sin_a;
-	m[6] = n.x * n.z * a + n.y * sin_a;
-	m[7] = n.y * n.z * a - n.x * sin_a;
-	m[8] = n.z * n.z * a + cos_a;
-}
-
-//-----------------------------------------------------------------------------
-Matrix3x3& Matrix3x3::transpose()
-{
-	float tmp;
-
-	tmp = m[1];
-	m[1] = m[3];
-	m[3] = tmp;
-
-	tmp = m[2];
-	m[2] = m[6];
-	m[6] = tmp;
-
-	tmp = m[5];
-	m[5] = m[7];
-	m[7] = tmp;
-
-	return *this;
-}
-
-//-----------------------------------------------------------------------------
-Matrix3x3 Matrix3x3::get_transposed() const
-{
-	Matrix3x3 tmp;
-
-	tmp.m[0] = m[0];
-	tmp.m[1] = m[3];
-	tmp.m[2] = m[6];
-	tmp.m[3] = m[1];
-	tmp.m[4] = m[4];
-	tmp.m[5] = m[7];
-	tmp.m[6] = m[2];
-	tmp.m[7] = m[5];
-	tmp.m[8] = m[8];
-
-	return tmp;
-}
-
-//-----------------------------------------------------------------------------
-float Matrix3x3::get_determinant() const
-{
-	float det;
-
-	det =	m[0] * (m[4] * m[8] - m[7] * m[5]) -
-			m[3] * (m[1] * m[8] - m[7] * m[2]) +
-			m[6] * (m[1] * m[5] - m[4] * m[2]);
-
-	return det;
-}
-
-//-----------------------------------------------------------------------------
-Matrix3x3& Matrix3x3::invert()
-{
-	Matrix3x3 mat;
-	float det;
-
-	mat.m[0] = (m[4] * m[8] - m[7] * m[5]);
-	mat.m[1] = (m[1] * m[8] - m[7] * m[2]);
-	mat.m[2] = (m[1] * m[5] - m[4] * m[2]);
-
-	det = m[0] * mat.m[0] - m[3] * mat.m[1] + m[6] * mat.m[2];
-	det = (float)1.0 / det;
-
-	mat.m[3] = (m[3] * m[8] - m[6] * m[5]);
-	mat.m[4] = (m[0] * m[8] - m[6] * m[2]);
-	mat.m[5] = (m[0] * m[5] - m[3] * m[2]);
-	mat.m[6] = (m[3] * m[7] - m[6] * m[4]);
-	mat.m[7] = (m[0] * m[7] - m[6] * m[1]);
-	mat.m[8] = (m[0] * m[4] - m[3] * m[1]);
-
-	m[0] = + mat.m[0] * det;
-	m[1] = - mat.m[1] * det;
-	m[2] = + mat.m[2] * det;
-	m[3] = - mat.m[3] * det;
-	m[4] = + mat.m[4] * det;
-	m[5] = - mat.m[5] * det;
-	m[6] = + mat.m[6] * det;
-	m[7] = - mat.m[7] * det;
-	m[8] = + mat.m[8] * det;
-
-	return *this;
-}
-
-//-----------------------------------------------------------------------------
-inline Matrix3x3 Matrix3x3::get_inverted() const
-{
-	Matrix3x3 tmp(*this);
-
-	return tmp.invert();
-}
-
-//-----------------------------------------------------------------------------
-void Matrix3x3::load_identity()
-{
-	m[0] = m[4] = m[8] = 1.0;
-	m[1] = m[2] = m[3] = m[5] = m[6] = m[7] = 0.0;
-}
-
-//-----------------------------------------------------------------------------
-Vector3 Matrix3x3::x() const
-{
-	return Vector3(m[0], m[1], m[2]);
-}
-
-//-----------------------------------------------------------------------------
-Vector3 Matrix3x3::y() const
-{
-	return Vector3(m[3], m[4], m[5]);
-}
-
-//-----------------------------------------------------------------------------
-Vector3 Matrix3x3::z() const
-{
-	return Vector3(m[6], m[7], m[8]);
-}
-
-//-----------------------------------------------------------------------------
-void Matrix3x3::set_x(const Vector3& x)
-{
-	m[0] = x.x;
-	m[1] = x.y;
-	m[2] = x.z;
-}
-
-//-----------------------------------------------------------------------------
-void Matrix3x3::set_y(const Vector3& y)
-{
-	m[3] = y.x;
-	m[4] = y.y;
-	m[5] = y.z;
-}
-
-//-----------------------------------------------------------------------------
-void Matrix3x3::set_z(const Vector3& z)
-{
-	m[6] = z.x;
-	m[7] = z.y;
-	m[8] = z.z;
-}
-
-//-----------------------------------------------------------------------------
-Vector3 Matrix3x3::get_scale() const
-{
-	Vector3 tmp;
-
-	tmp.x = m[0];
-	tmp.y = m[4];
-	tmp.z = m[8];
-
-	return tmp;
-}
-
-//-----------------------------------------------------------------------------
-void Matrix3x3::set_scale(const Vector3& scale)
-{
-	m[0] = scale.x;
-	m[4] = scale.y;
-	m[8] = scale.z;
-}
-
-//-----------------------------------------------------------------------------
-float* Matrix3x3::to_float_ptr()
-{
-	return &m[0];
-}
-
-//-----------------------------------------------------------------------------
-const float* Matrix3x3::to_float_ptr() const
-{
-	return &m[0];
-}
-
-//-----------------------------------------------------------------------------
-Matrix4x4 Matrix3x3::to_matrix4x4() const
-{
-	Matrix4x4 tmp;
-
-	tmp.m[0] = m[0];
-	tmp.m[1] = m[1];
-	tmp.m[2] = m[2];
-	tmp.m[3] = 0.0;
-	tmp.m[4] = m[3];
-	tmp.m[5] = m[4];
-	tmp.m[6] = m[5];
-	tmp.m[7] = 0.0;
-	tmp.m[8] = m[6];
-	tmp.m[9] = m[7];
-	tmp.m[10] = m[8];
-	tmp.m[11] = 0.0;
-	tmp.m[12] = 0.0;
-	tmp.m[13] = 0.0;
-	tmp.m[14] = 0.0;
-	tmp.m[15] = 1.0;
-
-	return tmp;
-}
-
-//-----------------------------------------------------------------------------
-Quaternion Matrix3x3::to_quaternion() const
-{
-	Quaternion tmp;
-
-	float fourWSquaredMinusOne = m[0] + m[4] + m[8];
-	float fourXSquaredMinusOne = m[0] - m[4] - m[8];
-	float fourYSquaredMinusOne = -m[0] + m[4] - m[8];
-	float fourZSquaredMinusOne = -m[0] - m[4] + m[8];
-	float fourMaxSquaredMinusOne = fourWSquaredMinusOne;
-	uint32_t index = 0;
-
-	if (fourXSquaredMinusOne > fourMaxSquaredMinusOne)
-	{
-		fourMaxSquaredMinusOne = fourXSquaredMinusOne;
-		index = 1;
-	}
-
-	if (fourYSquaredMinusOne > fourMaxSquaredMinusOne)
-	{
-		fourMaxSquaredMinusOne = fourYSquaredMinusOne;
-		index = 2;
-	}
-
-	if (fourZSquaredMinusOne > fourMaxSquaredMinusOne)
-	{
-		fourMaxSquaredMinusOne = fourZSquaredMinusOne;
-		index = 3;
-	}
-
-	float biggest = math::sqrt(fourMaxSquaredMinusOne + (float)1.0) * (float)0.5;
-	float mult = (float)0.25 / biggest;
-
-	switch (index)
-	{
-		case 0:
-			tmp.w = biggest;
-			tmp.x = (-m[7] + m[5]) * mult;
-			tmp.y = (-m[2] + m[6]) * mult;
-			tmp.z = (-m[3] + m[1]) * mult;
-			break;
-		case 1:
-			tmp.x = biggest;
-			tmp.w = (-m[7] + m[5]) * mult;
-			tmp.y = (-m[3] - m[1]) * mult;
-			tmp.z = (-m[2] - m[6]) * mult;
-			break;
-		case 2:
-			tmp.y = biggest;
-			tmp.w = (-m[2] + m[6]) * mult;
-			tmp.x = (-m[3] - m[1]) * mult;
-			tmp.z = (-m[7] - m[5]) * mult;
-			break;
-		case 3:
-			tmp.z = biggest;
-			tmp.w = (-m[3] + m[1]) * mult;
-			tmp.x = (-m[2] - m[6]) * mult;
-			tmp.y = (-m[7] - m[5]) * mult;
-			break;
-	}
-
-	return tmp;
-}
-
-} // namespace crown
-

+ 367 - 103
engine/core/math/Matrix3x3.h

@@ -26,138 +26,402 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 #pragma once
 
-#include "Types.h"
+#include "MathTypes.h"
+#include "Vector3.h"
+#include "Assert.h"
 
 namespace crown
 {
 
-struct Matrix4x4;
-struct Quaternion;
-struct Vector3;
-
-/// Column major 3x3 matrix.
-/// 
-/// The engine uses column vectors for coordinate space transformations
-/// so you'll have to specify transformations in reverse order.
-/// e.g. (rotation translation vector) will produce the result of first translating
-/// and then rotating the vector.
-/// Also note that a column major matrix needs to be placed to the left of a
-/// vector by matrix multiplication, so, to multiply a vector by a matrix you'll have
-/// to write something like: matrix vector. Since we are also using column vectors, inverting
-/// the operands would result in an impossible operation.
-/// 
-/// @a verbatim:
-///   X base vector
-///     | Y base vector
-///     |   | Z base vector
-///     |   |   |
-/// 1 [ Xx  Yx  Zx ]
-/// 2 | Xy  Yy  Zy |
-/// 3 [ Xz  Yz  Zz ]
-///     1   2   3
-struct Matrix3x3
-{
-
-public:
-
-	float				m[9];
-
-	/// Does nothing for efficiency.
-						Matrix3x3();			
-
-	/// Constructs from a set of float
-						Matrix3x3(float r1c1, float r2c1, float r3c1, float r1c2, float r2c2, float r3c2, float r1c3, float r2c3, float r3c3);
+/// Adds the matrix @a a to @a b and returns the result.
+Matrix3x3 operator+(Matrix3x3 a, const Matrix3x3& b);
+
+/// Subtracts the matrix @a b from @a a and returns the result.
+Matrix3x3 operator-(Matrix3x3 a, const Matrix3x3& b);
+
+/// Multiplies the matrix @a a by the scalar @a k and returns the result.
+Matrix3x3 operator*(Matrix3x3 a, float k);
+
+/// @copydoc operator*(Matrix3x3, float)
+Matrix3x3 operator*(float k, Matrix3x3 a);
+
+/// Divides the matrix @a a by the scalar @a k.
+Matrix3x3 operator/(Matrix3x3 a, float k);
+
+/// Multiplies the matrix @a a by the vector @a v and returns the result.
+Vector3 operator*(const Matrix3x3& a, const Vector3& v);
+
+/// Multiplies the matrix @a a by @a b and returns the result. (i.e. transforms first by @a b then by @a a)
+Matrix3x3 operator*(Matrix3x3 a, const Matrix3x3& b);
+
+/// Functions to manipulate Matrix3x3
+///
+/// @ingroup Math
+namespace matrix3x3
+{
+	const Matrix3x3 IDENTITY = Matrix3x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0);
 	
-	/// Constructs from the @a v array
-						Matrix3x3(const float v[9]);						
-						Matrix3x3(const Matrix3x3& a);	
+	/// Transposes the matrix @a m and returns the result.
+	Matrix3x3& transpose(Matrix3x3& m);
 
-	/// Assignment operator (copies the data)
-	Matrix3x3&			operator=(const Matrix3x3& a);					
+	/// Returns the transposed of the matrix @a m.
+	Matrix3x3 get_transposed(Matrix3x3 m);
 
-	/// Random access by index
-	float				operator[](uint32_t i) const;		
+	/// Returns the determinant of the matrix @a m.
+	float determinant(const Matrix3x3& m);
 
-	/// Random access by index			
-	float&				operator[](uint32_t i);							
+	/// Inverts the matrix @a m and returns the result.
+	Matrix3x3& invert(Matrix3x3& m);
 
-	/// Random access by row/column pair
-	float				operator()(uint32_t row, uint32_t column) const;	
+	/// Returns the inverse of the matrix @a m.
+	Matrix3x3 get_inverted(Matrix3x3 m);
 
-	Matrix3x3			operator+(const Matrix3x3& a) const;				
-	Matrix3x3&			operator+=(const Matrix3x3& a);					
-	Matrix3x3			operator-(const Matrix3x3& a) const;				
-	Matrix3x3&			operator-=(const Matrix3x3& a);					
-	Matrix3x3			operator*(float k) const;					
-	Matrix3x3&			operator*=(float k);						
-	Matrix3x3			operator/(float k) const;					
-	Matrix3x3&			operator/=(float k);							
-	Vector3				operator*(const Vector3& v) const;			
-	Matrix3x3			operator*(const Matrix3x3& a) const;				
-	Matrix3x3&			operator*=(const Matrix3x3& a);			
+	/// Sets the matrix @a m to identity.
+	void set_identity(Matrix3x3& m);							
 
-	/// For simmetry
-	friend Matrix3x3		operator*(float k, const Matrix3x3& a);			
+	/// Returns the pointer to the matrix's data
+	float* to_float_ptr(Matrix3x3& m);
 
-	/// Builds a rotation matrix about the X axis of @a radians radians
-	void				build_rotation_x(float radians);			
+	/// Returns the pointer to the matrix's data				
+	const float* to_float_ptr(const Matrix3x3& m);
 
-	/// Builds a rotation matrix about the Y axis of @a radians radians	
-	void				build_rotation_y(float radians);	
+	/// Returns a 4x4 matrix according to the matrix's rotation portion						
+	Matrix4x4 to_matrix4x4(const Matrix3x3& m);
 
-	/// Builds a rotation matrix about the Z axis of @a radians radians			
-	void				build_rotation_z(float radians);	
+	/// Returns a quaternion according to the matrix's rotation portion							
+	Quaternion to_quaternion(const Matrix3x3& m);
+} // namespace matrix3x3
 
-	/// Builds a rotation matrix about an arbitrary axis of "radians" radians			
-	void				build_rotation(const Vector3& n, float radians);
+inline Matrix3x3 operator+(Matrix3x3 a, const Matrix3x3& b)
+{
+	a += b;
+	return a;
+}
 
-	Matrix3x3&			transpose();								
-	Matrix3x3			get_transposed() const;						
-	float				get_determinant() const;					
-	Matrix3x3&			invert();									
-	Matrix3x3			get_inverted() const;						
+inline Matrix3x3 operator-(Matrix3x3 a, const Matrix3x3& b)
+{
+	a -= b;
+	return a;
+}
 
-	/// Builds the identity matrix
-	void				load_identity();							
+inline Matrix3x3 operator*(Matrix3x3 a, float k)
+{
+	a *= k;
+	return a;
+}
 
-	/// Returns a Vector3 containing the matrix's x base vector.
-	Vector3				x() const;
+inline Matrix3x3 operator*(float k, Matrix3x3 a)
+{
+	a *= k;
+	return a;
+}
 
-	/// Returns a Vector3 containing the matrix's y base vector.
-	Vector3				y() const;
+inline Matrix3x3 operator/(Matrix3x3 a, float k)
+{
+	a /= k;
+	return a;
+}
 
-	/// Returns a Vector3 containing the matrix's z base vector.
-	Vector3				z() const;
+inline Vector3 operator*(const Matrix3x3& a, const Vector3& v)
+{
+	Vector3 tmp;
 
-	/// Sets the matrix's x base vector.
-	void				set_x(const Vector3& x);
+	tmp.x = a.x.x * v.x + a.y.x * v.y + a.z.x * v.z;
+	tmp.y = a.x.y * v.x + a.y.y * v.y + a.z.y * v.z;
+	tmp.z = a.x.z * v.x + a.y.z * v.y + a.z.z * v.z;
 
-	/// Sets the matrix's y base vector.
-	void				set_y(const Vector3& y);
+	return tmp;
+}
 
-	/// Sets the matrix's z base vector.
-	void				set_z(const Vector3& z);
+inline Matrix3x3 operator*(Matrix3x3 a, const Matrix3x3& b)
+{
+	a *= b;
+	return a;
+}
 
-	/// Returns a Vector3 containing the matrix's scale portion
-	Vector3				get_scale() const;	
+namespace matrix3x3
+{
+	//-----------------------------------------------------------------------------
+	inline Matrix3x3& transpose(Matrix3x3& m)
+	{
+		float tmp;
+
+		tmp = m.x.y;
+		m.x.y = m.y.x;
+		m.y.x = tmp;
+
+		tmp = m.x.z;
+		m.x.z = m.z.x;
+		m.z.x = tmp;
+
+		tmp = m.y.z;
+		m.y.z = m.z.y;
+		m.z.y = tmp;
+
+		return m;
+	}
+
+	//-----------------------------------------------------------------------------
+	inline Matrix3x3 get_transposed(Matrix3x3 m)
+	{
+		transpose(m);
+		return m;
+	}
+
+	//-----------------------------------------------------------------------------
+	inline float determinant(const Matrix3x3& m)
+	{
+		return	m.x.x * (m.y.y * m.z.z - m.z.y * m.y.z) -
+				m.y.x * (m.x.y * m.z.z - m.z.y * m.x.z) +
+				m.z.x * (m.x.y * m.y.z - m.y.y * m.x.z);
+	}
+
+	//-----------------------------------------------------------------------------
+	inline Matrix3x3& invert(Matrix3x3& m)
+	{
+		Matrix3x3 mat;
+
+		mat.x.x = (m.y.y * m.z.z - m.z.y * m.y.z);
+		mat.x.y = (m.x.y * m.z.z - m.z.y * m.x.z);
+		mat.x.z = (m.x.y * m.y.z - m.y.y * m.x.z);
+
+		const float inv_det = 1.0 / (m.x.x * mat.x.x - m.y.x * mat.x.y + m.z.x * mat.x.z);
+
+		mat.y.x = (m.y.x * m.z.z - m.z.x * m.y.z);
+		mat.y.y = (m.x.x * m.z.z - m.z.x * m.x.z);
+		mat.y.z = (m.x.x * m.y.z - m.y.x * m.x.z);
+		mat.z.x = (m.y.x * m.z.y - m.z.x * m.y.y);
+		mat.z.y = (m.x.x * m.z.y - m.z.x * m.x.y);
+		mat.z.z = (m.x.x * m.y.y - m.y.x * m.x.y);
+
+		m.x.x = + mat.x.x * inv_det;
+		m.x.y = - mat.x.y * inv_det;
+		m.x.z = + mat.x.z * inv_det;
+		m.y.x = - mat.y.x * inv_det;
+		m.y.y = + mat.y.y * inv_det;
+		m.y.z = - mat.y.z * inv_det;
+		m.z.x = + mat.z.x * inv_det;
+		m.z.y = - mat.z.y * inv_det;
+		m.z.z = + mat.z.z * inv_det;
+
+		return m;
+	}
+
+	//-----------------------------------------------------------------------------
+	inline Matrix3x3 get_inverted(Matrix3x3 m)
+	{
+		invert(m);
+		return m;
+	}
+
+	//-----------------------------------------------------------------------------
+	inline void set_identity(Matrix3x3& m)
+	{
+		m.x = Vector3(1, 0, 0);
+		m.y = Vector3(0, 1, 0);
+		m.z = Vector3(0, 0, 1);
+	}
+
+	//-----------------------------------------------------------------------------
+	inline Matrix4x4 to_matrix4x4(const Matrix3x3& m)
+	{
+		return Matrix4x4(m);
+	}
+
+	//-----------------------------------------------------------------------------
+	inline Quaternion to_quaternion(const Matrix3x3& m)
+	{
+		const float fourWSquaredMinusOne = m.x.x + m.y.y + m.z.z;
+		const float fourXSquaredMinusOne = m.x.x - m.y.y - m.z.z;
+		const float fourYSquaredMinusOne = -m.x.x + m.y.y - m.z.z;
+		const float fourZSquaredMinusOne = -m.x.x - m.y.y + m.z.z;
+		float fourMaxSquaredMinusOne = fourWSquaredMinusOne;
+		uint32_t index = 0;
+
+		if (fourXSquaredMinusOne > fourMaxSquaredMinusOne)
+		{
+			fourMaxSquaredMinusOne = fourXSquaredMinusOne;
+			index = 1;
+		}
+
+		if (fourYSquaredMinusOne > fourMaxSquaredMinusOne)
+		{
+			fourMaxSquaredMinusOne = fourYSquaredMinusOne;
+			index = 2;
+		}
+
+		if (fourZSquaredMinusOne > fourMaxSquaredMinusOne)
+		{
+			fourMaxSquaredMinusOne = fourZSquaredMinusOne;
+			index = 3;
+		}
+
+		const float biggest = math::sqrt(fourMaxSquaredMinusOne + (float)1.0) * (float)0.5;
+		const float mult = (float)0.25 / biggest;
+
+		Quaternion tmp;
+		switch (index)
+		{
+			case 0:
+			{
+				tmp.w = biggest;
+				tmp.x = (-m.z.y + m.y.z) * mult;
+				tmp.y = (-m.x.z + m.z.x) * mult;
+				tmp.z = (-m.y.x + m.x.y) * mult;
+				break;
+			}
+			case 1:
+			{
+				tmp.x = biggest;
+				tmp.w = (-m.z.y + m.y.z) * mult;
+				tmp.y = (-m.y.x - m.x.y) * mult;
+				tmp.z = (-m.x.z - m.z.x) * mult;
+				break;
+			}
+			case 2:
+			{
+				tmp.y = biggest;
+				tmp.w = (-m.x.z + m.z.x) * mult;
+				tmp.x = (-m.y.x - m.x.y) * mult;
+				tmp.z = (-m.z.y - m.y.z) * mult;
+				break;
+			}
+			case 3:
+			{
+				tmp.z = biggest;
+				tmp.w = (-m.y.x + m.x.y) * mult;
+				tmp.x = (-m.x.z - m.z.x) * mult;
+				tmp.y = (-m.z.y - m.y.z) * mult;
+				break;
+			}
+			default:
+			{
+				CE_FATAL("You should not be here");
+				break;
+			}
+		}
+
+		return tmp;
+	}
+} // namespace matrix3x3
+
+//-----------------------------------------------------------------------------
+inline Matrix3x3::Matrix3x3()
+{
+	// Do not initialize
+}
+
+//-----------------------------------------------------------------------------
+inline Matrix3x3::Matrix3x3(const Vector3& x, const Vector3& y, const Vector3& z)
+	: x(x)
+	, y(y)
+	, z(z)
+{
+}
 
-	/// Fills the matrix's scale portion with the values contained in @a scale				
-	void				set_scale(const Vector3& scale);				
+//-----------------------------------------------------------------------------
+inline Matrix3x3::Matrix3x3(const Quaternion& r)
+	: x(1.0 - 2.0 * r.y * r.y - 2.0 * r.z * r.z, 2.0 * r.x * r.y + 2.0 * r.w * r.z, 2.0 * r.x * r.z - 2.0 * r.w * r.y)
+	, y(2.0 * r.x * r.y - 2.0 * r.w * r.z, 1.0 - 2.0 * r.x * r.x - 2.0 * r.z * r.z, 2.0 * r.y * r.z + 2.0 * r.w * r.x)
+	, z(2.0 * r.x * r.z + 2.0 * r.w * r.y, 2.0 * r.y * r.z - 2.0 * r.w * r.x, 1.0 - 2.0 * r.x * r.x - 2.0 * r.y * r.y)
+{
+}
+
+//-----------------------------------------------------------------------------
+inline Matrix3x3::Matrix3x3(float r1c1, float r2c1, float r3c1, float r1c2, float r2c2, float r3c2,
+						float r1c3, float r2c3, float r3c3)
+	: x(r1c1, r2c1, r3c1)
+	, y(r1c2, r2c2, r3c2)
+	, z(r1c3, r2c3, r3c3)
+{
+}
 
-	/// Returns the pointer to the matrix's data
-	float*				to_float_ptr();				
+//-----------------------------------------------------------------------------
+inline Matrix3x3::Matrix3x3(const float v[9])
+	: x(v[0], v[1], v[2])
+	, y(v[3], v[4], v[5])
+	, z(v[6], v[7], v[8])
+{
+}
 
-	/// Returns the pointer to the matrix's data				
-	const float*		to_float_ptr() const;
+//-----------------------------------------------------------------------------
+inline float& Matrix3x3::operator[](uint32_t i)
+{
+	CE_ASSERT(i < 9, "Index out of bounds");
 
-	/// Returns a 4x4 matrix according to the matrix's rotation portion						
-	Matrix4x4			to_matrix4x4() const;
+	return vector3::to_float_ptr(x)[i];
+}
 
-	/// Returns a quaternion according to the matrix's rotation portion							
-	Quaternion			to_quaternion() const;							
+//-----------------------------------------------------------------------------
+inline const float& Matrix3x3::operator[](uint32_t i) const
+{
+	CE_ASSERT(i < 9, "Index out of bounds");
 
-	static const Matrix3x3	IDENTITY;
-};
+	return vector3::to_float_ptr(x)[i];
+}
 
-} // namespace crown
+//-----------------------------------------------------------------------------
+inline Matrix3x3& Matrix3x3::operator+=(const Matrix3x3& a)
+{
+	x += a.x;
+	y += a.y;
+	z += a.z;
+
+	return *this;
+}
+
+//-----------------------------------------------------------------------------
+inline Matrix3x3& Matrix3x3::operator-=(const Matrix3x3& a)
+{
+	x -= a.x;
+	y -= a.y;
+	z -= a.z;
+
+	return *this;
+}
+
+//-----------------------------------------------------------------------------
+inline Matrix3x3& Matrix3x3::operator*=(float k)
+{
+	x *= k;
+	y *= k;
+	z *= k;
 
+	return *this;
+}
+
+//-----------------------------------------------------------------------------
+inline Matrix3x3& Matrix3x3::operator/=(float k)
+{
+	const float inv_k = 1.0 / k;
+
+	x *= inv_k;
+	y *= inv_k;
+	z *= inv_k;
+
+	return *this;
+}
+
+//-----------------------------------------------------------------------------
+inline Matrix3x3& Matrix3x3::operator*=(const Matrix3x3& a)
+{
+	Matrix3x3 tmp;
+
+	tmp.x.x = x.x * a.x.x + y.x * a.x.y + z.x * a.x.z;
+	tmp.x.y = x.y * a.x.x + y.y * a.x.y + z.y * a.x.z;
+	tmp.x.z = x.z * a.x.x + y.z * a.x.y + z.z * a.x.z;
+
+	tmp.y.x = x.x * a.y.x + y.x * a.y.y + z.x * a.y.z;
+	tmp.y.y = x.y * a.y.x + y.y * a.y.y + z.y * a.y.z;
+	tmp.y.z = x.z * a.y.x + y.z * a.y.y + z.z * a.y.z;
+
+	tmp.z.x = x.x * a.z.x + y.x * a.z.y + z.x * a.z.z;
+	tmp.z.y = x.y * a.z.x + y.y * a.z.y + z.y * a.z.z;
+	tmp.z.z = x.z * a.z.x + y.z * a.z.y + z.z * a.z.z;
+
+	*this = tmp;
+
+	return *this;
+}
+
+} // namespace crown

+ 0 - 1043
engine/core/math/Matrix4x4.cpp

@@ -1,1043 +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 "Assert.h"
-#include "Matrix3x3.h"
-#include "Types.h"
-#include "Matrix4x4.h"
-#include "MathUtils.h"
-#include "Quaternion.h"
-#include "Vector3.h"
-#include "Vector4.h"
-
-namespace crown
-{
-
-const Matrix4x4 Matrix4x4::IDENTITY = Matrix4x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0);
-
-//-----------------------------------------------------------------------------
-Matrix4x4::Matrix4x4()
-{
-}
-
-//-----------------------------------------------------------------------------
-Matrix4x4::Matrix4x4(float r1c1, float r2c1, float r3c1, float r4c1,
-						float r1c2, float r2c2, float r3c2, float r4c2,
-						float r1c3, float r2c3, float r3c3, float r4c3,
-						float r1c4, float r2c4, float r3c4, float r4c4)
-{
-	m[0] = r1c1;
-	m[1] = r2c1;
-	m[2] = r3c1;
-	m[3] = r4c1;
-	m[4] = r1c2;
-	m[5] = r2c2;
-	m[6] = r3c2;
-	m[7] = r4c2;
-	m[8] = r1c3;
-	m[9] = r2c3;
-	m[10] = r3c3;
-	m[11] = r4c3;
-	m[12] = r1c4;
-	m[13] = r2c4;
-	m[14] = r3c4;
-	m[15] = r4c4;
-}
-
-//-----------------------------------------------------------------------------
-Matrix4x4::Matrix4x4(const Quaternion& r, const Vector3& p)
-{
-	const float rx = r.x;
-	const float ry = r.y;
-	const float rz = r.z;
-	const float rw = r.w;
-
-	m[0] = 1.0 - 2.0 * ry * ry - 2.0 * rz * rz;
-	m[1] = 2.0 * rx * ry + 2.0 * rw * rz;
-	m[2] = 2.0 * rx * rz - 2.0 * rw * ry;
-	m[3] = 0;
-	m[4] = 2.0 * rx * ry - 2.0 * rw * rz;
-	m[5] = 1.0 - 2.0 * rx * rx - 2.0 * rz * rz;
-	m[6] = 2.0 * ry * rz + 2.0 * rw * rx;
-	m[7] = 0.0;
-	m[8] = 2.0 * rx * rz + 2.0 * rw * ry;
-	m[9] = 2.0 * ry * rz - 2.0 * rw * rx;
-	m[10] = 1.0 - 2.0 * rx * rx - 2.0 * ry * ry;
-	m[11] = 0.0;
-	m[12] = p.x;
-	m[13] = p.y;
-	m[14] = p.z;
-	m[15] = 1.0;
-}
-
-//-----------------------------------------------------------------------------
-Matrix4x4::Matrix4x4(const float v[16])
-{
-	m[0] = v[0];
-	m[1] = v[1];
-	m[2] = v[2];
-	m[3] = v[3];
-	m[4] = v[4];
-	m[5] = v[5];
-	m[6] = v[6];
-	m[7] = v[7];
-	m[8] = v[8];
-	m[9] = v[9];
-	m[10] = v[10];
-	m[11] = v[11];
-	m[12] = v[12];
-	m[13] = v[13];
-	m[14] = v[14];
-	m[15] = v[15];
-}
-
-//-----------------------------------------------------------------------------
-Matrix4x4::Matrix4x4(const Matrix4x4& a)
-{
-	m[0] = a.m[0];
-	m[1] = a.m[1];
-	m[2] = a.m[2];
-	m[3] = a.m[3];
-	m[4] = a.m[4];
-	m[5] = a.m[5];
-	m[6] = a.m[6];
-	m[7] = a.m[7];
-	m[8] = a.m[8];
-	m[9] = a.m[9];
-	m[10] = a.m[10];
-	m[11] = a.m[11];
-	m[12] = a.m[12];
-	m[13] = a.m[13];
-	m[14] = a.m[14];
-	m[15] = a.m[15];
-}
-
-//-----------------------------------------------------------------------------
-Matrix4x4& Matrix4x4::operator=(const Matrix4x4& a)
-{
-	m[0] = a.m[0];
-	m[1] = a.m[1];
-	m[2] = a.m[2];
-	m[3] = a.m[3];
-	m[4] = a.m[4];
-	m[5] = a.m[5];
-	m[6] = a.m[6];
-	m[7] = a.m[7];
-	m[8] = a.m[8];
-	m[9] = a.m[9];
-	m[10] = a.m[10];
-	m[11] = a.m[11];
-	m[12] = a.m[12];
-	m[13] = a.m[13];
-	m[14] = a.m[14];
-	m[15] = a.m[15];
-
-	return *this;
-}
-
-//-----------------------------------------------------------------------------
-float Matrix4x4::operator[](uint32_t i) const
-{
-	CE_ASSERT(i < 16, "Index must be < 16");
-
-	return m[i];
-}
-
-//-----------------------------------------------------------------------------
-float& Matrix4x4::operator[](uint32_t i)
-{
-	CE_ASSERT(i < 16, "Index must be < 16");
-
-	return m[i];
-}
-
-//-----------------------------------------------------------------------------
-float Matrix4x4::operator()(uint32_t row, uint32_t column) const
-{
-	CE_ASSERT(row < 4 && column < 4, "Row and column must be < 4");
-
-	return m[row + column * 4];
-}
-
-//-----------------------------------------------------------------------------
-Matrix4x4 Matrix4x4::operator+(const Matrix4x4& a) const
-{
-	Matrix4x4 tmp;
-
-	tmp.m[0] = m[0] + a.m[0];
-	tmp.m[1] = m[1] + a.m[1];
-	tmp.m[2] = m[2] + a.m[2];
-	tmp.m[3] = m[3] + a.m[3];
-	tmp.m[4] = m[4] + a.m[4];
-	tmp.m[5] = m[5] + a.m[5];
-	tmp.m[6] = m[6] + a.m[6];
-	tmp.m[7] = m[7] + a.m[7];
-	tmp.m[8] = m[8] + a.m[8];
-	tmp.m[9] = m[9] + a.m[9];
-	tmp.m[10] = m[10] + a.m[10];
-	tmp.m[11] = m[11] + a.m[11];
-	tmp.m[12] = m[12] + a.m[12];
-	tmp.m[13] = m[13] + a.m[13];
-	tmp.m[14] = m[14] + a.m[14];
-	tmp.m[14] = m[15] + a.m[15];
-
-	return tmp;
-}
-
-//-----------------------------------------------------------------------------
-Matrix4x4& Matrix4x4::operator+=(const Matrix4x4& a)
-{
-	m[0] = m[0] + a.m[0];
-	m[1] = m[1] + a.m[1];
-	m[2] = m[2] + a.m[2];
-	m[3] = m[3] + a.m[3];
-	m[4] = m[4] + a.m[4];
-	m[5] = m[5] + a.m[5];
-	m[6] = m[6] + a.m[6];
-	m[7] = m[7] + a.m[7];
-	m[8] = m[8] + a.m[8];
-	m[9] = m[9] + a.m[9];
-	m[10] = m[10] + a.m[10];
-	m[11] = m[11] + a.m[11];
-	m[12] = m[12] + a.m[12];
-	m[13] = m[13] + a.m[13];
-	m[14] = m[14] + a.m[14];
-	m[14] = m[15] + a.m[15];
-
-	return *this;
-}
-
-//-----------------------------------------------------------------------------
-Matrix4x4 Matrix4x4::operator-(const Matrix4x4& a) const
-{
-	Matrix4x4 tmp;
-
-	tmp.m[0] = m[0] - a.m[0];
-	tmp.m[1] = m[1] - a.m[1];
-	tmp.m[2] = m[2] - a.m[2];
-	tmp.m[3] = m[3] - a.m[3];
-	tmp.m[4] = m[4] - a.m[4];
-	tmp.m[5] = m[5] - a.m[5];
-	tmp.m[6] = m[6] - a.m[6];
-	tmp.m[7] = m[7] - a.m[7];
-	tmp.m[8] = m[8] - a.m[8];
-	tmp.m[9] = m[9] - a.m[9];
-	tmp.m[10] = m[10] - a.m[10];
-	tmp.m[11] = m[11] - a.m[11];
-	tmp.m[12] = m[12] - a.m[12];
-	tmp.m[13] = m[13] - a.m[13];
-	tmp.m[14] = m[14] - a.m[14];
-	tmp.m[14] = m[15] - a.m[15];
-
-	return tmp;
-}
-
-//-----------------------------------------------------------------------------
-Matrix4x4& Matrix4x4::operator-=(const Matrix4x4& a)
-{
-	m[0] = m[0] - a.m[0];
-	m[1] = m[1] - a.m[1];
-	m[2] = m[2] - a.m[2];
-	m[3] = m[3] - a.m[3];
-	m[4] = m[4] - a.m[4];
-	m[5] = m[5] - a.m[5];
-	m[6] = m[6] - a.m[6];
-	m[7] = m[7] - a.m[7];
-	m[8] = m[8] - a.m[8];
-	m[9] = m[9] - a.m[9];
-	m[10] = m[10] - a.m[10];
-	m[11] = m[11] - a.m[11];
-	m[12] = m[12] - a.m[12];
-	m[13] = m[13] - a.m[13];
-	m[14] = m[14] - a.m[14];
-	m[14] = m[15] - a.m[15];
-
-	return *this;
-}
-
-//-----------------------------------------------------------------------------
-Matrix4x4 Matrix4x4::operator*(float k) const
-{
-	Matrix4x4 tmp;
-
-	tmp.m[0] = m[0] * k;
-	tmp.m[1] = m[1] * k;
-	tmp.m[2] = m[2] * k;
-	tmp.m[3] = m[3] * k;
-	tmp.m[4] = m[4] * k;
-	tmp.m[5] = m[5] * k;
-	tmp.m[6] = m[6] * k;
-	tmp.m[7] = m[7] * k;
-	tmp.m[8] = m[8] * k;
-	tmp.m[9] = m[9] * k;
-	tmp.m[10] = m[10] * k;
-	tmp.m[11] = m[11] * k;
-	tmp.m[12] = m[12] * k;
-	tmp.m[13] = m[13] * k;
-	tmp.m[14] = m[14] * k;
-	tmp.m[15] = m[15] * k;
-
-	return tmp;
-}
-
-//-----------------------------------------------------------------------------
-Matrix4x4& Matrix4x4::operator*=(float k)
-{
-	m[0] *= k;
-	m[1] *= k;
-	m[2] *= k;
-	m[3] *= k;
-	m[4] *= k;
-	m[5] *= k;
-	m[6] *= k;
-	m[7] *= k;
-	m[8] *= k;
-	m[9] *= k;
-	m[10] *= k;
-	m[11] *= k;
-	m[12] *= k;
-	m[13] *= k;
-	m[14] *= k;
-	m[15] *= k;
-
-	return *this;
-}
-
-//-----------------------------------------------------------------------------
-Matrix4x4 Matrix4x4::operator/(float k) const
-{
-	Matrix4x4 tmp;
-
-	k = (float)1.0 / k;
-
-	tmp.m[0] = m[0] * k;
-	tmp.m[1] = m[1] * k;
-	tmp.m[2] = m[2] * k;
-	tmp.m[3] = m[3] * k;
-	tmp.m[4] = m[4] * k;
-	tmp.m[5] = m[5] * k;
-	tmp.m[6] = m[6] * k;
-	tmp.m[7] = m[7] * k;
-	tmp.m[8] = m[8] * k;
-	tmp.m[9] = m[9] * k;
-	tmp.m[10] = m[10] * k;
-	tmp.m[11] = m[11] * k;
-	tmp.m[12] = m[12] * k;
-	tmp.m[13] = m[13] * k;
-	tmp.m[14] = m[14] * k;
-	tmp.m[15] = m[15] * k;
-
-	return tmp;
-}
-
-//-----------------------------------------------------------------------------
-Matrix4x4& Matrix4x4::operator/=(float k)
-{
-	k = (float)1.0 / k;
-
-	m[0] *= k;
-	m[1] *= k;
-	m[2] *= k;
-	m[3] *= k;
-	m[4] *= k;
-	m[5] *= k;
-	m[6] *= k;
-	m[7] *= k;
-	m[8] *= k;
-	m[9] *= k;
-	m[10] *= k;
-	m[11] *= k;
-	m[12] *= k;
-	m[13] *= k;
-	m[14] *= k;
-	m[15] *= k;
-
-	return *this;
-}
-
-//-----------------------------------------------------------------------------
-Vector3 Matrix4x4::operator*(const Vector3& v) const
-{
-	Vector3 tmp;
-
-	tmp.x = m[0] * v.x + m[4] * v.y + m[8] * v.z + m[12];
-	tmp.y = m[1] * v.x + m[5] * v.y + m[9] * v.z + m[13];
-	tmp.z = m[2] * v.x + m[6] * v.y + m[10] * v.z + m[14];
-
-	return tmp;
-}
-
-//-----------------------------------------------------------------------------
-Vector4 Matrix4x4::operator*(const Vector4& v) const
-{
-	Vector4 tmp;
-
-	tmp.x = m[0] * v.x + m[4] * v.y + m[8] * v.z + m[12] * v.w;
-	tmp.y = m[1] * v.x + m[5] * v.y + m[9] * v.z + m[13] * v.w;
-	tmp.z = m[2] * v.x + m[6] * v.y + m[10] * v.z + m[14] * v.w;
-	tmp.w = m[3] * v.x + m[7] * v.y + m[11] * v.z + m[15] * v.w;
-
-	return tmp;
-}
-
-//-----------------------------------------------------------------------------
-Matrix4x4 Matrix4x4::operator*(const Matrix4x4& a) const
-{
-	Matrix4x4 tmp;
-
-	tmp.m[0] = m[0] * a.m[0] + m[4] * a.m[1] + m[8] * a.m[2] + m[12] * a.m[3];
-	tmp.m[1] = m[1] * a.m[0] + m[5] * a.m[1] + m[9] * a.m[2] + m[13] * a.m[3];
-	tmp.m[2] = m[2] * a.m[0] + m[6] * a.m[1] + m[10] * a.m[2] + m[14] * a.m[3];
-	tmp.m[3] = m[3] * a.m[0] + m[7] * a.m[1] + m[11] * a.m[2] + m[15] * a.m[3];
-
-	tmp.m[4] = m[0] * a.m[4] + m[4] * a.m[5] + m[8] * a.m[6] + m[12] * a.m[7];
-	tmp.m[5] = m[1] * a.m[4] + m[5] * a.m[5] + m[9] * a.m[6] + m[13] * a.m[7];
-	tmp.m[6] = m[2] * a.m[4] + m[6] * a.m[5] + m[10] * a.m[6] + m[14] * a.m[7];
-	tmp.m[7] = m[3] * a.m[4] + m[7] * a.m[5] + m[11] * a.m[6] + m[15] * a.m[7];
-
-	tmp.m[8] = m[0] * a.m[8] + m[4] * a.m[9] + m[8] * a.m[10] + m[12] * a.m[11];
-	tmp.m[9] = m[1] * a.m[8] + m[5] * a.m[9] + m[9] * a.m[10] + m[13] * a.m[11];
-	tmp.m[10] = m[2] * a.m[8] + m[6] * a.m[9] + m[10] * a.m[10] + m[14] * a.m[11];
-	tmp.m[11] = m[3] * a.m[8] + m[7] * a.m[9] + m[11] * a.m[10] + m[15] * a.m[11];
-
-	tmp.m[12] = m[0] * a.m[12] + m[4] * a.m[13] + m[8] * a.m[14] + m[12] * a.m[15];
-	tmp.m[13] = m[1] * a.m[12] + m[5] * a.m[13] + m[9] * a.m[14] + m[13] * a.m[15];
-	tmp.m[14] = m[2] * a.m[12] + m[6] * a.m[13] + m[10] * a.m[14] + m[14] * a.m[15];
-	tmp.m[15] = m[3] * a.m[12] + m[7] * a.m[13] + m[11] * a.m[14] + m[15] * a.m[15];
-
-	return tmp;
-}
-
-//-----------------------------------------------------------------------------
-Matrix4x4& Matrix4x4::operator*=(const Matrix4x4& a)
-{
-	Matrix4x4 tmp;
-
-	tmp.m[0] = m[0] * a.m[0] + m[4] * a.m[1] + m[8] * a.m[2] + m[12] * a.m[3];
-	tmp.m[1] = m[1] * a.m[0] + m[5] * a.m[1] + m[9] * a.m[2] + m[13] * a.m[3];
-	tmp.m[2] = m[2] * a.m[0] + m[6] * a.m[1] + m[10] * a.m[2] + m[14] * a.m[3];
-	tmp.m[3] = m[3] * a.m[0] + m[7] * a.m[1] + m[11] * a.m[2] + m[15] * a.m[3];
-
-	tmp.m[4] = m[0] * a.m[4] + m[4] * a.m[5] + m[8] * a.m[6] + m[12] * a.m[7];
-	tmp.m[5] = m[1] * a.m[4] + m[5] * a.m[5] + m[9] * a.m[6] + m[13] * a.m[7];
-	tmp.m[6] = m[2] * a.m[4] + m[6] * a.m[5] + m[10] * a.m[6] + m[14] * a.m[7];
-	tmp.m[7] = m[3] * a.m[4] + m[7] * a.m[5] + m[11] * a.m[6] + m[15] * a.m[7];
-
-	tmp.m[8] = m[0] * a.m[8] + m[4] * a.m[9] + m[8] * a.m[10] + m[12] * a.m[11];
-	tmp.m[9] = m[1] * a.m[8] + m[5] * a.m[9] + m[9] * a.m[10] + m[13] * a.m[11];
-	tmp.m[10] = m[2] * a.m[8] + m[6] * a.m[9] + m[10] * a.m[10] + m[14] * a.m[11];
-	tmp.m[11] = m[3] * a.m[8] + m[7] * a.m[9] + m[11] * a.m[10] + m[15] * a.m[11];
-
-	tmp.m[12] = m[0] * a.m[12] + m[4] * a.m[13] + m[8] * a.m[14] + m[12] * a.m[15];
-	tmp.m[13] = m[1] * a.m[12] + m[5] * a.m[13] + m[9] * a.m[14] + m[13] * a.m[15];
-	tmp.m[14] = m[2] * a.m[12] + m[6] * a.m[13] + m[10] * a.m[14] + m[14] * a.m[15];
-	tmp.m[15] = m[3] * a.m[12] + m[7] * a.m[13] + m[11] * a.m[14] + m[15] * a.m[15];
-
-	*this = tmp;
-
-	return *this;
-}
-
-Matrix4x4 operator*(float k, const Matrix4x4& a)
-{
-	return a * k;
-}
-
-//-----------------------------------------------------------------------------
-void Matrix4x4::build_rotation_x(float radians)
-{
-	m[0] = 1.0;
-	m[1] = 0.0;
-	m[2] = 0.0;
-	m[3] = 0.0;
-	m[4] = 0.0;
-	m[5] = math::cos(radians);
-	m[6] = math::sin(radians);
-	m[7] = 0.0;
-	m[8] = 0.0;
-	m[9] = -math::sin(radians);
-	m[10] = math::cos(radians);
-	m[11] = 0.0;
-	m[12] = 0.0;
-	m[13] = 0.0;
-	m[14] = 0.0;
-	m[15] = 1.0;
-}
-
-//-----------------------------------------------------------------------------
-void Matrix4x4::build_rotation_y(float radians)
-{
-	m[0] = math::cos(radians);
-	m[1] = 0.0;
-	m[2] = -math::sin(radians);
-	m[3] = 0.0;
-	m[4] = 0.0;
-	m[5] = 1.0;
-	m[6] = 0.0;
-	m[7] = 0.0;
-	m[8] = math::sin(radians);
-	m[9] = 0.0;
-	m[10] = math::cos(radians);
-	m[11] = 0.0;
-	m[12] = 0.0;
-	m[13] = 0.0;
-	m[14] = 0.0;
-	m[15] = 1.0;
-}
-
-//-----------------------------------------------------------------------------
-void Matrix4x4::build_rotation_z(float radians)
-{
-	m[0] = math::cos(radians);
-	m[1] = math::sin(radians);
-	m[2] = 0.0;
-	m[3] = 0.0;
-	m[4] = -math::sin(radians);
-	m[5] = math::cos(radians);
-	m[6] = 0.0;
-	m[7] = 0.0;
-	m[8] = 0.0;
-	m[9] = 0.0;
-	m[10] = 1.0;
-	m[11] = 0.0;
-	m[12] = 0.0;
-	m[13] = 0.0;
-	m[14] = 0.0;
-	m[15] = 1.0;
-}
-
-//-----------------------------------------------------------------------------
-void Matrix4x4::build_rotation(const Vector3& n, float radians)
-{
-	float a = (float)1.0 - math::cos(radians);
-	float sin_a = math::sin(radians);
-	float cos_a = math::cos(radians);
-
-	m[0] = n.x * n.x * a + cos_a;
-	m[1] = n.x * n.y * a + n.z * sin_a;
-	m[2] = n.x * n.z * a - n.y * sin_a;
-	m[3] = 0.0;
-	m[4] = n.x * n.y * a - n.z * sin_a;
-	m[5] = n.y * n.y * a + cos_a;
-	m[6] = n.y * n.z * a + n.x * sin_a;
-	m[7] = 0.0;
-	m[8] = n.x * n.z * a + n.y * sin_a;
-	m[9] = n.y * n.z * a - n.x * sin_a;
-	m[10] = n.z * n.z * a + cos_a;
-	m[11] = 0.0;
-	m[12] = 0.0;
-	m[13] = 0.0;
-	m[14] = 0.0;
-	m[15] = 1.0;
-}
-
-//-----------------------------------------------------------------------------
-void Matrix4x4::set_rotation(const Quaternion& rot)
-{
-	set_rotation(quaternion::to_matrix3x3(rot));
-}
-
-//-----------------------------------------------------------------------------
-void Matrix4x4::set_rotation(const Matrix3x3& rot)
-{
-	m[0] = rot.m[0];
-	m[1] = rot.m[1];
-	m[2] = rot.m[2];
-	m[4] = rot.m[3];
-	m[5] = rot.m[4];
-	m[6] = rot.m[5];
-	m[8] = rot.m[6];
-	m[9] = rot.m[7];
-	m[10] = rot.m[8];
-}
-
-//-----------------------------------------------------------------------------
-void Matrix4x4::build_projection_perspective_rh(float fovy, float aspect, float near, float far)
-{
-	double top, right;
-
-	top = math::tan((float)((double)fovy / 360.0 * math::PI)) * (double)near;
-	right = top * aspect;
-
-	m[0] = (float)(near / right);
-	m[1] = 0.0;
-	m[2] = 0.0;
-	m[3] = 0.0;
-	m[4] = 0.0;
-	m[5] = (float)(near / top);
-	m[6] = 0.0;
-	m[7] = 0.0;
-	m[8] = 0.0;
-	m[9] = 0.0;
-	m[10] = (float)((far + near) / (near - far));
-	m[11] = -1.0;
-	m[12] = 0.0;
-	m[13] = 0.0;
-	m[14] = (float)((2.0 * far * near) / (near - far));
-	m[15] = 0.0;
-}
-
-//-----------------------------------------------------------------------------
-void Matrix4x4::build_projection_ortho_rh(float left, float right, float bottom, float top, float near, float far)
-{
-	m[0] = 2.0 / (right - left);
-	m[1] = 0.0;
-	m[2] = 0.0;
-	m[3] = 0.0;
-	m[4] = 0.0;
-	m[5] = 2.0 / (top - bottom);
-	m[6] = 0.0;
-	m[7] = 0.0;
-	m[8] = 0.0;
-	m[9] = 0.0;
-	m[10] = -2.0 / (far - near);
-	m[11] = 0.0;
-	m[12] = -((right + left) / (right - left));
-	m[13] = -((top + bottom) / (top - bottom));
-	m[14] = -((far + near) / (far - near));
-	m[15] = 1.0;
-}
-
-//-----------------------------------------------------------------------------
-Matrix4x4& Matrix4x4::transpose()
-{
-	float tmp;
-
-	tmp = m[1];
-	m[1] = m[4];
-	m[4] = tmp;
-
-	tmp = m[2];
-	m[2] = m[8];
-	m[8] = tmp;
-
-	tmp = m[3];
-	m[3] = m[12];
-	m[12] = tmp;
-
-	tmp = m[6];
-	m[6] = m[9];
-	m[9] = tmp;
-
-	tmp = m[7];
-	m[7] = m[13];
-	m[13] = tmp;
-
-	tmp = m[11];
-	m[11] = m[14];
-	m[14] = tmp;
-
-	return *this;
-}
-
-//-----------------------------------------------------------------------------
-Matrix4x4 Matrix4x4::get_transposed() const
-{
-	Matrix4x4 tmp;
-
-	tmp.m[0] = m[0];
-	tmp.m[1] = m[4];
-	tmp.m[2] = m[8];
-	tmp.m[3] = m[12];
-	tmp.m[4] = m[1];
-	tmp.m[5] = m[5];
-	tmp.m[6] = m[9];
-	tmp.m[7] = m[13];
-	tmp.m[8] = m[2];
-	tmp.m[9] = m[6];
-	tmp.m[10] = m[10];
-	tmp.m[11] = m[14];
-	tmp.m[12] = m[3];
-	tmp.m[13] = m[7];
-	tmp.m[14] = m[11];
-	tmp.m[15] = m[15];
-
-	return tmp;
-}
-
-//-----------------------------------------------------------------------------
-void Matrix4x4::build_look_at_rh(const Vector3& pos, const Vector3& target, const Vector3& up)
-{
-	Vector3 zAxis =  pos - target;
-	vector3::normalize(zAxis);
-
-	Vector3 xAxis = vector3::cross(up, zAxis);
-	Vector3 yAxis = vector3::cross(zAxis, xAxis);
-
-	m[0] = xAxis.x;
-	m[1] = yAxis.x;
-	m[2] = zAxis.x;
-	m[3] = 0.0;
-	m[4] = xAxis.y;
-	m[5] = yAxis.y;
-	m[6] = zAxis.y;
-	m[7] = 0.0;
-	m[8] = xAxis.z;
-	m[9] = yAxis.z;
-	m[10] = zAxis.z;
-	m[11] = 0.0;
-	m[12] = -vector3::dot(pos, xAxis);
-	m[13] = -vector3::dot(pos, yAxis);
-	m[14] = -vector3::dot(pos, zAxis);
-	m[15] = 1.0;
-}
-
-//-----------------------------------------------------------------------------
-void Matrix4x4::build_viewpoint_billboard(const Vector3& pos, const Vector3& target, const Vector3& up)
-{
-	Vector3 zAxis = target - pos;
-	vector3::normalize(zAxis);
-
-	Vector3 xAxis = vector3::cross(up, zAxis);
-	Vector3 yAxis = vector3::cross(zAxis, xAxis);
-	vector3::normalize(xAxis);
-	vector3::normalize(yAxis);
-
-	m[0] = xAxis.x;
-	m[1] = xAxis.y;
-	m[2] = xAxis.z;
-	m[3] = 0.0;
-	m[4] = yAxis.x;
-	m[5] = yAxis.y;
-	m[6] = yAxis.z;
-	m[7] = 0.0;
-	m[8] = zAxis.x;
-	m[9] = zAxis.y;
-	m[10] = zAxis.z;
-	m[11] = 0.0;
-	m[12] = pos.x;
-	m[13] = pos.y;
-	m[14] = pos.z;
-	m[15] = 1.0;
-}
-
-//-----------------------------------------------------------------------------
-void Matrix4x4::build_axis_billboard(const Vector3& pos, const Vector3& target, const Vector3& axis)
-{
-	Vector3 zAxis = target - pos;
-
-	Vector3 xAxis = vector3::cross(axis, zAxis);
-	zAxis = vector3::cross(axis, xAxis);
-	vector3::normalize(xAxis);
-	vector3::normalize(zAxis);
-	const Vector3& yAxis = axis;
-
-	m[0] = xAxis.x;
-	m[1] = xAxis.y;
-	m[2] = xAxis.z;
-	m[3] = 0.0;
-	m[4] = yAxis.x;
-	m[5] = yAxis.y;
-	m[6] = yAxis.z;
-	m[7] = 0.0;
-	m[8] = zAxis.x;
-	m[9] = zAxis.y;
-	m[10] = zAxis.z;
-	m[11] = 0.0;
-	m[12] = pos.x;
-	m[13] = pos.y;
-	m[14] = pos.z;
-	m[15] = 1.0;
-}
-
-//-----------------------------------------------------------------------------
-float Matrix4x4::get_determinant() const
-{
-	float det;
-
-	float m02m07_m06m03 = m[2] * m[7] - m[6] * m[3];
-	float m02m11_m10m03 = m[2] * m[11] - m[10] * m[3];
-	float m02m15_m14m03 = m[2] * m[15] - m[14] * m[3];
-	float m06m11_m10m07 = m[6] * m[11] - m[10] * m[7];
-	float m06m15_m14m07 = m[6] * m[15] - m[14] * m[7];
-	float m10m15_m14m11 = m[10] * m[15] - m[14] * m[11];
-
-	det = 	+ m[0] * (m[5] * m10m15_m14m11 - m[9] * m06m15_m14m07 + m[13] * m06m11_m10m07)
-			- m[4] * (m[1] * m10m15_m14m11 - m[9] * m02m15_m14m03 + m[13] * m02m11_m10m03)
-			+ m[8] * (m[1] * m06m15_m14m07 - m[5] * m02m15_m14m03 + m[13] * m02m07_m06m03)
-			- m[12] * (m[1] * m06m11_m10m07 - m[5] * m02m11_m10m03 + m[9] * m02m07_m06m03);
-
-	return det;
-}
-
-//-----------------------------------------------------------------------------
-Matrix4x4& Matrix4x4::invert()
-{
-	Matrix4x4 mat;
-	float det;
-
-	float m01m06_m05m02 = m[1] * m[6] - m[5] * m[2];
-	float m01m07_m05m03 = m[1] * m[7] - m[5] * m[3];
-	float m01m10_m09m02 = m[1] * m[10] - m[9] * m[2];
-	float m01m11_m09m03 = m[1] * m[11] - m[9] * m[3];
-	float m01m14_m13m02 = m[1] * m[14] - m[13] * m[2];
-	float m01m15_m13m03 = m[1] * m[15] - m[13] * m[3];
-	float m02m07_m06m03 = m[2] * m[7] - m[6] * m[3];
-	float m02m11_m10m03 = m[2] * m[11] - m[10] * m[3];
-	float m02m15_m14m03 = m[2] * m[15] - m[14] * m[3];
-	float m05m10_m09m06 = m[5] * m[10] - m[9] * m[6];
-	float m05m11_m09m07 = m[5] * m[11] - m[9] * m[7];
-	float m05m14_m13m06 = m[5] * m[14] - m[13] * m[6];
-	float m05m15_m13m07 = m[5] * m[15] - m[13] * m[7];
-	float m06m11_m10m07 = m[6] * m[11] - m[10] * m[7];
-	float m06m15_m14m07 = m[6] * m[15] - m[14] * m[7];
-	float m09m14_m13m10 = m[9] * m[14] - m[13] * m[10];
-	float m09m15_m13m11 = m[9] * m[15] - m[13] * m[11];
-	float m10m15_m14m11 = m[10] * m[15] - m[14] * m[11];
-
-	mat.m[0] = (+ m[5] * m10m15_m14m11 - m[9] * m06m15_m14m07 + m[13] * m06m11_m10m07);
-	mat.m[1] = (+ m[1] * m10m15_m14m11 - m[9] * m02m15_m14m03 + m[13] * m02m11_m10m03);
-	mat.m[2] = (+ m[1] * m06m15_m14m07 - m[5] * m02m15_m14m03 + m[13] * m02m07_m06m03);
-	mat.m[3] = (+ m[1] * m06m11_m10m07 - m[5] * m02m11_m10m03 + m[9] * m02m07_m06m03);
-
-	det = m[0] * mat.m[0] - m[4] * mat.m[1] + m[8] * mat.m[2] - m[12] * mat.m[3];
-	det = (float)1.0 / det;
-
-	mat.m[4] = (+ m[4] * m10m15_m14m11 - m[8] * m06m15_m14m07 + m[12] * m06m11_m10m07);
-	mat.m[5] = (+ m[0] * m10m15_m14m11 - m[8] * m02m15_m14m03 + m[12] * m02m11_m10m03);
-	mat.m[6] = (+ m[0] * m06m15_m14m07 - m[4] * m02m15_m14m03 + m[12] * m02m07_m06m03);
-	mat.m[7] = (+ m[0] * m06m11_m10m07 - m[4] * m02m11_m10m03 + m[8] * m02m07_m06m03);
-	mat.m[8] = (+ m[4] * m09m15_m13m11 - m[8] * m05m15_m13m07 + m[12] * m05m11_m09m07);
-	mat.m[9] = (+ m[0] * m09m15_m13m11 - m[8] * m01m15_m13m03 + m[12] * m01m11_m09m03);
-	mat.m[10] = (+ m[0] * m05m15_m13m07 - m[4] * m01m15_m13m03 + m[12] * m01m07_m05m03);
-	mat.m[11] = (+ m[0] * m05m11_m09m07 - m[4] * m01m11_m09m03 + m[8] * m01m07_m05m03);
-	mat.m[12] = (+ m[4] * m09m14_m13m10 - m[8] * m05m14_m13m06 + m[12] * m05m10_m09m06);
-	mat.m[13] = (+ m[0] * m09m14_m13m10 - m[8] * m01m14_m13m02 + m[12] * m01m10_m09m02);
-	mat.m[14] = (+ m[0] * m05m14_m13m06 - m[4] * m01m14_m13m02 + m[12] * m01m06_m05m02);
-	mat.m[15] = (+ m[0] * m05m10_m09m06 - m[4] * m01m10_m09m02 + m[8] * m01m06_m05m02);
-
-	m[0] = + mat.m[0] * det;
-	m[1] = - mat.m[1] * det;
-	m[2] = + mat.m[2] * det;
-	m[3] = - mat.m[3] * det;
-	m[4] = - mat.m[4] * det;
-	m[5] = + mat.m[5] * det;
-	m[6] = - mat.m[6] * det;
-	m[7] = + mat.m[7] * det;
-	m[8] = + mat.m[8] * det;
-	m[9] = - mat.m[9] * det;
-	m[10] = + mat.m[10] * det;
-	m[11] = - mat.m[11] * det;
-	m[12] = - mat.m[12] * det;
-	m[13] = + mat.m[13] * det;
-	m[14] = - mat.m[14] * det;
-	m[15] = + mat.m[15] * det;
-
-	return *this;
-}
-
-//-----------------------------------------------------------------------------
-inline Matrix4x4 Matrix4x4::get_inverted() const
-{
-	Matrix4x4 tmp(*this);
-
-	return tmp.invert();
-}
-
-//-----------------------------------------------------------------------------
-void Matrix4x4::load_identity()
-{
-	m[0] = m[5] = m[10] = m[15] = 1.0;
-	m[1] = m[2] = m[3] = m[4] = m[6] = m[7] = m[8] = m[9] = m[11] = m[12] = m[13] = m[14] = 0.0;
-}
-
-//-----------------------------------------------------------------------------
-Vector3 Matrix4x4::x() const
-{
-	return Vector3(m[0], m[1], m[2]);
-}
-
-//-----------------------------------------------------------------------------
-Vector3 Matrix4x4::y() const
-{
-	return Vector3(m[4], m[5], m[6]);
-}
-
-//-----------------------------------------------------------------------------
-Vector3 Matrix4x4::z() const
-{
-	return Vector3(m[8], m[9], m[10]);
-}
-
-//-----------------------------------------------------------------------------
-void Matrix4x4::set_x(const Vector3& x)
-{
-	m[0] = x.x;
-	m[1] = x.y;
-	m[2] = x.z;
-}
-
-//-----------------------------------------------------------------------------
-void Matrix4x4::set_y(const Vector3& y)
-{
-	m[4] = y.x;
-	m[5] = y.y;
-	m[6] = y.z;
-}
-
-//-----------------------------------------------------------------------------
-void Matrix4x4::set_z(const Vector3& z)
-{
-	m[8] = z.x;
-	m[9] = z.y;
-	m[10] = z.z;
-}
-
-//-----------------------------------------------------------------------------
-Vector3 Matrix4x4::translation() const
-{
-	Vector3 tmp;
-
-	tmp.x = m[12];
-	tmp.y = m[13];
-	tmp.z = m[14];
-
-	return tmp;
-}
-
-//-----------------------------------------------------------------------------
-void Matrix4x4::set_translation(const Vector3& trans)
-{
-	m[12] = trans.x;
-	m[13] = trans.y;
-	m[14] = trans.z;
-}
-
-//-----------------------------------------------------------------------------
-Vector3 Matrix4x4::get_scale() const
-{
-	Vector3 tmp;
-
-	tmp.x = m[0];
-	tmp.y = m[5];
-	tmp.z = m[10];
-
-	return tmp;
-}
-
-//-----------------------------------------------------------------------------
-void Matrix4x4::set_scale(const Vector3& scale)
-{
-	m[0] = scale.x;
-	m[5] = scale.y;
-	m[10] = scale.z;
-}
-
-//-----------------------------------------------------------------------------
-float* Matrix4x4::to_float_ptr()
-{
-	return &m[0];
-}
-
-//-----------------------------------------------------------------------------
-const float* Matrix4x4::to_float_ptr() const
-{
-	return &m[0];
-}
-
-//-----------------------------------------------------------------------------
-Matrix3x3 Matrix4x4::to_matrix3x3() const
-{
-	Matrix3x3 tmp;
-
-	tmp.m[0] = m[0];
-	tmp.m[1] = m[1];
-	tmp.m[2] = m[2];
-	tmp.m[3] = m[4];
-	tmp.m[4] = m[5];
-	tmp.m[5] = m[6];
-	tmp.m[6] = m[8];
-	tmp.m[7] = m[9];
-	tmp.m[8] = m[10];
-
-	return tmp;
-}
-
-//-----------------------------------------------------------------------------
-Quaternion Matrix4x4::to_quaternion() const
-{
-	Quaternion tmp;
-	float fourWSquaredMinusOne = m[0] + m[5] + m[10];
-	float fourXSquaredMinusOne = m[0] - m[5] - m[10];
-	float fourYSquaredMinusOne = -m[0] + m[5] - m[10];
-	float fourZSquaredMinusOne = -m[0] - m[5] + m[10];
-	float fourMaxSquaredMinusOne = fourWSquaredMinusOne;
-	uint32_t index = 0;
-
-	if (fourXSquaredMinusOne > fourMaxSquaredMinusOne)
-	{
-		fourMaxSquaredMinusOne = fourXSquaredMinusOne;
-		index = 1;
-	}
-
-	if (fourYSquaredMinusOne > fourMaxSquaredMinusOne)
-	{
-		fourMaxSquaredMinusOne = fourYSquaredMinusOne;
-		index = 2;
-	}
-
-	if (fourZSquaredMinusOne > fourMaxSquaredMinusOne)
-	{
-		fourMaxSquaredMinusOne = fourZSquaredMinusOne;
-		index = 3;
-	}
-
-	float biggest = math::sqrt(fourMaxSquaredMinusOne + (float)1.0) * (float)0.5;
-	float mult = (float)0.25 / biggest;
-
-	switch (index)
-	{
-		case 0:
-			tmp.w = biggest;
-			tmp.x = (-m[9] + m[6]) * mult;
-			tmp.y = (-m[2] + m[8]) * mult;
-			tmp.z = (-m[4] + m[1]) * mult;
-			break;
-		case 1:
-			tmp.x = biggest;
-			tmp.w = (-m[9] + m[6]) * mult;
-			tmp.y = (-m[4] - m[1]) * mult;
-			tmp.z = (-m[2] - m[8]) * mult;
-			break;
-		case 2:
-			tmp.y = biggest;
-			tmp.w = (-m[2] + m[8]) * mult;
-			tmp.x = (-m[4] - m[1]) * mult;
-			tmp.z = (-m[9] - m[6]) * mult;
-			break;
-		case 3:
-			tmp.z = biggest;
-			tmp.w = (-m[4] + m[1]) * mult;
-			tmp.x = (-m[2] - m[8]) * mult;
-			tmp.y = (-m[9] - m[6]) * mult;
-			break;
-	}
-
-	return tmp;
-}
-
-} // namespace crown
-

+ 559 - 130
engine/core/math/Matrix4x4.h

@@ -26,174 +26,603 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 #pragma once
 
+#include "MathTypes.h"
+#include "Matrix3x3.h"
+#include "Quaternion.h"
+#include "Vector4.h"
 #include "Types.h"
 
 namespace crown
 {
 
-struct Matrix3x3;
-struct Quaternion;
-struct Vector3;
-struct Vector4;
-
-/// Column-major 4x4 matrix.
-/// 
-/// The engine uses column vectors for coordinate space transformations
-/// so you'll have to specify transformations in reverse order.
-/// e.g. (rotation * translation * vector) will produce the result of first translating
-/// and then rotating the vector.
-/// Also note that a column major matrix needs to be placed to the left of a
-/// vector by matrix multiplication, so, to multiply a vector by a matrix you'll have
-/// to write something like: matrix * vector. Since we are also using column vectors, inverting
-/// the operands would result in an impossible operation.
-/// 
-/// @a verbatim:
-///   X base vector
-///     | Y base vector
-///     |   | Z base vector
-///     |   |   | Translation vector
-///     |   |   |   |
-/// 1 [ Xx  Yx  Zx  Tx ]
-/// 2 | Xy  Yy  Zy  Ty |
-/// 3 | Xz  Yz  Zz  Tz |
-/// 4 [ 0   0   0   1  ]
-///     1   2   3   4
-struct Matrix4x4
-{
-
-public:
-
-	float				m[16];
-
-	/// Does nothing for efficiency.
-						Matrix4x4();	
-
-	/// Constructs from a set of float
-						Matrix4x4(float r1c1, float r2c1, float r3c1, float r4c1,
-									float r1c2, float r2c2, float r3c2, float r4c2,
-									float r1c3, float r2c3, float r3c3, float r4c3,
-									float r1c4, float r2c4, float r3c4, float r4c4);
-
-	/// Constructs from rotation @a r and position @a p.
-						Matrix4x4(const Quaternion& r, const Vector3& p);
-	
-	/// Contructs from the @a v array
-						Matrix4x4(const float v[16]);						
-						Matrix4x4(const Matrix4x4& a);					
+/// Adds the matrix @a a to @a b and returns the result.
+Matrix4x4 operator+(Matrix4x4 a, const Matrix4x4& b);
 
-	/// Assignment operator (copies the data)
-	Matrix4x4&			operator=(const Matrix4x4& a);					
+/// Subtracts the matrix @a b from @a a and returns the result.
+Matrix4x4 operator-(Matrix4x4 a, const Matrix4x4& b);
 
-	/// Random access by index
-	float				operator[](uint32_t i) const;
+/// Multiplies the matrix @a a by the scalar @a k and returns the result.
+Matrix4x4 operator*(Matrix4x4 a, float k);
 
-	/// Random access by index					
-	float&				operator[](uint32_t i);							
+/// @copydoc operator*(Matrix4x4, float)
+Matrix4x4 operator*(float k, Matrix4x4 a);
 
-	float				operator()(uint32_t row, uint32_t column) const;	//!< Random access by row/column pair
+/// Divides the matrix @a a by the scalar @a k and returns the result.
+Matrix4x4 operator/(Matrix4x4 a, float k);
 
-	Matrix4x4			operator+(const Matrix4x4& a) const;
-	Matrix4x4&			operator+=(const Matrix4x4& a);					
-	Matrix4x4			operator-(const Matrix4x4& a) const;				
-	Matrix4x4&			operator-=(const Matrix4x4& a);					
-	Matrix4x4			operator*(float k) const;				
-	Matrix4x4&			operator*=(float k);							
-	Matrix4x4			operator/(float k) const;					
-	Matrix4x4&			operator/=(float k);							
-	Vector3				operator*(const Vector3& v) const;				
-	Vector4				operator*(const Vector4& v) const;				
-	Matrix4x4			operator*(const Matrix4x4& a) const;			
-	Matrix4x4&			operator*=(const Matrix4x4& a);
+/// Multiplies the matrix @a a by the vector @a v and returns the result.
+Vector3 operator*(const Matrix4x4& a, const Vector3& v);
 
-	/// For simmetry
-	friend Matrix4x4	operator*(float k, const Matrix4x4& a);			
+/// Multiplies the matrix @a by the vector @a v and returns the result.
+Vector4 operator*(const Matrix4x4& a, const Vector4& v);
 
-	/// Builds a rotation matrix about the X axis of @a radians radians
-	void				build_rotation_x(float radians);
+/// Multiplies the matrix @a a by @a b and returns the result. (i.e. transforms first by @a b then by @a a)
+Matrix4x4 operator*(Matrix4x4 a, const Matrix4x4& b);
 
-	/// Builds a rotation matrix about the Y axis of "radians" radians	
-	void				build_rotation_y(float radians);	
+/// Functions to manipulate Matrix4x4.
+///
+/// @ingroup Math
+namespace matrix4x4
+{
+	const Matrix4x4 IDENTITY = Matrix4x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0);
 
-	/// Builds a rotation matrix about the Z axis of @a radians radians			
-	void				build_rotation_z(float radians);		
+	/// Sets the rotation portion of the matrix @a m.
+	void set_rotation(Matrix4x4& m, const Quaternion& rot);
 
-	/// Builds a rotation matrix about an arbitrary axis of "radians" radians		
-	void				build_rotation(const Vector3& n, float radians);
+	/// Sets the rotation portion of the matrix @a m.
+	void set_rotation(Matrix4x4& m, const Matrix3x3& rot);
 
-	/// Sets the rotation portion to the rotation described by @a rot.
-	void				set_rotation(const Quaternion& rot);
+	/// Sets the matrix @a m to perspective. (Right-Handed coordinate systems)
+	void set_perspective_rh(Matrix4x4& m, float fovy, float aspect, float near, float far);
 
-	/// Sets the rotation portion to the rotation described by @a rot.
-	void				set_rotation(const Matrix3x3& rot);
+	/// Sets the matrix @a m to orthographic. (Right-Handed coordinate systems)
+	void set_orthographic_rh(Matrix4x4& m, float left, float right, float bottom, float top, float near, float far);
 
-	/// Builds a perspetive projection matrix suited to Right-Handed coordinate systems
-	void				build_projection_perspective_rh(float fovy, float aspect, float near, float far);
+	/// Sets the matrix @a m to look. (Right-Handed coordinate systems)
+	void set_look_rh(Matrix4x4& m, const Vector3& pos, const Vector3& target, const Vector3& up);
 
-	/// Builds an orthographic projection matrix suited to Right-Handed coordinate systems	
-	void				build_projection_ortho_rh(float left, float right, float bottom, float top, float near, float far);
+	/// Transposes the matrix @a m and returns the result.
+	Matrix4x4& transpose(Matrix4x4& m);					
 
-	/// Builds a "Righ-Handed look-at" matrix from a position, a target, and an up vector
-	void				build_look_at_rh(const Vector3& pos, const Vector3& target, const Vector3& up);
+	/// Returns the transposed of the matrix @a m.			
+	Matrix4x4 get_transposed(Matrix4x4 m);
 
-	/// Builds a "Viewpoint-Oriented billboard" matrix which can be used to make an object face a specific point in space	
-	void				build_viewpoint_billboard(const Vector3& pos, const Vector3& target, const Vector3& up);	
+	/// Returns the determinant of the matrix @a m.						
+	float determinant(const Matrix4x4& m);
 
-	/// Builds a "Arbitrary-Axis billboard" matrix which can be used to make an object face a specific point in space
-	void				build_axis_billboard(const Vector3& pos, const Vector3& target, const Vector3& axis);	
+	/// Inverts the matrix @a m and returns the result.
+	Matrix4x4& invert(Matrix4x4& m);
 
-	Matrix4x4&			transpose();								
-	Matrix4x4			get_transposed() const;						
-	float				get_determinant() const;					
-	Matrix4x4&			invert();									
-	Matrix4x4			get_inverted() const;						
+	/// Returns the inverse of the matrix @a m.				
+	Matrix4x4 get_inverted(Matrix4x4 m);
 
-	/// Builds the identity matrix
-	void				load_identity();							
+	/// Sets the matrix @a m to identity.
+	void set_identity(Matrix4x4& m);
 
-	/// Returns a Vector3 containing the matrix's x base vector.
-	Vector3				x() const;
+	/// Returns the x asis of the matrix @a m.
+	Vector3 x(const Matrix4x4& m);
 
-	/// Returns a Vector3 containing the matrix's y base vector.
-	Vector3				y() const;
+	/// Returns the y axis of the matrix @a m.
+	Vector3 y(const Matrix4x4& m);
 
-	/// Returns a Vector3 containing the matrix's z base vector.
-	Vector3				z() const;
+	/// Returns the z axis of the matrix @a m.
+	Vector3 z(const Matrix4x4& m);
 
-	/// Sets the matrix's x base vector.
-	void				set_x(const Vector3& x);
+	/// Sets the x axis of the matrix @a m.
+	void set_x(Matrix4x4& m, const Vector3& x);
 
-	/// Sets the matrix's y base vector.
-	void				set_y(const Vector3& y);
+	/// Sets the y axis of the matrix @a m.
+	void set_y(Matrix4x4& m, const Vector3& y);
 
-	/// Sets the matrix's z base vector.
-	void				set_z(const Vector3& z);
+	/// Sets the z axis of the matrix @a m.
+	void set_z(Matrix4x4& m, const Vector3& z);
 
-	/// Returns a Vector3 containing the matrix's translation portion
-	Vector3				translation() const;	
+	/// Returns the translation portion of the matrix @a m.
+	Vector3 translation(const Matrix4x4& m);	
 
-	/// Fills the matrix's translation portion values contained in @a trans				
-	void				set_translation(const Vector3& trans);			
+	/// Sets the translation portion of the matrix @a m.
+	void set_translation(Matrix4x4& m, const Vector3& trans);
 
-	/// Returns a Vector3 containing the matrix's scale portion
-	Vector3				get_scale() const;
+	/// Returns the pointer to the matrix's data
+	float* to_float_ptr(Matrix4x4& m);
 
-	/// Fills the matrix's scale portion with the values contained in @a scale							
-	void				set_scale(const Vector3& scale);				
+	/// Returns the pointer to the first elemento of the matrix @a m.
+	const float* to_float_ptr(const Matrix4x4& m);
 
-	/// Returns the pointer to the matrix's data
-	float*				to_float_ptr();
+	/// Returns the rotation portion of the matrix @a m as a Matrix3x3.
+	Matrix3x3 to_matrix3x3(const Matrix4x4& m);
 
-	/// Returns the pointer to the matrix's data
-	const float*		to_float_ptr() const;
+	/// Returns the rotation portion of the matrix @a m as a Quaternion.
+	Quaternion to_quaternion(const Matrix4x4& m);
+} // namespace matrix4x4
 
-	/// Returns a 3x3 matrix according to the matrix's rotation portion
-	Matrix3x3			to_matrix3x3() const;
+inline Matrix4x4 operator+(Matrix4x4 a, const Matrix4x4& b)
+{
+	a += b;
+	return a;
+}
 
-	/// Returns a quaternion according to the matrix's rotation portion
-	Quaternion			to_quaternion() const;
+inline Matrix4x4 operator-(Matrix4x4 a, const Matrix4x4& b)
+{
+	a -= b;
+	return a;
+}
 
-	static const Matrix4x4	IDENTITY;
-};
+inline Matrix4x4 operator*(Matrix4x4 a, float k)
+{
+	a *= k;
+	return a;
+}
 
-} // namespace crown
+inline Matrix4x4 operator*(float k, Matrix4x4 a)
+{
+	a *= k;
+	return a;
+}
+
+inline Matrix4x4 operator/(Matrix4x4 a, float k)
+{
+	a /= k;
+	return a;
+}
+
+inline Vector3 operator*(const Matrix4x4& a, const Vector3& v)
+{
+	Vector3 tmp;
+
+	tmp.x = a.x.x * v.x + a.y.x * v.y + a.z.x * v.z + a.t.x;
+	tmp.y = a.x.y * v.x + a.y.y * v.y + a.z.y * v.z + a.t.y;
+	tmp.z = a.x.z * v.x + a.y.z * v.y + a.z.z * v.z + a.t.z;
 
+	return tmp;
+}
+
+inline Vector4 operator*(const Matrix4x4& a, const Vector4& v)
+{
+	Vector4 tmp;
+
+	tmp.x = a.x.x * v.x + a.y.x * v.y + a.z.x * v.z + a.t.x * v.w;
+	tmp.y = a.x.y * v.x + a.y.y * v.y + a.z.y * v.z + a.t.y * v.w;
+	tmp.z = a.x.z * v.x + a.y.z * v.y + a.z.z * v.z + a.t.z * v.w;
+	tmp.w = a.x.w * v.x + a.y.w * v.y + a.z.w * v.z + a.t.w * v.w;
+
+	return tmp;
+}
+
+inline Matrix4x4 operator*(Matrix4x4 a, const Matrix4x4& b)
+{
+	a *= b;
+	return a;
+}
+
+namespace matrix4x4
+{
+	//-----------------------------------------------------------------------------
+	inline void set_rotation(Matrix4x4& m, const Quaternion& rot)
+	{
+		set_rotation(m, quaternion::to_matrix3x3(rot));
+	}
+
+	//-----------------------------------------------------------------------------
+	inline void set_rotation(Matrix4x4& m, const Matrix3x3& rot)
+	{
+		m.x.x = rot.x.x;
+		m.x.y = rot.x.y;
+		m.x.z = rot.x.z;
+		m.y.x = rot.y.x;
+		m.y.y = rot.y.y;
+		m.y.y = rot.y.z;
+		m.z.x = rot.z.x;
+		m.z.y = rot.z.y;
+		m.z.z = rot.z.z;
+	}
+
+	//-----------------------------------------------------------------------------
+	inline void set_perspective_rh(Matrix4x4& m, float fovy, float aspect, float near, float far)
+	{
+		const double top = math::tan(((double)fovy / 360.0 * math::PI)) * (double)near;
+		const double right = top * aspect;
+
+		m.x = Vector4(near / right, 0, 0, 0);
+		m.y = Vector4(0, near / top, 0, 0);
+		m.z = Vector4(0, 0, (far + near) / (near - far), -1);
+		m.t = Vector4(0, 0, (2.0 * far * near) / (near - far), 0);
+	}
+
+	//-----------------------------------------------------------------------------
+	inline void set_orthographic_rh(Matrix4x4& m, float left, float right, float bottom, float top, float near, float far)
+	{
+		m.x = Vector4(2.0 / (right - left), 0, 0, 0);
+		m.y = Vector4(0, 2.0 / (top - bottom), 0, 0);
+		m.z = Vector4(0, 0, -2.0 / (far - near), 0);
+		m.t = Vector4(-((right + left) / (right - left)), -((top + bottom) / (top - bottom)), -((far + near) / (far - near)), 1.0);
+	}
+
+	//-----------------------------------------------------------------------------
+	inline Matrix4x4& transpose(Matrix4x4& m)
+	{
+		float tmp;
+
+		tmp = m.x.y;
+		m.x.y = m.y.x;
+		m.y.x = tmp;
+
+		tmp = m.x.z;
+		m.x.z = m.z.x;
+		m.z.x = tmp;
+
+		tmp = m.x.w;
+		m.x.w = m.t.x;
+		m.t.x = tmp;
+
+		tmp = m.y.z;
+		m.y.z = m.z.y;
+		m.z.y = tmp;
+
+		tmp = m.y.w;
+		m.y.w = m.t.y;
+		m.t.y = tmp;
+
+		tmp = m.z.w;
+		m.z.w = m.t.z;
+		m.t.z = tmp;
+
+		return m;
+	}
+
+	//-----------------------------------------------------------------------------
+	inline Matrix4x4 get_transposed(Matrix4x4 m)
+	{
+		transpose(m);
+		return m;
+	}
+
+	//-----------------------------------------------------------------------------
+	inline void set_look_rh(Matrix4x4& m, const Vector3& pos, const Vector3& target, const Vector3& up)
+	{
+		Vector3 zAxis = pos - target;
+		vector3::normalize(zAxis);
+		const Vector3 xAxis = vector3::cross(up, zAxis);
+		const Vector3 yAxis = vector3::cross(zAxis, xAxis);
+
+		m.x.x= xAxis.x;
+		m.x.y= yAxis.x;
+		m.x.z= zAxis.x;
+		m.x.w= 0;
+
+		m.y.x= xAxis.y;
+		m.y.y= yAxis.y;
+		m.y.z= zAxis.y;
+		m.y.w= 0;
+
+		m.z.x= xAxis.z;
+		m.z.y= yAxis.z;
+		m.z.z= zAxis.z;
+		m.z.w= 0;
+
+		m.t.x= -vector3::dot(pos, xAxis);
+		m.t.y= -vector3::dot(pos, yAxis);
+		m.t.z= -vector3::dot(pos, zAxis);
+		m.t.w= 1;
+	}
+
+	//-----------------------------------------------------------------------------
+	inline float determinant(const Matrix4x4& m)
+	{
+		const float m02m07_m06m03 = m.x.z * m.y.w - m.y.z * m.x.w;
+		const float m02m11_m10m03 = m.x.z * m.z.w - m.z.z * m.x.w;
+		const float m02m15_m14m03 = m.x.z * m.t.w - m.t.z * m.x.w;
+		const float m06m11_m10m07 = m.y.z * m.z.w - m.z.z * m.y.w;
+		const float m06m15_m14m07 = m.y.z * m.t.w - m.t.z * m.y.w;
+		const float m10m15_m14m11 = m.z.z * m.t.w - m.t.z * m.z.w;
+
+		return 	+ m.x.x * (m.y.y * m10m15_m14m11 - m.z.y * m06m15_m14m07 + m.t.y * m06m11_m10m07)
+				- m.y.x * (m.x.y * m10m15_m14m11 - m.z.y * m02m15_m14m03 + m.t.y * m02m11_m10m03)
+				+ m.z.x * (m.x.y * m06m15_m14m07 - m.y.y * m02m15_m14m03 + m.t.y * m02m07_m06m03)
+				- m.t.x * (m.x.y * m06m11_m10m07 - m.y.y * m02m11_m10m03 + m.z.y * m02m07_m06m03);
+	}
+
+	//-----------------------------------------------------------------------------
+	inline Matrix4x4& invert(Matrix4x4& m)
+	{
+		Matrix4x4 mat;
+
+		const float m01m06_m05m02 = m.x.y * m.y.z - m.y.y * m.x.z;
+		const float m01m07_m05m03 = m.x.y * m.y.w - m.y.y * m.x.w;
+		const float m01m10_m09m02 = m.x.y * m.z.z - m.z.y * m.x.z;
+		const float m01m11_m09m03 = m.x.y * m.z.w - m.z.y * m.x.w;
+		const float m01m14_m13m02 = m.x.y * m.t.z - m.t.y * m.x.z;
+		const float m01m15_m13m03 = m.x.y * m.t.w - m.t.y * m.x.w;
+		const float m02m07_m06m03 = m.x.z * m.y.w - m.y.z * m.x.w;
+		const float m02m11_m10m03 = m.x.z * m.z.w - m.z.z * m.x.w;
+		const float m02m15_m14m03 = m.x.z * m.t.w - m.t.z * m.x.w;
+		const float m05m10_m09m06 = m.y.y * m.z.z - m.z.y * m.y.z;
+		const float m05m11_m09m07 = m.y.y * m.z.w - m.z.y * m.y.w;
+		const float m05m14_m13m06 = m.y.y * m.t.z - m.t.y * m.y.z;
+		const float m05m15_m13m07 = m.y.y * m.t.w - m.t.y * m.y.w;
+		const float m06m11_m10m07 = m.y.z * m.z.w - m.z.z * m.y.w;
+		const float m06m15_m14m07 = m.y.z * m.t.w - m.t.z * m.y.w;
+		const float m09m14_m13m10 = m.z.y * m.t.z - m.t.y * m.z.z;
+		const float m09m15_m13m11 = m.z.y * m.t.w - m.t.y * m.z.w;
+		const float m10m15_m14m11 = m.z.z * m.t.w - m.t.z * m.z.w;
+
+		mat.x.x = (+ m.y.y * m10m15_m14m11 - m.z.y * m06m15_m14m07 + m.t.y * m06m11_m10m07);
+		mat.x.y = (+ m.x.y * m10m15_m14m11 - m.z.y * m02m15_m14m03 + m.t.y * m02m11_m10m03);
+		mat.x.z = (+ m.x.y * m06m15_m14m07 - m.y.y * m02m15_m14m03 + m.t.y * m02m07_m06m03);
+		mat.x.w = (+ m.x.y * m06m11_m10m07 - m.y.y * m02m11_m10m03 + m.z.y * m02m07_m06m03);
+
+		const float inv_det = 1.0 / (m.x.x * mat.x.x - m.y.x * mat.x.y + m.z.x * mat.x.z - m.t.x * mat.x.w);
+
+		mat.y.x = (+ m.y.x * m10m15_m14m11 - m.z.x * m06m15_m14m07 + m.t.x * m06m11_m10m07);
+		mat.y.y = (+ m.x.x * m10m15_m14m11 - m.z.x * m02m15_m14m03 + m.t.x * m02m11_m10m03);
+		mat.y.z = (+ m.x.x * m06m15_m14m07 - m.y.x * m02m15_m14m03 + m.t.x * m02m07_m06m03);
+		mat.y.w = (+ m.x.x * m06m11_m10m07 - m.y.x * m02m11_m10m03 + m.z.x * m02m07_m06m03);
+		mat.z.x = (+ m.y.x * m09m15_m13m11 - m.z.x * m05m15_m13m07 + m.t.x * m05m11_m09m07);
+		mat.z.y = (+ m.x.x * m09m15_m13m11 - m.z.x * m01m15_m13m03 + m.t.x * m01m11_m09m03);
+		mat.z.z = (+ m.x.x * m05m15_m13m07 - m.y.x * m01m15_m13m03 + m.t.x * m01m07_m05m03);
+		mat.z.w = (+ m.x.x * m05m11_m09m07 - m.y.x * m01m11_m09m03 + m.z.x * m01m07_m05m03);
+		mat.t.x = (+ m.y.x * m09m14_m13m10 - m.z.x * m05m14_m13m06 + m.t.x * m05m10_m09m06);
+		mat.t.y = (+ m.x.x * m09m14_m13m10 - m.z.x * m01m14_m13m02 + m.t.x * m01m10_m09m02);
+		mat.t.z = (+ m.x.x * m05m14_m13m06 - m.y.x * m01m14_m13m02 + m.t.x * m01m06_m05m02);
+		mat.t.w = (+ m.x.x * m05m10_m09m06 - m.y.x * m01m10_m09m02 + m.z.x * m01m06_m05m02);
+
+		m.x.x = + mat.x.x * inv_det;
+		m.x.y = - mat.x.y * inv_det;
+		m.x.z = + mat.x.z * inv_det;
+		m.x.w = - mat.x.w * inv_det;
+		m.y.x = - mat.y.x * inv_det;
+		m.y.y = + mat.y.y * inv_det;
+		m.y.z = - mat.y.z * inv_det;
+		m.y.w = + mat.y.w * inv_det;
+		m.z.x = + mat.z.x * inv_det;
+		m.z.y = - mat.z.y * inv_det;
+		m.z.z = + mat.z.z * inv_det;
+		m.z.w = - mat.z.w * inv_det;
+		m.t.x = - mat.t.x * inv_det;
+		m.t.y = + mat.t.y * inv_det;
+		m.t.z = - mat.t.z * inv_det;
+		m.t.w = + mat.t.w * inv_det;
+
+		return m;
+	}
+
+	//-----------------------------------------------------------------------------
+	inline Matrix4x4 get_inverted(Matrix4x4 m)
+	{
+		invert(m);
+		return m;
+	}
+
+	//-----------------------------------------------------------------------------
+	inline void set_identity(Matrix4x4& m)
+	{
+		m.x = Vector4(1, 0, 0, 0);
+		m.y = Vector4(0, 1, 0, 0);
+		m.z = Vector4(0, 0, 1, 0);
+		m.t = Vector4(0, 0, 0, 1);
+	}
+
+	//-----------------------------------------------------------------------------
+	inline Vector3 x(const Matrix4x4& m)
+	{
+		return Vector3(m.x.x, m.x.y, m.x.z);
+	}
+
+	//-----------------------------------------------------------------------------
+	inline Vector3 y(const Matrix4x4& m)
+	{
+		return Vector3(m.y.x, m.y.y, m.y.z);
+	}
+
+	//-----------------------------------------------------------------------------
+	inline Vector3 z(const Matrix4x4& m)
+	{
+		return Vector3(m.z.x, m.z.y, m.z.z);
+	}
+
+	//-----------------------------------------------------------------------------
+	inline void set_x(Matrix4x4& m, const Vector3& x)
+	{
+		m.x.x = x.x;
+		m.x.y = x.y;
+		m.x.z = x.z;
+	}
+
+	//-----------------------------------------------------------------------------
+	inline void set_y(Matrix4x4& m, const Vector3& y)
+	{
+		m.y.x = y.x;
+		m.y.y = y.y;
+		m.y.z = y.z;
+	}
+
+	//-----------------------------------------------------------------------------
+	inline void set_z(Matrix4x4& m, const Vector3& z)
+	{
+		m.z.x = z.x;
+		m.z.y = z.y;
+		m.z.z = z.z;
+	}
+
+	//-----------------------------------------------------------------------------
+	inline Vector3 translation(const Matrix4x4& m)
+	{
+		return Vector3(m.t.x, m.t.y, m.t.z);
+	}
+
+	//-----------------------------------------------------------------------------
+	inline void set_translation(Matrix4x4& m, const Vector3& trans)
+	{
+		m.t.x = trans.x;
+		m.t.y = trans.y;
+		m.t.z = trans.z;
+	}
+
+	//-----------------------------------------------------------------------------
+	inline float* to_float_ptr(Matrix4x4& m)
+	{
+		return vector4::to_float_ptr(m.x);
+	}
+
+	//-----------------------------------------------------------------------------
+	inline const float* to_float_ptr(const Matrix4x4& m)
+	{
+		return vector4::to_float_ptr(m.x);
+	}
+
+	//-----------------------------------------------------------------------------
+	inline Matrix3x3 to_matrix3x3(const Matrix4x4& m)
+	{
+		return Matrix3x3(x(m), y(m), z(m));
+	}
+
+	//-----------------------------------------------------------------------------
+	inline Quaternion to_quaternion(const Matrix4x4& m)
+	{
+		return matrix3x3::to_quaternion(to_matrix3x3(m));
+	}
+} // namespace matrix4x4
+
+//-----------------------------------------------------------------------------
+inline Matrix4x4::Matrix4x4()
+{
+	// Do not initialize
+}
+
+inline Matrix4x4::Matrix4x4(const Vector3& x, const Vector3& y, const Vector3& z, const Vector3& t)
+	: x(x, 0), y(y, 0), z(z, 0), t(t, 1)
+{
+}
+
+//-----------------------------------------------------------------------------
+inline Matrix4x4::Matrix4x4(float r1c1, float r2c1, float r3c1, float r4c1,
+							float r1c2, float r2c2, float r3c2, float r4c2,
+							float r1c3, float r2c3, float r3c3, float r4c3,
+							float r1c4, float r2c4, float r3c4, float r4c4)
+	: x(r1c1, r2c1, r3c1, r4c1)
+	, y(r1c2, r2c2, r3c2, r4c2)
+	, z(r1c3, r2c3, r3c3, r4c3)
+	, t(r1c4, r2c4, r3c4, r4c4)
+{
+}
+
+//-----------------------------------------------------------------------------
+inline Matrix4x4::Matrix4x4(const Quaternion& r, const Vector3& p)
+	: x(1.0 - 2.0 * r.y * r.y - 2.0 * r.z * r.z, 2.0 * r.x * r.y + 2.0 * r.w * r.z, 2.0 * r.x * r.z - 2.0 * r.w * r.y, 0)
+	, y(2.0 * r.x * r.y - 2.0 * r.w * r.z, 1.0 - 2.0 * r.x * r.x - 2.0 * r.z * r.z, 2.0 * r.y * r.z + 2.0 * r.w * r.x, 0)
+	, z(2.0 * r.x * r.z + 2.0 * r.w * r.y, 2.0 * r.y * r.z - 2.0 * r.w * r.x, 1.0 - 2.0 * r.x * r.x - 2.0 * r.y * r.y, 0)
+	, t(p, 1)
+{
+}
+
+//-----------------------------------------------------------------------------
+inline Matrix4x4::Matrix4x4(const Matrix3x3& m)
+	: x(m.x, 0)
+	, y(m.y, 0)
+	, z(m.z, 0)
+	, t(0, 0, 0, 1)
+{
+}
+
+//-----------------------------------------------------------------------------
+inline Matrix4x4::Matrix4x4(const float v[16])
+	: x(v[0], v[1], v[2], v[3])
+	, y(v[4], v[5], v[6], v[7])
+	, z(v[8], v[9], v[10], v[11])
+	, t(v[12], v[13], v[14], v[15])
+{
+}
+
+//-----------------------------------------------------------------------------
+inline float& Matrix4x4::operator[](uint32_t i)
+{
+	CE_ASSERT(i < 16, "Index out of bounds");
+
+	return vector4::to_float_ptr(x)[i];
+}
+
+//-----------------------------------------------------------------------------
+inline const float& Matrix4x4::operator[](uint32_t i) const
+{
+	CE_ASSERT(i < 16, "Index out of bounds");
+
+	return vector4::to_float_ptr(x)[i];
+}
+
+//-----------------------------------------------------------------------------
+inline Matrix4x4& Matrix4x4::operator+=(const Matrix4x4& a)
+{
+	x += a.x;
+	y += a.y;
+	z += a.z;
+	t += a.t;
+
+	return *this;
+}
+
+//-----------------------------------------------------------------------------
+inline Matrix4x4& Matrix4x4::operator-=(const Matrix4x4& a)
+{
+	x -= a.x;
+	y -= a.y;
+	z -= a.z;
+	t -= a.t;
+
+	return *this;
+}
+
+//-----------------------------------------------------------------------------
+inline Matrix4x4& Matrix4x4::operator*=(float k)
+{
+	x *= k;
+	y *= k;
+	z *= k;
+	t *= k;
+
+	return *this;
+}
+
+//-----------------------------------------------------------------------------
+inline Matrix4x4& Matrix4x4::operator/=(float k)
+{
+	const float inv_k = 1.0 / k;
+	
+	x *= inv_k;
+	y *= inv_k;
+	z *= inv_k;
+	t *= inv_k;
+
+	return *this;
+}
+
+//-----------------------------------------------------------------------------
+inline Matrix4x4& Matrix4x4::operator*=(const Matrix4x4& a)
+{
+	Matrix4x4 tmp;
+
+	tmp.x.x = x.x * a.x.x + y.x * a.x.y + z.x * a.x.z + t.x * a.x.w;
+	tmp.x.y = x.y * a.x.x + y.y * a.x.y + z.y * a.x.z + t.y * a.x.w;
+	tmp.x.z = x.z * a.x.x + y.z * a.x.y + z.z * a.x.z + t.z * a.x.w;
+	tmp.x.w = x.w * a.x.x + y.w * a.x.y + z.w * a.x.z + t.w * a.x.w;
+
+	tmp.y.x = x.x * a.y.x + y.x * a.y.y + z.x * a.y.z + t.x * a.y.w;
+	tmp.y.y = x.y * a.y.x + y.y * a.y.y + z.y * a.y.z + t.y * a.y.w;
+	tmp.y.z = x.z * a.y.x + y.z * a.y.y + z.z * a.y.z + t.z * a.y.w;
+	tmp.y.w = x.w * a.y.x + y.w * a.y.y + z.w * a.y.z + t.w * a.y.w;
+
+	tmp.z.x = x.x * a.z.x + y.x * a.z.y + z.x * a.z.z + t.x * a.z.w;
+	tmp.z.y = x.y * a.z.x + y.y * a.z.y + z.y * a.z.z + t.y * a.z.w;
+	tmp.z.z = x.z * a.z.x + y.z * a.z.y + z.z * a.z.z + t.z * a.z.w;
+	tmp.z.w = x.w * a.z.x + y.w * a.z.y + z.w * a.z.z + t.w * a.z.w;
+
+	tmp.t.x = x.x * a.t.x + y.x * a.t.y + z.x * a.t.z + t.x * a.t.w;
+	tmp.t.y = x.y * a.t.x + y.y * a.t.y + z.y * a.t.z + t.y * a.t.w;
+	tmp.t.z = x.z * a.t.x + y.z * a.t.y + z.z * a.t.z + t.z * a.t.w;
+	tmp.t.w = x.w * a.t.x + y.w * a.t.y + z.w * a.t.z + t.w * a.t.w;
+
+	*this = tmp;
+
+	return *this;
+}
+
+} // namespace crown

+ 0 - 6
engine/core/math/Plane.h

@@ -85,12 +85,6 @@ inline Plane::Plane()
 	// Do not initialize
 }
 
-//-----------------------------------------------------------------------------
-inline Plane::Plane(const Plane& p)
-	: n(p.n), d(p.d)
-{
-}
-
 //-----------------------------------------------------------------------------
 inline Plane::Plane(const Vector3& normal, float dist)
 	: n(normal), d(dist)

+ 16 - 44
engine/core/math/Quaternion.h

@@ -30,7 +30,6 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "Vector3.h"
 #include "MathTypes.h"
 #include "Matrix3x3.h"
-#include "Matrix4x4.h"
 
 namespace crown
 {
@@ -134,53 +133,12 @@ namespace quaternion
 
 	inline Matrix3x3 to_matrix3x3(const Quaternion& q)
 	{
-		const float x = q.x;
-		const float y = q.y;
-		const float z = q.z;
-		const float w = q.w;
-
-		Matrix3x3 tmp;
-
-		tmp.m[0] = (float)(1.0 - 2.0*y*y - 2.0*z*z);
-		tmp.m[1] = (float)(2.0*x*y + 2.0*w*z);
-		tmp.m[2] = (float)(2.0*x*z - 2.0*w*y);
-		tmp.m[3] = (float)(2.0*x*y - 2.0*w*z);
-		tmp.m[4] = (float)(1.0 - 2.0*x*x - 2.0*z*z);
-		tmp.m[5] = (float)(2.0*y*z + 2.0*w*x);
-		tmp.m[6] = (float)(2.0*x*z + 2.0*w*y);
-		tmp.m[7] = (float)(2.0*y*z - 2.0*w*x);
-		tmp.m[8] = (float)(1.0 - 2.0*x*x - 2.0*y*y);
-
-		return tmp;
+		return Matrix3x3(q);
 	}
 
 	inline Matrix4x4 to_matrix4x4(const Quaternion& q)
 	{
-		const float x = q.x;
-		const float y = q.y;
-		const float z = q.z;
-		const float w = q.w;
-
-		Matrix4x4 tmp;
-
-		tmp.m[0] = (float)(1.0 - 2.0*y*y - 2.0*z*z);
-		tmp.m[1] = (float)(2.0*x*y + 2.0*w*z);
-		tmp.m[2] = (float)(2.0*x*z - 2.0*w*y);
-		tmp.m[3] = 0;
-		tmp.m[4] = (float)(2.0*x*y - 2.0*w*z);
-		tmp.m[5] = (float)(1.0 - 2.0*x*x - 2.0*z*z);
-		tmp.m[6] = (float)(2.0*y*z + 2.0*w*x);
-		tmp.m[7] = 0.0;
-		tmp.m[8] = (float)(2.0*x*z + 2.0*w*y);
-		tmp.m[9] = (float)(2.0*y*z - 2.0*w*x);
-		tmp.m[10] = (float)(1.0 - 2.0*x*x - 2.0*y*y);
-		tmp.m[11] = 0.0;
-		tmp.m[12] = 0.0;
-		tmp.m[13] = 0.0;
-		tmp.m[14] = 0.0;
-		tmp.m[15] = 1.0;
-
-		return tmp;
+		return Matrix4x4(q, Vector3(0, 0, 0));
 	}
 } // namespace quaternion
 
@@ -208,6 +166,20 @@ inline Quaternion::Quaternion(const Vector3& axis, float angle)
 {
 }
 
+//-----------------------------------------------------------------------------	
+inline float& Quaternion::operator[](uint32_t i)
+{
+	CE_ASSERT(i < 4, "Index out of bounds");
+	return (&x)[i];
+}
+
+//-----------------------------------------------------------------------------	
+inline const float& Quaternion::operator[](uint32_t i) const
+{
+	CE_ASSERT(i < 4, "Index out of bounds");
+	return (&x)[i];
+}
+
 //-----------------------------------------------------------------------------
 inline Quaternion& Quaternion::operator*=(const Quaternion& a)
 {

+ 3 - 8
engine/core/math/Vector2.h

@@ -218,14 +218,9 @@ inline Vector2::Vector2(const float a[2]) : x(a[0]), y(a[1])
 }
 
 //-----------------------------------------------------------------------------
-inline Vector2::Vector2(const Vector2& a) : x(a.x), y(a.y)
+inline const float& Vector2::operator[](uint32_t i) const
 {
-}
-
-//-----------------------------------------------------------------------------
-inline float Vector2::operator[](uint32_t i) const
-{
-	CE_ASSERT(i < 2, "Index must be < 2");
+	CE_ASSERT(i < 2, "Index out of bounds");
 
 	return (&x)[i];
 }
@@ -233,7 +228,7 @@ inline float Vector2::operator[](uint32_t i) const
 //-----------------------------------------------------------------------------
 inline float& Vector2::operator[](uint32_t i)
 {
-	CE_ASSERT(i < 2, "Index must be < 2");
+	CE_ASSERT(i < 2, "Index out of bounds");
 
 	return (&x)[i];
 }

+ 3 - 8
engine/core/math/Vector3.h

@@ -241,14 +241,9 @@ inline Vector3::Vector3(const float v[3]) : x(v[0]), y(v[1]), z(v[2])
 }
 
 //-----------------------------------------------------------------------------
-inline Vector3::Vector3(const Vector3& a) : x(a.x), y(a.y), z(a.z)
+inline const float& Vector3::operator[](uint32_t i) const
 {
-}
-
-//-----------------------------------------------------------------------------
-inline float Vector3::operator[](uint32_t i) const
-{
-	CE_ASSERT(i < 3, "Index must be < 3");
+	CE_ASSERT(i < 3, "Index out of bounds");
 
 	return (&x)[i];
 }
@@ -256,7 +251,7 @@ inline float Vector3::operator[](uint32_t i) const
 //-----------------------------------------------------------------------------
 inline float& Vector3::operator[](uint32_t i)
 {
-	CE_ASSERT(i < 3, "Index must be < 3");
+	CE_ASSERT(i < 3, "Index out of bounds");
 
 	return (&x)[i];
 }

+ 8 - 7
engine/core/math/Vector4.h

@@ -215,32 +215,33 @@ namespace vector4
 //-----------------------------------------------------------------------------
 inline Vector4::Vector4()
 {
+	// Do not initialize
 }
 
 //-----------------------------------------------------------------------------
-inline Vector4::Vector4(float val) : x(val), y(val), z(val), w(val)
+inline Vector4::Vector4(const Vector3& a, float w) : x(a.x), y(a.y), z(a.z), w(w)
 {
 }
 
 //-----------------------------------------------------------------------------
-inline Vector4::Vector4(float nx, float ny, float nz, float nw) : x(nx), y(ny), z(nz), w(nw)
+inline Vector4::Vector4(float val) : x(val), y(val), z(val), w(val)
 {
 }
 
 //-----------------------------------------------------------------------------
-inline Vector4::Vector4(const float a[4]) : x(a[0]), y(a[1]), z(a[2]), w(a[3])
+inline Vector4::Vector4(float nx, float ny, float nz, float nw) : x(nx), y(ny), z(nz), w(nw)
 {
 }
 
 //-----------------------------------------------------------------------------
-inline Vector4::Vector4(const Vector4& a) : x(a.x), y(a.y), z(a.z), w(a.w)
+inline Vector4::Vector4(const float a[4]) : x(a[0]), y(a[1]), z(a[2]), w(a[3])
 {
 }
 
 //-----------------------------------------------------------------------------
-inline float Vector4::operator[](uint32_t i) const
+inline const float& Vector4::operator[](uint32_t i) const
 {
-	CE_ASSERT(i < 4, "Index must be < 4");
+	CE_ASSERT(i < 4, "Index out of bounds");
 
 	return (&x)[i];
 }
@@ -248,7 +249,7 @@ inline float Vector4::operator[](uint32_t i) const
 //-----------------------------------------------------------------------------
 inline float& Vector4::operator[](uint32_t i)
 {
-	CE_ASSERT(i < 4, "Index must be < 4");
+	CE_ASSERT(i < 4, "Index out of bounds");
 
 	return (&x)[i];
 }

+ 1 - 1
engine/core/mem/TempAllocator.h

@@ -112,7 +112,7 @@ inline void* TempAllocator<SIZE>::allocate(size_t size, size_t align)
 {
 	m_cur = (char*) memory::align_top(m_cur, align);
 
-	if (size > m_end - m_cur)
+	if (size > size_t(m_end - m_cur))
 	{
 		uint32_t to_allocate = sizeof(void*) + size + align;
 

+ 5 - 0
engine/core/strings/StringUtils.h

@@ -32,6 +32,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "Assert.h"
 #include "Types.h"
 #include "Config.h"
+#include "Macros.h"
 
 namespace crown
 {
@@ -201,6 +202,7 @@ inline int32_t parse_int(const char* string)
 	int ok = sscanf(string, "%d", &val);
 
 	CE_ASSERT(ok == 1, "Failed to parse int: %s", string);
+	CE_UNUSED(ok);
 
 	return val;
 }
@@ -212,6 +214,7 @@ inline uint32_t parse_uint(const char* string)
 	int ok = sscanf(string, "%u", &val);
 
 	CE_ASSERT(ok == 1, "Failed to parse uint: %s", string);
+	CE_UNUSED(ok);
 
 	return val;
 }
@@ -223,6 +226,7 @@ inline float parse_float(const char* string)
 	int ok = sscanf(string, "%f", &val);
 
 	CE_ASSERT(ok == 1, "Failed to parse float: %s", string);
+	CE_UNUSED(ok);
 
 	return val;
 }
@@ -234,6 +238,7 @@ inline float parse_double(const char* string)
 	int ok = sscanf(string, "%lf", &val);
 
 	CE_ASSERT(ok == 1, "Failed to parse float: %s", string);
+	CE_UNUSED(ok);
 
 	return val;
 }

+ 0 - 470
engine/gui/Gui.cpp

@@ -1,470 +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 "Gui.h"
-#include "Assert.h"
-#include "Renderer.h"
-#include "Vector3.h"
-#include "Vector2.h"
-#include "GuiResource.h"
-#include "RenderWorld.h"
-#include "RendererTypes.h"
-#include "Vector3.h"
-#include "Vector2.h"
-#include "Color4.h"
-#include "FontResource.h"
-#include "Device.h"
-#include "OsWindow.h"
-
-#include "GuiRect.h"
-#include "GuiTriangle.h"
-#include "GuiImage.h"
-#include "GuiText.h"
-
-namespace crown
-{
-
-ShaderId			gui_default_vs;
-ShaderId			gui_default_fs;
-ShaderId			gui_texture_fs;
-GPUProgramId		gui_default_program;
-GPUProgramId		gui_texture_program;
-UniformId			gui_albedo_0;
-
-ShaderId			font_vs;
-ShaderId			font_fs;
-GPUProgramId		font_program;
-UniformId			font_uniform;
-
-static const char* default_vertex =
-	"precision mediump float;"
-	"uniform mat4      	u_model_view_projection;"
-
-	"attribute vec4    	a_position;"
-	"attribute vec2    	a_tex_coord0;"
-	"attribute vec4    	a_color;"
-
-	"varying vec2		tex_coord0;"
-	"varying vec4		color;"
-
-	"void main(void)"
-	"{"
-	"	tex_coord0 = a_tex_coord0;"
-	"   color = a_color;"
-	"	gl_Position = u_model_view_projection * a_position;"
-	"}";
-
-static const char* default_fragment =
-	"precision mediump float;"
-	"varying vec4            color;"
-
-	"void main(void)"
-	"{"
-	"	gl_FragColor = color;"
-	"}";
-
-static const char* texture_fragment = 
-	"precision mediump float;"
-	"varying vec2       tex_coord0;"
-	"varying vec4       color;"
-
-	"uniform sampler2D  u_albedo_0;"
-
-	"void main(void)"
-	"{"
-	"	gl_FragColor = texture2D(u_albedo_0, tex_coord0);"
-	"}";
-
-static const char* sdf_vertex =
-	"precision mediump float;"
-	"uniform mat4      	u_model_view_projection;"
-
-	"attribute vec4		a_position;"
-	"attribute vec2		a_tex_coord0;"
-
-	"varying vec2		v_tex_coord;"
-	"varying vec4		v_color;"
-
-	"void main(void)"
-	"{"
-	"	gl_Position = u_model_view_projection * a_position;"
-	"	v_tex_coord = a_tex_coord0;"
-	"	v_color = vec4(1, 1, 1, 1);"
-	"}";
-
-static const char* sdf_fragment =
-	"precision mediump float;"
-	"uniform sampler2D u_texture;"
-
-	"varying vec4 v_color;"
-	"varying vec2 v_tex_coord;"
-
-	"const float smoothing = 1.0/16.0;"
-
-	"void main() {"
-		"float distance = texture2D(u_texture, v_tex_coord).a;"
-		"float alpha = smoothstep(0.5 - smoothing, 0.5 + smoothing, distance);"
-		"gl_FragColor = vec4(v_color.rgb, alpha);"
-	"}";
-
-//-----------------------------------------------------------------------------
-Gui::Gui(RenderWorld& render_world, GuiResource* gr, Renderer& r)
-	: m_render_world(render_world)
-	, m_resource(gr)
-	, m_r(r)
-	, m_resolution(1000, 625)
-	, m_visible(true)
-	, m_rect_pool(default_allocator(), CE_MAX_GUI_RECTS, sizeof(GuiRect), CE_ALIGNOF(GuiRect))
-	, m_triangle_pool(default_allocator(), CE_MAX_GUI_TRIANGLES, sizeof(GuiTriangle), CE_ALIGNOF(GuiTriangle))
-	, m_image_pool(default_allocator(), CE_MAX_GUI_IMAGES, sizeof(GuiImage), CE_ALIGNOF(GuiImage))
-	, m_text_pool(default_allocator(), CE_MAX_GUI_TEXTS, sizeof(GuiText), CE_ALIGNOF(GuiText))
-{
-	// orthographic projection
-	m_projection.build_projection_ortho_rh(0, m_resolution.x, m_resolution.y, 0, -0.01f, 100.0f);
-
-	// pose
-	Vector3 pos = m_resource->gui_position();
-	m_pose.load_identity();
-	m_pose.set_translation(pos);
-
-	create_gfx();
-
-	// Gui's rects creation
-	for (uint32_t i = 0; i < m_resource->num_rects(); i++)
-	{
-		GuiRectData data = m_resource->get_rect(i);
-		Vector3 pos(data.position[0], data.position[1], data.position[2]);
-		Vector2 size(data.size[0], data.size[1]);
-		Color4 color(data.color[0], data.color[1], data.color[2], data.color[3]);
-	
-		create_rect(pos, size, color);	
-	}
-
-	// Gui's triangles creation
-	for (uint32_t i = 0; i < m_resource->num_triangles(); i++)
-	{
-		GuiTriangleData data = m_resource->get_triangle(i);
-		Vector2 p1(data.points[0], data.points[1]);
-		Vector2 p2(data.points[2], data.points[3]);
-		Vector2 p3(data.points[4], data.points[5]);
-		Color4 color(data.color[0], data.color[1], data.color[2], data.color[3]);
-
-		create_triangle(p1, p2, p3, color);
-	}
-
-	// Gui's images creation
-	for (uint32_t i = 0; i < m_resource->num_images(); i++)
-	{
-		GuiImageData data = m_resource->get_image(i);
-		ResourceId mat = data.material;
-		Vector3 pos(data.position[0], data.position[1], 0);
-		Vector2 size(data.size[0], data.size[1]);
-
-		create_image(mat, pos, size);
-	}
-}
-
-//-----------------------------------------------------------------------------
-Gui::~Gui()
-{
-	for (uint32_t i = 0; i < m_rects.size(); i++)
-	{
-		CE_DELETE(m_rect_pool, m_rects[i]);
-	}
-
-	for (uint32_t i = 0; i < m_triangles.size(); i++)
-	{
-		CE_DELETE(m_triangle_pool, m_triangles[i]);
-	}
-
-	for (uint32_t i = 0; i < m_images.size(); i++)
-	{
-		CE_DELETE(m_image_pool, m_images[i]);
-	}
-
-	for (uint32_t i = 0; i < m_texts.size(); i++)
-	{
-		CE_DELETE(m_text_pool, m_texts[i]);
-	}
-
-	destroy_gfx();
-}
-
-//-----------------------------------------------------------------------------
-const GuiId Gui::id() const
-{
-	return m_id;
-}
-
-//-----------------------------------------------------------------------------
-void Gui::set_id(const GuiId id)
-{
-	m_id = id;
-}
-
-//-----------------------------------------------------------------------------
-Vector2 Gui::resolution() const
-{
-	return m_resolution;
-}
-
-//-----------------------------------------------------------------------------
-void Gui::move(const Vector3& pos)
-{
-	m_pose.load_identity();
-	m_pose.set_translation(pos);
-}
-
-//-----------------------------------------------------------------------------
-void Gui::show()
-{
-	m_visible = true;
-}
-
-//-----------------------------------------------------------------------------
-void Gui::hide()
-{
-	m_visible = false;
-}
-
-//-----------------------------------------------------------------------------
-GuiRectId Gui::create_rect(const Vector3& pos, const Vector2& size, const Color4& color)
-{
-	GuiRect* rect = CE_NEW(m_rect_pool, GuiRect)(m_r, pos, size, color);
-	return m_rects.create(rect);
-}
-
-//-----------------------------------------------------------------------------
-void Gui::update_rect(GuiRectId id, const Vector3& pos, const Vector2& size, const Color4& color)
-{
-	CE_ASSERT(m_rects.has(id), "GuiRect does not exists");
-
-	GuiRect* rect = m_rects.lookup(id);
-	rect->update(pos, size, color);
-}
-
-//-----------------------------------------------------------------------------
-void Gui::destroy_rect(GuiRectId id)
-{
-	CE_ASSERT(m_rects.has(id), "GuiRect does not exist");
-
-	GuiRect* rect = m_rects.lookup(id);
-	CE_DELETE(m_rect_pool, rect);
-	m_rects.destroy(id);
-}
-
-//-----------------------------------------------------------------------------
-GuiTriangleId Gui::create_triangle(const Vector2& p1, const Vector2& p2, const Vector2& p3, const Color4& color)
-{
-	GuiTriangle* triangle = CE_NEW(m_triangle_pool, GuiTriangle)(m_r, p1, p2, p3, color);
-	return m_triangles.create(triangle);
-}
-
-//-----------------------------------------------------------------------------
-void Gui::update_triangle(GuiTriangleId id, const Vector2& p1, const Vector2& p2, const Vector2& p3, const Color4& color)
-{
-	CE_ASSERT(m_triangles.has(id), "GuiTriangle does not exists");
-
-	GuiTriangle* triangle = m_triangles.lookup(id);
-	triangle->update(p1, p2, p3, color);
-}
-
-//-----------------------------------------------------------------------------
-void Gui::destroy_triangle(GuiTriangleId id)
-{
-	CE_ASSERT(m_triangles.has(id), "GuiTriangle does not exist");
-
-	GuiTriangle* triangle = m_triangles.lookup(id);
-	CE_DELETE(m_triangle_pool, triangle);
-	m_triangles.destroy(id);
-}
-
-//-----------------------------------------------------------------------------
-GuiImageId Gui::create_image(ResourceId material, const Vector3& pos, const Vector2& size)
-{
-	GuiImage* image = CE_NEW(m_image_pool, GuiImage)(m_render_world, m_r, material, pos, size);
-	return m_images.create(image);
-}
-
-//-----------------------------------------------------------------------------
-void Gui::update_image(GuiImageId id, const Vector3& pos, const Vector2& size)
-{
-	CE_ASSERT(m_images.has(id), "GuiImage does not exists");
-
-	GuiImage* image = m_images.lookup(id);
-	image->update(pos, size);
-}
-
-//-----------------------------------------------------------------------------
-void Gui::destroy_image(GuiImageId id)
-{
-	CE_ASSERT(m_images.has(id), "GuiImage does not exists");
-
-	GuiImage* image = m_images.lookup(id);
-	CE_DELETE(m_image_pool, image);
-	m_images.destroy(id);
-}
-
-//-----------------------------------------------------------------------------
-GuiTextId Gui::create_text(const char* str, const FontResource* font, uint32_t font_size, const Vector3& pos)
-{
-	GuiText* text = CE_NEW(m_text_pool, GuiText)(m_render_world, m_r, str, font, font_size, pos);
-	return m_texts.create(text);
-}
-
-//-----------------------------------------------------------------------------
-void Gui::update_text(GuiTextId id, const char* str, uint32_t font_size, const Vector3& pos)
-{
-	CE_ASSERT(m_texts.has(id), "GuiText does not exists");
-
-	GuiText* text = m_texts.lookup(id);
-	text->update(str, font_size, pos);
-}
-
-//-----------------------------------------------------------------------------
-void Gui::destroy_text(GuiTextId id)
-{
-	CE_ASSERT(m_texts.has(id), "GuiText does not exists");
-
-	GuiText* text = m_texts.lookup(id);
-	CE_DELETE(m_text_pool, text);
-	m_texts.destroy(id);
-}
-
-//-----------------------------------------------------------------------------
-void Gui::render()
-{
-	// resolution
-	uint32_t width = 0;
-	uint32_t height = 0;
-	device()->window()->get_size(width, height);
-	m_resolution.x = width;
-	m_resolution.y = height;
-
-	m_r.set_layer_view(1, Matrix4x4::IDENTITY);
-	m_r.set_layer_projection(1, m_projection);
-	m_r.set_layer_viewport(1, m_pose.translation().x, m_pose.translation().y, m_resolution.x, m_resolution.y);
-
-	if (!m_visible) return;
-
-	// Render all Rects
-	for (uint32_t i = 0; i < m_rects.size(); i++)
-	{
-		m_r.set_program(gui_default_program);
-		m_r.set_state(STATE_DEPTH_WRITE 
-		| STATE_COLOR_WRITE
-		| STATE_ALPHA_WRITE
-		| STATE_CULL_CW
-		| STATE_PRIMITIVE_LINES
-		| STATE_BLEND_EQUATION_ADD 
-		| STATE_BLEND_FUNC(STATE_BLEND_FUNC_SRC_ALPHA, STATE_BLEND_FUNC_ONE_MINUS_SRC_ALPHA));
-		m_r.set_pose(m_pose);
-
-		m_rects[i]->render();
-	}
-
-	// Render all Triangles
-	for (uint32_t i = 0; i < m_triangles.size(); i++)
-	{
-		m_r.set_program(gui_default_program);
-		m_r.set_state(STATE_DEPTH_WRITE 
-		| STATE_COLOR_WRITE
-		| STATE_ALPHA_WRITE
-		| STATE_CULL_CW
-		| STATE_PRIMITIVE_LINES
-		| STATE_BLEND_EQUATION_ADD 
-		| STATE_BLEND_FUNC(STATE_BLEND_FUNC_SRC_ALPHA, STATE_BLEND_FUNC_ONE_MINUS_SRC_ALPHA));
-		m_r.set_pose(m_pose);
-
-		m_triangles[i]->render();
-	}
-
-	// Render all Images
-	for (uint32_t i = 0; i < m_images.size(); i++)
-	{
-		m_r.set_program(gui_texture_program);
-		m_r.set_state(STATE_DEPTH_WRITE 
-		| STATE_COLOR_WRITE 
-		| STATE_ALPHA_WRITE 
-		| STATE_CULL_CW
-		| STATE_PRIMITIVE_TRIANGLES
-		| STATE_BLEND_EQUATION_ADD 
-		| STATE_BLEND_FUNC(STATE_BLEND_FUNC_SRC_ALPHA, STATE_BLEND_FUNC_ONE_MINUS_SRC_ALPHA));
-		m_r.set_pose(m_pose);
-
-		m_images[i]->render(gui_albedo_0);
-	}
-
-	// Render all Texts
-	for (uint32_t i = 0; i < m_texts.size(); i++)
-	{
-		m_r.set_program(font_program);
-		m_r.set_state(STATE_DEPTH_WRITE 
-		| STATE_COLOR_WRITE 
-		| STATE_ALPHA_WRITE 
-		| STATE_CULL_CW
-		| STATE_PRIMITIVE_TRIANGLES
-		| STATE_BLEND_EQUATION_ADD 
-		| STATE_BLEND_FUNC(STATE_BLEND_FUNC_SRC_ALPHA, STATE_BLEND_FUNC_ONE_MINUS_SRC_ALPHA));
-		m_r.set_pose(m_pose);
-
-		m_texts[i]->render(font_uniform);
-	}
-}
-
-//-----------------------------------------------------------------------------
-void Gui::create_gfx()
-{
-	gui_default_vs = m_r.create_shader(ShaderType::VERTEX, default_vertex);
-	gui_default_fs = m_r.create_shader(ShaderType::FRAGMENT, default_fragment);
-	gui_texture_fs = m_r.create_shader(ShaderType::FRAGMENT, texture_fragment);
-	gui_default_program = m_r.create_gpu_program(gui_default_vs, gui_default_fs);
-	gui_texture_program = m_r.create_gpu_program(gui_default_vs, gui_texture_fs);
-	gui_albedo_0 = m_r.create_uniform("u_albedo_0", UniformType::INTEGER_1, 1);
-
-	font_vs = m_r.create_shader(ShaderType::VERTEX, sdf_vertex);
-	font_fs = m_r.create_shader(ShaderType::FRAGMENT, sdf_fragment);
-	font_program = m_r.create_gpu_program(font_vs, font_fs);
-	font_uniform = m_r.create_uniform("u_texture", UniformType::INTEGER_1, 1);
-}
-
-//-----------------------------------------------------------------------------
-void Gui::destroy_gfx()
-{
-	m_r.destroy_uniform(gui_albedo_0);
-	m_r.destroy_gpu_program(gui_texture_program);
-	m_r.destroy_gpu_program(gui_default_program);
-	m_r.destroy_shader(gui_texture_fs);
-	m_r.destroy_shader(gui_default_fs);
-	m_r.destroy_shader(gui_default_vs);
-
-	m_r.destroy_uniform(font_uniform);
-	m_r.destroy_gpu_program(font_program);
-	m_r.destroy_shader(font_vs);
-	m_r.destroy_shader(font_fs);
-}
-
-} // namespace crown

+ 0 - 122
engine/gui/Gui.h

@@ -1,122 +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 "Matrix4x4.h"
-#include "IdTable.h"
-#include "IdArray.h"
-#include "PoolAllocator.h"
-#include "Vector2.h"
-#include "Resource.h"
-#include "Config.h"
-
-namespace crown
-{
-
-typedef Id UniformId;
-
-typedef Id GuiId;
-typedef Id GuiRectId;
-typedef Id GuiTriangleId;
-typedef Id GuiImageId;
-typedef Id GuiTextId;
-
-struct Renderer;
-struct RenderWorld;
-struct GuiResource;
-struct GuiRect;
-struct GuiTriangle;
-struct GuiImage;
-struct GuiText;
-struct Vector3;
-struct Vector2;
-struct Color4;
-struct FontResource;
-
-struct Gui
-{
-						Gui(RenderWorld& render_world, GuiResource* gr, Renderer& r);
-						~Gui();
-
-	const GuiId 		id() const;
-	void				set_id(const GuiId id);
-
-	Vector2				resolution() const;
-	void				move(const Vector3& pos);
-
-	void				show();
-	void				hide();
-
-	GuiRectId			create_rect(const Vector3& pos, const Vector2& size, const Color4& color);
-	void				update_rect(GuiRectId id, const Vector3& pos, const Vector2& size, const Color4& color);
-	void				destroy_rect(GuiRectId id);
-
-	GuiTriangleId		create_triangle(const Vector2& p1, const Vector2& p2, const Vector2& p3, const Color4& color);
-	void				update_triangle(GuiTriangleId id, const Vector2& p1, const Vector2& p2, const Vector2& p3, const Color4& color);
-	void				destroy_triangle(GuiTriangleId id);
-
-	GuiImageId			create_image(ResourceId material, const Vector3& pos, const Vector2& size);
-	void				update_image(GuiImageId id, const Vector3& pos, const Vector2& size);
-	void				destroy_image(GuiImageId);
-
-	GuiTextId			create_text(const char* str, const FontResource* font, uint32_t font_size, const Vector3& pos);
-	void				update_text(GuiTextId id, const char* str, uint32_t font_size, const Vector3& pos);
-	void				destroy_text(GuiTextId id);
-
-	void				render();
-
-private:
-
-	// FIXME FIXME FIXME -- tmp way
-	void 				create_gfx();
-	void 				destroy_gfx();
-
-public:
-
-	RenderWorld&		m_render_world;
-	const GuiResource*	m_resource;
-	Renderer&			m_r;
-	GuiId				m_id;
-
-	Matrix4x4			m_projection;
-	Matrix4x4			m_pose;
-	Vector2				m_resolution;
-
-	bool				m_visible;
-
-	PoolAllocator		m_rect_pool;
-	PoolAllocator		m_triangle_pool;
-	PoolAllocator		m_image_pool;
-	PoolAllocator		m_text_pool;
-
-	IdArray<CE_MAX_GUI_RECTS, GuiRect*> m_rects;
-	IdArray<CE_MAX_GUI_TRIANGLES, GuiTriangle*> m_triangles;
-	IdArray<CE_MAX_GUI_IMAGES, GuiImage*> m_images;
-	IdArray<CE_MAX_GUI_TEXTS, GuiText*> m_texts;
-};
-
-} // namespace crown

+ 0 - 110
engine/gui/GuiImage.h

@@ -1,110 +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 "Matrix4x4.h"
-#include "RendererTypes.h"
-
-// FIXME FIXME FIXME
-#include "Device.h"
-#include "ResourceManager.h"
-#include "Material.h"
-
-namespace crown
-{
-
-struct GuiImage
-{
-	//-------------------------------------------------------------------------
-	GuiImage(RenderWorld& render_world, Renderer& r, ResourceId material, const Vector3& pos, const Vector2& size)
-		: m_render_world(render_world)
-		, m_r(r)
-	{
-		update(pos, size);
-
-		// FIXME FIXME FIXME
-		MaterialResource* mat = (MaterialResource*) device()->resource_manager()->data(material);
-		m_material = m_render_world.create_material(mat);
-
-		m_vb = m_r.create_vertex_buffer(4 * Vertex::bytes_per_vertex(VertexFormat::P2_T2), m_vertices, VertexFormat::P2_T2);
-		m_ib = m_r.create_index_buffer(6 * sizeof(uint16_t), m_indices);
-	}
-
-	//-------------------------------------------------------------------------
-	~GuiImage()
-	{
-		m_r.destroy_vertex_buffer(m_vb);
-		m_r.destroy_index_buffer(m_ib);
-
-		m_render_world.destroy_material(m_material);
-	}
-
-	//-------------------------------------------------------------------------
-	void update(const Vector3& pos, const Vector2& size)
-	{
-		m_vertices[0] = pos.x; m_vertices[1] = pos.y;
-		m_vertices[2] = 0; m_vertices[3] = 0;
-
-		m_vertices[4] = pos.x + size.x; m_vertices[5] = pos.y;
-		m_vertices[6] = 1; m_vertices[7] = 0;
-
-		m_vertices[8] = pos.x + size.x; m_vertices[9] = pos.y - size.y;
-		m_vertices[10] = 1;	m_vertices[11] = 1;
-
-		m_vertices[12] = pos.x; m_vertices[13] = pos.y - size.y;
-		m_vertices[14] = 0;	m_vertices[15] = 1;
-
-		m_indices[0] = 0; m_indices[1] = 1;
-		m_indices[2] = 2; m_indices[3] = 0;
-		m_indices[4] = 2; m_indices[5] = 3;
-	}
-
-	//-------------------------------------------------------------------------
-	void render(UniformId uniform)
-	{
-		Material* material = m_render_world.lookup_material(m_material);
-		material->bind(m_r, uniform);
-		
-		m_r.set_vertex_buffer(m_vb);
-		m_r.set_index_buffer(m_ib);
-		m_r.commit(1);
-	}
-
-public:
-
-	RenderWorld& m_render_world;
-	Renderer& m_r;
-
-	float m_vertices[4*4];
-	uint16_t m_indices[2*3];
-
-	MaterialId m_material;
-	VertexBufferId m_vb;
-	IndexBufferId m_ib;
-};
-
-} // namespace crown

+ 0 - 100
engine/gui/GuiRect.h

@@ -1,100 +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 "Matrix4x4.h"
-#include "RendererTypes.h"
-#include "Renderer.h"
-
-namespace crown
-{
-
-struct Vector3;
-struct Vector2;
-struct Color4;
-
-struct GuiRect
-{
-	//-------------------------------------------------------------------------
-	GuiRect(Renderer& r, const Vector3& pos, const Vector2& size, const Color4& color)
-		: m_r(r)
-	{
-		update(pos, size, color);
-
-		m_vb = m_r.create_vertex_buffer(4 * Vertex::bytes_per_vertex(VertexFormat::P2_C4), m_vertices, VertexFormat::P2_C4);
-		m_ib = m_r.create_index_buffer(8 * sizeof(uint16_t), m_indices);
-	}
-
-	//-------------------------------------------------------------------------
-	~GuiRect()
-	{
-		m_r.destroy_index_buffer(m_ib);
-		m_r.destroy_vertex_buffer(m_vb);
-	}
-
-	//-------------------------------------------------------------------------
-	void update(const Vector3& pos, const Vector2& size, const Color4& color)
-	{
-		m_vertices[0] = pos.x; m_vertices[1] = pos.y;
-		m_vertices[2] = color.r; m_vertices[3] = color.g;
-		m_vertices[4] = color.b; m_vertices[5] = color.a;
-		m_vertices[6] = pos.x + size.x; m_vertices[7] = pos.y;
-		m_vertices[8] = color.r; m_vertices[9] = color.g;
-		m_vertices[10] = color.b; m_vertices[11] = color.a;
-		m_vertices[12] = pos.x + size.x; m_vertices[13] = pos.y - size.y;
-		m_vertices[14] = color.r; m_vertices[15] = color.g;
-		m_vertices[16] = color.b; m_vertices[17] = color.a;
-		m_vertices[18] = pos.x; m_vertices[19] = pos.y - size.y;
-		m_vertices[20] = color.r; m_vertices[21] = color.g;
-		m_vertices[22] = color.b; m_vertices[23] = color.a;
-
-		m_indices[0] = 0; m_indices[1] = 1;
-		m_indices[2] = 1; m_indices[3] = 2;
-		m_indices[4] = 2; m_indices[5] = 3;
-		m_indices[6] = 3; m_indices[7] = 0;
-	}
-
-	//-------------------------------------------------------------------------
-	void render()
-	{
-		m_r.set_vertex_buffer(m_vb);
-		m_r.set_index_buffer(m_ib);
-		m_r.commit(1);
-	}
-
-public:
-
-	Renderer& m_r;
-
-	float m_vertices[6*4];
-	uint16_t m_indices[2*4];
-
-	VertexBufferId m_vb;
-	IndexBufferId m_ib;
-};
-
-} // namespace crown

+ 0 - 251
engine/gui/GuiText.h

@@ -1,251 +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 "Matrix4x4.h"
-#include "Quaternion.h"
-#include "RendererTypes.h"
-#include "StringUtils.h"
-#include "Log.h"
-#include "FontResource.h"
-
-namespace crown
-{
-
-struct Vector3;
-struct Vector2;
-struct Color4;
-
-//-------------------------------------------------------------------------
-struct VertexData
-{
-	float x;
-	float y;
-	float u;
-	float v;
-};
-
-//-------------------------------------------------------------------------
-struct IndexData
-{
-	uint16_t a;
-	uint16_t b;
-};
-
-#define UTF8_ACCEPT 0
-
-//-------------------------------------------------------------------------
-static const uint8_t s_utf8d[364] =
-{
-	// The first part of the table maps bytes to character classes that
-	// to reduce the size of the transition table and create bitmasks.
-	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,  9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
-	7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
-	8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-	10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
-
-	// The second part is a transition table that maps a combination
-	// of a state of the automaton and a character class to a state.
-	 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
-	12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
-	12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
-	12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
-	12,36,12,12,12,12,12,12,12,12,12,12
-};
-
-//-------------------------------------------------------------------------
-uint32_t utf8_decode(uint32_t* state, uint32_t* code_point, uint8_t character)
-{
-	uint32_t byte = character;
-	uint32_t type = s_utf8d[byte];
-
-	*code_point = (*state != UTF8_ACCEPT) ? (byte & 0x3fu) | (*code_point << 6) : (0xff >> type) & (byte);
-	*state = s_utf8d[256 + *state + type];
-
-	return *state;
-}
-
-//-------------------------------------------------------------------------
-struct GuiText
-{
-	//-------------------------------------------------------------------------
-	GuiText(RenderWorld& render_world, Renderer& r, const char* str, const FontResource* fr, uint32_t font_size, const Vector3& pos)
-		: m_render_world(render_world)
-		, m_r(r)
-		, m_resource(fr)
-		, m_str(str)
-		, m_font_size(font_size)
-		, m_pos(pos)
-	{
-		MaterialResource* mat = (MaterialResource*) device()->resource_manager()->data(m_resource->material());
-		m_material = m_render_world.create_material(mat);
-	}
-
-	//-------------------------------------------------------------------------
-	~GuiText()
-	{
-		m_render_world.destroy_material(m_material);
-	}
-
-	//-------------------------------------------------------------------------
-	void update(const char* str, uint32_t font_size, const Vector3& pos)
-	{
-		m_str = str;
-		m_font_size = font_size;
-		m_pos = pos;
-	}
-
-	//-------------------------------------------------------------------------
-	void render(UniformId uniform)
-	{
-		Material* material = m_render_world.lookup_material(m_material);
-		material->bind(m_r, uniform);
-
-		const char* str = m_str.c_str();
-		const float scale = ((float)m_font_size / (float)m_resource->font_size());
-
-		TransientVertexBuffer vb;
-		TransientIndexBuffer ib;
-
-		m_r.reserve_transient_vertex_buffer(&vb, 4 * string::strlen(str), VertexFormat::P2_T2);
-		m_r.reserve_transient_index_buffer(&ib, 6 * string::strlen(str));
-
-		uint16_t index = 0;
-		float x_pen_advance = 0.0f;
-		float y_pen_advance = 0.0f;
-
-		uint32_t state = 0;
-		uint32_t code_point = 0;
-		for (uint32_t i = 0; i < string::strlen(str); i++)
-		{
-			switch (str[i])
-			{
-				case '\n':
-				{
-					x_pen_advance = 0.0f;
-					y_pen_advance += m_resource->font_size();
-					continue;
-				}
-				case '\t':
-				{
-					x_pen_advance += m_font_size * 4;
-					continue;
-				}
-			}
-			
-			if (utf8_decode(&state, &code_point, str[i]) == UTF8_ACCEPT)
-			{
-				FontGlyphData g = m_resource->get_glyph(code_point);
-
-				// Set pen position
-				m_pen.x = m_pos.x + g.x_offset;
-				m_pen.y = m_pos.y + (g.height - g.y_offset);
-
-				// Position coords
-				const float x0 = (m_pen.x + x_pen_advance) * scale;
-				const float y0 = (m_pen.y + y_pen_advance) * scale;
-				const float x1 = (m_pen.x + g.width + x_pen_advance) * scale;
-				const float y1 = (m_pen.y - g.height + y_pen_advance) * scale;
-
-				// Texture coords
-				const float u0 = (float) g.x / m_resource->texture_size();
-				const float v0 = (float) g.y / m_resource->texture_size();
-				const float u1 = u0 + ((float) g.width) / m_resource->texture_size();
-				const float v1 = v0 - ((float) g.height) / m_resource->texture_size();
-
-				// Fill vertex buffer
-				(*(VertexData*)(vb.data)).x		= x0;
-				(*(VertexData*)(vb.data)).y		= y0;
-				(*(VertexData*)(vb.data)).u		= u0;
-				(*(VertexData*)(vb.data)).v		= v1;
-				vb.data += sizeof(VertexData);
-
-				(*(VertexData*)(vb.data)).x		= x1;
-				(*(VertexData*)(vb.data)).y		= y0;
-				(*(VertexData*)(vb.data)).u		= u1; 
-				(*(VertexData*)(vb.data)).v		= v1;
-				vb.data += sizeof(VertexData);
-
-				(*(VertexData*)(vb.data)).x		= x1;
-				(*(VertexData*)(vb.data)).y		= y1;
-				(*(VertexData*)(vb.data)).u		= u1;
-				(*(VertexData*)(vb.data)).v		= v0;
-				vb.data += sizeof(VertexData);
-
-				(*(VertexData*)(vb.data)).x		= x0;
-				(*(VertexData*)(vb.data)).y		= y1;
-				(*(VertexData*)(vb.data)).u		= u0;
-				(*(VertexData*)(vb.data)).v		= v0;
-				vb.data += sizeof(VertexData);
-
-				// Fill index buffer
-				(*(IndexData*)(ib.data)).a		= index;
-				(*(IndexData*)(ib.data)).b		= index + 1;
-				ib.data += sizeof(IndexData);
-
-				(*(IndexData*)(ib.data)).a		= index + 2;
-				(*(IndexData*)(ib.data)).b		= index;
-				ib.data += sizeof(IndexData);
-
-				(*(IndexData*)(ib.data)).a		= index + 2;
-				(*(IndexData*)(ib.data)).b		= index + 3;
-				ib.data += sizeof(IndexData);
-
-				// Advance pen position
-				x_pen_advance += g.x_advance;
-
-				index += 4;
-			}
-		}
-
-		m_r.set_vertex_buffer(vb);
-		m_r.set_index_buffer(ib);
-		m_r.commit(1);
-	}
-
-public:
-
-	RenderWorld& 		m_render_world;
-	Renderer& 			m_r;
-	const FontResource* m_resource;
-
-	DynamicString		m_str;
-	uint32_t			m_font_size;
-
-	// position states
-	Vector3				m_pos;
-	Vector2				m_pen;
-
-	MaterialId 			m_material;
-};
-
-} // namespace crown
-

+ 0 - 93
engine/gui/GuiTriangle.h

@@ -1,93 +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 "Matrix4x4.h"
-#include "RendererTypes.h"
-
-namespace crown
-{
-
-struct GuiTriangle
-{
-	//-------------------------------------------------------------------------
-	GuiTriangle(Renderer& r, const Vector2& p1, const Vector2& p2, const Vector2& p3, const Color4& color)
-		: m_r(r)
-	{
-		update(p1, p2, p3, color);
-
-		m_vb = m_r.create_vertex_buffer(3 * Vertex::bytes_per_vertex(VertexFormat::P2_C4), m_vertices, VertexFormat::P2_C4);
-		m_ib = m_r.create_index_buffer(6 * sizeof(uint16_t), m_indices);
-	}
-
-	//-------------------------------------------------------------------------
-	~GuiTriangle()
-	{
-		m_r.destroy_vertex_buffer(m_vb);
-		m_r.destroy_index_buffer(m_ib);
-	}
-
-	//-------------------------------------------------------------------------
-	void update(const Vector2& p1, const Vector2& p2, const Vector2& p3, const Color4& color)
-	{
-		m_vertices[0] = p1.x; m_vertices[1] = p1.y;
-		m_vertices[2] = color.r; m_vertices[3] = color.g;
-		m_vertices[4] = color.b; m_vertices[5] = color.a;
-
-		m_vertices[6] = p2.x; m_vertices[7] = p2.y;
-		m_vertices[8] = color.r; m_vertices[9] = color.g;
-		m_vertices[10] = color.b; m_vertices[11] = color.a;
-
-		m_vertices[12] = p3.x; m_vertices[13] = p3.y;
-		m_vertices[14] = color.r; m_vertices[15] = color.g;
-		m_vertices[16] = color.b; m_vertices[17] = color.a;
-
-		m_indices[0] = 0; m_indices[1] = 1;
-		m_indices[2] = 1; m_indices[3] = 2;
-		m_indices[4] = 2; m_indices[5] = 0;
-	}
-
-	//-------------------------------------------------------------------------
-	void render()
-	{
-		m_r.set_vertex_buffer(m_vb);
-		m_r.set_index_buffer(m_ib);
-		m_r.commit(1);		
-	}
-
-public:
-
-	Renderer& m_r;
-
-	float m_vertices[6*3];
-	uint16_t m_indices[2*3];
-
-	VertexBufferId m_vb;
-	IndexBufferId m_ib;
-};
-
-} // namespace crown

+ 63 - 0
engine/lua/LuaColor4.cpp

@@ -0,0 +1,63 @@
+/*
+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 "Quaternion.h"
+#include "LuaStack.h"
+#include "LuaEnvironment.h"
+
+namespace crown
+{
+
+//-----------------------------------------------------------------------------
+static int color4_new(lua_State* L)
+{
+	LuaStack stack(L);
+
+	const float r = stack.get_float(1);
+	const float g = stack.get_float(2);
+	const float b = stack.get_float(3);
+	const float a = stack.get_float(4);
+
+	stack.push_quaternion(Quaternion(r, g, b, a));
+	return 1;
+}
+
+//-----------------------------------------------------------------------------
+static int color4_ctor(lua_State* L)
+{
+	LuaStack stack(L);
+	stack.remove(1); // Remove table
+	return color4_new(L);
+}
+
+//-----------------------------------------------------------------------------
+void load_color4(LuaEnvironment& env)
+{
+	env.load_module_function("Color4", "new", color4_new);
+	env.load_module_constructor("Color4", color4_ctor);
+}
+
+} // namespace crown

+ 11 - 0
engine/lua/LuaDebugLine.cpp

@@ -79,6 +79,15 @@ static int debug_line_commit(lua_State* L)
 	return 0;
 }
 
+//-----------------------------------------------------------------------------
+static int debug_line_tostring(lua_State* L)
+{
+	LuaStack stack(L);
+	DebugLine* dl = stack.get_debug_line(1);
+	stack.push_fstring("DebugLine (%p)", dl);
+	return 1;
+}
+
 //-----------------------------------------------------------------------------
 void load_debug_line(LuaEnvironment& env)
 {
@@ -86,6 +95,8 @@ void load_debug_line(LuaEnvironment& env)
 	env.load_module_function("DebugLine", "add_sphere",  debug_line_add_sphere);
 	env.load_module_function("DebugLine", "clear",       debug_line_clear);
 	env.load_module_function("DebugLine", "commit",      debug_line_commit);
+	env.load_module_function("DebugLine", "__index",	 "DebugLine");
+	env.load_module_function("DebugLine", "__tostring",  debug_line_tostring);
 }
 
 } // namespace crown

+ 45 - 0
engine/lua/LuaDevice.cpp

@@ -30,6 +30,8 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "WorldManager.h"
 #include "LuaEnvironment.h"
 #include "LuaStack.h"
+#include "TempAllocator.h"
+#include "Array.h"
 
 namespace crown
 {
@@ -157,6 +159,46 @@ static int device_destroy_resource_package(lua_State* L)
 	return 0;
 }
 
+//-----------------------------------------------------------------------------
+static int device_display_modes(lua_State* L)
+{
+	LuaStack stack(L);
+
+	TempAllocator512 alloc;
+	Array<DisplayMode> modes(alloc);
+
+	device()->display_modes(modes);
+
+	stack.push_table();
+	for (uint32_t i = 0; i < array::size(modes); i++)
+	{
+		stack.push_key_begin((int32_t) i + 1);
+		stack.push_table();
+		stack.push_key_begin("id"); stack.push_uint32(modes[i].id); stack.push_key_end();
+		stack.push_key_begin("width"); stack.push_uint32(modes[i].width); stack.push_key_end();
+		stack.push_key_begin("height"); stack.push_uint32(modes[i].height); stack.push_key_end();
+		stack.push_key_end();
+	}
+
+	return 1;
+}
+
+//-----------------------------------------------------------------------------
+static int device_set_display_mode(lua_State* L)
+{
+	LuaStack stack(L);
+	device()->set_display_mode(stack.get_int(1));
+	return 0;
+}
+
+//-----------------------------------------------------------------------------
+static int device_set_fullscreen(lua_State* L)
+{
+	LuaStack stack(L);
+	device()->set_fullscreen(stack.get_bool(1));
+	return 0;
+}
+
 //-----------------------------------------------------------------------------
 void load_device(LuaEnvironment& env)
 {
@@ -171,6 +213,9 @@ void load_device(LuaEnvironment& env)
 	env.load_module_function("Device", "render_world",             device_render_world);
 	env.load_module_function("Device", "create_resource_package",  device_create_resource_package);
 	env.load_module_function("Device", "destroy_resource_package", device_destroy_resource_package);
+	env.load_module_function("Device", "display_modes",            device_display_modes);
+	env.load_module_function("Device", "set_display_mode",         device_set_display_mode);
+	env.load_module_function("Device", "set_fullscreen",           device_set_fullscreen);
 }
 
 } // namespace crown

+ 2 - 2
engine/lua/LuaEnvironment.cpp

@@ -54,7 +54,7 @@ void LuaEnvironment::load_and_execute(const char* res_name)
 	// Load the resource
 	ResourceId res_id = resman->load("lua", res_name);
 	resman->flush();
-	LuaResource* lr = (LuaResource*) resman->data(res_id);
+	LuaResource* lr = (LuaResource*) resman->get(res_id);
 	
 	lua_pushcfunction(m_L, lua_system::error_handler);
 	luaL_loadbuffer(m_L, (const char*) lr->program(), lr->size(), res_name);
@@ -170,7 +170,7 @@ void LuaEnvironment::call_physics_callback(Actor* actor_0, Actor* actor_1, Unit*
 	LuaStack stack(m_L);
 
 	lua_pushcfunction(m_L, lua_system::error_handler);
-	lua_getglobal(m_L, "physics_callback");
+	lua_getglobal(m_L, "g_physics_callback");
 
 	stack.push_table();
 	stack.push_key_begin("actor_0"); stack.push_actor(actor_0); stack.push_key_end();

+ 15 - 206
engine/lua/LuaGui.cpp

@@ -57,229 +57,47 @@ static int gui_move(lua_State* L)
 	LuaStack stack(L);
 
 	Gui* gui = stack.get_gui(1);
-
-	const Vector3 pos = stack.get_vector3(2);
-
-	gui->move(pos);
-
-	return 0;
-}
-
-//-----------------------------------------------------------------------------
-static int gui_show(lua_State* L)
-{
-	LuaStack stack(L);
-
-	Gui* gui = stack.get_gui(1);
-
-	gui->show();
-
-	return 0;
-}
-
-//-----------------------------------------------------------------------------
-static int gui_hide(lua_State* L)
-{
-	LuaStack stack(L);
-
-	Gui* gui = stack.get_gui(1);
-
-	gui->hide();
-
+	gui->move(stack.get_vector2(2));
 	return 0;
 }
 
 //-----------------------------------------------------------------------------
-static int gui_create_rect(lua_State* L)
+static int gui_screen_to_gui(lua_State* L)
 {
 	LuaStack stack(L);
 
 	Gui* gui = stack.get_gui(1);
-	const Vector3 pos = stack.get_vector3(2);
-	const Vector2 size = stack.get_vector2(3);
-	const Quaternion col = stack.get_quaternion(4);
-	const Color4 color(col.x, col.y, col.z, col.w);
-
-	GuiComponentId rect_id = gui->create_rect(pos, size, color);
-	stack.push_gui_component_id(rect_id);
-
+	stack.push_vector2(gui->screen_to_gui(stack.get_vector2(2)));
 	return 1;
 }
 
 //-----------------------------------------------------------------------------
-static int gui_update_rect(lua_State* L)
+static int gui_draw_rectangle(lua_State* L)
 {
 	LuaStack stack(L);
 
 	Gui* gui = stack.get_gui(1);
-	GuiComponentId rect_id = stack.get_gui_component_id(2);
-	const Vector3 pos = stack.get_vector3(3);
-	const Vector2 size = stack.get_vector2(4);
-	const Quaternion col = stack.get_quaternion(4);
-	const Color4 color(col.x, col.y, col.z, col.w);
-
-	gui->update_rect(rect_id, pos, size, color);
-
+	gui->draw_rectangle(stack.get_vector3(2), stack.get_vector2(3), stack.get_color4(4));
 	return 0;
 }
 
 //-----------------------------------------------------------------------------
-static int gui_destroy_rect(lua_State* L)
+static int gui_draw_image(lua_State* L)
 {
 	LuaStack stack(L);
 
 	Gui* gui = stack.get_gui(1);
-	GuiComponentId rect_id = stack.get_gui_component_id(2);
-
-	gui->destroy_rect(rect_id);
-
+	gui->draw_image(stack.get_string(2), stack.get_vector3(3), stack.get_vector2(4), stack.get_color4(5));
 	return 0;
 }
 
 //-----------------------------------------------------------------------------
-static int gui_create_triangle(lua_State* L)
+static int gui_draw_text(lua_State* L)
 {
 	LuaStack stack(L);
 
 	Gui* gui = stack.get_gui(1);
-	const Vector2 p1 = stack.get_vector2(2);
-	const Vector2 p2 = stack.get_vector2(3);
-	const Vector2 p3 = stack.get_vector2(3);
-	const Quaternion col = stack.get_quaternion(4);
-	const Color4 color(col.x, col.y, col.z, col.w);
-
-	GuiComponentId triangle_id = gui->create_triangle(p1, p2, p3, color);
-
-	stack.push_gui_component_id(triangle_id);
-
-	return 1;
-}
-
-//-----------------------------------------------------------------------------
-static int gui_update_triangle(lua_State* L)
-{
-	LuaStack stack(L);
-
-	Gui* gui = stack.get_gui(1);
-	GuiComponentId triangle_id = stack.get_gui_component_id(2);
-	const Vector2 p1 = stack.get_vector2(3);
-	const Vector2 p2 = stack.get_vector2(4);
-	const Vector2 p3 = stack.get_vector2(5);
-	const Quaternion col = stack.get_quaternion(4);
-	const Color4 color(col.x, col.y, col.z, col.w);
-
-	gui->update_triangle(triangle_id, p1, p2, p3, color);
-
-	return 0;
-}
-
-//-----------------------------------------------------------------------------
-static int gui_destroy_triangle(lua_State* L)
-{
-	LuaStack stack(L);
-
-	Gui* gui = stack.get_gui(1);
-	GuiComponentId triangle_id = stack.get_gui_component_id(2);
-
-	gui->destroy_triangle(triangle_id);
-
-	return 0;
-}
-
-//-----------------------------------------------------------------------------
-static int gui_create_image(lua_State* L)
-{
-	LuaStack stack(L);
-
-	Gui* gui = stack.get_gui(1);
-	const char* mat_name = stack.get_string(2);
-	const Vector3 pos = stack.get_vector3(3);
-	const Vector2 size = stack.get_vector2(4);
-
-	ResourceId mat_id;
-	mat_id.id = string::murmur2_64(mat_name, string::strlen(mat_name), 0);
-
-	GuiImageId image_id = gui->create_image(mat_id, pos, size);
-
-	stack.push_gui_component_id(image_id);
-
-	return 1;
-}
-
-//-----------------------------------------------------------------------------
-static int gui_update_image(lua_State* L)
-{
-	LuaStack stack(L);
-
-	Gui* gui = stack.get_gui(1);
-	GuiComponentId image_id = stack.get_gui_component_id(2);
-	const Vector3 pos = stack.get_vector3(3);
-	const Vector2 size = stack.get_vector2(4);
-
-	gui->update_image(image_id, pos, size);
-
-	return 0;
-}
-
-//-----------------------------------------------------------------------------
-static int gui_destroy_image(lua_State* L)
-{
-	LuaStack stack(L);
-
-	Gui* gui = stack.get_gui(1);
-	GuiComponentId image_id = stack.get_gui_component_id(2);
-
-	gui->destroy_image(image_id);
-
-	return 0;
-}
-
-//-----------------------------------------------------------------------------
-static int gui_create_text(lua_State* L)
-{
-	LuaStack stack(L);
-
-	Gui* gui = stack.get_gui(1);
-	const char* str = stack.get_string(2);
-	const char* font = stack.get_string(3);
-	uint32_t font_size = stack.get_int(4);
-	Vector3 pos = stack.get_vector3(5);
-
-	FontResource* fr = (FontResource*) device()->resource_manager()->lookup("font", font);
-
-	GuiTextId text_id = gui->create_text(str, fr, font_size, pos);
-
-	stack.push_gui_component_id(text_id);
-
-	return 1;
-}
-
-//-----------------------------------------------------------------------------
-static int gui_update_text(lua_State* L)
-{
-	LuaStack stack(L);
-
-	Gui* gui = stack.get_gui(1);
-	GuiComponentId text_id = stack.get_gui_component_id(2);
-	const char* str = stack.get_string(3);
-	uint32_t font_size = stack.get_int(4);
-	Vector3 pos = stack.get_vector3(5);
-
-	gui->update_text(text_id, str, font_size, pos);
-
-	return 0;
-}
-
-//-----------------------------------------------------------------------------
-static int gui_destroy_text(lua_State* L)
-{
-	LuaStack stack(L);
-
-	Gui* gui = stack.get_gui(1);
-	GuiComponentId text_id = stack.get_gui_component_id(2);
-
-	gui->destroy_text(text_id);
-
+	gui->draw_text(stack.get_string(2), stack.get_string(3), stack.get_int(4), stack.get_vector3(5), stack.get_color4(6));
 	return 0;
 }
 
@@ -288,20 +106,11 @@ void load_gui(LuaEnvironment& env)
 {
 	env.load_module_function("Gui", "resolution",		gui_resolution);
 	env.load_module_function("Gui", "move",				gui_move);
-	env.load_module_function("Gui", "show",				gui_show);
-	env.load_module_function("Gui", "hide",				gui_hide);
-	env.load_module_function("Gui", "create_rect",		gui_create_rect);
-	env.load_module_function("Gui", "update_rect",		gui_update_rect);
-	env.load_module_function("Gui", "destroy_rect",		gui_destroy_rect);
-	env.load_module_function("Gui", "create_triangle",	gui_create_triangle);
-	env.load_module_function("Gui", "update_triangle",	gui_update_triangle);
-	env.load_module_function("Gui", "destroy_triangle",	gui_destroy_triangle);
-	env.load_module_function("Gui", "create_image",		gui_create_image);
-	env.load_module_function("Gui", "update_image",		gui_update_image);
-	env.load_module_function("Gui", "destroy_image",	gui_destroy_image);
-	env.load_module_function("Gui", "create_text", 		gui_create_text);
-	env.load_module_function("Gui", "update_text", 		gui_update_text);
-	env.load_module_function("Gui", "destroy_text",		gui_destroy_text);
+	env.load_module_function("Gui", "screen_to_gui",	gui_screen_to_gui);
+
+	env.load_module_function("Gui", "draw_rectangle",	gui_draw_rectangle);
+	env.load_module_function("Gui", "draw_image",		gui_draw_image);
+	env.load_module_function("Gui", "draw_text",		gui_draw_text);
 }
 
-} // namespace crown
+} // namespace crown

+ 49 - 157
engine/lua/LuaMatrix4x4.cpp

@@ -28,11 +28,12 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "Vector3.h"
 #include "LuaStack.h"
 #include "LuaEnvironment.h"
-#include "OS.h"
 
 namespace crown
 {
 
+using namespace matrix4x4;
+
 //-----------------------------------------------------------------------------
 static int matrix4x4_new(lua_State* L)
 {
@@ -68,141 +69,77 @@ static int matrix4x4_ctor(lua_State* L)
 	return matrix4x4_new(L);
 }
 
-//-----------------------------------------------------------------------------					
-static int matrix4x4_add(lua_State* L)
-{
-	LuaStack stack(L);
-
-	Matrix4x4& a = stack.get_matrix4x4(1);
-	Matrix4x4& b = stack.get_matrix4x4(2);
-
-	stack.push_matrix4x4(a + b);
-
-	return 1;
-}
-
 //-----------------------------------------------------------------------------
-static int matrix4x4_subtract(lua_State* L)
+static int matrix4x4_from_quaternion(lua_State* L)
 {
 	LuaStack stack(L);
-
-	Matrix4x4& a = stack.get_matrix4x4(1);
-	Matrix4x4& b = stack.get_matrix4x4(2);
-
-	stack.push_matrix4x4(a - b);
-
+	const Quaternion& q = stack.get_quaternion(1);
+	stack.push_matrix4x4(Matrix4x4(q, Vector3(0, 0, 0)));
 	return 1;
 }
 
 //-----------------------------------------------------------------------------
-static int matrix4x4_multiply(lua_State* L)
+static int matrix4x4_from_translation(lua_State* L)
 {
 	LuaStack stack(L);
-
-	Matrix4x4& a = stack.get_matrix4x4(1);
-	Matrix4x4& b = stack.get_matrix4x4(2);
-
-	stack.push_matrix4x4(a * b);
-
+	const Vector3& t = stack.get_vector3(1);
+	stack.push_matrix4x4(Matrix4x4(quaternion::IDENTITY, t));
 	return 1;
 }
 
 //-----------------------------------------------------------------------------
-static int matrix4x4_build_rotation_x(lua_State* L)
+static int matrix4x4_from_quaternion_translation(lua_State* L)
 {
 	LuaStack stack(L);
-
-	Matrix4x4& a = stack.get_matrix4x4(1);
-	float k = stack.get_float(2);
-
-	a.build_rotation_x(k);
-
-	return 0;
-}
-
-//-----------------------------------------------------------------------------
-static int matrix4x4_build_rotation_y(lua_State* L)
-{
-	LuaStack stack(L);
-
-	Matrix4x4& a = stack.get_matrix4x4(1);
-	float k = stack.get_float(2);
-
-	a.build_rotation_y(k);
-
-	return 0;
-}
-
-//-----------------------------------------------------------------------------
-static int matrix4x4_build_rotation_z(lua_State* L)
-{
-	LuaStack stack(L);
-
-	Matrix4x4& a = stack.get_matrix4x4(1);
-	float k = stack.get_float(2);
-
-	a.build_rotation_z(k);
-
-	return 0;
+	stack.push_matrix4x4(Matrix4x4(stack.get_quaternion(1), stack.get_vector3(2)));
+	return 1;
 }
 
 //-----------------------------------------------------------------------------
-static int matrix4x4_build_rotation(lua_State* L)
+static int matrix4x4_from_axes(lua_State* L)
 {
 	LuaStack stack(L);
-
-	Matrix4x4& a = stack.get_matrix4x4(1);
-	Vector3& d = stack.get_vector3(2);
-	float k = stack.get_float(3);
-
-	a.build_rotation(d, k);
-
-	return 0;
+	stack.push_matrix4x4(Matrix4x4(stack.get_vector3(1), stack.get_vector3(2), stack.get_vector3(3), stack.get_vector3(4)));
+	return 1;
 }
 
-//-----------------------------------------------------------------------------
-static int matrix4x4_build_look_at_rh(lua_State* L)
+//-----------------------------------------------------------------------------					
+static int matrix4x4_add(lua_State* L)
 {
 	LuaStack stack(L);
 
 	Matrix4x4& a = stack.get_matrix4x4(1);
-	Vector3& pos = stack.get_vector3(2);
-	Vector3& target = stack.get_vector3(3);
-	Vector3& up = stack.get_vector3(4);
+	Matrix4x4& b = stack.get_matrix4x4(2);
 
-	a.build_look_at_rh(pos, target, up);
+	stack.push_matrix4x4(a + b);
 
-	return 0;
+	return 1;
 }
 
 //-----------------------------------------------------------------------------
-static int matrix4x4_build_viewpoint_billboard(lua_State* L)
+static int matrix4x4_subtract(lua_State* L)
 {
 	LuaStack stack(L);
 
 	Matrix4x4& a = stack.get_matrix4x4(1);
-	Vector3& pos = stack.get_vector3(2);
-	Vector3& target = stack.get_vector3(3);
-	Vector3& up = stack.get_vector3(4);
+	Matrix4x4& b = stack.get_matrix4x4(2);
 
-	a.build_viewpoint_billboard(pos, target, up);
+	stack.push_matrix4x4(a - b);
 
-	return 0;
+	return 1;
 }
 
 //-----------------------------------------------------------------------------
-static int matrix4x4_build_axis_billboard(lua_State* L)
+static int matrix4x4_multiply(lua_State* L)
 {
 	LuaStack stack(L);
 
 	Matrix4x4& a = stack.get_matrix4x4(1);
-	Vector3& pos = stack.get_vector3(2);
-	Vector3& target = stack.get_vector3(3);
-	Vector3& up = stack.get_vector3(4);
+	Matrix4x4& b = stack.get_matrix4x4(2);
 
-	a.build_axis_billboard(pos, target, up);
+	stack.push_matrix4x4(a * b);
 
-	return 0;
+	return 1;
 }
 
 //-----------------------------------------------------------------------------
@@ -212,7 +149,7 @@ static int matrix4x4_transpose(lua_State* L)
 
 	Matrix4x4& a = stack.get_matrix4x4(1);
 
-	stack.push_matrix4x4(a.transpose());
+	stack.push_matrix4x4(transpose(a));
 
 	return 1;
 }
@@ -224,7 +161,7 @@ static int matrix4x4_determinant(lua_State* L)
 
 	Matrix4x4& a = stack.get_matrix4x4(1);
 
-	stack.push_float(a.get_determinant());
+	stack.push_float(determinant(a));
 
 	return 1;
 }
@@ -236,23 +173,11 @@ static int matrix4x4_invert(lua_State* L)
 
 	Matrix4x4& a = stack.get_matrix4x4(1);
 
-	stack.push_matrix4x4(a.invert());
+	stack.push_matrix4x4(invert(a));
 
 	return 1;
 }
 
-//-----------------------------------------------------------------------------
-static int matrix4x4_load_identity(lua_State* L)
-{
-	LuaStack stack(L);
-
-	Matrix4x4& a = stack.get_matrix4x4(1);
-
-	a.load_identity();
-
-	return 0;
-}
-
 //-----------------------------------------------------------------------------
 static int matrix4x4_x(lua_State* L)
 {	
@@ -260,7 +185,7 @@ static int matrix4x4_x(lua_State* L)
 
 	Matrix4x4& a = stack.get_matrix4x4(1);
 
-	stack.push_vector3(a.x());
+	stack.push_vector3(x(a));
 
 	return 1;
 }
@@ -272,7 +197,7 @@ static int matrix4x4_y(lua_State* L)
 
 	Matrix4x4& a = stack.get_matrix4x4(1);
 
-	stack.push_vector3(a.y());
+	stack.push_vector3(y(a));
 
 	return 1;
 }
@@ -284,7 +209,7 @@ static int matrix4x4_z(lua_State* L)
 
 	Matrix4x4& a = stack.get_matrix4x4(1);
 
-	stack.push_vector3(a.z());
+	stack.push_vector3(z(a));
 
 	return 1;
 }
@@ -297,7 +222,7 @@ static int matrix4x4_set_x(lua_State* L)
 	Matrix4x4& a = stack.get_matrix4x4(1);
 	Vector3& x = stack.get_vector3(2);
 
-	a.set_x(x);
+	set_x(a, x);
 
 	return 0;
 }
@@ -310,7 +235,7 @@ static int matrix4x4_set_y(lua_State* L)
 	Matrix4x4& a = stack.get_matrix4x4(1);
 	Vector3& y = stack.get_vector3(2);
 
-	a.set_y(y);
+	set_y(a, y);
 
 	return 0;
 }
@@ -323,7 +248,7 @@ static int matrix4x4_set_z(lua_State* L)
 	Matrix4x4& a = stack.get_matrix4x4(1);
 	Vector3& z = stack.get_vector3(2);
 
-	a.set_z(z);
+	set_z(a, z);
 
 	return 0;
 }
@@ -335,7 +260,7 @@ static int matrix4x4_translation(lua_State* L)
 
 	Matrix4x4& a = stack.get_matrix4x4(1);
 
-	stack.push_vector3(a.translation());
+	stack.push_vector3(translation(a));
 
 	return 1;
 }
@@ -348,32 +273,7 @@ static int matrix4x4_set_translation(lua_State* L)
 	Matrix4x4& a = stack.get_matrix4x4(1);
 	Vector3& trans = stack.get_vector3(2);
 
-	a.set_translation(trans);
-
-	return 0;
-}
-
-//-----------------------------------------------------------------------------
-static int matrix4x4_get_scale(lua_State* L)
-{
-	LuaStack stack(L);
-
-	Matrix4x4& a = stack.get_matrix4x4(1);
-
-	stack.push_vector3(a.get_scale());
-
-	return 1;
-}
-
-//-----------------------------------------------------------------------------
-static int matrix4x4_set_scale(lua_State* L)
-{
-	LuaStack stack(L);
-
-	Matrix4x4& a = stack.get_matrix4x4(1);
-	Vector3& scale = stack.get_vector3(2);
-
-	a.set_scale(scale);
+	set_translation(a, trans);
 
 	return 0;
 }
@@ -383,44 +283,38 @@ static int matrix4x4_identity(lua_State* L)
 {
 	LuaStack stack(L);
 
-	stack.push_matrix4x4(Matrix4x4::IDENTITY);
+	stack.push_matrix4x4(matrix4x4::IDENTITY);
 
 	return 1;
 }
 
 //-----------------------------------------------------------------------------
-static int matrix4x4_print(lua_State* L)
+static int matrix4x4_to_string(lua_State* L)
 {
 	LuaStack stack(L);
 
 	Matrix4x4& a = stack.get_matrix4x4(1);
 
-	os::printf("|%.1f|%.1f|%.1f|%.1f|\n", a.m[0], a.m[4], a.m[8], a.m[12]);
-	os::printf("|%.1f|%.1f|%.1f|%.1f|\n", a.m[1], a.m[5], a.m[9], a.m[13]);
-	os::printf("|%.1f|%.1f|%.1f|%.1f|\n", a.m[2], a.m[6], a.m[10], a.m[14]);
-	os::printf("|%.1f|%.1f|%.1f|%.1f|\n", a.m[3], a.m[7], a.m[11], a.m[15]);
+	stack.push_fstring("%.1f, %.1f, %.1f, %.1f\n%.1f, %.1f, %.1f, %.1f\n%.1f, %.1f, %.1f, %.1f\n%.1f, %.1f, %.1f, %.1f\n",
+						a[0], a[4], a[8], a[12], a[1], a[5], a[9], a[13], a[2], a[6], a[10], a[14], a[3], a[7], a[11], a[15]);
 
-	return 0;
+	return 1;
 }
 
 //-----------------------------------------------------------------------------
 void load_matrix4x4(LuaEnvironment& env)
 {
 	env.load_module_function("Matrix4x4", "new", 							matrix4x4_new);
+	env.load_module_function("Matrix4x4", "from_quaternion",				matrix4x4_from_quaternion);
+	env.load_module_function("Matrix4x4", "from_translation",				matrix4x4_from_translation);
+	env.load_module_function("Matrix4x4", "from_quaternion_translation",	matrix4x4_from_quaternion_translation);
+	env.load_module_function("Matrix4x4", "from_axes",						matrix4x4_from_axes);
 	env.load_module_function("Matrix4x4", "add", 							matrix4x4_add);
 	env.load_module_function("Matrix4x4", "subtract", 						matrix4x4_subtract);
 	env.load_module_function("Matrix4x4", "multiply", 						matrix4x4_multiply);
-	env.load_module_function("Matrix4x4", "build_rotation_x", 				matrix4x4_build_rotation_x);
-	env.load_module_function("Matrix4x4", "build_rotation_y", 				matrix4x4_build_rotation_y);
-	env.load_module_function("Matrix4x4", "build_rotation_z", 				matrix4x4_build_rotation_z);
-	env.load_module_function("Matrix4x4", "build_rotation", 				matrix4x4_build_rotation);
-	env.load_module_function("Matrix4x4", "build_look_at_rh", 				matrix4x4_build_look_at_rh);
-	env.load_module_function("Matrix4x4", "build_viewpoint_billboard", 		matrix4x4_build_viewpoint_billboard);
-	env.load_module_function("Matrix4x4", "build_axis_billboard", 			matrix4x4_build_axis_billboard);
 	env.load_module_function("Matrix4x4", "transpose", 						matrix4x4_transpose);
 	env.load_module_function("Matrix4x4", "determinant", 					matrix4x4_determinant);
 	env.load_module_function("Matrix4x4", "invert", 						matrix4x4_invert);
-	env.load_module_function("Matrix4x4", "load_identity", 					matrix4x4_load_identity);
 	env.load_module_function("Matrix4x4", "x",								matrix4x4_x);
 	env.load_module_function("Matrix4x4", "y",								matrix4x4_y);
 	env.load_module_function("Matrix4x4", "z",								matrix4x4_z);
@@ -429,10 +323,8 @@ void load_matrix4x4(LuaEnvironment& env)
 	env.load_module_function("Matrix4x4", "set_z",							matrix4x4_set_z);
 	env.load_module_function("Matrix4x4", "translation", 					matrix4x4_translation);
 	env.load_module_function("Matrix4x4", "set_translation", 				matrix4x4_set_translation);
-	env.load_module_function("Matrix4x4", "get_scale", 						matrix4x4_get_scale);
-	env.load_module_function("Matrix4x4", "set_scale", 						matrix4x4_set_scale);
-	env.load_module_function("Matrix4x4", "identity", 						matrix4x4_identity);	
-	env.load_module_function("Matrix4x4", "print", 							matrix4x4_print);
+	env.load_module_function("Matrix4x4", "identity", 						matrix4x4_identity);
+	env.load_module_function("Matrix4x4", "to_string",						matrix4x4_to_string);
 
 	env.load_module_constructor("Matrix4x4",								matrix4x4_ctor);
 }

+ 1 - 1
engine/lua/LuaPhysicsWorld.cpp

@@ -67,7 +67,7 @@ static int physics_world_make_raycast(lua_State* L)
 
 	RaycastId raycast = world->create_raycast((CollisionMode::Enum) mode, (CollisionType::Enum) filter);
 
-	stack.push_raycast(world->lookup_raycast(raycast));
+	stack.push_raycast(world->get_raycast(raycast));
 	return 1;
 }
 

+ 11 - 0
engine/lua/LuaSprite.cpp

@@ -110,6 +110,16 @@ static int sprite_set_local_pose(lua_State* L)
 	return 0;
 }
 
+//-----------------------------------------------------------------------------
+static int sprite_set_frame(lua_State* L)
+{
+	LuaStack stack(L);
+
+	Sprite* sprite = stack.get_sprite(1);
+	sprite->set_frame(stack.get_int(2));
+	return 0;
+}
+
 //-----------------------------------------------------------------------------
 void load_sprite(LuaEnvironment& env)
 {
@@ -119,6 +129,7 @@ void load_sprite(LuaEnvironment& env)
 	env.load_module_function("Sprite", "set_local_position", 	sprite_set_local_position);
 	env.load_module_function("Sprite", "set_local_rotation", 	sprite_set_local_rotation);
 	env.load_module_function("Sprite", "set_local_pose", 		sprite_set_local_pose);
+	env.load_module_function("Sprite", "set_frame",				sprite_set_frame);
 }
 
 } // namespace crown

+ 49 - 18
engine/lua/LuaStack.h

@@ -34,6 +34,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "Quaternion.h"
 #include "Matrix4x4.h"
 #include "StringUtils.h"
+#include "Color4.h"
 
 //-----------------------------------------------------------------------------
 #if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
@@ -126,6 +127,24 @@ public:
 		lua_remove(m_L, index);
 	}
 
+	//-----------------------------------------------------------------------------
+	bool is_nil(int32_t index)
+	{
+		return lua_isnil(m_L, index);
+	}
+
+	//-----------------------------------------------------------------------------
+	bool is_number(int32_t index)
+	{
+		return lua_isnumber(m_L, index);
+	}
+
+	/// Wraps lua_type.
+	int value_type(uint32_t index)
+	{
+		return lua_type(m_L, index);
+	}
+
 	//-----------------------------------------------------------------------------
 	void push_nil()
 	{
@@ -421,32 +440,20 @@ public:
 		return (Gui*) CHECKLIGHTDATA(m_L, index, always_true, "Gui");
 	}
 
-	//-----------------------------------------------------------------------------
-	void push_gui_component_id(GuiComponentId id)
-	{
-		uintptr_t enc = id.encode();
-		lua_pushlightuserdata(m_L, (void*)enc);		
-	}
-
-	//-----------------------------------------------------------------------------
-	GuiComponentId get_gui_component_id(int32_t index)
-	{
-		uint32_t enc = (uintptr_t) CHECKLIGHTDATA(m_L, index, always_true, "GuiComponentId");
-		GuiComponentId id;
-		id.decode(enc);
-		return id;	
-	}
-
 	//-----------------------------------------------------------------------------
 	void push_debug_line(DebugLine* line)
 	{
-		lua_pushlightuserdata(m_L, line);
+		DebugLine** l = (DebugLine**) lua_newuserdata(m_L, sizeof(DebugLine*));
+		*l = line;
+		luaL_getmetatable(m_L, "DebugLine");
+		lua_setmetatable(m_L, -2);
 	}
 
 	//-----------------------------------------------------------------------------
 	DebugLine* get_debug_line(int32_t index)
 	{
-		return (DebugLine*) CHECKLIGHTDATA(m_L, index, always_true, "DebugLine");
+		DebugLine* l = *(DebugLine**) CHECKUDATA(m_L, index, "DebugLine");
+		return l;
 	}
 
 	//-----------------------------------------------------------------------------
@@ -477,6 +484,14 @@ public:
 		return *(Quaternion*)q;
 	}
 
+	Color4 get_color4(int32_t index)
+	{
+		// Color4 represented as Quaternion
+		void* c = CHECKLIGHTDATA(m_L, index, lua_system::is_quaternion, "Color4");
+		Quaternion& q = *(Quaternion*)c;
+		return Color4(q.x, q.y, q.z, q.w);
+	}
+
 	//-----------------------------------------------------------------------------
 	void push_vector2(const Vector2& v)
 	{
@@ -509,6 +524,22 @@ public:
 		lua_setmetatable(m_L, -2);
 	}
 
+	//-----------------------------------------------------------------------------
+	void push_vector2box(const Vector2& v)
+	{
+		Vector2* vec = (Vector2*) lua_newuserdata(m_L, sizeof(Vector2));
+		luaL_getmetatable(m_L, "Vector2Box");
+		lua_setmetatable(m_L, -2);
+		*vec = v;
+	}
+
+	//-----------------------------------------------------------------------------
+	Vector2& get_vector2box(uint32_t index)
+	{
+		Vector2* v = (Vector2*) CHECKUDATA(m_L, index, "Vector2Box");
+		return *v;
+	}
+
 	//-----------------------------------------------------------------------------
 	void push_vector3box(const Vector3& v)
 	{

+ 6 - 2
engine/lua/LuaSystem.cpp

@@ -69,10 +69,12 @@ extern void load_string_setting(LuaEnvironment& env);
 extern void load_touch(LuaEnvironment& env);
 extern void load_unit(LuaEnvironment& env);
 extern void load_vector2(LuaEnvironment& env);
+extern void load_vector2box(LuaEnvironment& env);
 extern void load_vector3(LuaEnvironment& env);
 extern void load_vector3box(LuaEnvironment& env);
 extern void load_window(LuaEnvironment& env);
 extern void load_world(LuaEnvironment& env);
+extern void load_color4(LuaEnvironment& env);
 
 namespace lua_system
 {
@@ -108,7 +110,7 @@ namespace lua_system
 		lua_pushinteger(L, 2);
 		lua_call(L, 2, 1); // Call debug.traceback
 
-		Log::e(lua_tostring(L, -1)); // Print error message
+		CE_LOGE(lua_tostring(L, -1)); // Print error message
 		lua_pop(L, 1); // Remove error message from stack
 		lua_pop(L, 1); // Remove debug.traceback from stack
 
@@ -126,7 +128,7 @@ namespace lua_system
 		const ResourceId lua_res = device()->resource_manager()->load("lua", filename);
 		device()->resource_manager()->flush();
 
-		const LuaResource* lr = (LuaResource*) device()->resource_manager()->data(lua_res);
+		const LuaResource* lr = (LuaResource*) device()->resource_manager()->get(lua_res);
 		luaL_loadbuffer(L, (const char*) lr->program(), lr->size(), "");
 
 		device()->resource_manager()->unload(lua_res);
@@ -334,10 +336,12 @@ namespace lua_system
 		load_touch(env);
 		load_unit(env);
 		load_vector2(env);
+		load_vector2box(env);
 		load_vector3(env);
 		load_vector3box(env);
 		load_window(env);
 		load_world(env);
+		load_color4(env);
 
 		// Register custom loader
 		lua_getfield(s_L, LUA_GLOBALSINDEX, "package");

+ 130 - 8
engine/lua/LuaUnit.cpp

@@ -208,9 +208,14 @@ static int unit_camera(lua_State* L)
 	LuaStack stack(L);
 
 	Unit* unit = stack.get_unit(1);
-	const char* camera_name = stack.get_string(2);
 
-	stack.push_camera(unit->camera(camera_name));
+	if (stack.is_number(2))
+	{
+		stack.push_camera(unit->camera((uint32_t) stack.get_int(2)));
+		return 1;
+	}
+
+	stack.push_camera(unit->camera(stack.get_string(2)));
 	return 1;
 }
 
@@ -220,9 +225,14 @@ static int unit_mesh(lua_State* L)
 	LuaStack stack(L);
 
 	Unit* unit = stack.get_unit(1);
-	const char* mesh_name = stack.get_string(2);
 
-	stack.push_mesh(unit->mesh(mesh_name));
+	if (stack.is_number(2))
+	{
+		stack.push_mesh(unit->mesh((uint32_t) stack.get_int(2)));
+		return 1;
+	}
+
+	stack.push_mesh(unit->mesh(stack.get_string(2)));
 	return 1;
 }
 
@@ -232,9 +242,14 @@ static int unit_sprite(lua_State* L)
 	LuaStack stack(L);
 
 	Unit* unit = stack.get_unit(1);
-	const char* sprite_name = stack.get_string(2);
 
-	stack.push_sprite(unit->sprite(sprite_name));
+	if (stack.is_number(2))
+	{
+		stack.push_sprite(unit->sprite((uint32_t) stack.get_int(2)));
+		return 1;
+	}
+
+	stack.push_sprite(unit->sprite(stack.get_string(2)));
 	return 1;
 }
 
@@ -244,9 +259,14 @@ static int unit_actor(lua_State* L)
 	LuaStack stack(L);
 
 	Unit* unit = stack.get_unit(1);
-	const char* actor_name = stack.get_string(2);
 
-	stack.push_actor(unit->actor(actor_name));
+	if (stack.is_number(2))
+	{
+		stack.push_actor(unit->actor((uint32_t) stack.get_int(2)));
+		return 1;
+	}
+
+	stack.push_actor(unit->actor(stack.get_string(2)));
 	return 1;
 }
 
@@ -274,6 +294,101 @@ static int unit_is_a(lua_State* L)
 	return 1;
 }
 
+//-----------------------------------------------------------------------------
+static int unit_play_sprite_animation(lua_State* L)
+{
+	LuaStack stack(L);
+
+	Unit* unit = stack.get_unit(1);
+	const char* anim = stack.get_string(2);
+	unit->play_sprite_animation(anim, stack.get_bool(3));
+	return 0;
+}
+
+//-----------------------------------------------------------------------------
+static int unit_stop_sprite_animation(lua_State* L)
+{
+	LuaStack stack(L);
+
+	Unit* unit = stack.get_unit(1);
+	unit->stop_sprite_animation();
+	return 0;
+}
+
+//-----------------------------------------------------------------------------
+static int unit_has_key(lua_State* L)
+{
+	LuaStack stack(L);
+
+	Unit* unit = stack.get_unit(1);
+	stack.push_bool(unit->has_key(stack.get_string(2)));
+	return 1;
+}
+
+//-----------------------------------------------------------------------------
+static int unit_get_key(lua_State* L)
+{
+	LuaStack stack(L);
+
+	Unit* unit = stack.get_unit(1);
+	const char* key = stack.get_string(2);
+
+	switch (unit->value_type(key))
+	{
+		case ValueType::BOOL:
+		{
+			bool val;
+			unit->get_key(key, val);
+			stack.push_bool(val);
+			return 1;
+		}
+		case ValueType::FLOAT:
+		{
+			float val;
+			unit->get_key(key, val);
+			stack.push_float(val);
+			return 1;
+		}
+		case ValueType::STRING:
+		{
+			StringId32 val;
+			unit->get_key(key, val);
+			stack.push_uint32(val);
+			return 1;
+		}
+		case ValueType::VECTOR3:
+		{
+			Vector3 val;
+			unit->get_key(key, val);
+			stack.push_vector3(val);
+			return 1;
+		}
+		default: CE_FATAL("Unknown value type"); break;
+	}
+
+	return 0;
+}
+
+//-----------------------------------------------------------------------------
+static int unit_set_key(lua_State* L)
+{
+	LuaStack stack(L);
+
+	Unit* unit = stack.get_unit(1);
+	const char* key = stack.get_string(2);
+
+	switch (stack.value_type(3))
+	{
+		case LUA_TBOOLEAN: unit->set_key(key, stack.get_bool(3)); break;
+		case LUA_TNUMBER: unit->set_key(key, stack.get_float(3)); break;
+		case LUA_TSTRING: unit->set_key(key, stack.get_string(3)); break;
+		case LUA_TLIGHTUSERDATA: unit->set_key(key, stack.get_vector3(3)); break;
+		default: CE_FATAL("Unsupported value type"); break; // FIXME use LUA_ASSERT
+	}
+
+	return 0;
+}
+
 //-----------------------------------------------------------------------------
 void load_unit(LuaEnvironment& env)
 {
@@ -300,6 +415,13 @@ void load_unit(LuaEnvironment& env)
 	env.load_module_function("Unit", "controller",				unit_controller);
 
 	env.load_module_function("Unit", "is_a",					unit_is_a);
+
+	env.load_module_function("Unit", "play_sprite_animation",	unit_play_sprite_animation);
+	env.load_module_function("Unit", "stop_sprite_animation",	unit_stop_sprite_animation);
+
+	env.load_module_function("Unit", "has_key",					unit_has_key);
+	env.load_module_function("Unit", "get_key",					unit_get_key);
+	env.load_module_function("Unit", "set_key",					unit_set_key);
 }
 
 } // namespace crown

+ 162 - 0
engine/lua/LuaVector2Box.cpp

@@ -0,0 +1,162 @@
+/*
+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 "LuaEnvironment.h"
+#include "LuaStack.h"
+#include "Vector2.h"
+#include "StringUtils.h"
+
+namespace crown
+{
+
+//-----------------------------------------------------------------------------
+static int vector2box_new(lua_State* L)
+{
+	LuaStack stack(L);
+
+	Vector2 v;
+	if (stack.num_args() == 1)
+	{
+		const Vector2 tv = stack.get_vector2(1);
+		v = tv;
+	}
+	else if (stack.num_args() == 2)
+	{
+		v.x = stack.get_float(1);
+		v.y = stack.get_float(2);
+	}
+
+	stack.push_vector2box(v);
+	return 1;
+}
+
+//-----------------------------------------------------------------------------
+static int vector2box_ctor(lua_State* L)
+{
+	LuaStack stack(L);
+	stack.remove(1); // Remove table
+	return vector2box_new(L);
+}
+
+//-----------------------------------------------------------------------------
+static int vector2box_get_value(lua_State* L)
+{
+	LuaStack stack(L);
+
+	Vector2& v = stack.get_vector2box(1);
+	const char* s = stack.get_string(2);
+
+	if (string::strcmp(s, "x") == 0)
+	{
+		stack.push_float(v.x);
+		return 1;
+	}
+	else if (string::strcmp(s, "y") == 0)
+	{
+		stack.push_float(v.y);
+		return 1;
+	}
+
+	// Never happens
+	return 0;
+}
+
+//-----------------------------------------------------------------------------
+static int vector2box_set_value(lua_State* L)
+{
+	LuaStack stack(L);
+
+	Vector2& v = stack.get_vector2box(1);
+	const char* s = stack.get_string(2);
+	float value = stack.get_float(3);
+
+	if (string::strcmp(s, "x") == 0)
+	{
+		v.x = value;
+	}
+	else if (string::strcmp(s, "y") == 0)
+	{
+		v.y = value;
+	}
+
+	return 0;
+}
+
+//-----------------------------------------------------------------------------
+static int vector2box_store(lua_State* L)
+{
+	LuaStack stack(L);
+
+	Vector2& v = stack.get_vector2box(1);
+	
+	if (stack.num_args() == 2)
+	{
+		Vector2 tv = stack.get_vector2(2);
+
+		v = tv;
+	}
+	else if (stack.num_args() == 3)
+	{
+		v.x = stack.get_float(2);
+		v.y = stack.get_float(3);
+	}
+	return 0;
+}
+
+//-----------------------------------------------------------------------------
+static int vector2box_unbox(lua_State* L)
+{
+	LuaStack stack(L);
+
+	Vector2& v = stack.get_vector2box(1);
+
+	stack.push_vector2(v);
+	return 1;
+}
+
+//-----------------------------------------------------------------------------
+static int vector2box_tostring(lua_State* L)
+{
+	LuaStack stack(L);
+	Vector2& v = stack.get_vector2box(1);
+	stack.push_fstring("Vector2Box (%p)", &v);
+	return 1;
+}
+
+//-----------------------------------------------------------------------------
+void load_vector2box(LuaEnvironment& env)
+{
+	env.load_module_function("Vector2Box", "new",			vector2box_new);
+	env.load_module_function("Vector2Box", "store",			vector2box_store);
+	env.load_module_function("Vector2Box", "unbox",			vector2box_unbox);
+	env.load_module_function("Vector2Box", "__index",		vector2box_get_value);
+	env.load_module_function("Vector2Box", "__newindex",	vector2box_set_value);
+	env.load_module_function("Vector2Box", "__tostring",	vector2box_tostring);
+
+	env.load_module_constructor("Vector2Box",				vector2box_ctor);
+}
+
+} // namespace crown

+ 4 - 4
engine/lua/LuaVector3Box.cpp

@@ -124,15 +124,15 @@ static int vector3box_store(lua_State* L)
 	
 	if (stack.num_args() == 2)
 	{
-		Vector3 tv = stack.get_vector3(1);
+		Vector3 tv = stack.get_vector3(2);
 
 		v = tv;
 	}
 	else if (stack.num_args() == 4)
 	{
-		v.x = stack.get_float(1);
-		v.y = stack.get_float(2);
-		v.z = stack.get_float(3);
+		v.x = stack.get_float(2);
+		v.y = stack.get_float(3);
+		v.z = stack.get_float(4);
 	}
 	return 0;
 }

+ 41 - 5
engine/lua/LuaWorld.cpp

@@ -28,8 +28,8 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "LuaEnvironment.h"
 #include "World.h"
 #include "Gui.h"
-#include "Device.h"
-#include "LuaSystem.h"
+#include "TempAllocator.h"
+#include "Array.h"
 
 namespace crown
 {
@@ -47,7 +47,7 @@ static int world_spawn_unit(lua_State* L)
 
 	UnitId unit = world->spawn_unit(name, pos, rot);
 
-	stack.push_unit(world->lookup_unit(unit));
+	stack.push_unit(world->get_unit(unit));
 	return 1;
 }
 
@@ -74,6 +74,29 @@ static int world_num_units(lua_State* L)
 	return 1;
 }
 
+//-----------------------------------------------------------------------------
+static int world_units(lua_State* L)
+{
+	LuaStack stack(L);
+
+	World* world = stack.get_world(1);
+
+	TempAllocator1024 alloc;
+	Array<UnitId> all_units(alloc);
+
+	world->units(all_units);
+
+	stack.push_table();
+	for (uint32_t i = 0; i < array::size(all_units); i++)
+	{
+		stack.push_key_begin((int32_t) i + 1);
+		stack.push_unit(world->get_unit(all_units[i]));
+		stack.push_key_end();
+	}
+
+	return 1;
+}
+
 //-----------------------------------------------------------------------------
 static int world_play_sound(lua_State* L)
 {
@@ -175,9 +198,9 @@ static int world_create_window_gui(lua_State* L)
 	LuaStack stack(L);
 
 	World* world = stack.get_world(1);
-	GuiId id = world->create_window_gui(stack.get_string(2));
+	GuiId id = world->create_window_gui(stack.get_int(2), stack.get_int(3));
 
-	stack.push_gui(world->lookup_gui(id));
+	stack.push_gui(world->get_gui(id));
 	return 1;
 }
 
@@ -240,6 +263,16 @@ static int world_destroy_debug_line(lua_State* L)
 	return 0;
 }
 
+//-----------------------------------------------------------------------------
+static int world_load_level(lua_State* L)
+{
+	LuaStack stack(L);
+
+	World* world = stack.get_world(1);
+	world->load_level(stack.get_string(2));
+	return 0;
+}
+
 //-----------------------------------------------------------------------------
 static int world_tostring(lua_State* L)
 {
@@ -255,6 +288,7 @@ void load_world(LuaEnvironment& env)
 	env.load_module_function("World", "spawn_unit",			world_spawn_unit);
 	env.load_module_function("World", "destroy_unit",       world_destroy_unit);
 	env.load_module_function("World", "num_units",          world_num_units);
+	env.load_module_function("World", "units",              world_units);
 
 	env.load_module_function("World", "play_sound",			world_play_sound);
 	env.load_module_function("World", "stop_sound", 		world_stop_sound);
@@ -273,6 +307,8 @@ void load_world(LuaEnvironment& env)
 	env.load_module_function("World", "create_debug_line",  world_create_debug_line);
 	env.load_module_function("World", "destroy_debug_line", world_destroy_debug_line);
 
+	env.load_module_function("World", "load_level",			world_load_level);
+
 	env.load_module_function("World", "__index",			"World");
 	env.load_module_function("World", "__tostring",			world_tostring);
 }

+ 185 - 117
engine/os/android/AndroidDevice.cpp

@@ -25,6 +25,8 @@ OTHER DEALINGS IN THE SOFTWARE.
 */
 
 #include <jni.h>
+#include <android/sensor.h>
+#include <android_native_app_glue.h>
 #include "Allocator.h"
 #include "Device.h"
 #include "Log.h"
@@ -36,6 +38,9 @@ OTHER DEALINGS IN THE SOFTWARE.
 namespace crown
 {
 
+ANativeWindow* g_android_window;
+AAssetManager* g_android_asset_manager;
+
 class AndroidDevice : public Device
 {
 public:
@@ -50,27 +55,85 @@ public:
 	}
 
 	//-----------------------------------------------------------------------------
-	int32_t run(int, char**)
+	void display_modes(Array<DisplayMode>& /*modes*/)
+	{
+		// Do nothing
+	}
+
+	//-----------------------------------------------------------------------------
+	void set_display_mode(uint32_t /*id*/)
+	{
+		// Do nothing
+	}
+
+	//-----------------------------------------------------------------------------
+	void set_fullscreen(bool /*full*/)
+	{
+		// Do nothing
+	}
+
+	void run(struct android_app* app)
 	{
-		m_game_thread.start(main_loop, (void*)this);
+		app->userData = this;
+		app->onAppCmd = crown::AndroidDevice::on_app_cmd;
+		app->onInputEvent = crown::AndroidDevice::on_input_event;
+		g_android_asset_manager = app->activity->assetManager;
+
+		while (app->destroyRequested == 0)
+		{
+			int32_t num;
+			android_poll_source* source;
+			/*int32_t id =*/ ALooper_pollAll(-1, NULL, &num, (void**)&source);
 
-		//while (true) {}
+			if (NULL != source)
+			{
+				source->process(app, source);
+			}
+		}
+
+		m_game_thread.stop();
+	}
+
+	//-----------------------------------------------------------------------------
+	int32_t run(int, char**)
+	{
 		return 0;
 	}
 
 	//-----------------------------------------------------------------------------
 	int32_t loop()
 	{
+		#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
+			m_console = CE_NEW(default_allocator(), ConsoleServer)();
+			m_console->init(m_console_port, false);
+		#endif
+
 		Device::init();
 
+		// Push metrics here since Android does not trigger APP_CMD_WINDOW_RESIZED
+		const int32_t width = ANativeWindow_getWidth(g_android_window);
+		const int32_t height = ANativeWindow_getHeight(g_android_window);
+		m_queue.push_metrics_event(0, 0, width, height);
+
 		while (is_running() && !process_events())
 		{
+			#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
+				m_console->update();
+			#endif
+
 			Device::frame();
 			m_touch->update();
 			m_keyboard->update();
 		}
 
 		Device::shutdown();
+
+		#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
+			m_console->shutdown();
+			CE_DELETE(default_allocator(), m_console);
+		#endif
+
+		exit(EXIT_SUCCESS);
 		return 0;
 	}
 
@@ -107,33 +170,28 @@ public:
 				{
 					const OsKeyboardEvent& ev = event.keyboard;
 					m_keyboard->set_button_state(ev.button, ev.pressed);
-					Log::i("KEYBOARD EVENT RECEIVED");
 					break;
 				}
 				case OsEvent::METRICS:
 				{
 					const OsMetricsEvent& ev = event.metrics;
-					m_window->m_x = 0;
-					m_window->m_y = 0;
+					m_window->m_x = ev.x;
+					m_window->m_y = ev.y;
 					m_window->m_width = ev.width;
 					m_window->m_height = ev.height;
-					Log::i("METRICS EVENT RECEIVED");
 					break;
 				}
 				case OsEvent::EXIT:
 				{
-					Log::i("EXIT EVENT RECEIVED");
 					return true;
 				}
 				case OsEvent::PAUSE:
 				{
-					Log::i("PAUSE EVENT RECEIVED, pausing...");
 					pause();
 					break;
 				}
 				case OsEvent::RESUME:
 				{
-					Log::i("RESUME EVENT RECEIVED, resuming...");
 					unpause();
 					break;
 				}
@@ -149,139 +207,149 @@ public:
 	}
 
 	//-----------------------------------------------------------------------------
-	void push_keyboard_event(uint32_t modifier, KeyboardButton::Enum b, bool pressed)
-	{
-		m_queue.push_keyboard_event(modifier, b, pressed);
-	}
-
-	//-----------------------------------------------------------------------------
-	void push_touch_event(uint16_t x, uint16_t y, uint8_t pointer_id)
+	static void on_app_cmd(struct android_app* app, int32_t cmd)
 	{
-		m_queue.push_touch_event(x, y, pointer_id);
+		((AndroidDevice*) app->userData)->process_command(app, cmd);
 	}
 
 	//-----------------------------------------------------------------------------
-	void push_touch_event(uint16_t x, uint16_t y, uint8_t pointer_id, bool pressed)
+	void process_command(struct android_app* app, int32_t cmd)
 	{
-		m_queue.push_touch_event(x, y, pointer_id, pressed);
-	}
-
-	void push_metrics_event(uint16_t x, uint16_t y, uint16_t width, uint16_t height)
-	{
-		m_queue.push_metrics_event(x, y, width, height);
-	}
-
-	//-----------------------------------------------------------------------------
-	void push_pause_event()
-	{
-		m_queue.push_pause_event();
+		switch (cmd)
+		{
+			case APP_CMD_SAVE_STATE:
+			{
+				// // The system has asked us to save our current state.  Do so.
+				// engine->app->savedState = malloc(sizeof(struct saved_state));
+				// *((struct saved_state*)engine->app->savedState) = engine->state;
+				// engine->app->savedStateSize = sizeof(struct saved_state);
+				break;
+			}
+			case APP_CMD_INIT_WINDOW:
+			{
+				CE_ASSERT(app->window != NULL, "Android window is NULL");
+				g_android_window = app->window;
+				m_game_thread.start(main_loop, (void*)this);
+				break;
+			}
+			case APP_CMD_TERM_WINDOW:
+			{
+				// The window is being hidden or closed, clean it up.
+				break;
+			}
+			case APP_CMD_WINDOW_RESIZED:
+			{
+				// Not triggered by Android
+				break;
+			}
+			case APP_CMD_GAINED_FOCUS:
+			{
+				break;
+			}
+			case APP_CMD_LOST_FOCUS:
+			{
+				break;
+			}
+			case APP_CMD_DESTROY:
+			{
+				m_queue.push_exit_event(0);
+				break;
+			}
+		}
 	}
 
 	//-----------------------------------------------------------------------------
-	void push_resume_event()
+	static int32_t on_input_event(struct android_app* app, AInputEvent* event)
 	{
-		m_queue.push_resume_event();
+		return ((AndroidDevice*) app->userData)->process_input(app, event);
 	}
 
 	//-----------------------------------------------------------------------------
-	void push_exit_event(int32_t code)
+	int32_t process_input(struct android_app* app, AInputEvent* event)
 	{
-		m_queue.push_exit_event(code);
-	}
-
-private:
-
-	OsEventQueue m_queue;
-	OsThread m_game_thread;
-};
-
-static AndroidDevice* g_engine;
-ANativeWindow* g_android_window;
+		if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION)
+		{
+			const int32_t action = AMotionEvent_getAction(event);
+			const int32_t pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
+			const int32_t pointerCount = AMotionEvent_getPointerCount(event);
 
-//-----------------------------------------------------------------------------
-extern "C" JNIEXPORT void JNICALL Java_crown_android_CrownLib_initCrown(JNIEnv* /*env*/, jobject /*obj*/)
-{
-	memory::init();
-	os::init_os();
+			const int32_t pointerId = AMotionEvent_getPointerId(event, pointerIndex);
+			const float x = AMotionEvent_getX(event, pointerIndex);
+			const float y = AMotionEvent_getY(event, pointerIndex);
 
-	g_engine = CE_NEW(default_allocator(), AndroidDevice);
-	set_device(g_engine);
-}
+			const int32_t actionMasked = (action & AMOTION_EVENT_ACTION_MASK);
 
-//-----------------------------------------------------------------------------
-extern "C" JNIEXPORT void JNICALL Java_crown_android_CrownLib_shutdownCrown(JNIEnv* /*env*/, jobject /*obj*/)
-{
-	CE_DELETE(default_allocator(), g_engine);
-	memory::shutdown();
-}
+			switch (actionMasked)
+			{	
+				case AMOTION_EVENT_ACTION_DOWN:
+				case AMOTION_EVENT_ACTION_POINTER_DOWN:
+				{
+					m_queue.push_touch_event((uint16_t) x, (uint16_t) y, (uint8_t) pointerId, true);
+					break;			
+				}
+				case AMOTION_EVENT_ACTION_UP:
+				case AMOTION_EVENT_ACTION_POINTER_UP:
+				{
+					m_queue.push_touch_event((uint16_t) x, (uint16_t) y, (uint8_t) pointerId, false);
+					break;
+				}
+				case AMOTION_EVENT_ACTION_OUTSIDE:
+				case AMOTION_EVENT_ACTION_CANCEL:
+				{
+					m_queue.push_touch_event((uint16_t) x, (uint16_t) y, (uint8_t) pointerId, false);
+					break;			
+				}
+				case AMOTION_EVENT_ACTION_MOVE:
+				{
+					for (int index = 0; index < pointerCount; index++)
+					{
+						const float xx = AMotionEvent_getX(event, index);
+						const float yy = AMotionEvent_getY(event, index);
+						const int32_t id = AMotionEvent_getPointerId(event, index);
+						m_queue.push_touch_event((uint16_t) xx, (uint16_t) yy, (uint8_t) id);
+					}
+					break;
+				}
+			}
 
-//-----------------------------------------------------------------------------
-extern "C" JNIEXPORT void JNICALL Java_crown_android_CrownLib_run(JNIEnv* /*env*/, jobject /*obj*/)
-{
-	g_engine->run(0, NULL);
-}
+			return 1;
+		}
+		else if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY)
+		{
+			const int32_t keycode = AKeyEvent_getKeyCode(event);
+			const int32_t keyaction = AKeyEvent_getAction(event);
 
-//-----------------------------------------------------------------------------
-extern "C" void Java_crown_android_CrownLib_acquireWindow(JNIEnv *env, jclass /*clazz*/, jobject surface)
-{
-    // Obtain a native window from a Java surface
-	CE_ASSERT(surface != 0, "Unable to get Android window");
-    g_android_window = ANativeWindow_fromSurface(env, surface);
-    ANativeWindow_acquire(g_android_window);
-    Log::i("Window acquired");
-}
+			if (keycode == AKEYCODE_BACK)
+			{
+				m_queue.push_keyboard_event(0, KeyboardButton::ESCAPE, keyaction == AKEY_EVENT_ACTION_DOWN ? true : false);
+			}
 
-//-----------------------------------------------------------------------------
-extern "C" void Java_crown_android_CrownLib_releaseWindow(JNIEnv *env, jclass /*clazz*/, jobject surface)
-{
-    ANativeWindow_release(g_android_window);
-    Log::i("Window released");
-}
+			return 1;
+		}
 
-//-----------------------------------------------------------------------------
-extern "C" JNIEXPORT void JNICALL Java_crown_android_CrownLib_pushKeyboardEvent(JNIEnv * /*env*/, jobject /*obj*/, jint modifier, jint b, jint pressed)
-{
-	g_engine->push_keyboard_event(modifier, (KeyboardButton::Enum) b, pressed);
-}
+		return 0;
+	}
 
-//-----------------------------------------------------------------------------
-extern "C" JNIEXPORT void JNICALL Java_crown_android_CrownLib_pushTouchEventMove(JNIEnv * /*env*/, jobject /*obj*/, jint pointer_id, jint x, jint y)
-{
-	g_engine->push_touch_event(x, y, pointer_id);
-}
+private:
 
-//-----------------------------------------------------------------------------
-extern "C" JNIEXPORT void JNICALL Java_crown_android_CrownLib_pushTouchEventPointer(JNIEnv * /*env*/, jobject /*obj*/, jint pointer_id, jint x, jint y, jint pressed)
-{
-	g_engine->push_touch_event(x, y, pointer_id, pressed);
-}
+	OsEventQueue m_queue;
+	OsThread m_game_thread;
+};
 
-//-----------------------------------------------------------------------------
-extern "C" JNIEXPORT void JNICALL Java_crown_android_CrownLib_pushAccelerometerEvent(JNIEnv * /*env*/, jobject /*obj*/, jint type, jfloat x, jfloat y, jfloat z)
-{
-}
+} // namespace crown
 
-extern "C" JNIEXPORT void JNICALL Java_crown_android_CrownLib_pushMetricsEvent(JNIEnv * /*env*/, jobject /*obj*/, jint x, jint y, jint width, jint height)
+void android_main(struct android_app* app)
 {
-	g_engine->push_metrics_event(x, y, width, height);
-}
+	// Make sure glue isn't stripped.
+	app_dummy();
 
-//-----------------------------------------------------------------------------
-extern "C" JNIEXPORT void JNICALL Java_crown_android_CrownLib_pushPauseEvent(JNIEnv * /*env*/, jobject /*obj*/)
-{
-	g_engine->push_pause_event();
-}
+	crown::memory::init();
+	crown::os::init_os();
+	crown::AndroidDevice* engine = CE_NEW(crown::default_allocator(), crown::AndroidDevice)();
+	crown::set_device(engine);
 
-//-----------------------------------------------------------------------------
-extern "C" JNIEXPORT void JNICALL Java_crown_android_CrownLib_pushResumeEvent(JNIEnv * /*env*/, jobject /*obj*/)
-{
-	g_engine->push_resume_event();
-}
+	engine->run(app);
 
-//-----------------------------------------------------------------------------
-extern "C" JNIEXPORT void JNICALL Java_crown_android_CrownLib_pushExitEvent(JNIEnv * /*env*/, jobject /*obj*/, jint code)
-{
-	g_engine->push_exit_event(code);
+	CE_DELETE(crown::default_allocator(), engine);
+	crown::memory::shutdown();
 }
-
-} // namespace crown

+ 22 - 20
engine/os/android/AndroidManifest.xml

@@ -1,24 +1,26 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-      package="crown.android"
-      android:versionCode="1"
-      android:versionName="1.0">
-    <uses-sdk
-        android:minSdkVersion="9"/>
+			package="crown.android"
+			android:versionCode="1"
+			android:versionName="1.0">
+		<uses-sdk android:minSdkVersion="9"/>
 
-    <uses-permission android:name="android.permission.INTERNET"/>
-    <uses-permission android:name="android.permission.SET_DEBUG_APP"/>
-    
-    <application android:label="Crown" >
-        <activity android:name="CrownActivity"
-                  android:label="Crown"
-				  android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
-				  android:screenOrientation="landscape" 
-				  android:configChanges="orientation|keyboardHidden">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
+		<uses-permission android:name="android.permission.INTERNET"/>
+		<uses-permission android:name="android.permission.SET_DEBUG_APP"/>
+		
+		<application android:label="Crown" android:hasCode="true">
+				<activity android:name=".CrownActivity"
+									android:label="Crown"
+									android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+									android:screenOrientation="landscape" 
+									android:configChanges="orientation|keyboardHidden">
+						<!-- Tell NativeActivity the name of our .so -->
+						<meta-data android:name="android.app.lib_name"
+												android:value="crown" />
+						<intent-filter>
+								<action android:name="android.intent.action.MAIN" />
+								<category android:name="android.intent.category.LAUNCHER" />
+						</intent-filter>
+				</activity>
+		</application>
 </manifest> 

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

@@ -24,11 +24,16 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
 */
 
-#include <android/asset_manager_jni.h>
 #include "ApkFile.h"
 #include "Assert.h"
+#include "Macros.h"
+#include "Log.h"
+#include <android/asset_manager.h>
 
-static AAssetManager* g_android_asset_manager = NULL;
+namespace crown
+{
+
+extern AAssetManager* g_android_asset_manager;
 
 //-----------------------------------------------------------------------------
 AAssetManager* get_android_asset_manager()
@@ -36,15 +41,6 @@ AAssetManager* get_android_asset_manager()
 	return g_android_asset_manager;
 }
 
-//-----------------------------------------------------------------------------
-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
-{
-
 //-----------------------------------------------------------------------------
 ApkFile::ApkFile(const char* path)
 	: File(FOM_READ), m_asset(NULL)
@@ -68,6 +64,7 @@ void ApkFile::seek(size_t position)
 {
 	off_t seek_result = AAsset_seek(m_asset, (off_t)position, SEEK_SET);
 	CE_ASSERT(seek_result != (off_t) -1, "Failed to seek");
+	CE_UNUSED(seek_result);
 }
 
 //-----------------------------------------------------------------------------
@@ -75,6 +72,7 @@ void ApkFile::seek_to_end()
 {
 	off_t seek_result = AAsset_seek(m_asset, 0, SEEK_END);
 	CE_ASSERT(seek_result != (off_t) -1, "Failed to seek to end");
+	CE_UNUSED(seek_result);
 }
 
 //-----------------------------------------------------------------------------
@@ -82,6 +80,7 @@ void ApkFile::skip(size_t bytes)
 {
 	off_t seek_result = AAsset_seek(m_asset, (off_t) bytes, SEEK_CUR);
 	CE_ASSERT(seek_result != (off_t) -1, "Failed to skip");
+	CE_UNUSED(seek_result);
 }
 
 //-----------------------------------------------------------------------------
@@ -91,6 +90,7 @@ void ApkFile::read(void* buffer, size_t 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);
+	CE_UNUSED(bytes_read);
 }
 
 //-----------------------------------------------------------------------------

+ 18 - 17
engine/os/android/ApkFile.h

@@ -27,6 +27,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #pragma once
 
 #include "File.h"
+#include <android/asset_manager.h>
 
 namespace crown
 {
@@ -36,54 +37,54 @@ class ApkFile : public File
 public:
 
 	/// Opens the given @a filename.
-				ApkFile(const char* filename);
-				~ApkFile();
+	ApkFile(const char* filename);
+	~ApkFile();
 
 	/// @copydoc File::seek()
-	void		seek(size_t position);
+	void seek(size_t position);
 
 	/// @copydoc File::seek_to_end()
-	void		seek_to_end();
+	void seek_to_end();
 
 	/// @copydoc File::skip()
-	void		skip(size_t bytes);
+	void skip(size_t bytes);
 
 	/// @copydoc File::read()
-	void		read(void* buffer, size_t size);
+	void read(void* buffer, size_t size);
 
 	/// @copydoc File::write()
-	void		write(const void* buffer, size_t size);
+	void write(const void* buffer, size_t size);
 
 	/// @copydoc File::copy_to()
-	bool		copy_to(File& file, size_t size = 0);
+	bool copy_to(File& file, size_t size = 0);
 
 	/// @copydoc File::flush()
-	void		flush();
+	void flush();
 
 	/// @copydoc File::is_valid()
-	bool		is_valid();
+	bool is_valid();
 
 	/// @copydoc File::end_of_file()
-	bool		end_of_file();
+	bool end_of_file();
 
 	/// @copydoc File::size()
-	size_t		size();
+	size_t size();
 
 	/// @copydoc File::position()
-	size_t		position();
+	size_t position();
 
 	/// @copydoc File::can_read()
-	bool		can_read() const;
+	bool can_read() const;
 
 	/// @copydoc File::can_write()
-	bool		can_write() const;
+	bool can_write() const;
 
 	/// @copydoc File::can_seek()
-	bool		can_seek() const;
+	bool can_seek() const;
 
 private:
 
-	AAsset*		m_asset;
+	AAsset* m_asset;
 };
 
 } // namespace crown

+ 2 - 2
engine/os/android/ApkFilesystem.cpp

@@ -30,11 +30,11 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "ApkFile.h"
 #include "OS.h"
 
-extern AAssetManager* get_android_asset_manager();
-
 namespace crown
 {
 
+extern AAssetManager* get_android_asset_manager();
+
 //-----------------------------------------------------------------------------
 ApkFilesystem::ApkFilesystem()
 {

+ 22 - 22
engine/os/android/OsWindow.h

@@ -38,63 +38,63 @@ class OsWindow
 public:
 
 	/// Stub method, does nothing under Android.
-					OsWindow();
-					~OsWindow();
+	OsWindow();
+	~OsWindow();
 
 	/// Stub method, does nothing under Android.
-	void			show();
+	void show();
 
 	/// Stub method, does nothing under Android.
-	void			hide();
+	void hide();
 
 	/// Returns the size in pixel of the window.
-	void			get_size(uint32_t& width, uint32_t& height);
+	void get_size(uint32_t& width, uint32_t& height);
 
 	/// Returns always (0, 0) under Android.
-	void			get_position(uint32_t& x, uint32_t& y);
+	void get_position(uint32_t& x, uint32_t& y);
 
 	/// Stub method, does nothing under Android.
-	void			resize(uint32_t width, uint32_t height);
+	void resize(uint32_t width, uint32_t height);
 
 	/// Stub method, does nothing under Android.
-	void			move(uint32_t x, uint32_t y);
+	void move(uint32_t x, uint32_t y);
 
 	/// Stub method, does nothing under Android.	
-	void			minimize();
+	void minimize();
 
 	/// Stub method, does nothing under Android.
-	void			restore();
+	void restore();
 
 	/// Returns always false.
-	bool			is_resizable() const;
+	bool is_resizable() const;
 
 	/// Stub method, does nothing under Android.	
-	void			set_resizable(bool resizeable);
+	void set_resizable(bool resizeable);
 
 	/// Stub method, does nothing under Android.
-	void			show_cursor(bool show);
+	void show_cursor(bool show);
 
 	/// Stub method, does nothing under Android.
-	void			get_cursor_xy(int32_t& x, int32_t& y);
+	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);
+	void set_cursor_xy(int32_t x, int32_t y);
 
 	/// Returns always NULL under Android.
-	char*			title();
+	char* title();
 
 	/// Stub method, does nothing under Android.
-	void			set_title(const char* title);
+	void set_title(const char* title);
 
 	/// Stub method, does nothing under Android.
-	void			frame();
+	void frame();
 
 public:
 
-	uint32_t		m_x;
-	uint32_t		m_y;
-	uint32_t		m_width;
-	uint32_t		m_height;
+	uint32_t m_x;
+	uint32_t m_y;
+	uint32_t m_width;
+	uint32_t m_height;
 };
 
 } // namespace crown

+ 17 - 131
engine/os/android/java/CrownActivity.java

@@ -26,150 +26,36 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 package crown.android;
 
-import android.app.Activity;
+import android.app.NativeActivity;
 import android.os.Bundle;
 import android.util.Log;
-import android.view.WindowManager;
-import android.view.MotionEvent;
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener;
-import android.hardware.SensorManager;
-import android.content.Context;
-import android.widget.Toast;
-import android.content.res.AssetManager;
-import android.view.View;
-import android.view.Surface;
-import android.view.SurfaceView;
-import android.view.SurfaceHolder;
-import android.view.KeyEvent;
 
-public class CrownActivity extends Activity
+public class CrownActivity extends NativeActivity
 {
-	// Debug
-	public static String TAG = "crown";
-
-	// Resource attributes
-    static AssetManager 		mAssetManager;
-	private CrownSurfaceView 	mView;
-
-
-	//-----------------------------------------------------------------------------
-    public void onCreate(Bundle savedInstanceState)
-    {
-        super.onCreate(savedInstanceState);
-
-        // Initializes low-level systems (memory, os etc.)
-        CrownLib.initCrown();
-
-		// init AssetManager
-		mAssetManager = getAssets();
-		CrownLib.initAssetManager(mAssetManager);
-
-		// init Native Window
-		mView = new CrownSurfaceView(this);
-        setContentView(mView);
-
-		Log.i(TAG, "Crown Activity created");
-    }
-
-	//-----------------------------------------------------------------------------
-	public void onResume()
-	{
-		super.onResume();
-		CrownLib.pushResumeEvent();
-		Log.i(TAG, "Crown Activity resumed");
-	}
-
-	//-----------------------------------------------------------------------------
-	public void onPause()
+	static 
 	{
-		super.onPause();
-		CrownLib.pushPauseEvent();
-		Log.i(TAG, "Crown Activity paused");
+		System.loadLibrary("luajit-5.1");
+		System.loadLibrary("crown");
 	}
 
-	//-----------------------------------------------------------------------------
-	public void onDestroy()
-	{
-		super.onDestroy();
-		CrownLib.pushExitEvent(0);
-		CrownLib.releaseWindow();
-		CrownLib.shutdownCrown();
-		Log.i(TAG, "Crown Activity destroyed");
-	}
-
-	//-----------------------------------------------------------------------------
-	public void onBackPressed()
-	{
-		// Simulate ESCAPE key
-		CrownLib.pushKeyboardEvent(0, 0x1B, 1);
-	}
+	public static String TAG = "crown";
 
-	//-----------------------------------------------------------------------------
-	@Override
-	public boolean onKeyDown(int keyCode, KeyEvent event)
-	{
-		if ((keyCode == KeyEvent.KEYCODE_BACK))
-		{
-			CrownLib.pushKeyboardEvent(0, 0x1B, 1);
-		}
-		return super.onKeyUp(keyCode, event);
-	}
+	CrownActivity _activity;
 
-	//-----------------------------------------------------------------------------
 	@Override
-	public boolean onKeyUp(int keyCode, KeyEvent event)
-	{
-		if ((keyCode == KeyEvent.KEYCODE_BACK))
-		{
-			CrownLib.pushKeyboardEvent(0, 0x1B, 0);
-		}
-		return super.onKeyDown(keyCode, event);
-	}
-
-	//-----------------------------------------------------------------------------
-	public boolean onTouchEvent(MotionEvent event)
+	public void onCreate(Bundle savedInstanceState)
 	{
-		final int pointerIndex = event.getActionIndex();
-		final int pointerCount = event.getPointerCount();
+		super.onCreate(savedInstanceState);
 
-		final int pointerId = event.getPointerId(pointerIndex);
-		final float x = event.getX(pointerIndex);
-		final float y = event.getY(pointerIndex);
+		_activity = this;
 
-		final int actionMasked = event.getActionMasked();
-
-		switch (actionMasked) 
-		{	
-			case MotionEvent.ACTION_DOWN:
-			case MotionEvent.ACTION_POINTER_DOWN:
-			{
-				CrownLib.pushTouchEventPointer(pointerId, (int) x, (int) y, 1);
-				break;			
-			}
-			case MotionEvent.ACTION_UP:
-			case MotionEvent.ACTION_POINTER_UP:
-			{
-				CrownLib.pushTouchEventPointer(pointerId, (int) x, (int) y, 0);
-				break;
-			}
-			case MotionEvent.ACTION_OUTSIDE:
-			case MotionEvent.ACTION_CANCEL:
-			{
-				CrownLib.pushTouchEventPointer(pointerId, (int)x, (int)y, 0);
-				break;			
-			}
-			case MotionEvent.ACTION_MOVE:
-			{
-				for (int index = 0; index < pointerCount; index++)
-				{
-					CrownLib.pushTouchEventMove(event.getPointerId(index), (int)event.getX(index), (int)event.getY(index));
-				}
-				break;
-			}
-		}
+		// Init additional stuff here (ads, etc.)
+    }
 
-        return super.onTouchEvent(event);
+	@Override
+	public void onDestroy()
+	{
+		// Destroy additional stuff here (ads, etc)
+		super.onDestroy();
 	}
 }

+ 105 - 17
engine/os/linux/main.cpp

@@ -28,6 +28,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include <X11/Xatom.h>
 #include <X11/Xlib.h>
 #include <X11/XKBlib.h>
+#include <X11/extensions/Xrandr.h>
 #include "Config.h"
 #include "Crown.h"
 #include "Device.h"
@@ -128,6 +129,7 @@ public:
 		, m_x11_window(None)
 		, m_x11_parent_window(None)
 		, m_x11_hidden_cursor(None)
+		, m_screen_config(NULL)
 		, m_exit(false)
 		, m_x(0)
 		, m_y(0)
@@ -137,6 +139,7 @@ public:
 		, m_fullscreen(0)
 		, m_compile(0)
 		, m_continue(0)
+		, m_wait_console(0)
 	{
 	}
 
@@ -147,13 +150,16 @@ public:
 		check_preferred_settings();
 
 		#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
+			m_console = CE_NEW(default_allocator(), ConsoleServer)();
+			m_console->init(m_console_port, (bool) m_wait_console);
+
 			if (m_compile == 1)
 			{
 				m_bundle_compiler = CE_NEW(default_allocator(), BundleCompiler);
 				if (!m_bundle_compiler->compile(m_bundle_dir, m_source_dir))
 				{
 					CE_DELETE(default_allocator(), m_bundle_compiler);
-					Log::e("Exiting.");
+					CE_LOGE("Exiting.");
 					exit(EXIT_FAILURE);
 				}
 
@@ -176,9 +182,61 @@ public:
 	{
 		#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
 			CE_DELETE(default_allocator(), m_bundle_compiler);
+
+			m_console->shutdown();
+			CE_DELETE(default_allocator(), m_console);
 		#endif
 	}
 
+	//-----------------------------------------------------------------------------
+	void display_modes(Array<DisplayMode>& modes)
+	{
+		int num_rrsizes = 0;
+		XRRScreenSize* rrsizes = XRRConfigSizes(m_screen_config, &num_rrsizes);
+
+		for (int i = 0; i < num_rrsizes; i++)
+		{
+			DisplayMode dm;
+			dm.id = (uint32_t) i;
+			dm.width = rrsizes[i].width;
+			dm.height = rrsizes[i].height;
+			array::push_back(modes, dm);
+		}
+	}
+
+	//-----------------------------------------------------------------------------
+	void set_display_mode(uint32_t id)
+	{
+		// Check if id is valid
+		int num_rrsizes = 0;
+		XRRScreenSize* rrsizes = XRRConfigSizes(m_screen_config, &num_rrsizes);
+		(void) rrsizes;
+
+		if ((int) id >= num_rrsizes)
+			return;
+
+		XRRSetScreenConfig(m_x11_display,
+							m_screen_config,
+							RootWindow(m_x11_display, DefaultScreen(m_x11_display)),
+							(int) id,
+							RR_Rotate_0,
+							CurrentTime);
+	}
+
+	//-----------------------------------------------------------------------------
+	void set_fullscreen(bool full)
+	{
+		XEvent e;
+		e.xclient.type = ClientMessage;
+		e.xclient.window = m_x11_window;
+		e.xclient.message_type = XInternAtom(m_x11_display, "_NET_WM_STATE", False );
+		e.xclient.format = 32;
+		e.xclient.data.l[0] = full ? 1 : 0;
+		e.xclient.data.l[1] = XInternAtom(m_x11_display, "_NET_WM_STATE_FULLSCREEN", False);
+
+		XSendEvent(m_x11_display, DefaultRootWindow(m_x11_display), False, SubstructureNotifyMask, &e);
+	}
+
 	//-----------------------------------------------------------------------------
 	int32_t run(int argc, char** argv)
 	{
@@ -249,6 +307,12 @@ public:
 		oswindow_set_window(m_x11_display, m_x11_window);
 		set_x11_display_and_window(m_x11_display, m_x11_window);
 
+		// Get screen configuration
+		m_screen_config = XRRGetScreenInfo(m_x11_display, RootWindow(m_x11_display, screen));
+
+		Rotation rr_old_rot;
+		const SizeID rr_old_sizeid = XRRConfigCurrentConfiguration(m_screen_config, &rr_old_rot);
+
 		OsThread game_thread("game-thread");
 		game_thread.start(main_loop, (void*)this);
 
@@ -259,6 +323,21 @@ public:
 
 		game_thread.stop();
 
+		// Restore previous screen configuration if changed
+		Rotation rr_cur_rot;
+		const SizeID rr_cur_sizeid = XRRConfigCurrentConfiguration(m_screen_config, &rr_cur_rot);
+
+		if (rr_cur_rot != rr_old_rot || rr_cur_sizeid != rr_old_sizeid)
+		{
+			XRRSetScreenConfig(m_x11_display,
+								m_screen_config,
+								RootWindow(m_x11_display, screen),
+								rr_old_sizeid,
+								rr_old_rot,
+								CurrentTime);
+		}
+		XRRFreeScreenConfigInfo(m_screen_config);
+
 		LinuxDevice::shutdown();
 		XDestroyWindow(m_x11_display, m_x11_window);
 		XCloseDisplay(m_x11_display);
@@ -273,6 +352,10 @@ public:
 
 		while(!process_events() && is_running())
 		{
+			#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
+				m_console->update();
+			#endif
+
 			Device::frame();
 
 			m_keyboard->update();
@@ -483,21 +566,23 @@ public:
 			"  --compile                  Do a full compile of the resources.\n"
 			"  --continue                 Continue the execution after the resource compilation step.\n"
 			"  --file-server              Read resources from a remote engine instance.\n"
-			"  --console-port             Set the network port of the console server.\n";
+			"  --console-port             Set the network port of the console server.\n"
+			"  --wait-console             Wait for a console connection before starting up.\n";
 
 		static ArgsOption options[] = 
 		{
-			{ "help",             AOA_NO_ARGUMENT,       NULL,        'i' },
-			{ "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_fullscreen, 1 },
-			{ "parent-window",    AOA_REQUIRED_ARGUMENT, NULL,        'p' },
-			{ "file-server",      AOA_NO_ARGUMENT,       &m_fileserver, 1 },
-			{ "console-port",     AOA_REQUIRED_ARGUMENT, NULL,        'c' },
+			{ "help",             AOA_NO_ARGUMENT,       NULL,           'i' },
+			{ "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_fullscreen,    1 },
+			{ "parent-window",    AOA_REQUIRED_ARGUMENT, NULL,           'p' },
+			{ "file-server",      AOA_NO_ARGUMENT,       &m_fileserver,    1 },
+			{ "console-port",     AOA_REQUIRED_ARGUMENT, NULL,           'c' },
+			{ "wait-console",     AOA_NO_ARGUMENT,       &m_wait_console,  1 },
 			{ NULL, 0, NULL, 0 }
 		};
 
@@ -566,26 +651,26 @@ public:
 		{
 			if (string::strcmp(m_source_dir, "") == 0)
 			{
-				Log::e("You have to specify the source directory when running in compile mode.");
+				CE_LOGE("You have to specify the source directory when running in compile mode.");
 				exit(EXIT_FAILURE);
 			}
 
 			if (!os::is_absolute_path(m_source_dir))
 			{
-				Log::e("The source directory must be absolute.");
+				CE_LOGE("The source directory must be absolute.");
 				exit(EXIT_FAILURE);
 			}
 		}
 
 		if (!os::is_absolute_path(m_bundle_dir))
 		{
-			Log::e("The bundle directory must be absolute.");
+			CE_LOGE("The bundle directory must be absolute.");
 			exit(EXIT_FAILURE);
 		}
 
 		if (m_width == 0 || m_height == 0)
 		{
-			Log::e("Window width and height must be greater than zero.");
+			CE_LOGE("Window width and height must be greater than zero.");
 			exit(EXIT_FAILURE);
 		}
 	}
@@ -639,6 +724,8 @@ private:
 	Cursor m_x11_hidden_cursor;
 	Atom m_wm_delete_message;
 
+	XRRScreenConfiguration* m_screen_config;
+
 	bool m_exit;
 	uint32_t m_x;
 	uint32_t m_y;
@@ -650,6 +737,7 @@ private:
 	int32_t m_fullscreen;
 	int32_t m_compile;
 	int32_t m_continue;
+	int32_t m_wait_console;
 
 	OsEventQueue m_queue;
 };

+ 4 - 0
engine/os/posix/Cond.h

@@ -65,6 +65,7 @@ inline Cond::Cond()
 	int32_t result = pthread_cond_init(&m_cond, NULL);
 
 	CE_ASSERT(result == 0, "Failed to init cond. errno: %d", result);
+	CE_UNUSED(result);
 }
 
 //-----------------------------------------------------------------------------
@@ -73,6 +74,7 @@ inline Cond::~Cond()
 	int32_t result = pthread_cond_destroy(&m_cond);
 
 	CE_ASSERT(result == 0, "Failed to destroy cond. errno: %d", result);
+	CE_UNUSED(result);
 }
 
 //-----------------------------------------------------------------------------
@@ -81,6 +83,7 @@ inline void Cond::signal()
 	int32_t result = pthread_cond_signal(&m_cond);
 
 	CE_ASSERT(result == 0, "Failed to signal cond. errno: %d", result);
+	CE_UNUSED(result);
 }
 
 //-----------------------------------------------------------------------------
@@ -89,6 +92,7 @@ inline void Cond::wait(Mutex& mutex)
 	int32_t result = pthread_cond_wait(&m_cond, &(mutex.m_mutex));
 
 	CE_ASSERT(result == 0, "Failed to wait cond. errno: %d", result);
+	CE_UNUSED(result);
 }
 
 } // namespace crown

+ 4 - 0
engine/os/posix/Mutex.h

@@ -72,6 +72,7 @@ inline Mutex::Mutex()
 	CE_ASSERT(result == 0, "Failed to set mutex type. errno: %d", result);
 	result = pthread_mutex_init(&m_mutex, &m_attr);
 	CE_ASSERT(result == 0, "Failed to init mutex. errno: %d", result);
+	CE_UNUSED(result);
 }
 
 //-----------------------------------------------------------------------------
@@ -83,6 +84,7 @@ inline Mutex::~Mutex()
 	CE_ASSERT(result == 0, "Failed to destroy mutex. errno: %d", result);
 	result = pthread_mutexattr_destroy(&m_attr);
 	CE_ASSERT(result == 0, "Failed to destroy mutex attr. errno: %d", result);
+	CE_UNUSED(result);
 }
 
 //-----------------------------------------------------------------------------
@@ -90,6 +92,7 @@ inline void Mutex::lock()
 {
 	int result = pthread_mutex_lock(&m_mutex);
 	CE_ASSERT(result == 0, "Failed to acquire lock. errno: %d", result);
+	CE_UNUSED(result);
 }
 
 //-----------------------------------------------------------------------------
@@ -97,6 +100,7 @@ inline void Mutex::unlock()
 {
 	int result = pthread_mutex_unlock(&m_mutex);
 	CE_ASSERT(result == 0, "Failed to release lock. errno: %d", result);
+	CE_UNUSED(result);
 }
 
 } // namespace crown

+ 4 - 0
engine/os/posix/OsFile.cpp

@@ -83,6 +83,7 @@ size_t OsFile::size() const
 
 	fseek_result = fseek(m_file_handle, (long) pos, SEEK_SET);
 	CE_ASSERT(fseek_result == 0, "Failed to seek");
+	CE_UNUSED(fseek_result);
 
 	return size;
 }
@@ -108,6 +109,7 @@ void OsFile::seek(size_t position)
 {
 	int fseek_result = fseek(m_file_handle, (long) position, SEEK_SET);
 	CE_ASSERT(fseek_result == 0, "Failed to seek");
+	CE_UNUSED(fseek_result);
 }
 
 //-----------------------------------------------------------------------------
@@ -115,6 +117,7 @@ void OsFile::seek_to_end()
 {
 	int fseek_result = fseek(m_file_handle, 0, SEEK_END);
 	CE_ASSERT(fseek_result == 0, "Failed to seek");
+	CE_UNUSED(fseek_result);
 }
 
 //-----------------------------------------------------------------------------
@@ -122,6 +125,7 @@ void OsFile::skip(size_t bytes)
 {
 	int fseek_result = fseek(m_file_handle, bytes, SEEK_CUR);
 	CE_ASSERT(fseek_result == 0, "Failed to seek");
+	CE_UNUSED(fseek_result);
 }
 
 //-----------------------------------------------------------------------------

+ 2 - 0
engine/os/posix/OsSocket.h

@@ -298,6 +298,7 @@ public:
 
 		int bind_ret = bind(m_server.m_socket, (const sockaddr*) &address, sizeof(sockaddr_in));
 		CE_ASSERT(bind_ret != -1, "Failed to bind socket: errno: %d", errno);
+		CE_UNUSED(bind_ret);
 
 		return true;
 	}
@@ -313,6 +314,7 @@ public:
 	{
 		int listen_ret = ::listen(m_server.m_socket, max);
 		CE_ASSERT(listen_ret != -1, "Failed to listen on socket: errno: %d", errno);
+		CE_UNUSED(listen_ret);
 	}
 
 	//-----------------------------------------------------------------------------

+ 2 - 1
engine/os/posix/OsThread.h

@@ -100,7 +100,6 @@ inline void OsThread::start(ThreadFunction func, void* data, size_t stack_size)
 	int32_t result = pthread_attr_init(&attr);
 	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
 
-
 	CE_ASSERT(result == 0, "pthread_attr_init failed. errno: %d", result);
 
 	if (m_stack_size != 0)
@@ -115,6 +114,7 @@ inline void OsThread::start(ThreadFunction func, void* data, size_t stack_size)
 	// Free attr memory
 	result = pthread_attr_destroy(&attr);
 	CE_ASSERT(result == 0, "pthread_attr_destroy failed. errno: %d", result);
+	CE_UNUSED(result);
 
 	m_is_running = true;
 
@@ -128,6 +128,7 @@ inline void OsThread::stop()
 	
 	int32_t result = pthread_join(m_handle, NULL);
 	CE_ASSERT(result == 0, "OsThread join failed. errno: %d", result);
+	CE_UNUSED(result);
 
 	m_is_running = false;
 	m_handle = 0;

+ 1 - 0
engine/os/posix/Posix.cpp

@@ -303,6 +303,7 @@ void execute_process(const char* args[])
 	{
 		int res = execv(args[0], (char* const*)args);
 		CE_ASSERT(res != -1, "Unable to exec '%s'. errno %d", args[0], res);
+		CE_UNUSED(res);
 		exit(EXIT_SUCCESS);
 	}
 }

+ 53 - 18
engine/os/win/main.cpp

@@ -138,6 +138,7 @@ public:
 		, m_mouse_lock(false)
 		, m_started(false)
 		, m_exit(false)
+		, m_wait_console(0)
 	{
 
 	}
@@ -149,13 +150,16 @@ public:
 		check_preferred_settings();
 
 		#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
+			m_console = CE_NEW(default_allocator(), ConsoleServer)();
+			m_console->init(m_console_port, (bool) m_wait_console);
+
 			if (m_compile == 1)
 			{
 				m_bundle_compiler = CE_NEW(default_allocator(), BundleCompiler);
 				if (!m_bundle_compiler->compile(m_bundle_dir, m_source_dir))
 				{
 					CE_DELETE(default_allocator(), m_bundle_compiler);
-					Log::e("Exiting.");
+					CE_LOGE("Exiting.");
 					exit(EXIT_FAILURE);
 				}
 
@@ -175,16 +179,40 @@ public:
 	{
 		#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
 			CE_DELETE(default_allocator(), m_bundle_compiler);
+
+			m_console->shutdown();
+			CE_DELETE(default_allocator(), m_console);
 		#endif
 	}
 
+	//-----------------------------------------------------------------------------
+	void display_modes(Array<DisplayMode>& /*modes*/)
+	{
+		#error "Implement me"
+	}
+
+	//-----------------------------------------------------------------------------
+	void set_display_mode(uint32_t /*id*/)
+	{
+		#error "Implement me"
+	}
+
+	//-----------------------------------------------------------------------------
+	void set_fullscreen(bool full)
+	{
+		#error "Implement me"
+	}
+
 	//-----------------------------------------------------------------------------
 	int32_t	run(int argc, char** argv)
 	{
 		init(argc, argv);
 
 		WSADATA WsaData;
-		CE_ASSERT(WSAStartup(MAKEWORD(2,2), &WsaData) == 0L, "Unable to initialize socket");
+		int res = WSAStartup(MAKEWORD(2,2), &WsaData);
+		CE_ASSERT(res == 0, "Unable to initialize socket");
+		CE_UNUSED(WsaData);
+		CE_UNUSED(res);
 
 		HINSTANCE instance = (HINSTANCE)GetModuleHandle(NULL);
 
@@ -288,6 +316,10 @@ public:
 
 		while(!process_events() && is_running())
 		{
+			#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
+				m_console->update();
+			#endif
+
 			Device::frame();
 
 			m_keyboard->update();
@@ -709,20 +741,22 @@ public:
 			"  --continue                 Continue the execution after the resource compilation step.\n"
 			"  --file-server              Read resources from a remote engine instance.\n"
 			"  --console-port             Set the network port of the console server.\n";
+			"  --wait-console             Wait for a console connection before starting up.\n";
 
 		static ArgsOption options[] = 
 		{
-			{ "help",             AOA_NO_ARGUMENT,       NULL,        'i' },
-			{ "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_fullscreen, 1 },
-			{ "parent-window",    AOA_REQUIRED_ARGUMENT, NULL,        'p' },
-			{ "file-server",      AOA_NO_ARGUMENT,       &m_fileserver, 1 },
-			{ "console-port",     AOA_REQUIRED_ARGUMENT, NULL,        'c' },
+			{ "help",             AOA_NO_ARGUMENT,       NULL,           'i' },
+			{ "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_fullscreen,    1 },
+			{ "parent-window",    AOA_REQUIRED_ARGUMENT, NULL,           'p' },
+			{ "file-server",      AOA_NO_ARGUMENT,       &m_fileserver,    1 },
+			{ "console-port",     AOA_REQUIRED_ARGUMENT, NULL,           'c' },
+			{ "wait-console",     AOA_NO_ARGUMENT,       &m_wait_console,  1 },
 			{ NULL, 0, NULL, 0 }
 		};
 
@@ -791,26 +825,26 @@ public:
 		{
 			if (string::strcmp(m_source_dir, "") == 0)
 			{
-				Log::e("You have to specify the source directory when running in compile mode.");
+				CE_LOGE("You have to specify the source directory when running in compile mode.");
 				exit(EXIT_FAILURE);
 			}
 
 			if (!os::is_absolute_path(m_source_dir))
 			{
-				Log::e("The source directory must be absolute.");
+				CE_LOGE("The source directory must be absolute.");
 				exit(EXIT_FAILURE);
 			}
 		}
 
 		if (!os::is_absolute_path(m_bundle_dir))
 		{
-			Log::e("The bundle directory must be absolute.");
+			CE_LOGE("The bundle directory must be absolute.");
 			exit(EXIT_FAILURE);
 		}
 
 		// if (m_width == 0 || m_height == 0)
 		// {
-		// 	Log::e("Window width and height must be greater than zero.");
+		// 	CE_LOGE("Window width and height must be greater than zero.");
 		// 	exit(EXIT_FAILURE);
 		// }
 	}
@@ -883,7 +917,8 @@ public:
 	uint32_t m_parent_window_handle;
 	int32_t m_fullscreen;
 	int32_t m_compile;
-	int32_t m_continue;	
+	int32_t m_continue;
+	int32_t m_wait_console;
 
 	OsEventQueue m_queue;
 };

+ 16 - 8
engine/physics/Actor.cpp

@@ -40,10 +40,10 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "PhysicsWorld.h"
 #include "Quaternion.h"
 #include "StringUtils.h"
+
 #include "PxCooking.h"
 #include "PxDefaultStreams.h"
 
-
 using physx::PxActorFlag;
 using physx::PxActorType;
 using physx::PxBoxGeometry;
@@ -110,7 +110,7 @@ void Actor::create_objects()
 	const PhysicsActor2& actor_class = config->actor(actor.actor_class);
 
 	// Create rigid body
-	const PxMat44 pose((PxReal*) (m_scene_graph.world_pose(m_node).to_float_ptr()));
+	const PxMat44 pose((PxReal*) matrix4x4::to_float_ptr(m_scene_graph.world_pose(m_node)));
 
 	if (actor_class.flags & PhysicsActor2::DYNAMIC)
 	{
@@ -165,7 +165,7 @@ void Actor::create_objects()
 			}
 			case PhysicsShapeType::CONVEX_MESH:
 			{
-				MeshResource* resource = (MeshResource*) device()->resource_manager()->data(shape.resource);
+				MeshResource* resource = (MeshResource*) device()->resource_manager()->get(shape.resource);
 
 				PxConvexMeshDesc convex_mesh_desc;
 				convex_mesh_desc.points.count		= resource->num_vertices();
@@ -269,10 +269,12 @@ void Actor::teleport_world_rotation(const Quaternion& r)
 //-----------------------------------------------------------------------------
 void Actor::teleport_world_pose(const Matrix4x4& m)
 {
-	const PxVec3 x(m.x().x, m.x().y, m.x().z);
-	const PxVec3 y(m.y().x, m.y().y, m.y().z);
-	const PxVec3 z(m.z().x, m.z().y, m.z().z);
-	const PxVec3 t(m.translation().x, m.translation().y, m.translation().z);
+	using namespace matrix4x4;
+
+	const PxVec3 x(m.x.x, m.x.y, m.x.z);
+	const PxVec3 y(m.y.x, m.y.y, m.y.z);
+	const PxVec3 z(m.z.x, m.z.y, m.z.z);
+	const PxVec3 t(translation(m).x, translation(m).y, translation(m).z);
 	m_actor->setGlobalPose(PxTransform(PxMat44(x, y, z, t)));
 }
 
@@ -539,10 +541,16 @@ void Actor::wake_up()
 	static_cast<PxRigidDynamic*>(m_actor)->wakeUp();
 }
 
+//-----------------------------------------------------------------------------
+UnitId Actor::unit_id() const
+{
+	return m_unit;
+}
+
 //-----------------------------------------------------------------------------
 Unit* Actor::unit()
 {
-	return (m_unit.id == INVALID_ID) ? NULL : m_world.world().lookup_unit(m_unit);
+	return (m_unit.id == INVALID_ID) ? NULL : m_world.world().get_unit(m_unit);
 }
 
 //-----------------------------------------------------------------------------

+ 4 - 3
engine/physics/Actor.h

@@ -46,10 +46,8 @@ namespace crown
 
 struct PhysicsResource;
 struct PhysicsConfigResource;
-struct Quaternion;
-struct Matrix4x4;
 struct Unit;
-class SceneGraph;
+struct SceneGraph;
 
 /// Represents a rigid body.
 ///
@@ -165,6 +163,9 @@ struct Actor
 	/// Wakes the actor up.
 	void wake_up();
 
+	/// Returns the id of the unit that owns the actor.
+	UnitId unit_id() const;
+
 	/// Returns the unit that owns the actor.
 	Unit* unit();
 

+ 72 - 33
engine/physics/PhysicsWorld.cpp

@@ -40,6 +40,11 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "ResourceManager.h"
 #include "Raycast.h"
 #include "Unit.h"
+#include "Config.h"
+#include "World.h"
+#include "DebugLine.h"
+#include "Color4.h"
+#include "IntSetting.h"
 
 #include "PxPhysicsAPI.h"
 
@@ -68,10 +73,14 @@ using physx::PxVisualizationParameter;
 using physx::PxSphereGeometry;
 using physx::PxCapsuleGeometry;
 using physx::PxBoxGeometry;
+using physx::PxRenderBuffer;
+using physx::PxDebugLine;
 
 namespace crown
 {
 
+static IntSetting g_physics_debug("physics.debug", "Enable physics debug rendering.", 0, 0, 1);
+
 namespace physics_system
 {
 	using physx::PxFoundation;
@@ -119,13 +128,13 @@ namespace physics_system
 			{
 				case PxErrorCode::eDEBUG_INFO:
 				{
-					Log::i("PhysX: %s", message);
+					CE_LOGI("PhysX: %s", message);
 					break;
 				}
 				case PxErrorCode::eDEBUG_WARNING: 
 				case PxErrorCode::ePERF_WARNING:
 				{
-					Log::w("PhysX: %s", message);
+					CE_LOGW("PhysX: %s", message);
 					break;
 				}
 				case PxErrorCode::eINVALID_PARAMETER:
@@ -192,6 +201,7 @@ namespace physics_system
 
 		bool extension = PxInitExtensions(*s_physics);
 		CE_ASSERT(extension, "Unable to initialize PhysX Extensions");
+		CE_UNUSED(extension);
 
 		s_cooking = PxCreateCooking(PX_PHYSICS_VERSION, *s_foundation, PxCookingParams(PxTolerancesScale()));
 		CE_ASSERT(s_cooking, "Unable to create PhysX Cooking");
@@ -207,6 +217,22 @@ namespace physics_system
 		CE_DELETE(default_allocator(), s_px_error);
 		CE_DELETE(default_allocator(), s_px_allocator);
 	}
+
+	#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
+		void draw_debug_lines(PxScene* scene, DebugLine& line)
+		{
+			const PxRenderBuffer& rb = scene->getRenderBuffer();
+			for(PxU32 i = 0; i < rb.getNbLines(); i++)
+			{
+				const PxDebugLine& pxline = rb.getLines()[i];
+				line.add_line(Color4(pxline.color0), Vector3(pxline.pos0.x, pxline.pos0.y, pxline.pos0.z),
+								Vector3(pxline.pos1.x, pxline.pos1.y, pxline.pos1.z));
+			}
+
+			line.commit();
+			line.clear();
+		}
+	#endif
 } // namespace physics_system
 
 //-----------------------------------------------------------------------------
@@ -220,6 +246,10 @@ PhysicsWorld::PhysicsWorld(World& world)
 	, m_raycasts_pool(default_allocator(), CE_MAX_RAYCASTS, sizeof(Raycast), CE_ALIGNOF(Raycast))
 	, m_events(default_allocator())
 	, m_callback(m_events)
+
+	#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
+		, m_debug_line(NULL)
+	#endif
 {
 	// Create the scene
 	PxSceneLimits scene_limits;
@@ -250,7 +280,14 @@ PhysicsWorld::PhysicsWorld(World& world)
 	m_controller_manager = PxCreateControllerManager(*m_scene);
 	CE_ASSERT(m_controller_manager != NULL, "Failed to create PhysX controller manager");
 
-	m_resource = (PhysicsConfigResource*) device()->resource_manager()->lookup("physics_config", "global");
+	m_resource = (PhysicsConfigResource*) device()->resource_manager()->get("physics_config", "global");
+
+	#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
+		m_scene->setVisualizationParameter(PxVisualizationParameter::eSCALE, 1);
+		m_scene->setVisualizationParameter(PxVisualizationParameter::eACTOR_AXES, 1);
+		m_scene->setVisualizationParameter(PxVisualizationParameter::eCOLLISION_SHAPES, 1);
+		m_debug_line = world.create_debug_line(false);
+	#endif
 }
 
 //-----------------------------------------------------------------------------
@@ -259,91 +296,84 @@ PhysicsWorld::~PhysicsWorld()
 	m_cpu_dispatcher->release();
 	m_controller_manager->release();
 	m_scene->release();
+
+	#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
+		m_world.destroy_debug_line(m_debug_line);
+	#endif
 }
 
 //-----------------------------------------------------------------------------
 ActorId	PhysicsWorld::create_actor(const PhysicsResource* res, const uint32_t index, SceneGraph& sg, int32_t node, UnitId unit_id)
 {
 	Actor* actor = CE_NEW(m_actors_pool, Actor)(*this, res, index, sg, node, unit_id);
-	return m_actors.create(actor);
+	return id_array::create(m_actors, actor);
 }
 
 //-----------------------------------------------------------------------------
 void PhysicsWorld::destroy_actor(ActorId id)
 {
-	CE_ASSERT(m_actors.has(id), "Actor does not exist");
-
-	CE_DELETE(m_actors_pool, m_actors.lookup(id));
-	m_actors.destroy(id);
+	CE_DELETE(m_actors_pool, id_array::get(m_actors, id));
+	id_array::destroy(m_actors, id);
 }
 
 //-----------------------------------------------------------------------------
 ControllerId PhysicsWorld::create_controller(const PhysicsResource* pr, SceneGraph& sg, int32_t node)
 {
 	Controller* controller = CE_NEW(m_controllers_pool, Controller)(pr, sg, node, physics_system::s_physics, m_controller_manager);
-	return m_controllers.create(controller);
+	return id_array::create(m_controllers, controller);
 }
 
 //-----------------------------------------------------------------------------
 void PhysicsWorld::destroy_controller(ControllerId id)
 {
-	CE_ASSERT(m_controllers.has(id), "Controller does not exist");
-
-	CE_DELETE(m_controllers_pool, m_controllers.lookup(id));
-	m_controllers.destroy(id);
+	CE_DELETE(m_controllers_pool, id_array::get(m_controllers, id));
+	id_array::destroy(m_controllers, id);
 }
 
 //-----------------------------------------------------------------------------
 JointId	PhysicsWorld::create_joint(const PhysicsResource* pr, const uint32_t index, const Actor& actor_0, const Actor& actor_1)
 {
 	Joint* joint = CE_NEW(m_joints_pool, Joint)(physics_system::s_physics, pr, index, actor_0, actor_1);
-	return m_joints.create(joint);
+	return id_array::create(m_joints, joint);
 }
 
 //-----------------------------------------------------------------------------
 void PhysicsWorld::destroy_joint(JointId id)
 {
-	CE_ASSERT(m_joints.has(id), "Joint does not exist");
-
-	CE_DELETE(m_joints_pool, m_joints.lookup(id));
-	m_joints.destroy(id);
+	CE_DELETE(m_joints_pool, id_array::get(m_joints, id));
+	id_array::destroy(m_joints, id);
 }
 
 //-----------------------------------------------------------------------------
 RaycastId PhysicsWorld::create_raycast(CollisionMode::Enum mode, CollisionType::Enum filter)
 {
 	Raycast* raycast = CE_NEW(m_raycasts_pool, Raycast)(m_scene, mode, filter);
-	return m_raycasts.create(raycast);
+	return id_array::create(m_raycasts, raycast);
 }
 
 //-----------------------------------------------------------------------------
 void PhysicsWorld::destroy_raycast(RaycastId id)
 {
-	CE_ASSERT(m_raycasts.has(id), "Raycast does not exists");
-
-	CE_DELETE(m_raycasts_pool, m_raycasts.lookup(id));
-	m_raycasts.destroy(id);
+	CE_DELETE(m_raycasts_pool, id_array::get(m_raycasts, id));
+	id_array::destroy(m_raycasts, id);
 }
 
 //-----------------------------------------------------------------------------
-Actor* PhysicsWorld::lookup_actor(ActorId id)
+Actor* PhysicsWorld::get_actor(ActorId id)
 {
-	CE_ASSERT(m_actors.has(id), "Actor does not exist");
-	return m_actors.lookup(id);
+	return id_array::get(m_actors, id);
 }
 
 //-----------------------------------------------------------------------------
-Controller* PhysicsWorld::lookup_controller(ControllerId id)
+Controller* PhysicsWorld::get_controller(ControllerId id)
 {
-	CE_ASSERT(m_controllers.has(id), "Controller does not exist");
-	return m_controllers.lookup(id);
+	return id_array::get(m_controllers, id);
 }
 
 //-----------------------------------------------------------------------------
-Raycast* PhysicsWorld::lookup_raycast(RaycastId id)
+Raycast* PhysicsWorld::get_raycast(RaycastId id)
 {
-	CE_ASSERT(m_raycasts.has(id), "Raycast does not exists");
-	return m_raycasts.lookup(id);
+	return id_array::get(m_raycasts, id);
 }
 
 //-----------------------------------------------------------------------------
@@ -422,12 +452,21 @@ void PhysicsWorld::update(float dt)
 	}
 
 	// Update controllers
-	for (uint32_t i = 0; i < m_controllers.size(); i++)
+	for (uint32_t i = 0; i < id_array::size(m_controllers); i++)
 	{
 		m_controllers[i]->update();
 	}
 }
 
+//-----------------------------------------------------------------------------
+void PhysicsWorld::draw_debug()
+{
+	#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
+		if (g_physics_debug)
+			physics_system::draw_debug_lines(m_scene, *m_debug_line);
+	#endif
+}
+
 PxPhysics* PhysicsWorld::physx_physics() { return physics_system::s_physics; }
 PxCooking* PhysicsWorld::physx_cooking() { return physics_system::s_cooking; }
 PxScene* PhysicsWorld::physx_scene() { return m_scene; }

+ 22 - 13
engine/physics/PhysicsWorld.h

@@ -76,6 +76,7 @@ class World;
 struct PhysicsResource;
 struct PhysicsConfigResource;
 struct Unit;
+struct DebugLine;
 
 /// Manages physics objects in a World.
 ///
@@ -106,11 +107,15 @@ public:
 	void overlap_test(CollisionType::Enum filter, ShapeType::Enum type,
 						const Vector3& pos, const Quaternion& rot, const Vector3& size, Array<Actor*>& actors);
 
+	/// Updates the physics simulation.
 	void update(float dt);
 
-	Actor* lookup_actor(ActorId id);
-	Controller* lookup_controller(ControllerId id);
-	Raycast* lookup_raycast(RaycastId id);
+	/// Draws debug lines.
+	void draw_debug();
+
+	Actor* get_actor(ActorId id);
+	Controller* get_controller(ControllerId id);
+	Raycast* get_raycast(RaycastId id);
 
 	World& world() { return m_world; }
 	EventStream& events() { return m_events; }
@@ -124,18 +129,18 @@ public:
 
 private:
 
-	World&						m_world;
-	PxControllerManager*		m_controller_manager;
-	PxScene*					m_scene;
-	PxDefaultCpuDispatcher*		m_cpu_dispatcher;
+	World& m_world;
+	PxControllerManager* m_controller_manager;
+	PxScene* m_scene;
+	PxDefaultCpuDispatcher* m_cpu_dispatcher;
 
-	PxOverlapHit 				m_hits[64]; // hardcoded
-	PxOverlapBuffer 			m_buffer;
+	PxOverlapHit m_hits[64]; // hardcoded
+	PxOverlapBuffer m_buffer;
 
-	PoolAllocator				m_actors_pool;
-	PoolAllocator				m_controllers_pool;
-	PoolAllocator				m_joints_pool;
-	PoolAllocator				m_raycasts_pool;
+	PoolAllocator m_actors_pool;
+	PoolAllocator m_controllers_pool;
+	PoolAllocator m_joints_pool;
+	PoolAllocator m_raycasts_pool;
 
 	IdArray<CE_MAX_ACTORS, Actor*>	m_actors;
 	IdArray<CE_MAX_CONTROLLERS, Controller*> m_controllers;
@@ -147,6 +152,10 @@ private:
 	PhysicsSimulationCallback m_callback;
 
 	const PhysicsConfigResource* m_resource;
+
+	#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
+		DebugLine* m_debug_line;
+	#endif
 };
 
 } // namespace crown

+ 7 - 7
engine/renderers/DebugLine.cpp

@@ -30,12 +30,11 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "Vector3.h"
 #include "Device.h"
 #include "Renderer.h"
+#include "RenderWorld.h"
 
 namespace crown
 {
 
-typedef Id GPUProgramId;
-
 //-----------------------------------------------------------------------------
 DebugLine::DebugLine(bool depth_test)
 	: m_depth_test(depth_test)
@@ -47,9 +46,7 @@ DebugLine::DebugLine(bool depth_test)
 void DebugLine::add_line(const Color4& color, const Vector3& start, const Vector3& end)
 {
 	if (m_num_lines >= CE_MAX_DEBUG_LINES)
-	{
 		 return;
-	}
 
 	m_lines[m_num_lines].position_0[0] = start.x;
 	m_lines[m_num_lines].position_0[1] = start.y;
@@ -105,6 +102,9 @@ void DebugLine::clear()
 //-----------------------------------------------------------------------------
 void DebugLine::commit()
 {
+	if (!m_num_lines)
+		return;
+
 	Renderer* r = device()->renderer();
 
 	TransientVertexBuffer tvb;
@@ -120,11 +120,11 @@ void DebugLine::commit()
 		indices[i] = i;
 	}
 
-	r->set_state((m_depth_test ? 0 : STATE_DEPTH_TEST_ALWAYS) | STATE_COLOR_WRITE | STATE_CULL_CW | STATE_PRIMITIVE_LINES);
+	r->set_state((m_depth_test ? STATE_DEPTH_TEST_LESS : 0) | STATE_COLOR_WRITE | STATE_CULL_CW | STATE_PRIMITIVE_LINES);
 	r->set_vertex_buffer(tvb);
 	r->set_index_buffer(tib);
-	//r->set_program(default_program);
-	r->set_pose(Matrix4x4::IDENTITY);
+	r->set_program(render_world_globals::default_program());
+	r->set_pose(matrix4x4::IDENTITY);
 	r->commit(0);
 }
 

+ 2 - 7
engine/renderers/DebugLine.h

@@ -28,14 +28,12 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 #include "Types.h"
 #include "Config.h"
+#include "MathTypes.h"
+#include "Color4.h"
 
 namespace crown
 {
 
-struct Color4;
-struct Matrix4x4;
-struct Vector3;
-
 struct DebugLine
 {
 	/// Whether to enable @a depth_test
@@ -47,9 +45,6 @@ struct DebugLine
 	/// Adds a sphere at @a center with the given @a radius and @a color.
 	void add_sphere(const Color4& color, const Vector3& center, const float radius);
 
-	/// Adds a @a pose with the given @a color
-	//void add_pose(const Color4& color, const Matrix4x4& pose);
-
 	/// Clears all the lines.
 	void clear();
 

+ 376 - 0
engine/renderers/Gui.cpp

@@ -0,0 +1,376 @@
+/*
+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 "Gui.h"
+#include "Assert.h"
+#include "Renderer.h"
+#include "Vector3.h"
+#include "Vector2.h"
+#include "GuiResource.h"
+#include "RenderWorld.h"
+#include "RendererTypes.h"
+#include "Vector3.h"
+#include "Vector2.h"
+#include "Color4.h"
+#include "FontResource.h"
+#include "Device.h"
+#include "OsWindow.h"
+#include "ResourceManager.h"
+#include "TextureResource.h"
+#include "MaterialResource.h"
+
+namespace crown
+{
+
+using namespace matrix4x4;
+
+//-------------------------------------------------------------------------
+struct VertexData
+{
+	float x;
+	float y;
+	float u;
+	float v;
+};
+
+//-------------------------------------------------------------------------
+struct IndexData
+{
+	uint16_t a;
+	uint16_t b;
+};
+
+#define UTF8_ACCEPT 0
+
+//-------------------------------------------------------------------------
+static const uint8_t s_utf8d[364] =
+{
+	// The first part of the table maps bytes to character classes that
+	// to reduce the size of the transition table and create bitmasks.
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,  9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
+	7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+	8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+	10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
+
+	// The second part is a transition table that maps a combination
+	// of a state of the automaton and a character class to a state.
+	 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
+	12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
+	12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
+	12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
+	12,36,12,12,12,12,12,12,12,12,12,12
+};
+
+//-------------------------------------------------------------------------
+static uint32_t utf8_decode(uint32_t* state, uint32_t* code_point, uint8_t character)
+{
+	uint32_t byte = character;
+	uint32_t type = s_utf8d[byte];
+
+	*code_point = (*state != UTF8_ACCEPT) ? (byte & 0x3fu) | (*code_point << 6) : (0xff >> type) & (byte);
+	*state = s_utf8d[256 + *state + type];
+
+	return *state;
+}
+
+//-----------------------------------------------------------------------------
+Gui::Gui(RenderWorld& render_world, uint16_t width, uint16_t height)
+	: m_render_world(render_world)
+	, m_width(width)
+	, m_height(height)
+	, m_pose(matrix4x4::IDENTITY)
+{
+	set_orthographic_rh(m_projection, 0, width, 0, height, -0.01f, 100.0f);
+}
+
+//-----------------------------------------------------------------------------
+const GuiId Gui::id() const
+{
+	return m_id;
+}
+
+//-----------------------------------------------------------------------------
+void Gui::set_id(const GuiId id)
+{
+	m_id = id;
+}
+
+//-----------------------------------------------------------------------------
+Vector2 Gui::resolution() const
+{
+	return Vector2(m_width, m_height);
+}
+
+//-----------------------------------------------------------------------------
+void Gui::move(const Vector2& pos)
+{
+	set_identity(m_pose);
+	set_translation(m_pose, Vector3(pos.x, pos.y, 0));
+}
+
+//-----------------------------------------------------------------------------
+Vector2 Gui::screen_to_gui(const Vector2& pos)
+{
+	return Vector2(pos.x, m_height - pos.y);
+}
+
+//-----------------------------------------------------------------------------
+void Gui::draw_rectangle(const Vector3& pos, const Vector2& size, const Color4& color)
+{
+	Renderer* r = device()->renderer();
+	TransientVertexBuffer tvb;
+	TransientIndexBuffer tib;
+
+	r->reserve_transient_vertex_buffer(&tvb, 4, VertexFormat::P2);
+	r->reserve_transient_index_buffer(&tib, 6);
+
+	float* verts = (float*) tvb.data;
+	verts[0] = pos.x;
+	verts[1] = pos.y;
+
+	verts[2] = pos.x + size.x;
+	verts[3] = pos.y;
+
+	verts[4] = pos.x + size.x;
+	verts[5] = pos.y + size.y;
+
+	verts[6] = pos.x;
+	verts[7] = pos.y + size.y;
+
+	uint16_t* inds = (uint16_t*) tib.data;
+	inds[0] = 0;
+	inds[1] = 1;
+	inds[2] = 2;
+	inds[3] = 0;
+	inds[4] = 2;
+	inds[5] = 3;
+
+	r->set_layer_view(1, matrix4x4::IDENTITY);
+	r->set_layer_projection(1, m_projection);
+	r->set_layer_viewport(1, 0, 0, m_width, m_height);
+	r->set_state(STATE_COLOR_WRITE
+					| STATE_CULL_CW
+					| STATE_BLEND_EQUATION_ADD 
+					| STATE_BLEND_FUNC(STATE_BLEND_FUNC_SRC_ALPHA, STATE_BLEND_FUNC_ONE_MINUS_SRC_ALPHA));
+	r->set_pose(m_pose);
+	r->set_program(render_world_globals::default_color_program());
+	r->set_uniform(render_world_globals::default_color_uniform(), UniformType::FLOAT_4, color4::to_float_ptr(color), 1);
+	r->set_vertex_buffer(tvb);
+	r->set_index_buffer(tib);
+	r->commit(1, (int32_t) pos.z);
+}
+
+//-----------------------------------------------------------------------------
+void Gui::draw_image(const char* material, const Vector3& pos, const Vector2& size, const Color4& color)
+{
+	Renderer* r = device()->renderer();
+	TransientVertexBuffer tvb;
+	TransientIndexBuffer tib;
+
+	r->reserve_transient_vertex_buffer(&tvb, 4, VertexFormat::P2_T2);
+	r->reserve_transient_index_buffer(&tib, 6);
+
+	float* verts = (float*) tvb.data;
+	verts[0] = pos.x;
+	verts[1] = pos.y;
+	verts[2] = 0;
+	verts[3] = 0;
+
+	verts[4] = pos.x + size.x;
+	verts[5] = pos.y;
+	verts[6] = 1;
+	verts[7] = 0;
+
+	verts[8] = pos.x + size.x;
+	verts[9] = pos.y + size.y;
+	verts[10] = 1;
+	verts[11] = 1;
+
+	verts[12] = pos.x;
+	verts[13] = pos.y + size.y;
+	verts[14] = 0;
+	verts[15] = 1;
+
+	uint16_t* inds = (uint16_t*) tib.data;
+	inds[0] = 0;
+	inds[1] = 1;
+	inds[2] = 2;
+	inds[3] = 0;
+	inds[4] = 2;
+	inds[5] = 3;
+
+	const MaterialResource* mr = (MaterialResource*) device()->resource_manager()->get("material", material);
+	const TextureResource* tr = (TextureResource*) device()->resource_manager()->get(mr->get_texture_layer(0));
+
+	r->set_layer_view(1, matrix4x4::IDENTITY);
+	r->set_layer_projection(1, m_projection);
+	r->set_layer_viewport(1, 0, 0, m_width, m_height);
+	r->set_state(STATE_COLOR_WRITE
+					| STATE_CULL_CW
+					| STATE_BLEND_EQUATION_ADD 
+					| STATE_BLEND_FUNC(STATE_BLEND_FUNC_SRC_ALPHA, STATE_BLEND_FUNC_ONE_MINUS_SRC_ALPHA));
+	r->set_pose(m_pose);
+	r->set_program(render_world_globals::default_texture_program());
+	r->set_texture(0, render_world_globals::default_albedo_uniform(), tr->texture(),
+					TEXTURE_FILTER_LINEAR | TEXTURE_WRAP_U_CLAMP_REPEAT | TEXTURE_WRAP_V_CLAMP_REPEAT);
+	r->set_uniform(render_world_globals::default_color_uniform(), UniformType::FLOAT_4, color4::to_float_ptr(color), 1);
+	r->set_vertex_buffer(tvb);
+	r->set_index_buffer(tib);
+	r->commit(1, (int32_t) pos.z);
+}
+
+//-----------------------------------------------------------------------------
+void Gui::draw_text(const char* str, const char* font, uint32_t font_size, const Vector3& pos, const Color4& color)
+{
+	Renderer* r = device()->renderer();
+
+	const FontResource* resource = (FontResource*) device()->resource_manager()->get("font", font);
+	Vector2 m_pen;
+
+	const float scale = ((float)font_size / (float)resource->font_size());
+	const uint32_t str_len = string::strlen(str);
+
+	TransientVertexBuffer vb;
+	TransientIndexBuffer ib;
+
+	r->reserve_transient_vertex_buffer(&vb, 4 * str_len, VertexFormat::P2_T2);
+	r->reserve_transient_index_buffer(&ib, 6 * str_len);
+
+	uint16_t index = 0;
+	float x_pen_advance = 0.0f;
+	float y_pen_advance = 0.0f;
+
+	uint32_t state = 0;
+	uint32_t code_point = 0;
+	for (uint32_t i = 0; i < str_len; i++)
+	{
+		switch (str[i])
+		{
+			case '\n':
+			{
+				x_pen_advance = 0.0f;
+				y_pen_advance -= resource->font_size();
+				continue;
+			}
+			case '\t':
+			{
+				x_pen_advance += font_size * 4;
+				continue;
+			}
+		}
+		
+		if (utf8_decode(&state, &code_point, str[i]) == UTF8_ACCEPT)
+		{
+			FontGlyphData g = resource->get_glyph(code_point);
+
+			const float baseline = g.height - g.y_offset;
+
+			// Set pen position
+			m_pen.x = pos.x + g.x_offset;
+			m_pen.y = pos.y - baseline;
+
+			// Position coords
+			const float x0 = (m_pen.x + x_pen_advance) * scale;
+			const float y0 = (m_pen.y + y_pen_advance) * scale;
+			const float x1 = (m_pen.x + g.width + x_pen_advance) * scale;
+			const float y1 = (m_pen.y + g.height + y_pen_advance) * scale;
+
+			// Texture coords
+			const float u0 = (float) g.x / 512;
+			const float v0 = (float) g.y / 512;
+			const float u1 = u0 + ((float) g.width) / 512;
+			const float v1 = v0 - ((float) g.height) / 512;
+
+			// Fill vertex buffer
+			(*(VertexData*)(vb.data)).x		= x0;
+			(*(VertexData*)(vb.data)).y		= y0;
+			(*(VertexData*)(vb.data)).u		= u0;
+			(*(VertexData*)(vb.data)).v		= v1;
+			vb.data += sizeof(VertexData);
+
+			(*(VertexData*)(vb.data)).x		= x1;
+			(*(VertexData*)(vb.data)).y		= y0;
+			(*(VertexData*)(vb.data)).u		= u1;
+			(*(VertexData*)(vb.data)).v		= v1;
+			vb.data += sizeof(VertexData);
+
+			(*(VertexData*)(vb.data)).x		= x1;
+			(*(VertexData*)(vb.data)).y		= y1;
+			(*(VertexData*)(vb.data)).u		= u1;
+			(*(VertexData*)(vb.data)).v		= v0;
+			vb.data += sizeof(VertexData);
+
+			(*(VertexData*)(vb.data)).x		= x0;
+			(*(VertexData*)(vb.data)).y		= y1;
+			(*(VertexData*)(vb.data)).u		= u0;
+			(*(VertexData*)(vb.data)).v		= v0;
+			vb.data += sizeof(VertexData);
+
+			// Fill index buffer
+			(*(IndexData*)(ib.data)).a		= index;
+			(*(IndexData*)(ib.data)).b		= index + 1;
+			ib.data += sizeof(IndexData);
+
+			(*(IndexData*)(ib.data)).a		= index + 2;
+			(*(IndexData*)(ib.data)).b		= index;
+			ib.data += sizeof(IndexData);
+
+			(*(IndexData*)(ib.data)).a		= index + 2;
+			(*(IndexData*)(ib.data)).b		= index + 3;
+			ib.data += sizeof(IndexData);
+
+			// Advance pen position
+			x_pen_advance += g.x_advance;
+
+			index += 4;
+		}
+	}
+
+	const MaterialResource* mr = (MaterialResource*) device()->resource_manager()->get(resource->material());
+	const TextureResource* tr = (TextureResource*) device()->resource_manager()->get(mr->get_texture_layer(0));
+
+	r->set_layer_view(1, matrix4x4::IDENTITY);
+	r->set_layer_projection(1, m_projection);
+	r->set_layer_viewport(1, 0, 0, 1000, 625);
+	r->set_state(STATE_COLOR_WRITE
+					| STATE_CULL_CW
+					| STATE_BLEND_EQUATION_ADD 
+					| STATE_BLEND_FUNC(STATE_BLEND_FUNC_SRC_ALPHA, STATE_BLEND_FUNC_ONE_MINUS_SRC_ALPHA));
+	r->set_pose(m_pose);
+	r->set_program(render_world_globals::default_font_program());
+	r->set_texture(0, render_world_globals::default_font_uniform(), tr->texture(),
+					TEXTURE_FILTER_LINEAR | TEXTURE_WRAP_U_CLAMP_REPEAT | TEXTURE_WRAP_V_CLAMP_REPEAT);
+	r->set_uniform(render_world_globals::default_color_uniform(), UniformType::FLOAT_4, color4::to_float_ptr(color), 1);
+	r->set_vertex_buffer(vb);
+	r->set_index_buffer(ib);
+	r->commit(1, (int32_t) pos.z);
+}
+
+} // namespace crown

+ 77 - 0
engine/renderers/Gui.h

@@ -0,0 +1,77 @@
+/*
+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 "MathTypes.h"
+#include "Color4.h"
+#include "RenderWorldTypes.h"
+
+namespace crown
+{
+
+class RenderWorld;
+
+/// Manages the rendering of GUI objects.
+///
+/// @ingroup Graphics
+struct Gui
+{
+	Gui(RenderWorld& render_world, uint16_t width, uint16_t height);
+
+	const GuiId id() const;
+	void set_id(const GuiId id);
+
+	Vector2 resolution() const;
+	void move(const Vector2& pos);
+
+	Vector2 screen_to_gui(const Vector2& pos);
+
+	/// Draws a rectangle of size @a size at @a pos.
+	/// @note Higher values of pos.z make the object appear in front of other objects.
+	void draw_rectangle(const Vector3& pos, const Vector2& size, const Color4& color = Color4::WHITE);
+
+	/// Draws an image with the given @a material.
+	/// @note Higher values of pos.z make the object appear in front of other objects.
+	void draw_image(const char* material, const Vector3& pos, const Vector2& size, const Color4& color = Color4::WHITE);
+
+	/// Draws the text @a str with the given @a font and @a font_size.
+	/// @note Higher values of pos.z make the object appear in front of other objects.
+	void draw_text(const char* str, const char* font, uint32_t font_size, const Vector3& pos, const Color4& color = Color4::WHITE);
+
+public:
+
+	RenderWorld& m_render_world;
+	GuiId m_id;
+
+	uint16_t m_width;
+	uint16_t m_height;
+
+	Matrix4x4 m_projection;
+	Matrix4x4 m_pose;
+};
+
+} // namespace crown

+ 1 - 1
engine/renderers/Material.cpp

@@ -55,7 +55,7 @@ const MaterialResource* Material::resource()
 void Material::bind(Renderer& r, UniformId uniform)
 {
 	const ResourceId tr_id = m_resource->get_texture_layer(0);
-	const TextureResource* tr = (TextureResource*) device()->resource_manager()->data(tr_id);
+	const TextureResource* tr = (TextureResource*) device()->resource_manager()->get(tr_id);
 
 	r.set_texture(0, uniform, tr->texture(), TEXTURE_FILTER_LINEAR | TEXTURE_WRAP_U_CLAMP_REPEAT | TEXTURE_WRAP_V_CLAMP_REPEAT);
 }

+ 212 - 105
engine/renderers/RenderWorld.cpp

@@ -42,43 +42,185 @@ OTHER DEALINGS IN THE SOFTWARE.
 namespace crown
 {
 
-static const char* default_vertex =
-	"precision mediump float;"
-	"uniform mat4      	u_model;"
-	"uniform mat4      	u_model_view_projection;"
-
-	"attribute vec4    	a_position;"
-	"attribute vec2    	a_tex_coord0;"
-	"attribute vec4    	a_color;"
-
-	"varying vec2		tex_coord0;"
-	"varying vec4		color;"
-
-	"void main(void)"
-	"{"
-	"	tex_coord0 = a_tex_coord0;"
-	"   color = a_color;"
-	"	gl_Position = u_model_view_projection * a_position;"
-	"}";
-
-static const char* default_fragment = 
-	"precision mediump float;"
-	"void main(void)"
-	"{"
-	"	gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);"
-	"}";
-
-static const char* texture_fragment = 
-	"precision mediump float;"
-	"varying vec2       tex_coord0;"
-	"varying vec4       color;"
-
-	"uniform sampler2D  u_albedo_0;"
-
-	"void main(void)"
-	"{"
-	"	gl_FragColor = texture2D(u_albedo_0, tex_coord0);"
-	"}";
+namespace render_world_globals
+{
+	static const char* default_vertex =
+		"precision mediump float;\n"
+		"uniform mat4      	u_model_view_projection;\n"
+
+		"attribute vec4    	a_position;\n"
+		"attribute vec2    	a_tex_coord0;\n"
+		"attribute vec4		a_color;\n"
+
+		"varying vec2		tex_coord0;\n"
+		"varying vec4		color;\n"
+
+		"void main(void)\n"
+		"{\n"
+		"	tex_coord0 = a_tex_coord0;\n"
+		"	color = a_color;\n"
+		"	gl_Position = u_model_view_projection * a_position;\n"
+		"}\n";
+
+	static const char* default_fragment = 
+		"precision mediump float;\n"
+		"varying vec4 color;\n"
+		"void main(void)\n"
+		"{\n"
+		"	gl_FragColor = color;\n"
+		"}\n";
+
+	static const char* texture_fragment = 
+		"precision mediump float;\n"
+		"varying vec2       tex_coord0;\n"
+		"varying vec4       color;\n"
+
+		"uniform sampler2D  u_albedo_0;\n"
+
+		"void main(void)\n"
+		"{\n"
+		"	gl_FragColor = texture2D(u_albedo_0, tex_coord0);\n"
+		"}\n";
+
+	static const char* sdf_vertex =
+		"precision mediump float;\n"
+		"uniform mat4      	u_model_view_projection;\n"
+
+		"attribute vec4		a_position;\n"
+		"attribute vec2		a_tex_coord0;\n"
+
+		"varying vec2		v_tex_coord;\n"
+		"varying vec4		v_color;\n"
+
+		"void main(void)\n"
+		"{\n"
+		"	gl_Position = u_model_view_projection * a_position;\n"
+		"	v_tex_coord = a_tex_coord0;\n"
+		"	v_color = vec4(1, 1, 1, 1);\n"
+		"}\n";
+
+	static const char* sdf_fragment =
+		"precision mediump float;\n"
+		"uniform sampler2D u_texture;\n"
+		"uniform vec4 u_color;\n"
+
+		"varying vec2 v_tex_coord;\n"
+
+		"const float smoothing = 1.0/16.0;\n"
+
+		"void main() {\n"
+			"float distance = texture2D(u_texture, v_tex_coord).a;\n"
+			"float alpha = smoothstep(0.5 - smoothing, 0.5 + smoothing, distance);\n"
+			"gl_FragColor = vec4(u_color.rgb, alpha);\n"
+		"}\n";
+
+	static const char* default_color_fragment =
+		"precision mediump float;\n"
+		"uniform vec4 u_color;\n"
+		"void main(void)\n"
+		"{\n"
+		"	gl_FragColor = u_color;\n"
+		"}\n";
+
+	ShaderId default_vs;
+	ShaderId default_fs;
+	ShaderId texture_fs;
+	ShaderId font_vs;
+	ShaderId font_fs;
+	ShaderId color_fs;
+	GPUProgramId texture_program;
+	GPUProgramId def_program;
+	GPUProgramId font_program;
+	GPUProgramId color_program;
+	UniformId u_albedo_0;
+	UniformId u_font;
+	UniformId u_color;
+	uint32_t num_refs = 0;
+
+	void init()
+	{
+		if (num_refs)
+			return;
+
+		num_refs++;
+
+		Renderer* r = device()->renderer();
+
+		u_font = r->create_uniform("u_font", UniformType::INTEGER_1, 1);
+		u_albedo_0 = r->create_uniform("u_albedo_0", UniformType::INTEGER_1, 1);
+		u_color = r->create_uniform("u_color", UniformType::FLOAT_4, 1);
+
+		default_vs = r->create_shader(ShaderType::VERTEX, default_vertex);
+		default_fs = r->create_shader(ShaderType::FRAGMENT, default_fragment);
+		texture_fs = r->create_shader(ShaderType::FRAGMENT, texture_fragment);
+		font_vs = r->create_shader(ShaderType::VERTEX, sdf_vertex);
+		font_fs = r->create_shader(ShaderType::FRAGMENT, sdf_fragment);
+		color_fs = r->create_shader(ShaderType::FRAGMENT, default_color_fragment);
+
+		def_program = r->create_gpu_program(default_vs, default_fs);
+		texture_program = r->create_gpu_program(default_vs, texture_fs);
+		font_program = r->create_gpu_program(font_vs, font_fs);
+		color_program = r->create_gpu_program(default_vs, color_fs);
+	}
+
+	void shutdown()
+	{
+		num_refs--;
+
+		if (num_refs)
+			return;
+
+		Renderer* r = device()->renderer();
+		r->destroy_uniform(u_albedo_0);
+		r->destroy_uniform(u_font);
+		r->destroy_uniform(u_color);
+		r->destroy_gpu_program(texture_program);
+		r->destroy_gpu_program(def_program);
+		r->destroy_gpu_program(font_program);
+		r->destroy_gpu_program(color_program);
+		r->destroy_shader(default_vs);
+		r->destroy_shader(default_fs);
+		r->destroy_shader(texture_fs);
+		r->destroy_shader(font_vs);
+		r->destroy_shader(font_fs);
+		r->destroy_shader(color_fs);
+	}
+
+	GPUProgramId default_program()
+	{
+		return def_program;
+	}
+
+	GPUProgramId default_texture_program()
+	{
+		return texture_program;
+	}
+
+	GPUProgramId default_font_program()
+	{
+		return font_program;
+	}
+
+	GPUProgramId default_color_program()
+	{
+		return color_program;
+	}
+
+	UniformId default_albedo_uniform()
+	{
+		return u_albedo_0;
+	}
+
+	UniformId default_font_uniform()
+	{
+		return u_font;
+	}
+
+	UniformId default_color_uniform()
+	{
+		return u_color;
+	}
+};
 
 //-----------------------------------------------------------------------------
 RenderWorld::RenderWorld()
@@ -87,107 +229,81 @@ RenderWorld::RenderWorld()
 	, m_material_pool(default_allocator(), MAX_MATERIALS, sizeof(Material), CE_ALIGNOF(Material))
 	, m_gui_pool(default_allocator(), MAX_GUIS, sizeof(Gui), CE_ALIGNOF(Gui))
 {
-	Renderer* r = device()->renderer();
-
-	m_default_vs = r->create_shader(ShaderType::VERTEX, default_vertex);
-	m_default_fs = r->create_shader(ShaderType::FRAGMENT, default_fragment);
-	m_texture_fs = r->create_shader(ShaderType::FRAGMENT, texture_fragment);
-
-	m_u_albedo_0 = r->create_uniform("u_albedo_0", UniformType::INTEGER_1, 1);
-
-	m_default_program = r->create_gpu_program(m_default_vs, m_default_fs);
-	m_texture_program = r->create_gpu_program(m_default_vs, m_texture_fs);
+	render_world_globals::init();
 }
 
 //-----------------------------------------------------------------------------
 RenderWorld::~RenderWorld()
 {
-	Renderer* r = device()->renderer();
-
-	r->destroy_gpu_program(m_texture_program);
-	r->destroy_gpu_program(m_default_program);
-	r->destroy_uniform(m_u_albedo_0);
-	r->destroy_shader(m_default_vs);
-	r->destroy_shader(m_default_fs);
-	r->destroy_shader(m_texture_fs);
+	render_world_globals::shutdown();
 }
 
 //-----------------------------------------------------------------------------
 MeshId RenderWorld::create_mesh(MeshResource* mr, SceneGraph& sg, int32_t node)
 {
 	Mesh* mesh = CE_NEW(m_mesh_pool, Mesh)(sg, node, mr);
-	return m_mesh.create(mesh);
+	return id_array::create(m_mesh, mesh);
 }
 
 //-----------------------------------------------------------------------------
 void RenderWorld::destroy_mesh(MeshId id)
 {
-	CE_ASSERT(m_mesh.has(id), "Mesh does not exist");
-
-	Mesh* mesh = m_mesh.lookup(id);
+	Mesh* mesh = id_array::get(m_mesh, id);
 	CE_DELETE(m_mesh_pool, mesh);
-	m_mesh.destroy(id);
+	id_array::destroy(m_mesh, id);
 }
 
 //-----------------------------------------------------------------------------
-Mesh* RenderWorld::lookup_mesh(MeshId mesh)
+Mesh* RenderWorld::get_mesh(MeshId mesh)
 {
-	CE_ASSERT(m_mesh.has(mesh), "Mesh does not exits");
-
-	return m_mesh.lookup(mesh);
+	return id_array::get(m_mesh, mesh);
 }
 
 //-----------------------------------------------------------------------------
 SpriteId RenderWorld::create_sprite(SpriteResource* sr, SceneGraph& sg, int32_t node)
 {
 	Sprite* sprite = CE_NEW(m_sprite_pool, Sprite)(*this, sg, node, sr);
-	return m_sprite.create(sprite);
+	return id_array::create(m_sprite, sprite);
 }
 
 //-----------------------------------------------------------------------------
 void RenderWorld::destroy_sprite(SpriteId id)
 {
-	CE_ASSERT(m_sprite.has(id), "Sprite does not exist");
-
-	Sprite* sprite = m_sprite.lookup(id);
-	CE_DELETE(m_sprite_pool, sprite);
-	m_sprite.destroy(id);
+	CE_DELETE(m_sprite_pool, id_array::get(m_sprite, id));
+	id_array::destroy(m_sprite, id);
 }
 
 //-----------------------------------------------------------------------------
-Sprite*	RenderWorld::lookup_sprite(SpriteId id)
+Sprite*	RenderWorld::get_sprite(SpriteId id)
 {
-	CE_ASSERT(m_sprite.has(id), "Sprite does not exist");
-
-	return m_sprite.lookup(id);
+	return id_array::get(m_sprite, id);
 }
 
 //-----------------------------------------------------------------------------
 MaterialId RenderWorld::create_material(MaterialResource* mr)
 {
 	Material* mat = CE_NEW(m_material_pool, Material)(mr);
-	return m_materials.create(mat);
+	return id_array::create(m_materials, mat);
 }
 
 //-----------------------------------------------------------------------------
 void RenderWorld::destroy_material(MaterialId id)
 {
-	CE_DELETE(m_material_pool, m_materials.lookup(id));
-	m_materials.destroy(id);
+	CE_DELETE(m_material_pool, id_array::get(m_materials, id));
+	id_array::destroy(m_materials, id);
 }
 
 //-----------------------------------------------------------------------------
-Material* RenderWorld::lookup_material(MaterialId id)
+Material* RenderWorld::get_material(MaterialId id)
 {
-	return m_materials.lookup(id);
+	return id_array::get(m_materials, id);
 }
 
 //-----------------------------------------------------------------------------
-GuiId RenderWorld::create_gui(GuiResource* gr)
+GuiId RenderWorld::create_gui(uint16_t width, uint16_t height)
 {
-	Renderer* r = device()->renderer();
-	Gui* gui = CE_NEW(m_gui_pool, Gui)(*this, gr, *r);
-	GuiId id = m_guis.create(gui);
+	Gui* gui = CE_NEW(m_gui_pool, Gui)(*this, width, height);
+	GuiId id = id_array::create(m_guis, gui);
 	gui->set_id(id);
 	return id;
 }
@@ -195,18 +311,14 @@ GuiId RenderWorld::create_gui(GuiResource* gr)
 //-----------------------------------------------------------------------------
 void RenderWorld::destroy_gui(GuiId id)
 {
-	CE_ASSERT(m_guis.has(id), "Gui does not exist");
-
-	CE_DELETE(m_gui_pool, m_guis.lookup(id));
-	m_guis.destroy(id);
+	CE_DELETE(m_gui_pool, id_array::get(m_guis, id));
+	id_array::destroy(m_guis, id);
 }
 
 //-----------------------------------------------------------------------------
-Gui* RenderWorld::lookup_gui(GuiId id)
+Gui* RenderWorld::get_gui(GuiId id)
 {
-	CE_ASSERT(m_guis.has(id), "Gui does not exist");
-	
-	return m_guis.lookup(id);
+	return id_array::get(m_guis, id);
 }
 
 //-----------------------------------------------------------------------------
@@ -215,26 +327,26 @@ void RenderWorld::update(const Matrix4x4& view, const Matrix4x4& projection, uin
 	Renderer* r = device()->renderer();
 
 	Matrix4x4 inv_view = view;
-	inv_view.invert();
+	matrix4x4::invert(inv_view);
 
 	r->set_layer_view(0, inv_view);
 	r->set_layer_projection(0, projection);
 	r->set_layer_viewport(0, x, y, width, height);
-	r->set_layer_clear(0, CLEAR_COLOR | CLEAR_DEPTH, Color4::LIGHTBLUE, 1.0f);
+	r->set_layer_clear(0, CLEAR_COLOR | CLEAR_DEPTH, Color4(0x353839FF), 1.0f);
 
 	r->set_state(STATE_DEPTH_WRITE | STATE_COLOR_WRITE | STATE_CULL_CCW);
 	r->commit(0);
 
 	// Draw all meshes
-	for (uint32_t m = 0; m < m_mesh.size(); m++)
+	for (uint32_t m = 0; m < id_array::size(m_mesh); m++)
 	{
 		const Mesh* mesh = m_mesh.m_objects[m];
 
 		r->set_state(STATE_DEPTH_WRITE | STATE_COLOR_WRITE | STATE_ALPHA_WRITE | STATE_CULL_CW);
 		r->set_vertex_buffer(mesh->m_vbuffer);
 		r->set_index_buffer(mesh->m_ibuffer);
-		r->set_program(m_default_program);
-		// r->set_texture(0, m_u_albedo_0, grass_texture, TEXTURE_FILTER_LINEAR | TEXTURE_WRAP_CLAMP_EDGE);
+		r->set_program(render_world_globals::default_program());
+		// r->set_texture(0, render_world_globals::u_albedo_0, grass_texture, TEXTURE_FILTER_LINEAR | TEXTURE_WRAP_CLAMP_EDGE);
 		// r->set_uniform(u_brightness, UNIFORM_FLOAT_1, &brightness, 1);
 
 		r->set_pose(mesh->world_pose());
@@ -242,16 +354,11 @@ void RenderWorld::update(const Matrix4x4& view, const Matrix4x4& projection, uin
 	}
 
 	// Draw all sprites
-	for (uint32_t s = 0; s < m_sprite.size(); s++)
-	{
-		r->set_program(m_texture_program);
-		m_sprite[s]->render(*r, m_u_albedo_0, dt);
-	}
-
-	// Draw all guis
-	for (uint32_t g = 0; g < m_guis.size(); g++)
+	for (uint32_t s = 0; s < id_array::size(m_sprite); s++)
 	{
-		m_guis[g]->render();
+		r->set_program(render_world_globals::default_texture_program());
+		// m_sprite[s]->update(dt);
+		m_sprite[s]->render(*r, render_world_globals::u_albedo_0, dt);
 	}
 }
 

+ 51 - 31
engine/renderers/RenderWorld.h

@@ -54,6 +54,23 @@ struct Vector2;
 struct Vector3;
 struct GuiResource;
 
+namespace render_world_globals
+{
+	void init();
+	void shutdown();
+
+	GPUProgramId default_program();
+	GPUProgramId default_texture_program();
+	GPUProgramId default_font_program();
+	GPUProgramId default_color_program();
+	UniformId default_albedo_uniform();
+	UniformId default_font_uniform();
+	UniformId default_color_uniform();
+};
+
+/// Manages graphics objects in a World.
+///
+/// @ingroup Graphics
 class RenderWorld
 {
 public:
@@ -61,44 +78,47 @@ public:
 	RenderWorld();
 	~RenderWorld();
 
-	MeshId		create_mesh(MeshResource* mr, SceneGraph& sg, int32_t node);
-	void		destroy_mesh(MeshId id);
-	Mesh*		lookup_mesh(MeshId mesh);
+	MeshId create_mesh(MeshResource* mr, SceneGraph& sg, int32_t node);
+
+	/// Destroys the mesh @a id.
+	void destroy_mesh(MeshId id);
+
+	/// Returns the mesh @a id.
+	Mesh* get_mesh(MeshId mesh);
 
-	SpriteId	create_sprite(SpriteResource* sr, SceneGraph& sg, int32_t node);
-	void		destroy_sprite(SpriteId id);
-	Sprite*		lookup_sprite(SpriteId id);
+	SpriteId create_sprite(SpriteResource* sr, SceneGraph& sg, int32_t node);
 
-	MaterialId	create_material(MaterialResource* mr);
-	void		destroy_material(MaterialId id);
-	Material*	lookup_material(MaterialId id);
+	/// Destroys the sprite @a id.
+	void destroy_sprite(SpriteId id);
 
-	GuiId		create_gui(GuiResource* gr);
-	void		destroy_gui(GuiId id);
-	Gui*		lookup_gui(GuiId id);
+	/// Creates the sprite @a id.
+	Sprite* get_sprite(SpriteId id);
 
-	void		update(const Matrix4x4& view, const Matrix4x4& projection, uint16_t x, uint16_t y, uint16_t width, uint16_t height, float dt);
+	MaterialId create_material(MaterialResource* mr);
+
+	/// Destroys the material @a id.
+	void destroy_material(MaterialId id);
+
+	/// Returns the material @a id.
+	Material* get_material(MaterialId id);
+
+	GuiId create_gui(uint16_t width, uint16_t height);
+	void destroy_gui(GuiId id);
+	Gui* get_gui(GuiId id);
+
+	void update(const Matrix4x4& view, const Matrix4x4& projection, uint16_t x, uint16_t y, uint16_t width, uint16_t height, float dt);
 
 private:
 
-	PoolAllocator						m_mesh_pool;
-	PoolAllocator						m_sprite_pool;
-	PoolAllocator						m_material_pool;
-	PoolAllocator						m_gui_pool;
-
-	IdArray<MAX_MESHES, Mesh*>			m_mesh;
-	IdArray<MAX_SPRITES, Sprite*>		m_sprite;
-	IdArray<MAX_MATERIALS, Material*>	m_materials;
-	IdArray<MAX_GUIS, Gui*>				m_guis;
-
-	TextureId m_grass_texture;
-	TextureId m_lightmap_texture;
-	UniformId m_u_albedo_0;
-	ShaderId m_default_vs;
-	ShaderId m_default_fs;
-	ShaderId m_texture_fs;
-	GPUProgramId m_default_program;
-	GPUProgramId m_texture_program;
+	PoolAllocator m_mesh_pool;
+	PoolAllocator m_sprite_pool;
+	PoolAllocator m_material_pool;
+	PoolAllocator m_gui_pool;
+
+	IdArray<MAX_MESHES, Mesh*> m_mesh;
+	IdArray<MAX_SPRITES, Sprite*> m_sprite;
+	IdArray<MAX_MATERIALS, Material*> m_materials;
+	IdArray<MAX_GUIS, Gui*> m_guis;
 };
 
 } // namespace crown

+ 28 - 2
engine/renderers/Sprite.cpp

@@ -44,6 +44,8 @@ Sprite::Sprite(RenderWorld& render_world, SceneGraph& sg, int32_t node, const Sp
 	, m_scene_graph(sg)
 	, m_node(node)
 	, m_resource(sr)
+	, m_frame(0)
+	// , m_animator(this)
 {
 	m_vb = sr->vertex_buffer();
 	m_ib = sr->index_buffer();
@@ -114,10 +116,34 @@ void Sprite::set_material(MaterialId mat)
 	m_material = mat;
 }
 
+//-----------------------------------------------------------------------------
+void Sprite::set_frame(uint32_t i)
+{
+	m_frame = i;
+}
+
+//-----------------------------------------------------------------------------
+void Sprite::play_animation(const char* name, bool loop)
+{
+	// m_animator.play_animation(name, loop);
+}
+
+//-----------------------------------------------------------------------------
+void Sprite::stop_animation()
+{
+	// m_animator.stop_animation();
+}
+
+//-----------------------------------------------------------------------------
+void Sprite::update(float dt)
+{
+	// m_animator.update(dt);
+}
+
 //-----------------------------------------------------------------------------
 void Sprite::render(Renderer& r, UniformId uniform, float dt)
 {
-	Material* material = m_render_world.lookup_material(m_material);
+	Material* material = m_render_world.get_material(m_material);
 	material->bind(r, uniform);
 
 	r.set_state(STATE_DEPTH_WRITE 
@@ -127,7 +153,7 @@ void Sprite::render(Renderer& r, UniformId uniform, float dt)
 		| STATE_BLEND_EQUATION_ADD 
 		| STATE_BLEND_FUNC(STATE_BLEND_FUNC_SRC_ALPHA, STATE_BLEND_FUNC_ONE_MINUS_SRC_ALPHA));
 	r.set_vertex_buffer(m_vb);
-	r.set_index_buffer(m_ib, 0, 6);
+	r.set_index_buffer(m_ib, m_frame * 6, 6);
 	r.set_pose(world_pose());
 	r.commit(0);
 }

+ 24 - 14
engine/renderers/Sprite.h

@@ -31,6 +31,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "Vector3.h"
 #include "Matrix4x4.h"
 #include "Quaternion.h"
+// #include "SpriteAnimator.h"
 
 namespace crown
 {
@@ -44,23 +45,29 @@ struct Unit;
 //-----------------------------------------------------------------------------
 struct Sprite
 {
-							Sprite(RenderWorld& render_world, SceneGraph& sg, int32_t node, const SpriteResource* sr);
-							~Sprite();
+	Sprite(RenderWorld& render_world, SceneGraph& sg, int32_t node, const SpriteResource* sr);
+	~Sprite();
 
-	Vector3					local_position() const;
-	Quaternion				local_rotation() const;
-	Matrix4x4				local_pose() const;
+	Vector3 local_position() const;
+	Quaternion local_rotation() const;
+	Matrix4x4 local_pose() const;
 
-	Vector3					world_position() const;
-	Quaternion				world_rotation() const;
-	Matrix4x4				world_pose() const;
+	Vector3 world_position() const;
+	Quaternion world_rotation() const;
+	Matrix4x4 world_pose() const;
 
-	void					set_local_position(Unit* unit, const Vector3& pos);
-	void					set_local_rotation(Unit* unit, const Quaternion& rot);
-	void					set_local_pose(Unit* unit, const Matrix4x4& pose);
+	void set_local_position(Unit* unit, const Vector3& pos);
+	void set_local_rotation(Unit* unit, const Quaternion& rot);
+	void set_local_pose(Unit* unit, const Matrix4x4& pose);
 
-	void					set_material(MaterialId mat);
-	void					render(Renderer& r, UniformId uniform, float dt);
+	void set_material(MaterialId mat);
+	void render(Renderer& r, UniformId uniform, float dt);
+	void set_frame(uint32_t i);
+
+	void play_animation(const char* name, bool loop);
+	void stop_animation();
+
+	void update(float dt);
 
 public:
 
@@ -69,9 +76,12 @@ public:
 	int32_t					m_node;
 	const SpriteResource*	m_resource;
 
+	uint32_t				m_frame;
 	MaterialId				m_material;
 	VertexBufferId			m_vb;
 	IndexBufferId			m_ib;
+
+	// SpriteAnimator m_animator;
 };
 
-} // namespace crown
+} // namespace crown

+ 10 - 0
engine/renderers/backend/ConstantBuffer.h

@@ -51,6 +51,16 @@ public:
 		m_size = 0;
 	}
 
+	uint32_t position() const
+	{
+		return m_size;
+	}
+
+	void reset(uint32_t begin)
+	{
+		m_size = begin;
+	}
+
 	void write(uint32_t data)
 	{
 		write(&data, sizeof(uint32_t));

+ 91 - 28
engine/renderers/backend/RenderContext.h

@@ -100,30 +100,35 @@ namespace crown
 
 #define STATE_BLEND_FUNC(src, dst) (uint64_t(src << 4) | uint64_t(dst))
 
-#define CLEAR_COLOR					0x1
-#define CLEAR_DEPTH					0x2
+#define CLEAR_COLOR								0x1
+#define CLEAR_DEPTH								0x2
 
 // Texture flags
-#define TEXTURE_FILTER_NEAREST		0x00000001
-#define TEXTURE_FILTER_LINEAR		0x00000002
-#define TEXTURE_FILTER_BILINEAR		0x00000003
-#define TEXTURE_FILTER_TRILINEAR	0x00000004
-#define TEXTURE_FILTER_MASK			0x0000000F
-#define TEXTURE_FILTER_SHIFT		0
-
-#define TEXTURE_WRAP_U_CLAMP_EDGE	0x00000010
-#define TEXTURE_WRAP_U_CLAMP_REPEAT	0x00000020
-#define TEXTURE_WRAP_U_MASK			0x00000030
-#define TEXTURE_WRAP_U_SHIFT		4
-#define TEXTURE_WRAP_V_CLAMP_EDGE	0x00000100
-#define TEXTURE_WRAP_V_CLAMP_REPEAT	0x00000200
-#define TEXTURE_WRAP_V_MASK			0x00000300
-#define TEXTURE_WRAP_V_SHIFT		8
+#define TEXTURE_FILTER_NEAREST					0x00000001
+#define TEXTURE_FILTER_LINEAR					0x00000002
+#define TEXTURE_FILTER_BILINEAR					0x00000003
+#define TEXTURE_FILTER_TRILINEAR				0x00000004
+#define TEXTURE_FILTER_MASK						0x0000000F
+#define TEXTURE_FILTER_SHIFT					0
+
+#define TEXTURE_WRAP_U_CLAMP_EDGE				0x00000010
+#define TEXTURE_WRAP_U_CLAMP_REPEAT				0x00000020
+#define TEXTURE_WRAP_U_MASK						0x00000030
+#define TEXTURE_WRAP_U_SHIFT					4
+#define TEXTURE_WRAP_V_CLAMP_EDGE				0x00000100
+#define TEXTURE_WRAP_V_CLAMP_REPEAT				0x00000200
+#define TEXTURE_WRAP_V_MASK						0x00000300
+#define TEXTURE_WRAP_V_SHIFT					8
+
+#define RENDER_TARGET_NO_TEXTURE				0x00000001
+#define RENDER_TARGET_MASK						0x0000000F
+#define RENDER_TARGET_SHIFT						0
 
 // Sampler flags
-#define SAMPLER_TEXTURE				0x10000000
-#define SAMPLER_MASK				0xF0000000
-#define SAMPLER_SHIFT				28
+#define SAMPLER_TEXTURE							0x10000000
+#define SAMPLER_RENDER_TARGET					0x20000000
+#define SAMPLER_MASK							0xF0000000
+#define SAMPLER_SHIFT							28
 
 struct ViewRect
 {
@@ -175,7 +180,7 @@ struct RenderState
 	{
 		m_flags = STATE_NONE;
 
-		pose = Matrix4x4::IDENTITY;
+		pose = matrix4x4::IDENTITY;
 		program.id = INVALID_ID;
 		vb.id = INVALID_ID;
 		ib.id = INVALID_ID;
@@ -184,11 +189,13 @@ struct RenderState
 		start_index = 0;
 		num_indices = 0xFFFFFFFF;
 		vertex_format = VertexFormat::COUNT;
+		begin_uniform = 0;
+		end_uniform = 0;
 
 		for (uint32_t i = 0; i < STATE_MAX_TEXTURES; i++)
 		{
 			samplers[i].sampler_id.id = INVALID_ID;
-			samplers[i].flags = SAMPLER_TEXTURE;
+			samplers[i].flags = 0;
 		}
 	}
 
@@ -205,6 +212,8 @@ public:
 	uint32_t		start_index;
 	uint32_t		num_indices;
 	VertexFormat::Enum vertex_format;
+	uint32_t		begin_uniform;
+	uint32_t		end_uniform;
 	Sampler			samplers[STATE_MAX_TEXTURES];
 };
 
@@ -217,17 +226,32 @@ struct RenderKey
 
 	uint64_t encode()
 	{
-		return uint64_t(m_layer) << RENDER_LAYER_SHIFT;
+		const uint64_t a = uint64_t(m_layer) << RENDER_LAYER_SHIFT;
+		const uint64_t b = m_depth;
+		return a | b;
 	}
 
 	void decode(uint64_t key)
 	{
 		m_layer = (key & RENDER_LAYER_MASK) >> RENDER_LAYER_SHIFT;
+		m_depth = (key & 0xFFFFFFFF);
 	}
 
 public:
 
 	uint8_t m_layer;
+	int32_t m_depth;
+};
+
+struct SortKey
+{
+	uint64_t key;
+	uint16_t state;
+
+	bool operator()(const SortKey& a, const SortKey& b)
+	{
+		return a.key < b.key;
+	}
 };
 
 /// A vertex buffer valid for one frame only
@@ -258,7 +282,9 @@ struct RenderContext
 
 	uint32_t reserve_transient_vertex_buffer(uint32_t num, VertexFormat::Enum format)
 	{
-		const uint32_t offset = m_tvb_offset;
+		const uint32_t stride = Vertex::bytes_per_vertex(format);
+		uint32_t offset = m_tvb_offset;
+		offset = offset + (stride - (offset % stride)) % stride;
 		m_tvb_offset = offset + Vertex::bytes_per_vertex(format) * num;
 		return offset;
 	}
@@ -321,6 +347,7 @@ struct RenderContext
 
 	void set_texture(uint8_t unit, UniformId sampler_uniform, TextureId texture, uint32_t flags)
 	{
+		CE_ASSERT(unit < STATE_MAX_TEXTURES, "Texture unit out of bounds");
 		m_flags |= STATE_TEXTURE_0 << unit;
 
 		Sampler& sampler = m_state.samplers[unit];
@@ -331,6 +358,19 @@ struct RenderContext
 		set_uniform(sampler_uniform, UniformType::INTEGER_1, &val, 1);
 	}
 
+	void set_texture(uint8_t unit, UniformId sampler_uniform, RenderTargetId texture, uint8_t attachment, uint32_t texture_flags)
+	{
+		CE_ASSERT(unit < STATE_MAX_TEXTURES, "Texture unit out of bounds");
+		m_flags |= STATE_TEXTURE_0 << unit;
+
+		Sampler& sampler = m_state.samplers[unit];
+		sampler.sampler_id = texture;
+		sampler.flags |= SAMPLER_RENDER_TARGET | texture_flags;
+
+		const uint32_t val = unit;
+		set_uniform(sampler_uniform, UniformType::INTEGER_1, &val, 1);
+	}
+
 	void set_layer_render_target(uint8_t layer, RenderTargetId target)
 	{
 		CE_ASSERT(layer < MAX_RENDER_LAYERS, "Layer out of bounds");
@@ -381,13 +421,18 @@ struct RenderContext
 		m_scissors[layer].m_height = height;
 	}
 
-	void commit(uint8_t layer)
+	void commit(uint8_t layer, int32_t depth)
 	{
 		CE_ASSERT(layer < MAX_RENDER_LAYERS, "Layer out of bounds");
 		m_render_key.m_layer = layer;
+		m_render_key.m_depth = depth;
 
+		m_state.begin_uniform = m_last_uniform_offset;
+		m_state.end_uniform = m_constants.position();
+		m_last_uniform_offset = m_constants.position();
 		m_states[m_num_states] = m_state;
-		m_keys[m_num_states] = m_render_key.encode();
+		m_keys[m_num_states].key = m_render_key.encode();
+		m_keys[m_num_states].state = m_num_states;
 		m_num_states++;
 
 		m_render_key.clear();
@@ -402,6 +447,20 @@ struct RenderContext
 		m_num_states = 0;
 		m_state.clear();
 
+		memset(m_targets, 0xFF, sizeof(m_targets));
+		memset(m_viewports, 0, sizeof(m_viewports));
+		memset(m_scissors, 0, sizeof(m_scissors));
+		memset(m_clears, 0, sizeof(m_clears));
+
+		for (uint32_t i = 0; i < MAX_RENDER_LAYERS; i++)
+		{
+			m_projection_matrices[i] = matrix4x4::IDENTITY;
+			m_view_matrices[i] = matrix4x4::IDENTITY;
+		}
+
+		m_commands.clear();
+		m_last_uniform_offset = 0;
+		m_constants.clear();
 		m_tvb_offset = 0;
 		m_tib_offset = 0;
 	}
@@ -409,12 +468,13 @@ struct RenderContext
 	void push()
 	{
 		m_commands.commit();
+		m_last_uniform_offset = 0;
 		m_constants.commit();
 	}
 
 	void sort()
 	{
-		std::sort(m_keys, m_keys + m_num_states);
+		std::sort(m_keys, m_keys + m_num_states, SortKey());
 	}
 
 public:
@@ -424,9 +484,10 @@ public:
 	RenderState m_state;
 
 	// Per-state data
+	SortKey m_keys[MAX_RENDER_STATES];
+
 	uint32_t m_num_states;
 	RenderState m_states[MAX_RENDER_STATES];
-	uint64_t m_keys[MAX_RENDER_STATES];
 
 	// Per-layer data
 	RenderTargetId m_targets[MAX_RENDER_LAYERS];
@@ -437,6 +498,8 @@ public:
 	ClearState m_clears[MAX_RENDER_LAYERS];
 
 	CommandBuffer m_commands;
+
+	uint32_t m_last_uniform_offset;
 	ConstantBuffer m_constants;
 
 	uint32_t m_tvb_offset;

+ 95 - 40
engine/renderers/backend/Renderer.h

@@ -42,6 +42,11 @@ namespace crown
 extern ShaderUniform::Enum name_to_stock_uniform(const char* uniform);
 class RendererImplementation;
 
+/// @defgroup Graphics Graphics
+
+/// Renderer interface.
+///
+/// @ingroup Graphics
 class Renderer
 {
 public:
@@ -77,7 +82,7 @@ public:
 	void update_uniform_impl(UniformId id, size_t size, const void* data);
 	void destroy_uniform_impl(UniformId id);
 
-	void create_render_target_impl(RenderTargetId id, uint16_t width, uint16_t height, RenderTargetFormat::Enum format);
+	void create_render_target_impl(RenderTargetId id, uint16_t width, uint16_t height, PixelFormat::Enum format, uint32_t flags);
 	void destroy_render_target_impl(RenderTargetId id);
 
 	/// Initializes the renderer.
@@ -123,7 +128,7 @@ public:
 	/// @a data is the array containig @a size bytes of vertex data in the given @a format.
 	VertexBufferId create_vertex_buffer(size_t size, const void* data, VertexFormat::Enum format)
 	{
-		const VertexBufferId id = m_vertex_buffers.create();
+		const VertexBufferId id = id_table::create(m_vertex_buffers);
 
 		m_submit->m_commands.write(CommandType::CREATE_VERTEX_BUFFER);
 		m_submit->m_commands.write(id);
@@ -139,7 +144,7 @@ public:
 	/// use Renderer::update_vertex_buffer() to fill the buffer with actual data.
 	VertexBufferId create_dynamic_vertex_buffer(size_t size)
 	{
-		const VertexBufferId id = m_vertex_buffers.create();
+		const VertexBufferId id = id_table::create(m_vertex_buffers);
 
 		m_submit->m_commands.write(CommandType::CREATE_DYNAMIC_VERTEX_BUFFER);
 		m_submit->m_commands.write(id);
@@ -160,6 +165,7 @@ public:
 
 		tvb = (TransientVertexBuffer*) default_allocator().allocate(sizeof(TransientVertexBuffer) + size);
 		tvb->vb = vb;
+		tvb->start_vertex = 0;
 		tvb->data = (char*) &tvb[1]; // Nice trick
 		tvb->size = size;
 
@@ -189,7 +195,7 @@ public:
 	/// at the given @a offset.
 	void update_vertex_buffer(VertexBufferId id, size_t offset, size_t size, const void* data)
 	{
-		CE_ASSERT(m_vertex_buffers.has(id), "Vertex buffer does not exist");
+		CE_ASSERT(id_table::has(m_vertex_buffers, id), "Vertex buffer does not exist");
 
 		m_submit->m_commands.write(CommandType::UPDATE_VERTEX_BUFFER);
 		m_submit->m_commands.write(id);
@@ -201,7 +207,7 @@ public:
 	/// Destroys the given vertex buffer @a id.
 	void destroy_vertex_buffer(VertexBufferId id)
 	{
-		CE_ASSERT(m_vertex_buffers.has(id), "Vertex buffer does not exist");
+		CE_ASSERT(id_table::has(m_vertex_buffers, id), "Vertex buffer does not exist");
 
 		m_submit->m_commands.write(CommandType::DESTROY_VERTEX_BUFFER);
 		m_submit->m_commands.write(id);
@@ -220,7 +226,7 @@ public:
 	/// @a data is the array containing @a size bytes of index data.
 	IndexBufferId create_index_buffer(size_t size, const void* data)
 	{
-		const IndexBufferId id = m_index_buffers.create();
+		const IndexBufferId id = id_table::create(m_index_buffers);
 
 		m_submit->m_commands.write(CommandType::CREATE_INDEX_BUFFER);
 		m_submit->m_commands.write(id);
@@ -235,7 +241,7 @@ public:
 	/// use Renderer::update_index_buffer() to fill the buffer with actual data.
 	IndexBufferId create_dynamic_index_buffer(size_t size)
 	{
-		const IndexBufferId id = m_index_buffers.create();
+		const IndexBufferId id = id_table::create(m_index_buffers);
 
 		m_submit->m_commands.write(CommandType::CREATE_DYNAMIC_INDEX_BUFFER);
 		m_submit->m_commands.write(id);
@@ -256,6 +262,7 @@ public:
 
 		tib = (TransientIndexBuffer*) default_allocator().allocate(sizeof(TransientIndexBuffer) + size);
 		tib->ib = ib;
+		tib->start_index = 0;
 		tib->data = (char*) &tib[1]; // Same as before
 		tib->size = size;
 
@@ -283,7 +290,7 @@ public:
 	/// at the given @a offset.
 	void update_index_buffer(IndexBufferId id, size_t offset, size_t size, const void* data)
 	{
-		CE_ASSERT(m_index_buffers.has(id), "Index buffer does not exist");
+		CE_ASSERT(id_table::has(m_index_buffers, id), "Index buffer does not exist");
 
 		m_submit->m_commands.write(CommandType::UPDATE_INDEX_BUFFER);
 		m_submit->m_commands.write(id);
@@ -295,7 +302,7 @@ public:
 	/// Destroys the @a id index buffer.
 	void destroy_index_buffer(IndexBufferId id)
 	{
-		CE_ASSERT(m_index_buffers.has(id), "Index buffer does not exist");
+		CE_ASSERT(id_table::has(m_index_buffers, id), "Index buffer does not exist");
 
 		m_submit->m_commands.write(CommandType::DESTROY_INDEX_BUFFER);
 		m_submit->m_commands.write(id);
@@ -314,7 +321,7 @@ public:
 	/// The array @a data should contain @a width * @a height elements of the given @a format.
 	TextureId create_texture(uint32_t width, uint32_t height, PixelFormat::Enum format, const void* data)
 	{
-		const TextureId id = m_textures.create();
+		const TextureId id = id_table::create(m_textures);
 
 		m_submit->m_commands.write(CommandType::CREATE_TEXTURE);
 		m_submit->m_commands.write(id);
@@ -331,7 +338,7 @@ public:
 	/// to Renderer::create_texture()
 	void update_texture(TextureId id, uint32_t x, uint32_t y, uint32_t width, uint32_t height, const void* data)
 	{
-		CE_ASSERT(m_textures.has(id), "Texture does not exist");
+		CE_ASSERT(id_table::has(m_textures, id), "Texture does not exist");
 
 		m_submit->m_commands.write(CommandType::UPDATE_TEXTURE);
 		m_submit->m_commands.write(id);
@@ -345,7 +352,7 @@ public:
 	/// Destroys the texture @æ id.
 	void destroy_texture(TextureId id)
 	{
-		CE_ASSERT(m_textures.has(id), "Texture does not exist");
+		CE_ASSERT(id_table::has(m_textures, id), "Texture does not exist");
 
 		m_submit->m_commands.write(CommandType::DESTROY_TEXTURE);
 		m_submit->m_commands.write(id);
@@ -354,7 +361,7 @@ public:
 	/// Creates a new shader of the given @a type from the string @a text.
 	ShaderId create_shader(ShaderType::Enum type, const char* text)
 	{
-		const ShaderId id = m_shaders.create();
+		const ShaderId id = id_table::create(m_shaders);
 
 		m_submit->m_commands.write(CommandType::CREATE_SHADER);
 		m_submit->m_commands.write(id);
@@ -367,7 +374,7 @@ public:
 	/// Destroy the shader @a id.
 	void destroy_shader(ShaderId id)
 	{
-		CE_ASSERT(m_shaders.has(id), "Shader does not exist");
+		CE_ASSERT(id_table::has(m_shaders, id), "Shader does not exist");
 
 		m_submit->m_commands.write(CommandType::DESTROY_SHADER);
 		m_submit->m_commands.write(id);
@@ -376,7 +383,7 @@ public:
 	/// Creates a new gpu program from @a vertex shader and @a pixel shader.
 	GPUProgramId create_gpu_program(ShaderId vertex, ShaderId pixel)
 	{
-		const GPUProgramId id = m_gpu_programs.create();
+		const GPUProgramId id = id_table::create(m_gpu_programs);
 
 		m_submit->m_commands.write(CommandType::CREATE_GPU_PROGRAM);
 		m_submit->m_commands.write(id);
@@ -389,7 +396,7 @@ public:
 	/// Destroys the gpu program @a id.
 	void destroy_gpu_program(GPUProgramId id)
 	{
-		CE_ASSERT(m_gpu_programs.has(id), "GPU program does not exist");
+		CE_ASSERT(id_table::has(m_gpu_programs, id), "GPU program does not exist");
 
 		m_submit->m_commands.write(CommandType::DESTROY_GPU_PROGRAM);
 		m_submit->m_commands.write(id);
@@ -401,7 +408,7 @@ public:
 	{
 		CE_ASSERT(name_to_stock_uniform(name) == ShaderUniform::COUNT, "Uniform name '%s' is a stock uniform.", name);
 
-		const UniformId id = m_uniforms.create();
+		const UniformId id = id_table::create(m_uniforms);
 		size_t len = string::strlen(name);
 
 		CE_ASSERT(len < CE_MAX_UNIFORM_NAME_LENGTH, "Max uniform name length is %d", CE_MAX_UNIFORM_NAME_LENGTH);
@@ -419,21 +426,35 @@ public:
 	/// Destroys the uniform @a id.
 	void destroy_uniform(UniformId id)
 	{
-		CE_ASSERT(m_uniforms.has(id), "Uniform does not exist");
+		CE_ASSERT(id_table::has(m_uniforms, id), "Uniform does not exist");
 
 		m_submit->m_commands.write(CommandType::DESTROY_UNIFORM);
 		m_submit->m_commands.write(id);
 	}
 
-	// 
-	// RenderTargetId create_render_target(uint16_t width, uint16_t height, RenderTargetFormat::Enum format)
-	// {
+	/// Creates a new render target of size @a width and @a height with the given @a format.
+	RenderTargetId create_render_target(uint16_t width, uint16_t height, PixelFormat::Enum format, uint32_t flags = 0)
+	{
+		const RenderTargetId id = id_table::create(m_render_targets);
 
-	// }
-	// void destroy_render_target(RenderTargetId id)
-	// {
+		m_submit->m_commands.write(CommandType::CREATE_RENDER_TARGET);
+		m_submit->m_commands.write(id);
+		m_submit->m_commands.write(width);
+		m_submit->m_commands.write(height);
+		m_submit->m_commands.write(format);
+		m_submit->m_commands.write(flags);
 
-	// }
+		return id;
+	}
+
+	/// Destroys the render target @a id.
+	void destroy_render_target(RenderTargetId id)
+	{
+		CE_ASSERT(id_table::has(m_render_targets, id), "Render target does not exist");
+
+		m_submit->m_commands.write(CommandType::DESTROY_RENDER_TARGET);
+		m_submit->m_commands.write(id);
+	}
 
 	//-----------------------------------------------------------------------------
 	void execute_commands(CommandBuffer& cmds)
@@ -670,6 +691,31 @@ public:
 
 					break;
 				}
+				case CommandType::CREATE_RENDER_TARGET:
+				{
+					RenderTargetId id;
+					uint16_t width;
+					uint16_t height;
+					PixelFormat::Enum format;
+					uint32_t flags;
+
+					cmds.read(id);
+					cmds.read(width);
+					cmds.read(height);
+					cmds.read(format);
+					cmds.read(flags);
+
+					create_render_target_impl(id, width, height, format, flags);
+					break;
+				}
+				case CommandType::DESTROY_RENDER_TARGET:
+				{
+					RenderTargetId id;
+					cmds.read(id);
+
+					destroy_render_target_impl(id);
+					break;
+				}
 				case CommandType::END:
 				{
 					end = true;
@@ -687,12 +733,17 @@ public:
 		cmds.clear();
 	}
 
-	void update_uniforms(ConstantBuffer& cbuf)
+	void update_uniforms(ConstantBuffer& cbuf, uint32_t begin, uint32_t end)
 	{
-		UniformType::Enum type;
+		cbuf.reset(begin);
 
-		while ((type = (UniformType::Enum)cbuf.read()) != UniformType::END)
+		while (cbuf.position() < end)
 		{
+			UniformType::Enum type = (UniformType::Enum) cbuf.read();
+
+			if (type == UniformType::END)
+				break;
+
 			UniformId id;
 			uint32_t size;
 
@@ -702,8 +753,6 @@ public:
 
 			update_uniform_impl(id, size, data);
 		}
-
-		cbuf.clear();
 	}
 
 	void set_state(uint64_t flags)
@@ -718,13 +767,13 @@ public:
 
 	void set_program(GPUProgramId id)
 	{
-		CE_ASSERT(m_gpu_programs.has(id), "GPU program does not exist");
+		CE_ASSERT(id_table::has(m_gpu_programs, id), "GPU program does not exist");
 		m_submit->set_program(id);
 	}
 
 	void set_vertex_buffer(VertexBufferId id, uint32_t num_vertices = 0xFFFFFFFF)
 	{
-		CE_ASSERT(m_vertex_buffers.has(id), "Vertex buffer does not exist");
+		CE_ASSERT(id_table::has(m_vertex_buffers, id), "Vertex buffer does not exist");
 		m_submit->set_vertex_buffer(id, num_vertices);
 	}
 
@@ -735,7 +784,7 @@ public:
 
 	void set_index_buffer(IndexBufferId id, uint32_t start_index = 0, uint32_t num_indices = 0xFFFFFFFF)
 	{
-		CE_ASSERT(m_index_buffers.has(id), "Index buffer does not exist");
+		CE_ASSERT(id_table::has(m_index_buffers, id), "Index buffer does not exist");
 		m_submit->set_index_buffer(id, start_index, num_indices);
 	}
 
@@ -746,21 +795,28 @@ public:
 
 	void set_uniform(UniformId id, UniformType::Enum type, const void* value, uint8_t num)
 	{
-		CE_ASSERT(m_uniforms.has(id), "Uniform does not exist");
+		CE_ASSERT(id_table::has(m_uniforms, id), "Uniform does not exist");
 		CE_ASSERT_NOT_NULL(value);
 		m_submit->set_uniform(id, type, value, num);
 	}
 
 	void set_texture(uint8_t unit, UniformId sampler_uniform, TextureId texture, uint32_t flags)
 	{
-		CE_ASSERT(m_uniforms.has(sampler_uniform), "Uniform does not exist");
-		CE_ASSERT(m_textures.has(texture), "Texture does not exist");
+		CE_ASSERT(id_table::has(m_uniforms, sampler_uniform), "Uniform does not exist");
+		CE_ASSERT(id_table::has(m_textures, texture), "Texture does not exist");
 		m_submit->set_texture(unit, sampler_uniform, texture, flags);
 	}
 
+	void set_texture(uint8_t unit, UniformId sampler_uniform, RenderTargetId texture, uint8_t attachment, uint32_t texture_flags)
+	{
+		CE_ASSERT(id_table::has(m_uniforms, sampler_uniform), "Uniform does not exist");
+		CE_ASSERT(id_table::has(m_render_targets, texture), "Render target does not exist");
+		m_submit->set_texture(unit, sampler_uniform, texture, attachment, texture_flags);
+	}
+
 	void set_layer_render_target(uint8_t layer, RenderTargetId id)
 	{
-		CE_ASSERT(m_render_targets.has(id), "Render target does not exist");
+		CE_ASSERT(id_table::has(m_render_targets, id), "Render target does not exist");
 		m_submit->set_layer_render_target(layer, id);
 	}
 
@@ -789,9 +845,9 @@ public:
 		m_submit->set_layer_scissor(layer, x, y, width, height);
 	}
 
-	void commit(uint8_t layer)
+	void commit(uint8_t layer, int32_t depth = 0)
 	{
-		m_submit->commit(layer);
+		m_submit->commit(layer, depth);
 	}
 
 	static int32_t render_thread(void* thiz)
@@ -832,7 +888,6 @@ public:
 		swap_contexts();
 
 		execute_commands(m_draw->m_commands);
-		update_uniforms(m_draw->m_constants);
 
 		if (m_is_initialized)
 		{

+ 13 - 11
engine/renderers/backend/RendererTypes.h

@@ -66,16 +66,6 @@ struct UniformType
 	};
 };
 
-struct RenderTargetFormat
-{
-	enum Enum
-	{
-		RTF_RGB_8,		///< RGB values, 8-bit each
-		RTF_RGBA_8,		///< RGBA values, 8-bit each
-		RTF_D24			///< Depth
-	};
-};
-
 struct ShaderUniform
 {
 	enum Enum
@@ -141,8 +131,17 @@ struct PixelFormat
 {
 	enum Enum
 	{
-		RGB_8 = 0,
+		DXT1,
+		DXT3,
+		DXT5,
+
+		RGB_8,
 		RGBA_8,
+
+		D16,
+		D24,
+		D32,
+		D24S8,
 		COUNT
 	};
 };
@@ -177,6 +176,9 @@ struct CommandType
 		CREATE_UNIFORM,
 		DESTROY_UNIFORM,
 
+		CREATE_RENDER_TARGET,
+		DESTROY_RENDER_TARGET,
+
 		END
 	};
 };

+ 322 - 215
engine/renderers/backend/gl/GLRenderer.cpp

@@ -30,6 +30,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 	#include <GL/glew.h>
 #elif defined(ANDROID)
 	#include <GLES2/gl2.h>
+	#include <GLES2/gl2ext.h>
 #else
 	#error "Oops, wrong platform"
 #endif
@@ -49,22 +50,22 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "Vector4.h"
 #include "Memory.h"
 #include "VertexFormat.h"
+#include "Hash.h"
 
-//-----------------------------------------------------------------------------
-static const char* gl_error_to_string(GLenum error)
-{
-	switch (error)
+#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
+
+	static const char* gl_error_to_string(GLenum error)
 	{
-		case GL_INVALID_ENUM: return "GL_INVALID_ENUM";
-		case GL_INVALID_VALUE: return "GL_INVALID_VALUE";
-		case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION";
-		case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY";
-		default: return "UNKNOWN_GL_ERROR";
+		switch (error)
+		{
+			case GL_INVALID_ENUM: return "GL_INVALID_ENUM";
+			case GL_INVALID_VALUE: return "GL_INVALID_VALUE";
+			case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION";
+			case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY";
+			default: return "UNKNOWN_GL_ERROR";
+		}
 	}
-}
 
-//-----------------------------------------------------------------------------
-#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
 	#define GL_CHECK(function)\
 		function;\
 		do { GLenum error; CE_ASSERT((error = glGetError()) == GL_NO_ERROR,\
@@ -74,6 +75,26 @@ static const char* gl_error_to_string(GLenum error)
 		function;
 #endif
 
+#ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
+	#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
+#endif
+#ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
+	#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
+#endif
+#ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
+	#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
+#endif
+
+#ifdef ANDROID
+	#define GL_DEPTH_STENCIL GL_DEPTH_STENCIL_OES
+	#ifndef GL_DEPTH_STENCIL_ATTACHMENT
+		#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
+	#endif // GL_DEPTH_STENCIL_ATTACHMENT
+	#define GL_DEPTH_COMPONENT24 GL_DEPTH_COMPONENT24_OES
+	#define GL_DEPTH_COMPONENT32 GL_DEPTH_COMPONENT32_OES
+	#define GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_OES
+#endif // ANDROID
+
 namespace crown
 {
 
@@ -114,17 +135,58 @@ const GLenum TEXTURE_WRAP_TABLE[] =
 };
 
 //-----------------------------------------------------------------------------
-struct GLTextureFormatInfo
+struct TextureFormatInfo
 {
 	GLenum internal_format;
 	GLenum format;
 };
 
 //-----------------------------------------------------------------------------
-const GLTextureFormatInfo TEXTURE_FORMAT_TABLE[PixelFormat::COUNT] =
+const TextureFormatInfo TEXTURE_FORMAT_TABLE[PixelFormat::COUNT] =
 {
-	{ GL_RGB, GL_RGB },
-	{ GL_RGBA, GL_RGBA}
+	{ GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT },
+	{ GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT },
+	{ GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT },
+	{ GL_RGB,                           GL_RGB                           },
+	{ GL_RGBA,                          GL_RGBA                          },
+	{ GL_DEPTH_COMPONENT16,             GL_DEPTH_COMPONENT               },
+	{ GL_DEPTH_COMPONENT24,             GL_DEPTH_COMPONENT               },
+	{ GL_DEPTH_COMPONENT32,             GL_DEPTH_COMPONENT               },
+	{ GL_DEPTH24_STENCIL8,              GL_DEPTH_STENCIL                 }
+};
+
+//-----------------------------------------------------------------------------
+static bool is_compressed(PixelFormat::Enum fmt)
+{
+	return fmt < PixelFormat::RGB_8;
+}
+
+//-----------------------------------------------------------------------------
+static bool is_color(PixelFormat::Enum fmt)
+{
+	return fmt >= PixelFormat::RGB_8 && fmt < PixelFormat::D16;
+}
+
+//-----------------------------------------------------------------------------
+static bool is_depth(PixelFormat::Enum fmt)
+{
+	return fmt >= PixelFormat::D16 && fmt < PixelFormat::COUNT;
+}
+
+//-----------------------------------------------------------------------------
+static uint32_t PIXEL_FORMAT_SIZES[PixelFormat::COUNT] =
+{
+	8,  // DXT1,
+	16, // DXT3,
+	16, // DXT5,
+
+	3, // RGB_8,
+	4, // RGBA_8,
+
+	2, // D16,
+	3, // D24,
+	4, // D32,
+	4, // D24S8,
 };
 
 //-----------------------------------------------------------------------------
@@ -214,6 +276,25 @@ ShaderUniform::Enum name_to_stock_uniform(const char* uniform)
 	return ShaderUniform::COUNT;
 }
 
+static UniformType::Enum gl_enum_to_uniform_type(GLenum type)
+{
+	switch (type)
+	{
+		case GL_INT: return UniformType::INTEGER_1;
+		case GL_INT_VEC2: return UniformType::INTEGER_2;
+		case GL_INT_VEC3: return UniformType::INTEGER_3;
+		case GL_INT_VEC4: return UniformType::INTEGER_4;
+		case GL_FLOAT: return UniformType::FLOAT_1;
+		case GL_FLOAT_VEC2: return UniformType::FLOAT_2;
+		case GL_FLOAT_VEC3: return UniformType::FLOAT_3;
+		case GL_FLOAT_VEC4: return UniformType::FLOAT_4;
+		case GL_FLOAT_MAT3: return UniformType::FLOAT_3x3;
+		case GL_FLOAT_MAT4: return UniformType::FLOAT_4x4;
+		case GL_SAMPLER_2D: return UniformType::INTEGER_1;
+		default: CE_FATAL("Oops, unknown uniform type"); return UniformType::END;
+	}
+}
+
 //-----------------------------------------------------------------------------
 struct VertexBuffer
 {
@@ -288,48 +369,6 @@ public:
 	uint32_t	m_size;
 };
 
-//-----------------------------------------------------------------------------
-struct Uniform
-{
-	Uniform()
-	{
-		string::strncpy(m_name, "", CE_MAX_UNIFORM_NAME_LENGTH);
-	}
-
-	void create(const char* name, UniformType::Enum type, uint8_t num)
-	{
-		string::strncpy(m_name, name, CE_MAX_UNIFORM_NAME_LENGTH);
-		m_type = type;
-		m_num = num;
-
-		size_t size = UNIFORM_SIZE_TABLE[type] * num;
-		m_data = default_allocator().allocate(size);
-		memset(m_data, 0, size);
-
-		// Log::d("Uniform created, name = %s, type = %d, num = %d, size = %ld, ptr = %p", m_name, type, num, size, m_data);
-	}
-
-	void update(size_t size, const void* data)
-	{
-		// Log::d("Uniform updated, new size = %ld, new ptr = %d", size, *((int32_t*)data));
-		memcpy(m_data, data, size);
-	}
-
-	void destroy()
-	{
-		default_allocator().deallocate(m_data);
-		string::strncpy(m_name, "", CE_MAX_UNIFORM_NAME_LENGTH); // <- this is a temporary fix
-		// Log::d("Uniform destroyed, name = %s, type = %d, num = %d, ptr = %p", m_name, m_type, m_num, m_data);
-	}
-
-public:
-
-	char m_name[CE_MAX_UNIFORM_NAME_LENGTH];
-	UniformType::Enum m_type;
-	uint8_t m_num;
-	void* m_data;
-};
-
 //-----------------------------------------------------------------------------
 struct Shader
 {
@@ -370,29 +409,73 @@ struct Texture
 	void create(uint32_t width, uint32_t height, PixelFormat::Enum format, const void* data)
 	{
 		GL_CHECK(glGenTextures(1, &m_id));
+		CE_ASSERT(m_id != 0, "Failed to create texture");
 		GL_CHECK(glBindTexture(GL_TEXTURE_2D, m_id));
 
 		#if defined(LINUX) || defined(WINDOWS)
 			GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE));
 		#endif
 
-		GLenum internal_fmt = TEXTURE_FORMAT_TABLE[format].internal_format;
-		GLenum fmt = TEXTURE_FORMAT_TABLE[format].format;
+		const GLenum internal_fmt = TEXTURE_FORMAT_TABLE[format].internal_format;
+		const GLenum fmt = TEXTURE_FORMAT_TABLE[format].format;
+
+		if (is_compressed(format))
+		{
+			GL_CHECK(glCompressedTexImage2D(GL_TEXTURE_2D,
+						0,
+						internal_fmt,
+						width, height,
+						0,
+					 	width * height * PIXEL_FORMAT_SIZES[format],
+					 	data));
+		}
+		else
+		{
+			GL_CHECK(glTexImage2D(GL_TEXTURE_2D,
+						0,
+						internal_fmt,
+						width, height,
+						0,
+					 	fmt,
+					 	GL_UNSIGNED_BYTE,
+					 	data));
+		}
 
-		GL_CHECK(glTexImage2D(GL_TEXTURE_2D, 0, internal_fmt, width, height, 0,
-					 			fmt, GL_UNSIGNED_BYTE, data));
 		GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
 
 		m_target = GL_TEXTURE_2D;
+		m_width = width;
+		m_height = height;
 		m_format = format;
+		m_gl_fmt = fmt;
 	}
 
 	//-----------------------------------------------------------------------------
 	void update(uint32_t x, uint32_t y, uint32_t width, uint32_t height, const void* data)
 	{
 		GL_CHECK(glBindTexture(GL_TEXTURE_2D, m_id));
-		GL_CHECK(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA,
-									GL_UNSIGNED_BYTE, data));
+
+		if (is_compressed(m_format))
+		{
+			GL_CHECK(glCompressedTexSubImage2D(GL_TEXTURE_2D,
+				0,
+				x, y,
+				width, height,
+				m_gl_fmt,
+				width * height * PIXEL_FORMAT_SIZES[m_format],
+				data));
+		}
+		else
+		{
+			GL_CHECK(glTexSubImage2D(GL_TEXTURE_2D,
+				0,
+				x, y,
+				width, height,
+				GL_RGBA,
+				GL_UNSIGNED_BYTE,
+				data));
+		}
+
 		GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
 	}
 
@@ -430,18 +513,19 @@ struct Texture
 
 public:
 
-	GLuint				m_id;
-	GLenum				m_target;      // Always GL_TEXTURE_2D
-	uint32_t			m_width;
-	uint32_t			m_height;
-	PixelFormat::Enum	m_format;
+	GLuint m_id;
+	GLenum m_target;      // Always GL_TEXTURE_2D
+	uint32_t m_width;
+	uint32_t m_height;
+	PixelFormat::Enum m_format;
+	GLenum m_gl_fmt;
 };
 
 //-----------------------------------------------------------------------------
 struct GPUProgram
 {
 	//-----------------------------------------------------------------------------
-	void create(const Shader& vertex, const Shader& pixel, uint32_t num_uniforms, Uniform* uniforms)
+	void create(const Shader& vertex, const Shader& pixel, const Hash<void*>& registry)
 	{
 		m_id = GL_CHECK(glCreateProgram());
 
@@ -474,8 +558,8 @@ struct GPUProgram
 		GL_CHECK(glGetProgramiv(m_id, GL_ACTIVE_ATTRIBUTES, &num_active_attribs));
 		GL_CHECK(glGetProgramiv(m_id, GL_ACTIVE_UNIFORMS, &num_active_uniforms));
 
-		// Log::d("Found %d active attribs", num_active_attribs);
-		// Log::d("Found %d active uniforms", num_active_uniforms);
+		// CE_LOGD("Found %d active attribs", num_active_attribs);
+		// CE_LOGD("Found %d active uniforms", num_active_uniforms);
 
 		// Find active attribs/uniforms max length
 		GLint max_attrib_length;
@@ -491,7 +575,7 @@ struct GPUProgram
 			GL_CHECK(glGetActiveAttrib(m_id, attrib, max_attrib_length, NULL, &attrib_size, &attrib_type, attrib_name));
 
 			/* GLint attrib_location = */GL_CHECK(glGetAttribLocation(m_id, attrib_name));
-			// Log::d("Attrib %d: name = '%s' location = '%d'", attrib, attrib_name, attrib_location);
+			// CE_LOGD("Attrib %d: name = '%s' location = '%d'", attrib, attrib_name, attrib_location);
 		}
 
 		m_num_active_attribs = 0;
@@ -525,19 +609,18 @@ struct GPUProgram
 			}
 			else
 			{
-				for (uint32_t i = 0; i < num_uniforms; i++)
-				{
-					if (string::strcmp(uniforms[i].m_name, uniform_name) == 0)
-					{
-						m_uniforms[m_num_uniforms] = uniforms[i].m_type;
-						m_uniform_info[m_num_uniforms].loc = uniform_location;
-						m_uniform_info[m_num_uniforms].data = uniforms[i].m_data;
-						m_num_uniforms++;
-					}
-				}
+				void* data = hash::get(registry, string::murmur2_64(uniform_name, string::strlen(uniform_name)), (void*) NULL);
+
+				if (data == NULL)
+					continue;
+
+				m_uniforms[m_num_uniforms] = gl_enum_to_uniform_type(uniform_type);
+				m_uniform_info[m_num_uniforms].loc = uniform_location;
+				m_uniform_info[m_num_uniforms].data = data;
+				m_num_uniforms++;
 			}
 
-			// Log::d("Uniform %d: name = '%s' location = '%d' stock = %s", uniform, uniform_name, uniform_location,
+			// CE_LOGD("Uniform %d: name = '%s' location = '%d' stock = %s", uniform, uniform_name, uniform_location,
 			// 			 (stock_uniform != ShaderUniform::COUNT) ? "yes" : "no");
 		}
 	}
@@ -560,13 +643,20 @@ struct GPUProgram
 
 			const VertexFormatInfo& info = Vertex::info(format);
 
-			if (loc != -1 && info.has_attrib(attrib))
+			if (loc == -1)
+				return;
+
+			if (info.has_attrib(attrib))
 			{
 				GL_CHECK(glEnableVertexAttribArray(loc));
 				uint32_t base_vertex = start_vertex * info.attrib_stride(attrib) + info.attrib_offset(attrib);
 				GL_CHECK(glVertexAttribPointer(loc, info.num_components(attrib), GL_FLOAT, GL_FALSE, info.attrib_stride(attrib),
 										(GLvoid*)(uintptr_t) base_vertex));
 			}
+			else
+			{
+				GL_CHECK(glDisableVertexAttribArray(loc));
+			}
 		}
 	}
 
@@ -582,15 +672,15 @@ struct GPUProgram
 			switch (type)
 			{
 				case UniformType::INTEGER_1:   GL_CHECK(glUniform1iv(loc, 1, (const GLint*)data)); break;
-				case UniformType::INTEGER_2:   GL_CHECK(glUniform2iv(loc, 2, (const GLint*)data)); break;
-				case UniformType::INTEGER_3:   GL_CHECK(glUniform3iv(loc, 3, (const GLint*)data)); break;				
-				case UniformType::INTEGER_4:   GL_CHECK(glUniform4iv(loc, 4, (const GLint*)data)); break;
+				case UniformType::INTEGER_2:   GL_CHECK(glUniform2iv(loc, 1, (const GLint*)data)); break;
+				case UniformType::INTEGER_3:   GL_CHECK(glUniform3iv(loc, 1, (const GLint*)data)); break;				
+				case UniformType::INTEGER_4:   GL_CHECK(glUniform4iv(loc, 1, (const GLint*)data)); break;
 				case UniformType::FLOAT_1:     GL_CHECK(glUniform1fv(loc, 1, (const GLfloat*)data)); break;
-				case UniformType::FLOAT_2:     GL_CHECK(glUniform2fv(loc, 2, (const GLfloat*)data)); break;
-				case UniformType::FLOAT_3:     GL_CHECK(glUniform3fv(loc, 3, (const GLfloat*)data)); break;
-				case UniformType::FLOAT_4:     GL_CHECK(glUniform4fv(loc, 4, (const GLfloat*)data)); break;
-				case UniformType::FLOAT_3x3:   GL_CHECK(glUniformMatrix3fv(loc, 9, GL_FALSE, (const GLfloat*)data)); break;
-				case UniformType::FLOAT_4x4:   GL_CHECK(glUniformMatrix4fv(loc, 16, GL_FALSE, (const GLfloat*)data)); break;
+				case UniformType::FLOAT_2:     GL_CHECK(glUniform2fv(loc, 1, (const GLfloat*)data)); break;
+				case UniformType::FLOAT_3:     GL_CHECK(glUniform3fv(loc, 1, (const GLfloat*)data)); break;
+				case UniformType::FLOAT_4:     GL_CHECK(glUniform4fv(loc, 1, (const GLfloat*)data)); break;
+				case UniformType::FLOAT_3x3:   GL_CHECK(glUniformMatrix3fv(loc, 1, GL_FALSE, (const GLfloat*)data)); break;
+				case UniformType::FLOAT_4x4:   GL_CHECK(glUniformMatrix4fv(loc, 1, GL_FALSE, (const GLfloat*)data)); break;
 				default: CE_FATAL("Oops, unknown uniform type"); break;
 			}
 		}
@@ -622,79 +712,74 @@ public:
 //-----------------------------------------------------------------------------
 struct RenderTarget
 {
-	void create(uint16_t /*width*/, uint16_t /*height*/, RenderTargetFormat /*format*/)
+	void create(uint16_t width, uint16_t height, PixelFormat::Enum format, uint32_t flags)
 	{
-		// // Create and bind FBO
-		// GL_CHECK(glGenFramebuffersEXT(1, &m_gl_fbo));
-		// GL_CHECK(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_gl_fbo));
-
-		// GLuint renderedTexture;
-		// glGenTextures(1, &renderedTexture);
-		 
-		// // "Bind" the newly created texture : all future texture functions will modify this texture
-		// glBindTexture(GL_TEXTURE_2D, renderedTexture);
-		 
-		// // Give an empty image to OpenGL ( the last "0" )
-		// glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, 1024, 768, 0,GL_RGB, GL_UNSIGNED_BYTE, 0);
-		 
-		// // Poor filtering. Needed !
-		// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-		// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-
-
-		// // Create color/depth attachments
-		// switch (format)
-		// {
-		// 	case RTF_RGBA_8:
-		// 	case RTF_D24:
-		// 	{
-		// 		if (format == RTF_RGBA_8)
-		// 		{
-		// 			GL_CHECK(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
-  //                      GL_COLOR_ATTACHMENT0_EXT,
-  //                      GL_TEXTURE_2D,
-  //                      renderedTexture,
-  //                      0));
-		// 			break;
-		// 		}
-		// 		else if (format == RTF_D24)
-		// 		{
-		// 			GL_CHECK(glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, width, height));
-		// 			GL_CHECK(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_gl_rbo));
-		// 		}
-
-		// 		break;
-		// 	}
-		// 	default:
-		// 	{
-		// 		CE_ASSERT(false, "Oops, render target format not supported!");
-		// 		break;
-		// 	}
-		// }
-
-		// GLenum status = glCheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT);
-		// CE_ASSERT(status == GL_FRAMEBUFFER_COMPLETE_EXT, "Oops, framebuffer incomplete!");
-
-		// GL_CHECK(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
-
-		// m_width = width;
-		// m_height = height;
-		// m_format = format;
+		m_width = width;
+		m_height = height;
+		m_format = format;
+		m_col_texture = 0;
+		m_fbo = 0;
+		m_rbo = 0;
+
+		GL_CHECK(glGenFramebuffers(1, &m_fbo));
+		CE_ASSERT(m_fbo != 0, "Failed to create frame buffer");
+		GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_fbo));
+
+		const bool no_texture = (flags & RENDER_TARGET_NO_TEXTURE) >> RENDER_TARGET_SHIFT;
+		const TextureFormatInfo& tif = TEXTURE_FORMAT_TABLE[format];
+
+		const GLenum attachment = is_depth(format) ? GL_DEPTH_ATTACHMENT :
+									is_color(format) ? GL_COLOR_ATTACHMENT0 : GL_DEPTH_STENCIL_ATTACHMENT;
+
+		if (!no_texture)
+		{
+			GL_CHECK(glGenTextures(1, &m_col_texture));
+			CE_ASSERT(m_col_texture != 0, "Failed to create texture");
+			GL_CHECK(glBindTexture(GL_TEXTURE_2D, m_col_texture));
+			GL_CHECK(glTexImage2D(GL_TEXTURE_2D, 0, tif.internal_format, width, height, 0, tif.format, GL_UNSIGNED_BYTE, 0));
+
+			GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
+			GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
+	
+			GL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER,
+											attachment,
+											GL_TEXTURE_2D,
+											m_col_texture,
+											0));
+
+			GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
+		}
+		else
+		{
+			GL_CHECK(glGenRenderbuffers(1, &m_rbo));
+			CE_ASSERT(m_rbo != 0, "Failed to create renderbuffer");
+			GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, m_rbo));
+			GL_CHECK(glRenderbufferStorage(GL_RENDERBUFFER, tif.internal_format, width, height));
+			GL_CHECK(glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, m_rbo));
+			GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, 0));
+		}
+
+		GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+		CE_ASSERT(status == GL_FRAMEBUFFER_COMPLETE, "Oops, framebuffer incomplete!");
+		CE_UNUSED(status);
+
+		GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0));
 	}
 
 	void destroy()
 	{
-		// GL_CHECK(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
-		// GL_CHECK(glDeleteFramebuffersEXT(1, &m_gl_fbo));
-
-		// GL_CHECK(glDeleteRenderbuffersEXT(1, &m_gl_rbo));
+		GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0));
+		GL_CHECK(glDeleteTextures(1, &m_col_texture));
+		GL_CHECK(glDeleteFramebuffers(1, &m_fbo));
+		GL_CHECK(glDeleteRenderbuffers(1, &m_rbo));
 	}
 
 	uint16_t m_width;
 	uint16_t m_height;
-	RenderTargetFormat m_format;
-	GLuint m_gl_fbo;
-	GLuint m_gl_rbo;
+	PixelFormat::Enum m_format;
+	GLuint m_col_texture;
+	GLuint m_fbo;
+	GLuint m_rbo;
 };
 
 /// OpenGL renderer
@@ -703,13 +788,14 @@ class RendererImplementation
 public:
 
 	//-----------------------------------------------------------------------------
-	RendererImplementation()
-		: m_max_texture_size(0)
+	RendererImplementation(Renderer* renderer)
+		: m_renderer(renderer)
+		, m_max_texture_size(0)
 		, m_max_texture_units(0)
 		, m_max_vertex_indices(0)
 		, m_max_vertex_vertices(0)
 		, m_max_anisotropy(0.0f)
-		, m_num_uniforms(0)
+		, m_uniform_registry(default_allocator())
 	{
 		m_min_max_point_size[0] = 0.0f;
 		m_min_max_point_size[1] = 0.0f;
@@ -730,6 +816,7 @@ public:
 		#if defined(LINUX) || defined(WINDOWS)
 			GLenum err = glewInit();
 			CE_ASSERT(err == GLEW_OK, "Failed to initialize GLEW");
+			CE_UNUSED(err);
 		#endif
 
 		GL_CHECK(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_max_texture_size));
@@ -740,19 +827,19 @@ public:
 		GL_CHECK(glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, &m_min_max_point_size[0]));
 		// GL_CHECK(glGetFloatv(GL_LINE_WIDTH_RANGE, &m_min_max_line_width[0]));
 
-		Log::i("OpenGL Vendor        : %s", glGetString(GL_VENDOR));
-		Log::i("OpenGL Renderer      : %s", glGetString(GL_RENDERER));
-		Log::i("OpenGL Version       : %s", glGetString(GL_VERSION));
-		Log::i("GLSL Version         : %s", glGetString(GL_SHADING_LANGUAGE_VERSION));
+		CE_LOGI("OpenGL Vendor        : %s", glGetString(GL_VENDOR));
+		CE_LOGI("OpenGL Renderer      : %s", glGetString(GL_RENDERER));
+		CE_LOGI("OpenGL Version       : %s", glGetString(GL_VERSION));
+		CE_LOGI("GLSL Version         : %s", glGetString(GL_SHADING_LANGUAGE_VERSION));
 
-		Log::d("Min Point Size       : %f", m_min_max_point_size[0]);
-		Log::d("Max Point Size       : %f", m_min_max_point_size[1]);
-		Log::d("Min Line Width       : %f", m_min_max_line_width[0]);
-		Log::d("Max Line Width       : %f", m_min_max_line_width[1]);
-		Log::d("Max Texture Size     : %dx%d", m_max_texture_size, m_max_texture_size);
-		Log::d("Max Texture Units    : %d", m_max_texture_units);
-		Log::d("Max Vertex Indices   : %d", m_max_vertex_indices);
-		Log::d("Max Vertex Vertices  : %d", m_max_vertex_vertices);
+		CE_LOGD("Min Point Size       : %f", m_min_max_point_size[0]);
+		CE_LOGD("Max Point Size       : %f", m_min_max_point_size[1]);
+		CE_LOGD("Min Line Width       : %f", m_min_max_line_width[0]);
+		CE_LOGD("Max Line Width       : %f", m_min_max_line_width[1]);
+		CE_LOGD("Max Texture Size     : %dx%d", m_max_texture_size, m_max_texture_size);
+		CE_LOGD("Max Texture Units    : %d", m_max_texture_units);
+		CE_LOGD("Max Vertex Indices   : %d", m_max_vertex_indices);
+		CE_LOGD("Max Vertex Vertices  : %d", m_max_vertex_vertices);
 
 		#if defined(LINUX) || defined(WINDOWS)
 			// Point sprites enabled by default
@@ -760,7 +847,7 @@ public:
 			GL_CHECK(glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE));
 		#endif
 
-		Log::i("OpenGL Renderer initialized.");
+		CE_LOGI("OpenGL Renderer initialized.");
 	}
 
 	//-----------------------------------------------------------------------------
@@ -772,8 +859,9 @@ public:
 	//-----------------------------------------------------------------------------
 	void render(RenderContext& context)
 	{
-		//RenderTargetId old_rt;
-		//old_rt.id = INVALID_ID;
+		RenderTargetId cur_rt;
+		cur_rt.index = 0xFFFF;
+		cur_rt.id = INVALID_ID;
 		uint8_t layer = 0xFF;
 
 		// Sort render keys
@@ -789,13 +877,16 @@ public:
 			m_index_buffers[context.m_transient_ib->ib.index].update(0, context.m_tib_offset, context.m_transient_ib->data);
 		}
 
+		// Bind default framebuffer
+		GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0));
+
 		for (uint32_t s = 0; s < context.m_num_states; s++)
 		{
-			const uint64_t key_s = context.m_keys[s];
+			const uint64_t key_s = context.m_keys[s].key;
 			RenderKey key;
 			key.decode(key_s);
 
-			const RenderState& cur_state = context.m_states[s];
+			const RenderState& cur_state = context.m_states[context.m_keys[s].state];
 			const uint64_t flags = cur_state.m_flags;
 			//const RenderTargetId& cur_rt = context.m_targets[layer];
 
@@ -804,6 +895,13 @@ public:
 			{
 				layer = key.m_layer;
 
+				// Switch render target if necessary
+				if (cur_rt != context.m_targets[layer])
+				{
+					cur_rt = context.m_targets[layer];
+					glBindFramebuffer(GL_FRAMEBUFFER, m_render_targets[cur_rt.index].m_fbo);
+				}
+
 				// Viewport
 				const ViewRect& viewport = context.m_viewports[layer];
 				GL_CHECK(glViewport(viewport.m_x, viewport.m_y, viewport.m_width, viewport.m_height));
@@ -913,6 +1011,13 @@ public:
 								texture.commit(unit, sampler.flags);
 								break;
 							}
+							case SAMPLER_RENDER_TARGET:
+							{
+								RenderTarget& rt = m_render_targets[sampler.sampler_id.index];
+								GL_CHECK(glActiveTexture(GL_TEXTURE0 + unit));
+								GL_CHECK(glBindTexture(GL_TEXTURE_2D, rt.m_col_texture));
+								break;
+							}
 							default:
 							{
 								CE_ASSERT(false, "Oops, sampler unknown");
@@ -925,6 +1030,8 @@ public:
 				}
 			}
 
+			m_renderer->update_uniforms(context.m_constants, cur_state.begin_uniform, cur_state.end_uniform);
+
 			// Bind GPU program
 			if (cur_state.program.id != INVALID_ID)
 			{
@@ -943,24 +1050,22 @@ public:
 					{
 						case ShaderUniform::VIEW:
 						{
-							GL_CHECK(glUniformMatrix4fv(uniform_location, 1, GL_FALSE, view.to_float_ptr()));
+							GL_CHECK(glUniformMatrix4fv(uniform_location, 1, GL_FALSE, matrix4x4::to_float_ptr(view)));
 							break;
 						}
 						case ShaderUniform::MODEL:
 						{
-							GL_CHECK(glUniformMatrix4fv(uniform_location, 1, GL_FALSE, cur_state.pose.to_float_ptr()));
+							GL_CHECK(glUniformMatrix4fv(uniform_location, 1, GL_FALSE, matrix4x4::to_float_ptr(cur_state.pose)));
 							break;
 						}
 						case ShaderUniform::MODEL_VIEW:
 						{
-							GL_CHECK(glUniformMatrix4fv(uniform_location, 1, GL_FALSE, (view *
-															cur_state.pose).to_float_ptr()));
+							GL_CHECK(glUniformMatrix4fv(uniform_location, 1, GL_FALSE, matrix4x4::to_float_ptr(view * cur_state.pose)));
 							break;
 						}
 						case ShaderUniform::MODEL_VIEW_PROJECTION:
 						{
-							GL_CHECK(glUniformMatrix4fv(uniform_location, 1, GL_FALSE, (projection * view *
-															cur_state.pose).to_float_ptr()));
+							GL_CHECK(glUniformMatrix4fv(uniform_location, 1, GL_FALSE, matrix4x4::to_float_ptr(projection * view * cur_state.pose)));
 							break;
 						}
 						case ShaderUniform::TIME_SINCE_START:
@@ -1020,6 +1125,7 @@ public:
 
 private:
 
+	Renderer*			m_renderer;
 	GLContext			m_gl_context;
 
 	// Limits
@@ -1037,8 +1143,8 @@ private:
 	Texture				m_textures[CE_MAX_TEXTURES];
 	Shader				m_shaders[CE_MAX_SHADERS];
 	GPUProgram			m_gpu_programs[CE_MAX_GPU_PROGRAMS];
-	uint32_t			m_num_uniforms;
-	Uniform				m_uniforms[CE_MAX_UNIFORMS];
+	Hash<void*>			m_uniform_registry;
+	void*				m_uniforms[CE_MAX_UNIFORMS];
 	RenderTarget		m_render_targets[CE_MAX_RENDER_TARGETS];
 
 private:
@@ -1051,19 +1157,18 @@ Renderer::Renderer(Allocator& a)
 	: m_allocator(a), m_impl(NULL), m_thread("render-thread"), m_submit(&m_contexts[0]), m_draw(&m_contexts[1]),
 		m_is_initialized(false), m_should_run(false)
 {
-	m_impl = CE_NEW(a, RendererImplementation);
+	m_impl = CE_NEW(a, RendererImplementation)(this);
 }
 
 //-----------------------------------------------------------------------------
 Renderer::~Renderer()
 {
-	CE_ASSERT(m_vertex_buffers.size() == 0, "%d vertex buffers not freed", m_vertex_buffers.size());
-	CE_ASSERT(m_index_buffers.size() == 0, "%d index buffers not freed", m_index_buffers.size());
-	CE_ASSERT(m_textures.size() == 0, "%d textures not freed", m_textures.size());
-	CE_ASSERT(m_shaders.size() == 0, "%d shaders not freed", m_shaders.size());
-	CE_ASSERT(m_gpu_programs.size() == 0, "%d GPU programs not freed", m_gpu_programs.size());
-	CE_ASSERT(m_uniforms.size() == 0, "%d uniforms not freed", m_uniforms.size());
-	CE_ASSERT(m_render_targets.size() == 0, "%d render targets not freed", m_render_targets.size());
+	CE_ASSERT(id_table::size(m_vertex_buffers) == 0, "%d vertex buffers not freed", id_table::size(m_vertex_buffers));
+	CE_ASSERT(id_table::size(m_index_buffers) == 0, "%d index buffers not freed", id_table::size(m_index_buffers));
+	CE_ASSERT(id_table::size(m_textures) == 0, "%d textures not freed", id_table::size(m_textures));
+	CE_ASSERT(id_table::size(m_shaders) == 0, "%d shaders not freed", id_table::size(m_shaders));
+	CE_ASSERT(id_table::size(m_gpu_programs) == 0, "%d GPU programs not freed", id_table::size(m_gpu_programs));
+	CE_ASSERT(id_table::size(m_render_targets) == 0, "%d render targets not freed", id_table::size(m_render_targets));
 
 	CE_DELETE(m_allocator, m_impl);
 }
@@ -1110,7 +1215,7 @@ void Renderer::update_vertex_buffer_impl(VertexBufferId id, size_t offset, size_
 void Renderer::destroy_vertex_buffer_impl(VertexBufferId id)
 {
 	m_impl->m_vertex_buffers[id.index].destroy();
-	m_vertex_buffers.destroy(id);
+	id_table::destroy(m_vertex_buffers, id);
 }
 
 //-----------------------------------------------------------------------------
@@ -1135,7 +1240,7 @@ void Renderer::update_index_buffer_impl(IndexBufferId id, size_t offset, size_t
 void Renderer::destroy_index_buffer_impl(IndexBufferId id)
 {
 	m_impl->m_index_buffers[id.index].destroy();
-	m_index_buffers.destroy(id);
+	id_table::destroy(m_index_buffers, id);
 }
 
 //-----------------------------------------------------------------------------
@@ -1154,7 +1259,7 @@ void Renderer::update_texture_impl(TextureId id, uint32_t x, uint32_t y, uint32_
 void Renderer::destroy_texture_impl(TextureId id)
 {
 	m_impl->m_textures[id.index].destroy();
-	m_textures.destroy(id);
+	id_table::destroy(m_textures, id);
 }
 
 //-----------------------------------------------------------------------------
@@ -1167,7 +1272,7 @@ void Renderer::create_shader_impl(ShaderId id, ShaderType::Enum type, const char
 void Renderer::destroy_shader_impl(ShaderId id)
 {
 	m_impl->m_shaders[id.index].destroy();
-	m_shaders.destroy(id);
+	id_table::destroy(m_shaders, id);
 }
 
 //-----------------------------------------------------------------------------
@@ -1175,47 +1280,49 @@ void Renderer::create_gpu_program_impl(GPUProgramId id, ShaderId vertex, ShaderI
 {
 	Shader& vs = m_impl->m_shaders[vertex.index];
 	Shader& ps = m_impl->m_shaders[pixel.index];
-	m_impl->m_gpu_programs[id.index].create(vs, ps, m_impl->m_num_uniforms, m_impl->m_uniforms);
+	m_impl->m_gpu_programs[id.index].create(vs, ps, m_impl->m_uniform_registry);
 }
 
 //-----------------------------------------------------------------------------
 void Renderer::destroy_gpu_program_impl(GPUProgramId id)
 {
 	m_impl->m_gpu_programs[id.index].destroy();
-	m_gpu_programs.destroy(id);
+	id_table::destroy(m_gpu_programs, id);
 }
 
 //-----------------------------------------------------------------------------
 void Renderer::create_uniform_impl(UniformId id, const char* name, UniformType::Enum type, uint8_t num)
 {
-	m_impl->m_uniforms[id.index].create(name, type, num);
-	m_impl->m_num_uniforms++;
+	const size_t size = UNIFORM_SIZE_TABLE[type] * num;
+	m_impl->m_uniforms[id.index] = default_allocator().allocate(size);
+	hash::set(m_impl->m_uniform_registry, string::murmur2_64(name, string::strlen(name)), m_impl->m_uniforms[id.index]);
+	memset(m_impl->m_uniforms[id.index], 0, size);
 }
 
 //-----------------------------------------------------------------------------
 void Renderer::update_uniform_impl(UniformId id, size_t size, const void* data)
 {
-	m_impl->m_uniforms[id.index].update(size, data);
+	memcpy(m_impl->m_uniforms[id.index], data, size);
 }
 
 //-----------------------------------------------------------------------------
 void Renderer::destroy_uniform_impl(UniformId id)
 {
-	m_impl->m_uniforms[id.index].destroy();
-	m_uniforms.destroy(id);
-	m_impl->m_num_uniforms--;
+	default_allocator().deallocate(m_impl->m_uniforms[id.index]);
+	id_table::destroy(m_uniforms, id);
 }
 
-// //-----------------------------------------------------------------------------
-// void Renderer::create_render_target_impl(RenderTargetId id, uint16_t width, uint16_t height, RenderTargetFormat::Enum format)
-// {
-
-// }
-
-// //-----------------------------------------------------------------------------
-// void Renderer::destroy_render_target_impl(RenderTargetId id)
-// {
+//-----------------------------------------------------------------------------
+void Renderer::create_render_target_impl(RenderTargetId id, uint16_t width, uint16_t height, PixelFormat::Enum format, uint32_t flags)
+{
+	m_impl->m_render_targets[id.index].create(width, height, format, flags);
+}
 
-// }
+//-----------------------------------------------------------------------------
+void Renderer::destroy_render_target_impl(RenderTargetId id)
+{
+	m_impl->m_render_targets[id.index].destroy();
+	id_table::destroy(m_render_targets, id);
+}
 
 } // namespace crown

+ 26 - 24
engine/renderers/backend/gl/egl/GLContext.cpp

@@ -37,30 +37,29 @@ namespace crown
 extern ANativeWindow* g_android_window;
 
 //-----------------------------------------------------------------------------
-static const char* egl_error_to_string(EGLint error)
-{
-	switch (error)
+#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
+	static const char* egl_error_to_string(EGLint error)
 	{
-		case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
-		case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
-		case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
-		case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
-		case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
-		case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
-		case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
-		case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
-		case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
-		case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
-		case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
-		case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
-		case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
-		case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
-		default: return "UNKNOWN_EGL_ERROR";
+		switch (error)
+		{
+			case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
+			case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
+			case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
+			case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
+			case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
+			case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
+			case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
+			case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
+			case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
+			case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
+			case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
+			case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
+			case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
+			case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
+			default: return "UNKNOWN_EGL_ERROR";
+		}
 	}
-}
 
-//-----------------------------------------------------------------------------
-#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
 	#define EGL_CHECK(function)\
 		function;\
 		do { EGLint error; CE_ASSERT((error = eglGetError()) == EGL_SUCCESS,\
@@ -95,14 +94,17 @@ void GLContext::create_context()
 	EGLint egl_major, egl_minor;
 	EGLBoolean init_success = EGL_CHECK(eglInitialize(display, &egl_major, &egl_minor));
 	CE_ASSERT(init_success == EGL_TRUE, "Failed to initialize EGL");
+	CE_UNUSED(init_success);
 
-	Log::d("EGL Initialized: major = %d, minor = %d", egl_major, egl_minor);
+	CE_LOGD("EGL Initialized: major = %d, minor = %d", egl_major, egl_minor);
 
 	EGLBoolean bind_success = EGL_CHECK(eglBindAPI(EGL_OPENGL_ES_API));
 	CE_ASSERT(bind_success != EGL_FALSE, "Failed to bind OpenGL|ES API");
+	CE_UNUSED(bind_success);
 
 	EGLBoolean cfg_success = EGL_CHECK(eglChooseConfig(display, attrib_list, &config, 1, &num_configs));
 	CE_ASSERT(cfg_success == EGL_TRUE, "Failed to choose EGL configuration");
+	CE_UNUSED(cfg_success);
 
 	EGLint format;
 	EGL_CHECK(eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format));
@@ -117,7 +119,7 @@ void GLContext::create_context()
 
 	EGL_CHECK(eglMakeCurrent(display, surface, surface, context));
 
-	Log::d("EGL context created");
+	CE_LOGD("EGL context created");
 }
 
 //-----------------------------------------------------------------------------
@@ -129,7 +131,7 @@ void GLContext::destroy_context()
 	EGL_CHECK(eglTerminate(display));
     display = EGL_NO_DISPLAY;
 
-	Log::i("EGL context destroyed");
+	CE_LOGI("EGL context destroyed");
 }
 
 //-----------------------------------------------------------------------------

+ 5 - 5
engine/resource/FontResource.cpp

@@ -93,10 +93,7 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 		array::push_back(m_glyphs, data);
 	}
 
-	fs.close(file);
-	default_allocator().deallocate(buf);
-
-	h.material.id = string::murmur2_64(material_name.c_str(), string::strlen(material_name.c_str()), 0);
+	h.material = ResourceId(material_name.c_str());
 	h.num_glyphs = array::size(m_glyphs);
 	h.texture_size = size.to_int();
 	h.font_size = font_size.to_int();
@@ -107,7 +104,10 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 	{
 		out_file->write((char*) array::begin(m_glyphs), sizeof(FontGlyphData) * h.num_glyphs);
 	}
+
+	fs.close(file);
+	default_allocator().deallocate(buf);
 }
 
 } // namespace font_resource
-} // namespace crown
+} // namespace crown

+ 92 - 0
engine/resource/LevelResource.cpp

@@ -0,0 +1,92 @@
+/*
+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 "LevelResource.h"
+#include "Array.h"
+#include "Memory.h"
+#include "JSONParser.h"
+#include "Filesystem.h"
+
+namespace crown
+{
+namespace level_resource
+{
+
+void parse_units(JSONElement root, Array<LevelUnit>& units)
+{
+	JSONElement units_arr = root.key("units");
+	const uint32_t size = units_arr.size();
+
+	for (uint32_t i = 0; i < size; i++)
+	{
+		JSONElement e = units_arr[i];
+
+		LevelUnit lu;
+
+		DynamicString name;
+		e.key("name").to_string(name);
+		name += ".unit";
+
+		lu.name = ResourceId(name.c_str());
+		lu.position = e.key("position").to_vector3();
+		lu.rotation = e.key("rotation").to_quaternion();
+
+		array::push_back(units, lu);
+	}
+}
+
+//-----------------------------------------------------------------------------
+void compile(Filesystem& fs, const char* resource_path, File* out_file)
+{
+	File* file = fs.open(resource_path, FOM_READ);
+	char* buf = (char*)default_allocator().allocate(file->size());
+	file->read(buf, file->size());
+
+	JSONParser json(buf);
+	JSONElement root = json.root();
+
+	Array<LevelUnit> units(default_allocator());
+
+	parse_units(root, units);
+
+	fs.close(file);
+	default_allocator().deallocate(buf);
+
+	LevelHeader lh;
+	lh.num_units = array::size(units);
+	uint32_t offt = sizeof(LevelHeader);
+	lh.units_offset = offt;
+
+	out_file->write((char*) &lh, sizeof(LevelHeader));
+
+	if (lh.num_units)
+	{
+		out_file->write((char*) array::begin(units), sizeof(LevelUnit) * lh.num_units);
+	}
+}
+
+} // namespace level_resource
+} // namespace crown

+ 59 - 26
engine/os/android/java/CrownSurfaceView.java → engine/resource/LevelResource.h

@@ -24,48 +24,81 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
 */
 
-package crown.android;
+#pragma once
 
-import android.content.Context;
-import android.view.Surface;
-import android.view.SurfaceView;
-import android.view.SurfaceHolder;
-import android.graphics.PixelFormat;
-import android.util.Log;
+#include "Allocator.h"
+#include "Assert.h"
+#include "Bundle.h"
+#include "File.h"
+#include "Resource.h"
+#include "Types.h"
+#include "Vector3.h"
+#include "Quaternion.h"
 
-public class CrownSurfaceView extends SurfaceView implements SurfaceHolder.Callback
+namespace crown
 {
-	private final String TAG = "crown";
+
+struct LevelHeader
+{
+	uint32_t num_units;
+	uint32_t units_offset;
+};
+
+struct LevelUnit
+{
+	ResourceId name;
+	Vector3 position;
+	Quaternion rotation;
+};
+
+struct LevelResource
+{
+	//-----------------------------------------------------------------------------
+	static void* load(Allocator& allocator, Bundle& bundle, ResourceId id)
+	{
+		File* file = bundle.open(id);
+		const size_t file_size = file->size();
+
+		void* res = allocator.allocate(file_size);
+		file->read(res, file_size);
+
+		bundle.close(file);
+
+		return res;
+	}
 
 	//-----------------------------------------------------------------------------
-	public CrownSurfaceView(Context context)
+	static void online(void* /*resource*/)
 	{
-		super(context);
-		getHolder().addCallback(this);
-		setFocusable(true);
 	}
 
 	//-----------------------------------------------------------------------------
-	@Override
-	public void surfaceCreated(SurfaceHolder holder) 
+	static void unload(Allocator& allocator, void* resource)
 	{
-		Log.d(TAG, "Crown Surface created");
-		CrownLib.acquireWindow(holder.getSurface());
-		CrownLib.run();
+		CE_ASSERT_NOT_NULL(resource);
+		allocator.deallocate(resource);
 	}
 
 	//-----------------------------------------------------------------------------
-	@Override
-	public void surfaceDestroyed(SurfaceHolder holder) 
+	static void offline(void* /*resource*/)
 	{
-		Log.d(TAG, "Crown Surface destroyed");
 	}
 
 	//-----------------------------------------------------------------------------
-	@Override
-	public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) 
+	uint32_t num_units() const
 	{
-		CrownLib.pushMetricsEvent(0, 0, width, height);
-		Log.d(TAG, "Crown Surface changed");
+		return ((LevelHeader*) this)->num_units;
 	}
-}
+
+	//-----------------------------------------------------------------------------
+	const LevelUnit* get_unit(uint32_t i) const
+	{
+		CE_ASSERT(i < num_units(), "Index out of bounds");
+
+		const LevelHeader* h = (LevelHeader*) this;
+		const LevelUnit* begin = (LevelUnit*) (((char*) this) + h->units_offset);
+		return &begin[i];
+	}
+};
+
+} // namespace crown

+ 1 - 1
engine/resource/LuaResource.cpp

@@ -84,7 +84,7 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 	}
 	else
 	{
-		Log::e("Error while reading luajit bytecode");
+		CE_LOGE("Error while reading luajit bytecode");
 		return;
 	}
 

Некоторые файлы не были показаны из-за большого количества измененных файлов