delete display manager threading. fix gdi+ leaks in lua code. add abstracted OSD drawing "blitter" system for sysdrawing/d3d dual compatibility and framework for future use for faster lua drawing.

This commit is contained in:
zeromus 2012-06-10 23:27:30 +00:00
parent e9983598c2
commit c7925d986c
4 changed files with 307 additions and 329 deletions

View File

@ -290,30 +290,27 @@ namespace BizHawk.MultiClient
{
public string FPS { get; set; }
public string MT { get; set; }
private Font MessageFont;
private Font AlertFont;
IBlitterFont MessageFont;
IBlitterFont AlertFont;
public void Dispose()
{
if (MessageFont != null)
{
MessageFont.Dispose();
MessageFont = null;
}
if (AlertFont != null)
{
AlertFont.Dispose();
AlertFont = null;
}
}
public OSDManager()
{
//MessageFont = new Font(Device, 16, 0, FontWeight.Bold, 1, false, CharacterSet.Default, Precision.Default, FontQuality.Default, PitchAndFamily.Default | PitchAndFamily.DontCare, "Courier");
//AlertFont = new Font(Device, 16, 0, FontWeight.ExtraBold, 1, true, CharacterSet.Default, Precision.Default, FontQuality.Default, PitchAndFamily.Default | PitchAndFamily.DontCare, "Courier");
MessageFont = new Font("Courier", 14, FontStyle.Bold, GraphicsUnit.Pixel);
AlertFont = new Font("Courier", 14, FontStyle.Bold, GraphicsUnit.Pixel);
}
private float GetX(Graphics g, int x, int anchor, Font font, string message)
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());
@ -329,7 +326,7 @@ namespace BizHawk.MultiClient
}
}
private float GetY(Graphics g, int y, int anchor, Font font, string message)
private float GetY(IBlitter g, int y, int anchor, IBlitterFont font, string message)
{
var size = g.MeasureString(message, font);
switch (anchor)
@ -377,9 +374,9 @@ namespace BizHawk.MultiClient
messages.Add(new UIMessage { Message = message, ExpireAt = DateTime.Now + TimeSpan.FromSeconds(2) });
}
public void AddGUIText(string message, int x, int y, bool alert, Brush BackGround, Brush ForeColor, int anchor)
public void AddGUIText(string message, int x, int y, bool alert, Color BackGround, Color ForeColor, int anchor)
{
GUITextList.Add(new UIDisplay { Message = message, X = x, Y = y, BackGround = BackGround, ForeColor = ForeColor, Alert = alert, Anchor = anchor });
GUITextList.Add(new UIDisplay { Message = message, X = x, Y = y, BackGround = BackGround, ForeColor = ForeColor, Alert = alert, Anchor = anchor });
}
public void ClearGUIText()
@ -388,7 +385,7 @@ namespace BizHawk.MultiClient
}
public void DrawMessages(Graphics g)
public void DrawMessages(IBlitter g)
{
//todo - not so much brush object churn?
@ -399,31 +396,29 @@ namespace BizHawk.MultiClient
{
float x = 3;
float y = g.ClipBounds.Height - (line * 18);
g.DrawString(messages[i].Message, MessageFont, Brushes.Black, x + 2, y + 2);
using(var brush = new SolidBrush(Color.FromArgb(Global.Config.MessagesColor)))
g.DrawString(messages[i].Message, MessageFont, brush, x, y);
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);
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, Brushes.Gray, posx + 1, posy + 1);
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)
using(var brush = new SolidBrush(Color.FromArgb(Global.Config.AlertMessageColor)))
g.DrawString(GUITextList[x].Message, MessageFont, brush, posx,posy);
else
g.DrawString(GUITextList[x].Message, MessageFont, GUITextList[x].ForeColor, posx, posy);
}
catch (Exception e)
{
return;
}
}
if (GUITextList[x].Alert)
g.DrawString(GUITextList[x].Message, MessageFont, FixedMessagesColor, posx, posy);
else
g.DrawString(GUITextList[x].Message, MessageFont, GUITextList[x].ForeColor, posx, posy);
}
catch (Exception e)
{
return;
}
}
}
@ -450,16 +445,15 @@ namespace BizHawk.MultiClient
/// <summary>
/// Display all screen info objects like fps, frame counter, lag counter, and input display
/// </summary>
public void DrawScreenInfo(Graphics g)
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, Brushes.Black, x + 1, y + 1);
using(var brush = new SolidBrush(Color.FromArgb(Global.Config.MessagesColor)))
g.DrawString(message, MessageFont, brush, x, y );
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)
{
@ -474,27 +468,24 @@ namespace BizHawk.MultiClient
else
c = Color.FromArgb(Global.Config.MessagesColor);
g.DrawString(input, MessageFont, Brushes.Black, x+1,y+1);
using(var brush = new SolidBrush(c))
g.DrawString(input, MessageFont, brush, x,y);
g.DrawString(input, MessageFont, Color.Black, x+1,y+1);
g.DrawString(input, MessageFont, c, x,y);
}
if (Global.MovieSession.MultiTrack.IsActive)
{
g.DrawString(MT, MessageFont, Brushes.Black,
g.DrawString(MT, MessageFont, Color.Black,
Global.Config.DispFPSx + 1, //TODO: Multitrack position variables
Global.Config.DispFPSy + 1);
using(var brush = new SolidBrush(Color.FromArgb(Global.Config.MessagesColor)))
g.DrawString(MT, MessageFont, Brushes.Black,
Global.Config.DispFPSx, //TODO: Multitrack position variables
Global.Config.DispFPSy);
g.DrawString(MT, MessageFont, FixedMessagesColor,
Global.Config.DispFPSx, //TODO: Multitrack position variables
Global.Config.DispFPSy);
}
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, Brushes.Black, x + 1, y + 1);
using(var brush = new SolidBrush(Color.FromArgb(Global.Config.MessagesColor)))
g.DrawString(FPS, MessageFont, brush, x, y);
g.DrawString(FPS, MessageFont, Color.Black, x + 1, y + 1);
g.DrawString(FPS, MessageFont, FixedMessagesColor, x, y);
}
if (Global.Config.DisplayLagCounter)
@ -505,21 +496,19 @@ namespace BizHawk.MultiClient
{
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(MakeLagCounter(), AlertFont, Brushes.Black,
g.DrawString(MakeLagCounter(), AlertFont, Color.Black,
Global.Config.DispLagx + 1,
Global.Config.DispLagy + 1);
using(var brush = new SolidBrush(Color.FromArgb(Global.Config.AlertMessageColor)))
g.DrawString(MakeLagCounter(), AlertFont, brush,
Global.Config.DispLagx,
Global.Config.DispLagy);
g.DrawString(MakeLagCounter(), AlertFont, FixedAlertMessageColor,
Global.Config.DispLagx,
Global.Config.DispLagy);
}
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, Brushes.Black, x + 1, y + 1);
using(var brush = new SolidBrush(Color.FromArgb(Global.Config.MessagesColor)))
g.DrawString(counter, MessageFont, brush, x , y );
g.DrawString(counter, MessageFont, Color.Black, x + 1, y + 1);
g.DrawString(counter, MessageFont, FixedMessagesColor, x , y );
}
}
@ -528,26 +517,26 @@ namespace BizHawk.MultiClient
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, Brushes.Black, x + 1, y + 1);
using(var brush = new SolidBrush(Color.FromArgb(Global.Config.MessagesColor)))
g.DrawString(rerec, MessageFont, brush, x , y);
g.DrawString(rerec, MessageFont, Color.Black, x + 1, y + 1);
g.DrawString(rerec, MessageFont, FixedMessagesColor, x, y);
}
if (Global.MovieSession.Movie.Mode == MOVIEMODE.PLAY)
{
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);
//TODO
//g.FillPolygon(new SolidBrush(Color.Red), p);
//g.DrawPolygon(new Pen(new SolidBrush(Color.Pink)), p);
}
else if (Global.MovieSession.Movie.Mode == MOVIEMODE.RECORD)
{
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));
//TODO
//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.Mode != MOVIEMODE.INACTIVE && Global.Config.DisplaySubtitles)
@ -557,11 +546,10 @@ namespace BizHawk.MultiClient
if (s == null) return;
for (int i = 0; i < s.Count; i++)
{
g.DrawString(s[i].Message, MessageFont, Brushes.Black,
g.DrawString(s[i].Message, MessageFont, Color.Black,
s[i].X + 1, s[i].Y + 1);
using (var brush = new SolidBrush(Color.FromArgb((int)s[i].Color)))
g.DrawString(s[i].Message, MessageFont, brush,
s[i].X, s[i].Y);
g.DrawString(s[i].Message, MessageFont, Color.FromArgb((int)s[i].Color),
s[i].X, s[i].Y);
}
}
@ -585,12 +573,6 @@ namespace BizHawk.MultiClient
{
//have at least something here at the start
luaNativeSurfacePreOSD = new DisplaySurface(1, 1);
wakeupEvent = new EventWaitHandle(false, EventResetMode.AutoReset);
suspendReplyEvent = new EventWaitHandle(false, EventResetMode.AutoReset);
displayThread = new Thread(ThreadProc);
displayThread.IsBackground = true;
displayThread.Start();
}
volatile bool VsyncToggle = false;
@ -598,31 +580,50 @@ namespace BizHawk.MultiClient
SwappableDisplaySurfaceSet sourceSurfaceSet = new SwappableDisplaySurfaceSet();
public void UpdateSource(IVideoProvider videoProvider)
{
VsyncRequested = Global.Config.DisplayVSync;
//needsclear = false because we're about to clobber the data with AcceptIntArray
var newPendingSurface = sourceSurfaceSet.AllocateSurface(videoProvider.BufferWidth, videoProvider.BufferHeight, false);
newPendingSurface.AcceptIntArray((int[])videoProvider.GetVideoBuffer().Clone());
newPendingSurface.AcceptIntArray(videoProvider.GetVideoBuffer());
sourceSurfaceSet.SetPending(newPendingSurface);
wakeupEvent.Set();
var renderPanel = Global.RenderPanel;
if (renderPanel == null) return;
if (VsyncRequested)
{
VsyncToggle = true;
currNativeWidth = Global.RenderPanel.NativeSize.Width;
currNativeHeight = Global.RenderPanel.NativeSize.Height;
//if we're configured to use a scaling filter, apply it now
//SHOULD THIS BE RUN REPEATEDLY?
//some filters may need to run repeatedly (temporal interpolation, ntsc scanline field alternating)
//but its sort of wasted work.
//IDisplayFilter filter = new Hq2xBase_Super2xSai();
//var tempSurface = filter.Execute(currentSourceSurface);
//currentSourceSurface.Dispose();
//currentSourceSurface = tempSurface;
currentSourceSurface = sourceSurfaceSet.GetCurrent();
if (currentSourceSurface == null) return;
int w = currNativeWidth;
int h = currNativeHeight;
DisplaySurface luaEmuSurface = luaEmuSurfaceSet.GetCurrent();
DisplaySurface luaSurface = luaNativeSurfaceSet.GetCurrent();
//do we have anything to do?
//bool complexComposite = false;
//if (luaEmuSurface != null) complexComposite = true;
//if (luaSurface != null) complexComposite = true;
Global.RenderPanel.Clear(Color.FromArgb(videoProvider.BackgroundColor));
Global.RenderPanel.Render(currentSourceSurface);
if (luaEmuSurface != null)
Global.RenderPanel.RenderOverlay(luaEmuSurface);
RenderOSD();
Global.RenderPanel.Present();
for (; ; )
{
//if (Direct3DRenderPanel.vsyncEvent.WaitOne(1)) break;
if (!VsyncToggle) break;
Application.DoEvents();
}
}
//for(;;)
//{
// if (Direct3DRenderPanel.vsyncEvent.WaitOne(1)) break;
// Application.DoEvents();
//}
}
public bool Disposed { get; private set; }
@ -630,10 +631,6 @@ namespace BizHawk.MultiClient
public void Dispose()
{
if (Disposed) return;
shutdownFlag = true;
VsyncToggle = true;
while (shutdownFlag) Thread.Sleep(1);
wakeupEvent.Dispose();
Disposed = true;
}
@ -663,42 +660,13 @@ namespace BizHawk.MultiClient
}
int currNativeWidth, currNativeHeight;
EventWaitHandle wakeupEvent, suspendReplyEvent;
bool shutdownFlag, suspendFlag;
void ThreadProc()
{
for (; ; )
{
Display();
//wait until we receive something interesting, or just a little while anyway
wakeupEvent.WaitOne(1);
if (suspendFlag)
{
suspendFlag = false;
suspendReplyEvent.Set();
wakeupEvent.WaitOne();
suspendReplyEvent.Set();
wakeupEvent.WaitOne();
suspendReplyEvent.Set();
}
if (shutdownFlag) break;
}
shutdownFlag = false;
}
/// <summary>
/// suspends the display manager so that tricky things can be changed without the display thread going in and getting all confused and hating
/// </summary>
public void Suspend()
{
suspendFlag = true;
wakeupEvent.Set();
suspendReplyEvent.WaitOne();
wakeupEvent.Set();
suspendReplyEvent.WaitOne();
}
/// <summary>
@ -706,126 +674,20 @@ namespace BizHawk.MultiClient
/// </summary>
public void Resume()
{
wakeupEvent.Set();
suspendReplyEvent.WaitOne();
}
void RenderOSD()
{
Global.OSD.Begin((IBlitter)Global.RenderPanel);
((IBlitter)Global.RenderPanel).Open();
Global.OSD.DrawScreenInfo((IBlitter)Global.RenderPanel);
Global.OSD.DrawMessages((IBlitter)Global.RenderPanel);
((IBlitter)Global.RenderPanel).Close();
}
SwappableDisplaySurfaceSet nativeDisplaySurfaceSet = new SwappableDisplaySurfaceSet();
/// <summary>
/// internal display worker proc; runs through the multiply layered display pipeline
/// </summary>
void Display()
{
var renderPanel = Global.RenderPanel;
if (renderPanel == null) return;
currNativeWidth = Global.RenderPanel.NativeSize.Width;
currNativeHeight = Global.RenderPanel.NativeSize.Height;
//if we're configured to use a scaling filter, apply it now
//SHOULD THIS BE RUN REPEATEDLY?
//some filters may need to run repeatedly (temporal interpolation, ntsc scanline field alternating)
//but its sort of wasted work.
//IDisplayFilter filter = new Hq2xBase_Super2xSai();
//var tempSurface = filter.Execute(currentSourceSurface);
//currentSourceSurface.Dispose();
//currentSourceSurface = tempSurface;
currentSourceSurface = sourceSurfaceSet.GetCurrent();
if (currentSourceSurface == null) return;
int w = currNativeWidth;
int h = currNativeHeight;
DisplaySurface luaEmuSurface = luaEmuSurfaceSet.GetCurrent();
DisplaySurface luaSurface = luaNativeSurfaceSet.GetCurrent();
//do we have anything to do?
bool complexComposite = false;
if (luaEmuSurface != null) complexComposite = true;
if (luaSurface != null) complexComposite = true;
if (!complexComposite)
{
if (Global.Config.SuppressGui)
{
Global.RenderPanel.Render(currentSourceSurface);
}
else
{
Global.RenderPanel.Render(currentSourceSurface);
var nativeBmp = nativeDisplaySurfaceSet.AllocateSurface(w, h, true);
using (var g = Graphics.FromImage(nativeBmp.PeekBitmap()))
{
Global.OSD.DrawScreenInfo(g);
Global.OSD.DrawMessages(g);
//Thread.Sleep(1);
}
nativeBmp.FromBitmap();
Global.RenderPanel.RenderOverlay(nativeBmp);
//release the native resolution image
nativeDisplaySurfaceSet.ReleaseSurface(nativeBmp);
//Global.RenderPanel.Present();
}
}
else
{
var nativeBmp = nativeDisplaySurfaceSet.AllocateSurface(w, h, true);
using (var g = Graphics.FromImage(nativeBmp.PeekBitmap()))
{
//scale the source bitmap to the desired size of the render panel
g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.CompositingMode = CompositingMode.SourceCopy;
g.CompositingQuality = CompositingQuality.HighSpeed;
g.DrawImage(currentSourceSurface.PeekBitmap(), 0, 0, w, h);
//switch to fancier composition for OSD overlays and such
g.CompositingMode = CompositingMode.SourceOver;
//this could have been done onto the source surface earlier and then scaled only once but the whole composition system needs revising, soo..
if (luaEmuSurface != null) g.DrawImage(luaEmuSurface.PeekBitmap(), 0, 0, w, h);
g.Clip = new Region(new Rectangle(0, 0, nativeBmp.Width, nativeBmp.Height));
//apply a lua layer
if (luaSurface != null) g.DrawImageUnscaled(luaSurface.PeekBitmap(), 0, 0);
//although we may want to change this if we want to fade out messages or have some other fancy alpha faded gui stuff
//draw the OSD at native resolution
if (!Global.Config.SuppressGui)
{
Global.OSD.DrawScreenInfo(g);
Global.OSD.DrawMessages(g);
}
g.Clip.Dispose();
}
//send the native resolution image to the render panel
Global.RenderPanel.Render(nativeBmp);
//Global.RenderPanel.Present();
//release the native resolution image
nativeDisplaySurfaceSet.ReleaseSurface(nativeBmp);
}
Global.RenderPanel.Present();
if (VsyncRequested)
{
for (; ; )
{
//if (Direct3DRenderPanel.vsyncEvent.WaitOne(1)) break;
if (VsyncToggle) break;
}
VsyncToggle = false;
}
}
Thread displayThread;
}
}

