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:
parent
0aa08984ed
commit
35fbe354c1
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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--)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue