Skip to content

Commit

Permalink
Camera support handling
Browse files Browse the repository at this point in the history
  • Loading branch information
KimihikoAkayasaki committed Oct 11, 2024
1 parent 4b547c2 commit 28b2082
Show file tree
Hide file tree
Showing 4 changed files with 304 additions and 75 deletions.
3 changes: 3 additions & 0 deletions Amethyst/Classes/AppSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,9 @@ public uint AppSoundsVolume
// Save the skeleton preview state
public bool SkeletonPreviewEnabled { get; set; } = true;

// Save the camera preview state
public bool CameraPreviewEnabled { get; set; } = false;

// If we wanna dismiss all warnings during the preview
public bool ForceSkeletonPreview { get; set; } = false;

Expand Down
100 changes: 77 additions & 23 deletions Amethyst/MVVM/TrackingDevice.cs
Original file line number Diff line number Diff line change
@@ -1,43 +1,77 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Threading.Tasks;
using Amethyst.Classes;
using Amethyst.Plugins.Contract;
using Amethyst.Utils;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media.Animation;
using Microsoft.UI.Xaml.Media.Imaging;
using static Amethyst.Classes.Interfacing;

namespace Amethyst.MVVM;

public class TrackingDevice(string name, string guid, string path, Version version, ITrackingDevice device) : INotifyPropertyChanged
public class TrackingDevice : INotifyPropertyChanged
{
public TrackingDevice(string name, string guid, string path, Version version, ITrackingDevice device)
{
// Setup device data
Guid = guid;
Name = name;
Location = path;
Version = version;
Device = device;

// Setup optional camera streams
if (guid is not "K2VRTEAM-AME2-APII-DVCE-DVCEKINECTV1"
and not "K2VRTEAM-AME2-APII-DVCE-DVCEKINECTV2") return;

var cameraImageProperty = device.GetType().GetProperty("GetCameraImage");
var cameraMapperProperty = device.GetType().GetProperty("MapCoordinateDelegate");
var cameraEnabledProperty = device.GetType().GetProperty("GetIsCameraEnabled");
var cameraEnabledSetter = device.GetType().GetProperty("SetIsCameraEnabled");

if (!(cameraImageProperty?.CanRead ?? false) ||
!(cameraEnabledProperty?.CanRead ?? false) ||
!(cameraEnabledSetter?.CanRead ?? false) ||
!(cameraMapperProperty?.CanRead ?? false)) return;

// Cache all getters & setters for quicker access later on
GetCameraImage = cameraImageProperty.GetValue(device) as Func<BitmapSource>;
GetIsCameraEnabled = cameraEnabledProperty.GetValue(device) as Func<bool>;
SetIsCameraEnabled = cameraEnabledSetter.GetValue(device) as Action<bool>;
MapCoordinateDelegate = cameraMapperProperty.GetValue(device) as Func<Vector3, Size>;
}

// Extensions: is this device set as base?
public bool IsBase => AppPlugins.IsBase(Guid);

// Extensions: is this device set as an override?
public bool IsOverride => AppPlugins.IsOverride(Guid);

// Get GUID
[DefaultValue("INVALID")] public string Guid { get; } = guid;
[DefaultValue("INVALID")] public string Guid { get; }

// Get Name
[DefaultValue("UNKNOWN")] public string Name { get; } = name;
[DefaultValue("UNKNOWN")] public string Name { get; }

// Get Path
[DefaultValue("UNKNOWN")] public string Location { get; } = path;
[DefaultValue("UNKNOWN")] public string Location { get; }

// Get the plugin version using its host assembly
[DefaultValue("0.0.0.0")] public Version Version { get; } = version;
[DefaultValue("0.0.0.0")] public Version Version { get; }

// Get Docs
[DefaultValue(null)] public Uri ErrorDocsUri => Device.ErrorDocsUri;

// Underlying device handler
public ITrackingDevice Device { get; } = device;
public ITrackingDevice Device { get; }

// Joints' list / you need to (should) update at every update() call
// Each must have its own role or _Manual to force user's manual set
Expand Down Expand Up @@ -115,6 +149,36 @@ public class TrackingDevice(string name, string guid, string path, Version versi
// Hot reload handler
public FileSystemWatcher AssetsWatcher { get; set; }

public string[] DeviceStatusSplit
{
get
{
// Split status and message by \n
var message = StringUtils.SplitStatusString(DeviceStatusString);
return message is null || message.Length < 3 ? new[] { "The status message was broken!", "E_FIX_YOUR_SHIT", "AAAAA" } : message;
}
}

public string DeviceJointsCount => $"Forwarded joints: {TrackedJoints.Count}";
public string DeviceSettingsText => LocalizedJsonString("/GeneralPage/Buttons/DeviceSettings").Format(Name);
public bool ServiceNotRelay => AppPlugins.CurrentServiceEndpoint.Guid is not "K2VRTEAM-AME2-APII-DVCE-TRACKINGRELAY";
public bool IsFromRelay => Guid.StartsWith("TRACKINGRELAY:");
public string RelayText => $"From {HostMachineName}";
public string HostMachineName { get; set; } = "Amethyst Tracking Relay";

private Func<BitmapSource> GetCameraImage { get; }
private Func<bool> GetIsCameraEnabled { get; }
private Action<bool> SetIsCameraEnabled { get; }
private Func<Vector3, Size> MapCoordinateDelegate { get; }

public BitmapSource CameraImage => GetCameraImage?.Invoke();

public bool IsCameraEnabled
{
get => GetIsCameraEnabled?.Invoke() ?? false;
set => SetIsCameraEnabled?.Invoke(value);
}

// Property changed event
public event PropertyChangedEventHandler PropertyChanged;

Expand Down Expand Up @@ -238,23 +302,6 @@ public void AssetsChanged(object o, FileSystemEventArgs fileSystemEventArgs)
});
}

