diff --git a/VRDash/MainWindow.xaml b/VRDash/MainWindow.xaml index f0e6ff5..17d9dd7 100644 --- a/VRDash/MainWindow.xaml +++ b/VRDash/MainWindow.xaml @@ -24,7 +24,7 @@ - + diff --git a/VRDash/MainWindow.xaml.cs b/VRDash/MainWindow.xaml.cs index 3f1f1e2..aaaf9ee 100644 --- a/VRDash/MainWindow.xaml.cs +++ b/VRDash/MainWindow.xaml.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -94,33 +95,39 @@ namespace VRDash Thread.Sleep(10000); } }); -#region Debug + #region Debug +#if DEBUG + //Task.Factory.StartNew(() => + //{ + // Compositor_FrameTiming previous = new Compositor_FrameTiming(); + // ulong prev = 0; + // while (true) + // { + // Thread.Sleep(1000); + // Compositor_FrameTiming current = new Compositor_FrameTiming(); + // current.m_nSize = (uint)Marshal.SizeOf(typeof(Compositor_FrameTiming)); + // if (OpenVR.Compositor.GetFrameTiming(ref current, 0)) + // { + // this.GetLogger().Debug(current.m_flTotalRenderGpuMs); + // } + // else + // { + // this.GetLogger().Info("Error getting timing..."); + // } + // previous = current; + // //Compositor_CumulativeStats stats = new Compositor_CumulativeStats(); + // //OpenVR.Compositor.GetCumulativeStats(ref stats, (uint)Marshal.SizeOf(typeof(Compositor_CumulativeStats))); - //StartOverlayWindow("Discord"); + // //this.GetLogger().Debug(stats.m_nNumFramePresents - prev); + // //prev = stats.m_nNumFramePresents; + // //stats. - //StartOverlayWindow("Microsoft Visual Studio"); + // } - //StartOverlayWindow("Notepad++"); - - //StartOverlayWindow("Putty"); - - //StartOverlayWindow("Paint"); - - //Overlay.WindowOverlay obsoverlay = new Overlay.WindowOverlay("obs", "obs", new WindowSelectors.FromProcessName("obs64"), false); - //obsoverlay.Create(); - //obsoverlay.DestroyOnNoWindowFound = true; - //var bringWindow = new Overlay.Actions.BringWindowToFrontAction(true); - //obsoverlay.OverlayShownActions.Add(bringWindow); - - //var displays = User32.GetDisplays(); - //MonitorOverlay mo0 = new MonitorOverlay("left", "Left Monitor", displays[0]); - //mo0.Create(); - //MonitorOverlay mo1 = new MonitorOverlay("center", "Center Monitor", displays[1]); - //mo1.Create(); - //MonitorOverlay mo2= new MonitorOverlay("right", "Right Monitor", displays[2]); - //mo2.Create(); -#endregion + //}); +#endif + #endregion } private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) @@ -131,9 +138,10 @@ namespace VRDash private void LoadProfile(Profile profile) { //Dispose of all overlays and clear list. - foreach (var overlay in OverlayManager.Overlays) + foreach (var overlayLVI in OverlayManager.Overlays) { - overlay.Overlay.Dispose(); + overlayLVI.Dispose(); + overlayLVI.OverlayInfo.Overlay.Dispose(); } OverlayManager.Overlays.Clear(); @@ -141,17 +149,25 @@ namespace VRDash foreach (var config in configs) { - //Get type of overlay based on config type - var attrs = OverlayInfo.GetOverlayInfos(); - var overlayInfo = attrs.Single(x => x.Info.ConfigType == config.GetType()); - Type overlayType = overlayInfo.OverlayType; - //Create overlay - IOverlay overlay = (IOverlay)Activator.CreateInstance(overlayType, new object[] { config }); - overlay.Create(); + try + { + //Get type of overlay based on config type + var attrs = OverlayInfo.GetOverlayInfos(); + var overlayInfo = attrs.Single(x => x.Info.ConfigType == config.GetType()); + Type overlayType = overlayInfo.OverlayType; + //Create overlay + IOverlay overlay = (IOverlay)Activator.CreateInstance(overlayType, new object[] { config }); + overlay.Create(); - UI.IOverlayEditor editor = (UI.IOverlayEditor)Activator.CreateInstance(overlayInfo.Info.EditorType, new object[] { overlay.OverlayConfig }); - OverlayEditorInfo overlayEditor = new OverlayEditorInfo(new UI.OverlayEditor(editor), overlay); - OverlayManager.Overlays.Add(overlayEditor); + UI.IOverlayEditor editor = (UI.IOverlayEditor)Activator.CreateInstance(overlayInfo.Info.EditorType, new object[] { overlay.OverlayConfig }); + OverlayEditorInfo overlayEditor = new OverlayEditorInfo(new UI.OverlayEditor(editor), overlay); + IOverlayListViewItem lvi = (IOverlayListViewItem)Activator.CreateInstance(overlayInfo.Info.ListViewType, new object[] { overlayEditor }); + OverlayManager.Overlays.Add(lvi); + } + catch(Exception ex) + { + this.GetLogger().Error($"Unable to load overlay {config.Name}.", ex); + } } } @@ -165,7 +181,8 @@ namespace VRDash var overlayInfo = attrs.Single(x => x.OverlayType == overlay.GetType()); UI.IOverlayEditor editor = (UI.IOverlayEditor)Activator.CreateInstance(overlayInfo.Info.EditorType, new object[] { overlay.OverlayConfig }); OverlayEditorInfo overlayEditor = new OverlayEditorInfo(new UI.OverlayEditor(editor), overlay); - OverlayManager.Overlays.Add(overlayEditor); + IOverlayListViewItem lvi = (IOverlayListViewItem)Activator.CreateInstance(overlayInfo.Info.ListViewType, new object[] { overlayEditor }); + OverlayManager.Overlays.Add(lvi); }; w.Content = uc; w.Width = 500; @@ -177,10 +194,11 @@ namespace VRDash private void btnRemove_Click(object sender, RoutedEventArgs e) { if(lvOverlays.SelectedItem == null) { return; } - OverlayEditorInfo overlayEditor = (OverlayEditorInfo)lvOverlays.SelectedItem; - overlayEditor.Overlay.Dispose(); - OverlayManager.Overlays.Remove(overlayEditor); - if (bdrContent.Child == overlayEditor.Editor) + IOverlayListViewItem overlayLVI = (IOverlayListViewItem)lvOverlays.SelectedItem; + overlayLVI.OverlayInfo.Overlay.Dispose(); + overlayLVI.Dispose(); + OverlayManager.Overlays.Remove(overlayLVI); + if (bdrContent.Child == overlayLVI.OverlayInfo.Editor) { bdrContent.Child = null; } @@ -189,9 +207,9 @@ namespace VRDash private void lvOverlays_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (lvOverlays.SelectedItem == null) { return; } - OverlayEditorInfo overlay = (OverlayEditorInfo)lvOverlays.SelectedItem; + IOverlayListViewItem overlay = (IOverlayListViewItem)lvOverlays.SelectedItem; - bdrContent.Child = (UserControl)overlay.Editor; + bdrContent.Child = (UserControl)overlay.OverlayInfo.Editor; } private void btnLoad_Click(object sender, RoutedEventArgs e) diff --git a/VRDash/Overlay/IOverlay.cs b/VRDash/Overlay/IOverlay.cs index 8fbecd4..a7b715a 100644 --- a/VRDash/Overlay/IOverlay.cs +++ b/VRDash/Overlay/IOverlay.cs @@ -27,16 +27,18 @@ namespace VRDash.Overlay public class OverlayInfo : System.Attribute { - public OverlayInfo(string description, Type configType, Type editorType) + public OverlayInfo(string description, Type configType, Type editorType, Type listViewType) { Description = description; ConfigType = configType; EditorType = editorType; + ListViewType = listViewType; } public string Description { get; private set; } public Type ConfigType { get; private set; } public Type EditorType { get; private set; } + public Type ListViewType { get; private set; } public static IEnumerable GetTypesWithAttribute() { diff --git a/VRDash/Overlay/MonitorOverlay.cs b/VRDash/Overlay/MonitorOverlay.cs index 2a19661..0d6f29b 100644 --- a/VRDash/Overlay/MonitorOverlay.cs +++ b/VRDash/Overlay/MonitorOverlay.cs @@ -22,12 +22,13 @@ using VRDash.UI; namespace VRDash.Overlay { - [OverlayInfo("Monitor Overlay", typeof(MonitorOverlayConfig), typeof(MonitorOverlayEditor))] + [OverlayInfo("Monitor Overlay", typeof(MonitorOverlayConfig), typeof(MonitorOverlayEditor), typeof(MonitorListViewItem))] public class MonitorOverlay : IOverlay { - public event EventHandler OverlayShown; public event EventHandler OverlayHidden; + + //public event EventHandler Rendered; public int CurrentFPS { get; private set; } @@ -40,7 +41,7 @@ namespace VRDash.Overlay public DisplayInfo DisplayInfo { get { - return User32.GetDisplays().Single(x => x.MonitorInfo.DeviceName == Config.MonitorName); + return User32.GetDisplays().SingleOrDefault(x => x.MonitorInfo.DeviceName == Config.MonitorName); } } @@ -73,17 +74,6 @@ namespace VRDash.Overlay private void createInternal() { if (m_Created) { throw new Exception("This overlay has already been created."); } - - - //Actually create the overlay - var overlay = OpenVR.Overlay; - EVROverlayError err = overlay.CreateDashboardOverlay(Config.Key, Config.Name, ref m_OverlayHandle, ref m_ThumbnailIcon); - - if (err != EVROverlayError.None) - { - throw new Exception($"Error creating overlay: {err}"); - } - overlay.SetOverlayInputMethod(m_OverlayHandle, VROverlayInputMethod.Mouse); m_Running = true; m_EventPumpTask = Task.Factory.StartNew(() => { EventPump(); }); @@ -122,8 +112,25 @@ namespace VRDash.Overlay private void EventPump() { - var overlay = OpenVR.Overlay; + if (!OpenVR.IsHmdPresent()) + { + this.GetLogger().Info("HMD is not present, waiting for HMD to come online."); + while (!OpenVR.IsHmdPresent()) + { + Thread.Sleep(1000); + } + } + //Actually create the overlay + var overlay = OpenVR.Overlay; + EVROverlayError err = overlay.CreateDashboardOverlay(Config.Key, Config.Name, ref m_OverlayHandle, ref m_ThumbnailIcon); + + if (err != EVROverlayError.None) + { + throw new Exception($"Error creating overlay: {err}"); + } + overlay.SetOverlayInputMethod(m_OverlayHandle, VROverlayInputMethod.Mouse); + DateTime lastClick = DateTime.MinValue; #region Rendering setup @@ -171,13 +178,14 @@ namespace VRDash.Overlay //#endregion //Skip rendering if overlay isn't visible -#if !DEBUG +//#if !DEBUG if ((m_OverlayHandle == OpenVR.k_ulOverlayHandleInvalid) || overlay == null || (!overlay.IsOverlayVisible(m_OverlayHandle))) { Thread.Sleep(100); + CurrentFPS = 0; continue; } -#endif +//#endif @@ -346,162 +354,165 @@ namespace VRDash.Overlay #endregion #region Acutally Render - - var rect = DisplayInfo.MonitorArea; - Point pnt = new Point { X = 0, Y = 0 }; - pnt.X = DisplayInfo.MonitorArea.left; - pnt.Y = DisplayInfo.MonitorArea.top; - - int width = rect.right - rect.left; - int height = rect.bottom - rect.top; - - if (width > 0 && height > 0) + if (DisplayInfo != null) { - using (var bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb)) + var rect = DisplayInfo.MonitorArea; + Point pnt = new Point { X = 0, Y = 0 }; + pnt.X = DisplayInfo.MonitorArea.left; + pnt.Y = DisplayInfo.MonitorArea.top; + + int width = rect.right - rect.left; + int height = rect.bottom - rect.top; + + if (width > 0 && height > 0) { - using (Graphics graphics = Graphics.FromImage(bmp)) + using (var bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb)) { - graphics.CopyFromScreen((int)pnt.X, (int)pnt.Y, 0, 0, new Size(width, height), CopyPixelOperation.SourceCopy); - - #region Cursor drawing - User32.CURSORINFO pci; - pci.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(typeof(User32.CURSORINFO)); - - if (User32.GetCursorInfo(out pci)) + using (Graphics graphics = Graphics.FromImage(bmp)) { + graphics.CopyFromScreen((int)pnt.X, (int)pnt.Y, 0, 0, new Size(width, height), CopyPixelOperation.SourceCopy); - Point cursorPoint = new Point() { X = pci.ptScreenPos.X, Y = pci.ptScreenPos.Y }; - cursorPoint.X -= DisplayInfo.MonitorArea.left; - cursorPoint.Y -= DisplayInfo.MonitorArea.top; + #region Cursor drawing + User32.CURSORINFO pci; + pci.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(typeof(User32.CURSORINFO)); - if (pci.flags == User32.CURSOR_SHOWING) + if (User32.GetCursorInfo(out pci)) { - User32.DrawIcon(graphics.GetHdc(), (int)cursorPoint.X, (int)cursorPoint.Y, pci.hCursor); - graphics.ReleaseHdc(); + + Point cursorPoint = new Point() { X = pci.ptScreenPos.X, Y = pci.ptScreenPos.Y }; + cursorPoint.X -= DisplayInfo.MonitorArea.left; + cursorPoint.Y -= DisplayInfo.MonitorArea.top; + + if (pci.flags == User32.CURSOR_SHOWING) + { + User32.DrawIcon(graphics.GetHdc(), (int)cursorPoint.X, (int)cursorPoint.Y, pci.hCursor); + graphics.ReleaseHdc(); + } + else + { + this.GetLogger().Warn($"[{Config.Name}] Error getting coords to draw cursor."); + } } else { - this.GetLogger().Warn($"[{Config.Name}] Error getting coords to draw cursor."); + string errorMessage = new Win32Exception(Marshal.GetLastWin32Error()).Message; + this.GetLogger().Warn($"[{Config.Name}] Error getting cursor info: {errorMessage}"); } - } - else - { - string errorMessage = new Win32Exception(Marshal.GetLastWin32Error()).Message; - this.GetLogger().Warn($"[{Config.Name}] Error getting cursor info: {errorMessage}"); - } - #endregion + #endregion - var data = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); + var data = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); - if (screenTexture == null || (lastWidth != data.Width || lastHeight != data.Height)) - { - lastWidth = data.Width; - lastHeight = data.Height; - - if (screenTexture != null) + if (screenTexture == null || (lastWidth != data.Width || lastHeight != data.Height)) { - screenTexture.Dispose(); + lastWidth = data.Width; + lastHeight = data.Height; - //Dispose not freeing screenTexture: https://gamedev.stackexchange.com/questions/93311/freeing-texture-memory-in-sharpdx-what-am-i-missing - device.ImmediateContext.ClearState(); - device.ImmediateContext.Flush(); - } - - var textureDesc = new Texture2DDescription - { - CpuAccessFlags = CpuAccessFlags.Write, - BindFlags = BindFlags.ShaderResource, - Format = Format.B8G8R8A8_UNorm, - //Format = Format.B8G8R8A8_UNorm_SRgb, - Width = data.Width, - Height = data.Height, - OptionFlags = ResourceOptionFlags.None, - MipLevels = 1, - ArraySize = 1, - SampleDescription = { Count = 1, Quality = 0 }, - Usage = ResourceUsage.Dynamic - }; - screenTexture = new Texture2D(device, textureDesc); - stream = new DataStream(4 * width * height, true, true); - - overlay.SetOverlayWidthInMeters(m_OverlayHandle, Config.OverlayWidth); - - HmdVector2_t vecWindowSize = new HmdVector2_t() { v0 = data.Width, v1 = data.Height }; - OpenVR.Overlay.SetOverlayMouseScale(m_OverlayHandle, ref vecWindowSize); - this.GetLogger().Info($"[{Config.Name}] Monitor resized, texture updated."); - - - } - //Render using graphics card, in DirectX context. - - //using () - { - var screenView = new ShaderResourceView(device, screenTexture); - device.ImmediateContext.PixelShader.SetShaderResource(0, screenView); - - var dr = new SharpDX.DataRectangle(data.Scan0, data.Stride); - - DataBox databox = device.ImmediateContext.MapSubresource(screenTexture, 0, MapMode.WriteDiscard, - SharpDX.Direct3D11.MapFlags.None, out stream); - - - - if (!databox.IsEmpty) - { - int count = 4 * data.Width * data.Height; - - //Stride compensation. Sometimes the BMP and DX texture strides are different. This fixes it. - if (databox.RowPitch == data.Stride) + if (screenTexture != null) { + screenTexture.Dispose(); + + //Dispose not freeing screenTexture: https://gamedev.stackexchange.com/questions/93311/freeing-texture-memory-in-sharpdx-what-am-i-missing + device.ImmediateContext.ClearState(); + device.ImmediateContext.Flush(); + } + + var textureDesc = new Texture2DDescription + { + CpuAccessFlags = CpuAccessFlags.Write, + BindFlags = BindFlags.ShaderResource, + Format = Format.B8G8R8A8_UNorm, + //Format = Format.B8G8R8A8_UNorm_SRgb, + Width = data.Width, + Height = data.Height, + OptionFlags = ResourceOptionFlags.None, + MipLevels = 1, + ArraySize = 1, + SampleDescription = { Count = 1, Quality = 0 }, + Usage = ResourceUsage.Dynamic + }; + screenTexture = new Texture2D(device, textureDesc); + stream = new DataStream(4 * width * height, true, true); + + overlay.SetOverlayWidthInMeters(m_OverlayHandle, Config.OverlayWidth); + + HmdVector2_t vecWindowSize = new HmdVector2_t() { v0 = data.Width, v1 = data.Height }; + OpenVR.Overlay.SetOverlayMouseScale(m_OverlayHandle, ref vecWindowSize); + this.GetLogger().Info($"[{Config.Name}] Monitor resized, texture updated."); + + + } + //Render using graphics card, in DirectX context. + + //using () + { + //var screenView = new ShaderResourceView(device, screenTexture); + //device.ImmediateContext.PixelShader.SetShaderResource(0, screenView); + + //var dr = new SharpDX.DataRectangle(data.Scan0, data.Stride); + + DataBox databox = device.ImmediateContext.MapSubresource(screenTexture, 0, MapMode.WriteDiscard, + SharpDX.Direct3D11.MapFlags.None, out stream); + + + + if (!databox.IsEmpty) + { + int count = 4 * data.Width * data.Height; + + // //Stride compensation. Sometimes the BMP and DX texture strides are different. This fixes it. + // if (databox.RowPitch == data.Stride) + // { + // stream.Write(data.Scan0, 0, count); + // } + // //Truncate the extra BMP bytes. + // else if (databox.RowPitch < data.Stride) + // { + // for (int i = 0; i < data.Height; i++) + // { + // stream.Write(data.Scan0, (data.Stride * i), databox.RowPitch); + // } + // } + // //Add some junk on empty bytes on the end to make everyone happy. + // else if (databox.RowPitch > data.Stride) + // { + // int difference = databox.RowPitch - data.Stride; + // byte[] junk = new byte[difference]; + // for (int i = 0; i < data.Height; i++) + // { + // stream.Write(data.Scan0, (data.Stride * i), data.Stride); + // stream.Write(junk, 0, difference); + // } + // } stream.Write(data.Scan0, 0, count); } - //Truncate the extra BMP bytes. - else if (databox.RowPitch < data.Stride) + + + + device.ImmediateContext.UpdateSubresource(ref databox, screenTexture, 0, width, 1); + + var texture = new Texture_t(); + texture.handle = screenTexture.NativePointer; + texture.eType = ETextureType.DirectX; + texture.eColorSpace = EColorSpace.Auto; + EVROverlayError result = overlay.SetOverlayTexture(m_OverlayHandle, ref texture); + if (result != EVROverlayError.None) { - for (int i = 0; i < data.Height; i++) - { - stream.Write(data.Scan0, (data.Stride * i), databox.RowPitch); - } - } - //Add some junk on empty bytes on the end to make everyone happy. - else if (databox.RowPitch > data.Stride) - { - int difference = databox.RowPitch - data.Stride; - byte[] junk = new byte[difference]; - for (int i = 0; i < data.Height; i++) - { - stream.Write(data.Scan0, (data.Stride * i), data.Stride); - stream.Write(junk, 0, difference); - } + + this.GetLogger().Warn($"Error rendering: {result}"); } + + device.ImmediateContext.UnmapSubresource(screenTexture, 0); + + + + frames++; + + bmp.UnlockBits(data); } - - - VRTextureBounds_t bounds = new VRTextureBounds_t(); - OpenVR.Overlay.GetOverlayTextureBounds(m_OverlayHandle, ref bounds); - - var texture = new Texture_t(); - texture.handle = screenTexture.NativePointer; - texture.eType = ETextureType.DirectX; - texture.eColorSpace = EColorSpace.Auto; - EVROverlayError result = overlay.SetOverlayTexture(m_OverlayHandle, ref texture); - if (result != EVROverlayError.None) - { - - this.GetLogger().Warn($"Error rendering: {result}"); - } - - device.ImmediateContext.UnmapSubresource(screenTexture, 0); - - - - frames++; - - bmp.UnlockBits(data); } } - } + } } #endregion @@ -517,7 +528,7 @@ namespace VRDash.Overlay } //Clean up after we exit while loop. - screenTexture.Dispose(); + screenTexture?.Dispose(); device.ImmediateContext.ClearState(); device.ImmediateContext.Flush(); diff --git a/VRDash/Overlay/WindowOverlay.cs b/VRDash/Overlay/WindowOverlay.cs index 42352e9..b156a95 100644 --- a/VRDash/Overlay/WindowOverlay.cs +++ b/VRDash/Overlay/WindowOverlay.cs @@ -21,7 +21,7 @@ using VRDash.UI; namespace VRDash.Overlay { - [OverlayInfo("Window Overlay", typeof(WindowOverlayConfig), typeof(WindowOverlayEditor))] + [OverlayInfo("Window Overlay", typeof(WindowOverlayConfig), typeof(WindowOverlayEditor), typeof(UI.WindowOverlayListViewItem))] public class WindowOverlay : IOverlay { public event EventHandler OverlayShown; @@ -221,15 +221,14 @@ namespace VRDash.Overlay } //Skip rendering if overlay isn't visible -#if !DEBUG +//#if !DEBUG if ((m_OverlayHandle == OpenVR.k_ulOverlayHandleInvalid) || overlay == null || (!overlay.IsOverlayVisible(m_OverlayHandle))) { Thread.Sleep(100); + CurrentFPS = 0; continue; } -#endif - - +//#endif #region VR Events VREvent_t vrEvent = new VREvent_t(); @@ -515,10 +514,10 @@ namespace VRDash.Overlay //using () { - var screenView = new ShaderResourceView(device, screenTexture); - device.ImmediateContext.PixelShader.SetShaderResource(0, screenView); + //var screenView = new ShaderResourceView(device, screenTexture); + //device.ImmediateContext.PixelShader.SetShaderResource(0, screenView); - var dr = new SharpDX.DataRectangle(data.Scan0, data.Stride); + //var dr = new SharpDX.DataRectangle(data.Scan0, data.Stride); DataBox databox = device.ImmediateContext.MapSubresource(screenTexture, 0, MapMode.WriteDiscard, SharpDX.Direct3D11.MapFlags.None, out stream); @@ -529,35 +528,36 @@ namespace VRDash.Overlay { int count = 4 * data.Width * data.Height; - //Stride compensation. Sometimes the BMP and DX texture strides are different. This fixes it. - if (databox.RowPitch == data.Stride) - { - stream.Write(data.Scan0, 0, count); - } - //Truncate the extra BMP bytes. - else if (databox.RowPitch < data.Stride) - { - for (int i = 0; i < data.Height; i++) - { - stream.Write(data.Scan0, (data.Stride * i), databox.RowPitch); - } - } - //Add some junk on empty bytes on the end to make everyone happy. - else if (databox.RowPitch > data.Stride) - { - int difference = databox.RowPitch - data.Stride; - byte[] junk = new byte[difference]; - for (int i = 0; i < data.Height; i++) - { - stream.Write(data.Scan0, (data.Stride * i), data.Stride); - stream.Write(junk, 0, difference); - } - } + // //Stride compensation. Sometimes the BMP and DX texture strides are different. This fixes it. + // if (databox.RowPitch == data.Stride) + // { + // stream.Write(data.Scan0, 0, count); + // } + // //Truncate the extra BMP bytes. + // else if (databox.RowPitch < data.Stride) + // { + // for (int i = 0; i < data.Height; i++) + // { + // stream.Write(data.Scan0, (data.Stride * i), databox.RowPitch); + // } + // } + // //Add some junk on empty bytes on the end to make everyone happy. + // else if (databox.RowPitch > data.Stride) + // { + // int difference = databox.RowPitch - data.Stride; + // byte[] junk = new byte[difference]; + // for (int i = 0; i < data.Height; i++) + // { + // stream.Write(data.Scan0, (data.Stride * i), data.Stride); + // stream.Write(junk, 0, difference); + // } + // } + stream.Write(data.Scan0, 0, count); } - VRTextureBounds_t bounds = new VRTextureBounds_t(); - OpenVR.Overlay.GetOverlayTextureBounds(m_OverlayHandle, ref bounds); + + device.ImmediateContext.UpdateSubresource(ref databox, screenTexture, 0, width, 1); var texture = new Texture_t(); texture.handle = screenTexture.NativePointer; @@ -567,7 +567,7 @@ namespace VRDash.Overlay if (result != EVROverlayError.None) { - this.GetLogger().Warn($"[{Config.Name}] Error rendering: {result}"); + this.GetLogger().Warn($"Error rendering: {result}"); } device.ImmediateContext.UnmapSubresource(screenTexture, 0); diff --git a/VRDash/OverlayManager.cs b/VRDash/OverlayManager.cs index 177b4d7..561f919 100644 --- a/VRDash/OverlayManager.cs +++ b/VRDash/OverlayManager.cs @@ -13,7 +13,7 @@ namespace VRDash { public class OverlayManager { - public ObservableCollection Overlays { get; internal set; } = new ObservableCollection(); + public ObservableCollection Overlays { get; internal set; } = new ObservableCollection(); } diff --git a/VRDash/ProfileManager.cs b/VRDash/ProfileManager.cs index efa6e7a..1ac3132 100644 --- a/VRDash/ProfileManager.cs +++ b/VRDash/ProfileManager.cs @@ -38,7 +38,7 @@ namespace VRDash public string GetLoadedProfileJson() { - IOverlayConfig[] selection = MainWindow.OverlayManager.Overlays.Select(x => x.Overlay.OverlayConfig).ToArray(); + IOverlayConfig[] selection = MainWindow.OverlayManager.Overlays.Select(x => x.OverlayInfo.Overlay.OverlayConfig).ToArray(); var profile = new Profile(selection); var json = JsonConvert.SerializeObject(profile, m_Settings); return json; @@ -52,6 +52,7 @@ namespace VRDash public bool IsProfileSaveUpToDate() { + if (!File.Exists(ConfigLocation)) { return false; } return GetLoadedProfileJson() == GetDefaultProfileJson(); } diff --git a/VRDash/UI/IOverlayListViewItem.cs b/VRDash/UI/IOverlayListViewItem.cs new file mode 100644 index 0000000..63c6118 --- /dev/null +++ b/VRDash/UI/IOverlayListViewItem.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace VRDash.UI +{ + public interface IOverlayListViewItem:IDisposable + { + OverlayEditorInfo OverlayInfo { get; } + + } +} diff --git a/VRDash/UI/MonitorOverlayListViewItem.xaml b/VRDash/UI/MonitorOverlayListViewItem.xaml new file mode 100644 index 0000000..14de27f --- /dev/null +++ b/VRDash/UI/MonitorOverlayListViewItem.xaml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + Name + Loading... + Loading... + + diff --git a/VRDash/UI/MonitorOverlayListViewItem.xaml.cs b/VRDash/UI/MonitorOverlayListViewItem.xaml.cs new file mode 100644 index 0000000..7f53192 --- /dev/null +++ b/VRDash/UI/MonitorOverlayListViewItem.xaml.cs @@ -0,0 +1,57 @@ +using SharpDX.DXGI; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using System.Windows.Threading; +using VRDash.Overlay; + +namespace VRDash.UI +{ + /// + /// Interaction logic for WindowOverlayListViewItem.xaml + /// + public partial class MonitorListViewItem : UserControl,IDisposable,IOverlayListViewItem + { + public MonitorOverlay Overlay { get { return (MonitorOverlay)OverlayInfo.Overlay; } } + + public OverlayEditorInfo OverlayInfo { get; private set; } + + DispatcherTimer m_Timer = null; + public MonitorListViewItem(OverlayEditorInfo overlayInfo) + { + InitializeComponent(); + OverlayInfo = overlayInfo; + + m_Timer = new DispatcherTimer(new TimeSpan(0, 0, 0, 0, 300), DispatcherPriority.Normal, OnTimerTick, this.Dispatcher); + m_Timer.Start(); + } + + private void TestShit() + { + + } + + private void OnTimerTick(object x, object y) + { + tbName.Text = Overlay.OverlayConfig.Name; + tbFPS.Text = $"{Overlay.CurrentFPS} FPS"; + tbMonitor.Text = Overlay.Config.MonitorName; + } + + public void Dispose() + { + m_Timer?.Stop(); + } + } +} diff --git a/VRDash/UI/WindowOverlayListViewItem.xaml b/VRDash/UI/WindowOverlayListViewItem.xaml new file mode 100644 index 0000000..021f0a1 --- /dev/null +++ b/VRDash/UI/WindowOverlayListViewItem.xaml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + Name + Loading... + Loading... + + diff --git a/VRDash/UI/WindowOverlayListViewItem.xaml.cs b/VRDash/UI/WindowOverlayListViewItem.xaml.cs new file mode 100644 index 0000000..c9b439a --- /dev/null +++ b/VRDash/UI/WindowOverlayListViewItem.xaml.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using System.Windows.Threading; +using VRDash.Overlay; + +namespace VRDash.UI +{ + /// + /// Interaction logic for WindowOverlayListViewItem.xaml + /// + public partial class WindowOverlayListViewItem : UserControl, IDisposable,IOverlayListViewItem + { + public WindowOverlay Overlay { get { return (WindowOverlay)OverlayInfo.Overlay; } } + + public OverlayEditorInfo OverlayInfo { get; private set; } + + DispatcherTimer m_Timer = null; + public WindowOverlayListViewItem(OverlayEditorInfo overlayInfo) + { + InitializeComponent(); + OverlayInfo = overlayInfo; + + m_Timer = new DispatcherTimer(new TimeSpan(0, 0, 0, 0, 300), DispatcherPriority.Normal, OnTimerTick, this.Dispatcher); + m_Timer.Start(); + } + + private void OnTimerTick(object x, object y) + { + tbName.Text = Overlay.OverlayConfig.Name; + tbFPS.Text = $"{Overlay.CurrentFPS} FPS"; + + if (Overlay.Config.Selector.WindowExists()) + { + tbWindowFound.Text = "Window Found"; + tbWindowFound.Foreground = Brushes.Green; + } + else + { + tbWindowFound.Text = "Window Not Found"; + tbWindowFound.Foreground = Brushes.Red; + } + } + + public void Dispose() + { + m_Timer?.Stop(); + } + } +} diff --git a/VRDash/VRDash.csproj b/VRDash/VRDash.csproj index 0218828..ea7f1db 100644 --- a/VRDash/VRDash.csproj +++ b/VRDash/VRDash.csproj @@ -115,6 +115,7 @@ CreateNewOverlay.xaml + MonitorOverlayEditor.xaml @@ -128,6 +129,12 @@ WindowOverlayEditor.xaml + + MonitorOverlayListViewItem.xaml + + + WindowOverlayListViewItem.xaml + WindowSelectorEditor.xaml @@ -172,6 +179,14 @@ Designer MSBuild:Compile + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/VRDash/WindowSelectors/FromWindowTitle.cs b/VRDash/WindowSelectors/FromWindowTitle.cs index 72e3f98..595fe9a 100644 --- a/VRDash/WindowSelectors/FromWindowTitle.cs +++ b/VRDash/WindowSelectors/FromWindowTitle.cs @@ -54,24 +54,28 @@ namespace VRDash.WindowSelectors var windows = WindowInfo.GetWindowList(); if (SearchType == TitleSearchType.Contains) { - var results = windows.Where(x => x.Title.ToLower().Contains(TitleFilter.ToLower())); - if(results.Count() == 0) - { - throw new WindowNotFoundException("No windows match the filter settings."); + var results = windows.Where(x => x.Title.ToLower().Contains(TitleFilter.ToLower()) && x.IsVisible); + if (results.Count() == 0) + { + //throw new WindowNotFoundException("No windows match the filter settings."); + return null; } return results.First(); + //return windows.SingleOrDefault(x => x.Title.ToLower().Contains(TitleFilter.ToLower())); } if(SearchType == TitleSearchType.Regex) { - var results = windows.Where(x => Regex.IsMatch(x.Title, TitleFilter)); + var results = windows.Where(x => Regex.IsMatch(x.Title, TitleFilter) && x.IsVisible); if (results.Count() == 0) { - throw new WindowNotFoundException("No windows match the filter settings."); + //throw new WindowNotFoundException("No windows match the filter settings."); + return null; } return results.First(); + //return windows.SingleOrDefault(x => Regex.IsMatch(x.Title, TitleFilter)); } throw new WindowNotFoundException("Error fetching matching window."); @@ -79,6 +83,7 @@ namespace VRDash.WindowSelectors public IntPtr GetWindowHandle() { + if(Window == null) { return IntPtr.Zero; } return Window.hWnd; } @@ -98,7 +103,10 @@ namespace VRDash.WindowSelectors // return false; //} //return true; - + if(Window == null) + { + return false; + } return User32.IsWindow(GetWindowHandle()); }