feat: move rendering to an imgui window
This commit is contained in:
+139
-11
@@ -14,6 +14,7 @@
|
||||
#include <destrum/Util/DeltaTime.h>
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_internal.h"
|
||||
#include "glm/gtx/transform.hpp"
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
@@ -158,9 +159,15 @@ void App::run()
|
||||
event.type == SDL_KEYUP ||
|
||||
event.type == SDL_TEXTINPUT;
|
||||
|
||||
// ImGui wants every event while a window is hovered or focused, the editor viewport
|
||||
// is one, so the game gets them there instead
|
||||
const bool mouseCaptured = InputManager::GetInstance().IsMouseCaptured();
|
||||
const bool viewportGetsMouse = usesEditorViewport() && viewportHovered && !viewportMouseClaimed;
|
||||
const bool viewportGetsKeyboard = usesEditorViewport() && (viewportFocused || mouseCaptured) &&
|
||||
!ImGui::GetIO().WantTextInput;
|
||||
const bool capturedByImgui =
|
||||
(mouseEvent && !InputManager::GetInstance().IsMouseCaptured() && imguiPass.wantsMouse()) ||
|
||||
(keyboardEvent && imguiPass.wantsKeyboard());
|
||||
(mouseEvent && !mouseCaptured && !viewportGetsMouse && imguiPass.wantsMouse()) ||
|
||||
(keyboardEvent && !viewportGetsKeyboard && imguiPass.wantsKeyboard());
|
||||
|
||||
if (!capturedByImgui)
|
||||
{
|
||||
@@ -184,24 +191,39 @@ if (!isRunning) break;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (InputManager::GetInstance().WasKeyPressed(SDL_SCANCODE_F5))
|
||||
{
|
||||
playModeToggleRequested = true;
|
||||
}
|
||||
if (playing && InputManager::GetInstance().WasKeyPressed(SDL_SCANCODE_F7))
|
||||
{
|
||||
setPaused(!paused);
|
||||
}
|
||||
|
||||
// Consume SDL events before updating the base camera so held and
|
||||
// newly pressed inputs are applied in the same frame.
|
||||
camera.Update(dt);
|
||||
|
||||
if (usesEditorViewport())
|
||||
{
|
||||
applyViewportResize();
|
||||
}
|
||||
|
||||
{
|
||||
ZoneScopedN("ImGui BeginFrame");
|
||||
imguiPass.beginFrame();
|
||||
}
|
||||
|
||||
{
|
||||
// Global shortcuts, also when an editor window has keyboard focus
|
||||
const auto& input = InputManager::GetInstance();
|
||||
const bool typing = ImGui::GetIO().WantTextInput;
|
||||
if (input.WasKeyPressed(SDL_SCANCODE_F5) || (!typing && ImGui::IsKeyPressed(ImGuiKey_F5, false)))
|
||||
{
|
||||
playModeToggleRequested = true;
|
||||
}
|
||||
if (playing && (input.WasKeyPressed(SDL_SCANCODE_F7) || (!typing && ImGui::IsKeyPressed(ImGuiKey_F7, false))))
|
||||
{
|
||||
setPaused(!paused);
|
||||
}
|
||||
}
|
||||
|
||||
if (usesEditorViewport())
|
||||
{
|
||||
drawDockSpace();
|
||||
}
|
||||
|
||||
{
|
||||
ZoneScopedN("customUpdate");
|
||||
customUpdate(dt);
|
||||
@@ -211,6 +233,7 @@ if (!isRunning) break;
|
||||
{
|
||||
ZoneScopedN("Debug ImGui");
|
||||
drawWindowsMenu();
|
||||
drawViewportWindow();
|
||||
|
||||
if (m_DebugWindows.inspector)
|
||||
{
|
||||
@@ -336,6 +359,11 @@ if (!isRunning) break;
|
||||
}
|
||||
spdlog::info("Recreated swapchain at {}x{}", w, h);
|
||||
imguiPass.onSwapchainRecreated();
|
||||
if (!usesEditorViewport())
|
||||
{
|
||||
renderer.resize(gfxDevice, drawableSize);
|
||||
onViewportResize(w, h);
|
||||
}
|
||||
onWindowResize(w, h);
|
||||
}
|
||||
|
||||
@@ -433,6 +461,106 @@ void App::drawWindowsMenu()
|
||||
ImGui::EndMainMenuBar();
|
||||
}
|
||||
|
||||
void App::drawDockSpace()
|
||||
{
|
||||
const ImGuiID dockspaceId = ImGui::GetID("EditorDockSpace");
|
||||
const bool hasSavedLayout = ImGui::DockBuilderGetNode(dockspaceId) != nullptr;
|
||||
const ImGuiViewport* mainViewport = ImGui::GetMainViewport();
|
||||
ImGui::DockSpaceOverViewport(dockspaceId, mainViewport);
|
||||
if (hasSavedLayout)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// First run without an imgui.ini: scene in the middle, inspector right, tools left
|
||||
ImGui::DockBuilderRemoveNode(dockspaceId);
|
||||
ImGui::DockBuilderAddNode(dockspaceId, ImGuiDockNodeFlags_DockSpace);
|
||||
ImGui::DockBuilderSetNodeSize(dockspaceId, mainViewport->WorkSize);
|
||||
|
||||
ImGuiID center = dockspaceId;
|
||||
const ImGuiID right = ImGui::DockBuilderSplitNode(center, ImGuiDir_Right, 0.25f, nullptr, ¢er);
|
||||
const ImGuiID left = ImGui::DockBuilderSplitNode(center, ImGuiDir_Left, 0.22f, nullptr, ¢er);
|
||||
|
||||
ImGui::DockBuilderDockWindow("Viewport", center);
|
||||
ImGui::DockBuilderDockWindow("Inspector", right);
|
||||
ImGui::DockBuilderDockWindow("Debug", left);
|
||||
ImGui::DockBuilderDockWindow("Physics", left);
|
||||
ImGui::DockBuilderFinish(dockspaceId);
|
||||
}
|
||||
|
||||
void App::drawViewportWindow()
|
||||
{
|
||||
viewportMouseClaimed = false;
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2{0.0f, 0.0f});
|
||||
const bool visible = ImGui::Begin("Viewport", nullptr, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
if (!visible)
|
||||
{
|
||||
viewportHovered = false;
|
||||
viewportFocused = false;
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
const ImVec2 origin = ImGui::GetCursorScreenPos();
|
||||
const ImVec2 available = ImGui::GetContentRegionAvail();
|
||||
const ImVec2 framebufferScale = ImGui::GetIO().DisplayFramebufferScale;
|
||||
viewportRect = {
|
||||
.min = {origin.x, origin.y},
|
||||
.size = {std::max(available.x, 1.0f), std::max(available.y, 1.0f)},
|
||||
};
|
||||
viewportDesiredSize = {
|
||||
std::max(static_cast<int>(available.x * framebufferScale.x), 1),
|
||||
std::max(static_cast<int>(available.y * framebufferScale.y), 1),
|
||||
};
|
||||
|
||||
const GPUImage& drawImage = renderer.getDrawImage();
|
||||
if (const ImTextureID texture = imguiPass.getFrameTexture(drawImage.imageView); texture != ImTextureID{})
|
||||
{
|
||||
ImGui::Image(texture, ImVec2{viewportRect.size.x, viewportRect.size.y});
|
||||
}
|
||||
|
||||
viewportHovered = ImGui::IsWindowHovered();
|
||||
// ImGui only focuses windows on a left click, the free camera looks around with the right button
|
||||
if (viewportHovered && (ImGui::IsMouseClicked(ImGuiMouseButton_Right) || ImGui::IsMouseClicked(ImGuiMouseButton_Middle)))
|
||||
{
|
||||
ImGui::SetWindowFocus();
|
||||
}
|
||||
viewportFocused = ImGui::IsWindowFocused();
|
||||
|
||||
ImGui::SetCursorScreenPos(origin);
|
||||
drawViewportOverlay();
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void App::applyViewportResize()
|
||||
{
|
||||
if (viewportDesiredSize.x <= 0 || viewportDesiredSize.y <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const VkExtent3D current = renderer.getDrawImage().extent;
|
||||
if (static_cast<int>(current.width) == viewportDesiredSize.x &&
|
||||
static_cast<int>(current.height) == viewportDesiredSize.y)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// While a dock splitter is dragged the old image is stretched, recreating it every frame is wasteful
|
||||
if (ImGui::GetIO().MouseDown[ImGuiMouseButton_Left])
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ZoneScopedN("Resize Viewport");
|
||||
renderer.resize(gfxDevice, viewportDesiredSize);
|
||||
onViewportResize(viewportDesiredSize.x, viewportDesiredSize.y);
|
||||
}
|
||||
|
||||
void App::drawPlayControls()
|
||||
{
|
||||
const char* state = !playing ? "EDIT" : paused ? "PAUSED" : "PLAYING";
|
||||
|
||||
Reference in New Issue
Block a user