public string[] DeviceStatusSplit
{
get
{
// Split status and message by \n
var message = StringUtils.SplitStatusString(DeviceStatusString);
return message is null || message.Length < 3 ? new[] { "The status message was broken!", "E_FIX_YOUR_SHIT", "AAAAA" } : message;
}
}

public string DeviceJointsCount => $"Forwarded joints: {TrackedJoints.Count}";
public string DeviceSettingsText => LocalizedJsonString("/GeneralPage/Buttons/DeviceSettings").Format(Name);
public bool ServiceNotRelay => AppPlugins.CurrentServiceEndpoint.Guid is not "K2VRTEAM-AME2-APII-DVCE-TRACKINGRELAY";
public bool IsFromRelay => Guid.StartsWith("TRACKINGRELAY:");
public string RelayText => $"From {HostMachineName}";
public string HostMachineName { get; set; } = "Amethyst Tracking Relay";

public async void ViewDeviceSettings(object sender, RoutedEventArgs e)
{
// Go to the devices page to view device settings
Expand Down Expand Up @@ -282,4 +329,11 @@ public async void ViewDeviceSettings(object sender, RoutedEventArgs e)
await Shared.Devices.ReloadSelectedDevice(skipAnimation);
Shared.Events.ReloadDevicesPageEvent?.Set(); // Full reload
}

public (double Left, double Top) MapCoordinate(Vector3 position)
{
var result = MapCoordinateDelegate?.Invoke(position) ?? Size.Empty;
//return (Left: result.Width / 1000.0f, Top: result.Height / 1000.0f);
return (Left: result.Width, Top: result.Height);
}
}
80 changes: 56 additions & 24 deletions Amethyst/Pages/General.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mvvm="using:Amethyst.MVVM" xmlns:classes="using:Amethyst.Classes"
xmlns:local="using:Amethyst.Pages" xmlns:util="using:Amethyst.Utils"
xmlns:media="using:CommunityToolkit.WinUI.UI.Media"
Loaded="Page_Loaded" NavigationCacheMode="Required"
mc:Ignorable="d" Background="Transparent">

Expand Down Expand Up @@ -1198,7 +1199,7 @@
<StackPanel Orientation="Vertical" Margin="10,0">
<StackPanel Orientation="Horizontal">
<TextBlock HorizontalAlignment="Left" VerticalAlignment="Top" FontWeight="SemiBold"
Text="{x:Bind Name, Mode=OneWay}" Margin="0,5,0,0"
Text="{x:Bind Name, Mode=OneWay}" Margin="0,5,0,0"
Foreground="{ThemeResource SystemFillColorAttentionBrush}" />

<TextBlock HorizontalAlignment="Left" VerticalAlignment="Top" FontWeight="SemiBold"
Expand Down Expand Up @@ -1545,16 +1546,29 @@
</Grid>

<!--Skeleton canvas-->
<Canvas HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Column="1" Canvas.ZIndex="-1"
Opacity="0.0" x:Name="SkeletonDrawingCanvas" Loaded="SkeletonDrawingCanvas_Loaded">
<Canvas.OpacityTransition>
<ScalarTransition />
</Canvas.OpacityTransition>
<Viewbox Grid.Column="1" Canvas.ZIndex="-1" Stretch="UniformToFill"
HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid x:Name="DrawingContainerGrid">
<Canvas HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="640" Height="480"
Opacity="0.0" x:Name="SkeletonDrawingCanvas" Loaded="SkeletonDrawingCanvas_Loaded">
<Canvas.OpacityTransition>
<ScalarTransition />
</Canvas.OpacityTransition>

<Canvas.Clip>
<RectangleGeometry Rect="0,0,10000000,10000000" />
</Canvas.Clip>
</Canvas>

