Formalize scene viewport interaction actions
This commit is contained in:
@@ -83,6 +83,7 @@ add_executable(${PROJECT_NAME} WIN32
|
||||
src/Viewport/SceneViewportRotateGizmo.cpp
|
||||
src/Viewport/SceneViewportScaleGizmo.cpp
|
||||
src/Viewport/SceneViewportHudOverlay.cpp
|
||||
src/Viewport/SceneViewportInteractionActions.cpp
|
||||
src/Viewport/SceneViewportInteractionResolver.cpp
|
||||
src/Viewport/SceneViewportOrientationGizmo.cpp
|
||||
src/Viewport/SceneViewportOverlayBuilder.cpp
|
||||
|
||||
128
editor/src/Viewport/SceneViewportInteractionActions.cpp
Normal file
128
editor/src/Viewport/SceneViewportInteractionActions.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
#include "SceneViewportInteractionActions.h"
|
||||
|
||||
#include "IViewportHostService.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Editor {
|
||||
|
||||
SceneViewportActiveGizmoKind ToSceneViewportActiveGizmoKind(SceneViewportInteractionKind kind) {
|
||||
switch (kind) {
|
||||
case SceneViewportInteractionKind::MoveGizmo:
|
||||
return SceneViewportActiveGizmoKind::Move;
|
||||
case SceneViewportInteractionKind::RotateGizmo:
|
||||
return SceneViewportActiveGizmoKind::Rotate;
|
||||
case SceneViewportInteractionKind::ScaleGizmo:
|
||||
return SceneViewportActiveGizmoKind::Scale;
|
||||
case SceneViewportInteractionKind::OrientationGizmo:
|
||||
case SceneViewportInteractionKind::SceneIcon:
|
||||
case SceneViewportInteractionKind::None:
|
||||
default:
|
||||
return SceneViewportActiveGizmoKind::None;
|
||||
}
|
||||
}
|
||||
|
||||
SceneViewportHoveredHandleState BuildSceneViewportHoveredHandleState(
|
||||
const SceneViewportInteractionResult& interaction) {
|
||||
SceneViewportHoveredHandleState state = {};
|
||||
state.hoveredGizmoKind = ToSceneViewportActiveGizmoKind(interaction.kind);
|
||||
if (interaction.kind == SceneViewportInteractionKind::MoveGizmo) {
|
||||
state.moveAxis = interaction.moveAxis;
|
||||
state.movePlane = interaction.movePlane;
|
||||
} else if (interaction.kind == SceneViewportInteractionKind::RotateGizmo) {
|
||||
state.rotateAxis = interaction.rotateAxis;
|
||||
} else if (interaction.kind == SceneViewportInteractionKind::ScaleGizmo) {
|
||||
state.scaleHandle = interaction.scaleHandle;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
void ApplySceneViewportHoveredHandleState(
|
||||
const SceneViewportHoveredHandleState& hoveredHandleState,
|
||||
bool gizmoActive,
|
||||
bool showingMoveGizmo,
|
||||
SceneViewportMoveGizmo& moveGizmo,
|
||||
bool showingRotateGizmo,
|
||||
SceneViewportRotateGizmo& rotateGizmo,
|
||||
bool showingScaleGizmo,
|
||||
SceneViewportScaleGizmo& scaleGizmo) {
|
||||
if (gizmoActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (showingMoveGizmo) {
|
||||
moveGizmo.SetHoveredHandle(hoveredHandleState.moveAxis, hoveredHandleState.movePlane);
|
||||
}
|
||||
if (showingRotateGizmo) {
|
||||
rotateGizmo.SetHoveredHandle(hoveredHandleState.rotateAxis);
|
||||
}
|
||||
if (showingScaleGizmo) {
|
||||
scaleGizmo.SetHoveredHandle(hoveredHandleState.scaleHandle);
|
||||
}
|
||||
}
|
||||
|
||||
SceneViewportInteractionActions BuildSceneViewportInteractionActions(
|
||||
const SceneViewportInteractionResult& interaction,
|
||||
bool hasInteractiveViewport,
|
||||
bool clickedLeft,
|
||||
bool canResolveViewportInteraction) {
|
||||
SceneViewportInteractionActions actions = {};
|
||||
actions.hoveredGizmoKind = ToSceneViewportActiveGizmoKind(interaction.kind);
|
||||
actions.orientationAxis = interaction.kind == SceneViewportInteractionKind::OrientationGizmo
|
||||
? interaction.orientationAxis
|
||||
: SceneViewportOrientationAxis::None;
|
||||
actions.sceneIconEntityId = interaction.kind == SceneViewportInteractionKind::SceneIcon
|
||||
? interaction.entityId
|
||||
: 0;
|
||||
actions.beginTransformGizmo =
|
||||
hasInteractiveViewport &&
|
||||
clickedLeft &&
|
||||
actions.hoveredGizmoKind != SceneViewportActiveGizmoKind::None;
|
||||
actions.orientationGizmoClick =
|
||||
hasInteractiveViewport &&
|
||||
clickedLeft &&
|
||||
actions.orientationAxis != SceneViewportOrientationAxis::None;
|
||||
actions.sceneIconClick =
|
||||
hasInteractiveViewport &&
|
||||
clickedLeft &&
|
||||
actions.sceneIconEntityId != 0;
|
||||
actions.selectSceneClick =
|
||||
hasInteractiveViewport &&
|
||||
clickedLeft &&
|
||||
canResolveViewportInteraction &&
|
||||
!interaction.HasHit();
|
||||
return actions;
|
||||
}
|
||||
|
||||
void DispatchSceneViewportInteractionActions(
|
||||
const SceneViewportInteractionActions& actions,
|
||||
IEditorContext& context,
|
||||
IViewportHostService& viewportHostService,
|
||||
const ImVec2& viewportSize,
|
||||
const Math::Vector2& localMousePosition) {
|
||||
if (actions.orientationGizmoClick) {
|
||||
viewportHostService.AlignSceneViewToOrientationAxis(actions.orientationAxis);
|
||||
}
|
||||
|
||||
if (actions.sceneIconClick) {
|
||||
context.GetSelectionManager().SetSelectedEntity(actions.sceneIconEntityId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!actions.selectSceneClick) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uint64_t selectedEntity = viewportHostService.PickSceneViewEntity(
|
||||
context,
|
||||
viewportSize,
|
||||
ImVec2(localMousePosition.x, localMousePosition.y));
|
||||
if (selectedEntity != 0) {
|
||||
context.GetSelectionManager().SetSelectedEntity(selectedEntity);
|
||||
} else {
|
||||
context.GetSelectionManager().ClearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Editor
|
||||
} // namespace XCEngine
|
||||
65
editor/src/Viewport/SceneViewportInteractionActions.h
Normal file
65
editor/src/Viewport/SceneViewportInteractionActions.h
Normal file
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
#include "Core/IEditorContext.h"
|
||||
#include "SceneViewportInteractionResolver.h"
|
||||
#include "SceneViewportTransformGizmoFrameBuilder.h"
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Editor {
|
||||
|
||||
struct SceneViewportHoveredHandleState {
|
||||
SceneViewportActiveGizmoKind hoveredGizmoKind = SceneViewportActiveGizmoKind::None;
|
||||
SceneViewportGizmoAxis moveAxis = SceneViewportGizmoAxis::None;
|
||||
SceneViewportGizmoPlane movePlane = SceneViewportGizmoPlane::None;
|
||||
SceneViewportRotateGizmoAxis rotateAxis = SceneViewportRotateGizmoAxis::None;
|
||||
SceneViewportScaleGizmoHandle scaleHandle = SceneViewportScaleGizmoHandle::None;
|
||||
};
|
||||
|
||||
struct SceneViewportInteractionActions {
|
||||
SceneViewportActiveGizmoKind hoveredGizmoKind = SceneViewportActiveGizmoKind::None;
|
||||
SceneViewportOrientationAxis orientationAxis = SceneViewportOrientationAxis::None;
|
||||
uint64_t sceneIconEntityId = 0;
|
||||
bool beginTransformGizmo = false;
|
||||
bool orientationGizmoClick = false;
|
||||
bool sceneIconClick = false;
|
||||
bool selectSceneClick = false;
|
||||
|
||||
bool HasClickAction() const {
|
||||
return beginTransformGizmo || orientationGizmoClick || sceneIconClick || selectSceneClick;
|
||||
}
|
||||
};
|
||||
|
||||
SceneViewportActiveGizmoKind ToSceneViewportActiveGizmoKind(SceneViewportInteractionKind kind);
|
||||
|
||||
SceneViewportHoveredHandleState BuildSceneViewportHoveredHandleState(
|
||||
const SceneViewportInteractionResult& interaction);
|
||||
|
||||
void ApplySceneViewportHoveredHandleState(
|
||||
const SceneViewportHoveredHandleState& hoveredHandleState,
|
||||
bool gizmoActive,
|
||||
bool showingMoveGizmo,
|
||||
SceneViewportMoveGizmo& moveGizmo,
|
||||
bool showingRotateGizmo,
|
||||
SceneViewportRotateGizmo& rotateGizmo,
|
||||
bool showingScaleGizmo,
|
||||
SceneViewportScaleGizmo& scaleGizmo);
|
||||
|
||||
SceneViewportInteractionActions BuildSceneViewportInteractionActions(
|
||||
const SceneViewportInteractionResult& interaction,
|
||||
bool hasInteractiveViewport,
|
||||
bool clickedLeft,
|
||||
bool canResolveViewportInteraction);
|
||||
|
||||
void DispatchSceneViewportInteractionActions(
|
||||
const SceneViewportInteractionActions& actions,
|
||||
IEditorContext& context,
|
||||
IViewportHostService& viewportHostService,
|
||||
const ImVec2& viewportSize,
|
||||
const Math::Vector2& localMousePosition);
|
||||
|
||||
} // namespace Editor
|
||||
} // namespace XCEngine
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "SceneViewPanel.h"
|
||||
#include "Viewport/SceneViewportEditorOverlayData.h"
|
||||
#include "Viewport/SceneViewportHudOverlay.h"
|
||||
#include "Viewport/SceneViewportInteractionActions.h"
|
||||
#include "Viewport/SceneViewportInteractionResolver.h"
|
||||
#include "Viewport/SceneViewportOverlayHandleBuilder.h"
|
||||
#include "Viewport/SceneViewportMath.h"
|
||||
@@ -38,22 +39,6 @@ const char* GetSceneViewportTransformSpaceModeLabel(SceneViewportTransformSpaceM
|
||||
return mode == SceneViewportTransformSpaceMode::Global ? "Global" : "Local";
|
||||
}
|
||||
|
||||
SceneViewportActiveGizmoKind ToActiveGizmoKind(SceneViewportInteractionKind kind) {
|
||||
switch (kind) {
|
||||
case SceneViewportInteractionKind::MoveGizmo:
|
||||
return SceneViewportActiveGizmoKind::Move;
|
||||
case SceneViewportInteractionKind::RotateGizmo:
|
||||
return SceneViewportActiveGizmoKind::Rotate;
|
||||
case SceneViewportInteractionKind::ScaleGizmo:
|
||||
return SceneViewportActiveGizmoKind::Scale;
|
||||
case SceneViewportInteractionKind::OrientationGizmo:
|
||||
case SceneViewportInteractionKind::SceneIcon:
|
||||
case SceneViewportInteractionKind::None:
|
||||
default:
|
||||
return SceneViewportActiveGizmoKind::None;
|
||||
}
|
||||
}
|
||||
|
||||
float GetSceneToolbarToggleWidth(const char* firstLabel, const char* secondLabel) {
|
||||
constexpr float kHorizontalPadding = 10.0f;
|
||||
constexpr float kMinWidth = 68.0f;
|
||||
@@ -440,58 +425,22 @@ void SceneViewPanel::Render() {
|
||||
hoveredInteraction = ResolveSceneViewportInteraction(interactionRequest);
|
||||
}
|
||||
|
||||
if (!gizmoActive) {
|
||||
if (showingMoveGizmo) {
|
||||
m_moveGizmo.SetHoveredHandle(
|
||||
hoveredInteraction.kind == SceneViewportInteractionKind::MoveGizmo
|
||||
? hoveredInteraction.moveAxis
|
||||
: SceneViewportGizmoAxis::None,
|
||||
hoveredInteraction.kind == SceneViewportInteractionKind::MoveGizmo
|
||||
? hoveredInteraction.movePlane
|
||||
: SceneViewportGizmoPlane::None);
|
||||
}
|
||||
if (showingRotateGizmo) {
|
||||
m_rotateGizmo.SetHoveredHandle(
|
||||
hoveredInteraction.kind == SceneViewportInteractionKind::RotateGizmo
|
||||
? hoveredInteraction.rotateAxis
|
||||
: SceneViewportRotateGizmoAxis::None);
|
||||
}
|
||||
if (showingScaleGizmo) {
|
||||
m_scaleGizmo.SetHoveredHandle(
|
||||
hoveredInteraction.kind == SceneViewportInteractionKind::ScaleGizmo
|
||||
? hoveredInteraction.scaleHandle
|
||||
: SceneViewportScaleGizmoHandle::None);
|
||||
}
|
||||
}
|
||||
ApplySceneViewportHoveredHandleState(
|
||||
BuildSceneViewportHoveredHandleState(hoveredInteraction),
|
||||
gizmoActive,
|
||||
showingMoveGizmo,
|
||||
m_moveGizmo,
|
||||
showingRotateGizmo,
|
||||
m_rotateGizmo,
|
||||
showingScaleGizmo,
|
||||
m_scaleGizmo);
|
||||
|
||||
const SceneViewportActiveGizmoKind hoveredGizmoKind =
|
||||
ToActiveGizmoKind(hoveredInteraction.kind);
|
||||
const bool gizmoHovering = hoveredGizmoKind != SceneViewportActiveGizmoKind::None;
|
||||
const SceneViewportOrientationAxis orientationAxisHit =
|
||||
hoveredInteraction.kind == SceneViewportInteractionKind::OrientationGizmo
|
||||
? hoveredInteraction.orientationAxis
|
||||
: SceneViewportOrientationAxis::None;
|
||||
const uint64_t clickedSceneIconEntity =
|
||||
hoveredInteraction.kind == SceneViewportInteractionKind::SceneIcon
|
||||
? hoveredInteraction.entityId
|
||||
: 0;
|
||||
const bool beginTransformGizmo =
|
||||
hasInteractiveViewport &&
|
||||
content.clickedLeft &&
|
||||
gizmoHovering;
|
||||
const bool orientationGizmoClick =
|
||||
hasInteractiveViewport &&
|
||||
content.clickedLeft &&
|
||||
orientationAxisHit != SceneViewportOrientationAxis::None;
|
||||
const bool sceneIconClick =
|
||||
hasInteractiveViewport &&
|
||||
content.clickedLeft &&
|
||||
clickedSceneIconEntity != 0;
|
||||
const bool selectClick =
|
||||
hasInteractiveViewport &&
|
||||
content.clickedLeft &&
|
||||
canResolveViewportInteraction &&
|
||||
!hoveredInteraction.HasHit();
|
||||
const SceneViewportInteractionActions interactionActions =
|
||||
BuildSceneViewportInteractionActions(
|
||||
hoveredInteraction,
|
||||
hasInteractiveViewport,
|
||||
content.clickedLeft,
|
||||
canResolveViewportInteraction);
|
||||
const bool beginLeftPanDrag = usingViewMoveTool
|
||||
? ShouldBeginSceneViewportNavigationDrag(
|
||||
hasInteractiveViewport,
|
||||
@@ -517,38 +466,27 @@ void SceneViewPanel::Render() {
|
||||
ImGuiMouseButton_Middle);
|
||||
const bool beginPanDrag = beginLeftPanDrag || beginMiddlePanDrag;
|
||||
|
||||
if (toolOverlay.clicked || beginTransformGizmo || orientationGizmoClick || sceneIconClick || selectClick || beginLookDrag ||
|
||||
if (toolOverlay.clicked || interactionActions.HasClickAction() || beginLookDrag ||
|
||||
beginPanDrag) {
|
||||
ImGui::SetWindowFocus();
|
||||
}
|
||||
|
||||
if (beginTransformGizmo) {
|
||||
if (hoveredGizmoKind == SceneViewportActiveGizmoKind::Scale) {
|
||||
if (interactionActions.beginTransformGizmo) {
|
||||
if (interactionActions.hoveredGizmoKind == SceneViewportActiveGizmoKind::Scale) {
|
||||
m_scaleGizmo.TryBeginDrag(gizmoFrameState.scaleContext, m_context->GetUndoManager());
|
||||
} else if (hoveredGizmoKind == SceneViewportActiveGizmoKind::Move) {
|
||||
} else if (interactionActions.hoveredGizmoKind == SceneViewportActiveGizmoKind::Move) {
|
||||
m_moveGizmo.TryBeginDrag(gizmoFrameState.moveContext, m_context->GetUndoManager());
|
||||
} else if (hoveredGizmoKind == SceneViewportActiveGizmoKind::Rotate) {
|
||||
} else if (interactionActions.hoveredGizmoKind == SceneViewportActiveGizmoKind::Rotate) {
|
||||
m_rotateGizmo.TryBeginDrag(gizmoFrameState.rotateContext, m_context->GetUndoManager());
|
||||
}
|
||||
}
|
||||
|
||||
if (orientationGizmoClick) {
|
||||
viewportHostService->AlignSceneViewToOrientationAxis(orientationAxisHit);
|
||||
}
|
||||
|
||||
if (sceneIconClick) {
|
||||
m_context->GetSelectionManager().SetSelectedEntity(clickedSceneIconEntity);
|
||||
} else if (selectClick) {
|
||||
const uint64_t selectedEntity = viewportHostService->PickSceneViewEntity(
|
||||
*m_context,
|
||||
content.availableSize,
|
||||
ImVec2(localMousePosition.x, localMousePosition.y));
|
||||
if (selectedEntity != 0) {
|
||||
m_context->GetSelectionManager().SetSelectedEntity(selectedEntity);
|
||||
} else {
|
||||
m_context->GetSelectionManager().ClearSelection();
|
||||
}
|
||||
}
|
||||
DispatchSceneViewportInteractionActions(
|
||||
interactionActions,
|
||||
*m_context,
|
||||
*viewportHostService,
|
||||
content.availableSize,
|
||||
localMousePosition);
|
||||
|
||||
if (gizmoActive) {
|
||||
if (ImGui::IsMouseDown(ImGuiMouseButton_Left)) {
|
||||
|
||||
Reference in New Issue
Block a user