add threaded display manager to allow heavy OSD/compositing/filtering to happen on another thread. add a lua layer accessible via GDI+ which can be automatically composited and the simplest possible demo of it. add some filtering infrastructure and a hq2x filter set ported to c# but need to work on a minimal selector gui before its usable. separate OSD from RenderPanel so that gdi+ presentation mode now gets full OSD support. the OSD is now a little uglier because its drawn entirely differently and could use some finetuning

This commit is contained in:
zeromus 2012-04-16 08:18:41 +00:00
parent 0aa08984ed
commit 35fbe354c1
19 changed files with 1427 additions and 371 deletions

View File

@ -638,6 +638,15 @@ namespace BizHawk
bptr[i] = (byte)val;
}
public static unsafe void memset32(void* ptr, int val, int len)
{
System.Diagnostics.Debug.Assert(len % 4 == 0);
int dwords = len / 4;
int* dwptr = (int*)ptr;
for (int i = 0; i < dwords; i++)
dwptr[i] = val;
}
public static byte[] ReadAllBytes(Stream stream)
{
const int BUFF_SIZE = 4096;

View File

@ -158,6 +158,8 @@
<Compile Include="config\SoundConfig.Designer.cs">
<DependentUpon>SoundConfig.cs</DependentUpon>
</Compile>
<Compile Include="DisplayManager\DisplayManager.cs" />
<Compile Include="DisplayManager\Filters\Hq2x.cs" />
<Compile Include="Gameboy\Debugger.cs">
<SubType>Form</SubType>
</Compile>
@ -772,6 +774,7 @@
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

View File

@ -0,0 +1,688 @@
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
namespace BizHawk.MultiClient
{
public interface IDisplayFilter
{
/// <summary>
/// describes how this filter will respond to an input format
/// </summary>
DisplayFilterAnalysisReport Analyze(Size sourceSize);
/// <summary>
/// runs the filter
/// </summary>
DisplaySurface Execute(DisplaySurface surface);
}
public class DisplayFilterAnalysisReport
{
public bool Success;
public Size OutputSize;
}
public class DisplaySurface : IDisposable
{
/// <summary>
/// returns a Graphics object used to render to this surface. be sure to dispose it!
/// </summary>
public Graphics GetGraphics()
{
Unlock();
return Graphics.FromImage(bmp);
}
Bitmap bmp;
BitmapData bmpdata;
//TODO - lock and cache these
public unsafe int* PixelPtr { get { return (int*)bmpdata.Scan0.ToPointer(); } }
public IntPtr PixelIntPtr { get { return bmpdata.Scan0; } }
public int Stride { get { return bmpdata.Stride; } }
public int OffsetOf(int x, int y) { return y * Stride + x*4; }
public unsafe void Clear()
{
Lock();
Util.memset32(PixelPtr, 0, Stride * Height);
}
/// <summary>
/// returns a bitmap which you can use but not hold onto.
/// we may remove this later, as managing a Bitmap just for this may be a drag. (probably not though)
/// </summary>
public Bitmap PeekBitmap()
{
Unlock();
return bmp;
}
public DisplaySurface(int width, int height)
{
Width = width;
Height = height;
//can't create a bitmap with zero dimensions, so for now, just bump it up to one
if (width == 0) width = 1;
if (height == 0) height = 1;
bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb);
Lock();
}
/// <summary>
/// returns a new surface
/// </summary>
/// <param name="xpad"></param>
/// <param name="ypad"></param>
/// <returns></returns>
public unsafe DisplaySurface ToPaddedSurface(int xpad0, int ypad0, int xpad1, int ypad1)
{
Lock();
int new_width = Width + xpad0 + xpad1;
int new_height = Height + ypad0 + ypad1;
DisplaySurface ret = new DisplaySurface(new_width, new_height);
ret.Lock();
int* dptr = ret.PixelPtr;
int* sptr = PixelPtr;
int dstride = ret.Stride/4;
int sstride = Stride/4;
for (int y = 0; y < Height; y++)
for (int x = 0; x < Width; x++)
{
dptr[(y + ypad0) * dstride + x + xpad0] = sptr[y * sstride + x];
}
return ret;
}
public int Width { get; private set; }
public int Height { get; private set; }
public void Dispose()
{
if (bmp != null)
bmp.Dispose();
bmp = null;
}
/// <summary>
/// copies out the buffer as an int array (hopefully you can do this with a pointer instead and save some time!)
/// </summary>
public unsafe int[] ToIntArray()
{
Lock();
int w = bmp.Width;
int h = bmp.Height;
var ret = new int[bmp.Width * bmp.Height];
int* pData = (int*)bmpdata.Scan0.ToPointer();
int stride = bmpdata.Stride / 4;
for (int y = 0, i = 0; y < h; y++)
for (int x = 0; x < w; x++)
ret[i++] = pData[y * stride + x];
return ret;
}
public unsafe void SetFromIntArray(int[] pixels)
{
Lock();
if (Stride == Width * 4)
{
Marshal.Copy(pixels, 0, PixelIntPtr, Width * Height);
return;
}
int w = Width;
int h = Height;
int* pData = PixelPtr;
int stride = Stride / 4;
for (int y = 0, i = 0; y < h; y++)
for (int x = 0; x < w; x++)
pData[y * stride + x] = pixels[i++];
}
/// <summary>
/// locks this surface so that it can be accessed by raw pointer
/// </summary>
public void Lock()
{
if (bmpdata != null) return;
var imageLockMode = ImageLockMode.ReadWrite;
bmpdata = bmp.LockBits(new Rectangle(0, 0, Width, Height), imageLockMode, PixelFormat.Format32bppArgb);
}
public bool IsLocked { get { return bmpdata != null; } }
public void Unlock()
{
if (bmpdata != null)
bmp.UnlockBits(bmpdata);
bmpdata = null;
}
public static unsafe DisplaySurface FromVideoProvider(IVideoProvider provider)
{
int w = provider.BufferWidth;
int h = provider.BufferHeight;
int[] buffer = provider.GetVideoBuffer();
var ret = new DisplaySurface(w,h);
int* pData = ret.PixelPtr;
int stride = ret.Stride / 4;
for (int y = 0, i=0; y < h; y++)
for (int x = 0; x < w; x++)
pData[y * stride + x] = buffer[i++];
return ret;
}
}
public class OSDManager
{
public string FPS { get; set; }
public string MT { get; set; }
private Font MessageFont;
private Font 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", 16, FontStyle.Bold, GraphicsUnit.Pixel);
AlertFont = new Font("Courier", 16, FontStyle.Bold, GraphicsUnit.Pixel);
}
private float GetX(Graphics g, int x, int anchor, Font 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(Graphics g, int y, int anchor, Font 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.Mode == MOVIEMODE.FINISHED)
{
return Global.Emulator.Frame.ToString() + "/" + Global.MovieSession.Movie.Length().ToString() + " (Finished)";
}
else if (Global.MovieSession.Movie.Mode == MOVIEMODE.PLAY)
{
return Global.Emulator.Frame.ToString() + "/" + Global.MovieSession.Movie.Length().ToString();
}
else if (Global.MovieSession.Movie.Mode == MOVIEMODE.RECORD)
return Global.Emulator.Frame.ToString();
else
{
return Global.Emulator.Frame.ToString();
}
}
private string MakeLagCounter()
{
return Global.Emulator.LagCount.ToString();
}
private List<UIMessage> messages = new List<UIMessage>(5);
private List<UIDisplay> GUITextList = new List<UIDisplay>();
public void AddMessage(string message)
{
messages.Add(new UIMessage { Message = message, ExpireAt = DateTime.Now + TimeSpan.FromSeconds(2) });
}
public void AddGUIText(string message, int x, int y, bool alert, int anchor)
{
GUITextList.Add(new UIDisplay { Message = message, X = x, Y = y, Alert = alert, Anchor = anchor });
}
public void ClearGUIText()
{
GUITextList.Clear();
}
public void DrawMessages(Graphics g)
{
//todo - not so much brush object churn?
messages.RemoveAll(m => DateTime.Now > m.ExpireAt);
DrawScreenInfo(g);
int line = 1;
for (int i = messages.Count - 1; i >= 0; i--, line++)
{
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);
}
for (int x = 0; x < GUITextList.Count; x++)
{
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, Brushes.Black, posx + 2, posy + 2);
g.DrawString(GUITextList[x].Message, MessageFont, Brushes.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
using (var brush = new SolidBrush(Color.FromArgb(Global.Config.MessagesColor)))
g.DrawString(GUITextList[x].Message, MessageFont, brush, posx, posy);
}
}
public string MakeInputDisplay()
{
StringBuilder s;
if (Global.MovieSession.Movie.Mode == MOVIEMODE.INACTIVE || Global.MovieSession.Movie.Mode == MOVIEMODE.FINISHED)
s = new StringBuilder(Global.GetOutputControllersAsMnemonic());
else
s = new StringBuilder(Global.MovieSession.Movie.GetInputFrame(Global.Emulator.Frame - 1));
s.Replace(".", " ");
s.Replace("|", "");
return s.ToString();
}
public string MakeRerecordCount()
{
if (Global.MovieSession.Movie.Mode != MOVIEMODE.INACTIVE)
return "Rerecord Count: " + Global.MovieSession.Movie.Rerecords.ToString();
else
return "";
}
/// <summary>
/// Display all screen info objects like fps, frame counter, lag counter, and input display
/// </summary>
public void DrawScreenInfo(Graphics 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 );
}
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.Mode == MOVIEMODE.PLAY)
{
c = Color.FromArgb(Global.Config.MovieInput);
}
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);
}
if (Global.MovieSession.MultiTrack.IsActive)
{
g.DrawString(MT, MessageFont, Brushes.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);
}
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);
}
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(MakeLagCounter(), AlertFont, Brushes.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);
}
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 );
}
}
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, Brushes.Black, x + 1, y + 1);
using(var brush = new SolidBrush(Color.FromArgb(Global.Config.MessagesColor)))
g.DrawString(rerec, MessageFont, brush, x , y);
}
if (Global.MovieSession.Movie.Mode == MOVIEMODE.PLAY)
{
g.DrawString("Play", MessageFont,Brushes.Black,
g.ClipBounds.Width-47,
0+1);
using(var brush = new SolidBrush(Color.FromArgb(Global.Config.MovieColor)))
g.DrawString("Play", MessageFont, brush,
g.ClipBounds.Width-48,
0);
}
else if (Global.MovieSession.Movie.Mode == MOVIEMODE.RECORD)
{
g.DrawString("Record",AlertFont, Brushes.Black,
g.ClipBounds.Width-65,
0+1);
using(var brush = new SolidBrush(Color.FromArgb(Global.Config.MovieColor)))
g.DrawString("Record",AlertFont, brush,
g.ClipBounds.Width-64,
0);
}
if (Global.MovieSession.Movie.Mode != MOVIEMODE.INACTIVE && Global.Config.DisplaySubtitles)
{
//TODO: implement multiple subtitles at once feature
Subtitle s = Global.MovieSession.Movie.Subtitles.GetSubtitle(Global.Emulator.Frame);
g.DrawString(s.Message, MessageFont, Brushes.Black,
s.X + 1, s.Y + 1);
using(var brush = new SolidBrush(Color.FromArgb((int)s.Color)))
g.DrawString(s.Message, MessageFont, brush,
s.X , s.Y );
}
}
}
public class VideoProviderData : IVideoProvider
{
public int[] VideoBuffer;
public int BufferWidth { get; set; }
public int BufferHeight { get; set; }
public int BackgroundColor { get; set; }
public int[] GetVideoBuffer() { return VideoBuffer; }
}
public class DisplayManager : IDisposable
{
public DisplayManager()
{
//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();
}
SwappableDisplaySurfaceSet sourceSurfaceSet = new SwappableDisplaySurfaceSet();
public void UpdateSource(IVideoProvider videoProvider)
{
var newPendingSurface = sourceSurfaceSet.AllocateSurface(videoProvider.BufferWidth, videoProvider.BufferHeight, false);
newPendingSurface.SetFromIntArray(videoProvider.GetVideoBuffer());
sourceSurfaceSet.SetPending(newPendingSurface);
wakeupEvent.Set();
}
public bool Disposed { get; private set; }
public void Dispose()
{
if (Disposed) return;
shutdownFlag = true;
while (shutdownFlag) Thread.Sleep(1);
wakeupEvent.Dispose();
Disposed = true;
}
DisplaySurface currentSourceSurface;
//the surface to use to render a lua layer at native resolution (under the OSD)
DisplaySurface luaNativeSurfacePreOSD;
/// <summary>
/// encapsulates thread-safe concept of pending/current display surfaces, reusing buffers where matching
/// sizes are available and keeping them cleaned up when they dont seem like theyll need to be used anymore
/// </summary>
class SwappableDisplaySurfaceSet
{
DisplaySurface Pending, Current;
Queue<DisplaySurface> ReleasedSurfaces = new Queue<DisplaySurface>();
/// <summary>
/// retrieves a surface with the specified size, reusing an old buffer if available and clearing if requested
/// </summary>
public DisplaySurface AllocateSurface(int width, int height, bool needsClear=true)
{
for(;;)
{
DisplaySurface trial;
lock (this)
{
if (ReleasedSurfaces.Count == 0) break;
trial = ReleasedSurfaces.Dequeue();
}
if (trial.Width == width && trial.Height == height)
{
if(needsClear) trial.Clear();
return trial;
}
trial.Dispose();
}
return new DisplaySurface(width, height);
}
/// <summary>
/// sets the provided buffer as pending. takes control of the supplied buffer
/// </summary>
public void SetPending(DisplaySurface newPending)
{
lock(this)
{
if (Pending != null) ReleasedSurfaces.Enqueue(Pending);
Pending = newPending;
}
}
/// <summary>
/// returns the current buffer, making the most recent pending buffer (if there is such) as the new current first.
/// </summary>
public DisplaySurface GetCurrent()
{
lock(this)
{
if(Pending != null)
{
if (Current != null) ReleasedSurfaces.Enqueue(Current);
Current = Pending;
Pending = null;
}
}
return Current;
}
}
SwappableDisplaySurfaceSet luaNativeSurfaceSet = new SwappableDisplaySurfaceSet();
public void SetLuaSurfaceNativePreOSD(DisplaySurface surface) { luaNativeSurfaceSet.SetPending(surface); }
public DisplaySurface GetLuaSurfaceNative()
{
return luaNativeSurfaceSet.AllocateSurface(currNativeWidth, currNativeHeight);
}
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(10);
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>
/// resumes the display manager after a suspend
/// </summary>
public void Resume()
{
wakeupEvent.Set();
suspendReplyEvent.WaitOne();
}
/// <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;
using (var nativeBmp = new DisplaySurface(w,h))
{
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);
g.Clip = new Region(new Rectangle(0, 0, nativeBmp.Width, nativeBmp.Height));
//switch to fancier composition for OSD overlays and such
g.CompositingMode = CompositingMode.SourceOver;
//apply a lua layer
var luaSurface = luaNativeSurfaceSet.GetCurrent();
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
Global.OSD.DrawScreenInfo(g);
Global.OSD.DrawMessages(g);
g.Clip.Dispose();
}
//send the native resolution image to the render panel
Global.RenderPanel.Render(nativeBmp);
}
}
Thread displayThread;
}
}

