603 lines
22 KiB
C++
603 lines
22 KiB
C++
#pragma once
|
|
|
|
#include "SceneViewportEditorOverlayData.h"
|
|
#include "SceneViewportMoveGizmo.h"
|
|
#include "SceneViewportRotateGizmo.h"
|
|
#include "SceneViewportScaleGizmo.h"
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
|
|
namespace XCEngine {
|
|
namespace Editor {
|
|
|
|
struct SceneViewportTransformGizmoHandleBuildInputs {
|
|
const SceneViewportMoveGizmoDrawData* moveGizmo = nullptr;
|
|
uint64_t moveEntityId = 0;
|
|
const SceneViewportRotateGizmoDrawData* rotateGizmo = nullptr;
|
|
uint64_t rotateEntityId = 0;
|
|
const SceneViewportScaleGizmoDrawData* scaleGizmo = nullptr;
|
|
uint64_t scaleEntityId = 0;
|
|
};
|
|
|
|
struct SceneViewportTransformGizmoOverlayState {
|
|
bool hasMoveGizmo = false;
|
|
SceneViewportMoveGizmoDrawData moveGizmo = {};
|
|
uint64_t moveEntityId = 0;
|
|
bool hasRotateGizmo = false;
|
|
SceneViewportRotateGizmoDrawData rotateGizmo = {};
|
|
uint64_t rotateEntityId = 0;
|
|
bool hasScaleGizmo = false;
|
|
SceneViewportScaleGizmoDrawData scaleGizmo = {};
|
|
uint64_t scaleEntityId = 0;
|
|
|
|
bool HasAnyVisibleGizmo() const {
|
|
return (hasMoveGizmo && moveGizmo.visible) ||
|
|
(hasRotateGizmo && rotateGizmo.visible) ||
|
|
(hasScaleGizmo && scaleGizmo.visible);
|
|
}
|
|
};
|
|
|
|
inline SceneViewportTransformGizmoHandleBuildInputs BuildSceneViewportTransformGizmoHandleBuildInputs(
|
|
bool showingMoveGizmo,
|
|
const SceneViewportMoveGizmo& moveGizmo,
|
|
const SceneViewportMoveGizmoContext& moveGizmoContext,
|
|
bool showingRotateGizmo,
|
|
const SceneViewportRotateGizmo& rotateGizmo,
|
|
const SceneViewportRotateGizmoContext& rotateGizmoContext,
|
|
bool showingScaleGizmo,
|
|
const SceneViewportScaleGizmo& scaleGizmo,
|
|
const SceneViewportScaleGizmoContext& scaleGizmoContext) {
|
|
SceneViewportTransformGizmoHandleBuildInputs inputs = {};
|
|
if (showingMoveGizmo && moveGizmoContext.selectedObject != nullptr) {
|
|
inputs.moveGizmo = &moveGizmo.GetDrawData();
|
|
inputs.moveEntityId = moveGizmoContext.selectedObject->GetID();
|
|
}
|
|
if (showingRotateGizmo && rotateGizmoContext.selectedObject != nullptr) {
|
|
inputs.rotateGizmo = &rotateGizmo.GetDrawData();
|
|
inputs.rotateEntityId = rotateGizmoContext.selectedObject->GetID();
|
|
}
|
|
if (showingScaleGizmo && scaleGizmoContext.selectedObject != nullptr) {
|
|
inputs.scaleGizmo = &scaleGizmo.GetDrawData();
|
|
inputs.scaleEntityId = scaleGizmoContext.selectedObject->GetID();
|
|
}
|
|
|
|
return inputs;
|
|
}
|
|
|
|
inline SceneViewportTransformGizmoOverlayState BuildSceneViewportTransformGizmoOverlayState(
|
|
const SceneViewportTransformGizmoHandleBuildInputs& inputs) {
|
|
SceneViewportTransformGizmoOverlayState state = {};
|
|
if (inputs.moveGizmo != nullptr) {
|
|
state.hasMoveGizmo = true;
|
|
state.moveGizmo = *inputs.moveGizmo;
|
|
state.moveEntityId = inputs.moveEntityId;
|
|
}
|
|
if (inputs.rotateGizmo != nullptr) {
|
|
state.hasRotateGizmo = true;
|
|
state.rotateGizmo = *inputs.rotateGizmo;
|
|
state.rotateEntityId = inputs.rotateEntityId;
|
|
}
|
|
if (inputs.scaleGizmo != nullptr) {
|
|
state.hasScaleGizmo = true;
|
|
state.scaleGizmo = *inputs.scaleGizmo;
|
|
state.scaleEntityId = inputs.scaleEntityId;
|
|
}
|
|
|
|
return state;
|
|
}
|
|
|
|
inline SceneViewportTransformGizmoHandleBuildInputs BuildSceneViewportTransformGizmoHandleBuildInputs(
|
|
const SceneViewportTransformGizmoOverlayState& state) {
|
|
SceneViewportTransformGizmoHandleBuildInputs inputs = {};
|
|
if (state.hasMoveGizmo) {
|
|
inputs.moveGizmo = &state.moveGizmo;
|
|
inputs.moveEntityId = state.moveEntityId;
|
|
}
|
|
if (state.hasRotateGizmo) {
|
|
inputs.rotateGizmo = &state.rotateGizmo;
|
|
inputs.rotateEntityId = state.rotateEntityId;
|
|
}
|
|
if (state.hasScaleGizmo) {
|
|
inputs.scaleGizmo = &state.scaleGizmo;
|
|
inputs.scaleEntityId = state.scaleEntityId;
|
|
}
|
|
|
|
return inputs;
|
|
}
|
|
|
|
namespace Internal {
|
|
|
|
inline constexpr int kSceneViewportHandlePrioritySceneIcon = 100;
|
|
inline constexpr int kSceneViewportHandlePriorityRotateAxis = 311;
|
|
inline constexpr int kSceneViewportHandlePriorityMovePlane = 321;
|
|
inline constexpr int kSceneViewportHandlePriorityMoveAxis = 322;
|
|
inline constexpr int kSceneViewportHandlePriorityScaleAxisLine = 331;
|
|
inline constexpr int kSceneViewportHandlePriorityScaleAxisCap = 332;
|
|
inline constexpr int kSceneViewportHandlePriorityScaleUniform = 333;
|
|
|
|
inline constexpr float kSceneViewportMoveAxisHitThicknessPixels = 10.0f;
|
|
inline constexpr float kSceneViewportRotateAxisHitThicknessPixels = 9.0f;
|
|
inline constexpr float kSceneViewportScaleAxisHitThicknessPixels = 10.0f;
|
|
inline constexpr float kSceneViewportScaleCapHitPaddingPixels = 2.0f;
|
|
|
|
inline constexpr float kSceneViewportMoveArrowLengthPixels = 14.0f;
|
|
inline constexpr float kSceneViewportMoveArrowHalfWidthPixels = 7.0f;
|
|
|
|
inline Math::Color WithAlpha(const Math::Color& color, float alpha) {
|
|
return Math::Color(color.r, color.g, color.b, alpha);
|
|
}
|
|
|
|
inline Math::Color LerpColor(const Math::Color& a, const Math::Color& b, float t) {
|
|
return Math::Color(
|
|
a.r + (b.r - a.r) * t,
|
|
a.g + (b.g - a.g) * t,
|
|
a.b + (b.b - a.b) * t,
|
|
a.a + (b.a - a.a) * t);
|
|
}
|
|
|
|
inline Math::Vector2 NormalizeVector2(
|
|
const Math::Vector2& value,
|
|
const Math::Vector2& fallback = Math::Vector2(1.0f, 0.0f)) {
|
|
const float lengthSq = value.SqrMagnitude();
|
|
if (lengthSq <= Math::EPSILON) {
|
|
return fallback;
|
|
}
|
|
|
|
return value / std::sqrt(lengthSq);
|
|
}
|
|
|
|
inline void AppendScreenTriangle(
|
|
SceneViewportOverlayFrameData& frameData,
|
|
const Math::Vector2& a,
|
|
const Math::Vector2& b,
|
|
const Math::Vector2& c,
|
|
const Math::Color& color,
|
|
SceneViewportOverlayDepthMode depthMode = SceneViewportOverlayDepthMode::AlwaysOnTop) {
|
|
SceneViewportOverlayScreenTrianglePrimitive& triangle = frameData.screenTriangles.emplace_back();
|
|
triangle.vertices[0].screenPosition = a;
|
|
triangle.vertices[0].color = color;
|
|
triangle.vertices[1].screenPosition = b;
|
|
triangle.vertices[1].color = color;
|
|
triangle.vertices[2].screenPosition = c;
|
|
triangle.vertices[2].color = color;
|
|
triangle.depthMode = depthMode;
|
|
}
|
|
|
|
inline void AppendScreenQuad(
|
|
SceneViewportOverlayFrameData& frameData,
|
|
const Math::Vector2& a,
|
|
const Math::Vector2& b,
|
|
const Math::Vector2& c,
|
|
const Math::Vector2& d,
|
|
const Math::Color& color,
|
|
SceneViewportOverlayDepthMode depthMode = SceneViewportOverlayDepthMode::AlwaysOnTop) {
|
|
AppendScreenTriangle(frameData, a, b, c, color, depthMode);
|
|
AppendScreenTriangle(frameData, a, c, d, color, depthMode);
|
|
}
|
|
|
|
inline void AppendScreenRect(
|
|
SceneViewportOverlayFrameData& frameData,
|
|
const Math::Vector2& center,
|
|
const Math::Vector2& halfSize,
|
|
const Math::Color& color,
|
|
SceneViewportOverlayDepthMode depthMode = SceneViewportOverlayDepthMode::AlwaysOnTop) {
|
|
AppendScreenQuad(
|
|
frameData,
|
|
Math::Vector2(center.x - halfSize.x, center.y - halfSize.y),
|
|
Math::Vector2(center.x + halfSize.x, center.y - halfSize.y),
|
|
Math::Vector2(center.x + halfSize.x, center.y + halfSize.y),
|
|
Math::Vector2(center.x - halfSize.x, center.y + halfSize.y),
|
|
color,
|
|
depthMode);
|
|
}
|
|
|
|
inline void AppendScreenSegmentQuad(
|
|
SceneViewportOverlayFrameData& frameData,
|
|
const Math::Vector2& start,
|
|
const Math::Vector2& end,
|
|
float thicknessPixels,
|
|
const Math::Color& color,
|
|
SceneViewportOverlayDepthMode depthMode = SceneViewportOverlayDepthMode::AlwaysOnTop) {
|
|
const Math::Vector2 delta = end - start;
|
|
if (delta.SqrMagnitude() <= Math::EPSILON || thicknessPixels <= Math::EPSILON) {
|
|
return;
|
|
}
|
|
|
|
const Math::Vector2 direction = NormalizeVector2(delta);
|
|
const Math::Vector2 normal(-direction.y, direction.x);
|
|
const Math::Vector2 offset = normal * (thicknessPixels * 0.5f);
|
|
AppendScreenQuad(
|
|
frameData,
|
|
start + offset,
|
|
start - offset,
|
|
end - offset,
|
|
end + offset,
|
|
color,
|
|
depthMode);
|
|
}
|
|
|
|
inline void AppendScreenQuadOutline(
|
|
SceneViewportOverlayFrameData& frameData,
|
|
const std::array<Math::Vector2, 4>& corners,
|
|
float thicknessPixels,
|
|
const Math::Color& color) {
|
|
for (size_t index = 0; index < corners.size(); ++index) {
|
|
AppendScreenSegmentQuad(
|
|
frameData,
|
|
corners[index],
|
|
corners[(index + 1u) % corners.size()],
|
|
thicknessPixels,
|
|
color);
|
|
}
|
|
}
|
|
|
|
inline void AppendScreenRectOutline(
|
|
SceneViewportOverlayFrameData& frameData,
|
|
const Math::Vector2& center,
|
|
const Math::Vector2& halfSize,
|
|
float thicknessPixels,
|
|
const Math::Color& color) {
|
|
const std::array<Math::Vector2, 4> corners = {{
|
|
Math::Vector2(center.x - halfSize.x, center.y - halfSize.y),
|
|
Math::Vector2(center.x + halfSize.x, center.y - halfSize.y),
|
|
Math::Vector2(center.x + halfSize.x, center.y + halfSize.y),
|
|
Math::Vector2(center.x - halfSize.x, center.y + halfSize.y)
|
|
}};
|
|
AppendScreenQuadOutline(frameData, corners, thicknessPixels, color);
|
|
}
|
|
|
|
inline void AppendMoveGizmoHandleRecords(
|
|
SceneViewportOverlayFrameData& frameData,
|
|
const SceneViewportMoveGizmoDrawData& drawData,
|
|
uint64_t entityId) {
|
|
if (!drawData.visible || entityId == 0) {
|
|
return;
|
|
}
|
|
|
|
for (const SceneViewportMoveGizmoHandleDrawData& handle : drawData.handles) {
|
|
if (!handle.visible || handle.axis == SceneViewportGizmoAxis::None) {
|
|
continue;
|
|
}
|
|
|
|
SceneViewportOverlayHandleRecord& record = frameData.handleRecords.emplace_back();
|
|
record.kind = SceneViewportOverlayHandleKind::MoveAxis;
|
|
record.handleId = static_cast<uint64_t>(handle.axis);
|
|
record.entityId = entityId;
|
|
record.shape = SceneViewportOverlayHandleShape::ScreenSegment;
|
|
record.priority = kSceneViewportHandlePriorityMoveAxis;
|
|
record.screenStart = handle.start;
|
|
record.screenEnd = handle.end;
|
|
record.hitThicknessPixels = kSceneViewportMoveAxisHitThicknessPixels;
|
|
}
|
|
|
|
for (const SceneViewportMoveGizmoPlaneDrawData& plane : drawData.planes) {
|
|
if (!plane.visible || plane.plane == SceneViewportGizmoPlane::None) {
|
|
continue;
|
|
}
|
|
|
|
SceneViewportOverlayHandleRecord& record = frameData.handleRecords.emplace_back();
|
|
record.kind = SceneViewportOverlayHandleKind::MovePlane;
|
|
record.handleId = static_cast<uint64_t>(plane.plane);
|
|
record.entityId = entityId;
|
|
record.shape = SceneViewportOverlayHandleShape::ScreenQuad;
|
|
record.priority = kSceneViewportHandlePriorityMovePlane;
|
|
record.screenQuad = plane.corners;
|
|
}
|
|
}
|
|
|
|
inline void AppendRotateGizmoHandleRecords(
|
|
SceneViewportOverlayFrameData& frameData,
|
|
const SceneViewportRotateGizmoDrawData& drawData,
|
|
uint64_t entityId) {
|
|
if (!drawData.visible || entityId == 0) {
|
|
return;
|
|
}
|
|
|
|
for (const SceneViewportRotateGizmoHandleDrawData& handle : drawData.handles) {
|
|
if (!handle.visible || handle.axis == SceneViewportRotateGizmoAxis::None) {
|
|
continue;
|
|
}
|
|
|
|
for (const SceneViewportRotateGizmoSegmentDrawData& segment : handle.segments) {
|
|
if (!segment.visible ||
|
|
(handle.axis != SceneViewportRotateGizmoAxis::View && !segment.frontFacing)) {
|
|
continue;
|
|
}
|
|
|
|
SceneViewportOverlayHandleRecord& record = frameData.handleRecords.emplace_back();
|
|
record.kind = SceneViewportOverlayHandleKind::RotateAxis;
|
|
record.handleId = static_cast<uint64_t>(handle.axis);
|
|
record.entityId = entityId;
|
|
record.shape = SceneViewportOverlayHandleShape::ScreenSegment;
|
|
record.priority = kSceneViewportHandlePriorityRotateAxis;
|
|
record.screenStart = segment.start;
|
|
record.screenEnd = segment.end;
|
|
record.hitThicknessPixels = kSceneViewportRotateAxisHitThicknessPixels;
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void AppendScaleGizmoHandleRecords(
|
|
SceneViewportOverlayFrameData& frameData,
|
|
const SceneViewportScaleGizmoDrawData& drawData,
|
|
uint64_t entityId) {
|
|
if (!drawData.visible || entityId == 0) {
|
|
return;
|
|
}
|
|
|
|
if (drawData.centerHandle.visible) {
|
|
SceneViewportOverlayHandleRecord& uniformRecord = frameData.handleRecords.emplace_back();
|
|
uniformRecord.kind = SceneViewportOverlayHandleKind::ScaleUniform;
|
|
uniformRecord.handleId = static_cast<uint64_t>(SceneViewportScaleGizmoHandle::Uniform);
|
|
uniformRecord.entityId = entityId;
|
|
uniformRecord.shape = SceneViewportOverlayHandleShape::ScreenRect;
|
|
uniformRecord.priority = kSceneViewportHandlePriorityScaleUniform;
|
|
uniformRecord.screenCenter = drawData.centerHandle.center;
|
|
uniformRecord.screenHalfSize = Math::Vector2(
|
|
drawData.centerHandle.halfSize + kSceneViewportScaleCapHitPaddingPixels,
|
|
drawData.centerHandle.halfSize + kSceneViewportScaleCapHitPaddingPixels);
|
|
}
|
|
|
|
for (const SceneViewportScaleGizmoAxisHandleDrawData& handle : drawData.axisHandles) {
|
|
if (!handle.visible || handle.handle == SceneViewportScaleGizmoHandle::None) {
|
|
continue;
|
|
}
|
|
|
|
SceneViewportOverlayHandleRecord& capRecord = frameData.handleRecords.emplace_back();
|
|
capRecord.kind = SceneViewportOverlayHandleKind::ScaleAxis;
|
|
capRecord.handleId = static_cast<uint64_t>(handle.handle);
|
|
capRecord.entityId = entityId;
|
|
capRecord.shape = SceneViewportOverlayHandleShape::ScreenRect;
|
|
capRecord.priority = kSceneViewportHandlePriorityScaleAxisCap;
|
|
capRecord.screenCenter = handle.capCenter;
|
|
capRecord.screenHalfSize = Math::Vector2(
|
|
handle.capHalfSize + kSceneViewportScaleCapHitPaddingPixels,
|
|
handle.capHalfSize + kSceneViewportScaleCapHitPaddingPixels);
|
|
|
|
SceneViewportOverlayHandleRecord& lineRecord = frameData.handleRecords.emplace_back();
|
|
lineRecord.kind = SceneViewportOverlayHandleKind::ScaleAxis;
|
|
lineRecord.handleId = static_cast<uint64_t>(handle.handle);
|
|
lineRecord.entityId = entityId;
|
|
lineRecord.shape = SceneViewportOverlayHandleShape::ScreenSegment;
|
|
lineRecord.priority = kSceneViewportHandlePriorityScaleAxisLine;
|
|
lineRecord.screenStart = handle.start;
|
|
lineRecord.screenEnd = handle.end;
|
|
lineRecord.hitThicknessPixels = kSceneViewportScaleAxisHitThicknessPixels;
|
|
}
|
|
}
|
|
|
|
inline void AppendMoveGizmoScreenTriangles(
|
|
SceneViewportOverlayFrameData& frameData,
|
|
const SceneViewportMoveGizmoDrawData& drawData) {
|
|
if (!drawData.visible) {
|
|
return;
|
|
}
|
|
|
|
for (const SceneViewportMoveGizmoPlaneDrawData& plane : drawData.planes) {
|
|
if (!plane.visible) {
|
|
continue;
|
|
}
|
|
|
|
AppendScreenQuad(
|
|
frameData,
|
|
plane.corners[0],
|
|
plane.corners[1],
|
|
plane.corners[2],
|
|
plane.corners[3],
|
|
plane.fillColor);
|
|
AppendScreenQuadOutline(
|
|
frameData,
|
|
plane.corners,
|
|
plane.active ? 2.6f : (plane.hovered ? 2.0f : 1.4f),
|
|
plane.outlineColor);
|
|
}
|
|
|
|
for (const SceneViewportMoveGizmoHandleDrawData& handle : drawData.handles) {
|
|
if (!handle.visible) {
|
|
continue;
|
|
}
|
|
|
|
const float thickness = handle.active ? 4.0f : (handle.hovered ? 3.0f : 2.0f);
|
|
const Math::Vector2 direction = NormalizeVector2(handle.end - handle.start);
|
|
const float arrowLength =
|
|
(std::min)(kSceneViewportMoveArrowLengthPixels, (handle.end - handle.start).Magnitude());
|
|
const Math::Vector2 normal(-direction.y, direction.x);
|
|
const Math::Vector2 arrowBase = handle.end - direction * arrowLength;
|
|
const Math::Vector2 arrowLeft = arrowBase + normal * kSceneViewportMoveArrowHalfWidthPixels;
|
|
const Math::Vector2 arrowRight = arrowBase - normal * kSceneViewportMoveArrowHalfWidthPixels;
|
|
|
|
AppendScreenSegmentQuad(frameData, handle.start, arrowBase, thickness, handle.color);
|
|
AppendScreenTriangle(frameData, handle.end, arrowLeft, arrowRight, handle.color);
|
|
}
|
|
}
|
|
|
|
inline void AppendRotateGizmoHandleScreenTriangles(
|
|
SceneViewportOverlayFrameData& frameData,
|
|
const SceneViewportRotateGizmoHandleDrawData& handle,
|
|
bool frontPass) {
|
|
if (!handle.visible) {
|
|
return;
|
|
}
|
|
|
|
const bool isViewHandle = handle.axis == SceneViewportRotateGizmoAxis::View;
|
|
if (isViewHandle && !frontPass) {
|
|
return;
|
|
}
|
|
|
|
const float thickness = handle.active ? 3.6f : (handle.hovered ? 3.0f : 2.1f);
|
|
for (const SceneViewportRotateGizmoSegmentDrawData& segment : handle.segments) {
|
|
if (!segment.visible || (!isViewHandle && segment.frontFacing != frontPass)) {
|
|
continue;
|
|
}
|
|
|
|
Math::Color drawColor = handle.color;
|
|
if (!isViewHandle && !frontPass) {
|
|
drawColor = LerpColor(handle.color, Math::Color(0.72f, 0.72f, 0.72f, 1.0f), 0.78f);
|
|
drawColor = WithAlpha(drawColor, handle.active ? 0.55f : 0.38f);
|
|
} else if (isViewHandle) {
|
|
drawColor = WithAlpha(drawColor, handle.active ? 0.95f : (handle.hovered ? 0.88f : 0.78f));
|
|
}
|
|
|
|
AppendScreenSegmentQuad(frameData, segment.start, segment.end, thickness, drawColor);
|
|
}
|
|
}
|
|
|
|
inline void AppendRotateGizmoAngleFillScreenTriangles(
|
|
SceneViewportOverlayFrameData& frameData,
|
|
const SceneViewportRotateGizmoAngleFillDrawData& angleFill) {
|
|
if (!angleFill.visible || angleFill.arcPointCount < 2u) {
|
|
return;
|
|
}
|
|
|
|
for (size_t index = 0; index + 1u < angleFill.arcPointCount; ++index) {
|
|
AppendScreenTriangle(
|
|
frameData,
|
|
angleFill.pivot,
|
|
angleFill.arcPoints[index],
|
|
angleFill.arcPoints[index + 1u],
|
|
angleFill.fillColor);
|
|
}
|
|
|
|
for (size_t index = 0; index + 1u < angleFill.arcPointCount; ++index) {
|
|
AppendScreenSegmentQuad(
|
|
frameData,
|
|
angleFill.arcPoints[index],
|
|
angleFill.arcPoints[index + 1u],
|
|
2.0f,
|
|
angleFill.outlineColor);
|
|
}
|
|
|
|
AppendScreenSegmentQuad(
|
|
frameData,
|
|
angleFill.pivot,
|
|
angleFill.arcPoints[0],
|
|
1.6f,
|
|
angleFill.outlineColor);
|
|
AppendScreenSegmentQuad(
|
|
frameData,
|
|
angleFill.pivot,
|
|
angleFill.arcPoints[angleFill.arcPointCount - 1u],
|
|
1.6f,
|
|
angleFill.outlineColor);
|
|
}
|
|
|
|
inline void AppendRotateGizmoScreenTriangles(
|
|
SceneViewportOverlayFrameData& frameData,
|
|
const SceneViewportRotateGizmoDrawData& drawData) {
|
|
if (!drawData.visible) {
|
|
return;
|
|
}
|
|
|
|
for (const SceneViewportRotateGizmoHandleDrawData& handle : drawData.handles) {
|
|
if (handle.axis == SceneViewportRotateGizmoAxis::View) {
|
|
AppendRotateGizmoHandleScreenTriangles(frameData, handle, true);
|
|
}
|
|
}
|
|
|
|
for (const SceneViewportRotateGizmoHandleDrawData& handle : drawData.handles) {
|
|
if (handle.axis != SceneViewportRotateGizmoAxis::View) {
|
|
AppendRotateGizmoHandleScreenTriangles(frameData, handle, false);
|
|
}
|
|
}
|
|
|
|
AppendRotateGizmoAngleFillScreenTriangles(frameData, drawData.angleFill);
|
|
|
|
for (const SceneViewportRotateGizmoHandleDrawData& handle : drawData.handles) {
|
|
if (handle.axis != SceneViewportRotateGizmoAxis::View) {
|
|
AppendRotateGizmoHandleScreenTriangles(frameData, handle, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void AppendScaleGizmoScreenTriangles(
|
|
SceneViewportOverlayFrameData& frameData,
|
|
const SceneViewportScaleGizmoDrawData& drawData) {
|
|
if (!drawData.visible) {
|
|
return;
|
|
}
|
|
|
|
constexpr Math::Color kScaleCapOutlineColor(24.0f / 255.0f, 24.0f / 255.0f, 24.0f / 255.0f, 220.0f / 255.0f);
|
|
|
|
for (const SceneViewportScaleGizmoAxisHandleDrawData& handle : drawData.axisHandles) {
|
|
if (!handle.visible) {
|
|
continue;
|
|
}
|
|
|
|
const float thickness = handle.active ? 4.0f : (handle.hovered ? 3.0f : 2.2f);
|
|
const Math::Vector2 direction = NormalizeVector2(handle.capCenter - handle.start);
|
|
const Math::Vector2 lineEnd = handle.capCenter - direction * handle.capHalfSize;
|
|
const Math::Vector2 capHalfSize(handle.capHalfSize, handle.capHalfSize);
|
|
AppendScreenSegmentQuad(frameData, handle.start, lineEnd, thickness, handle.color);
|
|
AppendScreenRect(frameData, handle.capCenter, capHalfSize, handle.color);
|
|
AppendScreenRectOutline(
|
|
frameData,
|
|
handle.capCenter,
|
|
capHalfSize,
|
|
handle.active ? 2.0f : 1.0f,
|
|
kScaleCapOutlineColor);
|
|
}
|
|
|
|
if (drawData.centerHandle.visible) {
|
|
const Math::Vector2 halfSize(drawData.centerHandle.halfSize, drawData.centerHandle.halfSize);
|
|
AppendScreenRect(
|
|
frameData,
|
|
drawData.centerHandle.center,
|
|
halfSize,
|
|
drawData.centerHandle.fillColor);
|
|
AppendScreenRectOutline(
|
|
frameData,
|
|
drawData.centerHandle.center,
|
|
halfSize,
|
|
drawData.centerHandle.active ? 2.0f : 1.0f,
|
|
drawData.centerHandle.outlineColor);
|
|
}
|
|
}
|
|
|
|
} // namespace Internal
|
|
|
|
inline void AppendTransformGizmoHandleRecords(
|
|
SceneViewportOverlayFrameData& frameData,
|
|
const SceneViewportTransformGizmoHandleBuildInputs& inputs) {
|
|
if (inputs.moveGizmo != nullptr) {
|
|
Internal::AppendMoveGizmoHandleRecords(frameData, *inputs.moveGizmo, inputs.moveEntityId);
|
|
}
|
|
|
|
if (inputs.rotateGizmo != nullptr) {
|
|
Internal::AppendRotateGizmoHandleRecords(frameData, *inputs.rotateGizmo, inputs.rotateEntityId);
|
|
}
|
|
|
|
if (inputs.scaleGizmo != nullptr) {
|
|
Internal::AppendScaleGizmoHandleRecords(frameData, *inputs.scaleGizmo, inputs.scaleEntityId);
|
|
}
|
|
}
|
|
|
|
inline void AppendTransformGizmoScreenTriangles(
|
|
SceneViewportOverlayFrameData& frameData,
|
|
const SceneViewportTransformGizmoHandleBuildInputs& inputs) {
|
|
if (inputs.moveGizmo != nullptr) {
|
|
Internal::AppendMoveGizmoScreenTriangles(frameData, *inputs.moveGizmo);
|
|
}
|
|
|
|
if (inputs.rotateGizmo != nullptr) {
|
|
Internal::AppendRotateGizmoScreenTriangles(frameData, *inputs.rotateGizmo);
|
|
}
|
|
|
|
if (inputs.scaleGizmo != nullptr) {
|
|
Internal::AppendScaleGizmoScreenTriangles(frameData, *inputs.scaleGizmo);
|
|
}
|
|
}
|
|
|
|
inline SceneViewportOverlayFrameData BuildSceneViewportTransformGizmoOverlayFrameData(
|
|
const SceneViewportOverlayData& overlay,
|
|
const SceneViewportTransformGizmoHandleBuildInputs& inputs) {
|
|
SceneViewportOverlayFrameData frameData = {};
|
|
frameData.overlay = overlay;
|
|
AppendTransformGizmoScreenTriangles(frameData, inputs);
|
|
AppendTransformGizmoHandleRecords(frameData, inputs);
|
|
return frameData;
|
|
}
|
|
|
|
} // namespace Editor
|
|
} // namespace XCEngine
|