feat: add editor viewport host service
This commit is contained in:
@@ -68,6 +68,9 @@ void Application::InitializeImGui(HWND hwnd) {
|
||||
m_imguiBackend,
|
||||
m_windowRenderer.GetDevice(),
|
||||
m_windowRenderer.GetCommandQueue());
|
||||
|
||||
m_viewportHostService.Initialize(m_imguiBackend, m_windowRenderer.GetRHIDevice());
|
||||
static_cast<EditorContext*>(m_editorContext.get())->SetViewportHostService(&m_viewportHostService);
|
||||
}
|
||||
|
||||
void Application::AttachEditorLayer() {
|
||||
@@ -94,10 +97,18 @@ void Application::ShutdownEditorContext() {
|
||||
void Application::RenderEditorFrame() {
|
||||
static constexpr float kClearColor[4] = { 0.22f, 0.22f, 0.22f, 1.0f };
|
||||
m_imguiBackend.BeginFrame();
|
||||
m_viewportHostService.BeginFrame();
|
||||
m_layerStack.onImGuiRender();
|
||||
UpdateWindowTitle();
|
||||
ImGui::Render();
|
||||
m_windowRenderer.Render(m_imguiBackend, kClearColor);
|
||||
m_windowRenderer.Render(
|
||||
m_imguiBackend,
|
||||
kClearColor,
|
||||
[this](const Rendering::RenderContext& renderContext) {
|
||||
if (m_editorContext) {
|
||||
m_viewportHostService.RenderRequestedViewports(*m_editorContext, renderContext);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool Application::Initialize(HWND hwnd) {
|
||||
@@ -135,6 +146,10 @@ bool Application::Initialize(HWND hwnd) {
|
||||
void Application::Shutdown() {
|
||||
m_renderReady = false;
|
||||
DetachEditorLayer();
|
||||
if (m_editorContext) {
|
||||
static_cast<EditorContext*>(m_editorContext.get())->SetViewportHostService(nullptr);
|
||||
}
|
||||
m_viewportHostService.Shutdown();
|
||||
UI::ShutdownBuiltInIcons();
|
||||
m_imguiBackend.Shutdown();
|
||||
m_imguiSession.Shutdown();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "Platform/D3D12WindowRenderer.h"
|
||||
#include "UI/ImGuiBackendBridge.h"
|
||||
#include "UI/ImGuiSession.h"
|
||||
#include "Viewport/ViewportHostService.h"
|
||||
|
||||
#include <XCEngine/Rendering/RenderContext.h>
|
||||
#include <memory>
|
||||
@@ -35,6 +36,7 @@ public:
|
||||
Rendering::RenderContext GetMainRenderContext() const { return m_windowRenderer.GetRenderContext(); }
|
||||
RHI::RHIDevice* GetMainRHIDevice() const { return m_windowRenderer.GetRHIDevice(); }
|
||||
RHI::RHISwapChain* GetMainSwapChain() const { return m_windowRenderer.GetSwapChain(); }
|
||||
IViewportHostService& GetViewportHostService() { return m_viewportHostService; }
|
||||
bool IsRenderReady() const { return m_renderReady; }
|
||||
HWND GetWindowHandle() const { return m_hwnd; }
|
||||
|
||||
@@ -60,6 +62,7 @@ private:
|
||||
Platform::D3D12WindowRenderer m_windowRenderer;
|
||||
UI::ImGuiBackendBridge m_imguiBackend;
|
||||
UI::ImGuiSession m_imguiSession;
|
||||
ViewportHostService m_viewportHostService;
|
||||
uint64_t m_exitRequestedHandlerId = 0;
|
||||
std::wstring m_lastWindowTitle;
|
||||
bool m_renderReady = false;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "Managers/SceneManager.h"
|
||||
#include "Managers/ProjectManager.h"
|
||||
#include "EditorEvents.h"
|
||||
#include "Viewport/IViewportHostService.h"
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
@@ -56,6 +57,14 @@ public:
|
||||
return *m_undoManager;
|
||||
}
|
||||
|
||||
IViewportHostService* GetViewportHostService() override {
|
||||
return m_viewportHostService;
|
||||
}
|
||||
|
||||
void SetViewportHostService(IViewportHostService* viewportHostService) {
|
||||
m_viewportHostService = viewportHostService;
|
||||
}
|
||||
|
||||
void SetActiveActionRoute(EditorActionRoute route) override {
|
||||
m_activeActionRoute = route;
|
||||
}
|
||||
@@ -78,6 +87,7 @@ private:
|
||||
std::unique_ptr<SceneManager> m_sceneManager;
|
||||
std::unique_ptr<UndoManager> m_undoManager;
|
||||
std::unique_ptr<ProjectManager> m_projectManager;
|
||||
IViewportHostService* m_viewportHostService = nullptr;
|
||||
EditorActionRoute m_activeActionRoute = EditorActionRoute::None;
|
||||
std::string m_projectPath;
|
||||
uint64_t m_entityDeletedHandlerId;
|
||||
|
||||
@@ -13,6 +13,7 @@ class ISelectionManager;
|
||||
class IProjectManager;
|
||||
class ISceneManager;
|
||||
class IUndoManager;
|
||||
class IViewportHostService;
|
||||
|
||||
class IEditorContext {
|
||||
public:
|
||||
@@ -23,6 +24,7 @@ public:
|
||||
virtual ISceneManager& GetSceneManager() = 0;
|
||||
virtual IProjectManager& GetProjectManager() = 0;
|
||||
virtual IUndoManager& GetUndoManager() = 0;
|
||||
virtual IViewportHostService* GetViewportHostService() = 0;
|
||||
virtual void SetActiveActionRoute(EditorActionRoute route) = 0;
|
||||
virtual EditorActionRoute GetActiveActionRoute() const = 0;
|
||||
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
#include <XCEngine/Components/GameObject.h>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Components {
|
||||
class Scene;
|
||||
}
|
||||
|
||||
namespace Editor {
|
||||
|
||||
class ISceneManager {
|
||||
@@ -32,6 +36,8 @@ public:
|
||||
virtual void MarkSceneDirty() = 0;
|
||||
virtual const std::string& GetCurrentScenePath() const = 0;
|
||||
virtual const std::string& GetCurrentSceneName() const = 0;
|
||||
virtual ::XCEngine::Components::Scene* GetScene() = 0;
|
||||
virtual const ::XCEngine::Components::Scene* GetScene() const = 0;
|
||||
virtual void CreateDemoScene() = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -59,6 +59,8 @@ public:
|
||||
void MarkSceneDirty() override;
|
||||
const std::string& GetCurrentScenePath() const override { return m_currentScenePath; }
|
||||
const std::string& GetCurrentSceneName() const override { return m_currentSceneName; }
|
||||
::XCEngine::Components::Scene* GetScene() override { return m_scene.get(); }
|
||||
const ::XCEngine::Components::Scene* GetScene() const override { return m_scene.get(); }
|
||||
void CreateDemoScene() override;
|
||||
|
||||
bool HasClipboardData() const { return m_clipboard.has_value(); }
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <XCEngine/RHI/D3D12/D3D12SwapChain.h>
|
||||
|
||||
#include <d3d12.h>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <windows.h>
|
||||
|
||||
@@ -154,7 +155,10 @@ public:
|
||||
RecreateBackBufferViews();
|
||||
}
|
||||
|
||||
void Render(UI::ImGuiBackendBridge& imguiBackend, const float clearColor[4]) {
|
||||
void Render(
|
||||
UI::ImGuiBackendBridge& imguiBackend,
|
||||
const float clearColor[4],
|
||||
const std::function<void(const Rendering::RenderContext&)>& beforeUiRender = {}) {
|
||||
auto* d3d12Queue = GetD3D12CommandQueue();
|
||||
auto* d3d12CommandList = GetD3D12CommandList();
|
||||
if (m_swapChain == nullptr ||
|
||||
@@ -167,6 +171,10 @@ public:
|
||||
d3d12Queue->WaitForPreviousFrame();
|
||||
m_commandList->Reset();
|
||||
|
||||
if (beforeUiRender) {
|
||||
beforeUiRender(GetRenderContext());
|
||||
}
|
||||
|
||||
const uint32_t backBufferIndex = m_swapChain->GetCurrentBackBufferIndex();
|
||||
if (backBufferIndex >= m_backBufferViews.size() || m_backBufferViews[backBufferIndex] == nullptr) {
|
||||
return;
|
||||
|
||||
42
editor/src/Viewport/IViewportHostService.h
Normal file
42
editor/src/Viewport/IViewportHostService.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Rendering {
|
||||
struct RenderContext;
|
||||
} // namespace Rendering
|
||||
|
||||
namespace Editor {
|
||||
|
||||
class IEditorContext;
|
||||
|
||||
enum class EditorViewportKind {
|
||||
Scene,
|
||||
Game
|
||||
};
|
||||
|
||||
struct EditorViewportFrame {
|
||||
ImTextureID textureId = {};
|
||||
ImVec2 requestedSize = ImVec2(0.0f, 0.0f);
|
||||
ImVec2 renderSize = ImVec2(0.0f, 0.0f);
|
||||
bool hasTexture = false;
|
||||
bool wasRequested = false;
|
||||
std::string statusText;
|
||||
};
|
||||
|
||||
class IViewportHostService {
|
||||
public:
|
||||
virtual ~IViewportHostService() = default;
|
||||
|
||||
virtual void BeginFrame() = 0;
|
||||
virtual EditorViewportFrame RequestViewport(EditorViewportKind kind, const ImVec2& requestedSize) = 0;
|
||||
virtual void RenderRequestedViewports(
|
||||
IEditorContext& context,
|
||||
const Rendering::RenderContext& renderContext) = 0;
|
||||
};
|
||||
|
||||
} // namespace Editor
|
||||
} // namespace XCEngine
|
||||
338
editor/src/Viewport/ViewportHostService.h
Normal file
338
editor/src/Viewport/ViewportHostService.h
Normal file
@@ -0,0 +1,338 @@
|
||||
#pragma once
|
||||
|
||||
#include "Core/IEditorContext.h"
|
||||
#include "Core/ISceneManager.h"
|
||||
#include "IViewportHostService.h"
|
||||
#include "UI/ImGuiBackendBridge.h"
|
||||
|
||||
#include <XCEngine/Components/CameraComponent.h>
|
||||
#include <XCEngine/RHI/D3D12/D3D12Device.h>
|
||||
#include <XCEngine/RHI/D3D12/D3D12Texture.h>
|
||||
#include <XCEngine/RHI/RHIEnums.h>
|
||||
#include <XCEngine/RHI/RHIResourceView.h>
|
||||
#include <XCEngine/RHI/RHITexture.h>
|
||||
#include <XCEngine/Rendering/RenderContext.h>
|
||||
#include <XCEngine/Rendering/RenderSurface.h>
|
||||
#include <XCEngine/Rendering/SceneRenderer.h>
|
||||
#include <XCEngine/Scene/Scene.h>
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Editor {
|
||||
|
||||
class ViewportHostService : public IViewportHostService {
|
||||
public:
|
||||
void Initialize(UI::ImGuiBackendBridge& backend, RHI::RHIDevice* device) {
|
||||
Shutdown();
|
||||
m_backend = &backend;
|
||||
m_device = device ? static_cast<RHI::D3D12Device*>(device) : nullptr;
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
for (ViewportEntry& entry : m_entries) {
|
||||
DestroyViewportResources(entry);
|
||||
entry = {};
|
||||
}
|
||||
|
||||
m_device = nullptr;
|
||||
m_backend = nullptr;
|
||||
m_sceneRenderer.reset();
|
||||
}
|
||||
|
||||
void BeginFrame() override {
|
||||
for (ViewportEntry& entry : m_entries) {
|
||||
entry.requestedThisFrame = false;
|
||||
entry.requestedWidth = 0;
|
||||
entry.requestedHeight = 0;
|
||||
}
|
||||
}
|
||||
|
||||
EditorViewportFrame RequestViewport(EditorViewportKind kind, const ImVec2& requestedSize) override {
|
||||
ViewportEntry& entry = GetEntry(kind);
|
||||
entry.requestedThisFrame = requestedSize.x > 1.0f && requestedSize.y > 1.0f;
|
||||
entry.requestedWidth = entry.requestedThisFrame
|
||||
? static_cast<uint32_t>(requestedSize.x)
|
||||
: 0u;
|
||||
entry.requestedHeight = entry.requestedThisFrame
|
||||
? static_cast<uint32_t>(requestedSize.y)
|
||||
: 0u;
|
||||
|
||||
if (entry.requestedThisFrame && m_backend != nullptr && m_device != nullptr) {
|
||||
EnsureViewportResources(entry);
|
||||
}
|
||||
|
||||
EditorViewportFrame frame = {};
|
||||
frame.textureId = entry.textureId;
|
||||
frame.requestedSize = requestedSize;
|
||||
frame.renderSize = ImVec2(static_cast<float>(entry.width), static_cast<float>(entry.height));
|
||||
frame.hasTexture = entry.textureId != ImTextureID{};
|
||||
frame.wasRequested = entry.requestedThisFrame;
|
||||
frame.statusText = entry.statusText;
|
||||
return frame;
|
||||
}
|
||||
|
||||
void RenderRequestedViewports(
|
||||
IEditorContext& context,
|
||||
const Rendering::RenderContext& renderContext) override {
|
||||
if (m_backend == nullptr || m_device == nullptr || !renderContext.IsValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureSceneRenderer();
|
||||
const auto* scene = context.GetSceneManager().GetScene();
|
||||
|
||||
for (ViewportEntry& entry : m_entries) {
|
||||
if (!entry.requestedThisFrame) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!EnsureViewportResources(entry)) {
|
||||
entry.statusText = "Failed to create viewport render targets";
|
||||
continue;
|
||||
}
|
||||
|
||||
RenderViewportEntry(entry, scene, renderContext);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
struct ViewportEntry {
|
||||
EditorViewportKind kind = EditorViewportKind::Scene;
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
uint32_t requestedWidth = 0;
|
||||
uint32_t requestedHeight = 0;
|
||||
bool requestedThisFrame = false;
|
||||
RHI::RHITexture* colorTexture = nullptr;
|
||||
RHI::RHIResourceView* colorView = nullptr;
|
||||
RHI::RHITexture* depthTexture = nullptr;
|
||||
RHI::RHIResourceView* depthView = nullptr;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE imguiCpuHandle = {};
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE imguiGpuHandle = {};
|
||||
ImTextureID textureId = {};
|
||||
RHI::ResourceStates colorState = RHI::ResourceStates::Common;
|
||||
std::string statusText;
|
||||
};
|
||||
|
||||
ViewportEntry& GetEntry(EditorViewportKind kind) {
|
||||
const size_t index = kind == EditorViewportKind::Scene ? 0u : 1u;
|
||||
m_entries[index].kind = kind;
|
||||
return m_entries[index];
|
||||
}
|
||||
|
||||
void EnsureSceneRenderer() {
|
||||
if (!m_sceneRenderer) {
|
||||
m_sceneRenderer = std::make_unique<Rendering::SceneRenderer>();
|
||||
}
|
||||
}
|
||||
|
||||
bool EnsureViewportResources(ViewportEntry& entry) {
|
||||
if (entry.requestedWidth == 0 || entry.requestedHeight == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (entry.width == entry.requestedWidth &&
|
||||
entry.height == entry.requestedHeight &&
|
||||
entry.colorTexture != nullptr &&
|
||||
entry.colorView != nullptr &&
|
||||
entry.depthTexture != nullptr &&
|
||||
entry.depthView != nullptr &&
|
||||
entry.textureId != ImTextureID{}) {
|
||||
return true;
|
||||
}
|
||||
|
||||
DestroyViewportResources(entry);
|
||||
|
||||
entry.width = entry.requestedWidth;
|
||||
entry.height = entry.requestedHeight;
|
||||
|
||||
RHI::TextureDesc colorDesc = {};
|
||||
colorDesc.width = entry.width;
|
||||
colorDesc.height = entry.height;
|
||||
colorDesc.depth = 1;
|
||||
colorDesc.mipLevels = 1;
|
||||
colorDesc.arraySize = 1;
|
||||
colorDesc.format = static_cast<uint32_t>(RHI::Format::R8G8B8A8_UNorm);
|
||||
colorDesc.textureType = static_cast<uint32_t>(RHI::TextureType::Texture2D);
|
||||
colorDesc.sampleCount = 1;
|
||||
colorDesc.sampleQuality = 0;
|
||||
colorDesc.flags = 0;
|
||||
entry.colorTexture = m_device->CreateTexture(colorDesc);
|
||||
if (entry.colorTexture == nullptr) {
|
||||
DestroyViewportResources(entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
RHI::ResourceViewDesc colorViewDesc = {};
|
||||
colorViewDesc.format = static_cast<uint32_t>(RHI::Format::R8G8B8A8_UNorm);
|
||||
colorViewDesc.dimension = RHI::ResourceViewDimension::Texture2D;
|
||||
entry.colorView = m_device->CreateRenderTargetView(entry.colorTexture, colorViewDesc);
|
||||
if (entry.colorView == nullptr) {
|
||||
DestroyViewportResources(entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
RHI::TextureDesc depthDesc = {};
|
||||
depthDesc.width = entry.width;
|
||||
depthDesc.height = entry.height;
|
||||
depthDesc.depth = 1;
|
||||
depthDesc.mipLevels = 1;
|
||||
depthDesc.arraySize = 1;
|
||||
depthDesc.format = static_cast<uint32_t>(RHI::Format::D24_UNorm_S8_UInt);
|
||||
depthDesc.textureType = static_cast<uint32_t>(RHI::TextureType::Texture2D);
|
||||
depthDesc.sampleCount = 1;
|
||||
depthDesc.sampleQuality = 0;
|
||||
depthDesc.flags = 0;
|
||||
entry.depthTexture = m_device->CreateTexture(depthDesc);
|
||||
if (entry.depthTexture == nullptr) {
|
||||
DestroyViewportResources(entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
RHI::ResourceViewDesc depthViewDesc = {};
|
||||
depthViewDesc.format = static_cast<uint32_t>(RHI::Format::D24_UNorm_S8_UInt);
|
||||
depthViewDesc.dimension = RHI::ResourceViewDimension::Texture2D;
|
||||
entry.depthView = m_device->CreateDepthStencilView(entry.depthTexture, depthViewDesc);
|
||||
if (entry.depthView == nullptr) {
|
||||
DestroyViewportResources(entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_backend->AllocateTextureDescriptor(&entry.imguiCpuHandle, &entry.imguiGpuHandle);
|
||||
if (entry.imguiCpuHandle.ptr == 0 || entry.imguiGpuHandle.ptr == 0) {
|
||||
DestroyViewportResources(entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* nativeTexture = static_cast<RHI::D3D12Texture*>(entry.colorTexture);
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
||||
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
||||
srvDesc.Texture2D.MipLevels = 1;
|
||||
m_device->GetDevice()->CreateShaderResourceView(
|
||||
nativeTexture->GetResource(),
|
||||
&srvDesc,
|
||||
entry.imguiCpuHandle);
|
||||
|
||||
entry.textureId = static_cast<ImTextureID>(entry.imguiGpuHandle.ptr);
|
||||
entry.colorState = RHI::ResourceStates::Common;
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderViewportEntry(
|
||||
ViewportEntry& entry,
|
||||
const Components::Scene* scene,
|
||||
const Rendering::RenderContext& renderContext) {
|
||||
if (entry.colorView == nullptr || entry.depthView == nullptr) {
|
||||
entry.statusText = "Viewport render target is unavailable";
|
||||
return;
|
||||
}
|
||||
|
||||
if (scene == nullptr) {
|
||||
entry.statusText = "No active scene";
|
||||
ClearViewport(entry, renderContext, 0.07f, 0.08f, 0.10f, 1.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto cameras = scene->FindObjectsOfType<Components::CameraComponent>();
|
||||
if (cameras.empty()) {
|
||||
entry.statusText = "No camera in scene";
|
||||
ClearViewport(entry, renderContext, 0.10f, 0.09f, 0.08f, 1.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
Rendering::RenderSurface surface(entry.width, entry.height);
|
||||
surface.SetColorAttachment(entry.colorView);
|
||||
surface.SetDepthAttachment(entry.depthView);
|
||||
surface.SetColorStateBefore(entry.colorState);
|
||||
surface.SetColorStateAfter(RHI::ResourceStates::PixelShaderResource);
|
||||
|
||||
if (!m_sceneRenderer->Render(*scene, nullptr, renderContext, surface)) {
|
||||
entry.statusText = "Scene renderer failed";
|
||||
ClearViewport(entry, renderContext, 0.18f, 0.07f, 0.07f, 1.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
entry.colorState = RHI::ResourceStates::PixelShaderResource;
|
||||
entry.statusText.clear();
|
||||
}
|
||||
|
||||
void ClearViewport(
|
||||
ViewportEntry& entry,
|
||||
const Rendering::RenderContext& renderContext,
|
||||
float r,
|
||||
float g,
|
||||
float b,
|
||||
float a) {
|
||||
RHI::RHICommandList* commandList = renderContext.commandList;
|
||||
if (commandList == nullptr) {
|
||||
entry.statusText = "Viewport command list is unavailable";
|
||||
return;
|
||||
}
|
||||
|
||||
const float clearColor[4] = { r, g, b, a };
|
||||
RHI::RHIResourceView* colorView = entry.colorView;
|
||||
commandList->TransitionBarrier(
|
||||
colorView,
|
||||
entry.colorState,
|
||||
RHI::ResourceStates::RenderTarget);
|
||||
commandList->SetRenderTargets(1, &colorView, entry.depthView);
|
||||
commandList->ClearRenderTarget(colorView, clearColor);
|
||||
commandList->ClearDepthStencil(entry.depthView, 1.0f, 0);
|
||||
commandList->TransitionBarrier(
|
||||
colorView,
|
||||
RHI::ResourceStates::RenderTarget,
|
||||
RHI::ResourceStates::PixelShaderResource);
|
||||
entry.colorState = RHI::ResourceStates::PixelShaderResource;
|
||||
}
|
||||
|
||||
void DestroyViewportResources(ViewportEntry& entry) {
|
||||
if (m_backend != nullptr && entry.imguiCpuHandle.ptr != 0) {
|
||||
m_backend->FreeTextureDescriptor(entry.imguiCpuHandle, entry.imguiGpuHandle);
|
||||
}
|
||||
|
||||
if (entry.depthView != nullptr) {
|
||||
entry.depthView->Shutdown();
|
||||
delete entry.depthView;
|
||||
entry.depthView = nullptr;
|
||||
}
|
||||
|
||||
if (entry.depthTexture != nullptr) {
|
||||
entry.depthTexture->Shutdown();
|
||||
delete entry.depthTexture;
|
||||
entry.depthTexture = nullptr;
|
||||
}
|
||||
|
||||
if (entry.colorView != nullptr) {
|
||||
entry.colorView->Shutdown();
|
||||
delete entry.colorView;
|
||||
entry.colorView = nullptr;
|
||||
}
|
||||
|
||||
if (entry.colorTexture != nullptr) {
|
||||
entry.colorTexture->Shutdown();
|
||||
delete entry.colorTexture;
|
||||
entry.colorTexture = nullptr;
|
||||
}
|
||||
|
||||
entry.width = 0;
|
||||
entry.height = 0;
|
||||
entry.imguiCpuHandle = {};
|
||||
entry.imguiGpuHandle = {};
|
||||
entry.textureId = {};
|
||||
entry.colorState = RHI::ResourceStates::Common;
|
||||
}
|
||||
|
||||
UI::ImGuiBackendBridge* m_backend = nullptr;
|
||||
RHI::D3D12Device* m_device = nullptr;
|
||||
std::unique_ptr<Rendering::SceneRenderer> m_sceneRenderer;
|
||||
std::array<ViewportEntry, 2> m_entries = {};
|
||||
};
|
||||
|
||||
} // namespace Editor
|
||||
} // namespace XCEngine
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "Actions/ActionRouting.h"
|
||||
#include "GameViewPanel.h"
|
||||
#include "ViewportPanelContent.h"
|
||||
#include "UI/UI.h"
|
||||
#include <imgui.h>
|
||||
|
||||
@@ -14,6 +15,7 @@ void GameViewPanel::Render() {
|
||||
return;
|
||||
}
|
||||
|
||||
RenderViewportPanelContent(*m_context, EditorViewportKind::Game);
|
||||
Actions::ObserveInactiveActionRoute(*m_context);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "Actions/ActionRouting.h"
|
||||
#include "SceneViewPanel.h"
|
||||
#include "ViewportPanelContent.h"
|
||||
#include "UI/UI.h"
|
||||
#include <imgui.h>
|
||||
|
||||
@@ -14,6 +15,7 @@ void SceneViewPanel::Render() {
|
||||
return;
|
||||
}
|
||||
|
||||
RenderViewportPanelContent(*m_context, EditorViewportKind::Scene);
|
||||
Actions::ObserveInactiveActionRoute(*m_context);
|
||||
}
|
||||
|
||||
|
||||
60
editor/src/panels/ViewportPanelContent.h
Normal file
60
editor/src/panels/ViewportPanelContent.h
Normal file
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include "Core/IEditorContext.h"
|
||||
#include "Viewport/IViewportHostService.h"
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Editor {
|
||||
|
||||
inline void DrawViewportStatusMessage(const std::string& message) {
|
||||
if (message.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ImDrawList* drawList = ImGui::GetWindowDrawList();
|
||||
if (drawList == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ImVec2 min = ImGui::GetItemRectMin();
|
||||
const ImVec2 max = ImGui::GetItemRectMax();
|
||||
const ImVec2 textSize = ImGui::CalcTextSize(message.c_str());
|
||||
const ImVec2 textPos(
|
||||
min.x + ((max.x - min.x) - textSize.x) * 0.5f,
|
||||
min.y + ((max.y - min.y) - textSize.y) * 0.5f);
|
||||
|
||||
drawList->AddText(textPos, ImGui::GetColorU32(ImGuiCol_TextDisabled), message.c_str());
|
||||
}
|
||||
|
||||
inline void RenderViewportPanelContent(IEditorContext& context, EditorViewportKind kind) {
|
||||
IViewportHostService* viewportHostService = context.GetViewportHostService();
|
||||
const ImVec2 availableSize = ImGui::GetContentRegionAvail();
|
||||
if (availableSize.x <= 1.0f || availableSize.y <= 1.0f) {
|
||||
ImGui::Dummy(ImVec2(0.0f, 0.0f));
|
||||
return;
|
||||
}
|
||||
|
||||
if (viewportHostService == nullptr) {
|
||||
ImGui::Dummy(availableSize);
|
||||
DrawViewportStatusMessage("Viewport host is unavailable");
|
||||
return;
|
||||
}
|
||||
|
||||
const EditorViewportFrame frame = viewportHostService->RequestViewport(kind, availableSize);
|
||||
if (frame.hasTexture) {
|
||||
ImGui::Image(frame.textureId, availableSize);
|
||||
DrawViewportStatusMessage(frame.statusText);
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::Dummy(availableSize);
|
||||
DrawViewportStatusMessage(
|
||||
frame.statusText.empty() ? "Viewport is initializing" : frame.statusText);
|
||||
}
|
||||
|
||||
} // namespace Editor
|
||||
} // namespace XCEngine
|
||||
Reference in New Issue
Block a user