using System; using System.Linq; using System.Text; using System.Drawing; using System.Collections.Generic; using BizHawk.Client.Common; using BizHawk.Bizware.BizwareGL; namespace BizHawk.Client.EmuHawk { /// /// This is an old abstracted rendering class that the OSD system is using to get its work done. /// We should probably just use a GuiRenderer (it was designed to do that) although wrapping it with /// more information for OSDRendering could be helpful I suppose /// public interface IBlitter { IBlitterFont GetFontType(string fontType); void DrawString(string s, IBlitterFont font, Color color, float x, float y); SizeF MeasureString(string s, IBlitterFont font); Rectangle ClipBounds { get; set; } } class UIMessage { public string Message; public DateTime ExpireAt; } class UIDisplay { public string Message; public int X; public int Y; public bool Alert; public int Anchor; public Color ForeColor; public Color BackGround; } public class OSDManager { public string FPS { get; set; } public string MT { get; set; } public IBlitterFont MessageFont; public IBlitterFont AlertFont; public void Dispose() { } public void Begin(IBlitter blitter) { MessageFont = blitter.GetFontType("MessageFont"); AlertFont = blitter.GetFontType("AlertFont"); } public System.Drawing.Color FixedMessagesColor { get { return System.Drawing.Color.FromArgb(Global.Config.MessagesColor); } } public System.Drawing.Color FixedAlertMessageColor { get { return System.Drawing.Color.FromArgb(Global.Config.AlertMessageColor); } } public OSDManager() { } private float GetX(IBlitter g, int x, int anchor, IBlitterFont font, string message) { var size = g.MeasureString(message, font); //Rectangle rect = g.MeasureString(Sprite, message, new DrawTextFormat()); switch (anchor) { default: case 0: //Top Left case 2: //Bottom Left return x; case 1: //Top Right case 3: //Bottom Right return g.ClipBounds.Width - x - size.Width; } } private float GetY(IBlitter g, int y, int anchor, IBlitterFont font, string message) { var size = g.MeasureString(message, font); switch (anchor) { default: case 0: //Top Left case 1: //Top Right return y; case 2: //Bottom Left case 3: //Bottom Right return g.ClipBounds.Height - y - size.Height; } } private string MakeFrameCounter() { if (Global.MovieSession.Movie.IsFinished) { var sb = new StringBuilder(); sb .Append(Global.Emulator.Frame) .Append('/') .Append(Global.MovieSession.Movie.FrameCount) .Append(" (Finished)"); return sb.ToString(); } else if (Global.MovieSession.Movie.IsPlaying) { var sb = new StringBuilder(); sb .Append(Global.Emulator.Frame) .Append('/') .Append(Global.MovieSession.Movie.FrameCount); return sb.ToString(); } else if (Global.MovieSession.Movie.IsRecording) { return Global.Emulator.Frame.ToString(); } else { return Global.Emulator.Frame.ToString(); } } private string MakeLagCounter() { return Global.Emulator.LagCount.ToString(); } private List messages = new List(5); private List GUITextList = new List(); public void AddMessage(string message) { GlobalWin.DisplayManager.NeedsToPaint = true; messages.Add(new UIMessage { Message = message, ExpireAt = DateTime.Now + TimeSpan.FromSeconds(2) }); } public void AddGUIText(string message, int x, int y, bool alert, Color BackGround, Color ForeColor, int anchor) { GlobalWin.DisplayManager.NeedsToPaint = true; GUITextList.Add(new UIDisplay { Message = message, X = x, Y = y, BackGround = BackGround, ForeColor = ForeColor, Alert = alert, Anchor = anchor }); } public void ClearGUIText() { GlobalWin.DisplayManager.NeedsToPaint = true; GUITextList.Clear(); } public void DrawMessages(IBlitter g) { if (!Global.ClientControls["MaxTurbo"]) { messages.RemoveAll(m => DateTime.Now > m.ExpireAt); int line = 1; if (Global.Config.StackOSDMessages) { for (int i = messages.Count - 1; i >= 0; i--, line++) { float x = GetX(g, Global.Config.DispMessagex, Global.Config.DispMessageanchor, MessageFont, messages[i].Message); float y = GetY(g, Global.Config.DispMessagey, Global.Config.DispMessageanchor, MessageFont, messages[i].Message); if (Global.Config.DispMessageanchor < 2) { y += ((line - 1) * 18); } else { y -= ((line - 1) * 18); } g.DrawString(messages[i].Message, MessageFont, Color.Black, x + 2, y + 2); g.DrawString(messages[i].Message, MessageFont, FixedMessagesColor, x, y); } } else { if (messages.Count > 0) { int i = messages.Count - 1; float x = GetX(g, Global.Config.DispMessagex, Global.Config.DispMessageanchor, MessageFont, messages[i].Message); float y = GetY(g, Global.Config.DispMessagey, Global.Config.DispMessageanchor, MessageFont, messages[i].Message); if (Global.Config.DispMessageanchor < 2) { y += ((line - 1) * 18); } else { y -= ((line - 1) * 18); } g.DrawString(messages[i].Message, MessageFont, Color.Black, x + 2, y + 2); g.DrawString(messages[i].Message, MessageFont, FixedMessagesColor, x, y); } } for (int x = 0; x < GUITextList.Count; x++) { try { float posx = GetX(g, GUITextList[x].X, GUITextList[x].Anchor, MessageFont, GUITextList[x].Message); float posy = GetY(g, GUITextList[x].Y, GUITextList[x].Anchor, MessageFont, GUITextList[x].Message); g.DrawString(GUITextList[x].Message, MessageFont, GUITextList[x].BackGround, posx + 2, posy + 2); //g.DrawString(GUITextList[x].Message, MessageFont, Color.Gray, posx + 1, posy + 1); if (GUITextList[x].Alert) g.DrawString(GUITextList[x].Message, AlertFont, FixedMessagesColor, posx, posy); else g.DrawString(GUITextList[x].Message, MessageFont, GUITextList[x].ForeColor, posx, posy); } catch (Exception) { return; } } } } public string MakeInputDisplay() { StringBuilder s; if (!Global.MovieSession.Movie.IsActive || Global.MovieSession.Movie.IsFinished) { s = new StringBuilder(Global.GetOutputControllersAsMnemonic()); } else { s = new StringBuilder(Global.MovieSession.Movie.GetInput(Global.Emulator.Frame - 1)); } s.Replace(".", " ").Replace("|", "").Replace(" 000, 000", " "); return s.ToString(); } public string MakeRerecordCount() { if (Global.MovieSession.Movie.IsActive) { return "Rerecord Count: " + Global.MovieSession.Movie.Header.Rerecords; } else { return String.Empty; } } /// /// Display all screen info objects like fps, frame counter, lag counter, and input display /// public void DrawScreenInfo(IBlitter g) { if (Global.Config.DisplayFrameCounter) { string message = MakeFrameCounter(); float x = GetX(g, Global.Config.DispFrameCx, Global.Config.DispFrameanchor, MessageFont, message); float y = GetY(g, Global.Config.DispFrameCy, Global.Config.DispFrameanchor, MessageFont, message); g.DrawString(message, MessageFont, Color.Black, x + 1, y + 1); g.DrawString(message, MessageFont, Color.FromArgb(Global.Config.MessagesColor), x, y); } if (Global.Config.DisplayInput) { string input = MakeInputDisplay(); Color c; float x = GetX(g, Global.Config.DispInpx, Global.Config.DispInpanchor, MessageFont, input); float y = GetY(g, Global.Config.DispInpy, Global.Config.DispInpanchor, MessageFont, input); if (Global.MovieSession.Movie.IsPlaying && !Global.MovieSession.Movie.IsRecording) { c = Color.FromArgb(Global.Config.MovieInput); } else { c = Color.FromArgb(Global.Config.MessagesColor); } g.DrawString(input, MessageFont, Color.Black, x + 1, y + 1); g.DrawString(input, MessageFont, c, x, y); } if (Global.MovieSession.MultiTrack.IsActive) { float x = GetX(g, Global.Config.DispMultix, Global.Config.DispMultianchor, MessageFont, MT); float y = GetY(g, Global.Config.DispMultiy, Global.Config.DispMultianchor, MessageFont, MT); g.DrawString(MT, MessageFont, Color.Black, x + 1, y + 1); g.DrawString(MT, MessageFont, FixedMessagesColor, x, y); } if (Global.Config.DisplayFPS && FPS != null) { float x = GetX(g, Global.Config.DispFPSx, Global.Config.DispFPSanchor, MessageFont, FPS); float y = GetY(g, Global.Config.DispFPSy, Global.Config.DispFPSanchor, MessageFont, FPS); g.DrawString(FPS, MessageFont, Color.Black, x + 1, y + 1); g.DrawString(FPS, MessageFont, FixedMessagesColor, x, y); } if (Global.Config.DisplayLagCounter) { string counter = MakeLagCounter(); if (Global.Emulator.IsLagFrame) { float x = GetX(g, Global.Config.DispLagx, Global.Config.DispLaganchor, AlertFont, counter); float y = GetY(g, Global.Config.DispLagy, Global.Config.DispLaganchor, AlertFont, counter); g.DrawString(counter, AlertFont, Color.Black, x + 1, y + 1); g.DrawString(counter, AlertFont, FixedAlertMessageColor, x, y); } else { float x = GetX(g, Global.Config.DispLagx, Global.Config.DispLaganchor, MessageFont, counter); float y = GetY(g, Global.Config.DispLagy, Global.Config.DispLaganchor, MessageFont, counter); g.DrawString(counter, MessageFont, Color.Black, x + 1, y + 1); g.DrawString(counter, MessageFont, FixedMessagesColor, x, y); } } if (Global.Config.DisplayRerecordCount) { string rerec = MakeRerecordCount(); float x = GetX(g, Global.Config.DispRecx, Global.Config.DispRecanchor, MessageFont, rerec); float y = GetY(g, Global.Config.DispRecy, Global.Config.DispRecanchor, MessageFont, rerec); g.DrawString(rerec, MessageFont, Color.Black, x + 1, y + 1); g.DrawString(rerec, MessageFont, FixedMessagesColor, x, y); } if (Global.ClientControls["Autohold"] || Global.ClientControls["Autofire"]) { StringBuilder disp = new StringBuilder("Held: "); foreach (string s in Global.StickyXORAdapter.CurrentStickies) { disp.Append(s); disp.Append(' '); } foreach (string s in Global.AutofireStickyXORAdapter.CurrentStickies) { disp.Append("Auto-"); disp.Append(s); disp.Append(' '); } g.DrawString(disp.ToString(), MessageFont, Color.White, GetX(g, Global.Config.DispAutoholdx, Global.Config.DispAutoholdanchor, MessageFont, disp.ToString()), GetY(g, Global.Config.DispAutoholdy, Global.Config.DispAutoholdanchor, MessageFont, disp.ToString())); } //TODO //if (Global.MovieSession.Movie.IsPlaying) //{ // //int r = (int)g.ClipBounds.Width; // //Point[] p = { new Point(r - 20, 2), // // new Point(r - 4, 12), // // new Point(r - 20, 22) }; // //g.FillPolygon(new SolidBrush(Color.Red), p); // //g.DrawPolygon(new Pen(new SolidBrush(Color.Pink)), p); //} //else if (Global.MovieSession.Movie.IsRecording) //{ // //g.FillEllipse(new SolidBrush(Color.Red), new Rectangle((int)g.ClipBounds.Width - 22, 2, 20, 20)); // //g.DrawEllipse(new Pen(new SolidBrush(Color.Pink)), new Rectangle((int)g.ClipBounds.Width - 22, 2, 20, 20)); //} if (Global.MovieSession.Movie.IsActive && Global.Config.DisplaySubtitles) { var subList = Global.MovieSession.Movie.Header.Subtitles.GetSubtitles(Global.Emulator.Frame).ToList(); for (int i = 0; i < subList.Count; i++) { g.DrawString(subList[i].Message, MessageFont, Color.Black, subList[i].X + 1, subList[i].Y + 1); g.DrawString(subList[i].Message, MessageFont, Color.FromArgb((int)subList[i].Color), subList[i].X, subList[i].Y); } } } } }