#include "SceneViewportOverlayRenderer.h" #include "SceneViewportOrientationGizmo.h" #include #include namespace XCEngine { namespace Editor { namespace { constexpr float kMoveGizmoArrowLength = 14.0f; constexpr float kMoveGizmoArrowHalfWidth = 7.0f; ImU32 ToImGuiColor(const Math::Color& color) { const auto toChannel = [](float value) -> int { return static_cast(std::clamp(value, 0.0f, 1.0f) * 255.0f + 0.5f); }; return IM_COL32( toChannel(color.r), toChannel(color.g), toChannel(color.b), toChannel(color.a)); } ImVec2 NormalizeImVec2(const ImVec2& value, const ImVec2& fallback = ImVec2(1.0f, 0.0f)) { const float lengthSq = value.x * value.x + value.y * value.y; if (lengthSq <= 1e-6f) { return fallback; } const float inverseLength = 1.0f / std::sqrt(lengthSq); return ImVec2(value.x * inverseLength, value.y * inverseLength); } void DrawSceneMoveGizmoPlane( ImDrawList* drawList, const ImVec2& viewportMin, const SceneViewportMoveGizmoPlaneDrawData& plane) { if (drawList == nullptr || !plane.visible) { return; } ImVec2 points[4] = {}; for (size_t index = 0; index < plane.corners.size(); ++index) { points[index] = ImVec2( viewportMin.x + plane.corners[index].x, viewportMin.y + plane.corners[index].y); } drawList->AddConvexPolyFilled(points, 4, ToImGuiColor(plane.fillColor)); drawList->AddPolyline( points, 4, ToImGuiColor(plane.outlineColor), true, plane.active ? 2.6f : (plane.hovered ? 2.0f : 1.4f)); } void DrawSceneMoveGizmoAxis( ImDrawList* drawList, const ImVec2& viewportMin, const SceneViewportMoveGizmoHandleDrawData& handle) { if (drawList == nullptr || !handle.visible) { return; } const ImU32 color = ToImGuiColor(handle.color); const float thickness = handle.active ? 4.0f : (handle.hovered ? 3.0f : 2.0f); const ImVec2 start(viewportMin.x + handle.start.x, viewportMin.y + handle.start.y); const ImVec2 end(viewportMin.x + handle.end.x, viewportMin.y + handle.end.y); const ImVec2 direction = NormalizeImVec2(ImVec2(end.x - start.x, end.y - start.y)); const ImVec2 normal(-direction.y, direction.x); const ImVec2 arrowBase( end.x - direction.x * kMoveGizmoArrowLength, end.y - direction.y * kMoveGizmoArrowLength); const ImVec2 arrowLeft( arrowBase.x + normal.x * kMoveGizmoArrowHalfWidth, arrowBase.y + normal.y * kMoveGizmoArrowHalfWidth); const ImVec2 arrowRight( arrowBase.x - normal.x * kMoveGizmoArrowHalfWidth, arrowBase.y - normal.y * kMoveGizmoArrowHalfWidth); drawList->AddLine(start, arrowBase, color, thickness); const ImVec2 triangle[3] = { end, arrowLeft, arrowRight }; drawList->AddConvexPolyFilled(triangle, 3, color); } void DrawSceneMoveGizmo( ImDrawList* drawList, const ImVec2& viewportMin, const SceneViewportMoveGizmoDrawData& moveGizmo) { if (drawList == nullptr || !moveGizmo.visible) { return; } const ImVec2 pivot(viewportMin.x + moveGizmo.pivot.x, viewportMin.y + moveGizmo.pivot.y); for (const SceneViewportMoveGizmoPlaneDrawData& plane : moveGizmo.planes) { DrawSceneMoveGizmoPlane(drawList, viewportMin, plane); } for (const SceneViewportMoveGizmoHandleDrawData& handle : moveGizmo.handles) { DrawSceneMoveGizmoAxis(drawList, viewportMin, handle); } drawList->AddCircleFilled(pivot, moveGizmo.pivotRadius + 1.0f, IM_COL32(20, 22, 24, 220), 20); drawList->AddCircle(pivot, moveGizmo.pivotRadius + 1.0f, IM_COL32(255, 255, 255, 48), 20, 1.0f); } } // namespace void DrawSceneViewportOverlay( ImDrawList* drawList, const SceneViewportOverlayData& overlay, const ImVec2& viewportMin, const ImVec2& viewportMax, const ImVec2& viewportSize, const SceneViewportMoveGizmoDrawData* moveGizmo) { if (drawList == nullptr || viewportSize.x <= 1.0f || viewportSize.y <= 1.0f) { return; } drawList->PushClipRect(viewportMin, viewportMax, true); if (overlay.valid) { DrawSceneViewportOrientationGizmo(drawList, overlay, viewportMin, viewportMax); } if (moveGizmo != nullptr) { DrawSceneMoveGizmo(drawList, viewportMin, *moveGizmo); } drawList->PopClipRect(); } } // namespace Editor } // namespace XCEngine