Browse Source

Merge pull request #50 from godlikepanos/console

Developer console
Panagiotis Christopoulos Charitos 6 years ago
parent
commit
1182872802

BIN
engine_data/UbuntuMonoRegular.ttf


+ 97 - 80
samples/common/Framework.cpp

@@ -56,111 +56,128 @@ Error SampleApp::userMainLoop(Bool& quit)
 		return Error::NONE;
 		return Error::NONE;
 	}
 	}
 
 
-	// move the camera
-	static MoveComponent* mover = &scene.getActiveCameraNode().getComponent<MoveComponent>();
-
-	if(in.getKey(KeyCode::_1) == 1)
+	if(in.getKey(KeyCode::BACKQUOTE) == 1)
 	{
 	{
-		mover = &scene.getActiveCameraNode().getComponent<MoveComponent>();
+		setDisplayDeveloperConsole(!getDisplayDeveloperConsole());
 	}
 	}
 
 
-	if(in.getKey(KeyCode::F1) == 1)
+	if(!getDisplayDeveloperConsole())
 	{
 	{
-		static U mode = 0;
-		mode = (mode + 1) % 3;
-		if(mode == 0)
+		in.hideCursor(true);
+		in.lockCursor(true);
+
+		// move the camera
+		static MoveComponent* mover = &scene.getActiveCameraNode().getComponent<MoveComponent>();
+
+		if(in.getKey(KeyCode::_1) == 1)
 		{
 		{
-			renderer.getDbg().setEnabled(false);
+			mover = &scene.getActiveCameraNode().getComponent<MoveComponent>();
 		}
 		}
-		else if(mode == 1)
+
+		if(in.getKey(KeyCode::F1) == 1)
 		{
 		{
-			renderer.getDbg().setEnabled(true);
-			renderer.getDbg().setDepthTestEnabled(true);
-			renderer.getDbg().setDitheredDepthTestEnabled(false);
+			static U mode = 0;
+			mode = (mode + 1) % 3;
+			if(mode == 0)
+			{
+				renderer.getDbg().setEnabled(false);
+			}
+			else if(mode == 1)
+			{
+				renderer.getDbg().setEnabled(true);
+				renderer.getDbg().setDepthTestEnabled(true);
+				renderer.getDbg().setDitheredDepthTestEnabled(false);
+			}
+			else
+			{
+				renderer.getDbg().setEnabled(true);
+				renderer.getDbg().setDepthTestEnabled(false);
+				renderer.getDbg().setDitheredDepthTestEnabled(true);
+			}
 		}
 		}
-		else
+		if(in.getKey(KeyCode::F2) == 1)
 		{
 		{
-			renderer.getDbg().setEnabled(true);
-			renderer.getDbg().setDepthTestEnabled(false);
-			renderer.getDbg().setDitheredDepthTestEnabled(true);
+			// renderer.getDbg().flipFlags(DbgFlag::SPATIAL_COMPONENT);
 		}
 		}
-	}
-	if(in.getKey(KeyCode::F2) == 1)
-	{
-		// renderer.getDbg().flipFlags(DbgFlag::SPATIAL_COMPONENT);
-	}
 
 
-	if(in.getKey(KeyCode::UP))
-	{
-		mover->rotateLocalX(ROTATE_ANGLE);
-	}
+		if(in.getKey(KeyCode::UP))
+		{
+			mover->rotateLocalX(ROTATE_ANGLE);
+		}
 
 
-	if(in.getKey(KeyCode::DOWN))
-	{
-		mover->rotateLocalX(-ROTATE_ANGLE);
-	}
+		if(in.getKey(KeyCode::DOWN))
+		{
+			mover->rotateLocalX(-ROTATE_ANGLE);
+		}
 
 
-	if(in.getKey(KeyCode::LEFT))
-	{
-		mover->rotateLocalY(ROTATE_ANGLE);
-	}
+		if(in.getKey(KeyCode::LEFT))
+		{
+			mover->rotateLocalY(ROTATE_ANGLE);
+		}
 
 
-	if(in.getKey(KeyCode::RIGHT))
-	{
-		mover->rotateLocalY(-ROTATE_ANGLE);
-	}
+		if(in.getKey(KeyCode::RIGHT))
+		{
+			mover->rotateLocalY(-ROTATE_ANGLE);
+		}
 
 
-	if(in.getKey(KeyCode::A))
-	{
-		mover->moveLocalX(-MOVE_DISTANCE);
-	}
+		if(in.getKey(KeyCode::A))
+		{
+			mover->moveLocalX(-MOVE_DISTANCE);
+		}
 
 
-	if(in.getKey(KeyCode::D))
-	{
-		mover->moveLocalX(MOVE_DISTANCE);
-	}
+		if(in.getKey(KeyCode::D))
+		{
+			mover->moveLocalX(MOVE_DISTANCE);
+		}
 
 
-	if(in.getKey(KeyCode::C))
-	{
-		mover->moveLocalY(-MOVE_DISTANCE);
-	}
+		if(in.getKey(KeyCode::C))
+		{
+			mover->moveLocalY(-MOVE_DISTANCE);
+		}
 
 
-	if(in.getKey(KeyCode::SPACE))
-	{
-		mover->moveLocalY(MOVE_DISTANCE);
-	}
+		if(in.getKey(KeyCode::SPACE))
+		{
+			mover->moveLocalY(MOVE_DISTANCE);
+		}
 
 
-	if(in.getKey(KeyCode::W))
-	{
-		mover->moveLocalZ(-MOVE_DISTANCE);
-	}
+		if(in.getKey(KeyCode::W))
+		{
+			mover->moveLocalZ(-MOVE_DISTANCE);
+		}
 
 
-	if(in.getKey(KeyCode::S))
-	{
-		mover->moveLocalZ(MOVE_DISTANCE);
-	}
+		if(in.getKey(KeyCode::S))
+		{
+			mover->moveLocalZ(MOVE_DISTANCE);
+		}
 
 
-	if(in.getKey(KeyCode::Q))
-	{
-		mover->rotateLocalZ(ROTATE_ANGLE);
-	}
+		if(in.getKey(KeyCode::Q))
+		{
+			mover->rotateLocalZ(ROTATE_ANGLE);
+		}
 
 
-	if(in.getKey(KeyCode::E))
-	{
-		mover->rotateLocalZ(-ROTATE_ANGLE);
-	}
+		if(in.getKey(KeyCode::E))
+		{
+			mover->rotateLocalZ(-ROTATE_ANGLE);
+		}
 
 
-	if(in.getKey(KeyCode::F12) == 1)
-	{
-		CoreTracerSingleton::get().m_enabled = !CoreTracerSingleton::get().m_enabled;
-	}
+		if(in.getKey(KeyCode::F12) == 1)
+		{
+			CoreTracerSingleton::get().m_enabled = !CoreTracerSingleton::get().m_enabled;
+		}
 
 
-	if(in.getMousePosition() != Vec2(0.0))
-	{
-		F32 angY = -ROTATE_ANGLE * in.getMousePosition().x() * MOUSE_SENSITIVITY * getMainRenderer().getAspectRatio();
+		if(in.getMousePosition() != Vec2(0.0))
+		{
+			F32 angY =
+				-ROTATE_ANGLE * in.getMousePosition().x() * MOUSE_SENSITIVITY * getMainRenderer().getAspectRatio();
 
 
-		mover->rotateLocalY(angY);
-		mover->rotateLocalX(ROTATE_ANGLE * in.getMousePosition().y() * MOUSE_SENSITIVITY);
+			mover->rotateLocalY(angY);
+			mover->rotateLocalX(ROTATE_ANGLE * in.getMousePosition().y() * MOUSE_SENSITIVITY);
+		}
+	}
+	else
+	{
+		in.hideCursor(false);
+		in.lockCursor(false);
 	}
 	}
 
 
 	return Error::NONE;
 	return Error::NONE;

