using Avalonia; using Avalonia.Controls.ApplicationLifetimes; using CommunityToolkit.Mvvm.Input; using Controls.ViewModels; using NamedPipes; using NrxDebugVisualizer.Models; using NrxDebugVisualizer.Scenes; using Num.Roto.Visualization.Math.Geometry; using Num.Roto.Visualization.Math.Utilities; using Num.Roto.Visualization.Types; using Num.Roto.Visualization.VulkanLib.SceneInteraction; using System; using System.Collections.Generic; using System.Linq; using System.Numerics; using System.Threading; using KontractFrame = System.ValueTuple; namespace NrxDebugVisualizer.ViewModels; internal sealed partial class MainWindowViewModel : ViewModelBase { public ProportionalDockControlViewModel ProportionalDockControlViewModel { get; } = new(); public VulkanSceneControlViewModel VulkanSceneControlViewModel => ProportionalDockControlViewModel.VulkanSceneControlViewModel; public SceneTreeViewViewModel SceneTreeViewViewModel => ProportionalDockControlViewModel.SceneTreeViewViewModel?? throw new InvalidOperationException("SceneTreeViewViewModel is not available"); public SceneInteraction SceneInteraction => ProportionalDockControlViewModel.SceneInteraction; public DebugVisualizerScene DebugVisualizerScene => ProportionalDockControlViewModel.Scene as DebugVisualizerScene ?? throw new InvalidOperationException("Scene is not a DebugVisualizerScene"); private PipeServer PipeServer {get;init;} public MainWindowViewModel() { ProportionalDockControlViewModel.Scene = new DebugVisualizerScene(); ProportionalDockControlViewModel.Scene.SelectedCamera.DefaultFrame = CameraView.Frame(ViewPosition); PipeServer = new PipeServer(nameof(NrxDebugVisualizer), UpdateScene, cancellationToken: CancellationToken.None); } #region Commands [RelayCommand] public static void ShowLogViewer() { Log.LogViewerEnabled = true; } [RelayCommand] private static void Exit(object? parameter) { if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktopApp) { desktopApp.Shutdown(); } } [RelayCommand] internal void ResetCamera() { ProportionalDockControlViewModel.VulkanSceneControlViewModel.ResetCamera(CameraView.Frame(ViewPosition)); } [RelayCommand] internal void FitToWindow() { ProportionalDockControlViewModel.Scene?.FitToWindow(0.95f); ProportionalDockControlViewModel.VulkanSceneControlViewModel.SceneInteraction.Update(); } #endregion #region Camera View public static IEnumerable ViewPositions => Enum.GetValues(); private CameraView.Position _viewPosition = CameraView.Position.Custom1; public CameraView.Position ViewPosition { get => _viewPosition; set { if (_viewPosition == value) return; _viewPosition = value; OnPropertyChanged(); if (_viewPosition == CameraView.Position.User) return; ProportionalDockControlViewModel.Scene?.SelectedCamera.DefaultFrame = CameraView.Frame(_viewPosition); FitToWindow(); } } #endregion #region Pipe Server private void UpdateScene(VisualizerModel visualizerModel) { SetPoint(visualizerModel.Point); SetPointList(visualizerModel.PointArray); SetFrame(visualizerModel.Frame); SetFrameList(visualizerModel.FrameArray); SceneInteraction.Update(); } private static Frame ToFrame(KontractFrame kontractFrame) { var (translation, orientation, scale) = kontractFrame; return new Frame(translation, scale, orientation); } private static Frame[] ToFrameArray(IEnumerable frameList) { return [.. frameList.Select(ToFrame)]; } private void SetPoint(Vector3? point) { if (point is null) return; DebugVisualizerScene.AddPointGeometry(point.Value, 5f); } private void SetPointList(Vector3[]? pointList) { if (pointList == null || pointList.Length < 1) return; DebugVisualizerScene.AddPointListGeometry(pointList, 5); } private void SetFrame(KontractFrame? kontractFrame) { if (kontractFrame is null) return; DebugVisualizerScene.AddFrameGeometry(ToFrame(kontractFrame.Value), 1); } private void SetFrameList(KontractFrame[]? frameArray) { if (frameArray == null || frameArray.Length < 1) return; DebugVisualizerScene.AddFrameListGeometry(ToFrameArray(frameArray), 1); } #endregion }