Files
XCEngine/editor/src/panels/SceneViewPanel.cpp

218 lines
8.2 KiB
C++
Raw Normal View History

2026-03-26 22:31:22 +08:00
#include "Actions/ActionRouting.h"
#include "Core/IEditorContext.h"
2026-03-29 16:18:13 +08:00
#include "Core/ISceneManager.h"
#include "Core/ISelectionManager.h"
#include "SceneViewPanel.h"
#include "Viewport/SceneViewportOverlayRenderer.h"
2026-03-28 17:04:14 +08:00
#include "ViewportPanelContent.h"
2026-03-26 21:18:33 +08:00
#include "UI/UI.h"
2026-03-28 17:50:54 +08:00
#include <imgui.h>
namespace XCEngine {
namespace Editor {
2026-03-29 16:18:13 +08:00
namespace {
SceneViewportMoveGizmoContext BuildMoveGizmoContext(
IEditorContext& context,
const SceneViewportOverlayData& overlay,
const ViewportPanelContentResult& content,
const ImVec2& mousePosition) {
SceneViewportMoveGizmoContext gizmoContext = {};
gizmoContext.overlay = overlay;
gizmoContext.viewportSize = Math::Vector2(content.availableSize.x, content.availableSize.y);
gizmoContext.mousePosition = Math::Vector2(
mousePosition.x - content.itemMin.x,
mousePosition.y - content.itemMin.y);
if (context.GetSelectionManager().GetSelectionCount() == 1) {
const uint64_t selectedEntity = context.GetSelectionManager().GetSelectedEntity();
if (selectedEntity != 0) {
gizmoContext.selectedObject = context.GetSceneManager().GetEntity(selectedEntity);
}
}
return gizmoContext;
}
} // namespace
SceneViewPanel::SceneViewPanel() : Panel("Scene") {}
void SceneViewPanel::Render() {
2026-03-29 16:18:13 +08:00
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
UI::PanelWindowScope panel(m_name.c_str());
2026-03-29 16:18:13 +08:00
ImGui::PopStyleVar();
2026-03-26 22:31:22 +08:00
if (!panel.IsOpen()) {
return;
}
const ViewportPanelContentResult content = RenderViewportPanelContent(*m_context, EditorViewportKind::Scene);
if (IViewportHostService* viewportHostService = m_context->GetViewportHostService()) {
const ImGuiIO& io = ImGui::GetIO();
2026-03-29 16:18:13 +08:00
const bool hasInteractiveViewport = content.hasViewportArea && content.frame.hasTexture;
SceneViewportOverlayData overlay = {};
SceneViewportMoveGizmoContext moveGizmoContext = {};
if (hasInteractiveViewport) {
overlay = viewportHostService->GetSceneViewOverlayData();
moveGizmoContext = BuildMoveGizmoContext(*m_context, overlay, content, io.MousePos);
if (m_moveGizmo.IsActive() &&
(moveGizmoContext.selectedObject == nullptr ||
m_context->GetSelectionManager().GetSelectedEntity() != m_moveGizmo.GetActiveEntityId())) {
m_moveGizmo.CancelDrag(&m_context->GetUndoManager());
}
m_moveGizmo.Update(moveGizmoContext);
} else if (m_moveGizmo.IsActive()) {
m_moveGizmo.CancelDrag(&m_context->GetUndoManager());
}
const bool beginMoveGizmo =
hasInteractiveViewport &&
content.hovered &&
ImGui::IsMouseClicked(ImGuiMouseButton_Left) &&
!m_lookDragging &&
!m_panDragging &&
m_moveGizmo.IsHoveringHandle();
const bool selectClick =
2026-03-29 16:18:13 +08:00
hasInteractiveViewport &&
content.hovered &&
ImGui::IsMouseClicked(ImGuiMouseButton_Left) &&
!m_lookDragging &&
2026-03-29 16:18:13 +08:00
!m_panDragging &&
!m_moveGizmo.IsHoveringHandle() &&
!m_moveGizmo.IsActive();
const bool beginLookDrag =
2026-03-29 16:18:13 +08:00
content.hovered &&
!m_moveGizmo.IsActive() &&
ImGui::IsMouseClicked(ImGuiMouseButton_Right);
const bool beginPanDrag =
2026-03-29 16:18:13 +08:00
content.hovered &&
!m_moveGizmo.IsActive() &&
ImGui::IsMouseClicked(ImGuiMouseButton_Middle);
2026-03-29 16:18:13 +08:00
if (beginMoveGizmo || selectClick || beginLookDrag || beginPanDrag) {
ImGui::SetWindowFocus();
}
2026-03-29 16:18:13 +08:00
if (beginMoveGizmo) {
m_moveGizmo.TryBeginDrag(moveGizmoContext, m_context->GetUndoManager());
}
if (selectClick) {
const ImVec2 localMousePosition(
io.MousePos.x - content.itemMin.x,
io.MousePos.y - content.itemMin.y);
const uint64_t selectedEntity = viewportHostService->PickSceneViewEntity(
*m_context,
content.availableSize,
localMousePosition);
if (selectedEntity != 0) {
m_context->GetSelectionManager().SetSelectedEntity(selectedEntity);
} else {
m_context->GetSelectionManager().ClearSelection();
}
}
2026-03-29 16:18:13 +08:00
if (m_moveGizmo.IsActive()) {
if (ImGui::IsMouseDown(ImGuiMouseButton_Left)) {
m_moveGizmo.UpdateDrag(moveGizmoContext);
} else {
m_moveGizmo.EndDrag(m_context->GetUndoManager());
}
}
if (beginLookDrag) {
m_lookDragging = true;
m_lastLookDragDelta = ImVec2(0.0f, 0.0f);
}
if (beginPanDrag) {
m_panDragging = true;
m_lastPanDragDelta = ImVec2(0.0f, 0.0f);
}
if (m_lookDragging && !ImGui::IsMouseDown(ImGuiMouseButton_Right)) {
m_lookDragging = false;
m_lastLookDragDelta = ImVec2(0.0f, 0.0f);
}
if (m_panDragging && !ImGui::IsMouseDown(ImGuiMouseButton_Middle)) {
m_panDragging = false;
m_lastPanDragDelta = ImVec2(0.0f, 0.0f);
}
2026-03-29 16:18:13 +08:00
if (m_lookDragging || m_panDragging || m_moveGizmo.IsActive()) {
ImGui::SetNextFrameWantCaptureMouse(true);
}
if (m_lookDragging) {
ImGui::SetNextFrameWantCaptureKeyboard(true);
}
SceneViewportInput input = {};
input.viewportSize = content.availableSize;
2026-03-28 18:28:11 +08:00
input.deltaTime = io.DeltaTime;
input.hovered = content.hovered;
input.focused = content.focused || m_lookDragging || m_panDragging;
input.mouseWheel = (content.hovered && !m_lookDragging) ? io.MouseWheel : 0.0f;
input.flySpeedDelta = (content.hovered && m_lookDragging) ? io.MouseWheel : 0.0f;
input.looking = m_lookDragging;
input.orbiting = false;
input.panning = m_panDragging;
2026-03-28 18:28:11 +08:00
input.fastMove = io.KeyShift;
input.focusSelectionRequested =
input.focused && !io.WantTextInput && ImGui::IsKeyPressed(ImGuiKey_F, false);
if (m_lookDragging && !io.WantTextInput) {
2026-03-28 18:28:11 +08:00
input.moveForward =
(ImGui::IsKeyDown(ImGuiKey_W) ? 1.0f : 0.0f) -
(ImGui::IsKeyDown(ImGuiKey_S) ? 1.0f : 0.0f);
input.moveRight =
(ImGui::IsKeyDown(ImGuiKey_D) ? 1.0f : 0.0f) -
(ImGui::IsKeyDown(ImGuiKey_A) ? 1.0f : 0.0f);
input.moveUp =
(ImGui::IsKeyDown(ImGuiKey_E) ? 1.0f : 0.0f) -
(ImGui::IsKeyDown(ImGuiKey_Q) ? 1.0f : 0.0f);
}
if (m_lookDragging || m_panDragging) {
if (m_lookDragging) {
const ImVec2 lookDragDelta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Right, 0.0f);
input.mouseDelta.x += lookDragDelta.x - m_lastLookDragDelta.x;
input.mouseDelta.y += lookDragDelta.y - m_lastLookDragDelta.y;
m_lastLookDragDelta = lookDragDelta;
} else {
m_lastLookDragDelta = ImVec2(0.0f, 0.0f);
}
if (m_panDragging) {
const ImVec2 panDragDelta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Middle, 0.0f);
input.mouseDelta.x += panDragDelta.x - m_lastPanDragDelta.x;
input.mouseDelta.y += panDragDelta.y - m_lastPanDragDelta.y;
m_lastPanDragDelta = panDragDelta;
} else {
m_lastPanDragDelta = ImVec2(0.0f, 0.0f);
}
}
viewportHostService->UpdateSceneViewInput(*m_context, input);
2026-03-28 17:50:54 +08:00
if (content.hasViewportArea && content.frame.hasTexture) {
2026-03-29 16:18:13 +08:00
overlay = viewportHostService->GetSceneViewOverlayData();
moveGizmoContext = BuildMoveGizmoContext(*m_context, overlay, content, io.MousePos);
m_moveGizmo.Update(moveGizmoContext);
DrawSceneViewportOverlay(
2026-03-28 17:50:54 +08:00
ImGui::GetWindowDrawList(),
overlay,
content.itemMin,
content.itemMax,
2026-03-29 16:18:13 +08:00
content.availableSize,
&m_moveGizmo.GetDrawData());
2026-03-28 17:50:54 +08:00
}
}
2026-03-26 22:31:22 +08:00
Actions::ObserveInactiveActionRoute(*m_context);
}
}
}