public static void Main(string[] args) { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); PerformanceMonitor.Start(); Discord.Start(); LocalConfig.LoadConfig(); VRCApi.LoadCookie(); new MainForm(); MainForm.Instance.Show(); Application.DoEvents(); m_RenderForm = new RenderForm { AllowUserResizing = false, ClientSize = new System.Drawing.Size(512, 768), Icon = null, Text = APP }; Application.DoEvents(); Device.CreateWithSwapChain(SharpDX.Direct3D.DriverType.Hardware, DeviceCreationFlags.BgraSupport, new[] { SharpDX.Direct3D.FeatureLevel.Level_10_0 }, new SwapChainDescription() { BufferCount = 1, ModeDescription = new ModeDescription(XS, YS, new Rational(30, 1), Format.R8G8B8A8_UNorm), IsWindowed = true, OutputHandle = m_RenderForm.Handle, SampleDescription = new SampleDescription(1, 0), SwapEffect = SwapEffect.Discard, Usage = Usage.RenderTargetOutput }, out m_Device, out m_SwapChain); m_SwapChain.GetParent <SharpDX.DXGI.Factory>().MakeWindowAssociation(m_RenderForm.Handle, WindowAssociationFlags.IgnoreAll); m_BackBuffer = Texture2D.FromSwapChain <Texture2D>(m_SwapChain, 0); m_BackBuffer2 = new Texture2D(m_Device, new Texture2DDescription() { Width = 1024, Height = 1024, MipLevels = 1, ArraySize = 1, Format = Format.R8G8B8A8_UNorm, SampleDescription = new SampleDescription(1, 0), BindFlags = BindFlags.RenderTarget }); var factory2D = new SharpDX.Direct2D1.Factory(); using (var surface = m_BackBuffer.QueryInterface <Surface>()) { m_RenderTarget = new RenderTarget(factory2D, surface, new RenderTargetProperties(new PixelFormat(Format.Unknown, SharpDX.Direct2D1.AlphaMode.Premultiplied))) { TextAntialiasMode = SharpDX.Direct2D1.TextAntialiasMode.Cleartype, AntialiasMode = AntialiasMode.PerPrimitive }; } using (var surface = m_BackBuffer2.QueryInterface <Surface>()) { m_RenderTarget2 = new RenderTarget(factory2D, surface, new RenderTargetProperties(new PixelFormat(Format.Unknown, SharpDX.Direct2D1.AlphaMode.Premultiplied))) { TextAntialiasMode = SharpDX.Direct2D1.TextAntialiasMode.Cleartype, AntialiasMode = AntialiasMode.PerPrimitive }; } // fonts var factoryDW = new SharpDX.DirectWrite.Factory(); var textFormat1 = new TextFormat(factoryDW, "Arial", FontWeight.Bold, FontStyle.Normal, 64) { WordWrapping = WordWrapping.NoWrap, ParagraphAlignment = ParagraphAlignment.Center, TextAlignment = TextAlignment.Center, }; var textFormat2 = new TextFormat(factoryDW, "Arial", FontWeight.Bold, FontStyle.Normal, 32) { WordWrapping = WordWrapping.NoWrap, ParagraphAlignment = ParagraphAlignment.Center, TextAlignment = TextAlignment.Center, }; var textFormat3 = new TextFormat(factoryDW, "Arial", FontWeight.Normal, FontStyle.Normal, 48) { WordWrapping = WordWrapping.NoWrap, ParagraphAlignment = ParagraphAlignment.Far, TextAlignment = TextAlignment.Leading, }; var textFormat4 = new TextFormat(factoryDW, "Arial", FontWeight.Bold, FontStyle.Normal, 48) { WordWrapping = WordWrapping.NoWrap, ParagraphAlignment = ParagraphAlignment.Far, TextAlignment = TextAlignment.Center, }; // colors var backColor = new Color(0.15f, 0.15f, 0.15f, 1); // brushes var blackBrush = new SolidColorBrush(m_RenderTarget, Color.Black); var whiteBrush = new SolidColorBrush(m_RenderTarget, Color.White); var grayBrush = new SolidColorBrush(m_RenderTarget, Color.Gray); var lightGrayBrush = new SolidColorBrush(m_RenderTarget, Color.LightGray); var limeBrush = new SolidColorBrush(m_RenderTarget, Color.Lime); var goldBrush = new SolidColorBrush(m_RenderTarget, Color.Gold); var redBrush = new SolidColorBrush(m_RenderTarget, Color.Red); var enterWorldBrush = new SolidColorBrush(m_RenderTarget, Color.Orange); var playerJoinBrush = new SolidColorBrush(m_RenderTarget, Color.Cyan); var playerLeftBrush = new SolidColorBrush(m_RenderTarget, Color.HotPink); var playerLoginBrush = new SolidColorBrush(m_RenderTarget, Color.Yellow); var playerLogoutBrush = new SolidColorBrush(m_RenderTarget, Color.DeepPink); var playerGPSBrush = new SolidColorBrush(m_RenderTarget, Color.Lime); var group1Brush = new SolidColorBrush(m_RenderTarget, new Color(1, 0, 0.5f, 0.25f)); var group2Brush = new SolidColorBrush(m_RenderTarget, new Color(0.5f, 1, 0, 0.25f)); var group3Brush = new SolidColorBrush(m_RenderTarget, new Color(0, 0.5f, 1, 0.25f)); // brushes (RenderTarget2) var blackBrush2 = new SolidColorBrush(m_RenderTarget2, Color.Black); var whiteBrush2 = new SolidColorBrush(m_RenderTarget2, Color.White); // images var sex = LoadBitmap(m_RenderTarget, Properties.Resources.icon_17); var controllerStatusOff = LoadBitmap(m_RenderTarget, Properties.Resources.controller_status_off); var controllerStatusReady = LoadBitmap(m_RenderTarget, Properties.Resources.controller_status_ready); var controllerStatusReadyLow = LoadBitmap(m_RenderTarget, Properties.Resources.controller_status_ready_low); var trackerStatusOff = LoadBitmap(m_RenderTarget, Properties.Resources.tracker_status_off); var trackerStatusReady = LoadBitmap(m_RenderTarget, Properties.Resources.tracker_status_ready); var trackerStatusReadyLow = LoadBitmap(m_RenderTarget, Properties.Resources.tracker_status_ready_low); var otherStatusOff = LoadBitmap(m_RenderTarget, Properties.Resources.other_status_off); var otherStatusReady = LoadBitmap(m_RenderTarget, Properties.Resources.other_status_ready); var otherStatusReadyLow = LoadBitmap(m_RenderTarget, Properties.Resources.other_status_ready_low); var leftControllerOff = LoadBitmap(m_RenderTarget, Properties.Resources.cb_left_controller_off); var leftControllerReady = LoadBitmap(m_RenderTarget, Properties.Resources.cb_left_controller_ready); var leftControllerReadyLow = LoadBitmap(m_RenderTarget, Properties.Resources.cb_left_controller_ready_low); var rightControllerOff = LoadBitmap(m_RenderTarget, Properties.Resources.cb_right_controller_off); var rightControllerReady = LoadBitmap(m_RenderTarget, Properties.Resources.cb_right_controller_ready); var rightControllerReadyLow = LoadBitmap(m_RenderTarget, Properties.Resources.cb_right_controller_ready_low); var epoch = DateTime.Now; var next = DateTime.MinValue; var uptime = string.Empty; RenderLoop.Run(m_RenderForm, () => { if (DateTime.Now.CompareTo(next) >= 0) { var sec = (DateTime.Now.Ticks - epoch.Ticks) / 10000000; var min = sec / 60; var hour = min / 60; uptime = string.Format("Uptime {0:D2}:{1:D2}:{2:D2}", hour % 100, min % 60, sec % 60); for (var i = m_NotifyInfos.Count - 1; i >= 0; --i) { if (DateTime.Now.CompareTo(m_NotifyInfos[i].Expire) >= 0) { m_NotifyInfos.RemoveAt(i); } } next = DateTime.Now.AddSeconds(1); } Discord.Update(); UpdateVR(); var index = 0; // VR Overlay m_RenderTarget2.BeginDraw(); m_RenderTarget2.Clear(null); for (var i = Math.Max(0, m_NotifyInfos.Count - 10); i < m_NotifyInfos.Count; ++i) { var info = m_NotifyInfos[i]; m_RenderTarget2.FillRectangle(new RawRectangleF(0, 80 * i, 1024, 80 * i + 80), blackBrush2); m_RenderTarget2.DrawText(info.Text, textFormat4, new RawRectangleF(0, 80 * i, 1024, 80 * i + 65), whiteBrush2, DrawTextOptions.None); } m_RenderTarget2.EndDraw(); // Ingame m_RenderTarget.BeginDraw(); m_RenderTarget.Clear(backColor); m_RenderTarget.DrawText(DateTime.Now.ToString("yyyy/MM/dd (ddd) tt hh:mm:ss"), textFormat1, new RawRectangleF(0, 0, XS, 80), whiteBrush, DrawTextOptions.Clip); { var x = 5; var y = YS - 60; var cpu = PerformanceMonitor.CpuUsage; m_RenderTarget.DrawText("CPU", textFormat3, new RawRectangleF(x, y + 50, x, y + 50), whiteBrush, DrawTextOptions.None); m_RenderTarget.FillRectangle(new RawRectangleF(x + 115, y, x + 115 + 150, y + 48), whiteBrush); m_RenderTarget.FillRectangle(new RawRectangleF(x + 115, y, x + 115 + 150 * cpu / 100, y + 48), (cpu >= 80f) ? redBrush : (cpu >= 50f) ? goldBrush : limeBrush); m_RenderTarget.DrawText(cpu.ToString("N0") + "%", textFormat2, new RawRectangleF(x + 115, y, x + 115 + 150, y + 48), blackBrush, DrawTextOptions.Clip); // m_RenderTarget.DrawText(uptime, textFormat3, new RawRectangleF(660, YS - 10, 660, YS - 10), whiteBrush, DrawTextOptions.None); m_RenderTarget.DrawText("InRoom:" + VRChatLog.InRoom, textFormat3, new RawRectangleF(300, YS - 10, 300, YS - 10), whiteBrush, DrawTextOptions.None); } index = 0; for (var i = Math.Max(0, m_ActivityInfos.Count - 21); i < m_ActivityInfos.Count; ++i) { var info = m_ActivityInfos[i]; var brush = grayBrush; if (info.Type == ActivityType.EnterWorld) { brush = enterWorldBrush; } else if (info.Type == ActivityType.Moderation) { brush = blackBrush; m_RenderTarget.FillRectangle(new RawRectangleF(0, 300 + 55 * index, XS, 300 + 55 * index + 55), whiteBrush); } else if (info.Group >= 0) { switch (info.Type) { case ActivityType.PlayerJoined: brush = playerJoinBrush; break; case ActivityType.PlayerLeft: brush = playerLeftBrush; break; case ActivityType.PlayerLogin: brush = playerLoginBrush; break; case ActivityType.PlayerLogout: brush = playerLogoutBrush; break; case ActivityType.PlayerGPS: brush = playerGPSBrush; break; } switch (info.Group) { case 1: m_RenderTarget.FillRectangle(new RawRectangleF(0, 300 + 55 * index, XS, 300 + 55 * index + 55), group1Brush); break; case 2: m_RenderTarget.FillRectangle(new RawRectangleF(0, 300 + 55 * index, XS, 300 + 55 * index + 55), group2Brush); break; case 3: m_RenderTarget.FillRectangle(new RawRectangleF(0, 300 + 55 * index, XS, 300 + 55 * index + 55), group3Brush); break; } } else if (info.Type == ActivityType.PlayerJoined) { brush = lightGrayBrush; } m_RenderTarget.DrawText(info.Text, textFormat3, new RawRectangleF(5, 300 + 55 * index, XS - 5, 300 + 55 * index + 55), brush, DrawTextOptions.Clip); ++index; } index = 0; foreach (var info in m_DeviceInfos) { var x = 12 + (index % 6) * (150 + 20); var y = 100 + (index / 6) * (180 + 20); switch (info.Class) { case ETrackedDeviceClass.Controller: if (info.Oculus) { if (info.Role == ETrackedControllerRole.LeftHand) { DrawBitmap(m_RenderTarget, info.Connected ? info.BatteryPercentage >= 0.2f ? leftControllerReady : leftControllerReadyLow : leftControllerOff, x + 11, y); break; } if (info.Role == ETrackedControllerRole.RightHand) { DrawBitmap(m_RenderTarget, info.Connected ? info.BatteryPercentage >= 0.2f ? rightControllerReady : rightControllerReadyLow : rightControllerOff, x + 11, y); break; } } DrawBitmap(m_RenderTarget, info.Connected ? info.BatteryPercentage >= 0.2f ? controllerStatusReady : controllerStatusReadyLow : controllerStatusOff, x + 11, y); break; case ETrackedDeviceClass.GenericTracker: DrawBitmap(m_RenderTarget, info.Connected ? info.BatteryPercentage >= 0.2f ? trackerStatusReady : trackerStatusReadyLow : trackerStatusOff, x + 11, y); break; default: DrawBitmap(m_RenderTarget, info.Connected ? info.BatteryPercentage >= 0.2f ? otherStatusReady : otherStatusReadyLow : otherStatusOff, x + 11, y); break; } switch (info.Role) { case ETrackedControllerRole.LeftHand: m_RenderTarget.DrawText("L", textFormat2, new RawRectangleF(x, y + 10, x + 75, y + 10 + 48), whiteBrush, DrawTextOptions.Clip); break; case ETrackedControllerRole.RightHand: m_RenderTarget.DrawText("R", textFormat2, new RawRectangleF(x, y + 10, x + 75, y + 10 + 48), whiteBrush, DrawTextOptions.Clip); break; } y += 128 + 10; m_RenderTarget.FillRectangle(new RawRectangleF(x, y, x + 150, y + 48), whiteBrush); m_RenderTarget.FillRectangle(new RawRectangleF(x, y, x + 150 * info.BatteryPercentage, y + 48), (info.BatteryPercentage >= 0.5f) ? limeBrush : (info.BatteryPercentage >= 0.2f) ? goldBrush : redBrush); m_RenderTarget.DrawText((info.BatteryPercentage * 100f).ToString("N0") + "%", textFormat2, new RawRectangleF(x, y, x + 150, y + 48), blackBrush, DrawTextOptions.Clip); ++index; } if (index == 0) { m_RenderTarget.DrawText("No SteamVR Devices", textFormat2, new RawRectangleF(5, 100, XS - 5, 300), whiteBrush, DrawTextOptions.Clip); } m_RenderTarget.EndDraw(); m_SwapChain.Present(1, PresentFlags.None); RenderVR(); }); VRCApi.SaveCookie(); LocalConfig.SaveConfig(); Discord.Stop(); PerformanceMonitor.Stop(); }