View File

@ -168,33 +168,28 @@ namespace BizHawk.MultiClient
return Convert.ToUInt32((double)lua_arg);
}
public Pen GetPen(object color)
{
System.Drawing.Pen myPen;
if (color.GetType() == typeof(Double))
{
myPen = new System.Drawing.Pen(System.Drawing.Color.FromArgb(int.Parse(long.Parse(color.ToString()).ToString("X"), System.Globalization.NumberStyles.HexNumber)));
}
else
{
myPen = new System.Drawing.Pen(System.Drawing.Color.FromName(color.ToString().ToLower()));
}
return myPen;
}
public SolidBrush GetBrush(object color)
{
System.Drawing.SolidBrush myBrush;
if (color.GetType() == typeof(Double))
{
myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.FromArgb(int.Parse(long.Parse(color.ToString()).ToString("X"), System.Globalization.NumberStyles.HexNumber)));
}
else
{
myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.FromName(color.ToString().ToLower()));
}
return myBrush;
}
public Color GetColor(object color)
{
if (color.GetType() == typeof(Double))
{
return System.Drawing.Color.FromArgb(int.Parse(long.Parse(color.ToString()).ToString("X"), System.Globalization.NumberStyles.HexNumber));
}
else
{
return System.Drawing.Color.FromName(color.ToString().ToLower());
}
}
public SolidBrush GetBrush(object color)
{
return new System.Drawing.SolidBrush(GetColor(color));
}
public Pen GetPen(object color)
{
return new System.Drawing.Pen(GetColor(color));
}
/**
* LuaInterface requires the exact match of parameter count,
@ -455,12 +450,12 @@ namespace BizHawk.MultiClient
a = LuaInt(anchor);
}
}
Global.OSD.AddGUIText(luaStr.ToString(), LuaInt(luaX), LuaInt(luaY), alert, GetBrush(background), GetBrush(forecolor), a);
Global.OSD.AddGUIText(luaStr.ToString(), LuaInt(luaX), LuaInt(luaY), alert, GetColor(background), GetColor(forecolor), a);
}
public void gui_text(object luaX, object luaY, object luaStr, object background = null, object forecolor = null, object anchor = null)
public void gui_text(object luaX, object luaY, object luaStr, object background = null, object forecolor = null, object anchor = null)
{
do_gui_text(luaX, luaY, luaStr, false, background, forecolor, anchor);
do_gui_text(luaX, luaY, luaStr, false, background, forecolor, anchor);
}
public void gui_alert(object luaX, object luaY, object luaStr, object anchor = null)
@ -524,7 +519,8 @@ namespace BizHawk.MultiClient
int int_height = LuaInt(height);
g.DrawRectangle(GetPen(line), int_x, int_y, int_width, int_height);
if (background != null)
g.FillRectangle(GetBrush(background), int_x, int_y, int_width, int_height);
using(var brush = GetBrush(background))
g.FillRectangle(brush, int_x, int_y, int_width, int_height);
}
catch(Exception)
{
@ -572,10 +568,14 @@ namespace BizHawk.MultiClient
{
try
{
g.DrawEllipse(GetPen(line), LuaInt(X), LuaInt(Y), LuaInt(width), LuaInt(height));
if (background != null)
using (var pen = GetPen(line))
{
g.FillEllipse(GetBrush(background), LuaInt(X), LuaInt(Y), LuaInt(width), LuaInt(height));
g.DrawEllipse(pen, LuaInt(X), LuaInt(Y), LuaInt(width), LuaInt(height));
if (background != null)
{
using (var brush = GetBrush(background))
g.FillEllipse(brush, LuaInt(X), LuaInt(Y), LuaInt(width), LuaInt(height));
}
}
}
@ -601,11 +601,15 @@ namespace BizHawk.MultiClient
Points[i] = new System.Drawing.Point(LuaInt(point[1]), LuaInt(point[2]));
i++;
}
g.DrawPolygon(GetPen(line), Points);
if (background != null)
using (var pen = GetPen(line))
{
g.FillPolygon(GetBrush(background), Points);
g.DrawPolygon(pen, Points);
if (background != null)
{
using (var brush = GetBrush(background))
g.FillPolygon(brush, Points);
}
}
}
catch (Exception)
@ -645,10 +649,14 @@ namespace BizHawk.MultiClient
{
try
{
g.DrawPie(GetPen(line), LuaInt(X), LuaInt(Y), LuaInt(width), LuaInt(height), LuaInt(startangle), LuaInt(sweepangle));
if (background != null)
using(var pen = GetPen(line))
{
g.FillPie(GetBrush(background), LuaInt(X), LuaInt(Y), LuaInt(width), LuaInt(height), LuaInt(startangle), LuaInt(sweepangle));
g.DrawPie(pen, LuaInt(X), LuaInt(Y), LuaInt(width), LuaInt(height), LuaInt(startangle), LuaInt(sweepangle));
if (background != null)
{
using(var brush = GetBrush(background))
g.FillPie(brush, LuaInt(X), LuaInt(Y), LuaInt(width), LuaInt(height), LuaInt(startangle), LuaInt(sweepangle));
}
}
}

View File

@ -2,6 +2,7 @@
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Drawing;
using sysdrawingfont=System.Drawing.Font;
using sysdrawing2d=System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
@ -11,7 +12,7 @@ using System.Windows.Forms;
#if WINDOWS
using SlimDX;
using SlimDX.Direct3D9;
using Font = SlimDX.Direct3D9.Font;
using d3d9font=SlimDX.Direct3D9.Font;
#endif
using BizHawk.Core;
@ -63,7 +64,6 @@ namespace BizHawk.MultiClient
}
}
// If we need to recreate the texture, do so.
if (needsRecreating)
{
@ -83,6 +83,8 @@ namespace BizHawk.MultiClient
Texture = new Texture(GraphicsDevice, textureWidth, textureHeight, 1, Usage.Dynamic, Format.A8R8G8B8, Pool.Default);
}
surface.FromBitmap();
// Copy the image data to the texture.
using (var Data = Texture.LockRectangle(0, LockFlags.Discard | LockFlags.NoDirtyUpdate).Data)
{
@ -122,34 +124,29 @@ namespace BizHawk.MultiClient
}
#endif
public interface IRenderer : IDisposable
{
void FastRenderAndPresent(DisplaySurface surface);
void Render(DisplaySurface surface);
void RenderOverlay(DisplaySurface surface);
void Clear(System.Drawing.Color color);
void Present();
bool Resized { get; set; }
Size NativeSize { get; }
}
public class SysdrawingRenderPanel : IRenderer
public class SysdrawingRenderPanel : IRenderer, IBlitter
{
sysdrawingfont MessageFont;
sysdrawingfont AlertFont;
DisplaySurface tempBuffer;
Graphics g;
public bool Resized { get; set; }
public void Dispose() { }
public void Render(DisplaySurface surface)
{
backingControl.ReleaseCallback = RetainedViewportPanelDisposeCallback;
//Color BackgroundColor = Color.FromArgb(video.BackgroundColor);
//int[] data = video.GetVideoBuffer();
//Bitmap bmp = new Bitmap(video.BufferWidth, video.BufferHeight, PixelFormat.Format32bppArgb);
//BitmapData bmpdata = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
////TODO - this is not very intelligent. no handling of pitch, for instance
//Marshal.Copy(data, 0, bmpdata.Scan0, bmp.Width * bmp.Height);
//bmp.UnlockBits(bmpdata);
lock(this)
tempBuffer = surfaceSet.AllocateSurface(backingControl.Width, backingControl.Height, false);
@ -158,7 +155,52 @@ namespace BizHawk.MultiClient
}
SwappableDisplaySurfaceSet surfaceSet = new SwappableDisplaySurfaceSet();
DisplaySurface tempBuffer;
class FontWrapper : IBlitterFont
{
public FontWrapper(sysdrawingfont font)
{
this.font = font;
}
public sysdrawingfont font;
}
public Size NativeSize { get { return backingControl.ClientSize; } }
IBlitterFont IBlitter.GetFontType(string fontType)
{
if (fontType == "MessageFont") return new FontWrapper(MessageFont);
if (fontType == "AlertFont") return new FontWrapper(AlertFont);
return null;
}
void IBlitter.Open()
{
g = Graphics.FromImage(tempBuffer.PeekBitmap());
}
void IBlitter.Close()
{
g.Dispose();
}
void IBlitter.DrawString(string s, IBlitterFont font, Color color, float x, float y)
{
using (var brush = new SolidBrush(color))
g.DrawString(s, ((FontWrapper)font).font, brush, x, y);
}
SizeF IBlitter.MeasureString(string s, IBlitterFont _font)
{
var font = ((FontWrapper)_font).font;
return g.MeasureString(s, font);
}
public void Clear(Color color)
{
//todo
}
Rectangle IBlitter.ClipBounds { get; set; }
bool RetainedViewportPanelDisposeCallback(Bitmap bmp)
{
@ -205,13 +247,28 @@ namespace BizHawk.MultiClient
public SysdrawingRenderPanel(RetainedViewportPanel control)
{
backingControl = control;
MessageFont = new sysdrawingfont("Courier", 14, FontStyle.Bold, GraphicsUnit.Pixel);
AlertFont = new sysdrawingfont("Courier", 14, FontStyle.Bold, GraphicsUnit.Pixel);
}
RetainedViewportPanel backingControl;
public Size NativeSize { get { return backingControl.ClientSize; } }
}
public interface IBlitter
{
void Open();
void Close();
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; }
}
public interface IBlitterFont { }
#if WINDOWS
public class Direct3DRenderPanel : IRenderer
public class Direct3DRenderPanel : IRenderer, IBlitter
{
public Color BackgroundColor { get; set; }
public bool Resized { get; set; }
@ -222,11 +279,48 @@ namespace BizHawk.MultiClient
private Control backingControl;
public ImageTexture Texture;
private Sprite Sprite;
private d3d9font MessageFont;
private d3d9font AlertFont;
class FontWrapper : IBlitterFont
{
public FontWrapper(d3d9font font)
{
this.font = font;
}
public d3d9font font;
}
void IBlitter.Open() {}
void IBlitter.Close() {}
private bool Vsync;
public Size NativeSize { get { return backingControl.ClientSize; } }
IBlitterFont IBlitter.GetFontType(string fontType)
{
if (fontType == "MessageFont") return new FontWrapper(MessageFont);
if (fontType == "AlertFont") return new FontWrapper(AlertFont);
return null;
}
Color4 col(Color c) { return new Color4(c.ToArgb()); }
void IBlitter.DrawString(string s, IBlitterFont font, Color color, float x, float y)
{
((FontWrapper)font).font.DrawString(null, s, (int)x + 1, (int)y + 1, col(color));
}
SizeF IBlitter.MeasureString(string s, IBlitterFont _font)
{
var font = ((FontWrapper)_font).font;
Rectangle r = font.MeasureString(null, s, DrawTextFormat.Left);
return new SizeF(r.Width, r.Height);
}
Rectangle IBlitter.ClipBounds { get; set; }
public Direct3DRenderPanel(Direct3D direct3D, Control control)
{
d3d = direct3D;
@ -259,6 +353,17 @@ namespace BizHawk.MultiClient
Device.Dispose();
Device = null;
}
if (MessageFont != null)
{
MessageFont.Dispose();
MessageFont = null;
}
if (AlertFont != null)
{
AlertFont.Dispose();
AlertFont = null;
}
}
private bool VsyncRequested
@ -291,6 +396,11 @@ namespace BizHawk.MultiClient
Sprite = new Sprite(Device);
Texture = new ImageTexture(Device);
MessageFont = new d3d9font(Device, 16, 0, FontWeight.Bold, 1, false, CharacterSet.Default, Precision.Default, FontQuality.Default, PitchAndFamily.Default | PitchAndFamily.DontCare, "Courier");
AlertFont = new d3d9font(Device, 16, 0, FontWeight.ExtraBold, 1, true, CharacterSet.Default, Precision.Default, FontQuality.Default, PitchAndFamily.Default | PitchAndFamily.DontCare, "Courier");
// NOTE: if you add ANY objects, like new fonts, textures, etc, to this method
// ALSO add dispose code in DestroyDevice() or you will be responsible for VRAM memory leaks.
}
public void Render()
@ -342,27 +452,27 @@ namespace BizHawk.MultiClient
}
}
void RenderPrep()
{
if (Device == null || Resized || Vsync != VsyncRequested)
backingControl.Invoke(() => CreateDevice());
Resized = false;
}
public void Clear(Color color)
{
Device.Clear(ClearFlags.Target, col(color), 0.0f, 0);
}
private void RenderExec(DisplaySurface surface, bool overlay)
{
RenderPrep();
if (surface == null)
{
Render();
return;
}
if (Device == null || Resized || Vsync != VsyncRequested)
backingControl.Invoke(() => CreateDevice());
Resized = false;
//TODO
//BackgroundColor = Color.FromArgb(video.BackgroundColor);
if (overlay)
{
//return;
}
Texture.SetImage(surface, surface.Width, surface.Height);
if(!overlay) Device.Clear(ClearFlags.Target, BackgroundColor, 0.0f, 0);
@ -380,7 +490,6 @@ namespace BizHawk.MultiClient
Device.SetSamplerState(0, SamplerState.MinFilter, TextureFilter.Point);
Sprite.Transform = Matrix.Scaling(finalScale, finalScale, 0f);
Sprite.Draw(Texture.Texture, new Rectangle(0, 0, surface.Width, surface.Height), new Vector3(surface.Width / 2f, surface.Height / 2f, 0), new Vector3(backingControl.Size.Width / 2f / finalScale, backingControl.Size.Height / 2f / finalScale, 0), Color.White);
//if (overlay) Device.SetRenderState(RenderState.AlphaBlendEnable, false);
Sprite.End();
Device.EndScene();
@ -388,7 +497,6 @@ namespace BizHawk.MultiClient
public void Present()
{
//Device.Present(SlimDX.Direct3D9.Present.DoNotWait);
Device.Present(SlimDX.Direct3D9.Present.None);
vsyncEvent.Set();
}
@ -423,7 +531,7 @@ namespace BizHawk.MultiClient
public int Y;
public bool Alert;
public int Anchor;
public Brush ForeColor;
public Brush BackGround;
public Color ForeColor;
public Color BackGround;
}
}

View File

@ -79,7 +79,7 @@ namespace BizHawk.MultiClient
{
bool alert = Global.CheatList.IsActiveCheat(Domain, watchList[x].address);
Global.OSD.AddGUIText(watchList[x].ToString(),
Global.Config.DispRamWatchx, (Global.Config.DispRamWatchy + (x * 14)), alert, Brushes.Black, Brushes.White, 0);
Global.Config.DispRamWatchx, (Global.Config.DispRamWatchy + (x * 14)), alert, Color.Black, Color.White, 0);
}
}