View File

@ -0,0 +1,535 @@
using System;
using System.Text;
using System.Threading;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
//what license is this?? who knows??
//ref: http://vba-rerecording.googlecode.com/svn/trunk/src/2xsai.cpp
namespace BizHawk.MultiClient
{
class Hq2xBase_2xSai : Hq2xBase {}
class Hq2xBase_Super2xSai : Hq2xBase { }
class Hq2xBase_SuperEagle : Hq2xBase { }
public abstract class Hq2xBase : IDisplayFilter
{
public DisplayFilterAnalysisReport Analyze(Size sourceSize)
{
var ret = new DisplayFilterAnalysisReport();
ret.Success = true;
ret.OutputSize = new Size(sourceSize.Width * 2, sourceSize.Height * 2);
return ret;
}
public unsafe DisplaySurface Execute(DisplaySurface surface)
{
int w = surface.Width;
int h = surface.Height;
var ret = new DisplaySurface(w * 2, h * 2);
using (var padded = surface.ToPaddedSurface(1, 1, 2, 2))
{
if(this is Hq2xBase_2xSai) _2xSaI32((byte*)padded.PixelPtr + padded.OffsetOf(1, 1), (uint)(padded.Stride), null, (byte*)ret.PixelPtr, (uint)(ret.Stride), (uint)w, (uint)h);
if (this is Hq2xBase_Super2xSai) Super2xSaI32((byte*)padded.PixelPtr + padded.OffsetOf(1, 1), (uint)(padded.Stride), null, (byte*)ret.PixelPtr, (uint)(ret.Stride), (uint)w, (uint)h);
if (this is Hq2xBase_SuperEagle) SuperEagle32((byte*)padded.PixelPtr + padded.OffsetOf(1, 1), (uint)(padded.Stride), null, (byte*)ret.PixelPtr, (uint)(ret.Stride), (uint)w, (uint)h);
}
return ret;
}
static int GetResult1 (uint A, uint B, uint C, uint D, uint E )
{
int x = 0;
int y = 0;
int r = 0;
if (A == C)
x += 1;
else if (B == C)
y += 1;
if (A == D)
x += 1;
else if (B == D)
y += 1;
if (x <= 1)
r += 1;
if (y <= 1)
r -= 1;
return r;
}
static int GetResult2 (uint A, uint B, uint C, uint D, uint E )
{
int x = 0;
int y = 0;
int r = 0;
if (A == C)
x += 1;
else if (B == C)
y += 1;
if (A == D)
x += 1;
else if (B == D)
y += 1;
if (x <= 1)
r -= 1;
if (y <= 1)
r += 1;
return r;
}
static int GetResult (uint A, uint B, uint C, uint D)
{
int x = 0;
int y = 0;
int r = 0;
if (A == C)
x += 1;
else if (B == C)
y += 1;
if (A == D)
x += 1;
else if (B == D)
y += 1;
if (x <= 1)
r += 1;
if (y <= 1)
r -= 1;
return r;
}
const uint colorMask = 0xfefefe;
const uint lowPixelMask = 0x010101;
const uint qcolorMask = 0xfcfcfc;
const uint qlowpixelMask = 0x030303;
const uint redblueMask = 0xF81F;
const uint greenMask = 0x7E0;
static uint INTERPOLATE (uint A, uint B)
{
if (A != B) {
return (((A & colorMask) >> 1) + ((B & colorMask) >> 1) +
(A & B & lowPixelMask));
} else
return A;
}
static uint Q_INTERPOLATE(uint A, uint B, uint C, uint D)
{
uint x = ((A & qcolorMask) >> 2) +
((B & qcolorMask) >> 2) +
((C & qcolorMask) >> 2) + ((D & qcolorMask) >> 2);
uint y = (A & qlowpixelMask) +
(B & qlowpixelMask) + (C & qlowpixelMask) + (D & qlowpixelMask);
y = (y >> 2) & qlowpixelMask;
return x + y;
}
unsafe static void _2xSaI32 (byte *srcPtr, uint srcPitch, byte * deltaPtr ,
byte *dstPtr, uint dstPitch, uint width, uint height)
{
uint *dP;
uint *bP;
uint inc_bP = 1;
uint Nextline = srcPitch >> 2;
for (; height!=0; height--) {
bP = (uint *) srcPtr;
dP = (uint *) dstPtr;
for (uint finish = width; finish!=0; finish -= inc_bP) {
uint colorA, colorB;
uint colorC, colorD,
colorE, colorF, colorG, colorH,
colorI, colorJ, colorK, colorL,
colorM, colorN, colorO, colorP;
uint product, product1, product2;
//---------------------------------------
// Map of the pixels: I|E F|J
// G|A B|K
// H|C D|L
// M|N O|P
colorI = *(bP - Nextline - 1);
colorE = *(bP - Nextline);
colorF = *(bP - Nextline + 1);
colorJ = *(bP - Nextline + 2);
colorG = *(bP - 1);
colorA = *(bP);
colorB = *(bP + 1);
colorK = *(bP + 2);
colorH = *(bP + Nextline - 1);
colorC = *(bP + Nextline);
colorD = *(bP + Nextline + 1);
colorL = *(bP + Nextline + 2);
colorM = *(bP + Nextline + Nextline - 1);
colorN = *(bP + Nextline + Nextline);
colorO = *(bP + Nextline + Nextline + 1);
colorP = *(bP + Nextline + Nextline + 2);
if ((colorA == colorD) && (colorB != colorC)) {
if (((colorA == colorE) && (colorB == colorL)) ||
((colorA == colorC) && (colorA == colorF)
&& (colorB != colorE) && (colorB == colorJ))) {
product = colorA;
} else {
product = INTERPOLATE (colorA, colorB);
}
if (((colorA == colorG) && (colorC == colorO)) ||
((colorA == colorB) && (colorA == colorH)
&& (colorG != colorC) && (colorC == colorM))) {
product1 = colorA;
} else {
product1 = INTERPOLATE (colorA, colorC);
}
product2 = colorA;
} else if ((colorB == colorC) && (colorA != colorD)) {
if (((colorB == colorF) && (colorA == colorH)) ||
((colorB == colorE) && (colorB == colorD)
&& (colorA != colorF) && (colorA == colorI))) {
product = colorB;
} else {
product = INTERPOLATE (colorA, colorB);
}
if (((colorC == colorH) && (colorA == colorF)) ||
((colorC == colorG) && (colorC == colorD)
&& (colorA != colorH) && (colorA == colorI))) {
product1 = colorC;
} else {
product1 = INTERPOLATE (colorA, colorC);
}
product2 = colorB;
} else if ((colorA == colorD) && (colorB == colorC)) {
if (colorA == colorB) {
product = colorA;
product1 = colorA;
product2 = colorA;
} else {
int r = 0;
product1 = INTERPOLATE (colorA, colorC);
product = INTERPOLATE (colorA, colorB);
r += GetResult1 (colorA, colorB, colorG, colorE, colorI);
r += GetResult2 (colorB, colorA, colorK, colorF, colorJ);
r += GetResult2 (colorB, colorA, colorH, colorN, colorM);
r += GetResult1 (colorA, colorB, colorL, colorO, colorP);
if (r > 0)
product2 = colorA;
else if (r < 0)
product2 = colorB;
else {
product2 = Q_INTERPOLATE (colorA, colorB, colorC, colorD);
}
}
} else {
product2 = Q_INTERPOLATE (colorA, colorB, colorC, colorD);
if ((colorA == colorC) && (colorA == colorF)
&& (colorB != colorE) && (colorB == colorJ)) {
product = colorA;
} else if ((colorB == colorE) && (colorB == colorD)
&& (colorA != colorF) && (colorA == colorI)) {
product = colorB;
} else {
product = INTERPOLATE (colorA, colorB);
}
if ((colorA == colorB) && (colorA == colorH)
&& (colorG != colorC) && (colorC == colorM)) {
product1 = colorA;
} else if ((colorC == colorG) && (colorC == colorD)
&& (colorA != colorH) && (colorA == colorI)) {
product1 = colorC;
} else {
product1 = INTERPOLATE (colorA, colorC);
}
}
*(dP) = colorA | 0xFF000000;
*(dP + 1) = product | 0xFF000000;
*(dP + (dstPitch >> 2)) = product1 | 0xFF000000;
*(dP + (dstPitch >> 2) + 1) = product2 | 0xFF000000;
bP += inc_bP;
dP += 2;
} // end of for ( finish= width etc..)
srcPtr += srcPitch;
dstPtr += dstPitch * 2;
// deltaPtr += srcPitch;
} // endof: for (height; height; height--)
}
unsafe void SuperEagle32 (byte *srcPtr, uint srcPitch, byte * deltaPtr,
byte* dstPtr, uint dstPitch, uint width, uint height)
{
uint *dP;
uint *bP;
// uint *xP;
uint inc_bP;
inc_bP = 1;
uint Nextline = srcPitch >> 2;
for (; height!=0; height--) {
bP = (uint *) srcPtr;
// xP = (uint *) deltaPtr;
dP = (uint *)dstPtr;
for (uint finish = width; finish!=0; finish -= inc_bP) {
uint color4, color5, color6;
uint color1, color2, color3;
uint colorA1, colorA2, colorB1, colorB2, colorS1, colorS2;
uint product1a, product1b, product2a, product2b;
colorB1 = *(bP - Nextline);
colorB2 = *(bP - Nextline + 1);
color4 = *(bP - 1);
color5 = *(bP);
color6 = *(bP + 1);
colorS2 = *(bP + 2);
color1 = *(bP + Nextline - 1);
color2 = *(bP + Nextline);
color3 = *(bP + Nextline + 1);
colorS1 = *(bP + Nextline + 2);
colorA1 = *(bP + Nextline + Nextline);
colorA2 = *(bP + Nextline + Nextline + 1);
// --------------------------------------
if (color2 == color6 && color5 != color3) {
product1b = product2a = color2;
if ((color1 == color2) || (color6 == colorB2)) {
product1a = INTERPOLATE (color2, color5);
product1a = INTERPOLATE (color2, product1a);
// product1a = color2;
} else {
product1a = INTERPOLATE (color5, color6);
}
if ((color6 == colorS2) || (color2 == colorA1)) {
product2b = INTERPOLATE (color2, color3);
product2b = INTERPOLATE (color2, product2b);
// product2b = color2;
} else {
product2b = INTERPOLATE (color2, color3);
}
} else if (color5 == color3 && color2 != color6) {
product2b = product1a = color5;
if ((colorB1 == color5) || (color3 == colorS1)) {
product1b = INTERPOLATE (color5, color6);
product1b = INTERPOLATE (color5, product1b);
// product1b = color5;
} else {
product1b = INTERPOLATE (color5, color6);
}
if ((color3 == colorA2) || (color4 == color5)) {
product2a = INTERPOLATE (color5, color2);
product2a = INTERPOLATE (color5, product2a);
// product2a = color5;
} else {
product2a = INTERPOLATE (color2, color3);
}
} else if (color5 == color3 && color2 == color6) {
int r = 0;
r += GetResult (color6, color5, color1, colorA1);
r += GetResult (color6, color5, color4, colorB1);
r += GetResult (color6, color5, colorA2, colorS1);
r += GetResult (color6, color5, colorB2, colorS2);
if (r > 0) {
product1b = product2a = color2;
product1a = product2b = INTERPOLATE (color5, color6);
} else if (r < 0) {
product2b = product1a = color5;
product1b = product2a = INTERPOLATE (color5, color6);
} else {
product2b = product1a = color5;
product1b = product2a = color2;
}
} else {
product2b = product1a = INTERPOLATE (color2, color6);
product2b =
Q_INTERPOLATE (color3, color3, color3, product2b);
product1a =
Q_INTERPOLATE (color5, color5, color5, product1a);
product2a = product1b = INTERPOLATE (color5, color3);
product2a =
Q_INTERPOLATE (color2, color2, color2, product2a);
product1b =
Q_INTERPOLATE (color6, color6, color6, product1b);
// product1a = color5;
// product1b = color6;
// product2a = color2;
// product2b = color3;
}
*(dP) = product1a | 0xFF000000;
*(dP+1) = product1b | 0xFF000000;
*(dP + (dstPitch >> 2)) = product2a | 0xFF000000;
*(dP + (dstPitch >> 2) +1) = product2b | 0xFF000000;
// *xP = color5;
bP += inc_bP;
// xP += inc_bP;
dP += 2;
} // end of for ( finish= width etc..)
srcPtr += srcPitch;
dstPtr += dstPitch * 2;
// deltaPtr += srcPitch;
} // endof: for (height; height; height--)
}
unsafe void Super2xSaI32 (byte *srcPtr, uint srcPitch,
byte * deltaPtr , byte *dstPtr, uint dstPitch,
uint width, uint height)
{
uint *bP;
uint *dP;
uint inc_bP;
uint Nextline = srcPitch >> 2;
inc_bP = 1;
for (; height!=0; height--) {
bP = (uint *) srcPtr;
dP = (uint *) dstPtr;
for (uint finish = width; finish!=0; finish -= inc_bP) {
uint color4, color5, color6;
uint color1, color2, color3;
uint colorA0, colorA1, colorA2, colorA3,
colorB0, colorB1, colorB2, colorB3, colorS1, colorS2;
uint product1a, product1b, product2a, product2b;
//--------------------------------------- B1 B2
// 4 5 6 S2
// 1 2 3 S1
// A1 A2
colorB0 = *(bP - Nextline - 1);
colorB1 = *(bP - Nextline);
colorB2 = *(bP - Nextline + 1);
colorB3 = *(bP - Nextline + 2);
color4 = *(bP - 1);
color5 = *(bP);
color6 = *(bP + 1);
colorS2 = *(bP + 2);
color1 = *(bP + Nextline - 1);
color2 = *(bP + Nextline);
color3 = *(bP + Nextline + 1);
colorS1 = *(bP + Nextline + 2);
colorA0 = *(bP + Nextline + Nextline - 1);
colorA1 = *(bP + Nextline + Nextline);
colorA2 = *(bP + Nextline + Nextline + 1);
colorA3 = *(bP + Nextline + Nextline + 2);
//--------------------------------------
if (color2 == color6 && color5 != color3) {
product2b = product1b = color2;
} else if (color5 == color3 && color2 != color6) {
product2b = product1b = color5;
} else if (color5 == color3 && color2 == color6) {
int r = 0;
r += GetResult (color6, color5, color1, colorA1);
r += GetResult (color6, color5, color4, colorB1);
r += GetResult (color6, color5, colorA2, colorS1);
r += GetResult (color6, color5, colorB2, colorS2);
if (r > 0)
product2b = product1b = color6;
else if (r < 0)
product2b = product1b = color5;
else {
product2b = product1b = INTERPOLATE (color5, color6);
}
} else {
if (color6 == color3 && color3 == colorA1
&& color2 != colorA2 && color3 != colorA0)
product2b =
Q_INTERPOLATE (color3, color3, color3, color2);
else if (color5 == color2 && color2 == colorA2
&& colorA1 != color3 && color2 != colorA3)
product2b =
Q_INTERPOLATE (color2, color2, color2, color3);
else
product2b = INTERPOLATE (color2, color3);
if (color6 == color3 && color6 == colorB1
&& color5 != colorB2 && color6 != colorB0)
product1b =
Q_INTERPOLATE (color6, color6, color6, color5);
else if (color5 == color2 && color5 == colorB2
&& colorB1 != color6 && color5 != colorB3)
product1b =
Q_INTERPOLATE (color6, color5, color5, color5);
else
product1b = INTERPOLATE (color5, color6);
}
if (color5 == color3 && color2 != color6 && color4 == color5
&& color5 != colorA2)
product2a = INTERPOLATE (color2, color5);
else
if (color5 == color1 && color6 == color5
&& color4 != color2 && color5 != colorA0)
product2a = INTERPOLATE (color2, color5);
else
product2a = color2;
if (color2 == color6 && color5 != color3 && color1 == color2
&& color2 != colorB2)
product1a = INTERPOLATE (color2, color5);
else
if (color4 == color2 && color3 == color2
&& color1 != color5 && color2 != colorB0)
product1a = INTERPOLATE (color2, color5);
else
product1a = color5;
*(dP) = product1a | 0xFF000000;
*(dP + 1) = product1b | 0xFF000000;
*(dP + (dstPitch >> 2)) = product2a | 0xFF000000;
*(dP + (dstPitch >> 2) + 1) = product2b | 0xFF000000;
bP += inc_bP;
dP += 2;
} // end of for ( finish= width etc..)
srcPtr += srcPitch;
dstPtr += dstPitch * 2;
// deltaPtr += srcPitch;
} // endof: for (; height; height--)
}
}
}

