Add ImguiPipelinePass
This commit is contained in:
parent
c5bffa9c98
commit
741b593033
|
|
@ -0,0 +1,65 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <NazaraImgui/Config.hpp>
|
||||||
|
|
||||||
|
#include <Nazara/Renderer/ShaderBinding.hpp>
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
class CommandBufferBuilder;
|
||||||
|
class RenderBuffer;
|
||||||
|
class RenderDevice;
|
||||||
|
class RenderFrame;
|
||||||
|
class RenderPipeline;
|
||||||
|
|
||||||
|
class NAZARA_IMGUI_API ImguiDrawer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ImguiDrawer(RenderDevice& renderDevice);
|
||||||
|
ImguiDrawer(const ImguiDrawer&) = delete;
|
||||||
|
ImguiDrawer(ImguiDrawer&&) noexcept = default;
|
||||||
|
~ImguiDrawer();
|
||||||
|
|
||||||
|
ImguiDrawer& operator=(const ImguiDrawer&) = delete;
|
||||||
|
ImguiDrawer& operator=(ImguiDrawer&&) = delete;
|
||||||
|
|
||||||
|
void Prepare(RenderFrame& renderFrame);
|
||||||
|
|
||||||
|
void Reset(RenderFrame& renderFrame);
|
||||||
|
|
||||||
|
void Draw(CommandBufferBuilder& builder);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool LoadTexturedPipeline();
|
||||||
|
bool LoadUntexturedPipeline();
|
||||||
|
|
||||||
|
RenderDevice& m_renderDevice;
|
||||||
|
|
||||||
|
struct DrawCall
|
||||||
|
{
|
||||||
|
size_t vertex_offset, indice_offset;
|
||||||
|
std::vector<ImDrawCmd> cmdBuffer;
|
||||||
|
};
|
||||||
|
std::vector<DrawCall> m_drawCalls;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
std::shared_ptr<RenderPipeline> pipeline;
|
||||||
|
std::unordered_map<Texture*, ShaderBindingPtr> textureShaderBindings;
|
||||||
|
Nz::ShaderBindingPtr uboShaderBinding;
|
||||||
|
std::shared_ptr<TextureSampler> textureSampler;
|
||||||
|
} m_texturedPipeline;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
std::shared_ptr<RenderPipeline> pipeline;
|
||||||
|
Nz::ShaderBindingPtr uboShaderBinding;
|
||||||
|
} m_untexturedPipeline;
|
||||||
|
|
||||||
|
std::shared_ptr<RenderBuffer> m_vertexBuffer;
|
||||||
|
std::shared_ptr<RenderBuffer> m_indexBuffer;
|
||||||
|
std::shared_ptr<RenderBuffer> m_uboBuffer;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <NazaraImgui/Config.hpp>
|
||||||
|
|
||||||
|
#include <Nazara/Core/ParameterList.hpp>
|
||||||
|
#include <Nazara/Graphics/FramePipelinePass.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
class PassData;
|
||||||
|
|
||||||
|
class NAZARA_IMGUI_API ImguiPipelinePass
|
||||||
|
: public FramePipelinePass
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ImguiPipelinePass(PassData& passData, std::string passName, const ParameterList& parameters = {});
|
||||||
|
ImguiPipelinePass(const ImguiPipelinePass&) = delete;
|
||||||
|
ImguiPipelinePass(ImguiPipelinePass&&) = delete;
|
||||||
|
~ImguiPipelinePass() = default;
|
||||||
|
|
||||||
|
void Prepare(FrameData& frameData) override;
|
||||||
|
FramePass& RegisterToFrameGraph(FrameGraph& frameGraph, const PassInputOuputs& inputOuputs) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_passName;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#include <Nazara/Graphics/Graphics.hpp>
|
#include <Nazara/Graphics/Graphics.hpp>
|
||||||
#include <Nazara/Math/Rect.hpp>
|
#include <Nazara/Math/Rect.hpp>
|
||||||
#include <NazaraImgui/Config.hpp>
|
#include <NazaraImgui/Config.hpp>
|
||||||
|
#include <NazaraImgui/ImguiDrawer.hpp>
|
||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
@ -11,8 +12,6 @@
|
||||||
namespace Nz
|
namespace Nz
|
||||||
{
|
{
|
||||||
class Cursor;
|
class Cursor;
|
||||||
class RenderFrame;
|
|
||||||
class RenderTarget;
|
|
||||||
class RenderWindow;
|
class RenderWindow;
|
||||||
class Texture;
|
class Texture;
|
||||||
class Window;
|
class Window;
|
||||||
|
|
@ -39,6 +38,9 @@ namespace Nz
|
||||||
void Update(Nz::Window& window, float dt);
|
void Update(Nz::Window& window, float dt);
|
||||||
void Render(Nz::RenderTarget* renderTarget, Nz::RenderFrame& frame);
|
void Render(Nz::RenderTarget* renderTarget, Nz::RenderFrame& frame);
|
||||||
|
|
||||||
|
inline ImguiDrawer& GetImguiDrawer() { return m_imguiDrawer; }
|
||||||
|
inline const ImguiDrawer& GetImguiDrawer() const { return m_imguiDrawer; }
|
||||||
|
|
||||||
// User-defined
|
// User-defined
|
||||||
void AddHandler(ImguiHandler* handler);
|
void AddHandler(ImguiHandler* handler);
|
||||||
void RemoveHandler(ImguiHandler* handler);
|
void RemoveHandler(ImguiHandler* handler);
|
||||||
|
|
@ -63,35 +65,16 @@ namespace Nz
|
||||||
std::shared_ptr<Nz::Cursor> GetMouseCursor(ImGuiMouseCursor cursorType);
|
std::shared_ptr<Nz::Cursor> GetMouseCursor(ImGuiMouseCursor cursorType);
|
||||||
void UpdateMouseCursor(Nz::Window& window);
|
void UpdateMouseCursor(Nz::Window& window);
|
||||||
|
|
||||||
bool LoadTexturedPipeline();
|
|
||||||
bool LoadUntexturedPipeline();
|
|
||||||
void UpdateFontTexture();
|
void UpdateFontTexture();
|
||||||
|
|
||||||
void RenderDrawLists(Nz::RenderTarget* renderTarget, Nz::RenderFrame& frame, ImDrawData* drawData);
|
|
||||||
|
|
||||||
ImGuiContext* m_currentContext;
|
ImGuiContext* m_currentContext;
|
||||||
std::string m_clipboardText;
|
std::string m_clipboardText;
|
||||||
|
|
||||||
bool m_bWindowHasFocus;
|
bool m_bWindowHasFocus;
|
||||||
bool m_bMouseMoved;
|
bool m_bMouseMoved;
|
||||||
|
|
||||||
struct
|
ImguiDrawer m_imguiDrawer;
|
||||||
{
|
|
||||||
std::shared_ptr<Nz::RenderPipeline> pipeline;
|
|
||||||
std::unordered_map<Nz::Texture*, Nz::ShaderBindingPtr> textureShaderBindings;
|
|
||||||
Nz::ShaderBindingPtr uboShaderBinding;
|
|
||||||
std::shared_ptr<Nz::TextureSampler> textureSampler;
|
|
||||||
} m_texturedPipeline;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
std::shared_ptr<Nz::RenderPipeline> pipeline;
|
|
||||||
Nz::ShaderBindingPtr uboShaderBinding;
|
|
||||||
} m_untexturedPipeline;
|
|
||||||
|
|
||||||
std::shared_ptr<Nz::RenderBuffer> m_uboBuffer;
|
|
||||||
std::shared_ptr<Nz::Texture> m_fontTexture;
|
std::shared_ptr<Nz::Texture> m_fontTexture;
|
||||||
|
|
||||||
std::unordered_set<ImguiHandler*> m_handlers;
|
std::unordered_set<ImguiHandler*> m_handlers;
|
||||||
|
|
||||||
static Imgui* s_instance;
|
static Imgui* s_instance;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,319 @@
|
||||||
|
#include <NazaraImgui/ImguiDrawer.hpp>
|
||||||
|
|
||||||
|
#include <Nazara/Renderer/CommandBufferBuilder.hpp>
|
||||||
|
#include <Nazara/Renderer/RenderDevice.hpp>
|
||||||
|
#include <Nazara/Renderer/RenderFrame.hpp>
|
||||||
|
#include <Nazara/Renderer/UploadPool.hpp>
|
||||||
|
#include <Nazara/Utility/VertexStruct.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
#include <NZSL/Parser.hpp>
|
||||||
|
|
||||||
|
const char shaderSource_Textured[] =
|
||||||
|
#include "Textured.nzsl.h"
|
||||||
|
;
|
||||||
|
|
||||||
|
const char shaderSource_Untextured[] =
|
||||||
|
#include "Untextured.nzsl.h"
|
||||||
|
;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
inline Nz::Vector2f ToNzVec2(ImVec2 v)
|
||||||
|
{
|
||||||
|
return { v.x, v.y };
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Nz::Vector3f ToNzVec3(ImVec2 v)
|
||||||
|
{
|
||||||
|
return { v.x, v.y, 0.f };
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Nz::Color ToNzColor(ImU32 color)
|
||||||
|
{
|
||||||
|
auto c = ImGui::ColorConvertU32ToFloat4(color);
|
||||||
|
return { c.x, c.y, c.z, c.w };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
struct ImguiUbo
|
||||||
|
{
|
||||||
|
float screenWidth;
|
||||||
|
float screenHeight;
|
||||||
|
};
|
||||||
|
|
||||||
|
ImguiDrawer::ImguiDrawer(RenderDevice& renderDevice)
|
||||||
|
: m_renderDevice(renderDevice)
|
||||||
|
{
|
||||||
|
LoadTexturedPipeline();
|
||||||
|
LoadUntexturedPipeline();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImguiDrawer::~ImguiDrawer()
|
||||||
|
{
|
||||||
|
m_untexturedPipeline.uboShaderBinding.reset();
|
||||||
|
m_untexturedPipeline.pipeline.reset();
|
||||||
|
|
||||||
|
m_texturedPipeline.uboShaderBinding.reset();
|
||||||
|
m_texturedPipeline.textureShaderBindings.clear();
|
||||||
|
m_texturedPipeline.textureSampler.reset();
|
||||||
|
m_texturedPipeline.pipeline.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImguiDrawer::Prepare(RenderFrame& frame)
|
||||||
|
{
|
||||||
|
m_drawCalls.clear();
|
||||||
|
|
||||||
|
ImDrawData* drawData = ImGui::GetDrawData();
|
||||||
|
if (drawData->CmdListsCount == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
assert(io.Fonts->TexID != (ImTextureID)NULL); // You forgot to create and set font texture
|
||||||
|
|
||||||
|
// scale stuff (needed for proper handling of window resize)
|
||||||
|
int fb_width = static_cast<int>(io.DisplaySize.x * io.DisplayFramebufferScale.x);
|
||||||
|
int fb_height = static_cast<int>(io.DisplaySize.y * io.DisplayFramebufferScale.y);
|
||||||
|
if (fb_width == 0 || fb_height == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ImguiUbo ubo{ fb_width / 2.f, fb_height / 2.f };
|
||||||
|
auto& allocation = frame.GetUploadPool().Allocate(sizeof(ImguiUbo));
|
||||||
|
|
||||||
|
std::memcpy(allocation.mappedPtr, &ubo, sizeof(ImguiUbo));
|
||||||
|
|
||||||
|
frame.Execute([&](Nz::CommandBufferBuilder& builder)
|
||||||
|
{
|
||||||
|
builder.BeginDebugRegion("Imgui UBO Update", Nz::Color::Yellow());
|
||||||
|
{
|
||||||
|
builder.PreTransferBarrier();
|
||||||
|
builder.CopyBuffer(allocation, m_uboBuffer.get());
|
||||||
|
builder.PostTransferBarrier();
|
||||||
|
}
|
||||||
|
builder.EndDebugRegion();
|
||||||
|
}, Nz::QueueType::Transfer);
|
||||||
|
|
||||||
|
drawData->ScaleClipRects(io.DisplayFramebufferScale);
|
||||||
|
|
||||||
|
// first pass over cmd lists to prepare buffers
|
||||||
|
std::vector<Nz::VertexStruct_XYZ_Color_UV> vertices;
|
||||||
|
std::vector<uint16_t> indices;
|
||||||
|
for (int n = 0; n < drawData->CmdListsCount; ++n) {
|
||||||
|
const ImDrawList* cmd_list = drawData->CmdLists[n];
|
||||||
|
|
||||||
|
DrawCall drawCall;
|
||||||
|
drawCall.vertex_offset = vertices.size();
|
||||||
|
drawCall.indice_offset = indices.size();
|
||||||
|
|
||||||
|
vertices.reserve(vertices.size() + cmd_list->VtxBuffer.size());
|
||||||
|
for (auto& vertex : cmd_list->VtxBuffer)
|
||||||
|
vertices.push_back({ ToNzVec3(vertex.pos), ToNzColor(vertex.col), ToNzVec2(vertex.uv) });
|
||||||
|
|
||||||
|
indices.reserve(indices.size() + cmd_list->IdxBuffer.size());
|
||||||
|
for (auto indice : cmd_list->IdxBuffer)
|
||||||
|
indices.push_back(uint16_t(drawCall.vertex_offset + indice));
|
||||||
|
|
||||||
|
for (auto& cmd : cmd_list->CmdBuffer)
|
||||||
|
drawCall.cmdBuffer.push_back(cmd);
|
||||||
|
|
||||||
|
m_drawCalls.push_back(std::move(drawCall));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// now that we have macro buffers, allocate them on gpu
|
||||||
|
size_t size = vertices.size() * sizeof(Nz::VertexStruct_XYZ_Color_UV);
|
||||||
|
m_vertexBuffer = m_renderDevice.InstantiateBuffer(Nz::BufferType::Vertex, size, Nz::BufferUsage::DeviceLocal | Nz::BufferUsage::Dynamic, vertices.data());
|
||||||
|
size = indices.size() * sizeof(uint16_t);
|
||||||
|
m_indexBuffer = m_renderDevice.InstantiateBuffer(Nz::BufferType::Index, size, Nz::BufferUsage::DeviceLocal | Nz::BufferUsage::Dynamic, indices.data());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImguiDrawer::Draw(CommandBufferBuilder& builder)
|
||||||
|
{
|
||||||
|
if (m_drawCalls.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
int fb_width = static_cast<int>(io.DisplaySize.x * io.DisplayFramebufferScale.x);
|
||||||
|
int fb_height = static_cast<int>(io.DisplaySize.y * io.DisplayFramebufferScale.y);
|
||||||
|
|
||||||
|
builder.SetViewport(Nz::Recti{ 0, 0, fb_width, fb_height });
|
||||||
|
builder.BindIndexBuffer(*m_indexBuffer, Nz::IndexType::U16);
|
||||||
|
builder.BindVertexBuffer(0, *m_vertexBuffer);
|
||||||
|
|
||||||
|
for (auto& drawCall : m_drawCalls)
|
||||||
|
{
|
||||||
|
Nz::UInt64 indexOffset = drawCall.indice_offset;
|
||||||
|
for (auto& cmd : drawCall.cmdBuffer)
|
||||||
|
{
|
||||||
|
if (!cmd.UserCallback)
|
||||||
|
{
|
||||||
|
auto rect = cmd.ClipRect;
|
||||||
|
auto count = cmd.ElemCount;
|
||||||
|
auto texture = static_cast<Nz::Texture*>(cmd.GetTexID());
|
||||||
|
|
||||||
|
if (nullptr != texture)
|
||||||
|
{
|
||||||
|
if (std::end(m_texturedPipeline.textureShaderBindings) == m_texturedPipeline.textureShaderBindings.find(texture))
|
||||||
|
{
|
||||||
|
auto binding = m_texturedPipeline.pipeline->GetPipelineInfo().pipelineLayout->AllocateShaderBinding(1);
|
||||||
|
binding->Update({
|
||||||
|
{
|
||||||
|
0,
|
||||||
|
Nz::ShaderBinding::SampledTextureBinding {
|
||||||
|
texture, m_texturedPipeline.textureSampler.get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
m_texturedPipeline.textureShaderBindings[texture] = std::move(binding);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.BindRenderPipeline(*m_texturedPipeline.pipeline);
|
||||||
|
builder.BindRenderShaderBinding(0, *m_texturedPipeline.uboShaderBinding);
|
||||||
|
builder.BindRenderShaderBinding(1, *m_texturedPipeline.textureShaderBindings[texture]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
builder.BindRenderPipeline(*m_untexturedPipeline.pipeline);
|
||||||
|
builder.BindRenderShaderBinding(0, *m_untexturedPipeline.uboShaderBinding);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.SetScissor(Nz::Recti{ int(rect.x), int(rect.y), int(rect.z - rect.x), int(rect.w - rect.y) });// Nz::Recti{ int(rect.x), int(fb_height - rect.w), int(rect.z - rect.x), int(rect.w - rect.y) });
|
||||||
|
|
||||||
|
builder.DrawIndexed(count, 1, Nz::UInt32(indexOffset));
|
||||||
|
}
|
||||||
|
indexOffset += cmd.ElemCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImguiDrawer::Reset(RenderFrame& renderFrame)
|
||||||
|
{
|
||||||
|
m_drawCalls.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImguiDrawer::LoadTexturedPipeline()
|
||||||
|
{
|
||||||
|
nzsl::Ast::ModulePtr shaderModule = nzsl::Parse(std::string_view(shaderSource_Textured, sizeof(shaderSource_Textured)));
|
||||||
|
if (!shaderModule)
|
||||||
|
throw std::runtime_error("Failed to parse shader module");
|
||||||
|
|
||||||
|
nzsl::ShaderWriter::States states;
|
||||||
|
states.optimize = true;
|
||||||
|
|
||||||
|
auto shader = m_renderDevice.InstantiateShaderModule(nzsl::ShaderStageType::Fragment | nzsl::ShaderStageType::Vertex, *shaderModule, states);
|
||||||
|
if (!shader)
|
||||||
|
throw std::runtime_error("Failed to instantiate shader");
|
||||||
|
|
||||||
|
m_texturedPipeline.textureSampler = m_renderDevice.InstantiateTextureSampler({});
|
||||||
|
|
||||||
|
Nz::RenderPipelineLayoutInfo pipelineLayoutInfo;
|
||||||
|
|
||||||
|
auto& uboBinding = pipelineLayoutInfo.bindings.emplace_back();
|
||||||
|
uboBinding.setIndex = 0;
|
||||||
|
uboBinding.bindingIndex = 0;
|
||||||
|
uboBinding.shaderStageFlags = nzsl::ShaderStageType::Vertex;
|
||||||
|
uboBinding.type = Nz::ShaderBindingType::UniformBuffer;
|
||||||
|
|
||||||
|
auto& textureBinding = pipelineLayoutInfo.bindings.emplace_back();
|
||||||
|
textureBinding.setIndex = 1;
|
||||||
|
textureBinding.bindingIndex = 0;
|
||||||
|
textureBinding.shaderStageFlags = nzsl::ShaderStageType::Fragment;
|
||||||
|
textureBinding.type = Nz::ShaderBindingType::Texture;
|
||||||
|
|
||||||
|
std::shared_ptr<Nz::RenderPipelineLayout> renderPipelineLayout = m_renderDevice.InstantiateRenderPipelineLayout(std::move(pipelineLayoutInfo));
|
||||||
|
|
||||||
|
Nz::RenderPipelineInfo pipelineInfo;
|
||||||
|
pipelineInfo.pipelineLayout = renderPipelineLayout;
|
||||||
|
pipelineInfo.shaderModules.emplace_back(shader);
|
||||||
|
|
||||||
|
pipelineInfo.depthBuffer = false;
|
||||||
|
pipelineInfo.faceCulling = Nz::FaceCulling::None;
|
||||||
|
pipelineInfo.scissorTest = true;
|
||||||
|
|
||||||
|
pipelineInfo.blending = true;
|
||||||
|
pipelineInfo.blend.modeAlpha = Nz::BlendEquation::Add;
|
||||||
|
pipelineInfo.blend.srcColor = Nz::BlendFunc::SrcAlpha;
|
||||||
|
pipelineInfo.blend.dstColor = Nz::BlendFunc::InvSrcAlpha;
|
||||||
|
pipelineInfo.blend.srcAlpha = Nz::BlendFunc::One;
|
||||||
|
pipelineInfo.blend.dstAlpha = Nz::BlendFunc::Zero;
|
||||||
|
|
||||||
|
auto& pipelineVertexBuffer = pipelineInfo.vertexBuffers.emplace_back();
|
||||||
|
pipelineVertexBuffer.binding = 0;
|
||||||
|
pipelineVertexBuffer.declaration = Nz::VertexDeclaration::Get(Nz::VertexLayout::XYZ_Color_UV);
|
||||||
|
|
||||||
|
m_texturedPipeline.pipeline = m_renderDevice.InstantiateRenderPipeline(pipelineInfo);
|
||||||
|
|
||||||
|
m_uboBuffer = m_renderDevice.InstantiateBuffer(Nz::BufferType::Uniform, sizeof(ImguiUbo), Nz::BufferUsage::DeviceLocal | Nz::BufferUsage::Dynamic);
|
||||||
|
|
||||||
|
m_texturedPipeline.uboShaderBinding = renderPipelineLayout->AllocateShaderBinding(0);
|
||||||
|
m_texturedPipeline.uboShaderBinding->Update({
|
||||||
|
{
|
||||||
|
0,
|
||||||
|
Nz::ShaderBinding::UniformBufferBinding {
|
||||||
|
m_uboBuffer.get(), 0, sizeof(ImguiUbo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImguiDrawer::LoadUntexturedPipeline()
|
||||||
|
{
|
||||||
|
nzsl::Ast::ModulePtr shaderModule = nzsl::Parse(std::string_view(shaderSource_Untextured, sizeof(shaderSource_Untextured)));
|
||||||
|
if (!shaderModule)
|
||||||
|
throw std::runtime_error("Failed to parse shader module");
|
||||||
|
|
||||||
|
nzsl::ShaderWriter::States states;
|
||||||
|
states.optimize = true;
|
||||||
|
|
||||||
|
auto shader = m_renderDevice.InstantiateShaderModule(nzsl::ShaderStageType::Fragment | nzsl::ShaderStageType::Vertex, *shaderModule, states);
|
||||||
|
if (!shader)
|
||||||
|
throw std::runtime_error("Failed to instantiate shader");
|
||||||
|
|
||||||
|
Nz::RenderPipelineLayoutInfo pipelineLayoutInfo;
|
||||||
|
|
||||||
|
auto& uboBinding = pipelineLayoutInfo.bindings.emplace_back();
|
||||||
|
uboBinding.setIndex = 0;
|
||||||
|
uboBinding.bindingIndex = 0;
|
||||||
|
uboBinding.shaderStageFlags = nzsl::ShaderStageType::Vertex;
|
||||||
|
uboBinding.type = Nz::ShaderBindingType::UniformBuffer;
|
||||||
|
|
||||||
|
std::shared_ptr<Nz::RenderPipelineLayout> renderPipelineLayout = m_renderDevice.InstantiateRenderPipelineLayout(std::move(pipelineLayoutInfo));
|
||||||
|
|
||||||
|
Nz::RenderPipelineInfo pipelineInfo;
|
||||||
|
pipelineInfo.pipelineLayout = renderPipelineLayout;
|
||||||
|
pipelineInfo.shaderModules.emplace_back(shader);
|
||||||
|
|
||||||
|
pipelineInfo.depthBuffer = false;
|
||||||
|
pipelineInfo.faceCulling = Nz::FaceCulling::None;
|
||||||
|
pipelineInfo.scissorTest = true;
|
||||||
|
|
||||||
|
pipelineInfo.blending = true;
|
||||||
|
pipelineInfo.blend.modeAlpha = Nz::BlendEquation::Add;
|
||||||
|
pipelineInfo.blend.srcColor = Nz::BlendFunc::SrcAlpha;
|
||||||
|
pipelineInfo.blend.dstColor = Nz::BlendFunc::InvSrcAlpha;
|
||||||
|
pipelineInfo.blend.srcAlpha = Nz::BlendFunc::One;
|
||||||
|
pipelineInfo.blend.dstAlpha = Nz::BlendFunc::Zero;
|
||||||
|
|
||||||
|
auto& pipelineVertexBuffer = pipelineInfo.vertexBuffers.emplace_back();
|
||||||
|
pipelineVertexBuffer.binding = 0;
|
||||||
|
pipelineVertexBuffer.declaration = Nz::VertexDeclaration::Get(Nz::VertexLayout::XYZ_Color_UV);
|
||||||
|
|
||||||
|
m_untexturedPipeline.pipeline = m_renderDevice.InstantiateRenderPipeline(pipelineInfo);
|
||||||
|
|
||||||
|
m_untexturedPipeline.uboShaderBinding = renderPipelineLayout->AllocateShaderBinding(0);
|
||||||
|
m_untexturedPipeline.uboShaderBinding->Update({
|
||||||
|
{
|
||||||
|
0,
|
||||||
|
Nz::ShaderBinding::UniformBufferBinding {
|
||||||
|
m_uboBuffer.get(), 0, sizeof(ImguiUbo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
#include <NazaraImgui/ImguiPipelinePass.hpp>
|
||||||
|
|
||||||
|
#include <NazaraImgui/NazaraImgui.hpp>
|
||||||
|
#include <NazaraImgui/ImguiDrawer.hpp>
|
||||||
|
|
||||||
|
#include <Nazara/Graphics/FrameGraph.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
ImguiPipelinePass::ImguiPipelinePass(PassData& passData, std::string passName, const ParameterList& /*parameters*/) :
|
||||||
|
FramePipelinePass({})
|
||||||
|
, m_passName(std::move(passName))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImguiPipelinePass::Prepare(FrameData& frameData)
|
||||||
|
{
|
||||||
|
ImguiDrawer& imguiDrawer = Nz::Imgui::Instance()->GetImguiDrawer();
|
||||||
|
imguiDrawer.Prepare(frameData.renderFrame);
|
||||||
|
}
|
||||||
|
|
||||||
|
FramePass& ImguiPipelinePass::RegisterToFrameGraph(FrameGraph& frameGraph, const PassInputOuputs& inputOuputs)
|
||||||
|
{
|
||||||
|
if (inputOuputs.inputCount != 1)
|
||||||
|
throw std::runtime_error("one input expected");
|
||||||
|
|
||||||
|
if (inputOuputs.outputCount != 1)
|
||||||
|
throw std::runtime_error("one output expected");
|
||||||
|
|
||||||
|
FramePass& imguiPass = frameGraph.AddPass("Imgui pass");
|
||||||
|
imguiPass.AddInput(inputOuputs.inputAttachments[0]);
|
||||||
|
imguiPass.AddOutput(inputOuputs.outputAttachments[0]);
|
||||||
|
|
||||||
|
imguiPass.SetExecutionCallback([&]
|
||||||
|
{
|
||||||
|
return FramePassExecution::UpdateAndExecute;
|
||||||
|
});
|
||||||
|
|
||||||
|
imguiPass.SetCommandCallback([this](CommandBufferBuilder& builder, const FramePassEnvironment& /*env*/)
|
||||||
|
{
|
||||||
|
ImguiDrawer& imguiDrawer = Nz::Imgui::Instance()->GetImguiDrawer();
|
||||||
|
imguiDrawer.Draw(builder);
|
||||||
|
});
|
||||||
|
|
||||||
|
return imguiPass;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
#include <NazaraImgui/NazaraImgui.hpp>
|
#include <NazaraImgui/NazaraImgui.hpp>
|
||||||
|
#include <NazaraImgui/ImguiPipelinePass.hpp>
|
||||||
|
#include <NazaraImgui/ImguiDrawer.hpp>
|
||||||
|
|
||||||
#include <Nazara/Core/DynLib.hpp>
|
#include <Nazara/Core/DynLib.hpp>
|
||||||
#include <Nazara/Core/Log.hpp>
|
#include <Nazara/Core/Log.hpp>
|
||||||
|
|
@ -36,14 +38,6 @@ static_assert(sizeof(void*) <= sizeof(ImTextureID),
|
||||||
#define NazaraImguiDebugSuffix ""
|
#define NazaraImguiDebugSuffix ""
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const char shaderSource_Textured[] =
|
|
||||||
#include "Textured.nzsl.h"
|
|
||||||
;
|
|
||||||
|
|
||||||
const char shaderSource_Untextured[] =
|
|
||||||
#include "Untextured.nzsl.h"
|
|
||||||
;
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
inline Nz::SystemCursor ToNz(ImGuiMouseCursor type)
|
inline Nz::SystemCursor ToNz(ImGuiMouseCursor type)
|
||||||
|
|
@ -65,34 +59,11 @@ namespace
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Nz::Vector2f ToNzVec2(ImVec2 v)
|
|
||||||
{
|
|
||||||
return { v.x, v.y };
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Nz::Vector3f ToNzVec3(ImVec2 v)
|
|
||||||
{
|
|
||||||
return { v.x, v.y, 0.f };
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Nz::Color ToNzColor(ImU32 color)
|
|
||||||
{
|
|
||||||
auto c = ImGui::ColorConvertU32ToFloat4(color);
|
|
||||||
return { c.x, c.y, c.z, c.w };
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
namespace Nz
|
namespace Nz
|
||||||
{
|
{
|
||||||
struct ImguiUbo
|
|
||||||
{
|
|
||||||
float screenWidth;
|
|
||||||
float screenHeight;
|
|
||||||
};
|
|
||||||
|
|
||||||
Imgui* Imgui::s_instance = nullptr;
|
Imgui* Imgui::s_instance = nullptr;
|
||||||
|
|
||||||
Imgui::Imgui(Config /*config*/)
|
Imgui::Imgui(Config /*config*/)
|
||||||
|
|
@ -100,6 +71,7 @@ namespace Nz
|
||||||
, m_bMouseMoved(false)
|
, m_bMouseMoved(false)
|
||||||
, m_bWindowHasFocus(false)
|
, m_bWindowHasFocus(false)
|
||||||
, m_currentContext(nullptr)
|
, m_currentContext(nullptr)
|
||||||
|
, m_imguiDrawer(*Nz::Graphics::Instance()->GetRenderDevice())
|
||||||
{
|
{
|
||||||
ImGui::CreateContext();
|
ImGui::CreateContext();
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
@ -108,14 +80,6 @@ namespace Nz
|
||||||
|
|
||||||
Imgui::~Imgui()
|
Imgui::~Imgui()
|
||||||
{
|
{
|
||||||
m_untexturedPipeline.uboShaderBinding.reset();
|
|
||||||
m_untexturedPipeline.pipeline.reset();
|
|
||||||
|
|
||||||
m_texturedPipeline.uboShaderBinding.reset();
|
|
||||||
m_texturedPipeline.textureShaderBindings.clear();
|
|
||||||
m_texturedPipeline.textureSampler.reset();
|
|
||||||
m_texturedPipeline.pipeline.reset();
|
|
||||||
|
|
||||||
ImGui::GetIO().Fonts->TexID = nullptr;
|
ImGui::GetIO().Fonts->TexID = nullptr;
|
||||||
ImGui::DestroyContext();
|
ImGui::DestroyContext();
|
||||||
|
|
||||||
|
|
@ -139,11 +103,8 @@ namespace Nz
|
||||||
// init rendering
|
// init rendering
|
||||||
io.DisplaySize = ImVec2(window.GetSize().x * 1.f, window.GetSize().y * 1.f);
|
io.DisplaySize = ImVec2(window.GetSize().x * 1.f, window.GetSize().y * 1.f);
|
||||||
|
|
||||||
if (!LoadTexturedPipeline())
|
auto registry = Nz::Graphics::Instance()->GetFramePipelinePassRegistry();
|
||||||
return false;
|
registry.RegisterPass<ImguiPipelinePass>("Imgui", { "Input" }, { "Output" });
|
||||||
|
|
||||||
if (!LoadUntexturedPipeline())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (bLoadDefaultFont)
|
if (bLoadDefaultFont)
|
||||||
{
|
{
|
||||||
|
|
@ -320,7 +281,23 @@ namespace Nz
|
||||||
handler->OnRenderImgui();
|
handler->OnRenderImgui();
|
||||||
|
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
RenderDrawLists(renderTarget, frame, ImGui::GetDrawData());
|
|
||||||
|
m_imguiDrawer.Prepare(frame);
|
||||||
|
|
||||||
|
frame.Execute([this, renderTarget, &frame](Nz::CommandBufferBuilder& builder) {
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
int fb_width = static_cast<int>(io.DisplaySize.x * io.DisplayFramebufferScale.x);
|
||||||
|
int fb_height = static_cast<int>(io.DisplaySize.y * io.DisplayFramebufferScale.y);
|
||||||
|
Nz::Recti renderRect(0, 0, fb_width, fb_height);
|
||||||
|
|
||||||
|
builder.BeginDebugRegion("ImGui", Nz::Color::Green());
|
||||||
|
builder.BeginRenderPass(renderTarget->GetFramebuffer(frame.GetFramebufferIndex()), renderTarget->GetRenderPass(), renderRect);
|
||||||
|
m_imguiDrawer.Draw(builder);
|
||||||
|
builder.EndRenderPass();
|
||||||
|
builder.EndDebugRegion();
|
||||||
|
|
||||||
|
}, Nz::QueueType::Graphics);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Imgui::AddHandler(ImguiHandler* handler)
|
void Imgui::AddHandler(ImguiHandler* handler)
|
||||||
|
|
@ -406,286 +383,6 @@ namespace Nz
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Imgui::LoadTexturedPipeline()
|
|
||||||
{
|
|
||||||
auto renderDevice = Nz::Graphics::Instance()->GetRenderDevice();
|
|
||||||
|
|
||||||
nzsl::Ast::ModulePtr shaderModule = nzsl::Parse(std::string_view(shaderSource_Textured, sizeof(shaderSource_Textured)));
|
|
||||||
if (!shaderModule)
|
|
||||||
{
|
|
||||||
std::cout << "Failed to parse shader module" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
nzsl::ShaderWriter::States states;
|
|
||||||
states.optimize = true;
|
|
||||||
|
|
||||||
auto shader = renderDevice->InstantiateShaderModule(nzsl::ShaderStageType::Fragment | nzsl::ShaderStageType::Vertex, *shaderModule, states);
|
|
||||||
if (!shader)
|
|
||||||
{
|
|
||||||
std::cout << "Failed to instantiate shader" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
m_texturedPipeline.textureSampler = renderDevice->InstantiateTextureSampler({});
|
|
||||||
|
|
||||||
Nz::RenderPipelineLayoutInfo pipelineLayoutInfo;
|
|
||||||
|
|
||||||
auto& uboBinding = pipelineLayoutInfo.bindings.emplace_back();
|
|
||||||
uboBinding.setIndex = 0;
|
|
||||||
uboBinding.bindingIndex = 0;
|
|
||||||
uboBinding.shaderStageFlags = nzsl::ShaderStageType::Vertex;
|
|
||||||
uboBinding.type = Nz::ShaderBindingType::UniformBuffer;
|
|
||||||
|
|
||||||
auto& textureBinding = pipelineLayoutInfo.bindings.emplace_back();
|
|
||||||
textureBinding.setIndex = 1;
|
|
||||||
textureBinding.bindingIndex = 0;
|
|
||||||
textureBinding.shaderStageFlags = nzsl::ShaderStageType::Fragment;
|
|
||||||
textureBinding.type = Nz::ShaderBindingType::Texture;
|
|
||||||
|
|
||||||
std::shared_ptr<Nz::RenderPipelineLayout> renderPipelineLayout = renderDevice->InstantiateRenderPipelineLayout(std::move(pipelineLayoutInfo));
|
|
||||||
|
|
||||||
Nz::RenderPipelineInfo pipelineInfo;
|
|
||||||
pipelineInfo.pipelineLayout = renderPipelineLayout;
|
|
||||||
pipelineInfo.shaderModules.emplace_back(shader);
|
|
||||||
|
|
||||||
pipelineInfo.depthBuffer = false;
|
|
||||||
pipelineInfo.faceCulling = Nz::FaceCulling::None;
|
|
||||||
pipelineInfo.scissorTest = true;
|
|
||||||
|
|
||||||
pipelineInfo.blending = true;
|
|
||||||
pipelineInfo.blend.modeAlpha = Nz::BlendEquation::Add;
|
|
||||||
pipelineInfo.blend.srcColor = Nz::BlendFunc::SrcAlpha;
|
|
||||||
pipelineInfo.blend.dstColor = Nz::BlendFunc::InvSrcAlpha;
|
|
||||||
pipelineInfo.blend.srcAlpha = Nz::BlendFunc::One;
|
|
||||||
pipelineInfo.blend.dstAlpha = Nz::BlendFunc::Zero;
|
|
||||||
|
|
||||||
auto& pipelineVertexBuffer = pipelineInfo.vertexBuffers.emplace_back();
|
|
||||||
pipelineVertexBuffer.binding = 0;
|
|
||||||
pipelineVertexBuffer.declaration = Nz::VertexDeclaration::Get(Nz::VertexLayout::XYZ_Color_UV);
|
|
||||||
|
|
||||||
m_texturedPipeline.pipeline = renderDevice->InstantiateRenderPipeline(pipelineInfo);
|
|
||||||
|
|
||||||
m_uboBuffer = renderDevice->InstantiateBuffer(Nz::BufferType::Uniform, sizeof(ImguiUbo), Nz::BufferUsage::DeviceLocal | Nz::BufferUsage::Dynamic);
|
|
||||||
|
|
||||||
m_texturedPipeline.uboShaderBinding = renderPipelineLayout->AllocateShaderBinding(0);
|
|
||||||
m_texturedPipeline.uboShaderBinding->Update({
|
|
||||||
{
|
|
||||||
0,
|
|
||||||
Nz::ShaderBinding::UniformBufferBinding {
|
|
||||||
m_uboBuffer.get(), 0, sizeof(ImguiUbo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Imgui::LoadUntexturedPipeline()
|
|
||||||
{
|
|
||||||
auto renderDevice = Nz::Graphics::Instance()->GetRenderDevice();
|
|
||||||
|
|
||||||
nzsl::Ast::ModulePtr shaderModule = nzsl::Parse(std::string_view(shaderSource_Untextured, sizeof(shaderSource_Untextured)));
|
|
||||||
if (!shaderModule)
|
|
||||||
{
|
|
||||||
std::cout << "Failed to parse shader module" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
nzsl::ShaderWriter::States states;
|
|
||||||
states.optimize = true;
|
|
||||||
|
|
||||||
auto shader = renderDevice->InstantiateShaderModule(nzsl::ShaderStageType::Fragment | nzsl::ShaderStageType::Vertex, *shaderModule, states);
|
|
||||||
if (!shader)
|
|
||||||
{
|
|
||||||
std::cout << "Failed to instantiate shader" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Nz::RenderPipelineLayoutInfo pipelineLayoutInfo;
|
|
||||||
|
|
||||||
auto& uboBinding = pipelineLayoutInfo.bindings.emplace_back();
|
|
||||||
uboBinding.setIndex = 0;
|
|
||||||
uboBinding.bindingIndex = 0;
|
|
||||||
uboBinding.shaderStageFlags = nzsl::ShaderStageType::Vertex;
|
|
||||||
uboBinding.type = Nz::ShaderBindingType::UniformBuffer;
|
|
||||||
|
|
||||||
std::shared_ptr<Nz::RenderPipelineLayout> renderPipelineLayout = renderDevice->InstantiateRenderPipelineLayout(std::move(pipelineLayoutInfo));
|
|
||||||
|
|
||||||
Nz::RenderPipelineInfo pipelineInfo;
|
|
||||||
pipelineInfo.pipelineLayout = renderPipelineLayout;
|
|
||||||
pipelineInfo.shaderModules.emplace_back(shader);
|
|
||||||
|
|
||||||
pipelineInfo.depthBuffer = false;
|
|
||||||
pipelineInfo.faceCulling = Nz::FaceCulling::None;
|
|
||||||
pipelineInfo.scissorTest = true;
|
|
||||||
|
|
||||||
pipelineInfo.blending = true;
|
|
||||||
pipelineInfo.blend.modeAlpha = Nz::BlendEquation::Add;
|
|
||||||
pipelineInfo.blend.srcColor = Nz::BlendFunc::SrcAlpha;
|
|
||||||
pipelineInfo.blend.dstColor = Nz::BlendFunc::InvSrcAlpha;
|
|
||||||
pipelineInfo.blend.srcAlpha = Nz::BlendFunc::One;
|
|
||||||
pipelineInfo.blend.dstAlpha = Nz::BlendFunc::Zero;
|
|
||||||
|
|
||||||
auto& pipelineVertexBuffer = pipelineInfo.vertexBuffers.emplace_back();
|
|
||||||
pipelineVertexBuffer.binding = 0;
|
|
||||||
pipelineVertexBuffer.declaration = Nz::VertexDeclaration::Get(Nz::VertexLayout::XYZ_Color_UV);
|
|
||||||
|
|
||||||
m_untexturedPipeline.pipeline = renderDevice->InstantiateRenderPipeline(pipelineInfo);
|
|
||||||
|
|
||||||
m_untexturedPipeline.uboShaderBinding = renderPipelineLayout->AllocateShaderBinding(0);
|
|
||||||
m_untexturedPipeline.uboShaderBinding->Update({
|
|
||||||
{
|
|
||||||
0,
|
|
||||||
Nz::ShaderBinding::UniformBufferBinding {
|
|
||||||
m_uboBuffer.get(), 0, sizeof(ImguiUbo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rendering callback
|
|
||||||
void Imgui::RenderDrawLists(Nz::RenderTarget* renderTarget, Nz::RenderFrame& frame, ImDrawData* drawData)
|
|
||||||
{
|
|
||||||
if (drawData->CmdListsCount == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
assert(io.Fonts->TexID != (ImTextureID)NULL); // You forgot to create and set font texture
|
|
||||||
|
|
||||||
// scale stuff (needed for proper handling of window resize)
|
|
||||||
int fb_width = static_cast<int>(io.DisplaySize.x * io.DisplayFramebufferScale.x);
|
|
||||||
int fb_height = static_cast<int>(io.DisplaySize.y * io.DisplayFramebufferScale.y);
|
|
||||||
if (fb_width == 0 || fb_height == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ImguiUbo ubo{ fb_width / 2.f, fb_height / 2.f };
|
|
||||||
auto& allocation = frame.GetUploadPool().Allocate(sizeof(ImguiUbo));
|
|
||||||
|
|
||||||
std::memcpy(allocation.mappedPtr, &ubo, sizeof(ImguiUbo));
|
|
||||||
|
|
||||||
frame.Execute([&](Nz::CommandBufferBuilder& builder)
|
|
||||||
{
|
|
||||||
builder.BeginDebugRegion("UBO Update", Nz::Color::Yellow());
|
|
||||||
{
|
|
||||||
builder.PreTransferBarrier();
|
|
||||||
builder.CopyBuffer(allocation, m_uboBuffer.get());
|
|
||||||
builder.PostTransferBarrier();
|
|
||||||
}
|
|
||||||
builder.EndDebugRegion();
|
|
||||||
}, Nz::QueueType::Transfer);
|
|
||||||
|
|
||||||
drawData->ScaleClipRects(io.DisplayFramebufferScale);
|
|
||||||
|
|
||||||
auto renderDevice = Nz::Graphics::Instance()->GetRenderDevice();
|
|
||||||
|
|
||||||
struct DrawCall
|
|
||||||
{
|
|
||||||
size_t vertex_offset, indice_offset;
|
|
||||||
std::vector<ImDrawCmd> cmdBuffer;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<DrawCall> drawCalls;
|
|
||||||
|
|
||||||
// first pass over cmd lists to prepare buffers
|
|
||||||
std::vector<Nz::VertexStruct_XYZ_Color_UV> vertices;
|
|
||||||
std::vector<uint16_t> indices;
|
|
||||||
for (int n = 0; n < drawData->CmdListsCount; ++n) {
|
|
||||||
const ImDrawList* cmd_list = drawData->CmdLists[n];
|
|
||||||
|
|
||||||
DrawCall drawCall;
|
|
||||||
drawCall.vertex_offset = vertices.size();
|
|
||||||
drawCall.indice_offset = indices.size();
|
|
||||||
|
|
||||||
vertices.reserve(vertices.size() + cmd_list->VtxBuffer.size());
|
|
||||||
for (auto& vertex : cmd_list->VtxBuffer)
|
|
||||||
vertices.push_back({ ToNzVec3(vertex.pos), ToNzColor(vertex.col), ToNzVec2(vertex.uv) });
|
|
||||||
|
|
||||||
indices.reserve(indices.size() + cmd_list->IdxBuffer.size());
|
|
||||||
for (auto indice : cmd_list->IdxBuffer)
|
|
||||||
indices.push_back(uint16_t(drawCall.vertex_offset + indice));
|
|
||||||
|
|
||||||
for (auto& cmd : cmd_list->CmdBuffer)
|
|
||||||
drawCall.cmdBuffer.push_back(cmd);
|
|
||||||
|
|
||||||
drawCalls.push_back(std::move(drawCall));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// now that we have macro buffers, allocate them on gpu
|
|
||||||
size_t size = vertices.size() * sizeof(Nz::VertexStruct_XYZ_Color_UV);
|
|
||||||
auto vertexBuffer = renderDevice->InstantiateBuffer(Nz::BufferType::Vertex, size, Nz::BufferUsage::DeviceLocal | Nz::BufferUsage::Dynamic, vertices.data());
|
|
||||||
size = indices.size() * sizeof(uint16_t);
|
|
||||||
auto indexBuffer = renderDevice->InstantiateBuffer(Nz::BufferType::Index, size, Nz::BufferUsage::DeviceLocal | Nz::BufferUsage::Dynamic, indices.data());
|
|
||||||
|
|
||||||
// freeing memory now, no need to keep buffers on CPU
|
|
||||||
vertices.clear();
|
|
||||||
indices.clear();
|
|
||||||
|
|
||||||
frame.Execute([this, renderTarget, &frame, fb_width, fb_height, drawCalls, vertexBuffer, indexBuffer](Nz::CommandBufferBuilder& builder) {
|
|
||||||
builder.BeginDebugRegion("ImGui", Nz::Color::Green());
|
|
||||||
{
|
|
||||||
Nz::Recti renderRect(0, 0, fb_width, fb_height);
|
|
||||||
|
|
||||||
builder.BeginRenderPass(renderTarget->GetFramebuffer(frame.GetFramebufferIndex()), renderTarget->GetRenderPass(), renderRect);
|
|
||||||
{
|
|
||||||
builder.SetViewport(Nz::Recti{ 0, 0, fb_width, fb_height });
|
|
||||||
builder.BindIndexBuffer(*indexBuffer, Nz::IndexType::U16);
|
|
||||||
builder.BindVertexBuffer(0, *vertexBuffer);
|
|
||||||
|
|
||||||
for (auto& drawCall : drawCalls)
|
|
||||||
{
|
|
||||||
Nz::UInt64 indexOffset = drawCall.indice_offset;
|
|
||||||
for (auto& cmd : drawCall.cmdBuffer)
|
|
||||||
{
|
|
||||||
if (!cmd.UserCallback)
|
|
||||||
{
|
|
||||||
auto rect = cmd.ClipRect;
|
|
||||||
auto count = cmd.ElemCount;
|
|
||||||
auto texture = static_cast<Nz::Texture*>(cmd.GetTexID());
|
|
||||||
|
|
||||||
if (nullptr != texture)
|
|
||||||
{
|
|
||||||
if (std::end(m_texturedPipeline.textureShaderBindings) == m_texturedPipeline.textureShaderBindings.find(texture))
|
|
||||||
{
|
|
||||||
auto binding = m_texturedPipeline.pipeline->GetPipelineInfo().pipelineLayout->AllocateShaderBinding(1);
|
|
||||||
binding->Update({
|
|
||||||
{
|
|
||||||
0,
|
|
||||||
Nz::ShaderBinding::SampledTextureBinding {
|
|
||||||
texture, m_texturedPipeline.textureSampler.get()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
m_texturedPipeline.textureShaderBindings[texture] = std::move(binding);
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.BindRenderPipeline(*m_texturedPipeline.pipeline);
|
|
||||||
builder.BindRenderShaderBinding(0, *m_texturedPipeline.uboShaderBinding);
|
|
||||||
builder.BindRenderShaderBinding(1, *m_texturedPipeline.textureShaderBindings[texture]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
builder.BindRenderPipeline(*m_untexturedPipeline.pipeline);
|
|
||||||
builder.BindRenderShaderBinding(0, *m_untexturedPipeline.uboShaderBinding);
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.SetScissor(Nz::Recti{ int(rect.x), int(rect.y), int(rect.z - rect.x), int(rect.w - rect.y) });// Nz::Recti{ int(rect.x), int(fb_height - rect.w), int(rect.z - rect.x), int(rect.w - rect.y) });
|
|
||||||
|
|
||||||
builder.DrawIndexed(count, 1, Nz::UInt32(indexOffset));
|
|
||||||
}
|
|
||||||
indexOffset += cmd.ElemCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
builder.EndRenderPass();
|
|
||||||
}
|
|
||||||
builder.EndDebugRegion();
|
|
||||||
}, Nz::QueueType::Graphics);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue