Files
parkan-playground/NResUI/ImGuiUI/ViewportPanel.cs
T
2026-06-05 20:47:57 +03:00

187 lines
5.3 KiB
C#

using System.Numerics;
using ImGuiNET;
using NResUI.Abstractions;
using NResUI.Rendering.Viewport;
using NResUI.Rendering.Viewport.Meshes;
using Silk.NET.OpenGL;
using Silk.NET.Windowing;
namespace NResUI.ImGuiUI;
public sealed class ViewportPanel : IImGuiPanel
{
private readonly ViewportRenderer _renderer;
private readonly ViewportScene _scene;
private readonly ViewportCamera _camera = new();
private readonly ViewportInputController _inputController = new();
public ViewportPanel(GL gl, IWindow window)
{
var cubeMesh = PrimitiveMeshes.CreateCube(gl);
var gridMesh = PrimitiveMeshes.CreateWorldGrid(gl);
_scene = ViewportScene.CreateDefaultCubeScene(cubeMesh, gridMesh);
_renderer = new ViewportRenderer(gl, window);
}
public void OnImGuiRender()
{
if (!ImGui.Begin("Viewport"))
{
ImGui.End();
return;
}
DrawSelectionStatus();
DrawViewportToolbar();
DrawDebugControls();
var imageSize = ImGui.GetContentRegionAvail();
if (imageSize.X < 32 || imageSize.Y < 32)
{
ImGui.TextDisabled("Viewport is too small.");
ImGui.End();
return;
}
var textureId = _renderer.Render(
width: Math.Max(1, (int)imageSize.X),
height: Math.Max(1, (int)imageSize.Y),
scene: _scene,
camera: _camera);
ImGui.Image(
(IntPtr)textureId,
imageSize,
new Vector2(0, 1),
new Vector2(1, 0));
var viewportHovered = ImGui.IsItemHovered();
var viewportFocused = ImGui.IsWindowFocused(ImGuiFocusedFlags.RootAndChildWindows);
var imageMin = ImGui.GetItemRectMin();
DrawViewportHelpOverlay();
_inputController.Handle(
_scene,
_camera,
viewportHovered,
viewportFocused,
imageMin,
imageSize);
ImGui.End();
}
private void DrawSelectionStatus()
{
var selectedPiece = _scene.SelectedPiece;
if (selectedPiece != null)
ImGui.Text($"Selected: {selectedPiece.Name}");
else
ImGui.TextDisabled("Selected: none");
}
private void DrawViewportToolbar()
{
if (ImGui.Button("Reset view"))
_camera.Reset();
ImGui.SameLine();
if (ImGui.Button("Frame selected"))
{
if (_scene.TryGetSelectedPieceWorldBounds(out var selectedBounds))
_camera.FrameBounds(selectedBounds.Min, selectedBounds.Max);
}
ImGui.SameLine();
if (ImGui.Button("Frame all"))
{
if (_scene.TryGetSceneWorldBounds(out var sceneBounds))
_camera.FrameBounds(sceneBounds.Min, sceneBounds.Max);
else
_camera.Reset();
}
}
private void DrawDebugControls()
{
var grid = _scene.Grid;
if (grid != null)
{
var isVisible = grid.IsVisible;
if (ImGui.Checkbox("Grid", ref isVisible))
grid.IsVisible = isVisible;
}
ImGui.SameLine();
var showOriginAxes = _scene.Debug.ShowOriginAxes;
if (ImGui.Checkbox("Origin axes", ref showOriginAxes))
_scene.Debug.ShowOriginAxes = showOriginAxes;
ImGui.SameLine();
var showPieceOrigins = _scene.Debug.ShowPieceOrigins;
if (ImGui.Checkbox("Piece axes", ref showPieceOrigins))
_scene.Debug.ShowPieceOrigins = showPieceOrigins;
ImGui.SameLine();
var showSelectedBounds = _scene.Debug.ShowSelectedBounds;
if (ImGui.Checkbox("Selected bounds", ref showSelectedBounds))
_scene.Debug.ShowSelectedBounds = showSelectedBounds;
ImGui.SameLine();
var showSceneBounds = _scene.Debug.ShowSceneBounds;
if (ImGui.Checkbox("Scene bounds", ref showSceneBounds))
_scene.Debug.ShowSceneBounds = showSceneBounds;
ImGui.SameLine();
var wireframe = _scene.Debug.Wireframe;
if (ImGui.Checkbox("Wireframe", ref wireframe))
_scene.Debug.Wireframe = wireframe;
}
private static void DrawViewportHelpOverlay()
{
var drawList = ImGui.GetWindowDrawList();
var imageMin = ImGui.GetItemRectMin();
var imageMax = ImGui.GetItemRectMax();
const string helpText =
"LMB click: select / deselect\n" +
"MMB drag: rotate\n" +
"RMB drag or Alt+MMB: pan\n" +
"Mouse wheel: zoom\n" +
"F: frame selected Home: frame all";
var textSize = ImGui.CalcTextSize(helpText);
var padding = new Vector2(8.0f, 6.0f);
var boxMin = new Vector2(
imageMin.X + 8.0f,
imageMax.Y - textSize.Y - padding.Y * 2.0f - 8.0f);
var boxMax = new Vector2(
boxMin.X + textSize.X + padding.X * 2.0f,
boxMin.Y + textSize.Y + padding.Y * 2.0f);
drawList.AddRectFilled(
boxMin,
boxMax,
ImGui.GetColorU32(new Vector4(0.0f, 0.0f, 0.0f, 0.45f)),
4.0f);
drawList.AddText(
boxMin + padding,
ImGui.GetColorU32(new Vector4(1.0f, 1.0f, 1.0f, 0.9f)),
helpText);
}
}