View File

@ -16,6 +16,8 @@ namespace BizHawk.MultiClient
#endif
public static Sound Sound;
public static IRenderer RenderPanel;
public static OSDManager OSD = new OSDManager();
public static DisplayManager DisplayManager = new DisplayManager();
public static Config Config;
public static IEmulator Emulator;
public static CoreInputComm CoreInputComm;

View File

@ -221,7 +221,10 @@ namespace BizHawk.MultiClient
{
"text",
"alert",
"cleartext",
"cleartext",
"drawNew",
"drawRectangle",
"drawFinish",
};
public static string[] EmuFunctions = new string[]
@ -414,7 +417,7 @@ namespace BizHawk.MultiClient
a = LuaInt(anchor);
}
}
Global.RenderPanel.AddGUIText(luaStr.ToString(), LuaInt(luaX), LuaInt(luaY), alert, a);
Global.OSD.AddGUIText(luaStr.ToString(), LuaInt(luaX), LuaInt(luaY), alert, a);
}
public void gui_text(object luaX, object luaY, object luaStr, object anchor = null)
@ -427,10 +430,48 @@ namespace BizHawk.MultiClient
do_gui_text(luaX, luaY, luaStr, true, anchor);
}
public void gui_cleartext()
{
Global.RenderPanel.ClearGUIText();
}
public void gui_cleartext()
{
Global.OSD.ClearGUIText();
}
DisplaySurface luaSurface;
/// <summary>
/// sets the current drawing context to a new surface.
/// you COULD pass these back to lua to use as a target in rendering jobs, instead of setting it as current here.
/// could be more powerful.
/// performance test may reveal that repeatedly calling GetGraphics could be slow.
/// we may want to make a class here in LuaImplementation that wraps a DisplaySurface and a Graphics which would be created once
/// </summary>
public void gui_drawNew()
{
luaSurface = Global.DisplayManager.GetLuaSurfaceNative();
}
/// <summary>
/// finishes the current drawing and submits it to the display manager (at native [host] resolution pre-osd)
/// you would probably want some way to specify which surface to set it to, when there are other surfaces.
/// most notably, the client output [emulated] resolution
/// </summary>
public void gui_drawFinish()
{
Global.DisplayManager.SetLuaSurfaceNativePreOSD(luaSurface);
luaSurface = null;
}
/// <summary>
/// draws a random rectangle for testing purposes
/// </summary>
public void gui_drawRectangle()
{
var r = new Random((int)DateTime.Now.Ticks);
using (var g = luaSurface.GetGraphics())
{
g.DrawRectangle(System.Drawing.Pens.Black, new System.Drawing.Rectangle(r.Next(100), r.Next(100), 100, 100));
}
}
//----------------------------------------------------
//Emu library

View File

@ -7,18 +7,7 @@
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code

View File

@ -458,6 +458,7 @@ namespace BizHawk.MultiClient
private void forceGDIPPresentationToolStripMenuItem_Click(object sender, EventArgs e)
{
Global.Config.DisplayGDI ^= true;
Global.DisplayManager.Suspend();
SyncPresentationMode();
}
@ -1121,13 +1122,13 @@ namespace BizHawk.MultiClient
private void saveConfigToolStripMenuItem_Click(object sender, EventArgs e)
{
SaveConfig();
Global.RenderPanel.AddMessage("Saved settings");
Global.OSD.AddMessage("Saved settings");
}
private void loadConfigToolStripMenuItem_Click(object sender, EventArgs e)
{
Global.Config = ConfigService.Load<Config>(PathManager.DefaultIniPath, Global.Config);
Global.RenderPanel.AddMessage("Saved loaded");
Global.OSD.AddMessage("Saved loaded");
}
private void frameSkipToolStripMenuItem_DropDownOpened(object sender, EventArgs e)
@ -1416,7 +1417,7 @@ namespace BizHawk.MultiClient
{
string path = PathManager.SaveStatePrefix(Global.Game) + "." + "QuickSave" + Global.Config.SaveSlot + ".State";
SwapBackupSavestate(path);
Global.RenderPanel.AddMessage("Save slot " + Global.Config.SaveSlot.ToString() + " restored.");
Global.OSD.AddMessage("Save slot " + Global.Config.SaveSlot.ToString() + " restored.");
}
private void FreezeStatus_Click(object sender, EventArgs e)

