Add scene transform toolbar and scale gizmo
This commit is contained in:
@@ -6,15 +6,205 @@
|
||||
#include "Viewport/SceneViewportOrientationGizmo.h"
|
||||
#include "Viewport/SceneViewportOverlayRenderer.h"
|
||||
#include "ViewportPanelContent.h"
|
||||
#include "Platform/Win32Utf8.h"
|
||||
#include "UI/UI.h"
|
||||
|
||||
#include <XCEngine/Debug/Logger.h>
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <filesystem>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Editor {
|
||||
|
||||
namespace {
|
||||
|
||||
struct SceneViewportToolOverlayResult {
|
||||
bool hovered = false;
|
||||
bool clicked = false;
|
||||
SceneViewportToolMode clickedTool = SceneViewportToolMode::Move;
|
||||
};
|
||||
|
||||
enum class SceneViewportActiveGizmoKind : uint8_t {
|
||||
None = 0,
|
||||
Move,
|
||||
Rotate,
|
||||
Scale
|
||||
};
|
||||
|
||||
const char* GetSceneViewportToolTooltip(SceneViewportToolMode toolMode) {
|
||||
switch (toolMode) {
|
||||
case SceneViewportToolMode::ViewMove:
|
||||
return "View Move";
|
||||
case SceneViewportToolMode::Move:
|
||||
return "Move";
|
||||
case SceneViewportToolMode::Rotate:
|
||||
return "Rotate";
|
||||
case SceneViewportToolMode::Scale:
|
||||
return "Scale";
|
||||
case SceneViewportToolMode::Transform:
|
||||
return "Transform";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
const char* GetSceneViewportToolIconBaseName(SceneViewportToolMode toolMode) {
|
||||
switch (toolMode) {
|
||||
case SceneViewportToolMode::ViewMove:
|
||||
return "view_move_tool";
|
||||
case SceneViewportToolMode::Move:
|
||||
return "move_tool";
|
||||
case SceneViewportToolMode::Rotate:
|
||||
return "rotate_tool";
|
||||
case SceneViewportToolMode::Scale:
|
||||
return "scale_tool";
|
||||
case SceneViewportToolMode::Transform:
|
||||
return "transform_tool";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& GetSceneViewportToolIconPath(SceneViewportToolMode toolMode, bool active) {
|
||||
static std::string cachedPaths[5][2] = {};
|
||||
const size_t toolIndex = static_cast<size_t>(toolMode);
|
||||
const size_t stateIndex = active ? 1u : 0u;
|
||||
std::string& cachedPath = cachedPaths[toolIndex][stateIndex];
|
||||
if (!cachedPath.empty()) {
|
||||
return cachedPath;
|
||||
}
|
||||
|
||||
const std::filesystem::path exeDir(
|
||||
XCEngine::Editor::Platform::Utf8ToWide(XCEngine::Editor::Platform::GetExecutableDirectoryUtf8()));
|
||||
std::filesystem::path iconPath =
|
||||
(exeDir / L".." / L".." / L"resources" / L"Icons" /
|
||||
std::filesystem::path(XCEngine::Editor::Platform::Utf8ToWide(GetSceneViewportToolIconBaseName(toolMode))));
|
||||
if (active) {
|
||||
iconPath += L"_on";
|
||||
}
|
||||
iconPath += L".png";
|
||||
cachedPath = XCEngine::Editor::Platform::WideToUtf8(iconPath.lexically_normal().wstring());
|
||||
return cachedPath;
|
||||
}
|
||||
|
||||
SceneViewportToolOverlayResult RenderSceneViewportToolOverlay(
|
||||
const ViewportPanelContentResult& content,
|
||||
SceneViewportToolMode activeTool) {
|
||||
SceneViewportToolOverlayResult result = {};
|
||||
if (!content.hasViewportArea) {
|
||||
return result;
|
||||
}
|
||||
|
||||
constexpr float kButtonExtent = 30.0f;
|
||||
constexpr float kButtonSpacing = 6.0f;
|
||||
constexpr float kPanelPadding = 6.0f;
|
||||
constexpr float kViewportInset = 10.0f;
|
||||
constexpr float kIconInset = 4.0f;
|
||||
constexpr size_t kToolCount = 5;
|
||||
|
||||
ImDrawList* drawList = ImGui::GetWindowDrawList();
|
||||
if (drawList == nullptr) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const ImVec2 panelMin(
|
||||
content.itemMin.x + kViewportInset,
|
||||
content.itemMin.y + kViewportInset);
|
||||
const ImVec2 panelMax(
|
||||
panelMin.x + kPanelPadding * 2.0f + kButtonExtent,
|
||||
panelMin.y + kPanelPadding * 2.0f + kToolCount * kButtonExtent + (kToolCount - 1) * kButtonSpacing);
|
||||
drawList->AddRectFilled(panelMin, panelMax, IM_COL32(24, 26, 29, 220), 7.0f);
|
||||
drawList->AddRect(panelMin, panelMax, IM_COL32(255, 255, 255, 28), 7.0f, 0, 1.0f);
|
||||
|
||||
const SceneViewportToolMode toolModes[kToolCount] = {
|
||||
SceneViewportToolMode::ViewMove,
|
||||
SceneViewportToolMode::Move,
|
||||
SceneViewportToolMode::Rotate,
|
||||
SceneViewportToolMode::Scale,
|
||||
SceneViewportToolMode::Transform
|
||||
};
|
||||
|
||||
for (size_t index = 0; index < kToolCount; ++index) {
|
||||
const SceneViewportToolMode toolMode = toolModes[index];
|
||||
const bool active = toolMode == activeTool;
|
||||
const ImVec2 buttonMin(
|
||||
panelMin.x + kPanelPadding,
|
||||
panelMin.y + kPanelPadding + index * (kButtonExtent + kButtonSpacing));
|
||||
const ImVec2 buttonMax(buttonMin.x + kButtonExtent, buttonMin.y + kButtonExtent);
|
||||
|
||||
ImGui::SetCursorScreenPos(buttonMin);
|
||||
const std::string buttonId = std::string("##SceneToolButton") + std::to_string(static_cast<int>(toolMode));
|
||||
const bool clicked = ImGui::InvisibleButton(
|
||||
buttonId.c_str(),
|
||||
ImVec2(kButtonExtent, kButtonExtent),
|
||||
ImGuiButtonFlags_MouseButtonLeft |
|
||||
ImGuiButtonFlags_PressedOnClick |
|
||||
ImGuiButtonFlags_AllowOverlap);
|
||||
|
||||
const bool hovered = ImGui::IsItemHovered();
|
||||
const bool held = ImGui::IsItemActive();
|
||||
result.hovered = result.hovered || hovered;
|
||||
result.clicked = result.clicked || clicked;
|
||||
if (clicked) {
|
||||
result.clickedTool = toolMode;
|
||||
}
|
||||
|
||||
const ImU32 backgroundColor = ImGui::GetColorU32(
|
||||
held ? UI::ToolbarButtonActiveColor()
|
||||
: hovered ? UI::ToolbarButtonHoveredColor(active)
|
||||
: UI::ToolbarButtonColor(active));
|
||||
drawList->AddRectFilled(buttonMin, buttonMax, backgroundColor, 5.0f);
|
||||
drawList->AddRect(buttonMin, buttonMax, IM_COL32(255, 255, 255, active ? 48 : 24), 5.0f, 0, 1.0f);
|
||||
|
||||
const ImVec2 iconMin(buttonMin.x + kIconInset, buttonMin.y + kIconInset);
|
||||
const ImVec2 iconMax(buttonMax.x - kIconInset, buttonMax.y - kIconInset);
|
||||
if (!UI::DrawTextureAssetPreview(
|
||||
drawList,
|
||||
iconMin,
|
||||
iconMax,
|
||||
GetSceneViewportToolIconPath(toolMode, active))) {
|
||||
drawList->AddText(
|
||||
ImVec2(buttonMin.x + 8.0f, buttonMin.y + 7.0f),
|
||||
IM_COL32(230, 230, 230, 255),
|
||||
GetSceneViewportToolTooltip(toolMode));
|
||||
}
|
||||
|
||||
if (hovered) {
|
||||
ImGui::SetTooltip("%s", GetSceneViewportToolTooltip(toolMode));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void LogSceneViewNavigation(Debug::Logger& logger, const char* format, ...) {
|
||||
char buffer[512] = {};
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
std::vsnprintf(buffer, sizeof(buffer), format, args);
|
||||
va_end(args);
|
||||
logger.Info(Debug::LogCategory::General, buffer);
|
||||
}
|
||||
|
||||
bool ShouldBeginSceneViewportNavigationDrag(
|
||||
bool hasInteractiveViewport,
|
||||
bool hovered,
|
||||
bool activeDrag,
|
||||
bool otherDrag,
|
||||
bool gizmoActive,
|
||||
ImGuiMouseButton button) {
|
||||
return hasInteractiveViewport &&
|
||||
hovered &&
|
||||
!activeDrag &&
|
||||
!otherDrag &&
|
||||
!gizmoActive &&
|
||||
ImGui::IsMouseClicked(button);
|
||||
}
|
||||
|
||||
SceneViewportMoveGizmoContext BuildMoveGizmoContext(
|
||||
IEditorContext& context,
|
||||
const SceneViewportOverlayData& overlay,
|
||||
@@ -59,6 +249,28 @@ SceneViewportRotateGizmoContext BuildRotateGizmoContext(
|
||||
return gizmoContext;
|
||||
}
|
||||
|
||||
SceneViewportScaleGizmoContext BuildScaleGizmoContext(
|
||||
IEditorContext& context,
|
||||
const SceneViewportOverlayData& overlay,
|
||||
const ViewportPanelContentResult& content,
|
||||
const ImVec2& mousePosition) {
|
||||
SceneViewportScaleGizmoContext 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") {}
|
||||
@@ -74,53 +286,130 @@ void SceneViewPanel::Render() {
|
||||
const ViewportPanelContentResult content = RenderViewportPanelContent(*m_context, EditorViewportKind::Scene);
|
||||
if (IViewportHostService* viewportHostService = m_context->GetViewportHostService()) {
|
||||
const ImGuiIO& io = ImGui::GetIO();
|
||||
auto& logger = Debug::Logger::Get();
|
||||
const bool hasInteractiveViewport = content.hasViewportArea && content.frame.hasTexture;
|
||||
const SceneViewportToolOverlayResult toolOverlay = RenderSceneViewportToolOverlay(content, m_toolMode);
|
||||
const bool viewportContentHovered = content.hovered && !toolOverlay.hovered;
|
||||
|
||||
if (toolOverlay.clicked) {
|
||||
if (m_moveGizmo.IsActive()) {
|
||||
m_moveGizmo.CancelDrag(&m_context->GetUndoManager());
|
||||
}
|
||||
if (m_rotateGizmo.IsActive()) {
|
||||
m_rotateGizmo.CancelDrag(&m_context->GetUndoManager());
|
||||
}
|
||||
if (m_scaleGizmo.IsActive()) {
|
||||
m_scaleGizmo.CancelDrag(&m_context->GetUndoManager());
|
||||
}
|
||||
m_toolMode = toolOverlay.clickedTool;
|
||||
}
|
||||
|
||||
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;
|
||||
if (m_scaleGizmo.IsActive()) {
|
||||
m_scaleGizmo.CancelDrag(&m_context->GetUndoManager());
|
||||
}
|
||||
m_toolMode = SceneViewportToolMode::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();
|
||||
if (usingMoveGizmo) {
|
||||
if (m_scaleGizmo.IsActive()) {
|
||||
m_scaleGizmo.CancelDrag(&m_context->GetUndoManager());
|
||||
}
|
||||
m_toolMode = SceneViewportToolMode::Rotate;
|
||||
} else if (ImGui::IsKeyPressed(ImGuiKey_R, false)) {
|
||||
if (m_moveGizmo.IsActive()) {
|
||||
m_moveGizmo.CancelDrag(&m_context->GetUndoManager());
|
||||
}
|
||||
if (m_rotateGizmo.IsActive()) {
|
||||
m_rotateGizmo.CancelDrag(&m_context->GetUndoManager());
|
||||
}
|
||||
m_toolMode = SceneViewportToolMode::Scale;
|
||||
}
|
||||
}
|
||||
|
||||
const bool usingViewMoveTool = m_toolMode == SceneViewportToolMode::ViewMove;
|
||||
const bool usingTransformTool = m_toolMode == SceneViewportToolMode::Transform;
|
||||
const bool showingMoveGizmo = m_toolMode == SceneViewportToolMode::Move || usingTransformTool;
|
||||
const bool showingRotateGizmo = m_toolMode == SceneViewportToolMode::Rotate || usingTransformTool;
|
||||
const bool showingScaleGizmo = m_toolMode == SceneViewportToolMode::Scale || usingTransformTool;
|
||||
SceneViewportOverlayData overlay = {};
|
||||
SceneViewportMoveGizmoContext moveGizmoContext = {};
|
||||
SceneViewportRotateGizmoContext rotateGizmoContext = {};
|
||||
SceneViewportScaleGizmoContext scaleGizmoContext = {};
|
||||
SceneViewportActiveGizmoKind activeGizmoKind = SceneViewportActiveGizmoKind::None;
|
||||
|
||||
if (hasInteractiveViewport) {
|
||||
overlay = viewportHostService->GetSceneViewOverlayData();
|
||||
if (showingMoveGizmo) {
|
||||
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());
|
||||
}
|
||||
} else if (m_moveGizmo.IsActive()) {
|
||||
m_moveGizmo.CancelDrag(&m_context->GetUndoManager());
|
||||
}
|
||||
|
||||
if (showingRotateGizmo) {
|
||||
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_rotateGizmo.IsActive()) {
|
||||
m_rotateGizmo.CancelDrag(&m_context->GetUndoManager());
|
||||
}
|
||||
|
||||
if (showingScaleGizmo) {
|
||||
scaleGizmoContext = BuildScaleGizmoContext(*m_context, overlay, content, io.MousePos);
|
||||
scaleGizmoContext.uniformOnly = usingTransformTool;
|
||||
if (m_scaleGizmo.IsActive() &&
|
||||
(scaleGizmoContext.selectedObject == nullptr ||
|
||||
m_context->GetSelectionManager().GetSelectedEntity() != m_scaleGizmo.GetActiveEntityId())) {
|
||||
m_scaleGizmo.CancelDrag(&m_context->GetUndoManager());
|
||||
}
|
||||
} else if (m_scaleGizmo.IsActive()) {
|
||||
m_scaleGizmo.CancelDrag(&m_context->GetUndoManager());
|
||||
}
|
||||
|
||||
if (m_moveGizmo.IsActive()) {
|
||||
activeGizmoKind = SceneViewportActiveGizmoKind::Move;
|
||||
} else if (m_rotateGizmo.IsActive()) {
|
||||
activeGizmoKind = SceneViewportActiveGizmoKind::Rotate;
|
||||
} else if (m_scaleGizmo.IsActive()) {
|
||||
activeGizmoKind = SceneViewportActiveGizmoKind::Scale;
|
||||
}
|
||||
|
||||
if (showingMoveGizmo) {
|
||||
SceneViewportMoveGizmoContext updateContext = moveGizmoContext;
|
||||
if (activeGizmoKind != SceneViewportActiveGizmoKind::None &&
|
||||
activeGizmoKind != SceneViewportActiveGizmoKind::Move) {
|
||||
updateContext.mousePosition = Math::Vector2(-1.0f, -1.0f);
|
||||
}
|
||||
m_moveGizmo.Update(updateContext);
|
||||
}
|
||||
if (showingRotateGizmo) {
|
||||
SceneViewportRotateGizmoContext updateContext = rotateGizmoContext;
|
||||
if (activeGizmoKind != SceneViewportActiveGizmoKind::None &&
|
||||
activeGizmoKind != SceneViewportActiveGizmoKind::Rotate) {
|
||||
updateContext.mousePosition = Math::Vector2(-1.0f, -1.0f);
|
||||
}
|
||||
m_rotateGizmo.Update(updateContext);
|
||||
}
|
||||
if (showingScaleGizmo) {
|
||||
SceneViewportScaleGizmoContext updateContext = scaleGizmoContext;
|
||||
if (activeGizmoKind != SceneViewportActiveGizmoKind::None &&
|
||||
activeGizmoKind != SceneViewportActiveGizmoKind::Scale) {
|
||||
updateContext.mousePosition = Math::Vector2(-1.0f, -1.0f);
|
||||
}
|
||||
m_scaleGizmo.Update(updateContext);
|
||||
}
|
||||
} else {
|
||||
if (m_moveGizmo.IsActive()) {
|
||||
@@ -129,20 +418,45 @@ void SceneViewPanel::Render() {
|
||||
if (m_rotateGizmo.IsActive()) {
|
||||
m_rotateGizmo.CancelDrag(&m_context->GetUndoManager());
|
||||
}
|
||||
if (m_scaleGizmo.IsActive()) {
|
||||
m_scaleGizmo.CancelDrag(&m_context->GetUndoManager());
|
||||
}
|
||||
}
|
||||
|
||||
const bool gizmoHovering = usingMoveGizmo ? m_moveGizmo.IsHoveringHandle() : m_rotateGizmo.IsHoveringHandle();
|
||||
const bool gizmoActive = usingMoveGizmo ? m_moveGizmo.IsActive() : m_rotateGizmo.IsActive();
|
||||
const bool moveGizmoHovering = showingMoveGizmo && m_moveGizmo.IsHoveringHandle();
|
||||
const bool rotateGizmoHovering = showingRotateGizmo && m_rotateGizmo.IsHoveringHandle();
|
||||
const bool scaleGizmoHovering = showingScaleGizmo && m_scaleGizmo.IsHoveringHandle();
|
||||
const bool moveGizmoActive = showingMoveGizmo && m_moveGizmo.IsActive();
|
||||
const bool rotateGizmoActive = showingRotateGizmo && m_rotateGizmo.IsActive();
|
||||
const bool scaleGizmoActive = showingScaleGizmo && m_scaleGizmo.IsActive();
|
||||
const SceneViewportActiveGizmoKind hoveredGizmoKind = scaleGizmoHovering
|
||||
? SceneViewportActiveGizmoKind::Scale
|
||||
: (moveGizmoHovering ? SceneViewportActiveGizmoKind::Move
|
||||
: (rotateGizmoHovering ? SceneViewportActiveGizmoKind::Rotate
|
||||
: SceneViewportActiveGizmoKind::None));
|
||||
if (moveGizmoActive) {
|
||||
activeGizmoKind = SceneViewportActiveGizmoKind::Move;
|
||||
} else if (rotateGizmoActive) {
|
||||
activeGizmoKind = SceneViewportActiveGizmoKind::Rotate;
|
||||
} else if (scaleGizmoActive) {
|
||||
activeGizmoKind = SceneViewportActiveGizmoKind::Scale;
|
||||
} else {
|
||||
activeGizmoKind = SceneViewportActiveGizmoKind::None;
|
||||
}
|
||||
const bool gizmoHovering = hoveredGizmoKind != SceneViewportActiveGizmoKind::None;
|
||||
const bool gizmoActive = activeGizmoKind != SceneViewportActiveGizmoKind::None;
|
||||
|
||||
const bool beginTransformGizmo =
|
||||
hasInteractiveViewport &&
|
||||
content.clickedLeft &&
|
||||
!m_lookDragging &&
|
||||
!m_panDragging &&
|
||||
!toolOverlay.hovered &&
|
||||
gizmoHovering;
|
||||
const SceneViewportOrientationAxis orientationAxisHit =
|
||||
hasInteractiveViewport &&
|
||||
content.hovered &&
|
||||
viewportContentHovered &&
|
||||
!usingViewMoveTool &&
|
||||
!m_lookDragging &&
|
||||
!m_panDragging &&
|
||||
!gizmoHovering &&
|
||||
@@ -160,33 +474,68 @@ void SceneViewPanel::Render() {
|
||||
const bool selectClick =
|
||||
hasInteractiveViewport &&
|
||||
content.clickedLeft &&
|
||||
viewportContentHovered &&
|
||||
!usingViewMoveTool &&
|
||||
!m_lookDragging &&
|
||||
!m_panDragging &&
|
||||
!orientationGizmoClick &&
|
||||
!gizmoHovering &&
|
||||
!gizmoActive;
|
||||
const bool beginLookDrag =
|
||||
hasInteractiveViewport &&
|
||||
content.hovered &&
|
||||
!m_lookDragging &&
|
||||
!gizmoActive &&
|
||||
ImGui::IsMouseClicked(ImGuiMouseButton_Right);
|
||||
const bool beginPanDrag =
|
||||
hasInteractiveViewport &&
|
||||
content.hovered &&
|
||||
!m_panDragging &&
|
||||
!gizmoActive &&
|
||||
!m_lookDragging &&
|
||||
ImGui::IsMouseClicked(ImGuiMouseButton_Middle);
|
||||
const bool beginLeftPanDrag = usingViewMoveTool
|
||||
? ShouldBeginSceneViewportNavigationDrag(
|
||||
hasInteractiveViewport,
|
||||
viewportContentHovered,
|
||||
m_panDragging,
|
||||
m_lookDragging,
|
||||
gizmoActive,
|
||||
ImGuiMouseButton_Left)
|
||||
: false;
|
||||
const bool beginLookDrag = ShouldBeginSceneViewportNavigationDrag(
|
||||
hasInteractiveViewport,
|
||||
viewportContentHovered,
|
||||
m_lookDragging,
|
||||
m_panDragging,
|
||||
gizmoActive,
|
||||
ImGuiMouseButton_Right);
|
||||
const bool beginMiddlePanDrag = ShouldBeginSceneViewportNavigationDrag(
|
||||
hasInteractiveViewport,
|
||||
viewportContentHovered,
|
||||
m_panDragging,
|
||||
m_lookDragging,
|
||||
gizmoActive,
|
||||
ImGuiMouseButton_Middle);
|
||||
const bool beginPanDrag = beginLeftPanDrag || beginMiddlePanDrag;
|
||||
|
||||
if (beginTransformGizmo || orientationGizmoClick || selectClick || beginLookDrag || beginPanDrag) {
|
||||
if (ImGui::IsMouseClicked(ImGuiMouseButton_Right) || ImGui::IsMouseClicked(ImGuiMouseButton_Middle)) {
|
||||
LogSceneViewNavigation(
|
||||
logger,
|
||||
"SceneView nav click hovered=%d focused=%d hasViewport=%d clickedR=%d clickedM=%d downR=%d downM=%d "
|
||||
"look=%d pan=%d gizmoActive=%d ioDelta=(%.2f, %.2f)",
|
||||
content.hovered ? 1 : 0,
|
||||
content.focused ? 1 : 0,
|
||||
hasInteractiveViewport ? 1 : 0,
|
||||
ImGui::IsMouseClicked(ImGuiMouseButton_Right) ? 1 : 0,
|
||||
ImGui::IsMouseClicked(ImGuiMouseButton_Middle) ? 1 : 0,
|
||||
ImGui::IsMouseDown(ImGuiMouseButton_Right) ? 1 : 0,
|
||||
ImGui::IsMouseDown(ImGuiMouseButton_Middle) ? 1 : 0,
|
||||
m_lookDragging ? 1 : 0,
|
||||
m_panDragging ? 1 : 0,
|
||||
gizmoActive ? 1 : 0,
|
||||
io.MouseDelta.x,
|
||||
io.MouseDelta.y);
|
||||
}
|
||||
|
||||
if (toolOverlay.clicked || beginTransformGizmo || orientationGizmoClick || selectClick || beginLookDrag ||
|
||||
beginPanDrag) {
|
||||
ImGui::SetWindowFocus();
|
||||
}
|
||||
|
||||
if (beginTransformGizmo) {
|
||||
if (usingMoveGizmo) {
|
||||
if (hoveredGizmoKind == SceneViewportActiveGizmoKind::Scale) {
|
||||
m_scaleGizmo.TryBeginDrag(scaleGizmoContext, m_context->GetUndoManager());
|
||||
} else if (hoveredGizmoKind == SceneViewportActiveGizmoKind::Move) {
|
||||
m_moveGizmo.TryBeginDrag(moveGizmoContext, m_context->GetUndoManager());
|
||||
} else {
|
||||
} else if (hoveredGizmoKind == SceneViewportActiveGizmoKind::Rotate) {
|
||||
m_rotateGizmo.TryBeginDrag(rotateGizmoContext, m_context->GetUndoManager());
|
||||
}
|
||||
}
|
||||
@@ -194,13 +543,19 @@ void SceneViewPanel::Render() {
|
||||
if (orientationGizmoClick) {
|
||||
viewportHostService->AlignSceneViewToOrientationAxis(orientationAxisHit);
|
||||
overlay = viewportHostService->GetSceneViewOverlayData();
|
||||
if (usingMoveGizmo) {
|
||||
if (showingMoveGizmo) {
|
||||
moveGizmoContext = BuildMoveGizmoContext(*m_context, overlay, content, io.MousePos);
|
||||
m_moveGizmo.Update(moveGizmoContext);
|
||||
} else {
|
||||
}
|
||||
if (showingRotateGizmo) {
|
||||
rotateGizmoContext = BuildRotateGizmoContext(*m_context, overlay, content, io.MousePos);
|
||||
m_rotateGizmo.Update(rotateGizmoContext);
|
||||
}
|
||||
if (showingScaleGizmo) {
|
||||
scaleGizmoContext = BuildScaleGizmoContext(*m_context, overlay, content, io.MousePos);
|
||||
scaleGizmoContext.uniformOnly = usingTransformTool;
|
||||
m_scaleGizmo.Update(scaleGizmoContext);
|
||||
}
|
||||
}
|
||||
|
||||
if (selectClick) {
|
||||
@@ -220,16 +575,20 @@ void SceneViewPanel::Render() {
|
||||
|
||||
if (gizmoActive) {
|
||||
if (ImGui::IsMouseDown(ImGuiMouseButton_Left)) {
|
||||
if (usingMoveGizmo) {
|
||||
if (activeGizmoKind == SceneViewportActiveGizmoKind::Move) {
|
||||
m_moveGizmo.UpdateDrag(moveGizmoContext);
|
||||
} else {
|
||||
} else if (activeGizmoKind == SceneViewportActiveGizmoKind::Rotate) {
|
||||
m_rotateGizmo.UpdateDrag(rotateGizmoContext);
|
||||
} else if (activeGizmoKind == SceneViewportActiveGizmoKind::Scale) {
|
||||
m_scaleGizmo.UpdateDrag(scaleGizmoContext);
|
||||
}
|
||||
} else {
|
||||
if (usingMoveGizmo) {
|
||||
if (activeGizmoKind == SceneViewportActiveGizmoKind::Move) {
|
||||
m_moveGizmo.EndDrag(m_context->GetUndoManager());
|
||||
} else {
|
||||
} else if (activeGizmoKind == SceneViewportActiveGizmoKind::Rotate) {
|
||||
m_rotateGizmo.EndDrag(m_context->GetUndoManager());
|
||||
} else if (activeGizmoKind == SceneViewportActiveGizmoKind::Scale) {
|
||||
m_scaleGizmo.EndDrag(m_context->GetUndoManager());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -237,26 +596,49 @@ void SceneViewPanel::Render() {
|
||||
if (beginLookDrag) {
|
||||
m_lookDragging = true;
|
||||
m_panDragging = false;
|
||||
m_lastLookDragDelta = ImVec2(0.0f, 0.0f);
|
||||
m_lastPanDragDelta = ImVec2(0.0f, 0.0f);
|
||||
m_loggedLookDelta = false;
|
||||
m_loggedPanDelta = false;
|
||||
LogSceneViewNavigation(
|
||||
logger,
|
||||
"SceneView begin look drag hovered=%d focused=%d downR=%d downM=%d gizmoActive=%d",
|
||||
content.hovered ? 1 : 0,
|
||||
content.focused ? 1 : 0,
|
||||
ImGui::IsMouseDown(ImGuiMouseButton_Right) ? 1 : 0,
|
||||
ImGui::IsMouseDown(ImGuiMouseButton_Middle) ? 1 : 0,
|
||||
gizmoActive ? 1 : 0);
|
||||
}
|
||||
if (beginPanDrag) {
|
||||
m_panDragging = true;
|
||||
m_lookDragging = false;
|
||||
m_lastPanDragDelta = ImVec2(0.0f, 0.0f);
|
||||
m_lastLookDragDelta = ImVec2(0.0f, 0.0f);
|
||||
m_panDragButton = beginLeftPanDrag ? ImGuiMouseButton_Left : ImGuiMouseButton_Middle;
|
||||
m_loggedPanDelta = false;
|
||||
m_loggedLookDelta = false;
|
||||
LogSceneViewNavigation(
|
||||
logger,
|
||||
"SceneView begin pan drag hovered=%d focused=%d button=%d downR=%d downM=%d downL=%d gizmoActive=%d",
|
||||
content.hovered ? 1 : 0,
|
||||
content.focused ? 1 : 0,
|
||||
m_panDragButton,
|
||||
ImGui::IsMouseDown(ImGuiMouseButton_Right) ? 1 : 0,
|
||||
ImGui::IsMouseDown(ImGuiMouseButton_Middle) ? 1 : 0,
|
||||
ImGui::IsMouseDown(ImGuiMouseButton_Left) ? 1 : 0,
|
||||
gizmoActive ? 1 : 0);
|
||||
}
|
||||
|
||||
if (m_lookDragging && !ImGui::IsMouseDown(ImGuiMouseButton_Right)) {
|
||||
LogSceneViewNavigation(logger, "SceneView end look drag");
|
||||
m_lookDragging = false;
|
||||
m_lastLookDragDelta = ImVec2(0.0f, 0.0f);
|
||||
m_loggedLookDelta = false;
|
||||
}
|
||||
if (m_panDragging && !ImGui::IsMouseDown(ImGuiMouseButton_Middle)) {
|
||||
if (m_panDragging && !ImGui::IsMouseDown(m_panDragButton)) {
|
||||
LogSceneViewNavigation(logger, "SceneView end pan drag");
|
||||
m_panDragging = false;
|
||||
m_lastPanDragDelta = ImVec2(0.0f, 0.0f);
|
||||
m_panDragButton = ImGuiMouseButton_Middle;
|
||||
m_loggedPanDelta = false;
|
||||
}
|
||||
|
||||
if (m_lookDragging || m_panDragging || m_moveGizmo.IsActive() || m_rotateGizmo.IsActive()) {
|
||||
if (m_lookDragging || m_panDragging || m_moveGizmo.IsActive() || m_rotateGizmo.IsActive() ||
|
||||
m_scaleGizmo.IsActive()) {
|
||||
ImGui::SetNextFrameWantCaptureMouse(true);
|
||||
}
|
||||
if (m_lookDragging) {
|
||||
@@ -266,10 +648,10 @@ void SceneViewPanel::Render() {
|
||||
SceneViewportInput input = {};
|
||||
input.viewportSize = content.availableSize;
|
||||
input.deltaTime = io.DeltaTime;
|
||||
input.hovered = content.hovered;
|
||||
input.hovered = viewportContentHovered;
|
||||
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.mouseWheel = (viewportContentHovered && !m_lookDragging) ? io.MouseWheel : 0.0f;
|
||||
input.flySpeedDelta = (viewportContentHovered && m_lookDragging) ? io.MouseWheel : 0.0f;
|
||||
input.looking = m_lookDragging;
|
||||
input.orbiting = false;
|
||||
input.panning = m_panDragging;
|
||||
@@ -291,29 +673,33 @@ void SceneViewPanel::Render() {
|
||||
|
||||
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);
|
||||
input.mouseDelta = io.MouseDelta;
|
||||
if (!m_loggedLookDelta &&
|
||||
(input.mouseDelta.x != 0.0f || input.mouseDelta.y != 0.0f)) {
|
||||
LogSceneViewNavigation(
|
||||
logger,
|
||||
"SceneView look delta=(%.2f, %.2f) hovered=%d downR=%d",
|
||||
input.mouseDelta.x,
|
||||
input.mouseDelta.y,
|
||||
content.hovered ? 1 : 0,
|
||||
ImGui::IsMouseDown(ImGuiMouseButton_Right) ? 1 : 0);
|
||||
m_loggedLookDelta = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_panDragging) {
|
||||
const ImVec2 panDragDelta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Middle, 0.0f);
|
||||
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 = io.MouseDelta;
|
||||
if (!m_loggedPanDelta &&
|
||||
(input.mouseDelta.x != 0.0f || input.mouseDelta.y != 0.0f)) {
|
||||
LogSceneViewNavigation(
|
||||
logger,
|
||||
"SceneView pan delta=(%.2f, %.2f) hovered=%d downM=%d",
|
||||
input.mouseDelta.x,
|
||||
input.mouseDelta.y,
|
||||
content.hovered ? 1 : 0,
|
||||
ImGui::IsMouseDown(ImGuiMouseButton_Middle) ? 1 : 0);
|
||||
m_loggedPanDelta = true;
|
||||
}
|
||||
input.mouseDelta.x += framePanDelta.x;
|
||||
input.mouseDelta.y += framePanDelta.y;
|
||||
m_lastPanDragDelta = panDragDelta;
|
||||
} else {
|
||||
m_lastPanDragDelta = ImVec2(0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,12 +707,41 @@ void SceneViewPanel::Render() {
|
||||
|
||||
if (content.hasViewportArea && content.frame.hasTexture) {
|
||||
overlay = viewportHostService->GetSceneViewOverlayData();
|
||||
if (usingMoveGizmo) {
|
||||
SceneViewportActiveGizmoKind drawActiveGizmoKind = SceneViewportActiveGizmoKind::None;
|
||||
if (m_moveGizmo.IsActive()) {
|
||||
drawActiveGizmoKind = SceneViewportActiveGizmoKind::Move;
|
||||
} else if (m_rotateGizmo.IsActive()) {
|
||||
drawActiveGizmoKind = SceneViewportActiveGizmoKind::Rotate;
|
||||
} else if (m_scaleGizmo.IsActive()) {
|
||||
drawActiveGizmoKind = SceneViewportActiveGizmoKind::Scale;
|
||||
}
|
||||
if (showingMoveGizmo) {
|
||||
moveGizmoContext = BuildMoveGizmoContext(*m_context, overlay, content, io.MousePos);
|
||||
m_moveGizmo.Update(moveGizmoContext);
|
||||
} else {
|
||||
SceneViewportMoveGizmoContext updateContext = moveGizmoContext;
|
||||
if (drawActiveGizmoKind != SceneViewportActiveGizmoKind::None &&
|
||||
drawActiveGizmoKind != SceneViewportActiveGizmoKind::Move) {
|
||||
updateContext.mousePosition = Math::Vector2(-1.0f, -1.0f);
|
||||
}
|
||||
m_moveGizmo.Update(updateContext);
|
||||
}
|
||||
if (showingRotateGizmo) {
|
||||
rotateGizmoContext = BuildRotateGizmoContext(*m_context, overlay, content, io.MousePos);
|
||||
m_rotateGizmo.Update(rotateGizmoContext);
|
||||
SceneViewportRotateGizmoContext updateContext = rotateGizmoContext;
|
||||
if (drawActiveGizmoKind != SceneViewportActiveGizmoKind::None &&
|
||||
drawActiveGizmoKind != SceneViewportActiveGizmoKind::Rotate) {
|
||||
updateContext.mousePosition = Math::Vector2(-1.0f, -1.0f);
|
||||
}
|
||||
m_rotateGizmo.Update(updateContext);
|
||||
}
|
||||
if (showingScaleGizmo) {
|
||||
scaleGizmoContext = BuildScaleGizmoContext(*m_context, overlay, content, io.MousePos);
|
||||
scaleGizmoContext.uniformOnly = usingTransformTool;
|
||||
SceneViewportScaleGizmoContext updateContext = scaleGizmoContext;
|
||||
if (drawActiveGizmoKind != SceneViewportActiveGizmoKind::None &&
|
||||
drawActiveGizmoKind != SceneViewportActiveGizmoKind::Scale) {
|
||||
updateContext.mousePosition = Math::Vector2(-1.0f, -1.0f);
|
||||
}
|
||||
m_scaleGizmo.Update(updateContext);
|
||||
}
|
||||
|
||||
DrawSceneViewportOverlay(
|
||||
@@ -335,8 +750,9 @@ void SceneViewPanel::Render() {
|
||||
content.itemMin,
|
||||
content.itemMax,
|
||||
content.availableSize,
|
||||
usingMoveGizmo ? &m_moveGizmo.GetDrawData() : nullptr,
|
||||
usingMoveGizmo ? nullptr : &m_rotateGizmo.GetDrawData());
|
||||
showingMoveGizmo ? &m_moveGizmo.GetDrawData() : nullptr,
|
||||
showingRotateGizmo ? &m_rotateGizmo.GetDrawData() : nullptr,
|
||||
showingScaleGizmo ? &m_scaleGizmo.GetDrawData() : nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user