Browse Source

Update ImGui and refactor because of that

Panagiotis Christopoulos Charitos 2 months ago
parent
commit
a81af33ad6
100 changed files with 616 additions and 694 deletions
  1. 1 1
      AnKi/Core/App.cpp
  2. 0 1
      AnKi/Core/App.h
  3. 8 10
      AnKi/Editor/EditorUi.cpp
  4. 4 12
      AnKi/Editor/EditorUi.h
  5. 1 1
      AnKi/Gr/CommandBuffer.h
  6. 11 1
      AnKi/Gr/Common.h
  7. 7 6
      AnKi/Gr/D3D/D3DCommandBuffer.cpp
  8. 1 1
      AnKi/Gr/D3D/D3DGrManager.cpp
  9. 6 6
      AnKi/Gr/Vulkan/VkCommandBuffer.cpp
  10. 1 1
      AnKi/Gr/Vulkan/VkGrManager.cpp
  11. 7 4
      AnKi/Importer/ImageImporter.cpp
  12. 3 1
      AnKi/Renderer/FinalComposite.cpp
  13. 6 1
      AnKi/Renderer/Renderer.cpp
  14. 2 2
      AnKi/Renderer/TemporalUpscaler.cpp
  15. 2 2
      AnKi/Renderer/TemporalUpscaler.h
  16. 68 16
      AnKi/Renderer/UiStage.cpp
  17. 16 5
      AnKi/Renderer/UiStage.h
  18. 3 3
      AnKi/Scene/Components/UiComponent.h
  19. 9 6
      AnKi/Scene/DeveloperConsoleUiNode.cpp
  20. 3 3
      AnKi/Scene/DeveloperConsoleUiNode.h
  21. 9 7
      AnKi/Scene/StatsUiNode.cpp
  22. 3 3
      AnKi/Scene/StatsUiNode.h
  23. 1 1
      AnKi/Shaders/GBufferGeneric.ankiprog
  24. 0 4
      AnKi/Shaders/IndirectDiffuseClipmaps.ankiprog
  25. 1 0
      AnKi/Shaders/Intellisense.hlsl
  26. 0 4
      AnKi/Shaders/Reflections.ankiprog
  27. 6 3
      AnKi/Shaders/RtMaterialFetch.hlsl
  28. 1 3
      AnKi/Ui.h
  29. 0 17
      AnKi/Ui/Common.cpp
  30. 22 58
      AnKi/Ui/Common.h
  31. 0 107
      AnKi/Ui/Font.cpp
  32. 0 84
      AnKi/Ui/Font.h
  33. 72 0
      AnKi/Ui/ImGuiConfig.h
  34. 192 96
      AnKi/Ui/UiCanvas.cpp
  35. 28 22
      AnKi/Ui/UiCanvas.h
  36. 0 32
      AnKi/Ui/UiImmediateModeBuilder.h
  37. 4 19
      AnKi/Ui/UiManager.cpp
  38. 1 3
      AnKi/Ui/UiManager.h
  39. 0 39
      AnKi/Ui/UiObject.h
  40. 49 67
      AnKi/Window/Input.h
  41. 40 14
      AnKi/Window/InputSdl.cpp
  42. 16 16
      Samples/Common/SampleApp.cpp
  43. 8 8
      Samples/PhysicsPlayground/FpsCharacterNode.cpp
  44. 3 3
      Samples/PhysicsPlayground/Main.cpp
  45. BIN
      Samples/Sponza/Assets/Background_Roughness.ankitex
  46. BIN
      Samples/Sponza/Assets/ChainMail_baseColor.ankitex
  47. BIN
      Samples/Sponza/Assets/ChainMail_metallicRoughness.ankitex
  48. BIN
      Samples/Sponza/Assets/ChainMail_normal.ankitex
  49. BIN
      Samples/Sponza/Assets/Leather_baseColor.ankitex
  50. BIN
      Samples/Sponza/Assets/Leather_metallicRoughness.ankitex
  51. BIN
      Samples/Sponza/Assets/Leather_normal.ankitex
  52. BIN
      Samples/Sponza/Assets/Lion_Roughness.ankitex
  53. BIN
      Samples/Sponza/Assets/Metal_baseColor.ankitex
  54. BIN
      Samples/Sponza/Assets/Metal_metallicRoughness.ankitex
  55. BIN
      Samples/Sponza/Assets/Metal_normal.ankitex
  56. 1 1
      Samples/Sponza/Assets/Scene.lua
  57. BIN
      Samples/Sponza/Assets/Sponza_Ceiling_roughness.ankitex.ankitex
  58. BIN
      Samples/Sponza/Assets/Sponza_Column_b_roughness.ankitex.ankitex
  59. BIN
      Samples/Sponza/Assets/Sponza_Column_c_roughness.ankitex.ankitex
  60. BIN
      Samples/Sponza/Assets/Sponza_Curtain_Red_normal.ankitex
  61. BIN
      Samples/Sponza/Assets/Sponza_Curtain_Red_normal.ankitex.001.ankitex
  62. BIN
      Samples/Sponza/Assets/Sponza_Curtain_roughness.ankitex.001.ankitex
  63. BIN
      Samples/Sponza/Assets/Sponza_Details_metallic-Sponza_Details_roughness.ankitex
  64. BIN
      Samples/Sponza/Assets/Sponza_Details_normal.ankitex
  65. BIN
      Samples/Sponza/Assets/Sponza_Fabric_metallic-Sponza_Curtain_roughness.ankitex
  66. BIN
      Samples/Sponza/Assets/Sponza_FlagPole_normal.ankitex
  67. BIN
      Samples/Sponza/Assets/Sponza_FlagPole_roughness.ankitex
  68. BIN
      Samples/Sponza/Assets/Sponza_Floor_normal.ankitex
  69. BIN
      Samples/Sponza/Assets/Sponza_Floor_roughness.ankitex
  70. BIN
      Samples/Sponza/Assets/Sponza_Roof_normal.ankitex
  71. BIN
      Samples/Sponza/Assets/Sponza_Roof_roughness.ankitex
  72. BIN
      Samples/Sponza/Assets/Sponza_Thorn_roughness.ankitex
  73. BIN
      Samples/Sponza/Assets/VaseHanging_normal.ankitex.ankitex
  74. BIN
      Samples/Sponza/Assets/VaseHanging_roughness.ankitex.ankitex
  75. BIN
      Samples/Sponza/Assets/VasePlant_normal.ankitex
  76. BIN
      Samples/Sponza/Assets/VaseRound_normal.ankitex
  77. BIN
      Samples/Sponza/Assets/VaseRound_roughness.ankitex
  78. BIN
      Samples/Sponza/Assets/Vase_roughness.ankitex
  79. BIN
      Samples/Sponza/Assets/background.ankitex
  80. BIN
      Samples/Sponza/Assets/background_ddn.ankitex
  81. BIN
      Samples/Sponza/Assets/chain_texture.ankitex.ankitex
  82. BIN
      Samples/Sponza/Assets/lion.ankitex
  83. BIN
      Samples/Sponza/Assets/lion_ddn.ankitex
  84. BIN
      Samples/Sponza/Assets/material_baseColor.ankitex
  85. BIN
      Samples/Sponza/Assets/material_metallicRoughness.ankitex
  86. BIN
      Samples/Sponza/Assets/skinFace_baseColor.ankitex
  87. BIN
      Samples/Sponza/Assets/skinFace_metallicRoughness.ankitex
  88. BIN
      Samples/Sponza/Assets/skinFace_normal.ankitex
  89. BIN
      Samples/Sponza/Assets/sponza_arch_ddn.ankitex
  90. BIN
      Samples/Sponza/Assets/sponza_arch_ddn.ankitex.ankitex
  91. BIN
      Samples/Sponza/Assets/sponza_arch_diff.ankitex
  92. BIN
      Samples/Sponza/Assets/sponza_arch_diff.ankitex.ankitex
  93. BIN
      Samples/Sponza/Assets/sponza_arch_spec.ankitex
  94. BIN
      Samples/Sponza/Assets/sponza_arch_spec.ankitex.ankitex
  95. BIN
      Samples/Sponza/Assets/sponza_bricks_a_ddn.ankitex.ankitex
  96. BIN
      Samples/Sponza/Assets/sponza_bricks_a_diff.ankitex.ankitex
  97. BIN
      Samples/Sponza/Assets/sponza_ceiling_a_diff.ankitex.ankitex
  98. BIN
      Samples/Sponza/Assets/sponza_column_a_ddn.ankitex.ankitex
  99. BIN
      Samples/Sponza/Assets/sponza_column_a_diff.ankitex.ankitex
  100. BIN
      Samples/Sponza/Assets/sponza_column_a_spec.ankitex.ankitex

+ 1 - 1
AnKi/Core/App.cpp

@@ -29,7 +29,7 @@
 #include <AnKi/Resource/ResourceFilesystem.h>
 #include <AnKi/Resource/AsyncLoader.h>
 #include <AnKi/Ui/UiManager.h>
-#include <AnKi/Ui/Canvas.h>
+#include <AnKi/Ui/UiCanvas.h>
 #include <AnKi/Scene/DeveloperConsoleUiNode.h>
 #include <csignal>
 

+ 0 - 1
AnKi/Core/App.h

@@ -11,7 +11,6 @@
 #include <AnKi/Util/Ptr.h>
 #include <AnKi/Util/System.h>
 #include <AnKi/Util/Functions.h>
