Files
XCEngine/editor/src/panels/ViewportPanelContent.h

126 lines
4.0 KiB
C++

#pragma once
#include "Core/IEditorContext.h"
#include "Viewport/IViewportHostService.h"
#include "UI/UI.h"
#include <imgui.h>
#include <string>
namespace XCEngine {
namespace Editor {
inline ::XCEngine::UI::UISize ToUISize(const ImVec2& value) {
return ::XCEngine::UI::UISize(value.x, value.y);
}
inline ImTextureID ToImGuiTextureId(const ::XCEngine::UI::UITextureHandle& texture) {
return static_cast<ImTextureID>(texture.nativeHandle);
}
struct ViewportPanelContentResult {
EditorViewportFrame frame;
ImVec2 availableSize = ImVec2(0.0f, 0.0f);
ImVec2 itemMin = ImVec2(0.0f, 0.0f);
ImVec2 itemMax = ImVec2(0.0f, 0.0f);
bool hasViewportArea = false;
bool hovered = false;
bool focused = false;
bool clickedLeft = false;
bool clickedRight = false;
bool clickedMiddle = false;
};
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 const char* GetViewportInteractionSurfaceId(EditorViewportKind kind) {
switch (kind) {
case EditorViewportKind::Scene:
return "##SceneViewportInteractionSurface";
case EditorViewportKind::Game:
return "##GameViewportInteractionSurface";
default:
return "##ViewportInteractionSurface";
}
}
inline void RenderViewportInteractionSurface(
ViewportPanelContentResult& result,
EditorViewportKind kind,
const ImVec2& interactionSize) {
ImGui::SetNextItemAllowOverlap();
ImGui::InvisibleButton(
GetViewportInteractionSurfaceId(kind),
interactionSize,
ImGuiButtonFlags_MouseButtonLeft |
ImGuiButtonFlags_MouseButtonRight |
ImGuiButtonFlags_MouseButtonMiddle);
result.itemMin = ImGui::GetItemRectMin();
result.itemMax = ImGui::GetItemRectMax();
result.hovered = ImGui::IsItemHovered();
result.clickedLeft = ImGui::IsItemClicked(ImGuiMouseButton_Left);
result.clickedRight = ImGui::IsItemClicked(ImGuiMouseButton_Right);
result.clickedMiddle = ImGui::IsItemClicked(ImGuiMouseButton_Middle);
}
inline ViewportPanelContentResult RenderViewportPanelContent(
IEditorContext& context,
EditorViewportKind kind) {
ViewportPanelContentResult result = {};
UI::CollapsePanelSectionSpacing();
result.availableSize = ImGui::GetContentRegionAvail();
result.focused = ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows);
IViewportHostService* viewportHostService = context.GetViewportHostService();
if (result.availableSize.x <= 1.0f || result.availableSize.y <= 1.0f) {
ImGui::Dummy(ImVec2(0.0f, 0.0f));
return result;
}
result.hasViewportArea = true;
if (viewportHostService == nullptr) {
RenderViewportInteractionSurface(result, kind, result.availableSize);
DrawViewportStatusMessage("Viewport host is unavailable");
return result;
}
result.frame = viewportHostService->RequestViewport(kind, ToUISize(result.availableSize));
RenderViewportInteractionSurface(result, kind, result.availableSize);
if (result.frame.hasTexture) {
if (ImDrawList* drawList = ImGui::GetWindowDrawList()) {
drawList->AddImage(ToImGuiTextureId(result.frame.texture), result.itemMin, result.itemMax);
}
}
DrawViewportStatusMessage(
result.frame.statusText.empty() && !result.frame.hasTexture
? "Viewport is initializing"
: result.frame.statusText);
return result;
}
} // namespace Editor
} // namespace XCEngine