+ 33 - 12
src/anki/core/App.cpp

@@ -11,7 +11,7 @@
 #include <anki/util/System.h>
 #include <anki/util/System.h>
 #include <anki/util/ThreadHive.h>
 #include <anki/util/ThreadHive.h>
 #include <anki/core/Trace.h>
 #include <anki/core/Trace.h>
-
+#include <anki/core/DeveloperConsole.h>
 #include <anki/core/NativeWindow.h>
 #include <anki/core/NativeWindow.h>
 #include <anki/input/Input.h>
 #include <anki/input/Input.h>
 #include <anki/scene/SceneGraph.h>
 #include <anki/scene/SceneGraph.h>
@@ -95,7 +95,7 @@ public:
 	{
 	{
 	}
 	}
 
 
-	void build(CanvasPtr canvas)
+	void build(CanvasPtr canvas) override
 	{
 	{
 		// Misc
 		// Misc
 		++m_bufferedFrames;
 		++m_bufferedFrames;
@@ -267,10 +267,12 @@ App::~App()
 
 
 void App::cleanup()
 void App::cleanup()
 {
 {
+	m_statsUi.reset(nullptr);
+	m_console.reset(nullptr);
+
 	m_heapAlloc.deleteInstance(m_scene);
 	m_heapAlloc.deleteInstance(m_scene);
 	m_heapAlloc.deleteInstance(m_script);
 	m_heapAlloc.deleteInstance(m_script);
 	m_heapAlloc.deleteInstance(m_renderer);
 	m_heapAlloc.deleteInstance(m_renderer);
-	m_statsUi.reset(nullptr);
 	m_heapAlloc.deleteInstance(m_ui);
 	m_heapAlloc.deleteInstance(m_ui);
 	m_heapAlloc.deleteInstance(m_resources);
 	m_heapAlloc.deleteInstance(m_resources);
 	m_heapAlloc.deleteInstance(m_resourceFs);
 	m_heapAlloc.deleteInstance(m_resourceFs);
@@ -446,8 +448,6 @@ Error App::initInternal(const ConfigSet& config_, AllocAlignedCallback allocCb,
 	m_ui = m_heapAlloc.newInstance<UiManager>();
 	m_ui = m_heapAlloc.newInstance<UiManager>();
 	ANKI_CHECK(m_ui->init(m_allocCb, m_allocCbData, m_resources, m_gr, m_stagingMem, m_input));
 	ANKI_CHECK(m_ui->init(m_allocCb, m_allocCbData, m_resources, m_gr, m_stagingMem, m_input));
 
 
-	ANKI_CHECK(m_ui->newInstance<StatsUi>(m_statsUi));
-
 	//
 	//
 	// Renderer
 	// Renderer
 	//
 	//
@@ -480,6 +480,12 @@ Error App::initInternal(const ConfigSet& config_, AllocAlignedCallback allocCb,
 	m_script->setRenderer(m_renderer);
 	m_script->setRenderer(m_renderer);
 	m_script->setSceneGraph(m_scene);
 	m_script->setSceneGraph(m_scene);
 
 
+	//
+	// Misc
+	//
+	ANKI_CHECK(m_ui->newInstance<StatsUi>(m_statsUi));
+	ANKI_CHECK(m_ui->newInstance<DeveloperConsole>(m_console, m_allocCb, m_allocCbData, m_script));
+
 	ANKI_CORE_LOGI("Application initialized");
 	ANKI_CORE_LOGI("Application initialized");
 
 
 	return Error::NONE;
 	return Error::NONE;
@@ -578,7 +584,7 @@ Error App::mainLoop()
 
 
 		// Inject stats UI
 		// Inject stats UI
 		DynamicArrayAuto<UiQueueElement> newUiElementArr(m_heapAlloc);
 		DynamicArrayAuto<UiQueueElement> newUiElementArr(m_heapAlloc);
-		injectStatsUiElement(newUiElementArr, rqueue);
+		injectUiElements(newUiElementArr, rqueue);
 
 
 		// Render
 		// Render
 		TexturePtr presentableTex = m_gr->acquireNextPresentableTexture();
 		TexturePtr presentableTex = m_gr->acquireNextPresentableTexture();
@@ -639,24 +645,39 @@ Error App::mainLoop()
 	return Error::NONE;
 	return Error::NONE;
 }
 }
 
 
-void App::injectStatsUiElement(DynamicArrayAuto<UiQueueElement>& newUiElementArr, RenderQueue& rqueue)
+void App::injectUiElements(DynamicArrayAuto<UiQueueElement>& newUiElementArr, RenderQueue& rqueue)
 {
 {
-	if(m_displayStats)
+	const U originalCount = rqueue.m_uis.getSize();
+	if(m_displayStats || m_consoleEnabled)
 	{
 	{
-		U count = rqueue.m_uis.getSize();
-		newUiElementArr.create(count + 1u);
+		const U extraElements = (m_displayStats != 0) + (m_consoleEnabled != 0);
+		newUiElementArr.create(originalCount + extraElements);
 
 
-		if(count)
+		if(originalCount > 0)
 		{
 		{
 			memcpy(&newUiElementArr[0], &rqueue.m_uis[0], rqueue.m_uis.getSizeInBytes());
 			memcpy(&newUiElementArr[0], &rqueue.m_uis[0], rqueue.m_uis.getSizeInBytes());
 		}
 		}
 
 
+		rqueue.m_uis = WeakArray<UiQueueElement>(newUiElementArr);
+	}
+
+	U count = originalCount;
+	if(m_displayStats)
+	{
 		newUiElementArr[count].m_userData = m_statsUi.get();
 		newUiElementArr[count].m_userData = m_statsUi.get();
 		newUiElementArr[count].m_drawCallback = [](CanvasPtr& canvas, void* userData) -> void {
 		newUiElementArr[count].m_drawCallback = [](CanvasPtr& canvas, void* userData) -> void {
 			static_cast<StatsUi*>(userData)->build(canvas);
 			static_cast<StatsUi*>(userData)->build(canvas);
 		};
 		};
+		++count;
+	}
 
 
-		rqueue.m_uis = WeakArray<UiQueueElement>(newUiElementArr);
+	if(m_consoleEnabled)
+	{
+		newUiElementArr[count].m_userData = m_console.get();
+		newUiElementArr[count].m_drawCallback = [](CanvasPtr& canvas, void* userData) -> void {
+			static_cast<DeveloperConsole*>(userData)->build(canvas);
+		};
+		++count;
 	}
 	}
 }
 }
 
 

+ 14 - 2
src/anki/core/App.h

@@ -147,6 +147,16 @@ public:
 		return m_displayStats;
 		return m_displayStats;
 	}
 	}
 
 
+	void setDisplayDeveloperConsole(Bool display)
+	{
+		m_consoleEnabled = display;
+	}
+
+	Bool getDisplayDeveloperConsole() const
+	{
+		return m_consoleEnabled;
+	}
+
 private:
 private:
 	class StatsUi;
 	class StatsUi;
 
 
@@ -171,6 +181,8 @@ private:
 	// Misc
 	// Misc
 	UiImmediateModeBuilderPtr m_statsUi;
 	UiImmediateModeBuilderPtr m_statsUi;
 	Bool m_displayStats = false;
 	Bool m_displayStats = false;
+	UiImmediateModeBuilderPtr m_console;
+	Bool m_consoleEnabled = false;
 	Timestamp m_globalTimestamp = 1;
 	Timestamp m_globalTimestamp = 1;
 	ThreadHive* m_threadHive = nullptr;
 	ThreadHive* m_threadHive = nullptr;
 	String m_settingsDir; ///< The path that holds the configuration
 	String m_settingsDir; ///< The path that holds the configuration
@@ -198,8 +210,8 @@ private:
 	ANKI_USE_RESULT Error initDirs(const ConfigSet& cfg);
 	ANKI_USE_RESULT Error initDirs(const ConfigSet& cfg);
 	void cleanup();
 	void cleanup();
 
 
-	/// Inject a new UI element in the render queue for displaying stats.
-	void injectStatsUiElement(DynamicArrayAuto<UiQueueElement>& elements, RenderQueue& rqueue);
+	/// Inject a new UI element in the render queue for displaying various stuff.
+	void injectUiElements(DynamicArrayAuto<UiQueueElement>& elements, RenderQueue& rqueue);
 };
 };
 
 
 } // end namespace anki
 } // end namespace anki

