feat: expand editor scripting asset and viewport flow

This commit is contained in:
2026-04-03 13:22:30 +08:00
parent ed8c27fde2
commit a05d0b80a2
124 changed files with 10397 additions and 1737 deletions

View File

@@ -3,8 +3,13 @@
#include "Core/ISceneManager.h"
#include "Core/ISelectionManager.h"
#include "SceneViewPanel.h"
#include "Viewport/SceneViewportEditorOverlayData.h"
#include "Viewport/SceneViewportOverlayHandleBuilder.h"
#include "Viewport/SceneViewportOverlayHitTester.h"
#include "Viewport/SceneViewportMath.h"
#include "Viewport/SceneViewportOrientationGizmo.h"
#include "Viewport/SceneViewportOverlayRenderer.h"
#include "Viewport/SceneViewportTransformGizmoFrameBuilder.h"
#include "ViewportPanelContent.h"
#include "Platform/Win32Utf8.h"
#include "UI/UI.h"
@@ -13,9 +18,11 @@
#include <imgui.h>
#include <algorithm>
#include <cstdarg>
#include <cstdio>
#include <filesystem>
#include <vector>
namespace XCEngine {
namespace Editor {
@@ -28,13 +35,209 @@ struct SceneViewportToolOverlayResult {
SceneViewportToolMode clickedTool = SceneViewportToolMode::Move;
};
enum class SceneViewportActiveGizmoKind : uint8_t {
enum class SceneViewportInteractionKind : uint8_t {
None = 0,
Move,
Rotate,
Scale
MoveGizmo,
RotateGizmo,
ScaleGizmo,
OrientationGizmo,
SceneIcon
};
struct SceneViewportInteractionCandidate {
SceneViewportInteractionKind kind = SceneViewportInteractionKind::None;
int priority = 0;
int secondaryPriority = 0;
float distanceSq = Math::FLOAT_MAX;
float depth = Math::FLOAT_MAX;
uint64_t entityId = 0;
SceneViewportGizmoAxis moveAxis = SceneViewportGizmoAxis::None;
SceneViewportGizmoPlane movePlane = SceneViewportGizmoPlane::None;
SceneViewportRotateGizmoAxis rotateAxis = SceneViewportRotateGizmoAxis::None;
SceneViewportScaleGizmoHandle scaleHandle = SceneViewportScaleGizmoHandle::None;
SceneViewportOrientationAxis orientationAxis = SceneViewportOrientationAxis::None;
bool HasHit() const {
return kind != SceneViewportInteractionKind::None;
}
};
const char* GetSceneViewportPivotModeLabel(SceneViewportPivotMode mode) {
return mode == SceneViewportPivotMode::Pivot ? "Pivot" : "Center";
}
const char* GetSceneViewportTransformSpaceModeLabel(SceneViewportTransformSpaceMode mode) {
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;
}
}
bool IsBetterSceneViewportInteractionCandidate(
const SceneViewportInteractionCandidate& candidate,
const SceneViewportInteractionCandidate& current) {
constexpr float kMetricEpsilon = 0.001f;
if (!candidate.HasHit()) {
return false;
}
if (!current.HasHit()) {
return true;
}
if (candidate.priority != current.priority) {
return candidate.priority > current.priority;
}
if (candidate.distanceSq + kMetricEpsilon < current.distanceSq) {
return true;
}
if (current.distanceSq + kMetricEpsilon < candidate.distanceSq) {
return false;
}
if (candidate.depth + kMetricEpsilon < current.depth) {
return true;
}
if (current.depth + kMetricEpsilon < candidate.depth) {
return false;
}
return candidate.secondaryPriority > current.secondaryPriority;
}
void AccumulateSceneViewportInteractionCandidate(
const SceneViewportInteractionCandidate& candidate,
SceneViewportInteractionCandidate& bestCandidate) {
if (IsBetterSceneViewportInteractionCandidate(candidate, bestCandidate)) {
bestCandidate = candidate;
}
}
SceneViewportInteractionCandidate BuildOrientationGizmoInteractionCandidate(
SceneViewportOrientationAxis axis) {
SceneViewportInteractionCandidate candidate = {};
if (axis == SceneViewportOrientationAxis::None) {
return candidate;
}
candidate.kind = SceneViewportInteractionKind::OrientationGizmo;
candidate.priority = 200;
candidate.distanceSq = 0.0f;
candidate.depth = 0.0f;
candidate.orientationAxis = axis;
return candidate;
}
SceneViewportInteractionCandidate BuildOverlayHandleInteractionCandidate(
const SceneViewportOverlayHandleHitResult& hitResult) {
SceneViewportInteractionCandidate candidate = {};
if (!hitResult.HasHit()) {
return candidate;
}
candidate.priority = hitResult.priority;
candidate.distanceSq = hitResult.distanceSq;
candidate.depth = hitResult.depth;
candidate.entityId = hitResult.entityId;
switch (hitResult.kind) {
case SceneViewportOverlayHandleKind::SceneIcon:
candidate.kind = SceneViewportInteractionKind::SceneIcon;
return candidate;
case SceneViewportOverlayHandleKind::MoveAxis:
candidate.kind = SceneViewportInteractionKind::MoveGizmo;
candidate.moveAxis = static_cast<SceneViewportGizmoAxis>(hitResult.handleId);
return candidate;
case SceneViewportOverlayHandleKind::MovePlane:
candidate.kind = SceneViewportInteractionKind::MoveGizmo;
candidate.movePlane = static_cast<SceneViewportGizmoPlane>(hitResult.handleId);
return candidate;
case SceneViewportOverlayHandleKind::RotateAxis:
candidate.kind = SceneViewportInteractionKind::RotateGizmo;
candidate.rotateAxis = static_cast<SceneViewportRotateGizmoAxis>(hitResult.handleId);
return candidate;
case SceneViewportOverlayHandleKind::ScaleAxis:
case SceneViewportOverlayHandleKind::ScaleUniform:
candidate.kind = SceneViewportInteractionKind::ScaleGizmo;
candidate.scaleHandle = static_cast<SceneViewportScaleGizmoHandle>(hitResult.handleId);
return candidate;
case SceneViewportOverlayHandleKind::None:
default:
return SceneViewportInteractionCandidate{};
}
return candidate;
}
float GetSceneToolbarToggleWidth(const char* firstLabel, const char* secondLabel) {
constexpr float kHorizontalPadding = 10.0f;
constexpr float kMinWidth = 68.0f;
const float maxLabelWidth = (std::max)(
ImGui::CalcTextSize(firstLabel).x,
ImGui::CalcTextSize(secondLabel).x);
return (std::max)(kMinWidth, maxLabelWidth + kHorizontalPadding * 2.0f);
}
void RenderSceneViewportTopBar(
SceneViewportPivotMode& pivotMode,
SceneViewportTransformSpaceMode& transformSpaceMode) {
constexpr float kSceneToolbarHeight = 24.0f;
constexpr float kSceneToolbarPaddingY = 0.0f;
constexpr float kSceneToolbarButtonHeight = kSceneToolbarHeight - kSceneToolbarPaddingY * 2.0f;
constexpr ImVec2 kSceneToolbarButtonFramePadding(8.0f, 1.0f);
UI::PanelToolbarScope toolbar(
"SceneToolbar",
kSceneToolbarHeight,
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse,
true,
ImVec2(UI::ToolbarPadding().x, kSceneToolbarPaddingY),
ImVec2(0.0f, UI::ToolbarItemSpacing().y),
ImVec4(0.23f, 0.23f, 0.23f, 1.0f));
if (!toolbar.IsOpen()) {
return;
}
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, kSceneToolbarButtonFramePadding);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 0.0f);
if (UI::ToolbarButton(
GetSceneViewportPivotModeLabel(pivotMode),
true,
ImVec2(GetSceneToolbarToggleWidth("Pivot", "Center"), kSceneToolbarButtonHeight))) {
pivotMode = pivotMode == SceneViewportPivotMode::Pivot
? SceneViewportPivotMode::Center
: SceneViewportPivotMode::Pivot;
}
ImGui::SameLine(0.0f, 0.0f);
if (UI::ToolbarButton(
GetSceneViewportTransformSpaceModeLabel(transformSpaceMode),
true,
ImVec2(GetSceneToolbarToggleWidth("Global", "Local"), kSceneToolbarButtonHeight))) {
transformSpaceMode = transformSpaceMode == SceneViewportTransformSpaceMode::Global
? SceneViewportTransformSpaceMode::Local
: SceneViewportTransformSpaceMode::Global;
}
ImGui::PopStyleVar(2);
}
const char* GetSceneViewportToolTooltip(SceneViewportToolMode toolMode) {
switch (toolMode) {
case SceneViewportToolMode::ViewMove:
@@ -69,6 +272,19 @@ const char* GetSceneViewportToolIconBaseName(SceneViewportToolMode toolMode) {
}
}
std::string BuildSceneViewportIconPath(const char* iconBaseName, bool active = false) {
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(iconBaseName));
if (active) {
iconPath += L"_on";
}
iconPath += L".png";
return XCEngine::Editor::Platform::WideToUtf8(iconPath.lexically_normal().wstring());
}
const std::string& GetSceneViewportToolIconPath(SceneViewportToolMode toolMode, bool active) {
static std::string cachedPaths[5][2] = {};
const size_t toolIndex = static_cast<size_t>(toolMode);
@@ -78,16 +294,7 @@ const std::string& GetSceneViewportToolIconPath(SceneViewportToolMode toolMode,
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());
cachedPath = BuildSceneViewportIconPath(GetSceneViewportToolIconBaseName(toolMode), active);
return cachedPath;
}
@@ -205,72 +412,6 @@ bool ShouldBeginSceneViewportNavigationDrag(
ImGui::IsMouseClicked(button);
}
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;
}
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;
}
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") {}
@@ -283,6 +424,7 @@ void SceneViewPanel::Render() {
return;
}
RenderSceneViewportTopBar(m_pivotMode, m_transformSpaceMode);
const ViewportPanelContentResult content = RenderViewportPanelContent(*m_context, EditorViewportKind::Scene);
if (IViewportHostService* viewportHostService = m_context->GetViewportHostService()) {
const ImGuiIO& io = ImGui::GetIO();
@@ -304,8 +446,20 @@ void SceneViewPanel::Render() {
m_toolMode = toolOverlay.clickedTool;
}
if (content.focused && !io.WantTextInput && !m_lookDragging && !m_panDragging) {
if (ImGui::IsKeyPressed(ImGuiKey_W, false)) {
const bool allowToolShortcut = !io.WantTextInput && !m_lookDragging && !m_panDragging;
if (allowToolShortcut) {
if (ImGui::IsKeyPressed(ImGuiKey_Q, false)) {
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 = SceneViewportToolMode::ViewMove;
} else if (ImGui::IsKeyPressed(ImGuiKey_W, false)) {
if (m_rotateGizmo.IsActive()) {
m_rotateGizmo.CancelDrag(&m_context->GetUndoManager());
}
@@ -337,103 +491,68 @@ void SceneViewPanel::Render() {
const bool showingMoveGizmo = m_toolMode == SceneViewportToolMode::Move || usingTransformTool;
const bool showingRotateGizmo = m_toolMode == SceneViewportToolMode::Rotate || usingTransformTool;
const bool showingScaleGizmo = m_toolMode == SceneViewportToolMode::Scale || usingTransformTool;
const bool useCenterPivot = m_pivotMode == SceneViewportPivotMode::Center;
const bool localSpace = m_transformSpaceMode == SceneViewportTransformSpaceMode::Local;
const Math::Vector2 viewportSize(content.availableSize.x, content.availableSize.y);
const Math::Vector2 localMousePosition(
io.MousePos.x - content.itemMin.x,
io.MousePos.y - content.itemMin.y);
SceneViewportOverlayData overlay = {};
SceneViewportMoveGizmoContext moveGizmoContext = {};
SceneViewportRotateGizmoContext rotateGizmoContext = {};
SceneViewportScaleGizmoContext scaleGizmoContext = {};
SceneViewportTransformGizmoFrameState gizmoFrameState = {};
SceneViewportOverlayFrameData emptySceneOverlayFrameData = {};
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());
}
} 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());
}
} 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);
}
gizmoFrameState = RefreshSceneViewportTransformGizmos(
*m_context,
overlay,
viewportSize,
localMousePosition,
useCenterPivot,
localSpace,
usingTransformTool,
showingMoveGizmo,
m_moveGizmo,
showingRotateGizmo,
m_rotateGizmo,
showingScaleGizmo,
m_scaleGizmo);
activeGizmoKind = gizmoFrameState.activeGizmoKind;
} else {
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());
}
CancelSceneViewportTransformGizmoDrags(*m_context, m_moveGizmo, m_rotateGizmo, m_scaleGizmo);
}
const bool moveGizmoHovering = showingMoveGizmo && m_moveGizmo.IsHoveringHandle();
const bool rotateGizmoHovering = showingRotateGizmo && m_rotateGizmo.IsHoveringHandle();
const bool scaleGizmoHovering = showingScaleGizmo && m_scaleGizmo.IsHoveringHandle();
const SceneViewportTransformGizmoHandleBuildInputs interactionGizmoInputs =
hasInteractiveViewport
? BuildSceneViewportTransformGizmoHandleBuildInputs(
showingMoveGizmo,
m_moveGizmo,
gizmoFrameState.moveContext,
showingRotateGizmo,
m_rotateGizmo,
gizmoFrameState.rotateContext,
showingScaleGizmo,
m_scaleGizmo,
gizmoFrameState.scaleContext)
: SceneViewportTransformGizmoHandleBuildInputs{};
const SceneViewportOverlayFrameData& interactionOverlayFrameData =
hasInteractiveViewport
? viewportHostService->GetSceneViewInteractionOverlayFrameData(
*m_context,
overlay,
interactionGizmoInputs)
: emptySceneOverlayFrameData;
const SceneViewportOverlayHandleHitResult overlayHandleHit =
hasInteractiveViewport
? HitTestSceneViewportOverlayHandles(
interactionOverlayFrameData,
Math::Vector2(content.availableSize.x, content.availableSize.y),
localMousePosition)
: SceneViewportOverlayHandleHitResult{};
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) {
@@ -443,44 +562,83 @@ void SceneViewPanel::Render() {
} 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 =
SceneViewportInteractionCandidate hoveredInteraction = {};
const bool canResolveViewportInteraction =
hasInteractiveViewport &&
viewportContentHovered &&
!usingViewMoveTool &&
!m_lookDragging &&
!m_panDragging &&
!gizmoHovering &&
!gizmoActive
? HitTestSceneViewportOrientationGizmo(
overlay,
content.itemMin,
content.itemMax,
io.MousePos)
: SceneViewportOrientationAxis::None;
!toolOverlay.hovered &&
!gizmoActive;
if (canResolveViewportInteraction) {
AccumulateSceneViewportInteractionCandidate(
BuildOverlayHandleInteractionCandidate(overlayHandleHit),
hoveredInteraction);
AccumulateSceneViewportInteractionCandidate(
BuildOrientationGizmoInteractionCandidate(
HitTestSceneViewportOrientationGizmo(
overlay,
content.itemMin,
content.itemMax,
io.MousePos)),
hoveredInteraction);
}
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);
}
}
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 &&
viewportContentHovered &&
!usingViewMoveTool &&
!m_lookDragging &&
!m_panDragging &&
!orientationGizmoClick &&
!gizmoHovering &&
!gizmoActive;
canResolveViewportInteraction &&
!hoveredInteraction.HasHit();
const bool beginLeftPanDrag = usingViewMoveTool
? ShouldBeginSceneViewportNavigationDrag(
hasInteractiveViewport,
@@ -525,47 +683,32 @@ void SceneViewPanel::Render() {
io.MouseDelta.y);
}
if (toolOverlay.clicked || beginTransformGizmo || orientationGizmoClick || selectClick || beginLookDrag ||
if (toolOverlay.clicked || beginTransformGizmo || orientationGizmoClick || sceneIconClick || selectClick || beginLookDrag ||
beginPanDrag) {
ImGui::SetWindowFocus();
}
if (beginTransformGizmo) {
if (hoveredGizmoKind == SceneViewportActiveGizmoKind::Scale) {
m_scaleGizmo.TryBeginDrag(scaleGizmoContext, m_context->GetUndoManager());
m_scaleGizmo.TryBeginDrag(gizmoFrameState.scaleContext, m_context->GetUndoManager());
} else if (hoveredGizmoKind == SceneViewportActiveGizmoKind::Move) {
m_moveGizmo.TryBeginDrag(moveGizmoContext, m_context->GetUndoManager());
m_moveGizmo.TryBeginDrag(gizmoFrameState.moveContext, m_context->GetUndoManager());
} else if (hoveredGizmoKind == SceneViewportActiveGizmoKind::Rotate) {
m_rotateGizmo.TryBeginDrag(rotateGizmoContext, m_context->GetUndoManager());
m_rotateGizmo.TryBeginDrag(gizmoFrameState.rotateContext, m_context->GetUndoManager());
}
}
if (orientationGizmoClick) {
viewportHostService->AlignSceneViewToOrientationAxis(orientationAxisHit);
overlay = viewportHostService->GetSceneViewOverlayData();
if (showingMoveGizmo) {
moveGizmoContext = BuildMoveGizmoContext(*m_context, overlay, content, io.MousePos);
m_moveGizmo.Update(moveGizmoContext);
}
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) {
const ImVec2 localMousePosition(
io.MousePos.x - content.itemMin.x,
io.MousePos.y - content.itemMin.y);
if (sceneIconClick) {
m_context->GetSelectionManager().SetSelectedEntity(clickedSceneIconEntity);
} else if (selectClick) {
const uint64_t selectedEntity = viewportHostService->PickSceneViewEntity(
*m_context,
content.availableSize,
localMousePosition);
ImVec2(localMousePosition.x, localMousePosition.y));
if (selectedEntity != 0) {
m_context->GetSelectionManager().SetSelectedEntity(selectedEntity);
} else {
@@ -576,11 +719,11 @@ void SceneViewPanel::Render() {
if (gizmoActive) {
if (ImGui::IsMouseDown(ImGuiMouseButton_Left)) {
if (activeGizmoKind == SceneViewportActiveGizmoKind::Move) {
m_moveGizmo.UpdateDrag(moveGizmoContext);
m_moveGizmo.UpdateDrag(gizmoFrameState.moveContext);
} else if (activeGizmoKind == SceneViewportActiveGizmoKind::Rotate) {
m_rotateGizmo.UpdateDrag(rotateGizmoContext);
m_rotateGizmo.UpdateDrag(gizmoFrameState.rotateContext);
} else if (activeGizmoKind == SceneViewportActiveGizmoKind::Scale) {
m_scaleGizmo.UpdateDrag(scaleGizmoContext);
m_scaleGizmo.UpdateDrag(gizmoFrameState.scaleContext);
}
} else {
if (activeGizmoKind == SceneViewportActiveGizmoKind::Move) {
@@ -707,52 +850,41 @@ void SceneViewPanel::Render() {
if (content.hasViewportArea && content.frame.hasTexture) {
overlay = viewportHostService->GetSceneViewOverlayData();
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);
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);
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);
}
const SceneViewportTransformGizmoFrameState drawGizmoFrameState =
RefreshSceneViewportTransformGizmos(
*m_context,
overlay,
viewportSize,
localMousePosition,
useCenterPivot,
localSpace,
usingTransformTool,
showingMoveGizmo,
m_moveGizmo,
showingRotateGizmo,
m_rotateGizmo,
showingScaleGizmo,
m_scaleGizmo);
viewportHostService->SetSceneViewTransientTransformGizmoOverlayData(
overlay,
BuildSceneViewportTransformGizmoHandleBuildInputs(
showingMoveGizmo,
m_moveGizmo,
drawGizmoFrameState.moveContext,
showingRotateGizmo,
m_rotateGizmo,
drawGizmoFrameState.rotateContext,
showingScaleGizmo,
m_scaleGizmo,
drawGizmoFrameState.scaleContext));
DrawSceneViewportOverlay(
ImGui::GetWindowDrawList(),
overlay,
content.itemMin,
content.itemMax,
content.availableSize,
showingMoveGizmo ? &m_moveGizmo.GetDrawData() : nullptr,
showingRotateGizmo ? &m_rotateGizmo.GetDrawData() : nullptr,
showingScaleGizmo ? &m_scaleGizmo.GetDrawData() : nullptr);
content.availableSize);
}
}