View File

@ -94,7 +94,7 @@ namespace BizHawk.MultiClient
}
Global.MovieSession.Movie.StartPlayback();
SetMainformMovieInfo();
Global.RenderPanel.AddMessage("Replaying movie file in read-only mode");
Global.OSD.AddMessage("Replaying movie file in read-only mode");
Global.MainForm.ReadOnly = true;
}
}
@ -111,7 +111,7 @@ namespace BizHawk.MultiClient
if (Global.MovieSession.Movie.Mode != MOVIEMODE.INACTIVE)
{
Global.MovieSession.Movie.StopMovie();
Global.RenderPanel.AddMessage(message);
Global.OSD.AddMessage(message);
SetMainformMovieInfo();
Global.MainForm.ReadOnly = true;
}

View File

@ -255,6 +255,22 @@ namespace BizHawk.MultiClient
}
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if(Global.DisplayManager != null) Global.DisplayManager.Dispose();
Global.DisplayManager = null;
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
void SyncCoreInputComm()
{
Global.CoreInputComm.NES_BackdropColor = Global.Config.NESBackgroundColor;
@ -271,6 +287,8 @@ namespace BizHawk.MultiClient
void SyncPresentationMode()
{
Global.DisplayManager.Suspend();
#if WINDOWS
bool gdi = Global.Config.DisplayGDI;
@ -325,6 +343,8 @@ namespace BizHawk.MultiClient
}
}
#endif
Global.DisplayManager.Resume();
}
void SyncThrottle()
@ -346,14 +366,14 @@ namespace BizHawk.MultiClient
{
Global.Config.SpeedPercentAlternate = value;
SyncThrottle();
Global.RenderPanel.AddMessage("Alternate Speed: " + value + "%");
Global.OSD.AddMessage("Alternate Speed: " + value + "%");
}
void SetSpeedPercent(int value)
{
Global.Config.SpeedPercent = value;
SyncThrottle();
Global.RenderPanel.AddMessage("Speed: " + value + "%");
Global.OSD.AddMessage("Speed: " + value + "%");
}
public void ProgramRunLoop()
@ -831,7 +851,7 @@ namespace BizHawk.MultiClient
MessageBox.Show(errorMsg, "Conversion error", MessageBoxButtons.OK, MessageBoxIcon.Error);
else
StartNewMovie(m, false);
Global.RenderPanel.AddMessage(warningMsg);
Global.OSD.AddMessage(warningMsg);
}
else
LoadRom(filePaths[0]);
@ -1240,12 +1260,16 @@ namespace BizHawk.MultiClient
Text = DisplayNameForSystem(game.System) + " - " + game.Name;
ResetRewindBuffer();
if (Global.Config.RecentRoms.GetRecentFileByPosition(0) != file.CanonicalFullPath)
{
//restarts the lua console if a different rom is loaded.
//im not really a fan of how this is done..
if (Global.Config.RecentRoms.IsEmpty() || Global.Config.RecentRoms.GetRecentFileByPosition(0) != file.CanonicalFullPath)
{
#if WINDOWS
LuaConsole1.Restart();
LuaConsole1.Restart();
#endif
}
}
Global.Config.RecentRoms.Add(file.CanonicalFullPath);
if (File.Exists(PathManager.SaveRamPath(game)))
LoadSaveRam();
@ -1273,7 +1297,7 @@ namespace BizHawk.MultiClient
if (Global.Config.LoadCheatFileByGame)
{
if (Global.CheatList.AttemptLoadCheatFile())
Global.RenderPanel.AddMessage("Cheats file loaded");
Global.OSD.AddMessage("Cheats file loaded");
}
CurrentlyOpenRom = file.CanonicalFullPath;
@ -1325,6 +1349,11 @@ namespace BizHawk.MultiClient
DumpStatus.Image = BizHawk.MultiClient.Properties.Resources.Hack;
annotation = "Hacked ROM";
}
else if (Global.Game.Status == RomStatus.Unknown)
{
DumpStatus.Image = BizHawk.MultiClient.Properties.Resources.Hack;
annotation = "Warning: ROM of Unknown Character";
}
else
{
DumpStatus.Image = BizHawk.MultiClient.Properties.Resources.GreenCheck;
@ -1506,7 +1535,7 @@ namespace BizHawk.MultiClient
case "Unthrottle":
unthrottled ^= true;
Global.RenderPanel.AddMessage("Unthrottled: " + unthrottled);
Global.OSD.AddMessage("Unthrottled: " + unthrottled);
break;
case "Hard Reset":
@ -1611,17 +1640,17 @@ namespace BizHawk.MultiClient
Global.MovieSession.MultiTrack.IsActive = !Global.MovieSession.MultiTrack.IsActive;
if (Global.MovieSession.MultiTrack.IsActive)
{
Global.RenderPanel.AddMessage("MultiTrack Enabled");
Global.RenderPanel.MT = "Recording None";
Global.OSD.AddMessage("MultiTrack Enabled");
Global.OSD.MT = "Recording None";
}
else
Global.RenderPanel.AddMessage("MultiTrack Disabled");
Global.OSD.AddMessage("MultiTrack Disabled");
Global.MovieSession.MultiTrack.RecordAll = false;
Global.MovieSession.MultiTrack.CurrentPlayer = 0;
}
else
{
Global.RenderPanel.AddMessage("MultiTrack cannot be enabled while not recording.");
Global.OSD.AddMessage("MultiTrack cannot be enabled while not recording.");
}
break;
}
@ -1633,7 +1662,7 @@ namespace BizHawk.MultiClient
{
Global.MovieSession.MultiTrack.CurrentPlayer = 1;
}
Global.RenderPanel.MT = "Recording Player " + Global.MovieSession.MultiTrack.CurrentPlayer.ToString();
Global.OSD.MT = "Recording Player " + Global.MovieSession.MultiTrack.CurrentPlayer.ToString();
break;
}
@ -1645,21 +1674,21 @@ namespace BizHawk.MultiClient
{
Global.MovieSession.MultiTrack.CurrentPlayer = 5;//TODO: Replace with console's maximum or current maximum players??!
}
Global.RenderPanel.MT = "Recording Player " + Global.MovieSession.MultiTrack.CurrentPlayer.ToString();
Global.OSD.MT = "Recording Player " + Global.MovieSession.MultiTrack.CurrentPlayer.ToString();
break;
}
case "Record All":
{
Global.MovieSession.MultiTrack.CurrentPlayer = 0;
Global.MovieSession.MultiTrack.RecordAll = true;
Global.RenderPanel.MT = "Recording All";
Global.OSD.MT = "Recording All";
break;
}
case "Record None":
{
Global.MovieSession.MultiTrack.CurrentPlayer = 0;
Global.MovieSession.MultiTrack.RecordAll = false;
Global.RenderPanel.MT = "Recording None";
Global.OSD.MT = "Recording None";
break;
}
case "Emulator Pause":
@ -1748,7 +1777,7 @@ namespace BizHawk.MultiClient
if (runFrame)
{
//client input-related duties
Global.RenderPanel.ClearGUIText();
Global.OSD.ClearGUIText();
#if WINDOWS
LuaConsole1.ResumeScripts(true);
#endif
@ -1770,9 +1799,10 @@ namespace BizHawk.MultiClient
{
string fps_string = runloop_last_fps + " fps";
if (ff) fps_string += " >>";
Global.RenderPanel.FPS = fps_string;
Global.OSD.FPS = fps_string;
}
if (!suppressCaptureRewind && Global.Config.RewindEnabled) CaptureRewindState();
if (!runloop_frameadvance) genSound = true;
else if (!Global.Config.MuteFrameAdvance)
@ -1913,7 +1943,7 @@ namespace BizHawk.MultiClient
{
System.Windows.Forms.Clipboard.SetImage(img);
}
Global.RenderPanel.AddMessage("Screenshot saved to clipboard.");
Global.OSD.AddMessage("Screenshot saved to clipboard.");
}
private void TakeScreenshot()
@ -1938,7 +1968,7 @@ namespace BizHawk.MultiClient
{
img.Save(fi.FullName, ImageFormat.Png);
}
Global.RenderPanel.AddMessage(fi.Name + " saved.");
Global.OSD.AddMessage(fi.Name + " saved.");
}
public void SaveState(string name)
@ -1979,7 +2009,7 @@ namespace BizHawk.MultiClient
writer.Close();
Global.RenderPanel.AddMessage("Saved state: " + name);
Global.OSD.AddMessage("Saved state: " + name);
if (!fromLua)
{
@ -2029,10 +2059,10 @@ namespace BizHawk.MultiClient
reader.Close();
UpdateTools();
Global.RenderPanel.AddMessage("Loaded state: " + name);
Global.OSD.AddMessage("Loaded state: " + name);
}
else
Global.RenderPanel.AddMessage("Loadstate error!");
Global.OSD.AddMessage("Loadstate error!");
}
public void LoadState(string name)
@ -2067,7 +2097,7 @@ namespace BizHawk.MultiClient
private void SaveSlotSelectedMessage()
{
Global.RenderPanel.AddMessage("Slot " + Global.Config.SaveSlot + " selected.");
Global.OSD.AddMessage("Slot " + Global.Config.SaveSlot + " selected.");
}
private void UpdateAutoLoadRecentRom()
@ -2216,7 +2246,7 @@ namespace BizHawk.MultiClient
FrameBufferResized();
}
Global.RenderPanel.Render(Global.Emulator.VideoProvider);
Global.DisplayManager.UpdateSource(Global.Emulator.VideoProvider);
}
private void FrameBufferResized()
@ -2491,13 +2521,13 @@ namespace BizHawk.MultiClient
{
ReadOnly ^= true;
if (ReadOnly)
Global.RenderPanel.AddMessage("Movie read-only mode");
Global.OSD.AddMessage("Movie read-only mode");
else
Global.RenderPanel.AddMessage("Movie read+write mode");
Global.OSD.AddMessage("Movie read+write mode");
}
else
{
Global.RenderPanel.AddMessage("No movie active");
Global.OSD.AddMessage("No movie active");
}
}
@ -2506,9 +2536,9 @@ namespace BizHawk.MultiClient
{
ReadOnly = read_only;
if (ReadOnly)
Global.RenderPanel.AddMessage("Movie read-only mode");
Global.OSD.AddMessage("Movie read-only mode");
else
Global.RenderPanel.AddMessage("Movie read+write mode");
Global.OSD.AddMessage("Movie read+write mode");
}
public void LoadRamWatch()
@ -2541,7 +2571,7 @@ namespace BizHawk.MultiClient
if (Global.Config.SoundVolume > 100)
Global.Config.SoundVolume = 100;
Global.Sound.ChangeVolume(Global.Config.SoundVolume);
Global.RenderPanel.AddMessage("Volume " + Global.Config.SoundVolume.ToString());
Global.OSD.AddMessage("Volume " + Global.Config.SoundVolume.ToString());
}
private void VolumeDown()
@ -2550,7 +2580,7 @@ namespace BizHawk.MultiClient
if (Global.Config.SoundVolume < 0)
Global.Config.SoundVolume = 0;
Global.Sound.ChangeVolume(Global.Config.SoundVolume);
Global.RenderPanel.AddMessage("Volume " + Global.Config.SoundVolume.ToString());
Global.OSD.AddMessage("Volume " + Global.Config.SoundVolume.ToString());
}
private void SoftReset()
@ -2637,13 +2667,13 @@ namespace BizHawk.MultiClient
//commit the avi writing last, in case there were any errors earlier
CurrAviWriter = aw;
Global.RenderPanel.AddMessage("AVI capture started");
Global.OSD.AddMessage("AVI capture started");
AVIStatusLabel.Image = BizHawk.MultiClient.Properties.Resources.AVI;
AVIStatusLabel.ToolTipText = "AVI capture in progress";
}
catch
{
Global.RenderPanel.AddMessage("AVI capture failed!");
Global.OSD.AddMessage("AVI capture failed!");
aw.Dispose();
throw;
}
@ -2654,7 +2684,7 @@ namespace BizHawk.MultiClient
if (CurrAviWriter == null) return;
CurrAviWriter.CloseFile();
CurrAviWriter = null;
Global.RenderPanel.AddMessage("AVI capture stopped");
Global.OSD.AddMessage("AVI capture stopped");
AVIStatusLabel.Image = BizHawk.MultiClient.Properties.Resources.Blank;
AVIStatusLabel.ToolTipText = "";
}
@ -2751,9 +2781,9 @@ namespace BizHawk.MultiClient
if (errorMsg.Length > 0)
MessageBox.Show(errorMsg, "Conversion error", MessageBoxButtons.OK, MessageBoxIcon.Error);
if (warningMsg.Length > 0)
Global.RenderPanel.AddMessage(warningMsg);
Global.OSD.AddMessage(warningMsg);
else
Global.RenderPanel.AddMessage(Path.GetFileName(fn) + " imported as ." + Global.Config.MovieExtension);
Global.OSD.AddMessage(Path.GetFileName(fn) + " imported as ." + Global.Config.MovieExtension);
}
}
@ -2801,7 +2831,7 @@ namespace BizHawk.MultiClient
{
StepRunLoop_Core();
Global.Emulator.FrameAdvance(true); //Frame advance
Global.RenderPanel.Render(Global.Emulator.VideoProvider);
//Global.RenderPanel.Render(Global.Emulator.VideoProvider);
if (gifSpeed > 0)
{

View File

@ -76,7 +76,7 @@ namespace BizHawk.MultiClient
{
Global.Config.NESPaletteFile = palette.Name;
nes.SetPalette(NES.Palettes.Load_FCEUX_Palette(HawkFile.ReadAllBytes(palette.Name)));
Global.RenderPanel.AddMessage("Palette file loaded: " + palette.Name);
Global.OSD.AddMessage("Palette file loaded: " + palette.Name);
}
}
}
@ -84,7 +84,7 @@ namespace BizHawk.MultiClient
{
Global.Config.NESPaletteFile = "";
nes.SetPalette(NES.Palettes.FCEUX_Standard);
Global.RenderPanel.AddMessage("Standard Palette set");
Global.OSD.AddMessage("Standard Palette set");
}
Global.Config.NESTopLine = (int)FirstLineNumeric.Value;

