222 lines
7.5 KiB
C++
222 lines
7.5 KiB
C++
#include "Features/Scene/SceneViewportToolOverlay.h"
|
|
|
|
#include <Rendering/Native/NativeRenderer.h>
|
|
|
|
#include <algorithm>
|
|
#include <array>
|
|
|
|
namespace XCEngine::UI::Editor::App {
|
|
|
|
namespace {
|
|
|
|
using ::XCEngine::UI::UIColor;
|
|
using ::XCEngine::UI::UIDrawList;
|
|
using ::XCEngine::UI::UIPoint;
|
|
using ::XCEngine::UI::UIRect;
|
|
|
|
constexpr float kButtonExtent = 30.0f;
|
|
constexpr float kButtonSpacing = 6.0f;
|
|
constexpr float kPanelPadding = 6.0f;
|
|
constexpr float kViewportInset = 10.0f;
|
|
constexpr float kIconInset = 4.0f;
|
|
constexpr float kPanelCornerRounding = 7.0f;
|
|
constexpr float kButtonCornerRounding = 5.0f;
|
|
constexpr float kFallbackFontSize = 11.0f;
|
|
|
|
struct ToolTexturePath {
|
|
SceneToolMode mode = SceneToolMode::View;
|
|
const char* label = "";
|
|
const char* inactiveFile = "";
|
|
const char* activeFile = "";
|
|
};
|
|
|
|
constexpr std::array<ToolTexturePath, 4> kToolTexturePaths = {{
|
|
{ SceneToolMode::View, "View", "view_move_tool.png", "view_move_tool_on.png" },
|
|
{ SceneToolMode::Translate, "Move", "move_tool.png", "move_tool_on.png" },
|
|
{ SceneToolMode::Rotate, "Rotate", "rotate_tool.png", "rotate_tool_on.png" },
|
|
{ SceneToolMode::Scale, "Scale", "scale_tool.png", "scale_tool_on.png" }
|
|
}};
|
|
|
|
bool ContainsPoint(const UIRect& rect, const UIPoint& point) {
|
|
return point.x >= rect.x &&
|
|
point.x <= rect.x + rect.width &&
|
|
point.y >= rect.y &&
|
|
point.y <= rect.y + rect.height;
|
|
}
|
|
|
|
UIRect BuildButtonRect(const UIRect& panelRect, std::size_t index) {
|
|
return UIRect(
|
|
panelRect.x + kPanelPadding,
|
|
panelRect.y + kPanelPadding + static_cast<float>(index) * (kButtonExtent + kButtonSpacing),
|
|
kButtonExtent,
|
|
kButtonExtent);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
bool SceneViewportToolOverlay::Initialize(
|
|
const std::filesystem::path& repoRoot,
|
|
Host::NativeRenderer& renderer) {
|
|
Shutdown(renderer);
|
|
|
|
const std::filesystem::path iconRoot =
|
|
(repoRoot / "editor" / "resources" / "Icons").lexically_normal();
|
|
bool loadedAnyTexture = false;
|
|
for (std::size_t index = 0; index < kToolTexturePaths.size(); ++index) {
|
|
const ToolTexturePath& path = kToolTexturePaths[index];
|
|
ToolTextureSet& textureSet = m_toolTextures[index];
|
|
textureSet = {};
|
|
textureSet.mode = path.mode;
|
|
textureSet.label = path.label;
|
|
|
|
std::string error = {};
|
|
loadedAnyTexture =
|
|
renderer.LoadTextureFromFile(
|
|
iconRoot / path.inactiveFile,
|
|
textureSet.inactiveTexture,
|
|
error) || loadedAnyTexture;
|
|
error.clear();
|
|
loadedAnyTexture =
|
|
renderer.LoadTextureFromFile(
|
|
iconRoot / path.activeFile,
|
|
textureSet.activeTexture,
|
|
error) || loadedAnyTexture;
|
|
}
|
|
|
|
return loadedAnyTexture;
|
|
}
|
|
|
|
void SceneViewportToolOverlay::Shutdown(Host::NativeRenderer& renderer) {
|
|
for (ToolTextureSet& textureSet : m_toolTextures) {
|
|
renderer.ReleaseTexture(textureSet.inactiveTexture);
|
|
renderer.ReleaseTexture(textureSet.activeTexture);
|
|
textureSet = {};
|
|
}
|
|
|
|
ResetFrame();
|
|
}
|
|
|
|
void SceneViewportToolOverlay::ResetFrame() {
|
|
m_frame = {};
|
|
}
|
|
|
|
void SceneViewportToolOverlay::BuildFrame(
|
|
const UIRect& viewportRect,
|
|
SceneToolMode activeMode,
|
|
std::size_t hoveredIndex,
|
|
std::size_t pressedIndex) {
|
|
m_frame = {};
|
|
if (viewportRect.width <= 1.0f || viewportRect.height <= 1.0f) {
|
|
return;
|
|
}
|
|
|
|
m_frame.visible = true;
|
|
m_frame.clipRect = viewportRect;
|
|
m_frame.panelRect = UIRect(
|
|
viewportRect.x + kViewportInset,
|
|
viewportRect.y + kViewportInset,
|
|
kPanelPadding * 2.0f + kButtonExtent,
|
|
kPanelPadding * 2.0f +
|
|
static_cast<float>(m_frame.buttons.size()) * kButtonExtent +
|
|
static_cast<float>(m_frame.buttons.size() - 1u) * kButtonSpacing);
|
|
|
|
for (std::size_t index = 0; index < m_frame.buttons.size(); ++index) {
|
|
const ToolTextureSet& textureSet = m_toolTextures[index];
|
|
SceneViewportToolOverlayButtonFrame& button = m_frame.buttons[index];
|
|
button = {};
|
|
button.mode = textureSet.mode;
|
|
button.label = textureSet.label;
|
|
button.rect = BuildButtonRect(m_frame.panelRect, index);
|
|
button.active = textureSet.mode == activeMode;
|
|
button.hovered = index == hoveredIndex;
|
|
button.pressed = index == pressedIndex;
|
|
button.texture = button.active
|
|
? textureSet.activeTexture
|
|
: textureSet.inactiveTexture;
|
|
}
|
|
}
|
|
|
|
std::size_t SceneViewportToolOverlay::HitTest(const UIPoint& point) const {
|
|
if (!m_frame.visible || !Contains(point)) {
|
|
return kSceneViewportToolOverlayInvalidIndex;
|
|
}
|
|
|
|
for (std::size_t index = 0; index < m_frame.buttons.size(); ++index) {
|
|
if (ContainsPoint(m_frame.buttons[index].rect, point)) {
|
|
return index;
|
|
}
|
|
}
|
|
|
|
return kSceneViewportToolOverlayInvalidIndex;
|
|
}
|
|
|
|
bool SceneViewportToolOverlay::Contains(const UIPoint& point) const {
|
|
return m_frame.visible && ContainsPoint(m_frame.panelRect, point);
|
|
}
|
|
|
|
const SceneViewportToolOverlayFrame& SceneViewportToolOverlay::GetFrame() const {
|
|
return m_frame;
|
|
}
|
|
|
|
void AppendSceneViewportToolOverlay(
|
|
UIDrawList& drawList,
|
|
const SceneViewportToolOverlayFrame& frame) {
|
|
if (!frame.visible) {
|
|
return;
|
|
}
|
|
|
|
constexpr UIColor kPanelFill(24.0f / 255.0f, 26.0f / 255.0f, 29.0f / 255.0f, 220.0f / 255.0f);
|
|
constexpr UIColor kPanelOutline(1.0f, 1.0f, 1.0f, 28.0f / 255.0f);
|
|
constexpr UIColor kButtonIdle(44.0f / 255.0f, 47.0f / 255.0f, 54.0f / 255.0f, 230.0f / 255.0f);
|
|
constexpr UIColor kButtonHover(68.0f / 255.0f, 74.0f / 255.0f, 84.0f / 255.0f, 240.0f / 255.0f);
|
|
constexpr UIColor kButtonPressed(86.0f / 255.0f, 96.0f / 255.0f, 109.0f / 255.0f, 245.0f / 255.0f);
|
|
constexpr UIColor kButtonActive(78.0f / 255.0f, 102.0f / 255.0f, 126.0f / 255.0f, 245.0f / 255.0f);
|
|
constexpr UIColor kButtonOutline(1.0f, 1.0f, 1.0f, 24.0f / 255.0f);
|
|
constexpr UIColor kButtonActiveOutline(1.0f, 1.0f, 1.0f, 48.0f / 255.0f);
|
|
constexpr UIColor kFallbackText(230.0f / 255.0f, 230.0f / 255.0f, 230.0f / 255.0f, 1.0f);
|
|
|
|
drawList.PushClipRect(frame.clipRect);
|
|
drawList.AddFilledRect(frame.panelRect, kPanelFill, kPanelCornerRounding);
|
|
drawList.AddRectOutline(frame.panelRect, kPanelOutline, 1.0f, kPanelCornerRounding);
|
|
|
|
for (const SceneViewportToolOverlayButtonFrame& button : frame.buttons) {
|
|
UIColor fill = kButtonIdle;
|
|
if (button.active) {
|
|
fill = kButtonActive;
|
|
}
|
|
if (button.hovered) {
|
|
fill = button.active ? kButtonActive : kButtonHover;
|
|
}
|
|
if (button.pressed) {
|
|
fill = kButtonPressed;
|
|
}
|
|
|
|
drawList.AddFilledRect(button.rect, fill, kButtonCornerRounding);
|
|
drawList.AddRectOutline(
|
|
button.rect,
|
|
button.active ? kButtonActiveOutline : kButtonOutline,
|
|
1.0f,
|
|
kButtonCornerRounding);
|
|
|
|
if (button.texture.IsValid()) {
|
|
const UIRect iconRect(
|
|
button.rect.x + kIconInset,
|
|
button.rect.y + kIconInset,
|
|
button.rect.width - kIconInset * 2.0f,
|
|
button.rect.height - kIconInset * 2.0f);
|
|
drawList.AddImage(iconRect, button.texture);
|
|
continue;
|
|
}
|
|
|
|
drawList.AddText(
|
|
UIPoint(button.rect.x + 7.0f, button.rect.y + 9.0f),
|
|
button.label,
|
|
kFallbackText,
|
|
kFallbackFontSize);
|
|
}
|
|
|
|
drawList.PopClipRect();
|
|
}
|
|
|
|
} // namespace XCEngine::UI::Editor::App
|