+ 1 - 1
src/anki/core/CMakeLists.txt

@@ -1,4 +1,4 @@
-set(SOURCES App.cpp Config.cpp StagingGpuMemoryManager.cpp)
+set(SOURCES App.cpp Config.cpp StagingGpuMemoryManager.cpp DeveloperConsole.cpp)
 
 
 if(SDL)
 if(SDL)
 	set(SOURCES ${SOURCES} NativeWindowSdl.cpp)
 	set(SOURCES ${SOURCES} NativeWindowSdl.cpp)

+ 158 - 0
src/anki/core/DeveloperConsole.cpp

@@ -0,0 +1,158 @@
+// Copyright (C) 2009-2019, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <anki/core/DeveloperConsole.h>
+
+namespace anki
+{
+
+DeveloperConsole::~DeveloperConsole()
+{
+	LoggerSingleton::get().removeMessageHandler(this, loggerCallback);
+
+	while(!m_logItems.isEmpty())
+	{
+		LogItem* item = &m_logItems.getFront();
+		m_logItems.popFront();
+		item->m_msg.destroy(m_alloc);
+		m_alloc.deleteInstance(item);
+	}
+}
+
+Error DeveloperConsole::init(AllocAlignedCallback allocCb, void* allocCbUserData, ScriptManager* scriptManager)
+{
+	m_alloc = HeapAllocator<U8>(allocCb, allocCbUserData);
+	zeroMemory(m_inputText);
+
+	ANKI_CHECK(m_manager->newInstance(m_font, "engine_data/UbuntuMonoRegular.ttf", std::initializer_list<U32>{16}));
+
+	// Add a new callback to the logger
+	LoggerSingleton::get().addMessageHandler(this, loggerCallback);
+
+	ANKI_CHECK(m_scriptEnv.init(scriptManager));
+
+	return Error::NONE;
+}
+
+void DeveloperConsole::build(CanvasPtr ctx)
+{
+	const Vec4 oldWindowColor = ImGui::GetStyle().Colors[ImGuiCol_WindowBg];
+	ImGui::GetStyle().Colors[ImGuiCol_WindowBg].w = 0.3f;
+	ctx->pushFont(m_font, 16);
+
+	ImGui::Begin("Console", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoTitleBar);
+
+	ImGui::SetWindowPos(Vec2(0.0f, 0.0f));
+	ImGui::SetWindowSize(Vec2(ctx->getWidth(), ctx->getHeight() * (2.0f / 3.0f)));
+
+	// Push the items
+	const F32 footerHeightToPreserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
+	ImGui::BeginChild("ScrollingRegion",
+		Vec2(0, -footerHeightToPreserve),
+		false,
+		ImGuiWindowFlags_HorizontalScrollbar); // Leave room for 1 separator + 1 InputText
+
+	ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, Vec2(4.0f, 1.0f)); // Tighten spacing
+
+	for(const LogItem& item : m_logItems)
+	{
+		switch(item.m_type)
+		{
+		case LoggerMessageType::NORMAL:
+			ImGui::PushStyleColor(ImGuiCol_Text, Vec4(0.0f, 1.0f, 0.0f, 1.0f));
+			break;
+		case LoggerMessageType::ERROR:
+		case LoggerMessageType::FATAL:
+			ImGui::PushStyleColor(ImGuiCol_Text, Vec4(1.0f, 0.0f, 0.0f, 1.0f));
+			break;
+		case LoggerMessageType::WARNING:
+			ImGui::PushStyleColor(ImGuiCol_Text, Vec4(0.9f, 0.6f, 0.14f, 1.0f));
+			break;
+		default:
+			ANKI_ASSERT(0);
+		}
+
+		static const Array<const char*, static_cast<U>(LoggerMessageType::COUNT)> MSG_TEXT = {{"I", "E", "W", "F"}};
+		ImGui::TextWrapped("[%s][%s] %s (%s:%d %s)",
+			MSG_TEXT[static_cast<U>(item.m_type)],
+			(item.m_subsystem) ? item.m_subsystem : "N/A ",
+			item.m_msg.cstr(),
+			item.m_file,
+			item.m_line,
+			item.m_func);
+
+		ImGui::PopStyleColor();
+	}
+
+	const U32 timestamp = m_logItemsTimestamp.get();
+	const Bool scrollToLast = m_logItemsTimestampConsumed < timestamp;
+
+	if(scrollToLast)
+	{
+		ImGui::SetScrollHereY(1.0f);
+		++m_logItemsTimestampConsumed;
+	}
+	ImGui::PopStyleVar();
+	ImGui::EndChild();
+
+	// Commands
+	ImGui::Separator();
+	ImGui::PushItemWidth(-1.0f); // Use the whole size
+	if(ImGui::InputText(
+		   "", &m_inputText[0], m_inputText.getSizeInBytes(), ImGuiInputTextFlags_EnterReturnsTrue, nullptr, nullptr))
+	{
+		const Error err = m_scriptEnv.evalString(&m_inputText[0]);
+		if(!err)
+		{
+			ANKI_CORE_LOGI("Script run without errors");
+		}
+		m_inputText[0] = '\0';
+	}
+	ImGui::PopItemWidth();
+
+	ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget
+
+	ImGui::End();
+	ImGui::GetStyle().Colors[ImGuiCol_WindowBg] = oldWindowColor;
+	ctx->popFont();
+}
+
+void DeveloperConsole::newLogItem(const LoggerMessageInfo& inf)
+{
+	LogItem* newLogItem;
+
+	// Pop first
+	if(m_logItemCount + 1 > MAX_LOG_ITEMS)
+	{
+		LogItem* first = &m_logItems.getFront();
+		m_logItems.popFront();
+
+		first->m_msg.destroy(m_alloc);
+
+		// Re-use the log item
+		newLogItem = first;
+		--m_logItemCount;
+	}
+	else
+	{
+		newLogItem = m_alloc.newInstance<LogItem>();
+	}
+
+	// Create the new item
+	newLogItem->m_file = inf.m_file;
+	newLogItem->m_func = inf.m_func;
+	newLogItem->m_subsystem = inf.m_subsystem;
+	newLogItem->m_msg.create(m_alloc, inf.m_msg);
+	newLogItem->m_line = inf.m_line;
+	newLogItem->m_type = inf.m_type;
+
+	// Push it back
+	m_logItems.pushBack(newLogItem);
+	++m_logItemCount;
+
+	m_logItemsTimestamp.fetchAdd(1);
+}
+
+} // end namespace anki

