cleanups
This commit is contained in:
parent
094ae65e06
commit
64ea9afee5
|
@ -19,11 +19,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Frameskip
|
public int Frameskip
|
||||||
{
|
{
|
||||||
get
|
get => _frameskip;
|
||||||
{
|
|
||||||
return _frameskip;
|
|
||||||
}
|
|
||||||
|
|
||||||
private set
|
private set
|
||||||
{
|
{
|
||||||
if (value < 0)
|
if (value < 0)
|
||||||
|
@ -46,11 +42,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int FrameDelay
|
public int FrameDelay
|
||||||
{
|
{
|
||||||
get
|
get => _framedelay;
|
||||||
{
|
|
||||||
return _framedelay;
|
|
||||||
}
|
|
||||||
|
|
||||||
private set
|
private set
|
||||||
{
|
{
|
||||||
if (value < -1)
|
if (value < -1)
|
||||||
|
@ -81,10 +73,10 @@ namespace BizHawk.Client.EmuHawk
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private GifToken(int frameskip, int framedelay)
|
private GifToken(int frameskip, int frameDelay)
|
||||||
{
|
{
|
||||||
Frameskip = frameskip;
|
Frameskip = frameskip;
|
||||||
FrameDelay = framedelay;
|
FrameDelay = frameDelay;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,9 +84,9 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
public void SetVideoCodecToken(IDisposable token)
|
public void SetVideoCodecToken(IDisposable token)
|
||||||
{
|
{
|
||||||
if (token is GifToken)
|
if (token is GifToken gifToken)
|
||||||
{
|
{
|
||||||
_token = (GifToken)token;
|
_token = gifToken;
|
||||||
CalcDelay();
|
CalcDelay();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -169,35 +161,31 @@ namespace BizHawk.Client.EmuHawk
|
||||||
return; // skip this frame
|
return; // skip this frame
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var bmp = new Bitmap(source.BufferWidth, source.BufferHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb))
|
using var bmp = new Bitmap(source.BufferWidth, source.BufferHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
|
||||||
|
var data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
|
||||||
|
System.Runtime.InteropServices.Marshal.Copy(source.GetVideoBuffer(), 0, data.Scan0, bmp.Width * bmp.Height);
|
||||||
|
bmp.UnlockBits(data);
|
||||||
|
|
||||||
|
using var qBmp = new OctreeQuantizer(255, 8).Quantize(bmp);
|
||||||
|
MemoryStream ms = new MemoryStream();
|
||||||
|
qBmp.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
|
||||||
|
byte[] b = ms.GetBuffer();
|
||||||
|
if (!firstdone)
|
||||||
{
|
{
|
||||||
var data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
|
firstdone = true;
|
||||||
System.Runtime.InteropServices.Marshal.Copy(source.GetVideoBuffer(), 0, data.Scan0, bmp.Width * bmp.Height);
|
b[10] = (byte)(b[10] & 0x78); // no global color table
|
||||||
bmp.UnlockBits(data);
|
f.Write(b, 0, 13);
|
||||||
|
f.Write(GifAnimation, 0, GifAnimation.Length);
|
||||||
using (var qBmp = new OctreeQuantizer(255, 8).Quantize(bmp))
|
|
||||||
{
|
|
||||||
MemoryStream ms = new MemoryStream();
|
|
||||||
qBmp.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
|
|
||||||
byte[] b = ms.GetBuffer();
|
|
||||||
if (!firstdone)
|
|
||||||
{
|
|
||||||
firstdone = true;
|
|
||||||
b[10] = (byte)(b[10] & 0x78); // no global color table
|
|
||||||
f.Write(b, 0, 13);
|
|
||||||
f.Write(GifAnimation, 0, GifAnimation.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
b[785] = Delay[0];
|
|
||||||
b[786] = Delay[1];
|
|
||||||
b[798] = (byte)(b[798] | 0x87);
|
|
||||||
f.Write(b, 781, 18);
|
|
||||||
f.Write(b, 13, 768);
|
|
||||||
f.Write(b, 799, (int)(ms.Length - 800));
|
|
||||||
|
|
||||||
lastbyte = b[ms.Length - 1];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b[785] = Delay[0];
|
||||||
|
b[786] = Delay[1];
|
||||||
|
b[798] = (byte)(b[798] | 0x87);
|
||||||
|
f.Write(b, 781, 18);
|
||||||
|
f.Write(b, 13, 768);
|
||||||
|
f.Write(b, 799, (int)(ms.Length - 800));
|
||||||
|
|
||||||
|
lastbyte = b[ms.Length - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddSamples(short[] samples)
|
public void AddSamples(short[] samples)
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
using BizHawk.Client.Common;
|
using BizHawk.Client.Common;
|
||||||
|
using BizHawk.Client.EmuHawk.WinFormExtensions;
|
||||||
|
|
||||||
namespace BizHawk.Client.EmuHawk
|
namespace BizHawk.Client.EmuHawk
|
||||||
{
|
{
|
||||||
|
@ -14,23 +15,23 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
public static GifWriter.GifToken DoTokenForm(IWin32Window parent)
|
public static GifWriter.GifToken DoTokenForm(IWin32Window parent)
|
||||||
{
|
{
|
||||||
using (var dlg = new GifWriterForm())
|
using var dlg = new GifWriterForm
|
||||||
{
|
{
|
||||||
dlg.numericUpDown1.Value = Global.Config.GifWriterFrameskip;
|
numericUpDown1 = { Value = Global.Config.GifWriterFrameskip },
|
||||||
dlg.numericUpDown2.Value = Global.Config.GifWriterDelay;
|
numericUpDown2 = { Value = Global.Config.GifWriterDelay }
|
||||||
dlg.NumericUpDown2_ValueChanged(null, null);
|
};
|
||||||
|
dlg.NumericUpDown2_ValueChanged(null, null);
|
||||||
|
|
||||||
var result = dlg.ShowDialog(parent);
|
var result = dlg.ShowDialog(parent);
|
||||||
if (result == DialogResult.OK)
|
if (result.IsOk())
|
||||||
{
|
{
|
||||||
Global.Config.GifWriterFrameskip = (int)dlg.numericUpDown1.Value;
|
Global.Config.GifWriterFrameskip = (int)dlg.numericUpDown1.Value;
|
||||||
Global.Config.GifWriterDelay = (int)dlg.numericUpDown2.Value;
|
Global.Config.GifWriterDelay = (int)dlg.numericUpDown2.Value;
|
||||||
|
|
||||||
return GifWriter.GifToken.LoadFromConfig();
|
return GifWriter.GifToken.LoadFromConfig();
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void NumericUpDown2_ValueChanged(object sender, EventArgs e)
|
private void NumericUpDown2_ValueChanged(object sender, EventArgs e)
|
||||||
|
|
|
@ -22,351 +22,348 @@ using System.Drawing.Imaging;
|
||||||
|
|
||||||
namespace BizHawk.Client.EmuHawk
|
namespace BizHawk.Client.EmuHawk
|
||||||
{
|
{
|
||||||
/// <summary>
|
internal abstract unsafe class Quantizer
|
||||||
/// Summary description for Class1.
|
{
|
||||||
/// </summary>
|
/// <summary>
|
||||||
internal unsafe abstract class Quantizer
|
/// Flag used to indicate whether a single pass or two passes are needed for quantization.
|
||||||
{
|
/// </summary>
|
||||||
/// <summary>
|
private bool _singlePass;
|
||||||
/// Flag used to indicate whether a single pass or two passes are needed for quantization.
|
|
||||||
/// </summary>
|
|
||||||
private bool _singlePass;
|
|
||||||
|
|
||||||
protected bool highquality;
|
|
||||||
public bool HighQuality
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return highquality;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
protected bool highquality;
|
||||||
{
|
public bool HighQuality
|
||||||
highquality = value;
|
{
|
||||||
}
|
get
|
||||||
}
|
{
|
||||||
|
return highquality;
|
||||||
|
}
|
||||||
|
|
||||||
protected int ditherLevel;
|
set
|
||||||
public int DitherLevel
|
{
|
||||||
{
|
highquality = value;
|
||||||
get
|
}
|
||||||
{
|
}
|
||||||
return this.ditherLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
protected int ditherLevel;
|
||||||
{
|
public int DitherLevel
|
||||||
this.ditherLevel = value;
|
{
|
||||||
}
|
get
|
||||||
}
|
{
|
||||||
|
return ditherLevel;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
set
|
||||||
/// Construct the quantizer
|
{
|
||||||
/// </summary>
|
ditherLevel = value;
|
||||||
/// <param name="singlePass">If true, the quantization only needs to loop through the source pixels once</param>
|
}
|
||||||
/// <remarks>
|
}
|
||||||
/// If you construct this class with a true value for singlePass, then the code will, when quantizing your image,
|
|
||||||
/// only call the 'QuantizeImage' function. If two passes are required, the code will call 'InitialQuantizeImage'
|
|
||||||
/// and then 'QuantizeImage'.
|
|
||||||
/// </remarks>
|
|
||||||
public Quantizer(bool singlePass)
|
|
||||||
{
|
|
||||||
_singlePass = singlePass;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Quantize an image and return the resulting output bitmap
|
/// Construct the quantizer
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="source">The image to quantize</param>
|
/// <param name="singlePass">If true, the quantization only needs to loop through the source pixels once</param>
|
||||||
/// <returns>A quantized version of the image</returns>
|
/// <remarks>
|
||||||
public Bitmap Quantize(Image source)
|
/// If you construct this class with a true value for singlePass, then the code will, when quantizing your image,
|
||||||
{
|
/// only call the 'QuantizeImage' function. If two passes are required, the code will call 'InitialQuantizeImage'
|
||||||
// Get the size of the source image
|
/// and then 'QuantizeImage'.
|
||||||
int height = source.Height;
|
/// </remarks>
|
||||||
int width = source.Width;
|
public Quantizer(bool singlePass)
|
||||||
|
{
|
||||||
|
_singlePass = singlePass;
|
||||||
|
}
|
||||||
|
|
||||||
// And construct a rectangle from these dimensions
|
/// <summary>
|
||||||
Rectangle bounds = new Rectangle(0, 0, width, height);
|
/// Quantize an image and return the resulting output bitmap
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">The image to quantize</param>
|
||||||
|
/// <returns>A quantized version of the image</returns>
|
||||||
|
public Bitmap Quantize(Image source)
|
||||||
|
{
|
||||||
|
// Get the size of the source image
|
||||||
|
int height = source.Height;
|
||||||
|
int width = source.Width;
|
||||||
|
|
||||||
// First off take a 32bpp copy of the image
|
// And construct a rectangle from these dimensions
|
||||||
Bitmap copy;
|
Rectangle bounds = new Rectangle(0, 0, width, height);
|
||||||
|
|
||||||
if (source is Bitmap && source.PixelFormat == PixelFormat.Format32bppArgb)
|
|
||||||
{
|
|
||||||
copy = (Bitmap)source;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
copy = new Bitmap(width, height, PixelFormat.Format32bppArgb);
|
|
||||||
|
|
||||||
// Now lock the bitmap into memory
|
// First off take a 32bpp copy of the image
|
||||||
using (Graphics g = Graphics.FromImage(copy))
|
Bitmap copy;
|
||||||
{
|
|
||||||
g.PageUnit = GraphicsUnit.Pixel;
|
|
||||||
|
|
||||||
// Draw the source image onto the copy bitmap,
|
if (source is Bitmap && source.PixelFormat == PixelFormat.Format32bppArgb)
|
||||||
// which will effect a widening as appropriate.
|
{
|
||||||
g.DrawImage(source, 0, 0, bounds.Width, bounds.Height);
|
copy = (Bitmap)source;
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
|
copy = new Bitmap(width, height, PixelFormat.Format32bppArgb);
|
||||||
|
|
||||||
// And construct an 8bpp version
|
// Now lock the bitmap into memory
|
||||||
Bitmap output = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
|
using (Graphics g = Graphics.FromImage(copy))
|
||||||
|
{
|
||||||
|
g.PageUnit = GraphicsUnit.Pixel;
|
||||||
|
|
||||||
// Define a pointer to the bitmap data
|
// Draw the source image onto the copy bitmap,
|
||||||
BitmapData sourceData = null;
|
// which will effect a widening as appropriate.
|
||||||
|
g.DrawImage(source, 0, 0, bounds.Width, bounds.Height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try
|
// And construct an 8bpp version
|
||||||
{
|
Bitmap output = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
|
||||||
// Get the source image bits and lock into memory
|
|
||||||
sourceData = copy.LockBits(bounds, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
|
|
||||||
|
|
||||||
// Call the FirstPass function if not a single pass algorithm.
|
// Define a pointer to the bitmap data
|
||||||
// For something like an octree quantizer, this will run through
|
BitmapData sourceData = null;
|
||||||
// all image pixels, build a data structure, and create a palette.
|
|
||||||
if (!_singlePass)
|
|
||||||
{
|
|
||||||
FirstPass(sourceData, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Then set the color palette on the output bitmap. I'm passing in the current palette
|
try
|
||||||
// as there's no way to construct a new, empty palette.
|
{
|
||||||
output.Palette = this.GetPalette(output.Palette);
|
// Get the source image bits and lock into memory
|
||||||
|
sourceData = copy.LockBits(bounds, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
|
||||||
|
|
||||||
// Then call the second pass which actually does the conversion
|
// Call the FirstPass function if not a single pass algorithm.
|
||||||
SecondPass(sourceData, output, width, height, bounds);
|
// For something like an octree quantizer, this will run through
|
||||||
}
|
// all image pixels, build a data structure, and create a palette.
|
||||||
|
if (!_singlePass)
|
||||||
|
{
|
||||||
|
FirstPass(sourceData, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
finally
|
// Then set the color palette on the output bitmap. I'm passing in the current palette
|
||||||
{
|
// as there's no way to construct a new, empty palette.
|
||||||
// Ensure that the bits are unlocked
|
output.Palette = this.GetPalette(output.Palette);
|
||||||
copy.UnlockBits(sourceData);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (copy != source)
|
// Then call the second pass which actually does the conversion
|
||||||
{
|
SecondPass(sourceData, output, width, height, bounds);
|
||||||
copy.Dispose();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Last but not least, return the output bitmap
|
finally
|
||||||
return output;
|
{
|
||||||
}
|
// Ensure that the bits are unlocked
|
||||||
|
copy.UnlockBits(sourceData);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
if (copy != source)
|
||||||
/// Execute the first pass through the pixels in the image
|
{
|
||||||
/// </summary>
|
copy.Dispose();
|
||||||
/// <param name="sourceData">The source data</param>
|
}
|
||||||
/// <param name="width">The width in pixels of the image</param>
|
|
||||||
/// <param name="height">The height in pixels of the image</param>
|
|
||||||
protected virtual void FirstPass(BitmapData sourceData, int width, int height)
|
|
||||||
{
|
|
||||||
// Define the source data pointers. The source row is a byte to
|
|
||||||
// keep addition of the stride value easier (as this is in bytes)
|
|
||||||
byte* pSourceRow = (byte*)sourceData.Scan0.ToPointer();
|
|
||||||
int* pSourcePixel;
|
|
||||||
|
|
||||||
// Loop through each row
|
// Last but not least, return the output bitmap
|
||||||
for (int row = 0; row < height; row++)
|
return output;
|
||||||
{
|
}
|
||||||
// Set the source pixel to the first pixel in this row
|
|
||||||
pSourcePixel = (Int32*)pSourceRow;
|
|
||||||
|
|
||||||
// And loop through each column
|
/// <summary>
|
||||||
for (int col = 0; col < width; col++, pSourcePixel++)
|
/// Execute the first pass through the pixels in the image
|
||||||
{
|
/// </summary>
|
||||||
InitialQuantizePixel(*pSourcePixel);
|
/// <param name="sourceData">The source data</param>
|
||||||
}
|
/// <param name="width">The width in pixels of the image</param>
|
||||||
|
/// <param name="height">The height in pixels of the image</param>
|
||||||
|
protected virtual void FirstPass(BitmapData sourceData, int width, int height)
|
||||||
|
{
|
||||||
|
// Define the source data pointers. The source row is a byte to
|
||||||
|
// keep addition of the stride value easier (as this is in bytes)
|
||||||
|
byte* pSourceRow = (byte*)sourceData.Scan0.ToPointer();
|
||||||
|
int* pSourcePixel;
|
||||||
|
|
||||||
// Add the stride to the source row
|
// Loop through each row
|
||||||
pSourceRow += sourceData.Stride;
|
for (int row = 0; row < height; row++)
|
||||||
|
{
|
||||||
|
// Set the source pixel to the first pixel in this row
|
||||||
|
pSourcePixel = (Int32*)pSourceRow;
|
||||||
|
|
||||||
}
|
// And loop through each column
|
||||||
}
|
for (int col = 0; col < width; col++, pSourcePixel++)
|
||||||
|
{
|
||||||
|
InitialQuantizePixel(*pSourcePixel);
|
||||||
|
}
|
||||||
|
|
||||||
int ClampToByte(int val)
|
// Add the stride to the source row
|
||||||
{
|
pSourceRow += sourceData.Stride;
|
||||||
if (val < 0) return 0;
|
|
||||||
else if (val > 255) return 255;
|
|
||||||
else return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
}
|
||||||
/// Execute a second pass through the bitmap
|
}
|
||||||
/// </summary>
|
|
||||||
/// <param name="sourceData">The source bitmap, locked into memory</param>
|
|
||||||
/// <param name="output">The output bitmap</param>
|
|
||||||
/// <param name="width">The width in pixels of the image</param>
|
|
||||||
/// <param name="height">The height in pixels of the image</param>
|
|
||||||
/// <param name="bounds">The bounding rectangle</param>
|
|
||||||
protected virtual void SecondPass(BitmapData sourceData, Bitmap output, int width, int height, Rectangle bounds)
|
|
||||||
{
|
|
||||||
BitmapData outputData = null;
|
|
||||||
Color[] pallete = output.Palette.Entries;
|
|
||||||
int weight = ditherLevel;
|
|
||||||
|
|
||||||
try
|
int ClampToByte(int val)
|
||||||
{
|
{
|
||||||
// Lock the output bitmap into memory
|
if (val < 0) return 0;
|
||||||
outputData = output.LockBits(bounds, ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);
|
else if (val > 255) return 255;
|
||||||
|
else return val;
|
||||||
|
}
|
||||||
|
|
||||||
// Define the source data pointers. The source row is a byte to
|
/// <summary>
|
||||||
// keep addition of the stride value easier (as this is in bytes)
|
/// Execute a second pass through the bitmap
|
||||||
byte* pSourceRow = (byte *)sourceData.Scan0.ToPointer();
|
/// </summary>
|
||||||
Int32* pSourcePixel = (Int32 *)pSourceRow;
|
/// <param name="sourceData">The source bitmap, locked into memory</param>
|
||||||
|
/// <param name="output">The output bitmap</param>
|
||||||
|
/// <param name="width">The width in pixels of the image</param>
|
||||||
|
/// <param name="height">The height in pixels of the image</param>
|
||||||
|
/// <param name="bounds">The bounding rectangle</param>
|
||||||
|
protected virtual void SecondPass(BitmapData sourceData, Bitmap output, int width, int height, Rectangle bounds)
|
||||||
|
{
|
||||||
|
BitmapData outputData = null;
|
||||||
|
Color[] pallete = output.Palette.Entries;
|
||||||
|
int weight = ditherLevel;
|
||||||
|
|
||||||
// Now define the destination data pointers
|
try
|
||||||
byte* pDestinationRow = (byte *)outputData.Scan0.ToPointer();
|
{
|
||||||
byte* pDestinationPixel = pDestinationRow;
|
// Lock the output bitmap into memory
|
||||||
|
outputData = output.LockBits(bounds, ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);
|
||||||
|
|
||||||
int[] errorThisRowR = new int[width + 1];
|
// Define the source data pointers. The source row is a byte to
|
||||||
int[] errorThisRowG = new int[width + 1];
|
// keep addition of the stride value easier (as this is in bytes)
|
||||||
int[] errorThisRowB = new int[width + 1];
|
byte* pSourceRow = (byte*)sourceData.Scan0.ToPointer();
|
||||||
|
Int32* pSourcePixel = (Int32*)pSourceRow;
|
||||||
|
|
||||||
for (int row = 0; row < height; row++)
|
// Now define the destination data pointers
|
||||||
{
|
byte* pDestinationRow = (byte*)outputData.Scan0.ToPointer();
|
||||||
int[] errorNextRowR = new int[width + 1];
|
byte* pDestinationPixel = pDestinationRow;
|
||||||
int[] errorNextRowG = new int[width + 1];
|
|
||||||
int[] errorNextRowB = new int[width + 1];
|
|
||||||
|
|
||||||
int ptrInc;
|
int[] errorThisRowR = new int[width + 1];
|
||||||
|
int[] errorThisRowG = new int[width + 1];
|
||||||
|
int[] errorThisRowB = new int[width + 1];
|
||||||
|
|
||||||
if ((row & 1) == 0)
|
for (int row = 0; row < height; row++)
|
||||||
{
|
{
|
||||||
pSourcePixel = (Int32*)pSourceRow;
|
int[] errorNextRowR = new int[width + 1];
|
||||||
pDestinationPixel = pDestinationRow;
|
int[] errorNextRowG = new int[width + 1];
|
||||||
ptrInc = +1;
|
int[] errorNextRowB = new int[width + 1];
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pSourcePixel = (Int32*)pSourceRow + width - 1;
|
|
||||||
pDestinationPixel = pDestinationRow + width - 1;
|
|
||||||
ptrInc = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loop through each pixel on this scan line
|
int ptrInc;
|
||||||
for (int col = 0; col < width; ++col)
|
|
||||||
{
|
|
||||||
// Quantize the pixel
|
|
||||||
int srcPixel = *pSourcePixel;
|
|
||||||
|
|
||||||
int srcR = srcPixel & 0xFF; //not
|
if ((row & 1) == 0)
|
||||||
int srcG = (srcPixel>>8) & 0xFF; //a
|
{
|
||||||
int srcB = (srcPixel>>16) & 0xFF; //mistake
|
pSourcePixel = (Int32*)pSourceRow;
|
||||||
int srcA = (srcPixel >> 24) & 0xFF;
|
pDestinationPixel = pDestinationRow;
|
||||||
|
ptrInc = +1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pSourcePixel = (Int32*)pSourceRow + width - 1;
|
||||||
|
pDestinationPixel = pDestinationRow + width - 1;
|
||||||
|
ptrInc = -1;
|
||||||
|
}
|
||||||
|
|
||||||
int targetB = ClampToByte(srcB - ((errorThisRowB[col] * weight) / 8));
|
// Loop through each pixel on this scan line
|
||||||
int targetG = ClampToByte(srcG - ((errorThisRowG[col] * weight) / 8));
|
for (int col = 0; col < width; ++col)
|
||||||
int targetR = ClampToByte(srcR - ((errorThisRowR[col] * weight) / 8));
|
{
|
||||||
int targetA = srcA;
|
// Quantize the pixel
|
||||||
|
int srcPixel = *pSourcePixel;
|
||||||
|
|
||||||
int target = (targetA<<24)|(targetB<<16)|(targetG<<8)|targetR;
|
int srcR = srcPixel & 0xFF; //not
|
||||||
|
int srcG = (srcPixel >> 8) & 0xFF; //a
|
||||||
|
int srcB = (srcPixel >> 16) & 0xFF; //mistake
|
||||||
|
int srcA = (srcPixel >> 24) & 0xFF;
|
||||||
|
|
||||||
byte pixelValue = QuantizePixel(target);
|
int targetB = ClampToByte(srcB - ((errorThisRowB[col] * weight) / 8));
|
||||||
*pDestinationPixel = pixelValue;
|
int targetG = ClampToByte(srcG - ((errorThisRowG[col] * weight) / 8));
|
||||||
|
int targetR = ClampToByte(srcR - ((errorThisRowR[col] * weight) / 8));
|
||||||
|
int targetA = srcA;
|
||||||
|
|
||||||
int actual = pallete[pixelValue].ToArgb();
|
int target = (targetA << 24) | (targetB << 16) | (targetG << 8) | targetR;
|
||||||
|
|
||||||
int actualR = actual & 0xFF;
|
byte pixelValue = QuantizePixel(target);
|
||||||
int actualG = (actual >> 8) & 0xFF;
|
*pDestinationPixel = pixelValue;
|
||||||
int actualB = (actual >> 16) & 0xFF;
|
|
||||||
int errorR = actualR - targetR;
|
|
||||||
int errorG = actualG - targetG;
|
|
||||||
int errorB = actualB - targetB;
|
|
||||||
|
|
||||||
// Floyd-Steinberg Error Diffusion:
|
int actual = pallete[pixelValue].ToArgb();
|
||||||
// a) 7/16 error goes to x+1
|
|
||||||
// b) 5/16 error goes to y+1
|
|
||||||
// c) 3/16 error goes to x-1,y+1
|
|
||||||
// d) 1/16 error goes to x+1,y+1
|
|
||||||
|
|
||||||
const int a = 7;
|
int actualR = actual & 0xFF;
|
||||||
const int b = 5;
|
int actualG = (actual >> 8) & 0xFF;
|
||||||
const int c = 3;
|
int actualB = (actual >> 16) & 0xFF;
|
||||||
|
int errorR = actualR - targetR;
|
||||||
|
int errorG = actualG - targetG;
|
||||||
|
int errorB = actualB - targetB;
|
||||||
|
|
||||||
int errorRa = (errorR * a) / 16;
|
// Floyd-Steinberg Error Diffusion:
|
||||||
int errorRb = (errorR * b) / 16;
|
// a) 7/16 error goes to x+1
|
||||||
int errorRc = (errorR * c) / 16;
|
// b) 5/16 error goes to y+1
|
||||||
int errorRd = errorR - errorRa - errorRb - errorRc;
|
// c) 3/16 error goes to x-1,y+1
|
||||||
|
// d) 1/16 error goes to x+1,y+1
|
||||||
|
|
||||||
int errorGa = (errorG * a) / 16;
|
const int a = 7;
|
||||||
int errorGb = (errorG * b) / 16;
|
const int b = 5;
|
||||||
int errorGc = (errorG * c) / 16;
|
const int c = 3;
|
||||||
int errorGd = errorG - errorGa - errorGb - errorGc;
|
|
||||||
|
|
||||||
int errorBa = (errorB * a) / 16;
|
int errorRa = (errorR * a) / 16;
|
||||||
int errorBb = (errorB * b) / 16;
|
int errorRb = (errorR * b) / 16;
|
||||||
int errorBc = (errorB * c) / 16;
|
int errorRc = (errorR * c) / 16;
|
||||||
int errorBd = errorB - errorBa - errorBb - errorBc;
|
int errorRd = errorR - errorRa - errorRb - errorRc;
|
||||||
|
|
||||||
errorThisRowR[col + 1] += errorRa;
|
int errorGa = (errorG * a) / 16;
|
||||||
errorThisRowG[col + 1] += errorGa;
|
int errorGb = (errorG * b) / 16;
|
||||||
errorThisRowB[col + 1] += errorBa;
|
int errorGc = (errorG * c) / 16;
|
||||||
|
int errorGd = errorG - errorGa - errorGb - errorGc;
|
||||||
|
|
||||||
errorNextRowR[width - col] += errorRb;
|
int errorBa = (errorB * a) / 16;
|
||||||
errorNextRowG[width - col] += errorGb;
|
int errorBb = (errorB * b) / 16;
|
||||||
errorNextRowB[width - col] += errorBb;
|
int errorBc = (errorB * c) / 16;
|
||||||
|
int errorBd = errorB - errorBa - errorBb - errorBc;
|
||||||
|
|
||||||
if (col != 0)
|
errorThisRowR[col + 1] += errorRa;
|
||||||
{
|
errorThisRowG[col + 1] += errorGa;
|
||||||
errorNextRowR[width - (col - 1)] += errorRc;
|
errorThisRowB[col + 1] += errorBa;
|
||||||
errorNextRowG[width - (col - 1)] += errorGc;
|
|
||||||
errorNextRowB[width - (col - 1)] += errorBc;
|
|
||||||
}
|
|
||||||
|
|
||||||
errorNextRowR[width - (col + 1)] += errorRd;
|
errorNextRowR[width - col] += errorRb;
|
||||||
errorNextRowG[width - (col + 1)] += errorGd;
|
errorNextRowG[width - col] += errorGb;
|
||||||
errorNextRowB[width - (col + 1)] += errorBd;
|
errorNextRowB[width - col] += errorBb;
|
||||||
|
|
||||||
unchecked
|
if (col != 0)
|
||||||
{
|
{
|
||||||
pSourcePixel += ptrInc;
|
errorNextRowR[width - (col - 1)] += errorRc;
|
||||||
pDestinationPixel += ptrInc;
|
errorNextRowG[width - (col - 1)] += errorGc;
|
||||||
}
|
errorNextRowB[width - (col - 1)] += errorBc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the stride to the source row
|
errorNextRowR[width - (col + 1)] += errorRd;
|
||||||
pSourceRow += sourceData.Stride;
|
errorNextRowG[width - (col + 1)] += errorGd;
|
||||||
|
errorNextRowB[width - (col + 1)] += errorBd;
|
||||||
|
|
||||||
// And to the destination row
|
unchecked
|
||||||
pDestinationRow += outputData.Stride;
|
{
|
||||||
|
pSourcePixel += ptrInc;
|
||||||
|
pDestinationPixel += ptrInc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
errorThisRowB = errorNextRowB;
|
// Add the stride to the source row
|
||||||
errorThisRowG = errorNextRowG;
|
pSourceRow += sourceData.Stride;
|
||||||
errorThisRowR = errorNextRowR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
// Ensure that I unlock the output bits
|
|
||||||
output.UnlockBits(outputData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
// And to the destination row
|
||||||
/// Override this to process the pixel in the first pass of the algorithm
|
pDestinationRow += outputData.Stride;
|
||||||
/// </summary>
|
|
||||||
/// <param name="pixel">The pixel to quantize</param>
|
|
||||||
/// <remarks>
|
|
||||||
/// This function need only be overridden if your quantize algorithm needs two passes,
|
|
||||||
/// such as an Octree quantizer.
|
|
||||||
/// </remarks>
|
|
||||||
protected virtual void InitialQuantizePixel(int pixel)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
errorThisRowB = errorNextRowB;
|
||||||
/// Override this to process the pixel in the second pass of the algorithm
|
errorThisRowG = errorNextRowG;
|
||||||
/// </summary>
|
errorThisRowR = errorNextRowR;
|
||||||
/// <param name="pixel">The pixel to quantize</param>
|
}
|
||||||
/// <returns>The quantized value</returns>
|
}
|
||||||
protected abstract byte QuantizePixel(int pixel);
|
|
||||||
|
|
||||||
/// <summary>
|
finally
|
||||||
/// Retrieve the palette for the quantized image
|
{
|
||||||
/// </summary>
|
// Ensure that I unlock the output bits
|
||||||
/// <param name="original">Any old palette, this is overrwritten</param>
|
output.UnlockBits(outputData);
|
||||||
/// <returns>The new color palette</returns>
|
}
|
||||||
protected abstract ColorPalette GetPalette(ColorPalette original);
|
}
|
||||||
}
|
|
||||||
|
/// <summary>
|
||||||
|
/// Override this to process the pixel in the first pass of the algorithm
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pixel">The pixel to quantize</param>
|
||||||
|
/// <remarks>
|
||||||
|
/// This function need only be overridden if your quantize algorithm needs two passes,
|
||||||
|
/// such as an Octree quantizer.
|
||||||
|
/// </remarks>
|
||||||
|
protected virtual void InitialQuantizePixel(int pixel)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Override this to process the pixel in the second pass of the algorithm
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pixel">The pixel to quantize</param>
|
||||||
|
/// <returns>The quantized value</returns>
|
||||||
|
protected abstract byte QuantizePixel(int pixel);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieve the palette for the quantized image
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="original">Any old palette, this is overrwritten</param>
|
||||||
|
/// <returns>The new color palette</returns>
|
||||||
|
protected abstract ColorPalette GetPalette(ColorPalette original);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,18 +52,16 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
public void AddFrame(IVideoProvider source)
|
public void AddFrame(IVideoProvider source)
|
||||||
{
|
{
|
||||||
using (var bb = new BitmapBuffer(source.BufferWidth, source.BufferHeight, source.GetVideoBuffer()))
|
using var bb = new BitmapBuffer(source.BufferWidth, source.BufferHeight, source.GetVideoBuffer());
|
||||||
{
|
string subPath = GetAndCreatePathForFrameNum(mCurrFrame);
|
||||||
string subpath = GetAndCreatePathForFrameNum(mCurrFrame);
|
string path = $"{subPath}.png";
|
||||||
string path = $"{subpath}.png";
|
bb.ToSysdrawingBitmap().Save(path, System.Drawing.Imaging.ImageFormat.Png);
|
||||||
bb.ToSysdrawingBitmap().Save(path, System.Drawing.Imaging.ImageFormat.Png);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddSamples(short[] samples)
|
public void AddSamples(short[] samples)
|
||||||
{
|
{
|
||||||
string subpath = GetAndCreatePathForFrameNum(mCurrFrame);
|
string subPath = GetAndCreatePathForFrameNum(mCurrFrame);
|
||||||
string path = $"{subpath}.wav";
|
string path = $"{subPath}.wav";
|
||||||
WavWriterV wwv = new WavWriterV();
|
WavWriterV wwv = new WavWriterV();
|
||||||
wwv.SetAudioParameters(paramSampleRate, paramChannels, paramBits);
|
wwv.SetAudioParameters(paramSampleRate, paramChannels, paramBits);
|
||||||
wwv.OpenFile(path);
|
wwv.OpenFile(path);
|
||||||
|
@ -107,7 +105,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
paramBits = bits;
|
paramBits = bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetMetaData(string gameName, string authors, UInt64 lengthMS, UInt64 rerecords)
|
public void SetMetaData(string gameName, string authors, ulong lengthMS, ulong rerecords)
|
||||||
{
|
{
|
||||||
// not needed
|
// not needed
|
||||||
}
|
}
|
||||||
|
@ -146,9 +144,9 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
private string GetAndCreatePathForFrameNum(int index)
|
private string GetAndCreatePathForFrameNum(int index)
|
||||||
{
|
{
|
||||||
string subpath = GetPathFragmentForFrameNum(index);
|
string subPath = GetPathFragmentForFrameNum(index);
|
||||||
string path = mFramesDirectory;
|
string path = mFramesDirectory;
|
||||||
path = Path.Combine(path, subpath);
|
path = Path.Combine(path, subPath);
|
||||||
string fpath = $"{path}.nothing";
|
string fpath = $"{path}.nothing";
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(fpath));
|
Directory.CreateDirectory(Path.GetDirectoryName(fpath));
|
||||||
return path;
|
return path;
|
||||||
|
|
|
@ -18,9 +18,9 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
private void GetPaths(int index, out string png, out string wav)
|
private void GetPaths(int index, out string png, out string wav)
|
||||||
{
|
{
|
||||||
string subpath = SynclessRecorder.GetPathFragmentForFrameNum(index);
|
string subPath = SynclessRecorder.GetPathFragmentForFrameNum(index);
|
||||||
string path = mFramesDirectory;
|
string path = mFramesDirectory;
|
||||||
path = Path.Combine(path, subpath);
|
path = Path.Combine(path, subPath);
|
||||||
png = $"{path}.png";
|
png = $"{path}.png";
|
||||||
wav = $"{path}.wav";
|
wav = $"{path}.wav";
|
||||||
}
|
}
|
||||||
|
@ -64,8 +64,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
int frame = 1; // hacky! skip frame 0, because we have a problem with dumping that frame somehow
|
int frame = 1; // hacky! skip frame 0, because we have a problem with dumping that frame somehow
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
string wav, png;
|
GetPaths(frame, out var png, out var wav);
|
||||||
GetPaths(frame, out png, out wav);
|
|
||||||
if (!File.Exists(png) || !File.Exists(wav))
|
if (!File.Exists(png) || !File.Exists(wav))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
|
@ -115,37 +114,35 @@ namespace BizHawk.Client.EmuHawk
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var avw = new AviWriter())
|
using var avw = new AviWriter();
|
||||||
|
avw.SetAudioParameters(44100, 2, 16); // hacky
|
||||||
|
avw.SetMovieParameters(60, 1); // hacky
|
||||||
|
avw.SetVideoParameters(width, height);
|
||||||
|
var token = avw.AcquireVideoCodecToken(this);
|
||||||
|
avw.SetVideoCodecToken(token);
|
||||||
|
avw.OpenFile(sfd.FileName);
|
||||||
|
foreach (var fi in mFrameInfos)
|
||||||
{
|
{
|
||||||
avw.SetAudioParameters(44100, 2, 16); // hacky
|
using (var bb = new BitmapBuffer(fi.pngPath, new BitmapLoadOptions()))
|
||||||
avw.SetMovieParameters(60, 1); // hacky
|
|
||||||
avw.SetVideoParameters(width, height);
|
|
||||||
var token = avw.AcquireVideoCodecToken(this);
|
|
||||||
avw.SetVideoCodecToken(token);
|
|
||||||
avw.OpenFile(sfd.FileName);
|
|
||||||
foreach (var fi in mFrameInfos)
|
|
||||||
{
|
{
|
||||||
using (var bb = new BitmapBuffer(fi.pngPath, new BitmapLoadOptions()))
|
var bbvp = new BitmapBufferVideoProvider(bb);
|
||||||
{
|
avw.AddFrame(bbvp);
|
||||||
var bbvp = new BitmapBufferVideoProvider(bb);
|
|
||||||
avw.AddFrame(bbvp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// offset = 44 dec
|
|
||||||
var wavBytes = File.ReadAllBytes(fi.wavPath);
|
|
||||||
var ms = new MemoryStream(wavBytes) { Position = 44 };
|
|
||||||
var br = new BinaryReader(ms);
|
|
||||||
var sampledata = new List<short>();
|
|
||||||
while (br.BaseStream.Position != br.BaseStream.Length)
|
|
||||||
{
|
|
||||||
sampledata.Add(br.ReadInt16());
|
|
||||||
}
|
|
||||||
|
|
||||||
avw.AddSamples(sampledata.ToArray());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
avw.CloseFile();
|
// offset = 44 dec
|
||||||
|
var wavBytes = File.ReadAllBytes(fi.wavPath);
|
||||||
|
var ms = new MemoryStream(wavBytes) { Position = 44 };
|
||||||
|
var br = new BinaryReader(ms);
|
||||||
|
var sampledata = new List<short>();
|
||||||
|
while (br.BaseStream.Position != br.BaseStream.Length)
|
||||||
|
{
|
||||||
|
sampledata.Add(br.ReadInt16());
|
||||||
|
}
|
||||||
|
|
||||||
|
avw.AddSamples(sampledata.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
avw.CloseFile();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,6 @@
|
||||||
this.Controls.Add(this.CoreNameLabel);
|
this.Controls.Add(this.CoreNameLabel);
|
||||||
this.Name = "BizBoxInfoControl";
|
this.Name = "BizBoxInfoControl";
|
||||||
this.Size = new System.Drawing.Size(359, 25);
|
this.Size = new System.Drawing.Size(359, 25);
|
||||||
this.Load += new System.EventHandler(this.BizBoxInfoControl_Load);
|
|
||||||
this.ResumeLayout(false);
|
this.ResumeLayout(false);
|
||||||
this.PerformLayout();
|
this.PerformLayout();
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,11 @@
|
||||||
using System;
|
using System.Windows.Forms;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Data;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
|
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
namespace BizHawk.Client.EmuHawk
|
namespace BizHawk.Client.EmuHawk
|
||||||
{
|
{
|
||||||
public partial class BizBoxInfoControl : UserControl
|
public partial class BizBoxInfoControl : UserControl
|
||||||
{
|
{
|
||||||
private string url = "";
|
private readonly string _url = "";
|
||||||
|
|
||||||
public BizBoxInfoControl(CoreAttribute attributes)
|
public BizBoxInfoControl(CoreAttribute attributes)
|
||||||
{
|
{
|
||||||
|
@ -39,19 +31,14 @@ namespace BizHawk.Client.EmuHawk
|
||||||
{
|
{
|
||||||
CoreUrlLink.Visible = true;
|
CoreUrlLink.Visible = true;
|
||||||
CoreUrlLink.Text = attributes.PortedVersion;
|
CoreUrlLink.Text = attributes.PortedVersion;
|
||||||
url = attributes.PortedUrl;
|
_url = attributes.PortedUrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BizBoxInfoControl_Load(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CoreUrlLink_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
private void CoreUrlLink_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
||||||
{
|
{
|
||||||
CoreUrlLink.LinkVisited = true;
|
CoreUrlLink.LinkVisited = true;
|
||||||
System.Diagnostics.Process.Start(url);
|
System.Diagnostics.Process.Start(_url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
using BizHawk.Common;
|
using BizHawk.Common;
|
||||||
|
|
|
@ -25,8 +25,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
public void ActivateThreaded()
|
public void ActivateThreaded()
|
||||||
{
|
{
|
||||||
ewh = new EventWaitHandle(false, EventResetMode.AutoReset);
|
ewh = new EventWaitHandle(false, EventResetMode.AutoReset);
|
||||||
threadPaint = new Thread(PaintProc);
|
threadPaint = new Thread(PaintProc) { IsBackground = true };
|
||||||
threadPaint.IsBackground = true;
|
|
||||||
threadPaint.Start();
|
threadPaint.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,27 +61,25 @@ namespace BizHawk.Client.EmuHawk
|
||||||
{
|
{
|
||||||
if (bmp != null)
|
if (bmp != null)
|
||||||
{
|
{
|
||||||
using (Graphics g = CreateGraphics())
|
using Graphics g = CreateGraphics();
|
||||||
|
g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
|
||||||
|
g.InterpolationMode = InterpolationMode.NearestNeighbor;
|
||||||
|
g.CompositingMode = CompositingMode.SourceCopy;
|
||||||
|
g.CompositingQuality = CompositingQuality.HighSpeed;
|
||||||
|
if (ScaleImage)
|
||||||
{
|
{
|
||||||
g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
|
|
||||||
g.InterpolationMode = InterpolationMode.NearestNeighbor;
|
g.InterpolationMode = InterpolationMode.NearestNeighbor;
|
||||||
g.CompositingMode = CompositingMode.SourceCopy;
|
g.PixelOffsetMode = PixelOffsetMode.Half;
|
||||||
g.CompositingQuality = CompositingQuality.HighSpeed;
|
g.DrawImage(bmp, 0, 0, Width, Height);
|
||||||
if (ScaleImage)
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
using (var sb = new SolidBrush(Color.Black))
|
||||||
{
|
{
|
||||||
g.InterpolationMode = InterpolationMode.NearestNeighbor;
|
g.FillRectangle(sb, bmp.Width, 0, Width - bmp.Width, Height);
|
||||||
g.PixelOffsetMode = PixelOffsetMode.Half;
|
g.FillRectangle(sb, 0, bmp.Height, bmp.Width, Height - bmp.Height);
|
||||||
g.DrawImage(bmp, 0, 0, Width, Height);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
using (var sb = new SolidBrush(Color.Black))
|
|
||||||
{
|
|
||||||
g.FillRectangle(sb, bmp.Width, 0, Width - bmp.Width, Height);
|
|
||||||
g.FillRectangle(sb, 0, bmp.Height, bmp.Width, Height - bmp.Height);
|
|
||||||
}
|
|
||||||
g.DrawImageUnscaled(bmp, 0, 0);
|
|
||||||
}
|
}
|
||||||
|
g.DrawImageUnscaled(bmp, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +150,6 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
protected override void OnPaintBackground(PaintEventArgs pevent)
|
protected override void OnPaintBackground(PaintEventArgs pevent)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Drawing.Imaging;
|
using System.Drawing.Imaging;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
using BizHawk.Common;
|
using BizHawk.Common;
|
||||||
using BizHawk.Client.Common;
|
|
||||||
|
|
||||||
namespace BizHawk.Client.EmuHawk
|
namespace BizHawk.Client.EmuHawk
|
||||||
{
|
{
|
||||||
|
@ -15,9 +12,9 @@ namespace BizHawk.Client.EmuHawk
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public unsafe class DisplaySurface : IDisposable
|
public unsafe class DisplaySurface : IDisposable
|
||||||
{
|
{
|
||||||
Bitmap bmp;
|
private Bitmap bmp;
|
||||||
BitmapData bmpdata;
|
private BitmapData bmpdata;
|
||||||
int[] pixels;
|
private int[] pixels;
|
||||||
|
|
||||||
public unsafe void Clear()
|
public unsafe void Clear()
|
||||||
{
|
{
|
||||||
|
@ -42,8 +39,8 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
public unsafe void ToBitmap(bool copy=true)
|
public unsafe void ToBitmap(bool copy=true)
|
||||||
{
|
{
|
||||||
if (isBitmap) return;
|
if (_isBitmap) return;
|
||||||
isBitmap = true;
|
_isBitmap = true;
|
||||||
|
|
||||||
if (bmp == null)
|
if (bmp == null)
|
||||||
{
|
{
|
||||||
|
@ -67,13 +64,12 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsBitmap { get { return isBitmap; } }
|
bool _isBitmap;
|
||||||
bool isBitmap = false;
|
|
||||||
|
|
||||||
public unsafe void FromBitmap(bool copy=true)
|
public unsafe void FromBitmap(bool copy=true)
|
||||||
{
|
{
|
||||||
if (!isBitmap) return;
|
if (!_isBitmap) return;
|
||||||
isBitmap = false;
|
_isBitmap = false;
|
||||||
|
|
||||||
if (copy)
|
if (copy)
|
||||||
{
|
{
|
||||||
|
@ -91,21 +87,6 @@ namespace BizHawk.Client.EmuHawk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static DisplaySurface DisplaySurfaceWrappingBitmap(Bitmap bmp)
|
|
||||||
{
|
|
||||||
DisplaySurface ret = new DisplaySurface();
|
|
||||||
ret.Width = bmp.Width;
|
|
||||||
ret.Height = bmp.Height;
|
|
||||||
ret.bmp = bmp;
|
|
||||||
ret.isBitmap = true;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
private DisplaySurface()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public DisplaySurface(int width, int height)
|
public DisplaySurface(int width, int height)
|
||||||
{
|
{
|
||||||
//can't create a bitmap with zero dimensions, so for now, just bump it up to one
|
//can't create a bitmap with zero dimensions, so for now, just bump it up to one
|
||||||
|
@ -119,10 +100,8 @@ namespace BizHawk.Client.EmuHawk
|
||||||
LockPixels();
|
LockPixels();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int* PixelPtr { get { return (int*)ptr; } }
|
public int* PixelPtr => (int*)ptr;
|
||||||
public IntPtr PixelIntPtr { get { return new IntPtr(ptr); } }
|
public int Stride => Width * 4;
|
||||||
public int Stride { get { return Width*4; } }
|
|
||||||
public int OffsetOf(int x, int y) { return y * Stride + x*4; }
|
|
||||||
|
|
||||||
void* ptr;
|
void* ptr;
|
||||||
GCHandle handle;
|
GCHandle handle;
|
||||||
|
@ -133,52 +112,20 @@ namespace BizHawk.Client.EmuHawk
|
||||||
ptr = handle.AddrOfPinnedObject().ToPointer();
|
ptr = handle.AddrOfPinnedObject().ToPointer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnlockPixels()
|
private void UnlockPixels()
|
||||||
{
|
{
|
||||||
if(handle.IsAllocated) handle.Free();
|
if(handle.IsAllocated) handle.Free();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public int Width { get; }
|
||||||
/// returns a new surface
|
public int Height { get; }
|
||||||
/// </summary>
|
|
||||||
public DisplaySurface ToPaddedSurface(int xpad0, int ypad0, int xpad1, int ypad1)
|
|
||||||
{
|
|
||||||
int new_width = Width + xpad0 + xpad1;
|
|
||||||
int new_height = Height + ypad0 + ypad1;
|
|
||||||
DisplaySurface ret = new DisplaySurface(new_width, new_height);
|
|
||||||
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()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (bmp != null)
|
bmp?.Dispose();
|
||||||
bmp.Dispose();
|
|
||||||
bmp = null;
|
bmp = null;
|
||||||
UnlockPixels();
|
UnlockPixels();
|
||||||
}
|
}
|
||||||
|
|
||||||
//public unsafe int[] ToIntArray() { }
|
|
||||||
|
|
||||||
public void AcceptIntArray(int[] newpixels)
|
|
||||||
{
|
|
||||||
FromBitmap(false);
|
|
||||||
UnlockPixels();
|
|
||||||
pixels = newpixels;
|
|
||||||
LockPixels();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,10 @@
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
|
||||||
using BizHawk.Common;
|
|
||||||
using BizHawk.Client.Common;
|
|
||||||
using BizHawk.Client.EmuHawk.Filters;
|
using BizHawk.Client.EmuHawk.Filters;
|
||||||
|
|
||||||
using BizHawk.Bizware.BizwareGL;
|
using BizHawk.Bizware.BizwareGL;
|
||||||
using BizHawk.Bizware.BizwareGL.Drivers.OpenTK;
|
|
||||||
|
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
|
||||||
|
|
||||||
namespace BizHawk.Client.EmuHawk.FilterManager
|
namespace BizHawk.Client.EmuHawk.FilterManager
|
||||||
{
|
{
|
||||||
|
@ -24,8 +15,8 @@ namespace BizHawk.Client.EmuHawk.FilterManager
|
||||||
|
|
||||||
public class SurfaceFormat
|
public class SurfaceFormat
|
||||||
{
|
{
|
||||||
public SurfaceFormat(Size size) { this.Size = size; }
|
public SurfaceFormat(Size size) { Size = size; }
|
||||||
public Size Size { get; private set; }
|
public Size Size { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SurfaceState
|
public class SurfaceState
|
||||||
|
@ -33,9 +24,10 @@ namespace BizHawk.Client.EmuHawk.FilterManager
|
||||||
public SurfaceState() { }
|
public SurfaceState() { }
|
||||||
public SurfaceState(SurfaceFormat surfaceFormat, SurfaceDisposition surfaceDisposition = SurfaceDisposition.Unspecified)
|
public SurfaceState(SurfaceFormat surfaceFormat, SurfaceDisposition surfaceDisposition = SurfaceDisposition.Unspecified)
|
||||||
{
|
{
|
||||||
this.SurfaceFormat = surfaceFormat;
|
SurfaceFormat = surfaceFormat;
|
||||||
this.SurfaceDisposition = surfaceDisposition;
|
SurfaceDisposition = surfaceDisposition;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SurfaceFormat SurfaceFormat;
|
public SurfaceFormat SurfaceFormat;
|
||||||
public SurfaceDisposition SurfaceDisposition;
|
public SurfaceDisposition SurfaceDisposition;
|
||||||
}
|
}
|
||||||
|
@ -47,16 +39,16 @@ namespace BizHawk.Client.EmuHawk.FilterManager
|
||||||
|
|
||||||
public class FilterProgram
|
public class FilterProgram
|
||||||
{
|
{
|
||||||
|
private readonly Dictionary<string, BaseFilter> FilterNameIndex = new Dictionary<string, BaseFilter>();
|
||||||
|
|
||||||
public List<BaseFilter> Filters = new List<BaseFilter>();
|
public List<BaseFilter> Filters = new List<BaseFilter>();
|
||||||
Dictionary<string, BaseFilter> FilterNameIndex = new Dictionary<string, BaseFilter>();
|
|
||||||
public List<ProgramStep> Program = new List<ProgramStep>();
|
public List<ProgramStep> Program = new List<ProgramStep>();
|
||||||
|
|
||||||
public BaseFilter this[string name]
|
public BaseFilter this[string name]
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
BaseFilter ret;
|
FilterNameIndex.TryGetValue(name, out var ret);
|
||||||
FilterNameIndex.TryGetValue(name, out ret);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,7 +71,7 @@ namespace BizHawk.Client.EmuHawk.FilterManager
|
||||||
{
|
{
|
||||||
return RenderTargetProvider.Get(new Size(width, height));
|
return RenderTargetProvider.Get(new Size(width, height));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddFilter(BaseFilter filter, string name = "")
|
public void AddFilter(BaseFilter filter, string name = "")
|
||||||
{
|
{
|
||||||
Filters.Add(filter);
|
Filters.Add(filter);
|
||||||
|
@ -128,10 +120,11 @@ namespace BizHawk.Client.EmuHawk.FilterManager
|
||||||
{
|
{
|
||||||
public ProgramStep(ProgramStepType type, object args, string comment = null)
|
public ProgramStep(ProgramStepType type, object args, string comment = null)
|
||||||
{
|
{
|
||||||
this.Type = type;
|
Type = type;
|
||||||
this.Args = args;
|
Args = args;
|
||||||
this.Comment = comment;
|
Comment = comment;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProgramStepType Type;
|
public ProgramStepType Type;
|
||||||
public object Args;
|
public object Args;
|
||||||
public string Comment;
|
public string Comment;
|
||||||
|
@ -218,9 +211,11 @@ namespace BizHawk.Client.EmuHawk.FilterManager
|
||||||
{
|
{
|
||||||
if (currState == null)
|
if (currState == null)
|
||||||
{
|
{
|
||||||
currState = new SurfaceState();
|
currState = new SurfaceState
|
||||||
currState.SurfaceFormat = iosi.SurfaceFormat;
|
{
|
||||||
currState.SurfaceDisposition = iosi.SurfaceDisposition;
|
SurfaceFormat = iosi.SurfaceFormat,
|
||||||
|
SurfaceDisposition = iosi.SurfaceDisposition
|
||||||
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,19 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
|
||||||
using BizHawk.Common;
|
|
||||||
using BizHawk.Client.Common;
|
|
||||||
using BizHawk.Client.EmuHawk.FilterManager;
|
using BizHawk.Client.EmuHawk.FilterManager;
|
||||||
|
|
||||||
using BizHawk.Bizware.BizwareGL;
|
using BizHawk.Bizware.BizwareGL;
|
||||||
using BizHawk.Bizware.BizwareGL.Drivers.OpenTK;
|
|
||||||
|
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
|
||||||
|
|
||||||
//Here's how to make a filter:
|
//Here's how to make a filter:
|
||||||
//1. Reset your state entirely in Initialize().
|
//1. Reset your state entirely in Initialize().
|
||||||
|
@ -37,7 +28,7 @@ namespace BizHawk.Client.EmuHawk.Filters
|
||||||
public virtual Size PresizeOutput(string channel, Size size) { return size; }
|
public virtual Size PresizeOutput(string channel, Size size) { return size; }
|
||||||
public virtual void SetInputFormat(string channel, SurfaceState state) { } //TODO - why a different param order than DeclareOutput?
|
public virtual void SetInputFormat(string channel, SurfaceState state) { } //TODO - why a different param order than DeclareOutput?
|
||||||
public Dictionary<string, object> Parameters = new Dictionary<string, object>();
|
public Dictionary<string, object> Parameters = new Dictionary<string, object>();
|
||||||
public bool IsNOP { get { return _IsNop; } protected set { _IsNop = value; } }
|
public bool IsNOP { get => _IsNop; protected set => _IsNop = value; }
|
||||||
private Boolean _IsNop = false;
|
private Boolean _IsNop = false;
|
||||||
|
|
||||||
//runtime signals
|
//runtime signals
|
||||||
|
@ -111,10 +102,10 @@ namespace BizHawk.Client.EmuHawk.Filters
|
||||||
return iosi;
|
return iosi;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<IOSurfaceInfo> IOSurfaceInfos = new List<IOSurfaceInfo>();
|
private readonly List<IOSurfaceInfo> IOSurfaceInfos = new List<IOSurfaceInfo>();
|
||||||
|
|
||||||
|
|
||||||
IOSurfaceInfo FindIOSurfaceInfo(string channel, SurfaceDirection direction)
|
private IOSurfaceInfo FindIOSurfaceInfo(string channel, SurfaceDirection direction)
|
||||||
{
|
{
|
||||||
foreach (var iosi in IOSurfaceInfos)
|
foreach (var iosi in IOSurfaceInfos)
|
||||||
if (iosi.Channel == channel && iosi.SurfaceDirection == direction)
|
if (iosi.Channel == channel && iosi.SurfaceDirection == direction)
|
||||||
|
@ -135,5 +126,4 @@ namespace BizHawk.Client.EmuHawk.Filters
|
||||||
Input, Output
|
Input, Output
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,20 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
|
||||||
using BizHawk.Common;
|
|
||||||
using BizHawk.Client.Common;
|
|
||||||
using BizHawk.Client.EmuHawk;
|
|
||||||
using BizHawk.Client.EmuHawk.FilterManager;
|
using BizHawk.Client.EmuHawk.FilterManager;
|
||||||
|
|
||||||
using BizHawk.Bizware.BizwareGL;
|
using BizHawk.Bizware.BizwareGL;
|
||||||
using BizHawk.Bizware.BizwareGL.Drivers.OpenTK;
|
|
||||||
|
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
|
||||||
|
|
||||||
namespace BizHawk.Client.EmuHawk.Filters
|
namespace BizHawk.Client.EmuHawk.Filters
|
||||||
{
|
{
|
||||||
|
@ -486,8 +475,7 @@ namespace BizHawk.Client.EmuHawk.Filters
|
||||||
|
|
||||||
public override void Run()
|
public override void Run()
|
||||||
{
|
{
|
||||||
if (RenderCallback == null) return;
|
RenderCallback?.Invoke();
|
||||||
RenderCallback();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,20 +1,7 @@
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
|
||||||
using BizHawk.Common;
|
|
||||||
using BizHawk.Client.Common;
|
|
||||||
using BizHawk.Client.EmuHawk;
|
|
||||||
using BizHawk.Client.EmuHawk.FilterManager;
|
using BizHawk.Client.EmuHawk.FilterManager;
|
||||||
|
|
||||||
using BizHawk.Bizware.BizwareGL;
|
using BizHawk.Bizware.BizwareGL;
|
||||||
using BizHawk.Bizware.BizwareGL.Drivers.OpenTK;
|
|
||||||
|
|
||||||
using OpenTK;
|
|
||||||
using OpenTK.Graphics;
|
|
||||||
|
|
||||||
namespace BizHawk.Client.EmuHawk.Filters
|
namespace BizHawk.Client.EmuHawk.Filters
|
||||||
{
|
{
|
||||||
|
@ -22,10 +9,10 @@ namespace BizHawk.Client.EmuHawk.Filters
|
||||||
{
|
{
|
||||||
public SourceImage(Size size)
|
public SourceImage(Size size)
|
||||||
{
|
{
|
||||||
this.Size = size;
|
Size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
Size Size;
|
private readonly Size Size;
|
||||||
|
|
||||||
public Texture2d Texture;
|
public Texture2d Texture;
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,4 @@
|
||||||
using System;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Drawing.Imaging;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
using BizHawk.Common;
|
|
||||||
using BizHawk.Client.Common;
|
|
||||||
|
|
||||||
namespace BizHawk.Client.EmuHawk
|
namespace BizHawk.Client.EmuHawk
|
||||||
{
|
{
|
||||||
|
@ -13,11 +6,11 @@ namespace BizHawk.Client.EmuHawk
|
||||||
/// encapsulates thread-safe concept of pending/current display surfaces, reusing buffers where matching
|
/// 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
|
/// sizes are available and keeping them cleaned up when they dont seem like theyll need to be used anymore
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class SwappableDisplaySurfaceSet
|
public class SwappableDisplaySurfaceSet
|
||||||
{
|
{
|
||||||
DisplaySurface Pending, Current;
|
private DisplaySurface Pending, Current;
|
||||||
bool IsPending;
|
private bool IsPending;
|
||||||
Queue<DisplaySurface> ReleasedSurfaces = new Queue<DisplaySurface>();
|
private readonly Queue<DisplaySurface> ReleasedSurfaces = new Queue<DisplaySurface>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// retrieves a surface with the specified size, reusing an old buffer if available and clearing if requested
|
/// retrieves a surface with the specified size, reusing an old buffer if available and clearing if requested
|
||||||
|
@ -78,5 +71,4 @@ namespace BizHawk.Client.EmuHawk
|
||||||
return Current;
|
return Current;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,17 +1,12 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
using BizHawk.Common;
|
|
||||||
using BizHawk.Emulation.Common;
|
|
||||||
using BizHawk.Client.Common;
|
|
||||||
|
|
||||||
using BizHawk.Bizware.BizwareGL;
|
using BizHawk.Bizware.BizwareGL;
|
||||||
|
|
||||||
namespace BizHawk.Client.EmuHawk
|
namespace BizHawk.Client.EmuHawk
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Recycles a pair of temporary textures (in case double-buffering helps any) to contain a BitmapBuffer's or DisplaySurface's contents, as long as the dimensions match.
|
/// Recycles a pair of temporary textures (in case double-buffering helps any) to contain a BitmapBuffer's or DisplaySurface's contents, as long as the dimensions match.
|
||||||
/// When the dimensions dont match, a new one will be allocated
|
/// When the dimensions don't match, a new one will be allocated
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class TextureFrugalizer : IDisposable
|
public class TextureFrugalizer : IDisposable
|
||||||
{
|
{
|
||||||
|
@ -24,59 +19,56 @@ namespace BizHawk.Client.EmuHawk
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
foreach (var ct in CurrentTextures)
|
foreach (var ct in CurrentTextures)
|
||||||
if(ct != null)
|
{
|
||||||
ct.Dispose();
|
ct?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
ResetList();
|
ResetList();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResetList()
|
void ResetList()
|
||||||
{
|
{
|
||||||
CurrentTextures = new List<Texture2d>();
|
CurrentTextures = new List<Texture2d> { null, null };
|
||||||
CurrentTextures.Add(null);
|
|
||||||
CurrentTextures.Add(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IGL GL;
|
private readonly IGL GL;
|
||||||
List<Texture2d> CurrentTextures;
|
private List<Texture2d> CurrentTextures;
|
||||||
|
|
||||||
public Texture2d Get(DisplaySurface ds)
|
public Texture2d Get(DisplaySurface ds)
|
||||||
{
|
{
|
||||||
using (var bb = new BitmapBuffer(ds.PeekBitmap(), new BitmapLoadOptions()))
|
using var bb = new BitmapBuffer(ds.PeekBitmap(), new BitmapLoadOptions());
|
||||||
{
|
return Get(bb);
|
||||||
return Get(bb);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public Texture2d Get(BitmapBuffer bb)
|
public Texture2d Get(BitmapBuffer bb)
|
||||||
{
|
{
|
||||||
//get the current entry
|
//get the current entry
|
||||||
Texture2d CurrentTexture = CurrentTextures[0];
|
Texture2d currentTexture = CurrentTextures[0];
|
||||||
|
|
||||||
//TODO - its a bit cruddy here that we dont respect the current texture HasAlpha condition (in fact, theres no such concept)
|
// TODO - its a bit cruddy here that we dont respect the current texture HasAlpha condition (in fact, there's no such concept)
|
||||||
//we might need to deal with that in the future to fix some bugs.
|
// we might need to deal with that in the future to fix some bugs.
|
||||||
|
|
||||||
//check if its rotten and needs recreating
|
//check if its rotten and needs recreating
|
||||||
if (CurrentTexture == null || CurrentTexture.IntWidth != bb.Width || CurrentTexture.IntHeight != bb.Height)
|
if (currentTexture == null || currentTexture.IntWidth != bb.Width || currentTexture.IntHeight != bb.Height)
|
||||||
{
|
{
|
||||||
//needs recreating. be sure to kill the old one...
|
//needs recreating. be sure to kill the old one...
|
||||||
if (CurrentTexture != null)
|
currentTexture?.Dispose();
|
||||||
CurrentTexture.Dispose();
|
|
||||||
//and make a new one
|
//and make a new one
|
||||||
CurrentTexture = GL.LoadTexture(bb);
|
currentTexture = GL.LoadTexture(bb);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//its good! just load in the data
|
//its good! just load in the data
|
||||||
GL.LoadTextureData(CurrentTexture, bb);
|
GL.LoadTextureData(currentTexture, bb);
|
||||||
}
|
}
|
||||||
|
|
||||||
//now shuffle the buffers
|
//now shuffle the buffers
|
||||||
CurrentTextures[0] = CurrentTextures[1];
|
CurrentTextures[0] = CurrentTextures[1];
|
||||||
CurrentTextures[1] = CurrentTexture;
|
CurrentTextures[1] = currentTexture;
|
||||||
|
|
||||||
//deterministic state, i guess
|
//deterministic state, i guess
|
||||||
CurrentTexture.SetFilterNearest();
|
currentTexture.SetFilterNearest();
|
||||||
|
|
||||||
return CurrentTexture;
|
return currentTexture;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,27 +1,23 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.IO.Pipes;
|
using System.IO.Pipes;
|
||||||
using SlimDX;
|
|
||||||
using SlimDX.DirectInput;
|
using SlimDX.DirectInput;
|
||||||
|
|
||||||
//this is not a very safe or pretty protocol, I'm not proud of it
|
// this is not a very safe or pretty protocol, I'm not proud of it
|
||||||
|
|
||||||
namespace BizHawk.Client.EmuHawk
|
namespace BizHawk.Client.EmuHawk
|
||||||
{
|
{
|
||||||
public static class IPCKeyInput
|
public static class IPCKeyInput
|
||||||
{
|
{
|
||||||
public static void Initialize()
|
public static void Initialize()
|
||||||
{
|
{
|
||||||
var t = new Thread(IPCThread);
|
var t = new Thread(IPCThread) { IsBackground = true };
|
||||||
t.IsBackground = true;
|
|
||||||
t.Start();
|
t.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static List<KeyInput.KeyEvent> PendingEventList = new List<KeyInput.KeyEvent>();
|
private static readonly List<KeyInput.KeyEvent> PendingEventList = new List<KeyInput.KeyEvent>();
|
||||||
static List<KeyInput.KeyEvent> EventList = new List<KeyInput.KeyEvent>();
|
private static readonly List<KeyInput.KeyEvent> EventList = new List<KeyInput.KeyEvent>();
|
||||||
|
|
||||||
static void IPCThread()
|
static void IPCThread()
|
||||||
{
|
{
|
||||||
|
@ -30,24 +26,22 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
for (; ; )
|
for (; ; )
|
||||||
{
|
{
|
||||||
using (NamedPipeServerStream pipe = new NamedPipeServerStream(pipeName, PipeDirection.In, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous, 1024, 1024))
|
using var pipe = new NamedPipeServerStream(pipeName, PipeDirection.In, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous, 1024, 1024);
|
||||||
|
try
|
||||||
{
|
{
|
||||||
try
|
pipe.WaitForConnection();
|
||||||
|
|
||||||
|
BinaryReader br = new BinaryReader(pipe);
|
||||||
|
|
||||||
|
for (; ; )
|
||||||
{
|
{
|
||||||
pipe.WaitForConnection();
|
int e = br.ReadInt32();
|
||||||
|
bool pressed = (e & 0x80000000) != 0;
|
||||||
BinaryReader br = new BinaryReader(pipe);
|
lock (PendingEventList)
|
||||||
|
PendingEventList.Add(new KeyInput.KeyEvent { Key = (Key)(e & 0x7FFFFFFF), Pressed = pressed });
|
||||||
for (; ; )
|
|
||||||
{
|
|
||||||
int e = br.ReadInt32();
|
|
||||||
bool pressed = (e & 0x80000000) != 0;
|
|
||||||
lock (PendingEventList)
|
|
||||||
PendingEventList.Add(new KeyInput.KeyEvent { Key = (Key)(e & 0x7FFFFFFF), Pressed = pressed });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch { }
|
|
||||||
}
|
}
|
||||||
|
catch { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1683,11 +1683,9 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
// why do we silently truncate\pad here instead of warning\erroring?
|
// why do we silently truncate\pad here instead of warning\erroring?
|
||||||
sram = new byte[oldRam.Length];
|
sram = new byte[oldRam.Length];
|
||||||
using (var reader = new BinaryReader(
|
using var reader = new BinaryReader(
|
||||||
new FileStream(PathManager.SaveRamPath(Game), FileMode.Open, FileAccess.Read)))
|
new FileStream(PathManager.SaveRamPath(Game), FileMode.Open, FileAccess.Read));
|
||||||
{
|
reader.Read(sram, 0, sram.Length);
|
||||||
reader.Read(sram, 0, sram.Length);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Emulator.AsSaveRam().StoreSaveRam(sram);
|
Emulator.AsSaveRam().StoreSaveRam(sram);
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Data;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
using BizHawk.Emulation.Cores;
|
|
||||||
using BizHawk.Emulation.Cores.Libretro;
|
using BizHawk.Emulation.Cores.Libretro;
|
||||||
using BizHawk.Client.Common;
|
using BizHawk.Client.Common;
|
||||||
|
|
||||||
|
@ -19,35 +13,29 @@ namespace BizHawk.Client.EmuHawk
|
||||||
{
|
{
|
||||||
public partial class OpenAdvancedChooser : Form
|
public partial class OpenAdvancedChooser : Form
|
||||||
{
|
{
|
||||||
MainForm mainForm;
|
private readonly MainForm _mainForm;
|
||||||
|
|
||||||
public AdvancedRomLoaderType Result;
|
public AdvancedRomLoaderType Result;
|
||||||
public string SuggestedExtensionFilter;
|
public string SuggestedExtensionFilter;
|
||||||
|
|
||||||
public OpenAdvancedChooser(MainForm mainForm)
|
public OpenAdvancedChooser(MainForm mainForm)
|
||||||
{
|
{
|
||||||
this.mainForm = mainForm;
|
_mainForm = mainForm;
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
RefreshLibretroCore(true);
|
RefreshLibretroCore(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void btnOK_Click(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
DialogResult = System.Windows.Forms.DialogResult.OK;
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void btnCancel_Click(object sender, EventArgs e)
|
private void btnCancel_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
DialogResult = DialogResult.Cancel;
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void btnSetLibretroCore_Click(object sender, EventArgs e)
|
private void btnSetLibretroCore_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if(mainForm.RunLibretroCoreChooser())
|
if(_mainForm.RunLibretroCoreChooser())
|
||||||
RefreshLibretroCore(false);
|
RefreshLibretroCore(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,26 +61,24 @@ namespace BizHawk.Client.EmuHawk
|
||||||
////LibRetroEmulator should be able to survive having this stub corecomm
|
////LibRetroEmulator should be able to survive having this stub corecomm
|
||||||
//NEW COMMENTS:
|
//NEW COMMENTS:
|
||||||
//nope, we need to navigate to the dll path. this was a bad idea anyway. so many dlls get loaded, something to resolve them is needed
|
//nope, we need to navigate to the dll path. this was a bad idea anyway. so many dlls get loaded, something to resolve them is needed
|
||||||
var coreComm = new BizHawk.Emulation.Common.CoreComm(null, null);
|
var coreComm = new CoreComm(null, null);
|
||||||
CoreFileProvider.SyncCoreCommInputSignals(coreComm);
|
CoreFileProvider.SyncCoreCommInputSignals(coreComm);
|
||||||
using (var retro = new LibretroCore(coreComm, core))
|
using var retro = new LibretroCore(coreComm, core);
|
||||||
{
|
btnLibretroLaunchGame.Enabled = true;
|
||||||
btnLibretroLaunchGame.Enabled = true;
|
if (retro.Description.SupportsNoGame)
|
||||||
if (retro.Description.SupportsNoGame)
|
btnLibretroLaunchNoGame.Enabled = true;
|
||||||
btnLibretroLaunchNoGame.Enabled = true;
|
|
||||||
|
|
||||||
//print descriptive information
|
//print descriptive information
|
||||||
var descr = retro.Description;
|
var descr = retro.Description;
|
||||||
CurrentDescription = descr;
|
CurrentDescription = descr;
|
||||||
Console.WriteLine($"core name: {descr.LibraryName} version {descr.LibraryVersion}");
|
Console.WriteLine($"core name: {descr.LibraryName} version {descr.LibraryVersion}");
|
||||||
Console.WriteLine($"extensions: {descr.ValidExtensions}");
|
Console.WriteLine($"extensions: {descr.ValidExtensions}");
|
||||||
Console.WriteLine($"{nameof(descr.NeedsRomAsPath)}: {descr.NeedsRomAsPath}");
|
Console.WriteLine($"{nameof(descr.NeedsRomAsPath)}: {descr.NeedsRomAsPath}");
|
||||||
Console.WriteLine($"{nameof(descr.NeedsArchives)}: {descr.NeedsArchives}");
|
Console.WriteLine($"{nameof(descr.NeedsArchives)}: {descr.NeedsArchives}");
|
||||||
Console.WriteLine($"{nameof(descr.SupportsNoGame)}: {descr.SupportsNoGame}");
|
Console.WriteLine($"{nameof(descr.SupportsNoGame)}: {descr.SupportsNoGame}");
|
||||||
|
|
||||||
foreach (var v in descr.Variables.Values)
|
foreach (var v in descr.Variables.Values)
|
||||||
Console.WriteLine(v);
|
Console.WriteLine(v);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -111,8 +97,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
sw.Write("*.{0};",ext);
|
sw.Write("*.{0};",ext);
|
||||||
var filter = sw.ToString();
|
var filter = sw.ToString();
|
||||||
filter = filter.Substring(0,filter.Length-1); //remove last semicolon
|
filter = filter.Substring(0,filter.Length-1); //remove last semicolon
|
||||||
List<string> args = new List<string>();
|
var args = new List<string> { "Rom Files" };
|
||||||
args.Add("Rom Files");
|
|
||||||
if (!CurrentDescription.NeedsArchives)
|
if (!CurrentDescription.NeedsArchives)
|
||||||
filter += ";%ARCH%";
|
filter += ";%ARCH%";
|
||||||
args.Add(filter);
|
args.Add(filter);
|
||||||
|
|
|
@ -1,10 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Data;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
|
|
|
@ -47,12 +47,10 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
public static IEnumerable<string> GetDeviceNames()
|
public static IEnumerable<string> GetDeviceNames()
|
||||||
{
|
{
|
||||||
using (XAudio2 device = new XAudio2())
|
using XAudio2 device = new XAudio2();
|
||||||
{
|
return Enumerable.Range(0, device.DeviceCount)
|
||||||
return Enumerable.Range(0, device.DeviceCount)
|
.Select(n => device.GetDeviceDetails(n).DisplayName)
|
||||||
.Select(n => device.GetDeviceDetails(n).DisplayName)
|
.ToList(); // enumerate before local var device is disposed
|
||||||
.ToList(); // enumerate before local var device is disposed
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int BufferSizeSamples { get; set; }
|
private int BufferSizeSamples { get; set; }
|
||||||
|
@ -126,8 +124,8 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
private class BufferPool : IDisposable
|
private class BufferPool : IDisposable
|
||||||
{
|
{
|
||||||
private List<BufferPoolItem> _availableItems = new List<BufferPoolItem>();
|
private readonly List<BufferPoolItem> _availableItems = new List<BufferPoolItem>();
|
||||||
private Queue<BufferPoolItem> _obtainedItems = new Queue<BufferPoolItem>();
|
private readonly Queue<BufferPoolItem> _obtainedItems = new Queue<BufferPoolItem>();
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
|
|
@ -40,10 +40,8 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
private static SizeF GetCurrentAutoScaleSize(AutoScaleMode autoScaleMode)
|
private static SizeF GetCurrentAutoScaleSize(AutoScaleMode autoScaleMode)
|
||||||
{
|
{
|
||||||
using (var form = new Form { AutoScaleMode = autoScaleMode })
|
using var form = new Form { AutoScaleMode = autoScaleMode };
|
||||||
{
|
return form.CurrentAutoScaleDimensions;
|
||||||
return form.CurrentAutoScaleDimensions;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
using BizHawk.Emulation.Cores.Nintendo.SNES;
|
using BizHawk.Emulation.Cores.Nintendo.SNES;
|
||||||
using BizHawk.Client.Common;
|
|
||||||
using BizHawk.Client.EmuHawk.WinFormExtensions;
|
using BizHawk.Client.EmuHawk.WinFormExtensions;
|
||||||
|
|
||||||
namespace BizHawk.Client.EmuHawk
|
namespace BizHawk.Client.EmuHawk
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
using BizHawk.Emulation.Common.IEmulatorExtensions;
|
|
||||||
using BizHawk.Client.Common;
|
|
||||||
|
|
||||||
namespace BizHawk.Client.EmuHawk
|
namespace BizHawk.Client.EmuHawk
|
||||||
{
|
{
|
||||||
|
@ -18,13 +14,10 @@ namespace BizHawk.Client.EmuHawk
|
||||||
[RequiredService]
|
[RequiredService]
|
||||||
private IMemoryDomains MemoryDomains { get; set; }
|
private IMemoryDomains MemoryDomains { get; set; }
|
||||||
|
|
||||||
private IMemoryCallbackSystem MemoryCallbacks { get { return Debuggable.MemoryCallbacks; } }
|
private IMemoryCallbackSystem MemoryCallbacks => Debuggable.MemoryCallbacks;
|
||||||
|
|
||||||
|
|
||||||
private RegisterValue PCRegister
|
private RegisterValue PCRegister => Debuggable.GetCpuFlagsAndRegisters()[Disassembler.PCRegisterName];
|
||||||
{
|
|
||||||
get { return Debuggable.GetCpuFlagsAndRegisters()[Disassembler.PCRegisterName]; }
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Implementation checking
|
#region Implementation checking
|
||||||
|
|
||||||
|
@ -161,15 +154,8 @@ namespace BizHawk.Client.EmuHawk
|
||||||
EngageDebugger();
|
EngageDebugger();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool AskSaveChanges()
|
public bool AskSaveChanges() => true;
|
||||||
{
|
|
||||||
// TODO
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool UpdateBefore
|
public bool UpdateBefore => false;
|
||||||
{
|
|
||||||
get { return false; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
|
|
|
@ -194,7 +194,6 @@
|
||||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||||
this.Text = "Music Ripper";
|
this.Text = "Music Ripper";
|
||||||
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.NESMusicRipper_FormClosed);
|
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.NESMusicRipper_FormClosed);
|
||||||
this.Load += new System.EventHandler(this.NESMusicRipper_Load);
|
|
||||||
this.groupBox1.ResumeLayout(false);
|
this.groupBox1.ResumeLayout(false);
|
||||||
this.groupBox1.PerformLayout();
|
this.groupBox1.PerformLayout();
|
||||||
this.groupBox2.ResumeLayout(false);
|
this.groupBox2.ResumeLayout(false);
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
public partial class NESMusicRipper : Form, IToolFormAutoConfig
|
public partial class NESMusicRipper : Form, IToolFormAutoConfig
|
||||||
{
|
{
|
||||||
[RequiredService]
|
[RequiredService]
|
||||||
private NES nes { get; set; }
|
private NES Nes { get; set; }
|
||||||
|
|
||||||
public NESMusicRipper()
|
public NESMusicRipper()
|
||||||
{
|
{
|
||||||
|
@ -20,7 +20,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
SyncContents();
|
SyncContents();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool AskSaveChanges() { return true; }
|
public bool AskSaveChanges() => true;
|
||||||
public bool UpdateBefore => true;
|
public bool UpdateBefore => true;
|
||||||
|
|
||||||
public void Restart()
|
public void Restart()
|
||||||
|
@ -113,8 +113,10 @@ namespace BizHawk.Client.EmuHawk
|
||||||
{
|
{
|
||||||
Filter = "XRNS (*.xrns)|*.xrns"
|
Filter = "XRNS (*.xrns)|*.xrns"
|
||||||
};
|
};
|
||||||
if (sfd.ShowDialog() != System.Windows.Forms.DialogResult.OK)
|
if (sfd.ShowDialog() != DialogResult.OK)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//configuration:
|
//configuration:
|
||||||
var outPath = sfd.FileName;
|
var outPath = sfd.FileName;
|
||||||
|
@ -127,13 +129,11 @@ namespace BizHawk.Client.EmuHawk
|
||||||
var zfTemplate = new ICSharpCode.SharpZipLib.Zip.ZipFile(templatePath);
|
var zfTemplate = new ICSharpCode.SharpZipLib.Zip.ZipFile(templatePath);
|
||||||
{
|
{
|
||||||
int zfSongXmlIndex = zfTemplate.FindEntry("Song.xml", true);
|
int zfSongXmlIndex = zfTemplate.FindEntry("Song.xml", true);
|
||||||
using (var zis = zfTemplate.GetInputStream(zfTemplate.GetEntry("Song.xml")))
|
using var zis = zfTemplate.GetInputStream(zfTemplate.GetEntry("Song.xml"));
|
||||||
{
|
byte[] buffer = new byte[4096]; // 4K is optimum
|
||||||
byte[] buffer = new byte[4096]; // 4K is optimum
|
ICSharpCode.SharpZipLib.Core.StreamUtils.Copy(zis, msSongXml, buffer);
|
||||||
ICSharpCode.SharpZipLib.Core.StreamUtils.Copy(zis, msSongXml, buffer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
XElement templateRoot = XElement.Parse(System.Text.Encoding.UTF8.GetString(msSongXml.ToArray()));
|
var templateRoot = XElement.Parse(System.Text.Encoding.UTF8.GetString(msSongXml.ToArray()));
|
||||||
|
|
||||||
//get the pattern pool, and whack the child nodes
|
//get the pattern pool, and whack the child nodes
|
||||||
var xPatterns = templateRoot.XPathSelectElement("//Patterns");
|
var xPatterns = templateRoot.XPathSelectElement("//Patterns");
|
||||||
|
@ -424,7 +424,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
//fpulse = fCPU/(16*(t+1)) (where fCPU is 1.789773 MHz for NTSC, 1.662607 MHz for PAL, and 1.773448 MHz for Dendy)
|
//fpulse = fCPU/(16*(t+1)) (where fCPU is 1.789773 MHz for NTSC, 1.662607 MHz for PAL, and 1.773448 MHz for Dendy)
|
||||||
//ftriangle = fCPU/(32*(tval + 1))
|
//ftriangle = fCPU/(32*(tval + 1))
|
||||||
|
|
||||||
var apu = nes.apu;
|
var apu = Nes.apu;
|
||||||
|
|
||||||
//evaluate the pitches
|
//evaluate the pitches
|
||||||
int pulse0_period = apu.pulse[0].timer_reload_value;
|
int pulse0_period = apu.pulse[0].timer_reload_value;
|
||||||
|
@ -475,16 +475,16 @@ namespace BizHawk.Client.EmuHawk
|
||||||
if(IsRunning)
|
if(IsRunning)
|
||||||
{
|
{
|
||||||
SyncContents();
|
SyncContents();
|
||||||
nes.apu.DebugCallback = null;
|
Nes.apu.DebugCallback = null;
|
||||||
nes.apu.DebugCallbackDivider = 0;
|
Nes.apu.DebugCallbackDivider = 0;
|
||||||
IsRunning = false;
|
IsRunning = false;
|
||||||
btnControl.Text = "Start";
|
btnControl.Text = "Start";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log.Clear();
|
Log.Clear();
|
||||||
nes.apu.DebugCallback = DebugCallback;
|
Nes.apu.DebugCallback = DebugCallback;
|
||||||
nes.apu.DebugCallbackDivider = int.Parse(txtDivider.Text);
|
Nes.apu.DebugCallbackDivider = int.Parse(txtDivider.Text);
|
||||||
IsRunning = true;
|
IsRunning = true;
|
||||||
btnControl.Text = "Stop";
|
btnControl.Text = "Stop";
|
||||||
}
|
}
|
||||||
|
@ -497,15 +497,10 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
private void NESMusicRipper_FormClosed(object sender, FormClosedEventArgs e)
|
private void NESMusicRipper_FormClosed(object sender, FormClosedEventArgs e)
|
||||||
{
|
{
|
||||||
var apu = nes.apu;
|
var apu = Nes.apu;
|
||||||
apu.DebugCallbackDivider = 0;
|
apu.DebugCallbackDivider = 0;
|
||||||
apu.DebugCallbackTimer = 0;
|
apu.DebugCallbackTimer = 0;
|
||||||
apu.DebugCallback = null;
|
apu.DebugCallback = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void NESMusicRipper_Load(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
get => _x;
|
get => _x;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_x = RangeX.Constrain(value);
|
_x = _rangeX.Constrain(value);
|
||||||
SetAnalog();
|
SetAnalog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
get => _y;
|
get => _y;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_y = RangeY.Constrain(value);
|
_y = _rangeY.Constrain(value);
|
||||||
SetAnalog();
|
SetAnalog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,13 +42,13 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
private IController _previous;
|
private IController _previous;
|
||||||
|
|
||||||
private sbyte UserRangePercentageX = 100;
|
private sbyte _userRangePercentageX = 100;
|
||||||
private sbyte UserRangePercentageY = 100;
|
private sbyte _userRangePercentageY = 100;
|
||||||
|
|
||||||
public void SetUserRange(decimal rx, decimal ry)
|
public void SetUserRange(decimal rx, decimal ry)
|
||||||
{
|
{
|
||||||
UserRangePercentageX = (sbyte) rx;
|
_userRangePercentageX = (sbyte) rx;
|
||||||
UserRangePercentageY = (sbyte) ry;
|
_userRangePercentageY = (sbyte) ry;
|
||||||
|
|
||||||
Rerange();
|
Rerange();
|
||||||
Refresh();
|
Refresh();
|
||||||
|
@ -56,42 +56,42 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
public void SetRangeX(float[] range)
|
public void SetRangeX(float[] range)
|
||||||
{
|
{
|
||||||
ActualRangeX.Min = (int) range[0];
|
_actualRangeX.Min = (int) range[0];
|
||||||
ActualRangeX.Max = (int) range[2];
|
_actualRangeX.Max = (int) range[2];
|
||||||
|
|
||||||
Rerange();
|
Rerange();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetRangeY(float[] range)
|
public void SetRangeY(float[] range)
|
||||||
{
|
{
|
||||||
ActualRangeY.Min = (int) range[0];
|
_actualRangeY.Min = (int) range[0];
|
||||||
ActualRangeY.Max = (int) range[2];
|
_actualRangeY.Max = (int) range[2];
|
||||||
|
|
||||||
Rerange();
|
Rerange();
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly MutableIntRange RangeX = new MutableIntRange(-128, 127);
|
private readonly MutableIntRange _rangeX = new MutableIntRange(-128, 127);
|
||||||
private readonly MutableIntRange RangeY = new MutableIntRange(-128, 127);
|
private readonly MutableIntRange _rangeY = new MutableIntRange(-128, 127);
|
||||||
private readonly MutableIntRange ActualRangeX = new MutableIntRange(-128, 127);
|
private readonly MutableIntRange _actualRangeX = new MutableIntRange(-128, 127);
|
||||||
private readonly MutableIntRange ActualRangeY = new MutableIntRange(-128, 127);
|
private readonly MutableIntRange _actualRangeY = new MutableIntRange(-128, 127);
|
||||||
|
|
||||||
private bool ReverseX;
|
private bool _reverseX;
|
||||||
private bool ReverseY;
|
private bool _reverseY;
|
||||||
|
|
||||||
private void Rerange()
|
private void Rerange()
|
||||||
{
|
{
|
||||||
ReverseX = UserRangePercentageX < 0;
|
_reverseX = _userRangePercentageX < 0;
|
||||||
ReverseY = UserRangePercentageY < 0;
|
_reverseY = _userRangePercentageY < 0;
|
||||||
|
|
||||||
var midX = (ActualRangeX.Min + ActualRangeX.Max) / 2.0;
|
var midX = (_actualRangeX.Min + _actualRangeX.Max) / 2.0;
|
||||||
var halfRangeX = (ReverseX ? -1 : 1) * (ActualRangeX.Max - ActualRangeX.Min) * UserRangePercentageX / 200.0;
|
var halfRangeX = (_reverseX ? -1 : 1) * (_actualRangeX.Max - _actualRangeX.Min) * _userRangePercentageX / 200.0;
|
||||||
RangeX.Min = (int) (midX - halfRangeX);
|
_rangeX.Min = (int) (midX - halfRangeX);
|
||||||
RangeX.Max = (int) (midX + halfRangeX);
|
_rangeX.Max = (int) (midX + halfRangeX);
|
||||||
|
|
||||||
var midY = (ActualRangeY.Min + ActualRangeY.Max) / 2.0;
|
var midY = (_actualRangeY.Min + _actualRangeY.Max) / 2.0;
|
||||||
var halfRangeY = (ReverseY ? -1 : 1) * (ActualRangeY.Max - ActualRangeY.Min) * UserRangePercentageY / 200.0;
|
var halfRangeY = (_reverseY ? -1 : 1) * (_actualRangeY.Max - _actualRangeY.Min) * _userRangePercentageY / 200.0;
|
||||||
RangeY.Min = (int) (midY - halfRangeY);
|
_rangeY.Min = (int) (midY - halfRangeY);
|
||||||
RangeY.Max = (int) (midY + halfRangeY);
|
_rangeY.Max = (int) (midY + halfRangeY);
|
||||||
|
|
||||||
// re-constrain after changing ranges
|
// re-constrain after changing ranges
|
||||||
X = X;
|
X = X;
|
||||||
|
@ -108,12 +108,12 @@ namespace BizHawk.Client.EmuHawk
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// min + (max - i) == max - (i - min) == min + max - i
|
/// min + (max - i) == max - (i - min) == min + max - i
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
private int MaybeReversedInX(int i) => ReverseX ? RangeX.Min + RangeX.Max - i : i;
|
private int MaybeReversedInX(int i) => _reverseX ? _rangeX.Min + _rangeX.Max - i : i;
|
||||||
/// <inheritdoc cref="MaybeReversedInX"/>
|
/// <inheritdoc cref="MaybeReversedInX"/>
|
||||||
private int MaybeReversedInY(int i) => ReverseY ? RangeY.Min + RangeY.Max - i : i;
|
private int MaybeReversedInY(int i) => _reverseY ? _rangeY.Min + _rangeY.Max - i : i;
|
||||||
|
|
||||||
private int PixelSizeX => (int)(RangeX.GetCount() * ScaleX);
|
private int PixelSizeX => (int)(_rangeX.GetCount() * ScaleX);
|
||||||
private int PixelSizeY => (int)(RangeY.GetCount() * ScaleY);
|
private int PixelSizeY => (int)(_rangeY.GetCount() * ScaleY);
|
||||||
private int PixelMinX => (Size.Width - PixelSizeX) / 2;
|
private int PixelMinX => (Size.Width - PixelSizeX) / 2;
|
||||||
private int PixelMinY => (Size.Height - PixelSizeY) / 2;
|
private int PixelMinY => (Size.Height - PixelSizeY) / 2;
|
||||||
private int PixelMidX => PixelMinX + PixelSizeX / 2;
|
private int PixelMidX => PixelMinX + PixelSizeX / 2;
|
||||||
|
@ -122,23 +122,23 @@ namespace BizHawk.Client.EmuHawk
|
||||||
private int PixelMaxY => PixelMinY + PixelSizeY - 1;
|
private int PixelMaxY => PixelMinY + PixelSizeY - 1;
|
||||||
|
|
||||||
private int RealToGfxX(int val) =>
|
private int RealToGfxX(int val) =>
|
||||||
PixelMinX + ((MaybeReversedInX(RangeX.Constrain(val)) - RangeX.Min) * ScaleX).RoundToInt();
|
PixelMinX + ((MaybeReversedInX(_rangeX.Constrain(val)) - _rangeX.Min) * ScaleX).RoundToInt();
|
||||||
|
|
||||||
private int RealToGfxY(int val) =>
|
private int RealToGfxY(int val) =>
|
||||||
PixelMinY + ((MaybeReversedInY(RangeY.Constrain(val)) - RangeY.Min) * ScaleY).RoundToInt();
|
PixelMinY + ((MaybeReversedInY(_rangeY.Constrain(val)) - _rangeY.Min) * ScaleY).RoundToInt();
|
||||||
|
|
||||||
private int GfxToRealX(int val) =>
|
private int GfxToRealX(int val) =>
|
||||||
MaybeReversedInX(RangeX.Constrain(RangeX.Min + ((val - PixelMinX) / ScaleX).RoundToInt()));
|
MaybeReversedInX(_rangeX.Constrain(_rangeX.Min + ((val - PixelMinX) / ScaleX).RoundToInt()));
|
||||||
|
|
||||||
private int GfxToRealY(int val) =>
|
private int GfxToRealY(int val) =>
|
||||||
MaybeReversedInY(RangeY.Constrain(RangeY.Min + ((val - PixelMinY) / ScaleY).RoundToInt()));
|
MaybeReversedInY(_rangeY.Constrain(_rangeY.Min + ((val - PixelMinY) / ScaleY).RoundToInt()));
|
||||||
|
|
||||||
private readonly Pen BlackPen = new Pen(Brushes.Black);
|
private readonly Pen _blackPen = new Pen(Brushes.Black);
|
||||||
private readonly Pen BluePen = new Pen(Brushes.Blue, 2);
|
private readonly Pen _bluePen = new Pen(Brushes.Blue, 2);
|
||||||
private readonly Pen GrayPen = new Pen(Brushes.Gray, 2);
|
private readonly Pen _grayPen = new Pen(Brushes.Gray, 2);
|
||||||
|
|
||||||
private readonly Bitmap Dot = new Bitmap(7, 7);
|
private readonly Bitmap _dot = new Bitmap(7, 7);
|
||||||
private readonly Bitmap GrayDot = new Bitmap(7, 7);
|
private readonly Bitmap _grayDot = new Bitmap(7, 7);
|
||||||
|
|
||||||
public Action ClearCallback { private get; set; }
|
public Action ClearCallback { private get; set; }
|
||||||
|
|
||||||
|
@ -160,22 +160,18 @@ namespace BizHawk.Client.EmuHawk
|
||||||
BorderStyle = BorderStyle.Fixed3D;
|
BorderStyle = BorderStyle.Fixed3D;
|
||||||
|
|
||||||
// Draw the dot into a bitmap
|
// Draw the dot into a bitmap
|
||||||
using (var g = Graphics.FromImage(Dot))
|
using var g = Graphics.FromImage(_dot);
|
||||||
{
|
g.Clear(Color.Transparent);
|
||||||
g.Clear(Color.Transparent);
|
var redBrush = Brushes.Red;
|
||||||
var redBrush = Brushes.Red;
|
g.FillRectangle(redBrush, 2, 0, 3, 7);
|
||||||
g.FillRectangle(redBrush, 2, 0, 3, 7);
|
g.FillRectangle(redBrush, 1, 1, 5, 5);
|
||||||
g.FillRectangle(redBrush, 1, 1, 5, 5);
|
g.FillRectangle(redBrush, 0, 2, 7, 3);
|
||||||
g.FillRectangle(redBrush, 0, 2, 7, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var gg = Graphics.FromImage(GrayDot))
|
using var gg = Graphics.FromImage(_grayDot);
|
||||||
{
|
gg.Clear(Color.Transparent);
|
||||||
gg.Clear(Color.Transparent);
|
gg.FillRectangle(Brushes.Gray, 2, 0, 3, 7);
|
||||||
gg.FillRectangle(Brushes.Gray, 2, 0, 3, 7);
|
gg.FillRectangle(Brushes.Gray, 1, 1, 5, 5);
|
||||||
gg.FillRectangle(Brushes.Gray, 1, 1, 5, 5);
|
gg.FillRectangle(Brushes.Gray, 0, 2, 7, 3);
|
||||||
gg.FillRectangle(Brushes.Gray, 0, 2, 7, 3);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetAnalog()
|
private void SetAnalog()
|
||||||
|
@ -194,24 +190,24 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
e.Graphics.FillRectangle(Brushes.LightGray, PixelMinX, PixelMinY, PixelMaxX - PixelMinX, PixelMaxY - PixelMinY);
|
e.Graphics.FillRectangle(Brushes.LightGray, PixelMinX, PixelMinY, PixelMaxX - PixelMinX, PixelMaxY - PixelMinY);
|
||||||
e.Graphics.FillEllipse(ReadOnly ? Brushes.Beige : Brushes.White, PixelMinX, PixelMinY, PixelMaxX - PixelMinX - 2, PixelMaxY - PixelMinY - 3);
|
e.Graphics.FillEllipse(ReadOnly ? Brushes.Beige : Brushes.White, PixelMinX, PixelMinY, PixelMaxX - PixelMinX - 2, PixelMaxY - PixelMinY - 3);
|
||||||
e.Graphics.DrawEllipse(BlackPen, PixelMinX, PixelMinY, PixelMaxX - PixelMinX - 2, PixelMaxY - PixelMinY - 3);
|
e.Graphics.DrawEllipse(_blackPen, PixelMinX, PixelMinY, PixelMaxX - PixelMinX - 2, PixelMaxY - PixelMinY - 3);
|
||||||
e.Graphics.DrawLine(BlackPen, PixelMidX, 0, PixelMidX, PixelMaxY);
|
e.Graphics.DrawLine(_blackPen, PixelMidX, 0, PixelMidX, PixelMaxY);
|
||||||
e.Graphics.DrawLine(BlackPen, 0, PixelMidY, PixelMaxX, PixelMidY);
|
e.Graphics.DrawLine(_blackPen, 0, PixelMidY, PixelMaxX, PixelMidY);
|
||||||
|
|
||||||
// Previous frame
|
// Previous frame
|
||||||
if (_previous != null)
|
if (_previous != null)
|
||||||
{
|
{
|
||||||
var pX = (int)_previous.GetFloat(XName);
|
var pX = (int)_previous.GetFloat(XName);
|
||||||
var pY = (int)_previous.GetFloat(YName);
|
var pY = (int)_previous.GetFloat(YName);
|
||||||
e.Graphics.DrawLine(GrayPen, PixelMidX, PixelMidY, RealToGfxX(pX), RealToGfxY(pY));
|
e.Graphics.DrawLine(_grayPen, PixelMidX, PixelMidY, RealToGfxX(pX), RealToGfxY(pY));
|
||||||
e.Graphics.DrawImage(GrayDot, RealToGfxX(pX) - 3, RealToGfxY(RangeY.Max) - RealToGfxY(pY) - 3);
|
e.Graphics.DrawImage(_grayDot, RealToGfxX(pX) - 3, RealToGfxY(_rangeY.Max) - RealToGfxY(pY) - 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Line
|
// Line
|
||||||
if (HasValue)
|
if (HasValue)
|
||||||
{
|
{
|
||||||
e.Graphics.DrawLine(BluePen, PixelMidX, PixelMidY, RealToGfxX(X), RealToGfxY(Y));
|
e.Graphics.DrawLine(_bluePen, PixelMidX, PixelMidY, RealToGfxX(X), RealToGfxY(Y));
|
||||||
e.Graphics.DrawImage(ReadOnly ? GrayDot : Dot, RealToGfxX(X) - 3, RealToGfxY(Y) - 3);
|
e.Graphics.DrawImage(ReadOnly ? _grayDot : _dot, RealToGfxX(X) - 3, RealToGfxY(Y) - 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -319,6 +319,7 @@
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=preload/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=preload/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Prereqs/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Prereqs/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=prescale/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=prescale/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Quantizer/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=quickload/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=quickload/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=quicknes/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=quicknes/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=quicksave/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=quicksave/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
@ -379,6 +380,7 @@
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Virtualpad/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Virtualpad/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=vram/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=vram/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Vsync/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Vsync/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Waterbox/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Winform/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Winform/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=winforms/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=winforms/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=WSWAN/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=WSWAN/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
|
Loading…
Reference in New Issue