2026-03-29 15:12:38 +08:00
|
|
|
#include "SceneViewportOverlayRenderer.h"
|
|
|
|
|
#include "SceneViewportMath.h"
|
|
|
|
|
|
|
|
|
|
namespace XCEngine {
|
|
|
|
|
namespace Editor {
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
Math::Matrix4x4 BuildOverlayViewMatrix(const SceneViewportOverlayData& overlay) {
|
|
|
|
|
return BuildSceneViewportViewMatrix(overlay);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-29 16:18:13 +08:00
|
|
|
ImU32 ToImGuiColor(const Math::Color& color) {
|
|
|
|
|
const auto toChannel = [](float value) -> int {
|
|
|
|
|
return static_cast<int>(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));
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-29 15:12:38 +08:00
|
|
|
void DrawAxisLabel(ImDrawList* drawList, const ImVec2& position, const char* label, ImU32 color) {
|
|
|
|
|
if (drawList == nullptr || label == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const ImVec2 labelSize = ImGui::CalcTextSize(label);
|
|
|
|
|
drawList->AddText(
|
|
|
|
|
ImVec2(position.x - labelSize.x * 0.5f, position.y - labelSize.y * 0.5f),
|
|
|
|
|
color,
|
|
|
|
|
label);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DrawSceneAxisWidget(
|
|
|
|
|
ImDrawList* drawList,
|
|
|
|
|
const SceneViewportOverlayData& overlay,
|
|
|
|
|
const ImVec2& viewportMin,
|
|
|
|
|
const ImVec2& viewportMax) {
|
|
|
|
|
if (drawList == nullptr || !overlay.valid) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Math::Matrix4x4 view = BuildOverlayViewMatrix(overlay);
|
|
|
|
|
const ImVec2 center(viewportMax.x - 52.0f, viewportMin.y + 52.0f);
|
|
|
|
|
const float radius = 25.0f;
|
|
|
|
|
|
|
|
|
|
drawList->AddCircleFilled(center, radius + 12.0f, IM_COL32(17, 19, 22, 178), 24);
|
|
|
|
|
drawList->AddCircle(center, radius + 12.0f, IM_COL32(255, 255, 255, 30), 24, 1.0f);
|
|
|
|
|
|
|
|
|
|
struct AxisLine {
|
|
|
|
|
Math::Vector3 axis;
|
|
|
|
|
const char* label;
|
|
|
|
|
ImU32 color;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const AxisLine axes[] = {
|
|
|
|
|
{ Math::Vector3::Right(), "x", IM_COL32(239, 83, 80, 255) },
|
|
|
|
|
{ Math::Vector3::Up(), "y", IM_COL32(102, 187, 106, 255) },
|
|
|
|
|
{ Math::Vector3::Forward(), "z", IM_COL32(66, 165, 245, 255) }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (const AxisLine& axis : axes) {
|
|
|
|
|
const Math::Vector3 viewAxis = view.MultiplyVector(axis.axis);
|
|
|
|
|
const ImVec2 end(
|
|
|
|
|
center.x + viewAxis.x * radius,
|
|
|
|
|
center.y - viewAxis.y * radius);
|
|
|
|
|
drawList->AddLine(center, end, axis.color, 2.0f);
|
|
|
|
|
drawList->AddCircleFilled(end, 6.0f, axis.color, 16);
|
|
|
|
|
DrawAxisLabel(drawList, end, axis.label, IM_COL32(245, 245, 245, 255));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-29 16:18:13 +08:00
|
|
|
void DrawSceneMoveGizmo(
|
|
|
|
|
ImDrawList* drawList,
|
|
|
|
|
const SceneViewportMoveGizmoDrawData& moveGizmo) {
|
|
|
|
|
if (drawList == nullptr || !moveGizmo.visible) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const ImVec2 pivot(moveGizmo.pivot.x, moveGizmo.pivot.y);
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
for (const SceneViewportMoveGizmoHandleDrawData& handle : moveGizmo.handles) {
|
|
|
|
|
if (!handle.visible) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const ImU32 color = ToImGuiColor(handle.color);
|
|
|
|
|
const float thickness = handle.active ? 4.0f : (handle.hovered ? 3.0f : 2.0f);
|
|
|
|
|
const ImVec2 start(handle.start.x, handle.start.y);
|
|
|
|
|
const ImVec2 end(handle.end.x, handle.end.y);
|
|
|
|
|
drawList->AddLine(start, end, color, thickness);
|
|
|
|
|
drawList->AddCircleFilled(end, handle.active ? 6.5f : 5.5f, color, 20);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-29 15:12:38 +08:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
void DrawSceneViewportOverlay(
|
|
|
|
|
ImDrawList* drawList,
|
|
|
|
|
const SceneViewportOverlayData& overlay,
|
|
|
|
|
const ImVec2& viewportMin,
|
|
|
|
|
const ImVec2& viewportMax,
|
2026-03-29 16:18:13 +08:00
|
|
|
const ImVec2& viewportSize,
|
|
|
|
|
const SceneViewportMoveGizmoDrawData* moveGizmo) {
|
|
|
|
|
if (drawList == nullptr || viewportSize.x <= 1.0f || viewportSize.y <= 1.0f) {
|
2026-03-29 15:12:38 +08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
drawList->PushClipRect(viewportMin, viewportMax, true);
|
2026-03-29 16:18:13 +08:00
|
|
|
if (overlay.valid) {
|
|
|
|
|
DrawSceneAxisWidget(drawList, overlay, viewportMin, viewportMax);
|
|
|
|
|
}
|
|
|
|
|
if (moveGizmo != nullptr) {
|
|
|
|
|
DrawSceneMoveGizmo(drawList, *moveGizmo);
|
|
|
|
|
}
|
2026-03-29 15:12:38 +08:00
|
|
|
drawList->PopClipRect();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace Editor
|
|
|
|
|
} // namespace XCEngine
|