<Canvas.Clip>
<RectangleGeometry Rect="0,0,10000000,10000000" />
</Canvas.Clip>
</Canvas>
<Image x:Name="CameraImage" Opacity="0.0" Stretch="Uniform"
HorizontalAlignment="Center" VerticalAlignment="Center"
SizeChanged="CameraImage_OnSizeChanged" Canvas.ZIndex="-1">
<Image.OpacityTransition>
<ScalarTransition />
</Image.OpacityTransition>
</Image>
</Grid>
</Viewbox>

<!--Background-->
<Grid Background="Black" Grid.Column="1" Canvas.ZIndex="-2"
Expand All @@ -1563,22 +1577,27 @@
<!--No Skeleton-->
<Viewbox Grid.Column="1" HorizontalAlignment="Stretch" Margin="20"
VerticalAlignment="Stretch" Stretch="Uniform" StretchDirection="DownOnly">
<StackPanel Opacity="1.0" HorizontalAlignment="Center" VerticalAlignment="Center"
x:Name="NoSkeletonNotice" Margin="0,-10,0,0">
<StackPanel.OpacityTransition>
<Grid Padding="35, 20,35,23" CornerRadius="25" x:Name="NoSkeletonNotice">
<Grid.OpacityTransition>
<ScalarTransition />
</StackPanel.OpacityTransition>
</Grid.OpacityTransition>

<Grid.Background>
<media:BackdropBlurBrush Amount="25.0"/>
</Grid.Background>
<StackPanel Opacity="1.0" HorizontalAlignment="Center" VerticalAlignment="Center"
Margin="0,-10,0,0">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<FontIcon Glyph="&#xE7BA;" FontSize="45" FontWeight="Bold" Foreground="White" />
<TextBlock Margin="10,0,0,7" FontSize="50" FontWeight="SemiBold" Foreground="White"
Text="{x:Bind util:Translator.Get.String('/GeneralPage/Captions/Preview/NoSkeleton'), Mode=OneWay}" />
</StackPanel>

<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<FontIcon Glyph="&#xE7BA;" FontSize="45" FontWeight="Bold" Foreground="White" />
<TextBlock Margin="10,0,0,7" FontSize="50" FontWeight="SemiBold" Foreground="White"
Text="{x:Bind util:Translator.Get.String('/GeneralPage/Captions/Preview/NoSkeleton'), Mode=OneWay}" />
<TextBlock Margin="0,-5,0,0" FontSize="25" FontWeight="Medium" HorizontalAlignment="Center"
Text="{x:Bind util:Translator.Get.String('/GeneralPage/Captions/Preview/NoSkeletonText'), Mode=OneWay}"
x:Name="NoSkeletonTextNotice" HorizontalTextAlignment="Center" Foreground="White" />
</StackPanel>

<TextBlock Margin="0,-5,0,0" FontSize="25" FontWeight="Medium" HorizontalAlignment="Center"
Text="{x:Bind util:Translator.Get.String('/GeneralPage/Captions/Preview/NoSkeletonText'), Mode=OneWay}"
x:Name="NoSkeletonTextNotice" HorizontalTextAlignment="Center" Foreground="White" />
</StackPanel>
</Grid>
</Viewbox>

<!--Skeleton Disabled-->
Expand Down Expand Up @@ -1678,6 +1697,7 @@

<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="175" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>

Expand Down Expand Up @@ -1709,7 +1729,7 @@
FontWeight="Medium" Margin="30,0,0,0"
Text="{x:Bind util:Translator.Get.String('/GeneralPage/Captions/Preview/Force'), Mode=OneWay}"
Grid.Column="0" x:Name="ForceRenderText" />
<CheckBox x:Name="ForceRenderCheckBox"
<CheckBox x:Name="ForceRenderCheckBox" Grid.Column="0"
Checked="ForceRenderCheckBox_Checked"
Unchecked="ForceRenderCheckBox_Unchecked"
HorizontalAlignment="Left" VerticalAlignment="Center"
Expand All @@ -1721,6 +1741,18 @@
</ToggleSplitButton>
</Grid>

<Grid Grid.Row="1" Grid.Column="1">
<ToggleButton x:Name="CameraToggleButton" Click="CameraToggleButton_Click"
Visibility="{x:Bind DeviceSupportsCamera, Mode=OneWay}"
IsChecked="False" VerticalContentAlignment="Center" FontWeight="SemiBold"
IsTabStop="False" Margin="10,0,0,0" CornerRadius="4"
Padding="12,0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ToggleButton.Content>
<SymbolIcon Symbol="Camera" />
</ToggleButton.Content>
</ToggleButton>
</Grid>

<!--Flyout for manifest and reregister errors-->
<FlyoutBase.AttachedFlyout>
<Flyout x:Name="SetErrorFlyout" Placement="RightEdgeAlignedBottom"
Expand Down
Loading

0 comments on commit 28b2082

Please sign in to comment.