136 lines
4.4 KiB
C++
136 lines
4.4 KiB
C++
#include "SceneViewportOverlayRenderer.h"
|
|
#include "SceneViewportOrientationGizmo.h"
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
|
|
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<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));
|
|
}
|
|
|
|
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
|