+ 68 - 0
src/anki/core/DeveloperConsole.h

@@ -0,0 +1,68 @@
+// Copyright (C) 2009-2019, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <anki/Ui.h>
+#include <anki/core/Common.h>
+#include <anki/util/List.h>
+#include <anki/script/ScriptEnvironment.h>
+
+namespace anki
+{
+
+/// @addtogroup core
+/// @{
+
+/// Developer console UI.
+class DeveloperConsole : public UiImmediateModeBuilder
+{
+public:
+	DeveloperConsole(UiManager* ui)
+		: UiImmediateModeBuilder(ui)
+	{
+	}
+
+	~DeveloperConsole();
+
+	ANKI_USE_RESULT Error init(AllocAlignedCallback allocCb, void* allocCbUserData, ScriptManager* scriptManager);
+
+	void build(CanvasPtr ctx) override;
+
+private:
+	static constexpr U MAX_LOG_ITEMS = 64;
+
+	class LogItem : public IntrusiveListEnabled<LogItem>
+	{
+	public:
+		const char* m_file;
+		const char* m_func;
+		const char* m_subsystem;
+		String m_msg;
+		I32 m_line;
+		LoggerMessageType m_type;
+	};
+
+	HeapAllocator<U8> m_alloc;
+	FontPtr m_font;
+	IntrusiveList<LogItem> m_logItems;
+	U32 m_logItemCount = 0;
+	Array<char, 256> m_inputText;
+
+	Atomic<U32> m_logItemsTimestamp = {1};
+	U32 m_logItemsTimestampConsumed = 0;
+
+	ScriptEnvironment m_scriptEnv;
+
+	void newLogItem(const LoggerMessageInfo& inf);
+
+	static void loggerCallback(void* userData, const LoggerMessageInfo& info)
+	{
+		static_cast<DeveloperConsole*>(userData)->newLogItem(info);
+	}
+};
+/// @}
+
+} // end namespace anki

+ 1 - 0
src/anki/gr/Enums.h