View File

@ -45,18 +45,21 @@ namespace BizHawk.MultiClient
else
{
#endif
var mf = new MainForm(args);
var title = mf.Text;
mf.Show();
mf.Text = title;
mf.ProgramRunLoop();
using (var mf = new MainForm(args))
{
var title = mf.Text;
mf.Show();
mf.Text = title;
mf.ProgramRunLoop();
int zzz = 9;
}
#if WINDOWS
}
#endif
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
MessageBox.Show(e.ToString());
}
#if WINDOWS
finally

View File

@ -39,8 +39,11 @@ namespace BizHawk.MultiClient
GraphicsDevice = graphicsDevice;
}
public void SetImage(int[] data, int width, int height)
public unsafe void SetImage(DisplaySurface surface, int width, int height)
{
//this function fails if the width and height are zero
if (width == 0 || height == 0) return;
bool needsRecreating = false;
if (Texture == null)
{
@ -72,13 +75,15 @@ namespace BizHawk.MultiClient
// Create a new texture instance.
Texture = new Texture(GraphicsDevice, textureWidth, textureHeight, 1, Usage.Dynamic, Format.X8R8G8B8, Pool.Default);
}
// Copy the image data to the texture.
surface.Lock();
using (var Data = Texture.LockRectangle(0, new Rectangle(0, 0, imageWidth, imageHeight), LockFlags.None).Data)
{
if (imageWidth == textureWidth)
{
// Widths are the same, just dump the data across (easy!)
Data.WriteRange(data, 0, imageWidth * imageHeight);
Data.WriteRange(surface.PixelIntPtr, imageWidth * imageHeight * 4);
}
else
{
@ -86,7 +91,8 @@ namespace BizHawk.MultiClient
long RowSeekOffset = 4 * (textureWidth - imageWidth);
for (int r = 0, s = 0; r < imageHeight; ++r, s += imageWidth)
{
Data.WriteRange(data, s, imageWidth);
IntPtr src = new IntPtr(((byte*)surface.PixelPtr + r*surface.Stride));
Data.WriteRange(src,imageWidth * 4);
Data.Seek(RowSeekOffset, SeekOrigin.Current);
}
}
@ -112,33 +118,29 @@ namespace BizHawk.MultiClient
public interface IRenderer : IDisposable
{
void Render(IVideoProvider video);
void Render(DisplaySurface surface);
bool Resized { get; set; }
void AddMessage(string msg);
void AddGUIText(string msg, int x, int y, bool alert, int anchor);
void ClearGUIText();
string FPS { get; set; }
string MT { get; set; }
Size NativeSize { get; }
}
public class SysdrawingRenderPanel : IRenderer
{
public bool Resized { get; set; }
public void Dispose() { }
public string FPS { get; set; }
public string MT { get; set; }
public void Render(IVideoProvider video)
public void Render(DisplaySurface surface)
{
Color BackgroundColor = Color.FromArgb(video.BackgroundColor);
int[] data = video.GetVideoBuffer();
//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);
//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);
////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);
//bmp.UnlockBits(bmpdata);
Bitmap bmp = (Bitmap)surface.PeekBitmap().Clone();
backingControl.SetBitmap(bmp);
}
@ -147,9 +149,7 @@ namespace BizHawk.MultiClient
backingControl = control;
}
RetainedViewportPanel backingControl;
public void AddMessage(string msg) { }
public void AddGUIText(string msg, int x, int y, bool alert, int anchor) { }
public void ClearGUIText() { }
public Size NativeSize { get { return backingControl.ClientSize; } }
}
#if WINDOWS
@ -164,10 +164,10 @@ namespace BizHawk.MultiClient
private Control backingControl;
public ImageTexture Texture;
private Sprite Sprite;
private Font MessageFont;
private Font AlertFont;
private bool Vsync;
private bool Vsync;
public Size NativeSize { get { return backingControl.ClientSize; } }
public Direct3DRenderPanel(Direct3D direct3D, Control control)
{
@ -195,16 +195,7 @@ namespace BizHawk.MultiClient
Sprite.Dispose();
Sprite = null;
}
if (MessageFont != null)
{
MessageFont.Dispose();
MessageFont = null;
}
if (AlertFont != null)
{
AlertFont.Dispose();
AlertFont = null;
}
if (Device != null)
{
Device.Dispose();
@ -241,27 +232,24 @@ namespace BizHawk.MultiClient
Device = new Device(d3d, 0, DeviceType.Hardware, backingControl.Handle, flags, pp);
Sprite = new Sprite(Device);
Texture = new ImageTexture(Device);
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");
// 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()
{
if (Device == null || Resized || Vsync != VsyncRequested)
CreateDevice();
backingControl.Invoke(() => CreateDevice());
Resized = false;
Device.Clear(ClearFlags.Target, BackgroundColor, 1.0f, 0);
Device.Present(Present.DoNotWait);
}
public void Render(IVideoProvider video)
public void Render(DisplaySurface surface)
{
try
{
RenderExec(video);
RenderExec(surface);
}
catch (Direct3D9Exception)
{
@ -275,33 +263,33 @@ namespace BizHawk.MultiClient
// lets try recovery!
DestroyDevice();
CreateDevice();
RenderExec(video);
backingControl.Invoke(() => CreateDevice());
RenderExec(surface);
}
}
private void RenderExec(IVideoProvider video)
private void RenderExec(DisplaySurface surface)
{
if (video == null)
if (surface == null)
{
Render();
return;
}
if (Device == null || Resized || Vsync != VsyncRequested)
CreateDevice();
backingControl.Invoke(() => CreateDevice());
Resized = false;
BackgroundColor = Color.FromArgb(video.BackgroundColor);
//TODO
//BackgroundColor = Color.FromArgb(video.BackgroundColor);
int[] data = video.GetVideoBuffer();
Texture.SetImage(data, video.BufferWidth, video.BufferHeight);
Texture.SetImage(surface, surface.Width, surface.Height);
Device.Clear(ClearFlags.Target, BackgroundColor, 1.0f, 0);
// figure out scaling factor
float widthScale = (float)backingControl.Size.Width / video.BufferWidth;
float heightScale = (float)backingControl.Size.Height / video.BufferHeight;
float widthScale = (float)backingControl.Size.Width / surface.Width;
float heightScale = (float)backingControl.Size.Height / surface.Height;
float finalScale = Math.Min(widthScale, heightScale);
Device.BeginScene();
@ -310,227 +298,13 @@ namespace BizHawk.MultiClient
Device.SetSamplerState(0, SamplerState.MagFilter, TextureFilter.Point);
Device.SetSamplerState(1, SamplerState.MagFilter, TextureFilter.Point);
Sprite.Transform = Matrix.Scaling(finalScale, finalScale, 0f);
Sprite.Draw(Texture.Texture, new Rectangle(0, 0, video.BufferWidth, video.BufferHeight), new Vector3(video.BufferWidth / 2f, video.BufferHeight / 2f, 0), new Vector3(backingControl.Size.Width / 2f / finalScale, backingControl.Size.Height / 2f / finalScale, 0), Color.White);
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);
Sprite.End();
DrawMessages();
Device.EndScene();
Device.Present(Present.DoNotWait);
}
private int GetX(int x, int anchor, Font font, string message)
{
Rectangle rect = font.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 backingControl.Width - x - rect.Width;
}
}
private int GetY(int y, int anchor, Font font, string message)
{
Rectangle rect = font.MeasureString(Sprite, message, new DrawTextFormat());
switch (anchor)
{
default:
case 0: //Top Left
case 1: //Top Right
return y;
case 2: //Bottom Left
case 3: //Bottom Right
return backingControl.Size.Height - y - rect.Height;
}
}
/// <summary>
/// Display all screen info objects like fps, frame counter, lag counter, and input display
/// </summary>
public void DrawScreenInfo()
{
if (Global.Config.DisplayFrameCounter)
{
string message = MakeFrameCounter();
int x = GetX(Global.Config.DispFrameCx, Global.Config.DispFrameanchor, MessageFont, message);
int y = GetY(Global.Config.DispFrameCy, Global.Config.DispFrameanchor, MessageFont, message);
MessageFont.DrawString(null, message, x + 1,
y + 1, Color.Black);
MessageFont.DrawString(null, message, x,
y, Color.FromArgb(Global.Config.MessagesColor));
}
if (Global.Config.DisplayInput)
{
string input = MakeInputDisplay();
Color c;
int x = GetX(Global.Config.DispInpx, Global.Config.DispInpanchor, MessageFont, input);
int y = GetY(Global.Config.DispInpy, Global.Config.DispInpanchor, MessageFont, input);
if (Global.MovieSession.Movie.Mode == MOVIEMODE.PLAY)
{
c = Color.FromArgb(Global.Config.MovieInput);
}
else
c = Color.FromArgb(Global.Config.MessagesColor);
MessageFont.DrawString(null, input, x + 1, y + 1, Color.Black);
MessageFont.DrawString(null, input, x, y, c);
}
if (Global.MovieSession.MultiTrack.IsActive)
{
MessageFont.DrawString(null, MT, Global.Config.DispFPSx + 1, //TODO: Multitrack position variables
Global.Config.DispFPSy + 1, Color.Black);
MessageFont.DrawString(null, MT, Global.Config.DispFPSx,
Global.Config.DispFPSy, Color.FromArgb(Global.Config.MessagesColor));
}
if (Global.Config.DisplayFPS && FPS != null)
{
int x = GetX(Global.Config.DispFPSx, Global.Config.DispFPSanchor, MessageFont, FPS);
int y = GetY(Global.Config.DispFPSy, Global.Config.DispFPSanchor, MessageFont, FPS);
MessageFont.DrawString(null, FPS, x + 1,
y + 1, Color.Black);
MessageFont.DrawString(null, FPS, x,
y, Color.FromArgb(Global.Config.MessagesColor));
}
if (Global.Config.DisplayLagCounter)
{
string counter = MakeLagCounter();
if (Global.Emulator.IsLagFrame)
{
int x = GetX(Global.Config.DispLagx, Global.Config.DispLaganchor, AlertFont, counter);
int y = GetY(Global.Config.DispLagy, Global.Config.DispLaganchor, AlertFont, counter);
AlertFont.DrawString(null, MakeLagCounter(), Global.Config.DispLagx + 1,
Global.Config.DispLagy + 1, Color.Black);
AlertFont.DrawString(null, MakeLagCounter(), Global.Config.DispLagx,
Global.Config.DispLagy, Color.FromArgb(Global.Config.AlertMessageColor));
}
else
{
int x = GetX(Global.Config.DispLagx, Global.Config.DispLaganchor, MessageFont, counter);
int y = GetY(Global.Config.DispLagy, Global.Config.DispLaganchor, MessageFont, counter);
MessageFont.DrawString(null, counter, x + 1,
y + 1, Color.Black);
MessageFont.DrawString(null, counter, x,
y, Color.FromArgb(Global.Config.MessagesColor));
}
}
if (Global.Config.DisplayRerecordCount)
{
string rerec = MakeRerecordCount();
int x = GetX(Global.Config.DispRecx, Global.Config.DispRecanchor, MessageFont, rerec);
int y = GetY(Global.Config.DispRecy, Global.Config.DispRecanchor, MessageFont, rerec);
MessageFont.DrawString(null, rerec, x + 1,
y + 1, Color.Black);
MessageFont.DrawString(null, rerec, x,
y, Color.FromArgb(Global.Config.MessagesColor));
}
if (Global.MovieSession.Movie.Mode == MOVIEMODE.PLAY)
{
MessageFont.DrawString(null, "Play", backingControl.Size.Width - 47,
0 + 1, Color.Black);
MessageFont.DrawString(null, "Play", backingControl.Size.Width - 48,
0, Color.FromArgb(Global.Config.MovieColor));
}
else if (Global.MovieSession.Movie.Mode == MOVIEMODE.RECORD)
{
AlertFont.DrawString(null, "Record", backingControl.Size.Width - 65,
0 + 1, Color.Black);
AlertFont.DrawString(null, "Record", backingControl.Size.Width - 64,
0, Color.FromArgb(Global.Config.MovieColor));
}
if (Global.MovieSession.Movie.Mode != MOVIEMODE.INACTIVE && Global.Config.DisplaySubtitles)
{
//TODO: implement multiple subtitles at once feature
Subtitle s = Global.MovieSession.Movie.Subtitles.GetSubtitle(Global.Emulator.Frame);
MessageFont.DrawString(null, s.Message, s.X + 1,
s.Y + 1, new Color4(Color.Black));
MessageFont.DrawString(null, s.Message, s.X,
s.Y, Color.FromArgb((int)s.Color));
}
}
private string MakeFrameCounter()
{
if (Global.MovieSession.Movie.Mode == MOVIEMODE.FINISHED)
{
return Global.Emulator.Frame.ToString() + "/" + Global.MovieSession.Movie.Length().ToString() + " (Finished)";
}
else if (Global.MovieSession.Movie.Mode == MOVIEMODE.PLAY)
{
return Global.Emulator.Frame.ToString() + "/" + Global.MovieSession.Movie.Length().ToString();
}
else if (Global.MovieSession.Movie.Mode == MOVIEMODE.RECORD)
return Global.Emulator.Frame.ToString();
else
{
return Global.Emulator.Frame.ToString();
}
}
private string MakeLagCounter()
{
return Global.Emulator.LagCount.ToString();
}
private List<UIMessage> messages = new List<UIMessage>(5);
private List<UIDisplay> GUITextList = new List<UIDisplay>();
public void AddMessage(string message)
{
messages.Add(new UIMessage { Message = message, ExpireAt = DateTime.Now + TimeSpan.FromSeconds(2) });
}
public void AddGUIText(string message, int x, int y, bool alert, int anchor)
{
GUITextList.Add(new UIDisplay { Message = message, X = x, Y = y, Alert = alert, Anchor = anchor});
}
public void ClearGUIText()
{
GUITextList.Clear();
}
private void DrawMessages()
{
messages.RemoveAll(m => DateTime.Now > m.ExpireAt);
DrawScreenInfo();
int line = 1;
for (int i = messages.Count - 1; i >= 0; i--, line++)
{
int x = 3;
int y = backingControl.Size.Height - (line * 18);
MessageFont.DrawString(null, messages[i].Message, x + 2, y + 2, Color.Black);
MessageFont.DrawString(null, messages[i].Message, x, y, Color.FromArgb(Global.Config.MessagesColor));
}
for (int x = 0; x < GUITextList.Count; x++)
{
int posx = GetX(GUITextList[x].X, GUITextList[x].Anchor, MessageFont, GUITextList[x].Message);
int posy = GetY(GUITextList[x].Y, GUITextList[x].Anchor, MessageFont, GUITextList[x].Message);
MessageFont.DrawString(null, GUITextList[x].Message,
posx + 2, posy + 2, Color.Black);
MessageFont.DrawString(null, GUITextList[x].Message,
posx + 1, posy + 1, Color.Gray);
if (GUITextList[x].Alert)
MessageFont.DrawString(null, GUITextList[x].Message,
posx, posy, Color.FromArgb(Global.Config.AlertMessageColor));
else
MessageFont.DrawString(null, GUITextList[x].Message,
posx, posy, Color.FromArgb(Global.Config.MessagesColor));
}
}
private bool disposed;
@ -543,25 +317,6 @@ namespace BizHawk.MultiClient
}
}
public string MakeInputDisplay()
{
StringBuilder s;
if (Global.MovieSession.Movie.Mode == MOVIEMODE.INACTIVE || Global.MovieSession.Movie.Mode == MOVIEMODE.FINISHED)
s = new StringBuilder(Global.GetOutputControllersAsMnemonic());
else
s = new StringBuilder(Global.MovieSession.Movie.GetInputFrame(Global.Emulator.Frame - 1));
s.Replace(".", " ");
s.Replace("|", "");
return s.ToString();
}
public string MakeRerecordCount()
{
if (Global.MovieSession.Movie.Mode != MOVIEMODE.INACTIVE)
return "Rerecord Count: " + Global.MovieSession.Movie.Rerecords.ToString();
else
return "";
}
}
#endif

