2026-03-26 22:31:22 +08:00
|
|
|
#include "Actions/ActionRouting.h"
|
2026-03-28 17:40:14 +08:00
|
|
|
#include "Core/IEditorContext.h"
|
2026-03-29 16:18:13 +08:00
|
|
|
#include "Core/ISceneManager.h"
|
2026-03-29 15:12:38 +08:00
|
|
|
#include "Core/ISelectionManager.h"
|
2026-03-20 17:08:06 +08:00
|
|
|
#include "SceneViewPanel.h"
|
2026-03-29 15:12:38 +08:00
|
|
|
#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
|
|
|
|
2026-03-20 17:08:06 +08:00
|
|
|
#include <imgui.h>
|
|
|
|
|
|
2026-03-24 20:02:38 +08:00
|
|
|
namespace XCEngine {
|
|
|
|
|
namespace Editor {
|
2026-03-20 17:08:06 +08:00
|
|
|
|
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
|
|
|
|
|
|
2026-03-20 17:08:06 +08:00
|
|
|
SceneViewPanel::SceneViewPanel() : Panel("Scene") {}
|
|
|
|
|
|
|
|
|
|
void SceneViewPanel::Render() {
|
2026-03-29 16:18:13 +08:00
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
|
2026-03-26 16:43:06 +08:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-28 17:40:14 +08:00
|
|
|
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();
|
2026-03-29 15:12:38 +08:00
|
|
|
const bool selectClick =
|
2026-03-29 16:18:13 +08:00
|
|
|
hasInteractiveViewport &&
|
2026-03-29 15:12:38 +08:00
|
|
|
content.hovered &&
|
|
|
|
|
ImGui::IsMouseClicked(ImGuiMouseButton_Left) &&
|
|
|
|
|
!m_lookDragging &&
|
2026-03-29 16:18:13 +08:00
|
|
|
!m_panDragging &&
|
|
|
|
|
!m_moveGizmo.IsHoveringHandle() &&
|
|
|
|
|
!m_moveGizmo.IsActive();
|
2026-03-29 15:12:38 +08:00
|
|
|
const bool beginLookDrag =
|
2026-03-29 16:18:13 +08:00
|
|
|
content.hovered &&
|
|
|
|
|
!m_moveGizmo.IsActive() &&
|
|
|
|
|
ImGui::IsMouseClicked(ImGuiMouseButton_Right);
|
2026-03-29 15:12:38 +08:00
|
|
|
const bool beginPanDrag =
|
2026-03-29 16:18:13 +08:00
|
|
|
content.hovered &&
|
|
|
|
|
!m_moveGizmo.IsActive() &&
|
|
|
|
|
ImGui::IsMouseClicked(ImGuiMouseButton_Middle);
|
2026-03-29 15:12:38 +08:00
|
|
|
|
2026-03-29 16:18:13 +08:00
|
|
|
if (beginMoveGizmo || selectClick || beginLookDrag || beginPanDrag) {
|
2026-03-29 15:12:38 +08:00
|
|
|
ImGui::SetWindowFocus();
|
|
|
|
|
}
|
2026-03-28 18:21:18 +08:00
|
|
|
|
2026-03-29 16:18:13 +08:00
|
|
|
if (beginMoveGizmo) {
|
|
|
|
|
m_moveGizmo.TryBeginDrag(moveGizmoContext, m_context->GetUndoManager());
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-29 15:12:38 +08:00
|
|
|
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());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-29 15:12:38 +08:00
|
|
|
if (beginLookDrag) {
|
2026-03-28 18:21:18 +08:00
|
|
|
m_lookDragging = true;
|
2026-03-29 15:12:38 +08:00
|
|
|
m_lastLookDragDelta = ImVec2(0.0f, 0.0f);
|
2026-03-28 18:21:18 +08:00
|
|
|
}
|
2026-03-29 15:12:38 +08:00
|
|
|
if (beginPanDrag) {
|
2026-03-28 17:40:14 +08:00
|
|
|
m_panDragging = true;
|
2026-03-29 15:12:38 +08:00
|
|
|
m_lastPanDragDelta = ImVec2(0.0f, 0.0f);
|
2026-03-28 17:40:14 +08:00
|
|
|
}
|
|
|
|
|
|
2026-03-28 18:37:18 +08:00
|
|
|
if (m_lookDragging && !ImGui::IsMouseDown(ImGuiMouseButton_Right)) {
|
2026-03-28 18:21:18 +08:00
|
|
|
m_lookDragging = false;
|
2026-03-29 15:12:38 +08:00
|
|
|
m_lastLookDragDelta = ImVec2(0.0f, 0.0f);
|
2026-03-28 18:21:18 +08:00
|
|
|
}
|
2026-03-28 17:40:14 +08:00
|
|
|
if (m_panDragging && !ImGui::IsMouseDown(ImGuiMouseButton_Middle)) {
|
|
|
|
|
m_panDragging = false;
|
2026-03-29 15:12:38 +08:00
|
|
|
m_lastPanDragDelta = ImVec2(0.0f, 0.0f);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-29 16:18:13 +08:00
|
|
|
if (m_lookDragging || m_panDragging || m_moveGizmo.IsActive()) {
|
2026-03-29 15:12:38 +08:00
|
|
|
ImGui::SetNextFrameWantCaptureMouse(true);
|
|
|
|
|
}
|
|
|
|
|
if (m_lookDragging) {
|
|
|
|
|
ImGui::SetNextFrameWantCaptureKeyboard(true);
|
2026-03-28 17:40:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SceneViewportInput input = {};
|
|
|
|
|
input.viewportSize = content.availableSize;
|
2026-03-28 18:28:11 +08:00
|
|
|
input.deltaTime = io.DeltaTime;
|
2026-03-28 17:40:14 +08:00
|
|
|
input.hovered = content.hovered;
|
2026-03-29 15:12:38 +08:00
|
|
|
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;
|
2026-03-28 18:21:18 +08:00
|
|
|
input.looking = m_lookDragging;
|
2026-03-28 18:37:18 +08:00
|
|
|
input.orbiting = false;
|
2026-03-28 17:40:14 +08:00
|
|
|
input.panning = m_panDragging;
|
2026-03-28 18:28:11 +08:00
|
|
|
input.fastMove = io.KeyShift;
|
2026-03-28 17:40:14 +08:00
|
|
|
input.focusSelectionRequested =
|
2026-03-29 15:12:38 +08:00
|
|
|
input.focused && !io.WantTextInput && ImGui::IsKeyPressed(ImGuiKey_F, false);
|
2026-03-28 17:40:14 +08:00
|
|
|
|
2026-03-29 15:12:38 +08:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-28 18:37:18 +08:00
|
|
|
if (m_lookDragging || m_panDragging) {
|
2026-03-29 15:12:38 +08:00
|
|
|
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);
|
|
|
|
|
}
|
2026-03-28 17:40:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
2026-03-29 15:12:38 +08:00
|
|
|
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-28 17:40:14 +08:00
|
|
|
}
|
|
|
|
|
|
2026-03-26 22:31:22 +08:00
|
|
|
Actions::ObserveInactiveActionRoute(*m_context);
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
2026-03-24 20:02:38 +08:00
|
|
|
}
|