@@ -45,6 +45,7 @@ enum class FillMode : U8
 
 
 enum class FaceSelectionBit : U8
 enum class FaceSelectionBit : U8
 {
 {
+	NONE = 0,
 	FRONT = 1 << 0,
 	FRONT = 1 << 0,
 	BACK = 1 << 1,
 	BACK = 1 << 1,
 	FRONT_AND_BACK = FRONT | BACK
 	FRONT_AND_BACK = FRONT | BACK

+ 3 - 0
src/anki/gr/vulkan/Common.cpp

@@ -100,6 +100,9 @@ VkCullModeFlags convertCullMode(FaceSelectionBit ak)
 	VkCullModeFlags out = 0;
 	VkCullModeFlags out = 0;
 	switch(ak)
 	switch(ak)
 	{
 	{
+	case FaceSelectionBit::NONE:
+		out = VK_CULL_MODE_NONE;
+		break;
 	case FaceSelectionBit::FRONT:
 	case FaceSelectionBit::FRONT:
 		out = VK_CULL_MODE_FRONT_BIT;
 		out = VK_CULL_MODE_FRONT_BIT;
 		break;
 		break;

+ 1 - 0
src/anki/input/Input.cpp

@@ -16,6 +16,7 @@ void Input::reset()
 	m_mousePosNdc = Vec2(-1.0f);
 	m_mousePosNdc = Vec2(-1.0f);
 	m_mousePosWin = UVec2(0u);
 	m_mousePosWin = UVec2(0u);
 	zeroMemory(m_events);
 	zeroMemory(m_events);
+	zeroMemory(m_textInput);
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 21 - 0
src/anki/input/Input.h

@@ -99,6 +99,24 @@ public:
 		++m_events[static_cast<U>(eventId)];
 		++m_events[static_cast<U>(eventId)];
 	}
 	}
 
 
+	template<typename TFunc>
+	void iteratePressedKeys(TFunc func) const
+	{
+		for(KeyCode i = KeyCode::FIRST; i < KeyCode::COUNT; ++i)
+		{
+			if(m_keys[i] > 0)
+			{
+				func(i, m_keys[i]);
+			}
+		}
+	}
+
+	/// Get some easy to digest input from the keyboard.
+	CString getTextInput() const
+	{
+		return &m_textInput[0];
+	}
+
 private:
 private:
 	InputImpl* m_impl = nullptr;
 	InputImpl* m_impl = nullptr;
 	NativeWindow* m_nativeWindow = nullptr;
 	NativeWindow* m_nativeWindow = nullptr;
@@ -121,6 +139,9 @@ private:
 
 
 	Array<U8, static_cast<U>(InputEvent::COUNT)> m_events;
 	Array<U8, static_cast<U>(InputEvent::COUNT)> m_events;
 
 
+	/// The keybord input as ascii.
+	Array<char, static_cast<U>(KeyCode::COUNT)> m_textInput;
+
 	Bool m_lockCurs = false;
 	Bool m_lockCurs = false;
 
 
 	/// Initialize the platform's input system
 	/// Initialize the platform's input system

+ 7 - 0
src/anki/input/InputSdl.cpp

@@ -301,6 +301,8 @@ Error Input::handleEvents()
 {
 {
 	ANKI_ASSERT(m_nativeWindow != nullptr);
 	ANKI_ASSERT(m_nativeWindow != nullptr);
 
 
+	m_textInput[0] = '\0';
+
 	// add the times a key is being pressed
 	// add the times a key is being pressed
 	for(auto& k : m_keys)
 	for(auto& k : m_keys)
 	{
 	{
@@ -350,6 +352,10 @@ Error Input::handleEvents()
 			}
 			}
 			break;
 			break;
 		}
 		}
+		case SDL_MOUSEWHEEL:
+			m_mouseBtns[MouseButton::SCROLL_UP] = event.wheel.y > 0;
+			m_mouseBtns[MouseButton::SCROLL_DOWN] = event.wheel.y < 0;
+			break;
 		case SDL_MOUSEMOTION:
 		case SDL_MOUSEMOTION:
 			m_mousePosWin.x() = event.button.x;
 			m_mousePosWin.x() = event.button.x;
 			m_mousePosWin.y() = event.button.y;
 			m_mousePosWin.y() = event.button.y;
@@ -360,6 +366,7 @@ Error Input::handleEvents()
 			addEvent(InputEvent::WINDOW_CLOSED);
 			addEvent(InputEvent::WINDOW_CLOSED);
 			break;
 			break;
 		case SDL_TEXTINPUT:
 		case SDL_TEXTINPUT:
+			std::strncpy(&m_textInput[0], event.text.text, m_textInput.getSize() - 1);
 			break;
 			break;
 		}
 		}
 	} // end while events
 	} // end while events

+ 8 - 1
src/anki/input/KeyCode.h

@@ -5,6 +5,8 @@
 
 
 #pragma once
 #pragma once
 
 
+#include <anki/util/Enum.h>
+
 namespace anki
 namespace anki
 {
 {
 
 
@@ -261,16 +263,21 @@ enum class KeyCode
 	EJECT,
 	EJECT,
 	SLEEP,
 	SLEEP,
 
 
-	COUNT
+	COUNT,
+	FIRST = 0,
 };
 };
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(KeyCode, inline)
 
 
 enum class MouseButton
 enum class MouseButton
 {
 {
 	LEFT,
 	LEFT,
 	MIDDLE,
 	MIDDLE,
 	RIGHT,
 	RIGHT,
+	SCROLL_UP,
+	SCROLL_DOWN,
 
 
 	COUNT
 	COUNT
 };
 };
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(MouseButton, inline)
 
 
 } // end namespace anki
 } // end namespace anki

+ 70 - 1
src/anki/ui/Canvas.cpp

@@ -65,6 +65,34 @@ Error Canvas::init(FontPtr font, U32 fontHeight, U32 width, U32 height)
 	ImGui::GetIO().IniFilename = nullptr;
 	ImGui::GetIO().IniFilename = nullptr;
 	ImGui::GetIO().LogFilename = nullptr;
 	ImGui::GetIO().LogFilename = nullptr;
 	ImGui::StyleColorsLight();
 	ImGui::StyleColorsLight();
