Add Unity-style scene rotate gizmo
This commit is contained in:
@@ -37,6 +37,28 @@ SceneViewportMoveGizmoContext BuildMoveGizmoContext(
|
||||
return gizmoContext;
|
||||
}
|
||||
|
||||
SceneViewportRotateGizmoContext BuildRotateGizmoContext(
|
||||
IEditorContext& context,
|
||||
const SceneViewportOverlayData& overlay,
|
||||
const ViewportPanelContentResult& content,
|
||||
const ImVec2& mousePosition) {
|
||||
SceneViewportRotateGizmoContext 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") {}
|
||||
@@ -53,36 +75,78 @@ void SceneViewPanel::Render() {
|
||||
if (IViewportHostService* viewportHostService = m_context->GetViewportHostService()) {
|
||||
const ImGuiIO& io = ImGui::GetIO();
|
||||
const bool hasInteractiveViewport = content.hasViewportArea && content.frame.hasTexture;
|
||||
|
||||
if (content.focused && !io.WantTextInput && !m_lookDragging && !m_panDragging) {
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_W, false)) {
|
||||
if (m_rotateGizmo.IsActive()) {
|
||||
m_rotateGizmo.CancelDrag(&m_context->GetUndoManager());
|
||||
}
|
||||
m_transformTool = SceneViewportTransformTool::Move;
|
||||
} else if (ImGui::IsKeyPressed(ImGuiKey_E, false)) {
|
||||
if (m_moveGizmo.IsActive()) {
|
||||
m_moveGizmo.CancelDrag(&m_context->GetUndoManager());
|
||||
}
|
||||
m_transformTool = SceneViewportTransformTool::Rotate;
|
||||
}
|
||||
}
|
||||
|
||||
const bool usingMoveGizmo = m_transformTool == SceneViewportTransformTool::Move;
|
||||
SceneViewportOverlayData overlay = {};
|
||||
SceneViewportMoveGizmoContext moveGizmoContext = {};
|
||||
SceneViewportRotateGizmoContext rotateGizmoContext = {};
|
||||
|
||||
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())) {
|
||||
if (usingMoveGizmo) {
|
||||
if (m_rotateGizmo.IsActive()) {
|
||||
m_rotateGizmo.CancelDrag(&m_context->GetUndoManager());
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
rotateGizmoContext = BuildRotateGizmoContext(*m_context, overlay, content, io.MousePos);
|
||||
if (m_rotateGizmo.IsActive() &&
|
||||
(rotateGizmoContext.selectedObject == nullptr ||
|
||||
m_context->GetSelectionManager().GetSelectedEntity() != m_rotateGizmo.GetActiveEntityId())) {
|
||||
m_rotateGizmo.CancelDrag(&m_context->GetUndoManager());
|
||||
}
|
||||
m_rotateGizmo.Update(rotateGizmoContext);
|
||||
}
|
||||
} else {
|
||||
if (m_moveGizmo.IsActive()) {
|
||||
m_moveGizmo.CancelDrag(&m_context->GetUndoManager());
|
||||
}
|
||||
m_moveGizmo.Update(moveGizmoContext);
|
||||
} else if (m_moveGizmo.IsActive()) {
|
||||
m_moveGizmo.CancelDrag(&m_context->GetUndoManager());
|
||||
if (m_rotateGizmo.IsActive()) {
|
||||
m_rotateGizmo.CancelDrag(&m_context->GetUndoManager());
|
||||
}
|
||||
}
|
||||
|
||||
const bool beginMoveGizmo =
|
||||
const bool gizmoHovering = usingMoveGizmo ? m_moveGizmo.IsHoveringHandle() : m_rotateGizmo.IsHoveringHandle();
|
||||
const bool gizmoActive = usingMoveGizmo ? m_moveGizmo.IsActive() : m_rotateGizmo.IsActive();
|
||||
|
||||
const bool beginTransformGizmo =
|
||||
hasInteractiveViewport &&
|
||||
content.hovered &&
|
||||
ImGui::IsMouseClicked(ImGuiMouseButton_Left) &&
|
||||
content.clickedLeft &&
|
||||
!m_lookDragging &&
|
||||
!m_panDragging &&
|
||||
m_moveGizmo.IsHoveringHandle();
|
||||
gizmoHovering;
|
||||
const SceneViewportOrientationAxis orientationAxisHit =
|
||||
hasInteractiveViewport &&
|
||||
content.hovered &&
|
||||
!m_lookDragging &&
|
||||
!m_panDragging &&
|
||||
!m_moveGizmo.IsHoveringHandle() &&
|
||||
!m_moveGizmo.IsActive()
|
||||
!gizmoHovering &&
|
||||
!gizmoActive
|
||||
? HitTestSceneViewportOrientationGizmo(
|
||||
overlay,
|
||||
content.itemMin,
|
||||
@@ -91,45 +155,52 @@ void SceneViewPanel::Render() {
|
||||
: SceneViewportOrientationAxis::None;
|
||||
const bool orientationGizmoClick =
|
||||
hasInteractiveViewport &&
|
||||
content.hovered &&
|
||||
ImGui::IsMouseClicked(ImGuiMouseButton_Left) &&
|
||||
content.clickedLeft &&
|
||||
orientationAxisHit != SceneViewportOrientationAxis::None;
|
||||
const bool selectClick =
|
||||
hasInteractiveViewport &&
|
||||
content.hovered &&
|
||||
ImGui::IsMouseClicked(ImGuiMouseButton_Left) &&
|
||||
content.clickedLeft &&
|
||||
!m_lookDragging &&
|
||||
!m_panDragging &&
|
||||
!orientationGizmoClick &&
|
||||
!m_moveGizmo.IsHoveringHandle() &&
|
||||
!m_moveGizmo.IsActive();
|
||||
!gizmoHovering &&
|
||||
!gizmoActive;
|
||||
const bool beginLookDrag =
|
||||
hasInteractiveViewport &&
|
||||
content.hovered &&
|
||||
!m_lookDragging &&
|
||||
!m_moveGizmo.IsActive() &&
|
||||
!gizmoActive &&
|
||||
ImGui::IsMouseClicked(ImGuiMouseButton_Right);
|
||||
const bool beginPanDrag =
|
||||
hasInteractiveViewport &&
|
||||
content.hovered &&
|
||||
!m_panDragging &&
|
||||
!m_moveGizmo.IsActive() &&
|
||||
!gizmoActive &&
|
||||
!m_lookDragging &&
|
||||
ImGui::IsMouseClicked(ImGuiMouseButton_Middle);
|
||||
|
||||
if (beginMoveGizmo || orientationGizmoClick || selectClick || beginLookDrag || beginPanDrag) {
|
||||
if (beginTransformGizmo || orientationGizmoClick || selectClick || beginLookDrag || beginPanDrag) {
|
||||
ImGui::SetWindowFocus();
|
||||
}
|
||||
|
||||
if (beginMoveGizmo) {
|
||||
m_moveGizmo.TryBeginDrag(moveGizmoContext, m_context->GetUndoManager());
|
||||
if (beginTransformGizmo) {
|
||||
if (usingMoveGizmo) {
|
||||
m_moveGizmo.TryBeginDrag(moveGizmoContext, m_context->GetUndoManager());
|
||||
} else {
|
||||
m_rotateGizmo.TryBeginDrag(rotateGizmoContext, m_context->GetUndoManager());
|
||||
}
|
||||
}
|
||||
|
||||
if (orientationGizmoClick) {
|
||||
viewportHostService->AlignSceneViewToOrientationAxis(orientationAxisHit);
|
||||
overlay = viewportHostService->GetSceneViewOverlayData();
|
||||
moveGizmoContext = BuildMoveGizmoContext(*m_context, overlay, content, io.MousePos);
|
||||
m_moveGizmo.Update(moveGizmoContext);
|
||||
if (usingMoveGizmo) {
|
||||
moveGizmoContext = BuildMoveGizmoContext(*m_context, overlay, content, io.MousePos);
|
||||
m_moveGizmo.Update(moveGizmoContext);
|
||||
} else {
|
||||
rotateGizmoContext = BuildRotateGizmoContext(*m_context, overlay, content, io.MousePos);
|
||||
m_rotateGizmo.Update(rotateGizmoContext);
|
||||
}
|
||||
}
|
||||
|
||||
if (selectClick) {
|
||||
@@ -147,11 +218,19 @@ void SceneViewPanel::Render() {
|
||||
}
|
||||
}
|
||||
|
||||
if (m_moveGizmo.IsActive()) {
|
||||
if (gizmoActive) {
|
||||
if (ImGui::IsMouseDown(ImGuiMouseButton_Left)) {
|
||||
m_moveGizmo.UpdateDrag(moveGizmoContext);
|
||||
if (usingMoveGizmo) {
|
||||
m_moveGizmo.UpdateDrag(moveGizmoContext);
|
||||
} else {
|
||||
m_rotateGizmo.UpdateDrag(rotateGizmoContext);
|
||||
}
|
||||
} else {
|
||||
m_moveGizmo.EndDrag(m_context->GetUndoManager());
|
||||
if (usingMoveGizmo) {
|
||||
m_moveGizmo.EndDrag(m_context->GetUndoManager());
|
||||
} else {
|
||||
m_rotateGizmo.EndDrag(m_context->GetUndoManager());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,7 +256,7 @@ void SceneViewPanel::Render() {
|
||||
m_lastPanDragDelta = ImVec2(0.0f, 0.0f);
|
||||
}
|
||||
|
||||
if (m_lookDragging || m_panDragging || m_moveGizmo.IsActive()) {
|
||||
if (m_lookDragging || m_panDragging || m_moveGizmo.IsActive() || m_rotateGizmo.IsActive()) {
|
||||
ImGui::SetNextFrameWantCaptureMouse(true);
|
||||
}
|
||||
if (m_lookDragging) {
|
||||
@@ -222,8 +301,16 @@ void SceneViewPanel::Render() {
|
||||
|
||||
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;
|
||||
ImVec2 framePanDelta(
|
||||
panDragDelta.x - m_lastPanDragDelta.x,
|
||||
panDragDelta.y - m_lastPanDragDelta.y);
|
||||
// Some middle-button drags report a zero drag delta on the interaction surface.
|
||||
if ((framePanDelta.x == 0.0f && framePanDelta.y == 0.0f) &&
|
||||
(io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f)) {
|
||||
framePanDelta = io.MouseDelta;
|
||||
}
|
||||
input.mouseDelta.x += framePanDelta.x;
|
||||
input.mouseDelta.y += framePanDelta.y;
|
||||
m_lastPanDragDelta = panDragDelta;
|
||||
} else {
|
||||
m_lastPanDragDelta = ImVec2(0.0f, 0.0f);
|
||||
@@ -234,15 +321,22 @@ void SceneViewPanel::Render() {
|
||||
|
||||
if (content.hasViewportArea && content.frame.hasTexture) {
|
||||
overlay = viewportHostService->GetSceneViewOverlayData();
|
||||
moveGizmoContext = BuildMoveGizmoContext(*m_context, overlay, content, io.MousePos);
|
||||
m_moveGizmo.Update(moveGizmoContext);
|
||||
if (usingMoveGizmo) {
|
||||
moveGizmoContext = BuildMoveGizmoContext(*m_context, overlay, content, io.MousePos);
|
||||
m_moveGizmo.Update(moveGizmoContext);
|
||||
} else {
|
||||
rotateGizmoContext = BuildRotateGizmoContext(*m_context, overlay, content, io.MousePos);
|
||||
m_rotateGizmo.Update(rotateGizmoContext);
|
||||
}
|
||||
|
||||
DrawSceneViewportOverlay(
|
||||
ImGui::GetWindowDrawList(),
|
||||
overlay,
|
||||
content.itemMin,
|
||||
content.itemMax,
|
||||
content.availableSize,
|
||||
&m_moveGizmo.GetDrawData());
|
||||
usingMoveGizmo ? &m_moveGizmo.GetDrawData() : nullptr,
|
||||
usingMoveGizmo ? nullptr : &m_rotateGizmo.GetDrawData());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user