View File

@ -21,8 +21,8 @@ namespace BizHawk.MultiClient
{
RewindImpossible = true;
LastState = null;
Global.RenderPanel.AddMessage("Rewind Disabled: State too large.");
Global.RenderPanel.AddMessage("See 'Arcade Card Rewind Hack' in Emulation->PC Engine options.");
Global.OSD.AddMessage("Rewind Disabled: State too large.");
Global.OSD.AddMessage("See 'Arcade Card Rewind Hack' in Emulation->PC Engine options.");
}
return;
}

View File

@ -170,7 +170,7 @@ namespace BizHawk.MultiClient
Directory.CreateDirectory(new FileInfo(Filename).Directory.FullName);
string BackupName = Filename;
BackupName = BackupName.Insert(Filename.LastIndexOf("."), String.Format(".{0:yyyy-MM-dd HH.mm.ss}", DateTime.Now));
Global.RenderPanel.AddMessage("Backup movie saved to " + BackupName);
Global.OSD.AddMessage("Backup movie saved to " + BackupName);
if (IsText)
WriteText(BackupName);
else
@ -376,7 +376,7 @@ namespace BizHawk.MultiClient
{
stateFrame = int.Parse(strs[1], NumberStyles.HexNumber);
}
catch { Global.RenderPanel.AddMessage("Savestate Frame failed to parse"); } //TODO: message?
catch { Global.OSD.AddMessage("Savestate Frame failed to parse"); } //TODO: message?
}
else if (line.Contains("Frame "))
{
@ -385,7 +385,7 @@ namespace BizHawk.MultiClient
{
stateFrame = int.Parse(strs[1]);
}
catch { Global.RenderPanel.AddMessage("Savestate Frame failed to parse"); } //TODO: message?
catch { Global.OSD.AddMessage("Savestate Frame failed to parse"); } //TODO: message?
}
if (line[0] == '|')
{
@ -607,7 +607,7 @@ namespace BizHawk.MultiClient
{
stateFrame = int.Parse(strs[1], NumberStyles.HexNumber);
}
catch { Global.RenderPanel.AddMessage("Savestate Frame number failed to parse"); }
catch { Global.OSD.AddMessage("Savestate Frame number failed to parse"); }
}
else if (line.Contains("Frame "))
{
@ -616,7 +616,7 @@ namespace BizHawk.MultiClient
{
stateFrame = int.Parse(strs[1]);
}
catch { Global.RenderPanel.AddMessage("Savestate Frame number failed to parse"); }
catch { Global.OSD.AddMessage("Savestate Frame number failed to parse"); }
}
else if (line == "[Input]") continue;
else if (line == "[/Input]") break;