+
+#define ANKI_HANDLE(ak, im) ImGui::GetIO().KeyMap[im] = static_cast<int>(ak);
+
+	ANKI_HANDLE(KeyCode::TAB, ImGuiKey_Tab)
+	ANKI_HANDLE(KeyCode::LEFT, ImGuiKey_LeftArrow)
+	ANKI_HANDLE(KeyCode::RIGHT, ImGuiKey_RightArrow)
+	ANKI_HANDLE(KeyCode::UP, ImGuiKey_UpArrow)
+	ANKI_HANDLE(KeyCode::DOWN, ImGuiKey_DownArrow)
+	ANKI_HANDLE(KeyCode::PAGEUP, ImGuiKey_PageUp)
+	ANKI_HANDLE(KeyCode::PAGEDOWN, ImGuiKey_PageDown)
+	ANKI_HANDLE(KeyCode::HOME, ImGuiKey_Home)
+	ANKI_HANDLE(KeyCode::END, ImGuiKey_End)
+	ANKI_HANDLE(KeyCode::INSERT, ImGuiKey_Insert)
+	ANKI_HANDLE(KeyCode::DELETE, ImGuiKey_Delete)
+	ANKI_HANDLE(KeyCode::BACKSPACE, ImGuiKey_Backspace)
+	ANKI_HANDLE(KeyCode::SPACE, ImGuiKey_Space)
+	ANKI_HANDLE(KeyCode::RETURN, ImGuiKey_Enter)
+	// ANKI_HANDLE(KeyCode::RETURN2, ImGuiKey_Enter)
+	ANKI_HANDLE(KeyCode::ESCAPE, ImGuiKey_Escape)
+	ANKI_HANDLE(KeyCode::A, ImGuiKey_A)
+	ANKI_HANDLE(KeyCode::C, ImGuiKey_C)
+	ANKI_HANDLE(KeyCode::V, ImGuiKey_V)
+	ANKI_HANDLE(KeyCode::X, ImGuiKey_X)
+	ANKI_HANDLE(KeyCode::Y, ImGuiKey_Y)
+	ANKI_HANDLE(KeyCode::Z, ImGuiKey_Z)
+
+#undef ANKI_HANDLE
+
 	ImGui::SetCurrentContext(nullptr);
 	ImGui::SetCurrentContext(nullptr);
 	unsetImAllocator();
 	unsetImAllocator();
 
 
@@ -92,6 +120,45 @@ void Canvas::handleInput()
 	io.MouseClicked[0] = in.getMouseButton(MouseButton::LEFT) == 1;
 	io.MouseClicked[0] = in.getMouseButton(MouseButton::LEFT) == 1;
 	io.MouseDown[0] = in.getMouseButton(MouseButton::LEFT) > 0;
 	io.MouseDown[0] = in.getMouseButton(MouseButton::LEFT) > 0;
 
 
+	if(in.getMouseButton(MouseButton::SCROLL_UP) == 1)
+	{
+		io.MouseWheel = in.getMouseButton(MouseButton::SCROLL_UP);
+	}
+	else if(in.getMouseButton(MouseButton::SCROLL_DOWN) == 1)
+	{
+		io.MouseWheel = -I32(in.getMouseButton(MouseButton::SCROLL_DOWN));
+	}
+
+// Handle keyboard
+#define ANKI_HANDLE(ak) io.KeysDown[static_cast<int>(ak)] = (in.getKey(ak) == 1);
+
+	ANKI_HANDLE(KeyCode::TAB)
+	ANKI_HANDLE(KeyCode::LEFT)
+	ANKI_HANDLE(KeyCode::RIGHT)
+	ANKI_HANDLE(KeyCode::UP)
+	ANKI_HANDLE(KeyCode::DOWN)
+	ANKI_HANDLE(KeyCode::PAGEUP)
+	ANKI_HANDLE(KeyCode::PAGEDOWN)
+	ANKI_HANDLE(KeyCode::HOME)
+	ANKI_HANDLE(KeyCode::END)
+	ANKI_HANDLE(KeyCode::INSERT)
+	ANKI_HANDLE(KeyCode::DELETE)
+	ANKI_HANDLE(KeyCode::BACKSPACE)
+	ANKI_HANDLE(KeyCode::SPACE)
+	ANKI_HANDLE(KeyCode::RETURN)
+	// ANKI_HANDLE(KeyCode::RETURN2)
+	ANKI_HANDLE(KeyCode::ESCAPE)
+	ANKI_HANDLE(KeyCode::A)
+	ANKI_HANDLE(KeyCode::C)
+	ANKI_HANDLE(KeyCode::V)
+	ANKI_HANDLE(KeyCode::X)
+	ANKI_HANDLE(KeyCode::Y)
+	ANKI_HANDLE(KeyCode::Z)
+
+#undef ANKI_HANDLE
+
+	io.AddInputCharactersUTF8(in.getTextInput().cstr());
+
 	// End
 	// End
 	ImGui::SetCurrentContext(nullptr);
 	ImGui::SetCurrentContext(nullptr);
 	unsetImAllocator();
 	unsetImAllocator();
@@ -160,7 +227,7 @@ void Canvas::appendToCommandBufferInternal(CommandBufferPtr& cmdb)
 	}
 	}
 
 
 	cmdb->setBlendFactors(0, BlendFactor::SRC_ALPHA, BlendFactor::ONE_MINUS_SRC_ALPHA);
 	cmdb->setBlendFactors(0, BlendFactor::SRC_ALPHA, BlendFactor::ONE_MINUS_SRC_ALPHA);
-	cmdb->setCullMode(FaceSelectionBit::FRONT);
+	cmdb->setCullMode(FaceSelectionBit::NONE);
 
 
 	const U fbWidth = drawData.DisplaySize.x * drawData.FramebufferScale.x;
 	const U fbWidth = drawData.DisplaySize.x * drawData.FramebufferScale.x;
 	const U fbHeight = drawData.DisplaySize.y * drawData.FramebufferScale.y;
 	const U fbHeight = drawData.DisplaySize.y * drawData.FramebufferScale.y;
@@ -247,7 +314,9 @@ void Canvas::appendToCommandBufferInternal(CommandBufferPtr& cmdb)
 		vertOffset += cmdList.VtxBuffer.Size;
 		vertOffset += cmdList.VtxBuffer.Size;
 	}
 	}
 
 
+	// Restore state
 	cmdb->setBlendFactors(0, BlendFactor::ONE, BlendFactor::ZERO);
 	cmdb->setBlendFactors(0, BlendFactor::ONE, BlendFactor::ZERO);
+	cmdb->setCullMode(FaceSelectionBit::BACK);
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 10 - 0
src/anki/ui/Canvas.h

@@ -38,6 +38,16 @@ public:
 		m_height = height;
 		m_height = height;
 	}
 	}
 
 
+	U32 getWidth() const
+	{
+		return m_width;
+	}
+
+	U32 getHeight() const
+	{
+		return m_height;
+	}
+
 	/// @name building commands. The order matters.
 	/// @name building commands. The order matters.
 	/// @{
 	/// @{
 
 

+ 5 - 0
src/anki/util/Array.h

@@ -145,6 +145,11 @@ public:
 	{
 	{
 		return N;
 		return N;
 	}
 	}
+
+	static constexpr PtrSize getSizeInBytes()
+	{
+		return N * sizeof(Value);
+	}
 };
 };
 
 
 /// 2D Array. @code Array2d<X, 10, 2> a; @endcode is equivelent to @code X a[10][2]; @endcode
 /// 2D Array. @code Array2d<X, 10, 2> a; @endcode is equivelent to @code X a[10][2]; @endcode