-#include <AnKi/Ui/UiImmediateModeBuilder.h>
 
 namespace anki {
 

+ 8 - 10
AnKi/Editor/EditorUi.cpp

@@ -9,13 +9,15 @@
 
 namespace anki {
 
-void EditorUi::draw(Canvas& canvas)
+void EditorUi::draw(UiCanvas& canvas)
 {
-	if(m_font)
+	if(!m_font)
 	{
-		canvas.pushFont(m_font.get(), 20);
+		m_font = canvas.addFont("EngineAssets/UbuntuRegular.ttf");
 	}
 
+	ImGui::PushFont(m_font, 20);
+
 	const Vec4 oldWindowColor = ImGui::GetStyle().Colors[ImGuiCol_WindowBg];
 	ImGui::GetStyle().Colors[ImGuiCol_WindowBg].w = 0.0f;
 
@@ -33,15 +35,11 @@ void EditorUi::draw(Canvas& canvas)
 
 	ImGui::End();
 
-	if(m_font)
-	{
-		canvas.popFont();
-	}
-
+	ImGui::PopFont();
 	m_firstBuild = false;
 }
 
-void EditorUi::buildMainMenu(Canvas& canvas)
+void EditorUi::buildMainMenu(UiCanvas& canvas)
 {
 	if(ImGui::BeginMainMenuBar())
 	{
@@ -107,7 +105,7 @@ void EditorUi::buildSceneNode(SceneNode& node)
 #endif
 }
 
-void EditorUi::buildSceneHierarchyWindow(Canvas& canvas)
+void EditorUi::buildSceneHierarchyWindow(UiCanvas& canvas)
 {
 	if(m_firstBuild)
 	{

+ 4 - 12
AnKi/Editor/EditorUi.h

@@ -20,18 +20,10 @@ class EditorUi
 public:
 	Bool m_quit = false;
 
-	EditorUi()
-	{
-		if(UiManager::getSingleton().newFont("EngineAssets/UbuntuRegular.ttf", Array<U32, 3>{12, 16, 20}, m_font))
-		{
-			// Ignore
-		}
-	}
-
-	void draw(Canvas& canvas);
+	void draw(UiCanvas& canvas);
 
 private:
-	FontPtr m_font;
+	ImFont* m_font = nullptr;
 
 	F32 m_menuHeight = 0.0f;
 	Bool m_firstBuild = true;
@@ -45,9 +37,9 @@ private:
 		SceneNode* m_visibleNode;
 	} m_sceneHierarchyWindow;
 
-	void buildMainMenu(Canvas& canvas);
+	void buildMainMenu(UiCanvas& canvas);
 
-	void buildSceneHierarchyWindow(Canvas& canvas);
+	void buildSceneHierarchyWindow(UiCanvas& canvas);
 	void buildSceneNode(SceneNode& node);
 };
 /// @}

+ 1 - 1
AnKi/Gr/CommandBuffer.h

@@ -316,7 +316,7 @@ public:
 	void clearTexture(const TextureView& texView, const ClearValue& clearValue);
 
 	/// Copy a buffer to a texture surface or volume.
-	void copyBufferToTexture(const BufferView& buff, const TextureView& texView);
+	void copyBufferToTexture(const BufferView& buff, const TextureView& texView, const TextureRect& rect = TextureRect());
 
 	/// Fill a buffer with zeros. It's a copy operation.
 	void zeroBuffer(const BufferView& buff);

+ 11 - 1
AnKi/Gr/Common.h

@@ -21,7 +21,6 @@ class GrObject;
 class GrManager;
 class GrManagerImpl;
 class TextureInitInfo;
-class TextureViewInitInfo;
 class SamplerInitInfo;
 class GrManagerInitInfo;
 class FramebufferInitInfo;
@@ -1107,6 +1106,17 @@ public:
 	}
 };
 
+class TextureRect
+{
+public:
+	U32 m_offsetX = 0;
+	U32 m_offsetY = 0;
+	U32 m_offsetZ = 0;
+	U32 m_width = kMaxU32;
+	U32 m_height = kMaxU32;
+	U32 m_depth = kMaxU32;
+};
+
 /// Compute max number of mipmaps for a 2D texture.
 U8 computeMaxMipmapCount2d(U32 w, U32 h, U32 minSizeOfLastMip = 1);
 

+ 7 - 6
AnKi/Gr/D3D/D3DCommandBuffer.cpp

@@ -704,7 +704,7 @@ void CommandBuffer::clearTexture([[maybe_unused]] const TextureView& texView, [[
 	ANKI_ASSERT(!"TODO");
 }
 
-void CommandBuffer::copyBufferToTexture(const BufferView& buff, const TextureView& texView)
+void CommandBuffer::copyBufferToTexture(const BufferView& buff, const TextureView& texView, const TextureRect& rect)
 {
 	ANKI_D3D_SELF(CommandBufferImpl);
 
@@ -713,10 +713,11 @@ void CommandBuffer::copyBufferToTexture(const BufferView& buff, const TextureVie
 	const BufferImpl& buffImpl = static_cast<const BufferImpl&>(buff.getBuffer());
 	const TextureImpl& texImpl = static_cast<const TextureImpl&>(texView.getTexture());
 
-	const U32 width = texImpl.getWidth() >> texView.getFirstMipmap();
-	const U32 height = texImpl.getHeight() >> texView.getFirstMipmap();
-	const U32 depth = (texImpl.getTextureType() == TextureType::k3D) ? (texImpl.getDepth() >> texView.getFirstMipmap()) : 1u;
-	ANKI_ASSERT(width && height && depth);
+	const U32 width = (rect.m_width != kMaxU32) ? rect.m_width : texImpl.getWidth() >> texView.getFirstMipmap();
+	const U32 height = (rect.m_height != kMaxU32) ? rect.m_height : texImpl.getHeight() >> texView.getFirstMipmap();
+	const U32 depth = (texImpl.getTextureType() == TextureType::k3D)
+						  ? ((rect.m_depth != kMaxU32) ? rect.m_depth : texImpl.getDepth() >> texView.getFirstMipmap())
+						  : 1u;
 
 	const FormatInfo& formatInfo = getFormatInfo(texImpl.getFormat());
 
@@ -735,7 +736,7 @@ void CommandBuffer::copyBufferToTexture(const BufferView& buff, const TextureVie
 	dstLocation.pResource = &texImpl.getD3DResource();
 	dstLocation.SubresourceIndex = texImpl.calcD3DSubresourceIndex(texView.getSubresource());
 
-	self.m_cmdList->CopyTextureRegion(&dstLocation, 0, 0, 0, &srcLocation, nullptr);
+	self.m_cmdList->CopyTextureRegion(&dstLocation, rect.m_offsetX, rect.m_offsetY, rect.m_offsetZ, &srcLocation, nullptr);
 }
 
 void CommandBuffer::zeroBuffer(const BufferView& buff)

+ 1 - 1
AnKi/Gr/D3D/D3DGrManager.cpp

@@ -318,7 +318,7 @@ void GrManagerImpl::submitInternal(WeakArray<CommandBuffer*> cmdbs, WeakArray<Fe
 
 	if(fencesThrottled)
 	{
-		ANKI_D3D_LOGW("Had to throttle the number of fences");
+		ANKI_D3D_LOGV("Had to throttle the number of fences");
 	}
 }
 

+ 6 - 6
AnKi/Gr/Vulkan/VkCommandBuffer.cpp

@@ -745,7 +745,7 @@ void CommandBuffer::clearTexture(const TextureView& texView, const ClearValue& c
 	}
 }
 
-void CommandBuffer::copyBufferToTexture(const BufferView& buff, const TextureView& texView)
+void CommandBuffer::copyBufferToTexture(const BufferView& buff, const TextureView& texView, const TextureRect& rect)
 {
 	ANKI_TRACE_FUNCTION();
 	ANKI_ASSERT(buff.isValid());
@@ -760,10 +760,10 @@ void CommandBuffer::copyBufferToTexture(const BufferView& buff, const TextureVie
 	const VkImageSubresourceRange range = tex.computeVkImageSubresourceRange(texView.getSubresource());
 
 	// Compute the sizes of the mip
-	const U32 width = tex.getWidth() >> range.baseMipLevel;
-	const U32 height = tex.getHeight() >> range.baseMipLevel;
-	ANKI_ASSERT(width && height);
-	const U32 depth = (tex.getTextureType() == TextureType::k3D) ? (tex.getDepth() >> range.baseMipLevel) : 1u;
+	const U32 width = (rect.m_width != kMaxU32) ? rect.m_width : tex.getWidth() >> range.baseMipLevel;
+	const U32 height = (rect.m_height != kMaxU32) ? rect.m_height : tex.getHeight() >> range.baseMipLevel;
+	const U32 depth =
+		(tex.getTextureType() == TextureType::k3D) ? ((rect.m_depth != kMaxU32) ? rect.m_depth : tex.getDepth() >> range.baseMipLevel) : 1u;
 
 	if(tex.getTextureType() != TextureType::k3D)
 	{
@@ -780,7 +780,7 @@ void CommandBuffer::copyBufferToTexture(const BufferView& buff, const TextureVie
 	region.imageSubresource.baseArrayLayer = range.baseArrayLayer;
 	region.imageSubresource.layerCount = 1;
 	region.imageSubresource.mipLevel = range.baseMipLevel;
-	region.imageOffset = {0, 0, 0};
+	region.imageOffset = {I32(rect.m_offsetX), I32(rect.m_offsetY), I32(rect.m_offsetZ)};
 	region.imageExtent.width = width;
 	region.imageExtent.height = height;
 	region.imageExtent.depth = depth;

+ 1 - 1
AnKi/Gr/Vulkan/VkGrManager.cpp

@@ -1514,7 +1514,7 @@ void GrManagerImpl::submitInternal(WeakArray<CommandBuffer*> cmdbs, WeakArray<Fe
 
 		if(fencesThrottled)
 		{
-			ANKI_VK_LOGW("Had to throttle the number of fences");
+			ANKI_VK_LOGV("Had to throttle the number of fences");
 		}
 	}
 }

+ 7 - 4
AnKi/Importer/ImageImporter.cpp

@@ -362,21 +362,24 @@ static Vec4 computeAverageColor(WeakArray<TVec> pixels)
 {
 	Vec4 average(0.0f);
 	const F32 weight = 1.0f / F32(pixels.getSize());
+	constexpr Bool unorm = sizeof(pixels[0][0]) == 1;
+	constexpr U32 componentCount = TVec::kComponentCount;
+	static_assert(componentCount == 3 || componentCount == 4);
 
 	for(const TVec& color : pixels)
 	{
 		Vec4 v;
-		if constexpr(TVec::kComponentCount == 3)
+		if constexpr(componentCount == 3)
 		{
 			v = Vec4(Vec3(color), 0.0f);
 		}
 		else
 		{
-			ANKI_ASSERT(TVec::kComponentCount == 4);
+			ANKI_ASSERT(componentCount == 4);
 			v = Vec4(color);
 		}
 
-		if(sizeof(color[0]) == 1)
+		if(unorm)
 		{
 			v /= 255.0f;
 		}
@@ -388,7 +391,7 @@ static Vec4 computeAverageColor(WeakArray<TVec> pixels)
 		average += v * weight;
 	}
 
-	return average;
+	return (componentCount == 3) ? average.xyz1() : average;
 }
 
 static void applyScaleAndBias(WeakArray<Vec3> pixels, Vec3 scale, Vec3 bias)

+ 3 - 1
AnKi/Renderer/FinalComposite.cpp

@@ -132,6 +132,8 @@ void FinalComposite::populateRenderGraph(RenderingContext& ctx)
 		}
 	}
 
+	getUiStage().setDependencies(pass);
+
 	pass.setWork([this](RenderPassWorkContext& rgraphCtx) {
 		ANKI_TRACE_SCOPED_EVENT(FinalComposite);
 
@@ -212,7 +214,7 @@ void FinalComposite::populateRenderGraph(RenderingContext& ctx)
 		const Bool bRendersToSwapchain = getRenderer().getSwapchainResolution() == getRenderer().getPostProcessResolution();
 		if(bRendersToSwapchain)
 		{
-			getRenderer().getUiStage().draw(getRenderer().getPostProcessResolution().x(), getRenderer().getPostProcessResolution().y(), cmdb);
+			getRenderer().getUiStage().drawUi(cmdb);
 		}
 	});
 }

+ 6 - 1
AnKi/Renderer/Renderer.cpp

@@ -355,6 +355,7 @@ Error Renderer::populateRenderGraph(RenderingContext& ctx)
 	m_motionBlur->populateRenderGraph(ctx);
 	m_bloom2->populateRenderGraph(ctx);
 	m_dbg->populateRenderGraph(ctx);
+	m_uiStage->populateRenderGraph(ctx);
 
 	m_finalComposite->populateRenderGraph(ctx);
 
@@ -775,6 +776,8 @@ Error Renderer::render()
 	// First thing, reset the temp mem pool
 	m_framePool.reset();
 
+	m_uiStage->buildUiAsync();
+
 	RenderingContext ctx(&m_framePool);
 	ctx.m_renderGraphDescr.setStatisticsEnabled(ANKI_STATS_ENABLED);
 
@@ -844,6 +847,8 @@ Error Renderer::render()
 		pass.newTextureDependency(ctx.m_swapchainRenderTarget, TextureUsageBit::kRtvDsvWrite);
 		pass.newTextureDependency(m_finalComposite->getRenderTarget(), TextureUsageBit::kSrvPixel);
 
+		m_uiStage->setDependencies(pass);
+
 		pass.setWork([this](RenderPassWorkContext& rgraphCtx) {
 			ANKI_TRACE_SCOPED_EVENT(BlitAndUi);
 			CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
@@ -856,7 +861,7 @@ Error Renderer::render()
 			cmdb.draw(PrimitiveTopology::kTriangles, 3);
 
 			// Draw the UI
-			m_uiStage->draw(m_swapchainResolution.x(), m_swapchainResolution.y(), cmdb);
+			m_uiStage->drawUi(cmdb);
 		});
 	}
 

+ 2 - 2
AnKi/Renderer/TemporalUpscaler.cpp

@@ -24,14 +24,14 @@ Error TemporalUpscaler::init()
 		return Error::kNone;
 	}
 
-	if(GrManager::getSingleton().getDeviceCapabilities().m_dlss)
+	if(GrManager::getSingleton().getDeviceCapabilities().m_dlss && g_cvarRenderDlss)
 	{
 
 		GrUpscalerInitInfo inf;
 		inf.m_sourceTextureResolution = getRenderer().getInternalResolution();
 		inf.m_targetTextureResolution = getRenderer().getPostProcessResolution();
 		inf.m_upscalerType = GrUpscalerType::kDlss2;
-		inf.m_qualityMode = GrUpscalerQualityMode(g_cvarRenderDlssQuality - 1);
+		inf.m_qualityMode = GrUpscalerQualityMode(U32(g_cvarRenderDlssQuality));
 
 		m_grUpscaler = GrManager::getSingleton().newGrUpscaler(inf);
 	}

+ 2 - 2
AnKi/Renderer/TemporalUpscaler.h

@@ -11,8 +11,8 @@ namespace anki {
 
 /// @addtogroup renderer
 /// @{
-
-ANKI_CVAR(NumericCVar<U8>, Render, DlssQuality, 2, 0, 3, "0: Disabled, 1: Performance, 2: Balanced, 3: Quality")
+ANKI_CVAR(BoolCVar, Render, Dlss, true, "Enable or disable DLSS")
+ANKI_CVAR(NumericCVar<U8>, Render, DlssQuality, 1, 0, 3, "0: Performance, 1: Balanced, 2: Quality")
 
 /// Upscales.
 class TemporalUpscaler : public RendererObject

+ 68 - 16
AnKi/Renderer/UiStage.cpp

@@ -5,7 +5,6 @@
 
 #include <AnKi/Renderer/UiStage.h>
 #include <AnKi/Renderer/Renderer.h>
-#include <AnKi/Ui/Font.h>
 #include <AnKi/Ui/UiManager.h>
 #include <AnKi/Scene/Components/UiComponent.h>
 #include <AnKi/Scene/SceneGraph.h>
@@ -15,14 +14,13 @@ namespace anki {
 
 Error UiStage::init()
 {
-	ANKI_CHECK(UiManager::getSingleton().newFont("EngineAssets/UbuntuRegular.ttf", Array<U32, 3>{12, 16, 20}, m_font));
-	ANKI_CHECK(UiManager::getSingleton().newCanvas(m_font.get(), 12, getRenderer().getPostProcessResolution().x(),
-												   getRenderer().getPostProcessResolution().y(), m_canvas));
+	ANKI_CHECK(
+		UiManager::getSingleton().newCanvas(getRenderer().getPostProcessResolution().x(), getRenderer().getPostProcessResolution().y(), m_canvas));
 
 	return Error::kNone;
 }
 
-void UiStage::draw(U32 width, U32 height, CommandBuffer& cmdb)
+void UiStage::buildUiAsync()
 {
 	if(SceneGraph::getSingleton().getComponentArrays().getUis().getSize() == 0)
 	{
@@ -30,23 +28,77 @@ void UiStage::draw(U32 width, U32 height, CommandBuffer& cmdb)
 		return;
 	}
 
-	ANKI_TRACE_SCOPED_EVENT(Ui);
+	CoreThreadJobManager::getSingleton().dispatchTask([this]([[maybe_unused]] U32 tid) {
+		ANKI_TRACE_SCOPED_EVENT(UiBuild);
+
+		m_canvas->handleInput();
+		m_canvas->beginBuilding();
+		m_canvas->resize(getRenderer().getSwapchainResolution().x(), getRenderer().getSwapchainResolution().y());
+
+		for(UiComponent& comp : SceneGraph::getSingleton().getComponentArrays().getUis())
+		{
+			comp.drawUi(*m_canvas);
+		}
+
+		m_canvas->endBuilding();
+	});
+}
+
+void UiStage::populateRenderGraph(RenderingContext& ctx)
+{
+	// Create a pass that uploads UI textures
+
+	RenderGraphBuilder& rgraph = ctx.m_renderGraphDescr;
+	DynamicArray<RenderTargetHandle, MemoryPoolPtrWrapper<StackMemoryPool>> texHandles(&getRenderer().getFrameMemoryPool());
 
-	m_canvas->handleInput();
-	m_canvas->beginBuilding();
-	m_canvas->resize(width, height);
+	// Wait for the async task
+	CoreThreadJobManager::getSingleton().waitForAllTasksToFinish();
 
-	for(UiComponent& comp : SceneGraph::getSingleton().getComponentArrays().getUis())
+	m_canvas->visitTexturesForUpdate([&](Texture& tex, Bool isNew) {
+		const RenderTargetHandle handle = rgraph.importRenderTarget(&tex, (isNew) ? TextureUsageBit::kNone : TextureUsageBit::kSrvPixel);
+		texHandles.emplaceBack(handle);
+	});
+
+	if(texHandles.getSize() == 0) [[likely]]
 	{
-		comp.drawUi(*m_canvas);
+		m_runCtx.m_handles = {};
+		return;
 	}
 
-	m_canvas->appendToCommandBuffer(cmdb);
+	texHandles.moveAndReset(m_runCtx.m_handles);
 
-	// UI messes with the state, restore it
-	cmdb.setBlendFactors(0, BlendFactor::kOne, BlendFactor::kZero);
-	cmdb.setBlendOperation(0, BlendOperation::kAdd);
-	cmdb.setCullMode(FaceSelectionBit::kBack);
+	NonGraphicsRenderPass& pass = rgraph.newNonGraphicsRenderPass("UI copies");
+
+	for(RenderTargetHandle handle : m_runCtx.m_handles)
+	{
+		pass.newTextureDependency(handle, TextureUsageBit::kCopyDestination);
+	}
+
+	pass.setWork([this](RenderPassWorkContext& rgraphCtx) {
+		ANKI_TRACE_SCOPED_EVENT(UiCopies);
+		CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
+		m_canvas->appendNonGraphicsCommands(cmdb);
+	});
+}
+
+void UiStage::setDependencies(RenderPassBase& pass)
+{
+	for(RenderTargetHandle handle : m_runCtx.m_handles)
+	{
+		pass.newTextureDependency(handle, TextureUsageBit::kSrvPixel);
+	}
+}
+
+void UiStage::drawUi(CommandBuffer& cmdb)
+{
+	if(SceneGraph::getSingleton().getComponentArrays().getUis().getSize() == 0)
+	{
+		// Early exit
+		return;
+	}
+
+	ANKI_TRACE_SCOPED_EVENT(Ui);
+	m_canvas->appendGraphicsCommands(cmdb);
 }
 
 } // end namespace anki

+ 16 - 5
AnKi/Renderer/UiStage.h

@@ -6,8 +6,7 @@
 #pragma once
 
 #include <AnKi/Renderer/RendererObject.h>
-#include <AnKi/Ui/Canvas.h>
-#include <AnKi/Ui/Font.h>
+#include <AnKi/Ui/UiCanvas.h>
 
 namespace anki {
 
@@ -20,11 +19,23 @@ class UiStage : public RendererObject
 public:
 	Error init();
 
-	void draw(U32 width, U32 height, CommandBuffer& cmdb);
+	/// Need to wait the CoreThreadJobManager for that to finish and before calling the methods bellow.
+	void buildUiAsync();
+
+	void populateRenderGraph(RenderingContext& ctx);
+
+	void setDependencies(RenderPassBase& pass);
+
+	void drawUi(CommandBuffer& cmdb);
 
 private:
-	FontPtr m_font;
-	CanvasPtr m_canvas;
+	UiCanvasPtr m_canvas;
+
+	class
+	{
+	public:
+		WeakArray<RenderTargetHandle> m_handles;
+	} m_runCtx;
 };
 /// @}
 

+ 3 - 3
AnKi/Scene/Components/UiComponent.h

@@ -6,14 +6,14 @@
 #pragma once
 
 #include <AnKi/Scene/Components/SceneComponent.h>
-#include <AnKi/Ui/Canvas.h>
+#include <AnKi/Ui/UiCanvas.h>
 
 namespace anki {
 
 /// @addtogroup scene
 /// @{
 
-using UiQueueElementDrawCallback = void (*)(Canvas& canvas, void* userData);
+using UiQueueElementDrawCallback = void (*)(UiCanvas& canvas, void* userData);
 
 /// UI scene component.
 class UiComponent : public SceneComponent
@@ -38,7 +38,7 @@ public:
 		m_userData = userData;
 	}
 
-	void drawUi(Canvas& canvas)
+	void drawUi(UiCanvas& canvas)
 	{
 		if(m_drawCallback && m_enabled)
 		{

+ 9 - 6
AnKi/Scene/DeveloperConsoleUiNode.cpp

@@ -14,13 +14,11 @@ DeveloperConsoleUiNode::DeveloperConsoleUiNode(CString name)
 {
 	UiComponent* uic = newComponent<UiComponent>();
 	uic->init(
-		[](Canvas& canvas, void* ud) {
+		[](UiCanvas& canvas, void* ud) {
 			static_cast<DeveloperConsoleUiNode*>(ud)->draw(canvas);
 		},
 		this);
 	uic->setEnabled(false);
-
-	ANKI_CHECKF(UiManager::getSingleton().newFont("EngineAssets/UbuntuMonoRegular.ttf", Array<U32, 1>{16}, m_font));
 }
 
 DeveloperConsoleUiNode::~DeveloperConsoleUiNode()
@@ -90,11 +88,16 @@ void DeveloperConsoleUiNode::newLogItem(const LoggerMessageInfo& inf)
 	m_logItemsTimestamp.fetchAdd(1);
 }
 
-void DeveloperConsoleUiNode::draw(Canvas& canvas)
+void DeveloperConsoleUiNode::draw(UiCanvas& canvas)
 {
+	if(!m_font)
+	{
+		m_font = canvas.addFont("EngineAssets/UbuntuMonoRegular.ttf");
+	}
+
 	const Vec4 oldWindowColor = ImGui::GetStyle().Colors[ImGuiCol_WindowBg];
 	ImGui::GetStyle().Colors[ImGuiCol_WindowBg].w = 0.3f;
-	canvas.pushFont(m_font.get(), 16);
+	ImGui::PushFont(m_font, 16.0f);
 
 	ImGui::Begin("Console", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoTitleBar);
 
@@ -162,7 +165,7 @@ void DeveloperConsoleUiNode::draw(Canvas& canvas)
 
 	ImGui::End();
 	ImGui::GetStyle().Colors[ImGuiCol_WindowBg] = oldWindowColor;
-	canvas.popFont();
+	ImGui::PopFont();
 }
 
 } // end namespace anki

+ 3 - 3
AnKi/Scene/DeveloperConsoleUiNode.h

@@ -6,7 +6,7 @@
 #pragma once
 
 #include <AnKi/Scene/SceneNode.h>
-#include <AnKi/Ui/Canvas.h>
+#include <AnKi/Ui/UiCanvas.h>
 #include <AnKi/Script/ScriptEnvironment.h>
 
 namespace anki {
@@ -44,7 +44,7 @@ private:
 		LoggerMessageType m_type;
 	};
 
-	FontPtr m_font;
+	ImFont* m_font = nullptr;
 	IntrusiveList<LogItem> m_logItems;
 	U32 m_logItemCount = 0;
 	Array<Char, 256> m_inputText = {};
@@ -63,7 +63,7 @@ private:
 		static_cast<DeveloperConsoleUiNode*>(userData)->newLogItem(info);
 	}
 
-	void draw(Canvas& canvas);
+	void draw(UiCanvas& canvas);
 };
 /// @}
 

+ 9 - 7
AnKi/Scene/StatsUiNode.cpp

@@ -8,7 +8,6 @@
 #include <AnKi/Core/StatsSet.h>
 #include <AnKi/Core/App.h>
 #include <AnKi/Ui/UiManager.h>
-#include <AnKi/Ui/Font.h>
 #include <AnKi/Renderer/Renderer.h>
 
 namespace anki {
@@ -71,7 +70,7 @@ StatsUiNode::StatsUiNode(CString name)
 {
 	UiComponent* uic = newComponent<UiComponent>();
 	uic->init(
-		[](Canvas& canvas, void* ud) {
+		[](UiCanvas& canvas, void* ud) {
 			static_cast<StatsUiNode*>(ud)->draw(canvas);
 		},
 		this);
@@ -80,16 +79,19 @@ StatsUiNode::StatsUiNode(CString name)
 	{
 		m_averageValues.resize(StatsSet::getSingleton().getCounterCount());
 	}
-
-	ANKI_CHECKF(UiManager::getSingleton().newFont("EngineAssets/UbuntuMonoRegular.ttf", Array<U32, 1>{24}, m_font));
 }
 
 StatsUiNode::~StatsUiNode()
 {
 }
 
-void StatsUiNode::draw(Canvas& canvas)
+void StatsUiNode::draw(UiCanvas& canvas)
 {
+	if(!m_font)
+	{
+		m_font = canvas.addFont("EngineAssets/UbuntuMonoRegular.ttf");
+	}
+
 	Bool flush = false;
 	if(m_bufferedFrames == kBufferedFrames)
 	{
@@ -98,7 +100,7 @@ void StatsUiNode::draw(Canvas& canvas)
 	}
 	++m_bufferedFrames;
 
-	canvas.pushFont(m_font.get(), 24);
+	ImGui::PushFont(m_font, 24.0f);
 
 	const Vec4 oldWindowColor = ImGui::GetStyle().Colors[ImGuiCol_WindowBg];
 	ImGui::GetStyle().Colors[ImGuiCol_WindowBg].w = 0.3f;
@@ -166,7 +168,7 @@ void StatsUiNode::draw(Canvas& canvas)
 	ImGui::End();
 	ImGui::GetStyle().Colors[ImGuiCol_WindowBg] = oldWindowColor;
 
-	canvas.popFont();
+	ImGui::PopFont();
 }
 
 } // end namespace anki

+ 3 - 3
AnKi/Scene/StatsUiNode.h

@@ -6,7 +6,7 @@
 #pragma once
 
 #include <AnKi/Scene/SceneNode.h>
-#include <AnKi/Ui/Canvas.h>
+#include <AnKi/Ui/UiCanvas.h>
 
 namespace anki {
 
@@ -31,13 +31,13 @@ private:
 
 	static constexpr U32 kBufferedFrames = 30;
 
-	FontPtr m_font;
+	ImFont* m_font = nullptr;
 	Bool m_fpsOnly = false;
 
 	SceneDynamicArray<Value> m_averageValues;
 	U32 m_bufferedFrames = 0;
 
-	void draw(Canvas& canvas);
+	void draw(UiCanvas& canvas);
 };
 /// @}
 

+ 1 - 1
AnKi/Shaders/GBufferGeneric.ankiprog

@@ -618,7 +618,7 @@ GBufferPixelOut main(
 // ===========================================================================
 // RT Shadows                                                                =
 // ===========================================================================
-#if ANKI_TECHNIQUE_RtShadows
+#if NOT_ZERO(ANKI_TECHNIQUE_RtShadows)
 
 #	if ANKI_ANY_HIT_SHADER
 

+ 0 - 4
AnKi/Shaders/IndirectDiffuseClipmaps.ankiprog

@@ -136,11 +136,7 @@ ANKI_FAST_CONSTANTS(ProbeUpdateConsts, g_consts)
 	F32 rayT = 0.0;
 	Bool backfacing = false;
 #	if ANKI_COMPUTE_SHADER
-#		if ANKI_GR_BACKEND_VULKAN
 	const Bool hit = materialRayTraceInlineRt<F16>(probeWorldPos, dir, 0.0, tMax, 1000.0, gbuffer, rayT, backfacing);
-#		else
-	const Bool hit = false;
-#		endif
 #	else
 	const Bool hit = materialRayTrace<F16>(probeWorldPos, dir, 0.0, tMax, 1000.0, gbuffer, rayT, backfacing, traceFlags);
 #	endif

+ 1 - 0
AnKi/Shaders/Intellisense.hlsl

@@ -39,6 +39,7 @@
 #define ANKI_MISS_SHADER 1
 #define ANKI_CLOSEST_HIT_SHADER 1
 #define ANKI_RAY_GEN_SHADER 1
+#define ANKI_ANY_HIT_SHADER 1
 
 using I8 = int;
 using I16 = int;

+ 0 - 4
AnKi/Shaders/Reflections.ankiprog

@@ -747,12 +747,8 @@ vector<T, 3> getDiffuseIndirect(Vec3 worldPos, Vec3 worldNormal)
 	F32 rayT;
 	Bool unused;
 #	if ANKI_COMPUTE_SHADER
-#		if ANKI_GR_BACKEND_VULKAN
 	const Bool hasHitSky =
 		!materialRayTraceInlineRt(worldPos, reflDir, max(tmin + kTMinBias, 0.05), g_consts.m_maxRayT, textureLod, gbuffer, rayT, unused);
-#		else
-	const Bool hasHitSky = true;
-#		endif
 #	else
 	const Bool hasHitSky = !materialRayTrace(worldPos, reflDir, max(tmin + kTMinBias, 0.05), g_consts.m_maxRayT, textureLod, gbuffer, rayT, unused);
 #	endif

+ 6 - 3
AnKi/Shaders/RtMaterialFetch.hlsl

@@ -113,13 +113,16 @@ Bool materialRayTrace(Vec3 rayOrigin, Vec3 rayDir, F32 tMin, F32 tMax, T texture
 	return !hasHitSky;
 }
 
-#	if ANKI_GR_BACKEND_VULKAN
 template<typename T>
 Bool materialRayTraceInlineRt(Vec3 rayOrigin, Vec3 rayDir, F32 tMin, F32 tMax, T textureLod, out GBufferLight<T> gbuffer, out F32 rayT,
 							  out Bool backfacing)
 {
 	gbuffer = (GBufferLight<T>)0;
+	Bool hit = false;
+	rayT = -1.0;
+	backfacing = false;
 
+#	if ANKI_GR_BACKEND_VULKAN
 	RayQuery<RAY_FLAG_FORCE_OPAQUE> q;
 	const U32 cullMask = 0xFFu;
 	RayDesc ray;
@@ -131,7 +134,7 @@ Bool materialRayTraceInlineRt(Vec3 rayOrigin, Vec3 rayDir, F32 tMin, F32 tMax, T
 	while(q.Proceed())
 	{
 	}
-	const Bool hit = q.CommittedStatus() == COMMITTED_TRIANGLE_HIT;
+	hit = q.CommittedStatus() == COMMITTED_TRIANGLE_HIT;
 
 	if(!hit)
 	{
@@ -156,10 +159,10 @@ Bool materialRayTraceInlineRt(Vec3 rayOrigin, Vec3 rayDir, F32 tMin, F32 tMax, T
 
 		rayT = q.CommittedRayT();
 	}
+#	endif
 
 	return hit;
 }
-#	endif
 
 Bool rayVisibility(Vec3 rayOrigin, Vec3 rayDir, F32 tMax, U32 traceFlags)
 {

+ 1 - 3
AnKi/Ui.h

@@ -8,6 +8,4 @@
 /// @defgroup ui User interface that is using the ImGUI library.
 
 #include <AnKi/Ui/UiManager.h>
-#include <AnKi/Ui/Font.h>
-#include <AnKi/Ui/UiImmediateModeBuilder.h>
-#include <AnKi/Ui/Canvas.h>
+#include <AnKi/Ui/UiCanvas.h>

+ 0 - 17
AnKi/Ui/Common.cpp

@@ -1,17 +0,0 @@
-// Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include <AnKi/Ui/Common.h>
-#include <AnKi/Ui/UiObject.h>
-
-namespace anki {
-
-void UiObjectDeleter::operator()(UiObject* x)
-{
-	x->~UiObject();
-	UiMemoryPool::getSingleton().free(x);
-}
-
-} // end namespace anki

+ 22 - 58
AnKi/Ui/Common.h

@@ -17,7 +17,6 @@ namespace anki {
 // Forward
 class UiManager;
 class GrManager;
-class UiObject;
 
 /// @addtogroup ui
 /// @{
@@ -43,75 +42,40 @@ private:
 
 ANKI_DEFINE_SUBMODULE_UTIL_CONTAINERS(Ui, UiMemoryPool)
 
-class UiObjectDeleter
+/// The base of all UI objects.
+class UiObject
 {
 public:
-	void operator()(UiObject* x);
-};
-
-#define ANKI_UI_OBJECT_FW(className) \
-	class className; \
-	using className##Ptr = IntrusivePtr<className, UiObjectDeleter>;
-
-ANKI_UI_OBJECT_FW(Font)
-ANKI_UI_OBJECT_FW(Canvas)
-ANKI_UI_OBJECT_FW(UiImmediateModeBuilder)
-#undef ANKI_UI_OBJECT
-
-using UiObjectPtr = IntrusivePtr<UiObject, UiObjectDeleter>;
-
-inline Vec2 toAnki(const ImVec2& v)
-{
-	return Vec2(v.x, v.y);
-}
+	virtual ~UiObject() = default;
 
-/// This is extra data required by UiImageId.
-/// Since UiImageId needs to map to ImTextureID, UiImageId can only be a single pointer. Thus extra data required for
-/// custom drawing of that image need a different structure.
-class UiImageIdData
-{
-public:
-	TextureView m_textureView;
-	ShaderProgramPtr m_customProgram;
-	U8 m_extraFastConstantsSize = 0;
-	Array<U8, 64> m_extraFastConstants;
-	Bool m_pointSampling = false;
-
-	void setExtraFastConstants(const void* ptr, PtrSize fastConstantsSize)
+	void retain()
 	{
-		ANKI_ASSERT(ptr);
-		ANKI_ASSERT(fastConstantsSize > 0 && fastConstantsSize < sizeof(m_extraFastConstants));
-		m_extraFastConstantsSize = U8(fastConstantsSize);
-		memcpy(m_extraFastConstants.getBegin(), ptr, fastConstantsSize);
+		m_refcount.fetchAdd(1);
 	}
-};
 
-/// This is what someone should push to ImGui::Image() function.
-class UiImageId
-{
-	friend class Canvas;
-
-public:
-	/// Construct a complex UiImageId that points to an UiImageIdDAta structure. Someone else needs to own the data.
-	UiImageId(const UiImageIdData* data)
-		: m_data(data)
+	void release()
 	{
+		const U32 ref = m_refcount.fetchSub(1);
+		if(ref == 1)
+		{
+			deleteInstance(UiMemoryPool::getSingleton(), this);
+		}
 	}
 
-	operator void*() const
-	{
-		return const_cast<void*>(static_cast<const void*>(m_data));
-	}
+protected:
+	UiObject() = default;
 
 private:
-	const UiImageIdData* m_data = nullptr;
-
-	UiImageId(void* ptr)
-		: m_data(reinterpret_cast<const UiImageIdData*>(ptr))
-	{
-	}
+	Atomic<I32> m_refcount = {0};
 };
-static_assert(sizeof(UiImageId) == sizeof(void*), "See file");
+
+class UiCanvas;
+using UiCanvasPtr = IntrusiveNoDelPtr<UiCanvas>;
+
+inline Vec2 toAnki(const ImVec2& v)
+{
+	return Vec2(v.x, v.y);
+}
 /// @}
 
 } // end namespace anki

+ 0 - 107
AnKi/Ui/Font.cpp

@@ -1,107 +0,0 @@
-// Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include <AnKi/Ui/Font.h>
-#include <AnKi/Ui/UiManager.h>
-#include <AnKi/Resource/ResourceManager.h>
-#include <AnKi/Resource/ResourceFilesystem.h>
-#include <AnKi/Gr/GrManager.h>
-#include <AnKi/Gr/Buffer.h>
-#include <AnKi/Gr/Texture.h>
-#include <AnKi/Gr/CommandBuffer.h>
-#include <AnKi/Gr/ShaderProgram.h>
-
-namespace anki {
-
-Font::~Font()
-{
-	m_imFontAtlas.destroy();
-}
-
-Error Font::init(CString filename, ConstWeakArray<U32> fontHeights)
-{
-	m_imFontAtlas.construct();
-
-	// Load font in memory
-	ResourceFilePtr file;
-	ANKI_CHECK(ResourceFilesystem::getSingleton().openFile(filename, file));
-	m_fontData.resize(U32(file->getSize()));
-	ANKI_CHECK(file->read(&m_fontData[0], file->getSize()));
-
-	m_fonts.resize(fontHeights.getSize());
-
-	// Bake font
-	ImFontConfig cfg;
-	cfg.FontDataOwnedByAtlas = false;
-	U32 count = 0;
-	for(U32 height : fontHeights)
-	{
-		height = U32(F32(height) * g_cvarUiGlobalFontScale) + g_cvarUiGlobalFontBias;
-		cfg.SizePixels = F32(height);
-
-		m_fonts[count].m_imFont = m_imFontAtlas->AddFontFromMemoryTTF(&m_fontData[0], I32(m_fontData.getSize()), F32(height), &cfg);
-		m_fonts[count].m_height = height;
-		++count;
-	}
-
-	[[maybe_unused]] const Bool ok = m_imFontAtlas->Build();
-	ANKI_ASSERT(ok);
-
-	// Create the texture
-	U8* img;
-	int width, height;
-	m_imFontAtlas->GetTexDataAsRGBA32(&img, &width, &height);
-	createTexture(img, width, height);
-
-	return Error::kNone;
-}
-
-void Font::createTexture(const void* data, U32 width, U32 height)
-{
-	ANKI_ASSERT(data && width > 0 && height > 0);
-
-	// Create and populate the buffer
-	const U32 buffSize = width * height * 4;
-	BufferPtr buff = GrManager::getSingleton().newBuffer(BufferInitInfo(buffSize, BufferUsageBit::kCopySource, BufferMapAccessBit::kWrite, "UI"));
-	void* mapped = buff->map(0, buffSize, BufferMapAccessBit::kWrite);
-	memcpy(mapped, data, buffSize);
-	buff->flush(0, buffSize);
-	buff->unmap();
-
-	// Create the texture
-	TextureInitInfo texInit("Font");
-	texInit.m_width = width;
-	texInit.m_height = height;
-	texInit.m_format = Format::kR8G8B8A8_Unorm;
-	texInit.m_usage = TextureUsageBit::kCopyDestination | TextureUsageBit::kSrvPixel;
-	texInit.m_mipmapCount = 1; // No mips because it will appear blurry with trilinear filtering
-
-	m_tex = GrManager::getSingleton().newTexture(texInit);
-
-	// Create the whole texture view
-	m_imgData.m_textureView = TextureView(m_tex.get(), TextureSubresourceDesc::all());
-	m_imFontAtlas->SetTexID(UiImageId(&m_imgData));
-
-	// Do the copy
-	const TextureView firstMipView(m_tex.get(), TextureSubresourceDesc::firstSurface());
-
-	CommandBufferInitInfo cmdbInit;
-	cmdbInit.m_flags = CommandBufferFlag::kGeneralWork | CommandBufferFlag::kSmallBatch;
-	CommandBufferPtr cmdb = GrManager::getSingleton().newCommandBuffer(cmdbInit);
-
-	TextureBarrierInfo barrier = {firstMipView, TextureUsageBit::kNone, TextureUsageBit::kCopyDestination};
-	cmdb->setPipelineBarrier({&barrier, 1}, {}, {});
-
-	cmdb->copyBufferToTexture(BufferView(buff.get()), firstMipView);
-
-	barrier.m_previousUsage = TextureUsageBit::kCopyDestination;
-	barrier.m_nextUsage = TextureUsageBit::kSrvPixel;
-	cmdb->setPipelineBarrier({&barrier, 1}, {}, {});
-
-	cmdb->endRecording();
-	GrManager::getSingleton().submit(cmdb.get());
-}
-
-} // end namespace anki

+ 0 - 84
AnKi/Ui/Font.h

@@ -1,84 +0,0 @@
-// Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#pragma once
-
-#include <AnKi/Ui/UiObject.h>
-#include <AnKi/Gr/Texture.h>
-#include <AnKi/Util/ClassWrapper.h>
-#include <AnKi/Util/WeakArray.h>
-
-namespace anki {
-
-/// @addtogroup ui
-/// @{
-
-ANKI_CVAR(NumericCVar<U32>, Ui, GlobalFontBias, 0, 0, 100, "Bias that will be applied to all fonts")
-ANKI_CVAR(NumericCVar<F32>, Ui, GlobalFontScale, 1.0f, 0.1f, 100.0f, "Scale that will be applied to all fonts")
-
-/// Font class.
-class Font : public UiObject
-{
-	friend class UiManager;
-
-public:
-	Font() = default;
-
-	~Font();
-
-	/// Get font image atlas.
-	ANKI_INTERNAL const TexturePtr& getTexture() const
-	{
-		return m_tex;
-	}
-
-	ANKI_INTERNAL const ImFont& getImFont(U32 fontHeight) const
-	{
-		for(const FontEntry& f : m_fonts)
-		{
-			if(f.m_height == U32(F32(fontHeight) * g_cvarUiGlobalFontScale) + g_cvarUiGlobalFontBias)
-			{
-				return *f.m_imFont;
-			}
-		}
-
-		ANKI_ASSERT(0);
-		return *m_fonts[0].m_imFont;
-	}
-
-	ANKI_INTERNAL const ImFont& getFirstImFont() const
-	{
-		return *m_fonts[0].m_imFont;
-	}
-
-	ANKI_INTERNAL ImFontAtlas* getImFontAtlas()
-	{
-		return m_imFontAtlas.get();
-	}
-
-private:
-	ClassWrapper<ImFontAtlas> m_imFontAtlas;
-	UiDynamicArray<U8> m_fontData;
-
-	class FontEntry
-	{
-	public:
-		ImFont* m_imFont;
-		U32 m_height;
-	};
-
-	UiDynamicArray<FontEntry> m_fonts;
-
-	TexturePtr m_tex;
-	UiImageIdData m_imgData;
-
-	/// Initialize the font.
-	Error init(CString filename, ConstWeakArray<U32> fontHeights);
-
-	void createTexture(const void* data, U32 width, U32 height);
-};
-/// @}
-
-} // end namespace anki

+ 72 - 0
AnKi/Ui/ImGuiConfig.h

@@ -7,6 +7,8 @@
 
 #include <AnKi/Util/Assert.h>
 #include <AnKi/Math/Vec.h>
+#include <AnKi/Gr/Texture.h>
+#include <AnKi/Gr/ShaderProgram.h>
 
 #define IM_ASSERT(_EXPR) ANKI_ASSERT(_EXPR)
 
@@ -43,3 +45,73 @@ namespace anki {
 extern thread_local ImGuiContext* g_imguiTlsCtx;
 } // end namespace anki
 #define GImGui anki::g_imguiTlsCtx
+
+// ImTextureID
+namespace anki {
+struct AnKiImTextureID_Invalid
+{
+};
+
+/// Implements a custom ImTextureID
+class AnKiImTextureID
+{
+public:
+	Texture* m_texture = nullptr;
+	TextureSubresourceDesc m_textureSubresource = TextureSubresourceDesc::all();
+	ShaderProgram* m_customProgram = nullptr;
+	Array<U8, 64> m_extraFastConstants = {};
+	U8 m_extraFastConstantsSize = 0;
+	Bool m_pointSampling = false;
+	Bool m_textureIsRefcounted = false; ///< Only set for ImGui internal textures. Don't touch it.
+
+	AnKiImTextureID() = default;
+
+	AnKiImTextureID(const AnKiImTextureID& b) = default;
+
+	explicit AnKiImTextureID(AnKiImTextureID_Invalid)
+	{
+		*this = AnKiImTextureID();
+	}
+
+	AnKiImTextureID& operator=(AnKiImTextureID_Invalid)
+	{
+		*this = AnKiImTextureID();
+		return *this;
+	}
+
+	AnKiImTextureID& operator=(const AnKiImTextureID& b) = default;
+
+	Bool operator==(const AnKiImTextureID& b) const
+	{
+		return m_texture == b.m_texture;
+	}
+
+	Bool operator==(AnKiImTextureID_Invalid) const
+	{
+		return m_texture == nullptr;
+	}
+
+	Bool operator!=(AnKiImTextureID_Invalid) const
+	{
+		return m_texture != nullptr;
+	}
+
+	operator intptr_t() const
+	{
+		return intptr_t(this);
+	}
+
+	void setExtraFastConstants(const void* ptr, PtrSize fastConstantsSize)
+	{
+		ANKI_ASSERT(ptr);
+		ANKI_ASSERT(fastConstantsSize > 0 && fastConstantsSize < sizeof(m_extraFastConstants));
+		m_extraFastConstantsSize = U8(fastConstantsSize);
+		memcpy(m_extraFastConstants.getBegin(), ptr, fastConstantsSize);
+	}
+};
+
+static_assert(std::is_trivially_destructible_v<AnKiImTextureID>, "For some reason ImGui doesn't work otherwise");
+
+} // end namespace anki
+#define ImTextureID anki::AnKiImTextureID
+#define ImTextureID_Invalid anki::AnKiImTextureID_Invalid()

+ 192 - 96
AnKi/Ui/Canvas.cpp → AnKi/Ui/UiCanvas.cpp

@@ -3,14 +3,15 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#include <AnKi/Ui/Canvas.h>
-#include <AnKi/Ui/Font.h>
+#include <AnKi/Ui/UiCanvas.h>
 #include <AnKi/Ui/UiManager.h>
 #include <AnKi/Resource/ResourceManager.h>
 #include <AnKi/GpuMemory/RebarTransientMemoryPool.h>
 #include <AnKi/Window/Input.h>
 #include <AnKi/Gr/Sampler.h>
 #include <AnKi/Gr/GrManager.h>
+#include <AnKi/Gr/CommandBuffer.h>
+#include <AnKi/Resource/GenericResource.h>
 
 namespace anki {
 
@@ -59,9 +60,9 @@ static void setColorStyleAdia()
 	// Tabs
 	colors[ImGuiCol_Tab] = panelColor;
 	colors[ImGuiCol_TabHovered] = panelHoverColor;
-	colors[ImGuiCol_TabActive] = panelActiveColor;
-	colors[ImGuiCol_TabUnfocused] = panelColor;
-	colors[ImGuiCol_TabUnfocusedActive] = panelHoverColor;
+	colors[ImGuiCol_TabSelected] = panelActiveColor;
+	colors[ImGuiCol_TabDimmed] = panelColor;
+	colors[ImGuiCol_TabDimmedSelected] = panelHoverColor;
 
 	// Title
 	colors[ImGuiCol_TitleBg] = bgColor;
@@ -129,19 +130,26 @@ static void setColorStyleAdia()
 	style.ItemInnerSpacing = ImVec2(4.0f, 4.0f);
 }
 
-Canvas::~Canvas()
+UiCanvas::~UiCanvas()
 {
 	if(m_imCtx)
 	{
+		ImGui::SetCurrentContext(m_imCtx);
+		for(ImTextureData* tex : ImGui::GetPlatformIO().Textures)
+		{
+			ImTextureID it = tex->GetTexID();
+			ANKI_ASSERT(it.m_textureIsRefcounted);
+			TexturePtr pTex(it.m_texture);
+			it.m_texture->release();
+		}
+		ImGui::SetCurrentContext(nullptr);
+
 		ImGui::DestroyContext(m_imCtx);
 	}
 }
 
-Error Canvas::init(Font* font, U32 fontHeight, U32 width, U32 height)
+Error UiCanvas::init(U32 width, U32 height)
 {
-	ANKI_ASSERT(font);
-	m_font.reset(font);
-	m_dfltFontHeight = fontHeight;
 	resize(width, height);
 
 	// Create program
@@ -157,7 +165,7 @@ Error Canvas::init(Font* font, U32 fontHeight, U32 width, U32 height)
 	}
 
 	// Sampler
-	SamplerInitInfo samplerInit("Canvas");
+	SamplerInitInfo samplerInit("UiCanvas");
 	samplerInit.m_minMagFilter = SamplingFilter::kLinear;
 	samplerInit.m_mipmapFilter = SamplingFilter::kLinear;
 	samplerInit.m_addressing = SamplingAddressing::kRepeat;
@@ -168,46 +176,60 @@ Error Canvas::init(Font* font, U32 fontHeight, U32 width, U32 height)
 	m_nearestNearestRepeatSampler = GrManager::getSingleton().newSampler(samplerInit);
 
 	// Create the context
-	m_imCtx = ImGui::CreateContext(font->getImFontAtlas());
+	m_imCtx = ImGui::CreateContext(nullptr);
 	ImGui::SetCurrentContext(m_imCtx);
+
 	ImGui::GetIO().IniFilename = nullptr;
 	ImGui::GetIO().LogFilename = nullptr;
+	ImGui::GetIO().BackendFlags |= ImGuiBackendFlags_RendererHasTextures;
 	// ImGui::StyleColorsLight();
 	setColorStyleAdia();
 
-#define ANKI_HANDLE(ak, im) ImGui::GetIO().KeyMap[im] = static_cast<int>(ak);
-
-	ANKI_HANDLE(KeyCode::kTab, ImGuiKey_Tab)
-	ANKI_HANDLE(KeyCode::kLeft, ImGuiKey_LeftArrow)
-	ANKI_HANDLE(KeyCode::kRight, ImGuiKey_RightArrow)
-	ANKI_HANDLE(KeyCode::kUp, ImGuiKey_UpArrow)
-	ANKI_HANDLE(KeyCode::kDown, ImGuiKey_DownArrow)
-	ANKI_HANDLE(KeyCode::kPageUp, ImGuiKey_PageUp)
-	ANKI_HANDLE(KeyCode::kPageDown, ImGuiKey_PageDown)
-	ANKI_HANDLE(KeyCode::kHome, ImGuiKey_Home)
-	ANKI_HANDLE(KeyCode::kEnd, ImGuiKey_End)
-	ANKI_HANDLE(KeyCode::kInsert, ImGuiKey_Insert)
-	ANKI_HANDLE(KeyCode::kDelete, ImGuiKey_Delete)
-	ANKI_HANDLE(KeyCode::kBackspace, ImGuiKey_Backspace)
-	ANKI_HANDLE(KeyCode::kSpace, ImGuiKey_Space)
-	ANKI_HANDLE(KeyCode::kReturn, ImGuiKey_Enter)
-	// ANKI_HANDLE(KeyCode::RETURN2, ImGuiKey_Enter)
-	ANKI_HANDLE(KeyCode::kEscape, ImGuiKey_Escape)
-	ANKI_HANDLE(KeyCode::kA, ImGuiKey_A)
-	ANKI_HANDLE(KeyCode::kC, ImGuiKey_C)
-	ANKI_HANDLE(KeyCode::kV, ImGuiKey_V)
-	ANKI_HANDLE(KeyCode::kX, ImGuiKey_X)
-	ANKI_HANDLE(KeyCode::kY, ImGuiKey_Y)
-	ANKI_HANDLE(KeyCode::kZ, ImGuiKey_Z)
-
-#undef ANKI_HANDLE
+	m_defaultFont = addFont("EngineAssets/UbuntuRegular.ttf");
 
 	ImGui::SetCurrentContext(nullptr);
 
 	return Error::kNone;
 }
 
-void Canvas::handleInput()
+ImFont* UiCanvas::addFont(CString fname)
+{
+	ANKI_ASSERT(GImGui);
+	ImFont* font = nullptr;
+
+	auto it = m_fontCache.find(fname);
+	if(it != m_fontCache.getEnd())
+	{
+		font = (*it).m_font;
+	}
+	else
+	{
+		GenericResourcePtr rsrc;
+		if(ResourceManager::getSingleton().loadResource(fname, rsrc))
+		{
+			ANKI_UI_LOGE("Failed to add font. Will use the default one");
+			font = m_defaultFont;
+		}
+		else
+		{
+			ConstWeakArray<U8> data = rsrc->getData();
+
+			const F32 someFontSize = 13.0f; // Doesn't matter
+
+			ImFontConfig cfg;
+			cfg.FontDataOwnedByAtlas = false;
+			font = ImGui::GetIO().Fonts->AddFontFromMemoryTTF(const_cast<U8*>(data.getBegin()), data.getSize(), someFontSize, &cfg);
+			ANKI_ASSERT(font);
+
+			const FontCacheEntry entry = {font, rsrc};
+			m_fontCache.emplace(fname, entry);
+		}
+	}
+
+	return font;
+}
+
+void UiCanvas::handleInput()
 {
 	const Input& in = Input::getSingleton();
 
@@ -217,7 +239,7 @@ void Canvas::handleInput()
 
 	// Handle mouse
 	Array<U32, 4> viewport = {0, 0, m_width, m_height};
-	Vec2 mousePosf = in.getMousePosition() / 2.0f + 0.5f;
+	Vec2 mousePosf = in.getMousePositionNdc() / 2.0f + 0.5f;
 	mousePosf.y() = 1.0f - mousePosf.y();
 	const UVec2 mousePos(U32(mousePosf.x() * F32(viewport[2])), U32(mousePosf.y() * F32(viewport[3])));
 
@@ -227,42 +249,52 @@ void Canvas::handleInput()
 	io.MouseClicked[0] = in.getMouseButton(MouseButton::kLeft) == 1;
 	io.MouseDown[0] = in.getMouseButton(MouseButton::kLeft) > 0;
 
-	if(in.getMouseButton(MouseButton::kScrollUp) == 1)
+	if(in.getMouseButton(MouseButton::kScrollUp) > 0)
 	{
-		io.MouseWheel = F32(in.getMouseButton(MouseButton::kScrollUp));
+		io.AddMouseWheelEvent(0.0f, 1.0f);
 	}
-	else if(in.getMouseButton(MouseButton::kScrollDown) == 1)
+	else if(in.getMouseButton(MouseButton::kScrollDown) > 0)
 	{
-		io.MouseWheel = -F32(in.getMouseButton(MouseButton::kScrollDown));
+		io.AddMouseWheelEvent(0.0f, -1.0f);
 	}
 
-	io.KeyCtrl = (in.getKey(KeyCode::kLeftCtrl) || in.getKey(KeyCode::kRightCtrl));
+	// io.KeyCtrl = (in.getKey(KeyCode::kLeftCtrl) || in.getKey(KeyCode::kRightCtrl));
 
 // Handle keyboard
-#define ANKI_HANDLE(ak) io.KeysDown[int(ak)] = (in.getKey(ak) == 1);
-
-	ANKI_HANDLE(KeyCode::kTab)
-	ANKI_HANDLE(KeyCode::kLeft)
-	ANKI_HANDLE(KeyCode::kRight)
-	ANKI_HANDLE(KeyCode::kUp)
-	ANKI_HANDLE(KeyCode::kDown)
-	ANKI_HANDLE(KeyCode::kPageUp)
-	ANKI_HANDLE(KeyCode::kPageDown)
-	ANKI_HANDLE(KeyCode::kHome)
-	ANKI_HANDLE(KeyCode::kEnd)
-	ANKI_HANDLE(KeyCode::kInsert)
-	ANKI_HANDLE(KeyCode::kDelete)
-	ANKI_HANDLE(KeyCode::kBackspace)
-	ANKI_HANDLE(KeyCode::kSpace)
-	ANKI_HANDLE(KeyCode::kReturn)
-	// ANKI_HANDLE(KeyCode::RETURN2)
-	ANKI_HANDLE(KeyCode::kEscape)
-	ANKI_HANDLE(KeyCode::kA)
-	ANKI_HANDLE(KeyCode::kC)
-	ANKI_HANDLE(KeyCode::kV)
-	ANKI_HANDLE(KeyCode::kX)
-	ANKI_HANDLE(KeyCode::kY)
-	ANKI_HANDLE(KeyCode::kZ)
+#define ANKI_HANDLE(ak, imgui) \
+	if(in.getKey(ak) > 1) \
+	{ \
+		io.AddKeyEvent(imgui, true); \
+	} \
+	else if(in.getKey(ak) < 0) \
+	{ \
+		io.AddKeyEvent(imgui, false); \
+	}
+
+	ANKI_HANDLE(KeyCode::kTab, ImGuiKey_Tab)
+	ANKI_HANDLE(KeyCode::kLeft, ImGuiKey_LeftArrow)
+	ANKI_HANDLE(KeyCode::kRight, ImGuiKey_RightArrow)
+	ANKI_HANDLE(KeyCode::kUp, ImGuiKey_UpArrow)
+	ANKI_HANDLE(KeyCode::kDown, ImGuiKey_DownArrow)
+	ANKI_HANDLE(KeyCode::kPageUp, ImGuiKey_PageUp)
+	ANKI_HANDLE(KeyCode::kPageDown, ImGuiKey_PageDown)
+	ANKI_HANDLE(KeyCode::kHome, ImGuiKey_Home)
+	ANKI_HANDLE(KeyCode::kEnd, ImGuiKey_End)
+	ANKI_HANDLE(KeyCode::kInsert, ImGuiKey_Insert)
+	ANKI_HANDLE(KeyCode::kDelete, ImGuiKey_Delete)
+	ANKI_HANDLE(KeyCode::kBackspace, ImGuiKey_Backspace)
+	ANKI_HANDLE(KeyCode::kSpace, ImGuiKey_Space)
+	ANKI_HANDLE(KeyCode::kReturn, ImGuiKey_Enter)
+	// ANKI_HANDLE(KeyCode::RETURN2, ImGuiKey_Enter)
+	ANKI_HANDLE(KeyCode::kEscape, ImGuiKey_Escape)
+	ANKI_HANDLE(KeyCode::kA, ImGuiKey_A)
+	ANKI_HANDLE(KeyCode::kC, ImGuiKey_C)
+	ANKI_HANDLE(KeyCode::kV, ImGuiKey_V)
+	ANKI_HANDLE(KeyCode::kX, ImGuiKey_X)
+	ANKI_HANDLE(KeyCode::kY, ImGuiKey_Y)
+	ANKI_HANDLE(KeyCode::kZ, ImGuiKey_Z)
+	ANKI_HANDLE(KeyCode::kLeftCtrl, ImGuiKey_LeftCtrl)
+	ANKI_HANDLE(KeyCode::kRightCtrl, ImGuiKey_RightCtrl)
 
 #undef ANKI_HANDLE
 
@@ -272,7 +304,7 @@ void Canvas::handleInput()
 	ImGui::SetCurrentContext(nullptr);
 }
 
-void Canvas::beginBuilding()
+void UiCanvas::beginBuilding()
 {
 	ImGui::SetCurrentContext(m_imCtx);
 
@@ -281,30 +313,92 @@ void Canvas::beginBuilding()
 	io.DisplaySize = ImVec2(F32(m_width), F32(m_height));
 
 	ImGui::NewFrame();
-	ImGui::PushFont(&m_font->getImFont(m_dfltFontHeight));
 }
 
-void Canvas::pushFont(Font* font, U32 fontHeight)
+void UiCanvas::endBuilding()
 {
-	m_references.pushBack(UiObjectPtr(font));
-	ImGui::PushFont(&font->getImFont(fontHeight));
+	ImGui::Render();
+
+	// Create the new textures
+	m_texturesPendingUpload.destroy();
+	ImDrawData& drawData = *ImGui::GetDrawData();
+	if(drawData.Textures != nullptr)
+	{
+		for(ImTextureData* tex : *drawData.Textures)
+		{
+			if(tex->Status == ImTextureStatus_OK)
+			{
+				continue;
+			}
+
+			if(tex->Status == ImTextureStatus_WantCreate)
+			{
+				TextureInitInfo init("ImGui requested");
+				init.m_width = tex->Width;
+				init.m_height = tex->Height;
+				init.m_format = Format::kR8G8B8A8_Unorm;
+				init.m_usage = TextureUsageBit::kSrvPixel | TextureUsageBit::kCopyDestination;
+
+				TexturePtr aktex = GrManager::getSingleton().newTexture(init);
+				ImTextureID id;
+				id.m_texture = aktex.get();
+				id.m_texture->retain();
+				id.m_textureIsRefcounted = true;
+				tex->SetTexID(id);
+			}
+
+			if(tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates)
+			{
+				m_texturesPendingUpload.emplaceBack(std::pair(tex, tex->Status == ImTextureStatus_WantCreate));
+			}
+			else if(tex->Status == ImTextureStatus_Destroyed)
+			{
+				ImTextureID id = tex->GetTexID();
+				ANKI_ASSERT(id.m_textureIsRefcounted);
+
+				TexturePtr pTex(id.m_texture);
+				id.m_texture->release();
+			}
+			else
+			{
+				ANKI_ASSERT(0);
+			}
+
+			tex->Status = ImTextureStatus_OK;
+		}
+	}
+
+	ImGui::SetCurrentContext(nullptr);
 }
 
-void Canvas::appendToCommandBuffer(CommandBuffer& cmdb)
+void UiCanvas::appendNonGraphicsCommands(CommandBuffer& cmdb) const
 {
-	appendToCommandBufferInternal(cmdb);
+	for(const auto& pair : m_texturesPendingUpload)
+	{
+		const ImTextureData* tex = pair.first;
 
-	// Done
-	ImGui::SetCurrentContext(nullptr);
+		const UVec2 uploadOffset(tex->UpdateRect.x, tex->UpdateRect.y);
+		const UVec2 uploadSize(tex->UpdateRect.w, tex->UpdateRect.h);
+		const U32 uploadPitch = uploadSize.x() * U32(tex->BytesPerPixel);
+		const U32 copyBufferSize = uploadSize.y() * uploadPitch;
+
+		WeakArray<U8> mappedMem;
+		const BufferView copyBuffer = RebarTransientMemoryPool::getSingleton().allocateCopyBuffer(copyBufferSize, mappedMem);
+
+		for(U32 y = 0; y < uploadSize.y(); y++)
+		{
+			memcpy(&mappedMem[uploadPitch * y], tex->GetPixelsAt(uploadOffset.x(), uploadOffset.y() + y), uploadPitch);
+		}
 
-	m_references.destroy();
+		cmdb.copyBufferToTexture(copyBuffer, TextureView(tex->GetTexID().m_texture, TextureSubresourceDesc::all()),
+								 {uploadOffset.x(), uploadOffset.y(), 0, uploadSize.x(), uploadSize.y(), 1});
+	}
 }
 
-void Canvas::appendToCommandBufferInternal(CommandBuffer& cmdb)
+void UiCanvas::appendGraphicsCommands(CommandBuffer& cmdb) const
 {
-	ImGui::PopFont();
-	ImGui::Render();
-	ImDrawData& drawData = *ImGui::GetDrawData();
+	ImGui::SetCurrentContext(m_imCtx);
+	const ImDrawData& drawData = *ImGui::GetDrawData();
 
 	// Allocate index and vertex buffers
 	BufferView vertsToken, indicesToken;
@@ -385,15 +479,15 @@ void Canvas::appendToCommandBufferInternal(CommandBuffer& cmdb)
 					// Apply scissor/clipping rectangle
 					cmdb.setScissor(U32(clipRect.x()), U32(clipRect.y()), U32(clipRect.z() - clipRect.x()), U32(clipRect.w() - clipRect.y()));
 
-					UiImageId id(pcmd.TextureId);
-					const UiImageIdData* data = id.m_data;
+					const ImTextureID texid = pcmd.GetTexID();
+					const Bool hasTexture = texid.m_texture != nullptr;
 
 					// Bind program
-					if(data && data->m_customProgram.isCreated())
+					if(hasTexture && texid.m_customProgram)
 					{
-						cmdb.bindShaderProgram(data->m_customProgram.get());
+						cmdb.bindShaderProgram(texid.m_customProgram);
 					}
-					else if(data && data->m_textureView.isValid())
+					else if(hasTexture)
 					{
 						cmdb.bindShaderProgram(m_grProgs[kRgbaTex].get());
 					}
@@ -403,10 +497,10 @@ void Canvas::appendToCommandBufferInternal(CommandBuffer& cmdb)
 					}
 
 					// Bindings
-					if(data && data->m_textureView.isValid())
+					if(hasTexture)
 					{
-						cmdb.bindSampler(0, 0, (data->m_pointSampling) ? m_nearestNearestRepeatSampler.get() : m_linearLinearRepeatSampler.get());
-						cmdb.bindSrv(0, 0, data->m_textureView);
+						cmdb.bindSampler(0, 0, (texid.m_pointSampling) ? m_nearestNearestRepeatSampler.get() : m_linearLinearRepeatSampler.get());
+						cmdb.bindSrv(0, 0, TextureView(texid.m_texture, texid.m_textureSubresource));
 					}
 
 					// Push constants
@@ -414,19 +508,19 @@ void Canvas::appendToCommandBufferInternal(CommandBuffer& cmdb)
 					{
 					public:
 						Vec4 m_transform;
-						Array<U8, sizeof(UiImageIdData::m_extraFastConstants)> m_extra;
+						Array<U8, sizeof(AnKiImTextureID::m_extraFastConstants)> m_extra;
 					} pc;
 					pc.m_transform.x() = 2.0f / drawData.DisplaySize.x;
 					pc.m_transform.y() = -2.0f / drawData.DisplaySize.y;
 					pc.m_transform.z() = (drawData.DisplayPos.x / drawData.DisplaySize.x) * 2.0f - 1.0f;
 					pc.m_transform.w() = -((drawData.DisplayPos.y / drawData.DisplaySize.y) * 2.0f - 1.0f);
 					U32 extraFastConstantsSize = 0;
-					if(data && data->m_extraFastConstantsSize)
+					if(hasTexture && texid.m_extraFastConstantsSize)
 					{
-						ANKI_ASSERT(data->m_extraFastConstantsSize <= sizeof(data->m_extraFastConstants));
-						memcpy(&pc.m_extra[0], data->m_extraFastConstants.getBegin(), data->m_extraFastConstantsSize);
+						ANKI_ASSERT(texid.m_extraFastConstantsSize <= sizeof(texid.m_extraFastConstants));
+						memcpy(&pc.m_extra[0], texid.m_extraFastConstants.getBegin(), texid.m_extraFastConstantsSize);
 
-						extraFastConstantsSize = data->m_extraFastConstantsSize;
+						extraFastConstantsSize = texid.m_extraFastConstantsSize;
 					}
 					cmdb.setFastConstants(&pc, sizeof(Vec4) + extraFastConstantsSize);
 
@@ -442,6 +536,8 @@ void Canvas::appendToCommandBufferInternal(CommandBuffer& cmdb)
 	// Restore state
 	cmdb.setBlendFactors(0, BlendFactor::kOne, BlendFactor::kZero);
 	cmdb.setCullMode(FaceSelectionBit::kBack);
+
+	ImGui::SetCurrentContext(nullptr);
 }
 
 } // end namespace anki

+ 28 - 22
AnKi/Ui/Canvas.h → AnKi/Ui/UiCanvas.h

@@ -5,9 +5,9 @@
 
 #pragma once
 
-#include <AnKi/Ui/UiObject.h>
-#include <AnKi/Gr/CommandBuffer.h>
+#include <AnKi/Ui/Common.h>
 #include <AnKi/Resource/ShaderProgramResource.h>
+#include <AnKi/Resource/GenericResource.h>
 #include <AnKi/Gr/Sampler.h>
 
 namespace anki {
@@ -16,19 +16,14 @@ namespace anki {
 /// @{
 
 /// UI canvas. It's more of a context.
-class Canvas : public UiObject
+class UiCanvas : public UiObject
 {
 	friend class UiManager;
 
 public:
-	Canvas() = default;
+	UiCanvas() = default;
 
-	~Canvas();
-
-	const FontPtr& getDefaultFont() const
-	{
-		return m_font;
-	}
+	~UiCanvas();
 
 	/// Resize canvas.
 	void resize(U32 width, U32 height)
@@ -50,27 +45,31 @@ public:
 
 	/// @name building commands. The order matters.
 	/// @{
-
-	/// Handle input.
 	virtual void handleInput();
 
-	/// Begin building the UI.
 	void beginBuilding();
 
-	void pushFont(Font* font, U32 fontHeight);
+	ImFont* addFont(CString fname);
+
+	void endBuilding();
 
-	void popFont()
+	template<typename TFunc>
+	void visitTexturesForUpdate(TFunc func)
 	{
-		ImGui::PopFont();
+		for(const auto& pair : m_texturesPendingUpload)
+		{
+			func(*pair.first->GetTexID().m_texture, pair.second);
+		}
 	}
 
-	void appendToCommandBuffer(CommandBuffer& cmdb);
+	void appendNonGraphicsCommands(CommandBuffer& cmdb) const;
+
+	void appendGraphicsCommands(CommandBuffer& cmdb) const;
 	/// @}
 
 private:
-	FontPtr m_font;
-	U32 m_dfltFontHeight = 0;
 	ImGuiContext* m_imCtx = nullptr;
+	ImFont* m_defaultFont = nullptr;
 	U32 m_width;
 	U32 m_height;
 
@@ -86,11 +85,18 @@ private:
 	SamplerPtr m_linearLinearRepeatSampler;
 	SamplerPtr m_nearestNearestRepeatSampler;
 
-	UiList<UiObjectPtr> m_references;
+	class FontCacheEntry
+	{
+	public:
+		ImFont* m_font = nullptr;
+		GenericResourcePtr m_resource;
+	};
+
+	UiHashMap<CString, FontCacheEntry> m_fontCache;
 
-	Error init(Font* font, U32 fontHeight, U32 width, U32 height);
+	UiDynamicArray<std::pair<const ImTextureData*, Bool>> m_texturesPendingUpload;
 
-	void appendToCommandBufferInternal(CommandBuffer& cmdb);
+	Error init(U32 width, U32 height);
 };
 /// @}
 

+ 0 - 32
AnKi/Ui/UiImmediateModeBuilder.h

@@ -1,32 +0,0 @@
-// Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#pragma once
-
-#include <AnKi/Ui/UiObject.h>
-
-namespace anki {
-
-/// @addtogroup ui
-/// @{
-
-/// An interface that just builds the UI.
-class UiImmediateModeBuilder : public UiObject
-{
-public:
-	UiImmediateModeBuilder() = default;
-
-	~UiImmediateModeBuilder() = default;
-
-	virtual void build(CanvasPtr ctx) = 0;
-
-	Error init() const
-	{
-		return Error::kNone;
-	}
-};
-/// @}
-
-} // end namespace anki

+ 4 - 19
AnKi/Ui/UiManager.cpp

@@ -4,8 +4,7 @@
 // http://www.anki3d.org/LICENSE
 
 #include <AnKi/Ui/UiManager.h>
-#include <AnKi/Ui/Font.h>
-#include <AnKi/Ui/Canvas.h>
+#include <AnKi/Ui/UiCanvas.h>
 
 namespace anki {
 
@@ -41,24 +40,10 @@ Error UiManager::init(AllocAlignedCallback allocCallback, void* allocCallbackDat
 	return Error::kNone;
 }
 
-Error UiManager::newFont(CString filename, ConstWeakArray<U32> fontHeights, FontPtr& font)
+Error UiManager::newCanvas(U32 width, U32 height, UiCanvasPtr& canvas)
 {
-	Font* pFont = newInstance<Font>(UiMemoryPool::getSingleton());
-	if(pFont->init(filename, fontHeights))
-	{
-		ANKI_UI_LOGE("Unable to create font");
-		deleteInstance(UiMemoryPool::getSingleton(), pFont);
-		return Error::kFunctionFailed;
-	}
-
-	font.reset(pFont);
-	return Error::kNone;
-}
-
-Error UiManager::newCanvas(Font* font, U32 fontHeight, U32 width, U32 height, CanvasPtr& canvas)
-{
-	Canvas* pCanvas = newInstance<Canvas>(UiMemoryPool::getSingleton());
-	if(pCanvas->init(font, fontHeight, width, height))
+	UiCanvas* pCanvas = newInstance<UiCanvas>(UiMemoryPool::getSingleton());
+	if(pCanvas->init(width, height))
 	{
 		ANKI_UI_LOGE("Unable to create canvas");
 		deleteInstance(UiMemoryPool::getSingleton(), pCanvas);

+ 1 - 3
AnKi/Ui/UiManager.h

@@ -21,9 +21,7 @@ class UiManager : public MakeSingleton<UiManager>
 public:
 	Error init(AllocAlignedCallback allocCallback, void* allocCallbackData);
 
-	Error newFont(CString filename, ConstWeakArray<U32> fontHeights, FontPtr& font);
-
-	Error newCanvas(Font* font, U32 fontHeight, U32 width, U32 height, CanvasPtr& canvas);
+	Error newCanvas(U32 initialWidth, U32 initialHeight, UiCanvasPtr& canvas);
 
 private:
 	UiManager();

+ 0 - 39
AnKi/Ui/UiObject.h

@@ -1,39 +0,0 @@
-// Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#pragma once
-
-#include <AnKi/Ui/Common.h>
-
-namespace anki {
-
-/// @addtogroup ui
-/// @{
-
-/// The base of all UI objects.
-class UiObject
-{
-public:
-	virtual ~UiObject() = default;
-
-	void retain() const
-	{
-		m_refcount.fetchAdd(1);
-	}
-
-	I32 release() const
-	{
-		return m_refcount.fetchSub(1);
-	}
-
-protected:
-	UiObject() = default;
-
-private:
-	mutable Atomic<I32> m_refcount = {0};
-};
-/// @}
-
-} // end namespace anki

+ 49 - 67
AnKi/Window/Input.h

@@ -31,78 +31,75 @@ class Input : public MakeSingletonPtr<Input>
 public:
 	Error init();
 
-	U32 getKey(KeyCode i) const
+	/// Shows the current key state
+	/// 0: Key resting
+	/// 1: Ley pressed once
+	/// >1: Kept pressed 'n' times continuously
+	/// <0: Key up
+	I32 getKey(KeyCode i) const
 	{
 		return m_keys[i];
 	}
 
-	U32 getMouseButton(MouseButton i) const
+	/// See getKey()
+	I32 getMouseButton(MouseButton i) const
 	{
 		return m_mouseBtns[i];
 	}
 
-	const Vec2& getMousePosition() const
+	const Vec2& getMousePositionNdc() const
 	{
 		return m_mousePosNdc;
 	}
 
-	const UVec2& getWindowMousePosition() const
+	const Vec2& getMousePreviousPositionNdc() const
 	{
-		return m_mousePosWin;
+		return m_prevMousePosNdc;
 	}
 
-	/// Get the times an event was triggered and resets the counter
-	U32 getEvent(InputEvent eventId) const
+	Vec2 getMouseMoveDeltaNdc() const
 	{
-		return m_events[eventId];
+		return m_mousePosNdc - m_prevMousePosNdc;
 	}
 
-	/// Reset the keys and mouse buttons
-	void reset()
+	/// Move the mouse cursor to a position inside the window. Useful for locking the cursor into a fixed location (eg in the center of the screen)
+	void moveMouseNdc(const Vec2& posNdc);
+
+	/// Lock mouse to (0, 0)
+	void lockMouseWindowCenter(Bool lock)
 	{
-		zeroMemory(m_keys);
-		zeroMemory(m_mouseBtns);
-		m_mousePosNdc = Vec2(-1.0f);
-		m_mousePosWin = UVec2(0u);
-		zeroMemory(m_events);
-		zeroMemory(m_textInput);
-		zeroMemory(m_touchPointers);
-		zeroMemory(m_touchPointerPosNdc);
-		zeroMemory(m_touchPointerPosWin);
+		m_lockCurs = lock;
 	}
 
-	/// Populate the key and button with the new state
-	Error handleEvents();
-
-	/// Move the mouse cursor to a position inside the window. Useful for locking the cursor into a fixed location (eg
-	/// in the center of the screen)
-	void moveCursor(const Vec2& posNdc);
-
 	/// Hide the mouse cursor
 	void hideCursor(Bool hide);
 
-	/// Lock mouse to (0, 0)
-	void lockCursor(Bool lock)
+	/// See getKey()
+	I32 getTouchPointer(TouchPointer p) const
 	{
-		m_lockCurs = lock;
+		return m_touchPointers[p];
 	}
 
+	Vec2 getTouchPointerNdcPosition(TouchPointer p) const
+	{
+		return m_touchPointerPosNdc[p];
+	}
+
+	Bool hasTouchDevice() const;
+
+	/// Populate the key and button with the new state
+	Error handleEvents();
+
 	/// Add a new event
 	void addEvent(InputEvent eventId)
 	{
 		++m_events[eventId];
 	}
 
-	template<typename TFunc>
-	void iteratePressedKeys(TFunc func) const
+	/// Get the times an event was triggered and resets the counter
+	U32 getEvent(InputEvent eventId) const
 	{
-		for(const KeyCode i : EnumIterable<KeyCode>())
-		{
-			if(m_keys[i] > 0)
-			{
-				func(i, m_keys[i]);
-			}
-		}
+		return m_events[eventId];
 	}
 
 	/// Get some easy to digest input from the keyboard.
@@ -111,43 +108,21 @@ public:
 		return &m_textInput[0];
 	}
 
-	U32 getTouchPointer(TouchPointer p) const
-	{
-		return m_touchPointers[p];
-	}
-
-	Vec2 getTouchPointerNdcPosition(TouchPointer p) const
-	{
-		return m_touchPointerPosNdc[p];
-	}
-
-	UVec2 getTouchPointerWindowPosition(TouchPointer p) const
-	{
-		return m_touchPointerPosWin[p];
-	}
-
-	Bool hasTouchDevice() const;
-
 protected:
-	/// Shows the current key state
-	/// - 0 times: unpressed
-	/// - 1 times: pressed once
-	/// - >1 times: Kept pressed 'n' times continuously
-	Array<U32, U(KeyCode::kCount)> m_keys;
+	Array<I32, U(KeyCode::kCount)> m_keys;
 
-	/// Mouse btns. Supporting 3 btns & wheel. @see keys
-	Array<U32, U(MouseButton::kCount)> m_mouseBtns;
+	Array<I32, U(MouseButton::kCount)> m_mouseBtns;
 	Vec2 m_mousePosNdc;
-	UVec2 m_mousePosWin;
+	Vec2 m_prevMousePosNdc;
 
-	Array<U32, U(TouchPointer::kCount)> m_touchPointers;
+	Array<I32, U(TouchPointer::kCount)> m_touchPointers;
 	Array<Vec2, U(TouchPointer::kCount)> m_touchPointerPosNdc;
-	Array<UVec2, U(TouchPointer::kCount)> m_touchPointerPosWin;
 
 	Array<U8, U(InputEvent::kCount)> m_events;
 
 	/// The keybord input as ascii.
-	Array<char, U(KeyCode::kCount)> m_textInput;
+	static constexpr U32 kMaxTexInput = 256;
+	Array<Char, kMaxTexInput> m_textInput;
 
 	Bool m_lockCurs = false;
 
@@ -156,8 +131,15 @@ protected:
 		reset();
 	}
 
-	virtual ~Input()
+	void reset()
 	{
+		zeroMemory(m_keys);
+		zeroMemory(m_mouseBtns);
+		m_mousePosNdc = m_prevMousePosNdc = Vec2(-1.0f);
+		zeroMemory(m_events);
+		zeroMemory(m_textInput);
+		zeroMemory(m_touchPointers);
+		zeroMemory(m_touchPointerPosNdc);
 	}
 };
 

+ 40 - 14
AnKi/Window/InputSdl.cpp

@@ -86,7 +86,7 @@ Error Input::handleEvents()
 	return self->handleEventsInternal();
 }
 
-void Input::moveCursor(const Vec2& pos)
+void Input::moveMouseNdc(const Vec2& pos)
 {
 	if(pos != m_mousePosNdc)
 	{
@@ -151,37 +151,52 @@ Error InputSdl::handleEventsInternal()
 	// add the times a key is being pressed
 	for(auto& k : m_keys)
 	{
-		if(k)
+		if(k > 0)
 		{
 			++k;
 		}
+		else if(k < 0)
+		{
+			k = 0;
+		}
 	}
 	for(auto& k : m_mouseBtns)
 	{
-		if(k)
+		if(k > 0)
 		{
 			++k;
 		}
+		else if(k < 0)
+		{
+			k = 0;
+		}
 	}
 
-	SDL_Event event;
-	KeyCode akkey;
+	m_prevMousePosNdc = m_mousePosNdc;
+
+	SDL_Event event = {};
+	KeyCode akkey = KeyCode::kCount;
 	if(!SDL_StartTextInput(static_cast<NativeWindowSdl&>(NativeWindow::getSingleton()).m_sdlWindow))
 	{
 		ANKI_WIND_LOGE("SDL_StartTextInput() failed: %s", SDL_GetError());
 	}
 
+	MouseButton scrollKeyEvent = MouseButton::kCount;
 	while(SDL_PollEvent(&event))
 	{
 		switch(event.type)
 		{
 		case SDL_EVENT_KEY_DOWN:
-			akkey = sdlKeytoAnKi(event.key.key);
-			m_keys[akkey] = 1;
+			// key.repeat adds a delay but we only want the 1st time the key is pressed
+			if(!event.key.repeat)
+			{
+				akkey = sdlKeytoAnKi(event.key.key);
+				m_keys[akkey] = 1;
+			}
 			break;
 		case SDL_EVENT_KEY_UP:
 			akkey = sdlKeytoAnKi(event.key.key);
-			m_keys[akkey] = 0;
+			m_keys[akkey] = -1;
 			break;
 		case SDL_EVENT_MOUSE_BUTTON_DOWN:
 		{
@@ -197,17 +212,18 @@ Error InputSdl::handleEventsInternal()
 			MouseButton mb = sdlMouseButtonToAnKi(event.button.button);
 			if(mb != MouseButton::kCount)
 			{
-				m_mouseBtns[mb] = 0;
+				m_mouseBtns[mb] = -1;
 			}
 			break;
 		}
 		case SDL_EVENT_MOUSE_WHEEL:
-			m_mouseBtns[MouseButton::kScrollUp] = event.wheel.y > 0.0f;
-			m_mouseBtns[MouseButton::kScrollDown] = event.wheel.y < 0.0f;
+		{
+			const MouseButton btn = (event.wheel.y > 0.0f) ? MouseButton::kScrollUp : MouseButton::kScrollDown;
+			m_mouseBtns[btn] = max(m_mouseBtns[btn] + 1, 1);
+			scrollKeyEvent = btn;
 			break;
+		}
 		case SDL_EVENT_MOUSE_MOTION:
-			m_mousePosWin.x() = U32(event.button.x);
-			m_mousePosWin.y() = U32(event.button.y);
 			m_mousePosNdc.x() = F32(event.button.x) / F32(NativeWindow::getSingleton().getWidth()) * 2.0f - 1.0f;
 			m_mousePosNdc.y() = -(F32(event.button.y) / F32(NativeWindow::getSingleton().getHeight()) * 2.0f - 1.0f);
 			break;
@@ -220,10 +236,20 @@ Error InputSdl::handleEventsInternal()
 		}
 	} // end while events
 
+	if(scrollKeyEvent != MouseButton::kScrollDown)
+	{
+		m_mouseBtns[MouseButton::kScrollDown] = (m_mouseBtns[MouseButton::kScrollDown] > 0) ? -1 : 0;
+	}
+
+	if(scrollKeyEvent != MouseButton::kScrollUp)
+	{
+		m_mouseBtns[MouseButton::kScrollUp] = (m_mouseBtns[MouseButton::kScrollUp] > 0) ? -1 : 0;
+	}
+
 	// Lock mouse
 	if(m_lockCurs)
 	{
-		moveCursor(Vec2(0.0));
+		moveMouseNdc(Vec2(0.0f));
 	}
 
 	return Error::kNone;

+ 16 - 16
Samples/Common/SampleApp.cpp

@@ -41,7 +41,7 @@ Error SampleApp::userMainLoop(Bool& quit, Second elapsedTime)
 	Renderer& renderer = Renderer::getSingleton();
 	Input& in = Input::getSingleton();
 
-	if(in.getKey(KeyCode::kEscape))
+	if(in.getKey(KeyCode::kEscape) > 0)
 	{
 		quit = true;
 		return Error::kNone;
@@ -125,11 +125,11 @@ Error SampleApp::userMainLoop(Bool& quit, Second elapsedTime)
 		g_cvarGrVrs = !g_cvarGrVrs;
 	}
 
-	static Vec2 mousePosOn1stClick = in.getMousePosition();
+	static Vec2 mousePosOn1stClick = in.getMousePositionNdc();
 	if(in.getMouseButton(MouseButton::kRight) == 1)
 	{
 		// Re-init mouse pos
-		mousePosOn1stClick = in.getMousePosition();
+		mousePosOn1stClick = in.getMousePositionNdc();
 	}
 
 	if(in.getKey(KeyCode::kF1) == 1)
@@ -159,7 +159,7 @@ Error SampleApp::userMainLoop(Bool& quit, Second elapsedTime)
 		g_cvarCoreTracingEnabled = !g_cvarCoreTracingEnabled;
 	}
 
-	if(in.getMouseButton(MouseButton::kRight) || in.hasTouchDevice())
+	if(in.getMouseButton(MouseButton::kRight) > 0 || in.hasTouchDevice())
 	{
 		in.hideCursor(true);
 
@@ -176,22 +176,22 @@ Error SampleApp::userMainLoop(Bool& quit, Second elapsedTime)
 			mover = &scene.findSceneNode("Spot");
 		}
 
-		if(in.getKey(KeyCode::kUp))
+		if(in.getKey(KeyCode::kUp) > 0)
 		{
 			mover->rotateLocalX(ROTATE_ANGLE);
 		}
 
-		if(in.getKey(KeyCode::kDown))
+		if(in.getKey(KeyCode::kDown) > 0)
 		{
 			mover->rotateLocalX(-ROTATE_ANGLE);
 		}
 
-		if(in.getKey(KeyCode::kLeft))
+		if(in.getKey(KeyCode::kLeft) > 0)
 		{
 			mover->rotateLocalY(ROTATE_ANGLE);
 		}
 
-		if(in.getKey(KeyCode::kRight))
+		if(in.getKey(KeyCode::kRight) > 0)
 		{
 			mover->rotateLocalY(-ROTATE_ANGLE);
 		}
@@ -209,38 +209,38 @@ Error SampleApp::userMainLoop(Bool& quit, Second elapsedTime)
 			moveDistance = max(moveDistance, 0.1f);
 		}
 
-		if(in.getKey(KeyCode::kA))
+		if(in.getKey(KeyCode::kA) > 0)
 		{
 			mover->moveLocalX(-moveDistance);
 		}
 
-		if(in.getKey(KeyCode::kD))
+		if(in.getKey(KeyCode::kD) > 0)
 		{
 			mover->moveLocalX(moveDistance);
 		}
 
-		if(in.getKey(KeyCode::kQ))
+		if(in.getKey(KeyCode::kQ) > 0)
 		{
 			mover->moveLocalY(-moveDistance);
 		}
 
-		if(in.getKey(KeyCode::kE))
+		if(in.getKey(KeyCode::kE) > 0)
 		{
 			mover->moveLocalY(moveDistance);
 		}
 
-		if(in.getKey(KeyCode::kW))
+		if(in.getKey(KeyCode::kW) > 0)
 		{
 			mover->moveLocalZ(-moveDistance);
 		}
 
-		if(in.getKey(KeyCode::kS))
+		if(in.getKey(KeyCode::kS) > 0)
 		{
 			mover->moveLocalZ(moveDistance);
 		}
 
-		const Vec2 velocity = in.getMousePosition() - mousePosOn1stClick;
-		in.moveCursor(mousePosOn1stClick);
+		const Vec2 velocity = in.getMousePositionNdc() - mousePosOn1stClick;
+		in.moveMouseNdc(mousePosOn1stClick);
 		if(velocity != Vec2(0.0))
 		{
 			Euler angles(mover->getLocalRotation().getRotationPart());

+ 8 - 8
Samples/PhysicsPlayground/FpsCharacterNode.cpp

@@ -75,7 +75,7 @@ void FpsCharacter::frameUpdate([[maybe_unused]] Second prevUpdateTime, [[maybe_u
 
 	// Mouselook
 	const Input& inp = Input::getSingleton();
-	const Vec2 mousePos = inp.getMousePosition();
+	const Vec2 mousePos = inp.getMousePositionNdc();
 	if(mousePos != 0.0f)
 	{
 		Mat3 camRot = m_cameraNode->getLocalRotation();
@@ -95,34 +95,34 @@ void FpsCharacter::frameUpdate([[maybe_unused]] Second prevUpdateTime, [[maybe_u
 	// Movement
 	{
 		Vec3 moveVec(0.0);
-		if(inp.getKey(KeyCode::kW))
+		if(inp.getKey(KeyCode::kW) > 0)
 		{
 			moveVec.z() += 1.0f;
 		}
 
-		if(inp.getKey(KeyCode::kA))
+		if(inp.getKey(KeyCode::kA) > 0)
 		{
 			moveVec.x() += 1.0f;
 		}
 
-		if(inp.getKey(KeyCode::kS))
+		if(inp.getKey(KeyCode::kS) > 0)
 		{
 			moveVec.z() -= 1.0f;
 		}
 
-		if(inp.getKey(KeyCode::kD))
+		if(inp.getKey(KeyCode::kD) > 0)
 		{
 			moveVec.x() -= 1.0f;
 		}
 
 		F32 jumpSpeed = 0.0f;
-		if(inp.getKey(KeyCode::kSpace))
+		if(inp.getKey(KeyCode::kSpace) > 0)
 		{
 			jumpSpeed += m_jumpSpeed;
 		}
 
 		Bool crouchChanged = false;
-		if(inp.getKey(KeyCode::kC))
+		if(inp.getKey(KeyCode::kC) > 0)
 		{
 			m_crouching = !m_crouching;
 			crouchChanged = true;
@@ -139,7 +139,7 @@ void FpsCharacter::frameUpdate([[maybe_unused]] Second prevUpdateTime, [[maybe_u
 			}
 
 			F32 speed = m_walkingSpeed;
-			if(inp.getKey(KeyCode::kLeftShift))
+			if(inp.getKey(KeyCode::kLeftShift) > 0)
 			{
 				speed *= 2.0f;
 			}

+ 3 - 3
Samples/PhysicsPlayground/Main.cpp

@@ -131,9 +131,9 @@ Error MyApp::sampleExtraInit()
 		node->setLocalOrigin(Vec3(4.0f, 0.5f, 0.0f));
 	}
 
-	Input::getSingleton().lockCursor(true);
+	Input::getSingleton().lockMouseWindowCenter(true);
 	Input::getSingleton().hideCursor(true);
-	Input::getSingleton().moveCursor(Vec2(0.0f));
+	Input::getSingleton().moveMouseNdc(Vec2(0.0f));
 
 	return Error::kNone;
 }
@@ -149,7 +149,7 @@ Error MyApp::userMainLoop(Bool& quit, [[maybe_unused]] Second elapsedTime)
 		toggleDeveloperConsole();
 	}
 
-	if(Input::getSingleton().getKey(KeyCode::kEscape))
+	if(in.getKey(KeyCode::kEscape) > 0)
 	{
 		quit = true;
 	}

BIN
Samples/Sponza/Assets/Background_Roughness.ankitex


BIN
Samples/Sponza/Assets/ChainMail_baseColor.ankitex


BIN
Samples/Sponza/Assets/ChainMail_metallicRoughness.ankitex


BIN
Samples/Sponza/Assets/ChainMail_normal.ankitex


BIN
Samples/Sponza/Assets/Leather_baseColor.ankitex


BIN
Samples/Sponza/Assets/Leather_metallicRoughness.ankitex


BIN
Samples/Sponza/Assets/Leather_normal.ankitex


BIN
Samples/Sponza/Assets/Lion_Roughness.ankitex


BIN
Samples/Sponza/Assets/Metal_baseColor.ankitex


BIN
Samples/Sponza/Assets/Metal_metallicRoughness.ankitex


BIN
Samples/Sponza/Assets/Metal_normal.ankitex


+ 1 - 1
Samples/Sponza/Assets/Scene.lua

@@ -1,4 +1,4 @@
--- Generated by: C:\src\anki\out\build\x64-Release-VK\Binaries\GltfImporter.exe sponza_crytek_7_pbr_3.0.gltf C:/src/anki/Samples/Sponza/Assets/ -rpath Assets -texrpath Assets -lod-count 2 -light-scale 0.0001839 -import-textures 1 -j 8 -v
+-- Generated by: C:\src\anki\out\build\x64-Release-VK\Binaries\GltfImporter.exe sponza_crytek_7_pbr_3.0.gltf C:/src/anki/Samples/Sponza/Assets/ -rpath Assets -texrpath Assets -lod-count 2 -light-scale 0.0001839 -import-textures 1 -v
 local scene = getSceneGraph()
 local events = getEventManager()
 

BIN
Samples/Sponza/Assets/Sponza_Ceiling_roughness.ankitex.ankitex


BIN
Samples/Sponza/Assets/Sponza_Column_b_roughness.ankitex.ankitex


BIN
Samples/Sponza/Assets/Sponza_Column_c_roughness.ankitex.ankitex


BIN
Samples/Sponza/Assets/Sponza_Curtain_Red_normal.ankitex


BIN
Samples/Sponza/Assets/Sponza_Curtain_Red_normal.ankitex.001.ankitex


BIN
Samples/Sponza/Assets/Sponza_Curtain_roughness.ankitex.001.ankitex


BIN
Samples/Sponza/Assets/Sponza_Details_metallic-Sponza_Details_roughness.ankitex


BIN
Samples/Sponza/Assets/Sponza_Details_normal.ankitex


BIN
Samples/Sponza/Assets/Sponza_Fabric_metallic-Sponza_Curtain_roughness.ankitex


BIN
Samples/Sponza/Assets/Sponza_FlagPole_normal.ankitex


BIN
Samples/Sponza/Assets/Sponza_FlagPole_roughness.ankitex


BIN
Samples/Sponza/Assets/Sponza_Floor_normal.ankitex


BIN
Samples/Sponza/Assets/Sponza_Floor_roughness.ankitex


BIN
Samples/Sponza/Assets/Sponza_Roof_normal.ankitex


BIN
Samples/Sponza/Assets/Sponza_Roof_roughness.ankitex


BIN
Samples/Sponza/Assets/Sponza_Thorn_roughness.ankitex


BIN
Samples/Sponza/Assets/VaseHanging_normal.ankitex.ankitex


BIN
Samples/Sponza/Assets/VaseHanging_roughness.ankitex.ankitex


BIN
Samples/Sponza/Assets/VasePlant_normal.ankitex


BIN
Samples/Sponza/Assets/VaseRound_normal.ankitex


BIN
Samples/Sponza/Assets/VaseRound_roughness.ankitex


BIN
Samples/Sponza/Assets/Vase_roughness.ankitex


BIN
Samples/Sponza/Assets/background.ankitex


BIN
Samples/Sponza/Assets/background_ddn.ankitex


BIN
Samples/Sponza/Assets/chain_texture.ankitex.ankitex


BIN
Samples/Sponza/Assets/lion.ankitex


BIN
Samples/Sponza/Assets/lion_ddn.ankitex


BIN
Samples/Sponza/Assets/material_baseColor.ankitex


BIN
Samples/Sponza/Assets/material_metallicRoughness.ankitex


BIN
Samples/Sponza/Assets/skinFace_baseColor.ankitex


BIN
Samples/Sponza/Assets/skinFace_metallicRoughness.ankitex


BIN
Samples/Sponza/Assets/skinFace_normal.ankitex


BIN
Samples/Sponza/Assets/sponza_arch_ddn.ankitex


BIN
Samples/Sponza/Assets/sponza_arch_ddn.ankitex.ankitex


BIN
Samples/Sponza/Assets/sponza_arch_diff.ankitex


BIN
Samples/Sponza/Assets/sponza_arch_diff.ankitex.ankitex


BIN
Samples/Sponza/Assets/sponza_arch_spec.ankitex


BIN
Samples/Sponza/Assets/sponza_arch_spec.ankitex.ankitex


BIN
Samples/Sponza/Assets/sponza_bricks_a_ddn.ankitex.ankitex


BIN
Samples/Sponza/Assets/sponza_bricks_a_diff.ankitex.ankitex


BIN
Samples/Sponza/Assets/sponza_ceiling_a_diff.ankitex.ankitex


BIN
Samples/Sponza/Assets/sponza_column_a_ddn.ankitex.ankitex


BIN
Samples/Sponza/Assets/sponza_column_a_diff.ankitex.ankitex


BIN
Samples/Sponza/Assets/sponza_column_a_spec.ankitex.ankitex


Some files were not shown because too many files changed in this diff