View File

@ -143,7 +143,7 @@ namespace BizHawk.MultiClient
{
Changes();
Global.CheatList.Add(c);
Global.RenderPanel.AddMessage("Cheat added.");
Global.OSD.AddMessage("Cheat added.");
if (!this.IsHandleCreated || this.IsDisposed) return;
DisplayCheatsList();
CheatListView.Refresh();
@ -154,8 +154,8 @@ namespace BizHawk.MultiClient
Changes();
Global.CheatList.RemoveCheat(c.domain, c.address);
Global.RenderPanel.AddMessage("Cheat removed.");
Global.OSD.AddMessage("Cheat removed.");
if (!this.IsHandleCreated || this.IsDisposed) return;
DisplayCheatsList();
CheatListView.Refresh();

View File

@ -848,7 +848,7 @@ namespace BizHawk.MultiClient
if (ex is LuaInterface.LuaScriptException || ex is LuaInterface.LuaException)
{
s.Enabled = false;
s.Thread = null;
s.Thread = null;
AddText(ex.ToString());
UpdateNumberOfScripts();
}

View File

@ -75,11 +75,11 @@ namespace BizHawk.MultiClient
if (Global.Config.DisplayRamWatch)
{
Global.RenderPanel.ClearGUIText();
Global.OSD.ClearGUIText();
for (int x = 0; x < watchList.Count; x++)
{
bool alert = Global.CheatList.IsActiveCheat(Domain, watchList[x].address);
Global.RenderPanel.AddGUIText(watchList[x].ToString(),
Global.OSD.AddGUIText(watchList[x].ToString(),
Global.Config.DispRamWatchx, (Global.Config.DispRamWatchy + (x * 12)), alert, 0);
}
}
@ -1481,7 +1481,7 @@ namespace BizHawk.MultiClient
Global.Config.DisplayRamWatch ^= true;
if (!Global.Config.DisplayRamWatch)
Global.RenderPanel.ClearGUIText();
Global.OSD.ClearGUIText();
else
UpdateValues();
}

View File

@ -138,7 +138,7 @@ namespace BizHawk.MultiClient
//TODO: don't engage until new/open project
//
Engaged = true;
Global.RenderPanel.AddMessage("TAStudio engaged");
Global.OSD.AddMessage("TAStudio engaged");
LoadConfigSettings();
ReadOnlyCheckBox.Checked = Global.MainForm.ReadOnly;