+ 44 - 20
src/anki/util/Logger.cpp

@@ -17,7 +17,7 @@
 namespace anki
 namespace anki
 {
 {
 
 
-static const Array<const char*, static_cast<U>(Logger::MessageType::COUNT)> MSG_TEXT = {{"I", "E", "W", "F"}};
+static const Array<const char*, static_cast<U>(LoggerMessageType::COUNT)> MSG_TEXT = {{"I", "E", "W", "F"}};
 
 
 Logger::Logger()
 Logger::Logger()
 {
 {
@@ -28,17 +28,41 @@ Logger::~Logger()
 {
 {
 }
 }
 
 
-void Logger::addMessageHandler(void* data, MessageHandlerCallback callback)
+void Logger::addMessageHandler(void* data, LoggerMessageHandlerCallback callback)
 {
 {
+	LockGuard<Mutex> lock(m_mutex);
 	m_handlers[m_handlersCount++] = Handler(data, callback);
 	m_handlers[m_handlersCount++] = Handler(data, callback);
 }
 }
 
 
+void Logger::removeMessageHandler(void* data, LoggerMessageHandlerCallback callback)
+{
+	LockGuard<Mutex> lock(m_mutex);
+
+	U i;
+	for(i = 0; i < m_handlersCount; ++i)
+	{
+		if(m_handlers[i].m_callback == callback && m_handlers[i].m_data == data)
+		{
+			break;
+		}
+	}
+
+	if(i < m_handlersCount)
+	{
+		for(U j = i + 1; j < m_handlersCount; ++j)
+		{
+			m_handlers[j - 1] = m_handlers[j];
+		}
+		--m_handlersCount;
+	}
+}
+
 void Logger::write(
 void Logger::write(
-	const char* file, int line, const char* func, const char* subsystem, MessageType type, const char* msg)
+	const char* file, int line, const char* func, const char* subsystem, LoggerMessageType type, const char* msg)
 {
 {
 	m_mutex.lock();
 	m_mutex.lock();
 
 
-	Info inf = {file, line, func, type, msg, subsystem};
+	LoggerMessageInfo inf = {file, line, func, type, msg, subsystem};
 
 
 	U count = m_handlersCount;
 	U count = m_handlersCount;
 	while(count-- != 0)
 	while(count-- != 0)
@@ -48,14 +72,14 @@ void Logger::write(
 
 
 	m_mutex.unlock();
 	m_mutex.unlock();
 
 
-	if(type == MessageType::FATAL)
+	if(type == LoggerMessageType::FATAL)
 	{
 	{
 		abort();
 		abort();
 	}
 	}
 }
 }
 
 
 void Logger::writeFormated(
 void Logger::writeFormated(
-	const char* file, int line, const char* func, const char* subsystem, MessageType type, const char* fmt, ...)
+	const char* file, int line, const char* func, const char* subsystem, LoggerMessageType type, const char* fmt, ...)
 {
 {
 	char buffer[1024 * 10];
 	char buffer[1024 * 10];
 	va_list args;
 	va_list args;
@@ -90,7 +114,7 @@ void Logger::writeFormated(
 	}
 	}
 }
 }
 
 
-void Logger::defaultSystemMessageHandler(void*, const Info& info)
+void Logger::defaultSystemMessageHandler(void*, const LoggerMessageInfo& info)
 {
 {
 #if ANKI_OS == ANKI_OS_LINUX
 #if ANKI_OS == ANKI_OS_LINUX
 	FILE* out = nullptr;
 	FILE* out = nullptr;
@@ -100,22 +124,22 @@ void Logger::defaultSystemMessageHandler(void*, const Info& info)
 
 
 	switch(info.m_type)
 	switch(info.m_type)
 	{
 	{
-	case Logger::MessageType::NORMAL:
+	case LoggerMessageType::NORMAL:
 		out = stdout;
 		out = stdout;
 		terminalColor = "\033[0;32m";
 		terminalColor = "\033[0;32m";
 		terminalColorBg = "\033[1;42;37m";
 		terminalColorBg = "\033[1;42;37m";
 		break;
 		break;
-	case Logger::MessageType::ERROR:
+	case LoggerMessageType::ERROR:
 		out = stderr;
 		out = stderr;
 		terminalColor = "\033[0;31m";
 		terminalColor = "\033[0;31m";
 		terminalColorBg = "\033[1;41;37m";
 		terminalColorBg = "\033[1;41;37m";
 		break;
 		break;
-	case Logger::MessageType::WARNING:
+	case LoggerMessageType::WARNING:
 		out = stderr;
 		out = stderr;
 		terminalColor = "\033[2;33m";
 		terminalColor = "\033[2;33m";
 		terminalColorBg = "\033[1;43;37m";
 		terminalColorBg = "\033[1;43;37m";
 		break;
 		break;
-	case Logger::MessageType::FATAL:
+	case LoggerMessageType::FATAL:
 		out = stderr;
 		out = stderr;
 		terminalColor = "\033[0;31m";
 		terminalColor = "\033[0;31m";
 		terminalColorBg = "\033[1;41;37m";
 		terminalColorBg = "\033[1;41;37m";
@@ -149,16 +173,16 @@ void Logger::defaultSystemMessageHandler(void*, const Info& info)
 
 
 	switch(info.m_type)
 	switch(info.m_type)
 	{
 	{
-	case Logger::MessageType::NORMAL:
+	case LoggerMessageType::NORMAL:
 		andMsgType = ANDROID_LOG_INFO;
 		andMsgType = ANDROID_LOG_INFO;
 		break;
 		break;
-	case Logger::MessageType::ERROR:
+	case LoggerMessageType::ERROR:
 		andMsgType = ANDROID_LOG_ERROR;
 		andMsgType = ANDROID_LOG_ERROR;
 		break;
 		break;
-	case Logger::MessageType::WARNING:
+	case LoggerMessageType::WARNING:
 		andMsgType = ANDROID_LOG_WARN;
 		andMsgType = ANDROID_LOG_WARN;
 		break;
 		break;
-	case Logger::MessageType::FATAL:
+	case LoggerMessageType::FATAL:
 		andMsgType = ANDROID_LOG_ERROR;
 		andMsgType = ANDROID_LOG_ERROR;
 		break;
 		break;
 	default:
 	default:
@@ -173,16 +197,16 @@ void Logger::defaultSystemMessageHandler(void*, const Info& info)
 
 
 	switch(info.m_type)
 	switch(info.m_type)
 	{
 	{
-	case Logger::MessageType::NORMAL:
+	case LoggerMessageType::NORMAL:
 		out = stdout;
 		out = stdout;
 		break;
 		break;
-	case Logger::MessageType::ERROR:
+	case LoggerMessageType::ERROR:
 		out = stderr;
 		out = stderr;
 		break;
 		break;
-	case Logger::MessageType::WARNING:
+	case LoggerMessageType::WARNING:
 		out = stderr;
 		out = stderr;
 		break;
 		break;
-	case Logger::MessageType::FATAL:
+	case LoggerMessageType::FATAL:
 		out = stderr;
 		out = stderr;
 		break;
 		break;
 	default:
 	default:
@@ -202,7 +226,7 @@ void Logger::defaultSystemMessageHandler(void*, const Info& info)
 #endif
 #endif
 }
 }
 
 
-void Logger::fileMessageHandler(void* pfile, const Info& info)
+void Logger::fileMessageHandler(void* pfile, const LoggerMessageInfo& info)
 {
 {
 	File* file = reinterpret_cast<File*>(pfile);
 	File* file = reinterpret_cast<File*>(pfile);
 
 

+ 46 - 34
src/anki/util/Logger.h

@@ -18,6 +18,34 @@ class File;
 /// @addtogroup util_other
 /// @addtogroup util_other
 /// @{
 /// @{
 
 
+/// Logger message type.
+/// @memberof Logger
+enum class LoggerMessageType : U8
+{
+	NORMAL,
+	ERROR,
+	WARNING,
+	FATAL,
+	COUNT
+};
+
+/// Used as parammeter when emitting the signal.
+/// @memberof Logger
+class LoggerMessageInfo
+{
+public:
+	const char* m_file;
+	I32 m_line;
+	const char* m_func;
+	LoggerMessageType m_type;
+	const char* m_msg;
+	const char* m_subsystem;
+};
+
+/// The message handler callback.
+/// @memberof Logger
+using LoggerMessageHandlerCallback = void (*)(void*, const LoggerMessageInfo& info);
+
 /// The logger singleton class. The logger cannot print errors or throw exceptions, it has to recover somehow. It's
 /// The logger singleton class. The logger cannot print errors or throw exceptions, it has to recover somehow. It's
 /// thread safe.
 /// thread safe.
 /// To add a new signal:
 /// To add a new signal:
@@ -25,61 +53,45 @@ class File;
 class Logger
 class Logger
 {
 {
 public:
 public:
-	/// Logger message type
-	enum class MessageType : U8
-	{
-		NORMAL,
-		ERROR,
-		WARNING,
-		FATAL,
-		COUNT
-	};
-
-	/// Used as parammeter when emitting the signal
-	class Info
-	{
-	public:
-		const char* m_file;
-		I32 m_line;
-		const char* m_func;
-		MessageType m_type;
-		const char* m_msg;
-		const char* m_subsystem;
-	};
-
-	/// The message handler callback
-	using MessageHandlerCallback = void (*)(void*, const Info& info);
-
 	/// Initialize the logger and add the default message handler
 	/// Initialize the logger and add the default message handler
 	Logger();
 	Logger();
 
 
 	~Logger();
 	~Logger();
 
 
 	/// Add a new message handler
 	/// Add a new message handler
-	void addMessageHandler(void* data, MessageHandlerCallback callback);
+	void addMessageHandler(void* data, LoggerMessageHandlerCallback callback);
+
+	/// Remove a message handler.
+	void removeMessageHandler(void* data, LoggerMessageHandlerCallback callback);
 
 
 	/// Add file message handler.
 	/// Add file message handler.
 	void addFileMessageHandler(File* file);
 	void addFileMessageHandler(File* file);
 
 
 	/// Send a message
 	/// Send a message
-	void write(const char* file, int line, const char* func, const char* subsystem, MessageType type, const char* msg);
+	void write(
+		const char* file, int line, const char* func, const char* subsystem, LoggerMessageType type, const char* msg);
 
 
 	/// Send a formated message
 	/// Send a formated message
-	void writeFormated(
-		const char* file, int line, const char* func, const char* subsystem, MessageType type, const char* fmt, ...);
+	void writeFormated(const char* file,
+		int line,
+		const char* func,
+		const char* subsystem,
+		LoggerMessageType type,
+		const char* fmt,
+		...);
 
 
 private:
 private:
 	class Handler
 	class Handler
 	{
 	{
 	public:
 	public:
 		void* m_data = nullptr;
 		void* m_data = nullptr;
-		MessageHandlerCallback m_callback = nullptr;
+		LoggerMessageHandlerCallback m_callback = nullptr;
 
 
 		Handler() = default;
 		Handler() = default;
 
 
 		Handler(const Handler&) = default;
 		Handler(const Handler&) = default;
 
 
-		Handler(void* data, MessageHandlerCallback callback)
+		Handler(void* data, LoggerMessageHandlerCallback callback)
 			: m_data(data)
 			: m_data(data)
 			, m_callback(callback)
 			, m_callback(callback)
 		{
 		{
@@ -90,8 +102,8 @@ private:
 	Array<Handler, 4> m_handlers;
 	Array<Handler, 4> m_handlers;
 	U32 m_handlersCount = 0;
 	U32 m_handlersCount = 0;
 
 
-	static void defaultSystemMessageHandler(void*, const Info& info);
-	static void fileMessageHandler(void* file, const Info& info);
+	static void defaultSystemMessageHandler(void*, const LoggerMessageInfo& info);
+	static void fileMessageHandler(void* file, const LoggerMessageInfo& info);
 };
 };
 
 
 typedef Singleton<Logger> LoggerSingleton;
 typedef Singleton<Logger> LoggerSingleton;
@@ -100,7 +112,7 @@ typedef Singleton<Logger> LoggerSingleton;
 	do \
 	do \
 	{ \
 	{ \
 		LoggerSingleton::get().writeFormated( \
 		LoggerSingleton::get().writeFormated( \
-			ANKI_FILE, __LINE__, ANKI_FUNC, subsystem_, Logger::MessageType::t, __VA_ARGS__); \
+			ANKI_FILE, __LINE__, ANKI_FUNC, subsystem_, LoggerMessageType::t, __VA_ARGS__); \
 	} while(false);
 	} while(false);
 /// @}
 /// @}