Formalize scene viewport HUD overlay

This commit is contained in:
2026-04-03 17:04:34 +08:00
parent 2de254a16f
commit 5d24fd0337
9 changed files with 277 additions and 54 deletions

View File

@@ -82,10 +82,10 @@ add_executable(${PROJECT_NAME} WIN32
src/Viewport/SceneViewportMoveGizmo.cpp
src/Viewport/SceneViewportRotateGizmo.cpp
src/Viewport/SceneViewportScaleGizmo.cpp
src/Viewport/SceneViewportHudOverlay.cpp
src/Viewport/SceneViewportOrientationGizmo.cpp
src/Viewport/SceneViewportOverlayBuilder.cpp
src/Viewport/SceneViewportOverlayProviders.cpp
src/Viewport/SceneViewportOverlayRenderer.cpp
src/Viewport/Passes/SceneViewportEditorOverlayPass.cpp
src/Viewport/Passes/SceneViewportGridPass.cpp
src/Viewport/Passes/SceneViewportSelectionOutlinePass.cpp

View File

@@ -0,0 +1,64 @@
#include "SceneViewportHudOverlay.h"
#include "SceneViewportOrientationGizmo.h"
namespace XCEngine {
namespace Editor {
namespace {
bool IsViewportRectValid(const ImVec2& viewportMin, const ImVec2& viewportMax) {
return viewportMax.x - viewportMin.x > 1.0f &&
viewportMax.y - viewportMin.y > 1.0f;
}
} // namespace
void DrawSceneViewportHudOverlay(
ImDrawList* drawList,
const SceneViewportHudOverlayData& overlay,
const ImVec2& viewportMin,
const ImVec2& viewportMax) {
if (drawList == nullptr ||
!overlay.HasVisibleElements() ||
!IsViewportRectValid(viewportMin, viewportMax)) {
return;
}
drawList->PushClipRect(viewportMin, viewportMax, true);
if (overlay.showOrientationGizmo) {
DrawSceneViewportOrientationGizmo(
drawList,
overlay.sceneOverlay,
viewportMin,
viewportMax);
}
drawList->PopClipRect();
}
SceneViewportHudOverlayHitResult HitTestSceneViewportHudOverlay(
const SceneViewportHudOverlayData& overlay,
const ImVec2& viewportMin,
const ImVec2& viewportMax,
const ImVec2& mousePosition) {
SceneViewportHudOverlayHitResult result = {};
if (!overlay.HasVisibleElements() || !IsViewportRectValid(viewportMin, viewportMax)) {
return result;
}
if (overlay.showOrientationGizmo) {
const SceneViewportOrientationAxis axis = HitTestSceneViewportOrientationGizmo(
overlay.sceneOverlay,
viewportMin,
viewportMax,
mousePosition);
if (axis != SceneViewportOrientationAxis::None) {
result.kind = SceneViewportHudOverlayHitKind::OrientationAxis;
result.orientationAxis = axis;
}
}
return result;
}
} // namespace Editor
} // namespace XCEngine

View File

@@ -0,0 +1,57 @@
#pragma once
#include "IViewportHostService.h"
#include <imgui.h>
#include <cstdint>
namespace XCEngine {
namespace Editor {
enum class SceneViewportHudOverlayHitKind : uint8_t {
None = 0,
OrientationAxis
};
struct SceneViewportHudOverlayHitResult {
SceneViewportHudOverlayHitKind kind = SceneViewportHudOverlayHitKind::None;
SceneViewportOrientationAxis orientationAxis = SceneViewportOrientationAxis::None;
bool HasHit() const {
return kind != SceneViewportHudOverlayHitKind::None;
}
};
struct SceneViewportHudOverlayData {
SceneViewportOverlayData sceneOverlay = {};
bool showOrientationGizmo = true;
bool HasVisibleElements() const {
return sceneOverlay.valid && showOrientationGizmo;
}
};
inline SceneViewportHudOverlayData BuildSceneViewportHudOverlayData(
const SceneViewportOverlayData& sceneOverlay,
bool showOrientationGizmo = true) {
SceneViewportHudOverlayData data = {};
data.sceneOverlay = sceneOverlay;
data.showOrientationGizmo = showOrientationGizmo;
return data;
}
void DrawSceneViewportHudOverlay(
ImDrawList* drawList,
const SceneViewportHudOverlayData& overlay,
const ImVec2& viewportMin,
const ImVec2& viewportMax);
SceneViewportHudOverlayHitResult HitTestSceneViewportHudOverlay(
const SceneViewportHudOverlayData& overlay,
const ImVec2& viewportMin,
const ImVec2& viewportMax,
const ImVec2& mousePosition);
} // namespace Editor
} // namespace XCEngine

View File

@@ -1,26 +0,0 @@
#include "SceneViewportOverlayRenderer.h"
#include "SceneViewportOrientationGizmo.h"
namespace XCEngine {
namespace Editor {
void DrawSceneViewportOverlay(
ImDrawList* drawList,
const SceneViewportOverlayData& overlay,
const ImVec2& viewportMin,
const ImVec2& viewportMax,
const ImVec2& viewportSize) {
if (drawList == nullptr || viewportSize.x <= 1.0f || viewportSize.y <= 1.0f) {
return;
}
drawList->PushClipRect(viewportMin, viewportMax, true);
if (overlay.valid) {
DrawSceneViewportOrientationGizmo(drawList, overlay, viewportMin, viewportMax);
}
drawList->PopClipRect();
}
} // namespace Editor
} // namespace XCEngine

View File

@@ -1,18 +0,0 @@
#pragma once
#include "IViewportHostService.h"
#include <imgui.h>
namespace XCEngine {
namespace Editor {
void DrawSceneViewportOverlay(
ImDrawList* drawList,
const SceneViewportOverlayData& overlay,
const ImVec2& viewportMin,
const ImVec2& viewportMax,
const ImVec2& viewportSize);
} // namespace Editor
} // namespace XCEngine

View File

@@ -4,11 +4,10 @@
#include "Core/ISelectionManager.h"
#include "SceneViewPanel.h"
#include "Viewport/SceneViewportEditorOverlayData.h"
#include "Viewport/SceneViewportHudOverlay.h"
#include "Viewport/SceneViewportOverlayHandleBuilder.h"
#include "Viewport/SceneViewportOverlayHitTester.h"
#include "Viewport/SceneViewportMath.h"
#include "Viewport/SceneViewportOrientationGizmo.h"
#include "Viewport/SceneViewportOverlayRenderer.h"
#include "Viewport/SceneViewportTransformGizmoFrameBuilder.h"
#include "ViewportPanelContent.h"
#include "Platform/Win32Utf8.h"
@@ -139,6 +138,17 @@ SceneViewportInteractionCandidate BuildOrientationGizmoInteractionCandidate(
return candidate;
}
SceneViewportInteractionCandidate BuildHudOverlayInteractionCandidate(
const SceneViewportHudOverlayHitResult& hitResult) {
switch (hitResult.kind) {
case SceneViewportHudOverlayHitKind::OrientationAxis:
return BuildOrientationGizmoInteractionCandidate(hitResult.orientationAxis);
case SceneViewportHudOverlayHitKind::None:
default:
return {};
}
}
SceneViewportInteractionCandidate BuildOverlayHandleInteractionCandidate(
const SceneViewportOverlayHandleHitResult& hitResult) {
SceneViewportInteractionCandidate candidate = {};
@@ -549,6 +559,8 @@ void SceneViewPanel::Render() {
activeGizmoKind = SceneViewportActiveGizmoKind::None;
}
const bool gizmoActive = activeGizmoKind != SceneViewportActiveGizmoKind::None;
const SceneViewportHudOverlayData interactionHudOverlay =
BuildSceneViewportHudOverlayData(overlay);
SceneViewportInteractionCandidate hoveredInteraction = {};
const bool canResolveViewportInteraction =
hasInteractiveViewport &&
@@ -564,9 +576,9 @@ void SceneViewPanel::Render() {
hoveredInteraction);
AccumulateSceneViewportInteractionCandidate(
BuildOrientationGizmoInteractionCandidate(
HitTestSceneViewportOrientationGizmo(
overlay,
BuildHudOverlayInteractionCandidate(
HitTestSceneViewportHudOverlay(
interactionHudOverlay,
content.itemMin,
content.itemMax,
io.MousePos)),
@@ -812,12 +824,11 @@ void SceneViewPanel::Render() {
m_scaleGizmo,
drawGizmoFrameState.scaleContext)));
DrawSceneViewportOverlay(
DrawSceneViewportHudOverlay(
ImGui::GetWindowDrawList(),
overlay,
BuildSceneViewportHudOverlayData(overlay),
content.itemMin,
content.itemMax,
content.availableSize);
content.itemMax);
}
}