cleanups
This commit is contained in:
parent
094ae65e06
commit
64ea9afee5
|
@ -19,11 +19,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
/// </summary>
|
||||
public int Frameskip
|
||||
{
|
||||
get
|
||||
{
|
||||
return _frameskip;
|
||||
}
|
||||
|
||||
get => _frameskip;
|
||||
private set
|
||||
{
|
||||
if (value < 0)
|
||||
|
@ -46,11 +42,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
/// </summary>
|
||||
public int FrameDelay
|
||||
{
|
||||
get
|
||||
{
|
||||
return _framedelay;
|
||||
}
|
||||
|
||||
get => _framedelay;
|
||||
private set
|
||||
{
|
||||
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;
|
||||
FrameDelay = framedelay;
|
||||
FrameDelay = frameDelay;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,9 +84,9 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
public void SetVideoCodecToken(IDisposable token)
|
||||
{
|
||||
if (token is GifToken)
|
||||
if (token is GifToken gifToken)
|
||||
{
|
||||
_token = (GifToken)token;
|
||||
_token = gifToken;
|
||||
CalcDelay();
|
||||
}
|
||||
else
|
||||
|
@ -169,35 +161,31 @@ namespace BizHawk.Client.EmuHawk
|
|||
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);
|
||||
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)
|
||||
{
|
||||
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];
|
||||
}
|
||||
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];
|
||||
}
|
||||
|
||||
public void AddSamples(short[] samples)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using System.Windows.Forms;
|
||||
|
||||
using BizHawk.Client.Common;
|
||||
using BizHawk.Client.EmuHawk.WinFormExtensions;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
|
@ -14,23 +15,23 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
public static GifWriter.GifToken DoTokenForm(IWin32Window parent)
|
||||
{
|
||||
using (var dlg = new GifWriterForm())
|
||||
using var dlg = new GifWriterForm
|
||||
{
|
||||
dlg.numericUpDown1.Value = Global.Config.GifWriterFrameskip;
|
||||
dlg.numericUpDown2.Value = Global.Config.GifWriterDelay;
|
||||
dlg.NumericUpDown2_ValueChanged(null, null);
|
||||
numericUpDown1 = { Value = Global.Config.GifWriterFrameskip },
|
||||
numericUpDown2 = { Value = Global.Config.GifWriterDelay }
|
||||
};
|
||||
dlg.NumericUpDown2_ValueChanged(null, null);
|
||||
|
||||
var result = dlg.ShowDialog(parent);
|
||||
if (result == DialogResult.OK)
|
||||
{
|
||||
Global.Config.GifWriterFrameskip = (int)dlg.numericUpDown1.Value;
|
||||
Global.Config.GifWriterDelay = (int)dlg.numericUpDown2.Value;
|
||||
var result = dlg.ShowDialog(parent);
|
||||
if (result.IsOk())
|
||||
{
|
||||
Global.Config.GifWriterFrameskip = (int)dlg.numericUpDown1.Value;
|
||||
Global.Config.GifWriterDelay = (int)dlg.numericUpDown2.Value;
|
||||
|
||||
return GifWriter.GifToken.LoadFromConfig();
|
||||
}
|
||||
|
||||
return null;
|
||||
return GifWriter.GifToken.LoadFromConfig();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void NumericUpDown2_ValueChanged(object sender, EventArgs e)
|
||||
|
|
|
@ -22,351 +22,348 @@ using System.Drawing.Imaging;
|
|||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
/// <summary>
|
||||
/// Summary description for Class1.
|
||||
/// </summary>
|
||||
internal unsafe abstract class Quantizer
|
||||
{
|
||||
/// <summary>
|
||||
/// 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;
|
||||
}
|
||||
internal abstract unsafe class Quantizer
|
||||
{
|
||||
/// <summary>
|
||||
/// Flag used to indicate whether a single pass or two passes are needed for quantization.
|
||||
/// </summary>
|
||||
private bool _singlePass;
|
||||
|
||||
set
|
||||
{
|
||||
highquality = value;
|
||||
}
|
||||
}
|
||||
protected bool highquality;
|
||||
public bool HighQuality
|
||||
{
|
||||
get
|
||||
{
|
||||
return highquality;
|
||||
}
|
||||
|
||||
protected int ditherLevel;
|
||||
public int DitherLevel
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.ditherLevel;
|
||||
}
|
||||
set
|
||||
{
|
||||
highquality = value;
|
||||
}
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
this.ditherLevel = value;
|
||||
}
|
||||
}
|
||||
protected int ditherLevel;
|
||||
public int DitherLevel
|
||||
{
|
||||
get
|
||||
{
|
||||
return ditherLevel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct the quantizer
|
||||
/// </summary>
|
||||
/// <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;
|
||||
}
|
||||
set
|
||||
{
|
||||
ditherLevel = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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;
|
||||
/// <summary>
|
||||
/// Construct the quantizer
|
||||
/// </summary>
|
||||
/// <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;
|
||||
}
|
||||
|
||||
// And construct a rectangle from these dimensions
|
||||
Rectangle bounds = new Rectangle(0, 0, width, height);
|
||||
/// <summary>
|
||||
/// 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
|
||||
Bitmap copy;
|
||||
|
||||
if (source is Bitmap && source.PixelFormat == PixelFormat.Format32bppArgb)
|
||||
{
|
||||
copy = (Bitmap)source;
|
||||
}
|
||||
else
|
||||
{
|
||||
copy = new Bitmap(width, height, PixelFormat.Format32bppArgb);
|
||||
// And construct a rectangle from these dimensions
|
||||
Rectangle bounds = new Rectangle(0, 0, width, height);
|
||||
|
||||
// Now lock the bitmap into memory
|
||||
using (Graphics g = Graphics.FromImage(copy))
|
||||
{
|
||||
g.PageUnit = GraphicsUnit.Pixel;
|
||||
// First off take a 32bpp copy of the image
|
||||
Bitmap copy;
|
||||
|
||||
// Draw the source image onto the copy bitmap,
|
||||
// which will effect a widening as appropriate.
|
||||
g.DrawImage(source, 0, 0, bounds.Width, bounds.Height);
|
||||
}
|
||||
}
|
||||
if (source is Bitmap && source.PixelFormat == PixelFormat.Format32bppArgb)
|
||||
{
|
||||
copy = (Bitmap)source;
|
||||
}
|
||||
else
|
||||
{
|
||||
copy = new Bitmap(width, height, PixelFormat.Format32bppArgb);
|
||||
|
||||
// And construct an 8bpp version
|
||||
Bitmap output = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
|
||||
// Now lock the bitmap into memory
|
||||
using (Graphics g = Graphics.FromImage(copy))
|
||||
{
|
||||
g.PageUnit = GraphicsUnit.Pixel;
|
||||
|
||||
// Define a pointer to the bitmap data
|
||||
BitmapData sourceData = null;
|
||||
// Draw the source image onto the copy bitmap,
|
||||
// which will effect a widening as appropriate.
|
||||
g.DrawImage(source, 0, 0, bounds.Width, bounds.Height);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Get the source image bits and lock into memory
|
||||
sourceData = copy.LockBits(bounds, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
|
||||
// And construct an 8bpp version
|
||||
Bitmap output = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
|
||||
|
||||
// Call the FirstPass function if not a single pass algorithm.
|
||||
// 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);
|
||||
}
|
||||
// Define a pointer to the bitmap data
|
||||
BitmapData sourceData = null;
|
||||
|
||||
// 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.
|
||||
output.Palette = this.GetPalette(output.Palette);
|
||||
try
|
||||
{
|
||||
// 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
|
||||
SecondPass(sourceData, output, width, height, bounds);
|
||||
}
|
||||
// Call the FirstPass function if not a single pass algorithm.
|
||||
// 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
|
||||
{
|
||||
// Ensure that the bits are unlocked
|
||||
copy.UnlockBits(sourceData);
|
||||
}
|
||||
// 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.
|
||||
output.Palette = this.GetPalette(output.Palette);
|
||||
|
||||
if (copy != source)
|
||||
{
|
||||
copy.Dispose();
|
||||
}
|
||||
// Then call the second pass which actually does the conversion
|
||||
SecondPass(sourceData, output, width, height, bounds);
|
||||
}
|
||||
|
||||
// Last but not least, return the output bitmap
|
||||
return output;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Ensure that the bits are unlocked
|
||||
copy.UnlockBits(sourceData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute the first pass through the pixels in the image
|
||||
/// </summary>
|
||||
/// <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;
|
||||
if (copy != source)
|
||||
{
|
||||
copy.Dispose();
|
||||
}
|
||||
|
||||
// Loop through each row
|
||||
for (int row = 0; row < height; row++)
|
||||
{
|
||||
// Set the source pixel to the first pixel in this row
|
||||
pSourcePixel = (Int32*)pSourceRow;
|
||||
// Last but not least, return the output bitmap
|
||||
return output;
|
||||
}
|
||||
|
||||
// And loop through each column
|
||||
for (int col = 0; col < width; col++, pSourcePixel++)
|
||||
{
|
||||
InitialQuantizePixel(*pSourcePixel);
|
||||
}
|
||||
/// <summary>
|
||||
/// Execute the first pass through the pixels in the image
|
||||
/// </summary>
|
||||
/// <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
|
||||
pSourceRow += sourceData.Stride;
|
||||
// Loop through each row
|
||||
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)
|
||||
{
|
||||
if (val < 0) return 0;
|
||||
else if (val > 255) return 255;
|
||||
else return val;
|
||||
}
|
||||
// Add the stride to the source row
|
||||
pSourceRow += sourceData.Stride;
|
||||
|
||||
/// <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
|
||||
{
|
||||
// Lock the output bitmap into memory
|
||||
outputData = output.LockBits(bounds, ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);
|
||||
int ClampToByte(int val)
|
||||
{
|
||||
if (val < 0) return 0;
|
||||
else if (val > 255) return 255;
|
||||
else return val;
|
||||
}
|
||||
|
||||
// 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();
|
||||
Int32* pSourcePixel = (Int32 *)pSourceRow;
|
||||
/// <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;
|
||||
|
||||
// Now define the destination data pointers
|
||||
byte* pDestinationRow = (byte *)outputData.Scan0.ToPointer();
|
||||
byte* pDestinationPixel = pDestinationRow;
|
||||
try
|
||||
{
|
||||
// Lock the output bitmap into memory
|
||||
outputData = output.LockBits(bounds, ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);
|
||||
|
||||
int[] errorThisRowR = new int[width + 1];
|
||||
int[] errorThisRowG = new int[width + 1];
|
||||
int[] errorThisRowB = new int[width + 1];
|
||||
// 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();
|
||||
Int32* pSourcePixel = (Int32*)pSourceRow;
|
||||
|
||||
for (int row = 0; row < height; row++)
|
||||
{
|
||||
int[] errorNextRowR = new int[width + 1];
|
||||
int[] errorNextRowG = new int[width + 1];
|
||||
int[] errorNextRowB = new int[width + 1];
|
||||
// Now define the destination data pointers
|
||||
byte* pDestinationRow = (byte*)outputData.Scan0.ToPointer();
|
||||
byte* pDestinationPixel = pDestinationRow;
|
||||
|
||||
int ptrInc;
|
||||
int[] errorThisRowR = new int[width + 1];
|
||||
int[] errorThisRowG = new int[width + 1];
|
||||
int[] errorThisRowB = new int[width + 1];
|
||||
|
||||
if ((row & 1) == 0)
|
||||
{
|
||||
pSourcePixel = (Int32*)pSourceRow;
|
||||
pDestinationPixel = pDestinationRow;
|
||||
ptrInc = +1;
|
||||
}
|
||||
else
|
||||
{
|
||||
pSourcePixel = (Int32*)pSourceRow + width - 1;
|
||||
pDestinationPixel = pDestinationRow + width - 1;
|
||||
ptrInc = -1;
|
||||
}
|
||||
for (int row = 0; row < height; row++)
|
||||
{
|
||||
int[] errorNextRowR = new int[width + 1];
|
||||
int[] errorNextRowG = new int[width + 1];
|
||||
int[] errorNextRowB = new int[width + 1];
|
||||
|
||||
// Loop through each pixel on this scan line
|
||||
for (int col = 0; col < width; ++col)
|
||||
{
|
||||
// Quantize the pixel
|
||||
int srcPixel = *pSourcePixel;
|
||||
int ptrInc;
|
||||
|
||||
int srcR = srcPixel & 0xFF; //not
|
||||
int srcG = (srcPixel>>8) & 0xFF; //a
|
||||
int srcB = (srcPixel>>16) & 0xFF; //mistake
|
||||
int srcA = (srcPixel >> 24) & 0xFF;
|
||||
if ((row & 1) == 0)
|
||||
{
|
||||
pSourcePixel = (Int32*)pSourceRow;
|
||||
pDestinationPixel = pDestinationRow;
|
||||
ptrInc = +1;
|
||||
}
|
||||
else
|
||||
{
|
||||
pSourcePixel = (Int32*)pSourceRow + width - 1;
|
||||
pDestinationPixel = pDestinationRow + width - 1;
|
||||
ptrInc = -1;
|
||||
}
|
||||
|
||||
int targetB = ClampToByte(srcB - ((errorThisRowB[col] * weight) / 8));
|
||||
int targetG = ClampToByte(srcG - ((errorThisRowG[col] * weight) / 8));
|
||||
int targetR = ClampToByte(srcR - ((errorThisRowR[col] * weight) / 8));
|
||||
int targetA = srcA;
|
||||
// Loop through each pixel on this scan line
|
||||
for (int col = 0; col < width; ++col)
|
||||
{
|
||||
// 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);
|
||||
*pDestinationPixel = pixelValue;
|
||||
int targetB = ClampToByte(srcB - ((errorThisRowB[col] * weight) / 8));
|
||||
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;
|
||||
int actualG = (actual >> 8) & 0xFF;
|
||||
int actualB = (actual >> 16) & 0xFF;
|
||||
int errorR = actualR - targetR;
|
||||
int errorG = actualG - targetG;
|
||||
int errorB = actualB - targetB;
|
||||
byte pixelValue = QuantizePixel(target);
|
||||
*pDestinationPixel = pixelValue;
|
||||
|
||||
// Floyd-Steinberg Error Diffusion:
|
||||
// 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
|
||||
int actual = pallete[pixelValue].ToArgb();
|
||||
|
||||
const int a = 7;
|
||||
const int b = 5;
|
||||
const int c = 3;
|
||||
int actualR = actual & 0xFF;
|
||||
int actualG = (actual >> 8) & 0xFF;
|
||||
int actualB = (actual >> 16) & 0xFF;
|
||||
int errorR = actualR - targetR;
|
||||
int errorG = actualG - targetG;
|
||||
int errorB = actualB - targetB;
|
||||
|
||||
int errorRa = (errorR * a) / 16;
|
||||
int errorRb = (errorR * b) / 16;
|
||||
int errorRc = (errorR * c) / 16;
|
||||
int errorRd = errorR - errorRa - errorRb - errorRc;
|
||||
// Floyd-Steinberg Error Diffusion:
|
||||
// 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
|
||||
|
||||
int errorGa = (errorG * a) / 16;
|
||||
int errorGb = (errorG * b) / 16;
|
||||
int errorGc = (errorG * c) / 16;
|
||||
int errorGd = errorG - errorGa - errorGb - errorGc;
|
||||
const int a = 7;
|
||||
const int b = 5;
|
||||
const int c = 3;
|
||||
|
||||
int errorBa = (errorB * a) / 16;
|
||||
int errorBb = (errorB * b) / 16;
|
||||
int errorBc = (errorB * c) / 16;
|
||||
int errorBd = errorB - errorBa - errorBb - errorBc;
|
||||
int errorRa = (errorR * a) / 16;
|
||||
int errorRb = (errorR * b) / 16;
|
||||
int errorRc = (errorR * c) / 16;
|
||||
int errorRd = errorR - errorRa - errorRb - errorRc;
|
||||
|
||||
errorThisRowR[col + 1] += errorRa;
|
||||
errorThisRowG[col + 1] += errorGa;
|
||||
errorThisRowB[col + 1] += errorBa;
|
||||
int errorGa = (errorG * a) / 16;
|
||||
int errorGb = (errorG * b) / 16;
|
||||
int errorGc = (errorG * c) / 16;
|
||||
int errorGd = errorG - errorGa - errorGb - errorGc;
|
||||
|
||||
errorNextRowR[width - col] += errorRb;
|
||||
errorNextRowG[width - col] += errorGb;
|
||||
errorNextRowB[width - col] += errorBb;
|
||||
int errorBa = (errorB * a) / 16;
|
||||
int errorBb = (errorB * b) / 16;
|
||||
int errorBc = (errorB * c) / 16;
|
||||
int errorBd = errorB - errorBa - errorBb - errorBc;
|
||||
|
||||
if (col != 0)
|
||||
{
|
||||
errorNextRowR[width - (col - 1)] += errorRc;
|
||||
errorNextRowG[width - (col - 1)] += errorGc;
|
||||
errorNextRowB[width - (col - 1)] += errorBc;
|
||||
}
|
||||
errorThisRowR[col + 1] += errorRa;
|
||||
errorThisRowG[col + 1] += errorGa;
|
||||
errorThisRowB[col + 1] += errorBa;
|
||||
|
||||
errorNextRowR[width - (col + 1)] += errorRd;
|
||||
errorNextRowG[width - (col + 1)] += errorGd;
|
||||
errorNextRowB[width - (col + 1)] += errorBd;
|
||||
errorNextRowR[width - col] += errorRb;
|
||||
errorNextRowG[width - col] += errorGb;
|
||||
errorNextRowB[width - col] += errorBb;
|
||||
|
||||
unchecked
|
||||
{
|
||||
pSourcePixel += ptrInc;
|
||||
pDestinationPixel += ptrInc;
|
||||
}
|
||||
}
|
||||
if (col != 0)
|
||||
{
|
||||
errorNextRowR[width - (col - 1)] += errorRc;
|
||||
errorNextRowG[width - (col - 1)] += errorGc;
|
||||
errorNextRowB[width - (col - 1)] += errorBc;
|
||||
}
|
||||
|
||||
// Add the stride to the source row
|
||||
pSourceRow += sourceData.Stride;
|
||||
errorNextRowR[width - (col + 1)] += errorRd;
|
||||
errorNextRowG[width - (col + 1)] += errorGd;
|
||||
errorNextRowB[width - (col + 1)] += errorBd;
|
||||
|
||||
// And to the destination row
|
||||
pDestinationRow += outputData.Stride;
|
||||
unchecked
|
||||
{
|
||||
pSourcePixel += ptrInc;
|
||||
pDestinationPixel += ptrInc;
|
||||
}
|
||||
}
|
||||
|
||||
errorThisRowB = errorNextRowB;
|
||||
errorThisRowG = errorNextRowG;
|
||||
errorThisRowR = errorNextRowR;
|
||||
}
|
||||
}
|
||||
|
||||
finally
|
||||
{
|
||||
// Ensure that I unlock the output bits
|
||||
output.UnlockBits(outputData);
|
||||
}
|
||||
}
|
||||
// Add the stride to the source row
|
||||
pSourceRow += sourceData.Stride;
|
||||
|
||||
/// <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)
|
||||
{
|
||||
}
|
||||
// And to the destination row
|
||||
pDestinationRow += outputData.Stride;
|
||||
|
||||
/// <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);
|
||||
errorThisRowB = errorNextRowB;
|
||||
errorThisRowG = errorNextRowG;
|
||||
errorThisRowR = errorNextRowR;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Ensure that I unlock the output bits
|
||||
output.UnlockBits(outputData);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
using (var bb = new BitmapBuffer(source.BufferWidth, source.BufferHeight, source.GetVideoBuffer()))
|
||||
{
|
||||
string subpath = GetAndCreatePathForFrameNum(mCurrFrame);
|
||||
string path = $"{subpath}.png";
|
||||
bb.ToSysdrawingBitmap().Save(path, System.Drawing.Imaging.ImageFormat.Png);
|
||||
}
|
||||
using var bb = new BitmapBuffer(source.BufferWidth, source.BufferHeight, source.GetVideoBuffer());
|
||||
string subPath = GetAndCreatePathForFrameNum(mCurrFrame);
|
||||
string path = $"{subPath}.png";
|
||||
bb.ToSysdrawingBitmap().Save(path, System.Drawing.Imaging.ImageFormat.Png);
|
||||
}
|
||||
|
||||
public void AddSamples(short[] samples)
|
||||
{
|
||||
string subpath = GetAndCreatePathForFrameNum(mCurrFrame);
|
||||
string path = $"{subpath}.wav";
|
||||
string subPath = GetAndCreatePathForFrameNum(mCurrFrame);
|
||||
string path = $"{subPath}.wav";
|
||||
WavWriterV wwv = new WavWriterV();
|
||||
wwv.SetAudioParameters(paramSampleRate, paramChannels, paramBits);
|
||||
wwv.OpenFile(path);
|
||||
|
@ -107,7 +105,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
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
|
||||
}
|
||||
|
@ -146,9 +144,9 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
private string GetAndCreatePathForFrameNum(int index)
|
||||
{
|
||||
string subpath = GetPathFragmentForFrameNum(index);
|
||||
string subPath = GetPathFragmentForFrameNum(index);
|
||||
string path = mFramesDirectory;
|
||||
path = Path.Combine(path, subpath);
|
||||
path = Path.Combine(path, subPath);
|
||||
string fpath = $"{path}.nothing";
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(fpath));
|
||||
return path;
|
||||
|
|
|
@ -18,9 +18,9 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
private void GetPaths(int index, out string png, out string wav)
|
||||
{
|
||||
string subpath = SynclessRecorder.GetPathFragmentForFrameNum(index);
|
||||
string subPath = SynclessRecorder.GetPathFragmentForFrameNum(index);
|
||||
string path = mFramesDirectory;
|
||||
path = Path.Combine(path, subpath);
|
||||
path = Path.Combine(path, subPath);
|
||||
png = $"{path}.png";
|
||||
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
|
||||
for (;;)
|
||||
{
|
||||
string wav, png;
|
||||
GetPaths(frame, out png, out wav);
|
||||
GetPaths(frame, out var png, out var wav);
|
||||
if (!File.Exists(png) || !File.Exists(wav))
|
||||
{
|
||||
break;
|
||||
|
@ -115,37 +114,35 @@ namespace BizHawk.Client.EmuHawk
|
|||
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
|
||||
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()))
|
||||
{
|
||||
using (var bb = new BitmapBuffer(fi.pngPath, new BitmapLoadOptions()))
|
||||
{
|
||||
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());
|
||||
var bbvp = new BitmapBufferVideoProvider(bb);
|
||||
avw.AddFrame(bbvp);
|
||||
}
|
||||
|
||||
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.Name = "BizBoxInfoControl";
|
||||
this.Size = new System.Drawing.Size(359, 25);
|
||||
this.Load += new System.EventHandler(this.BizBoxInfoControl_Load);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
|
|
|
@ -1,19 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using System.Windows.Forms;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
public partial class BizBoxInfoControl : UserControl
|
||||
{
|
||||
private string url = "";
|
||||
private readonly string _url = "";
|
||||
|
||||
public BizBoxInfoControl(CoreAttribute attributes)
|
||||
{
|
||||
|
@ -39,19 +31,14 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
CoreUrlLink.Visible = true;
|
||||
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)
|
||||
{
|
||||
CoreUrlLink.LinkVisited = true;
|
||||
System.Diagnostics.Process.Start(url);
|
||||
System.Diagnostics.Process.Start(_url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using BizHawk.Common;
|
||||
|
|
|
@ -25,8 +25,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
public void ActivateThreaded()
|
||||
{
|
||||
ewh = new EventWaitHandle(false, EventResetMode.AutoReset);
|
||||
threadPaint = new Thread(PaintProc);
|
||||
threadPaint.IsBackground = true;
|
||||
threadPaint = new Thread(PaintProc) { IsBackground = true };
|
||||
threadPaint.Start();
|
||||
}
|
||||
|
||||
|
@ -62,27 +61,25 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
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.CompositingMode = CompositingMode.SourceCopy;
|
||||
g.CompositingQuality = CompositingQuality.HighSpeed;
|
||||
if (ScaleImage)
|
||||
g.PixelOffsetMode = PixelOffsetMode.Half;
|
||||
g.DrawImage(bmp, 0, 0, Width, Height);
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var sb = new SolidBrush(Color.Black))
|
||||
{
|
||||
g.InterpolationMode = InterpolationMode.NearestNeighbor;
|
||||
g.PixelOffsetMode = PixelOffsetMode.Half;
|
||||
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.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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,7 +150,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
protected override void OnPaintBackground(PaintEventArgs pevent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Client.Common;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
|
@ -15,9 +12,9 @@ namespace BizHawk.Client.EmuHawk
|
|||
/// </summary>
|
||||
public unsafe class DisplaySurface : IDisposable
|
||||
{
|
||||
Bitmap bmp;
|
||||
BitmapData bmpdata;
|
||||
int[] pixels;
|
||||
private Bitmap bmp;
|
||||
private BitmapData bmpdata;
|
||||
private int[] pixels;
|
||||
|
||||
public unsafe void Clear()
|
||||
{
|
||||
|
@ -42,8 +39,8 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
public unsafe void ToBitmap(bool copy=true)
|
||||
{
|
||||
if (isBitmap) return;
|
||||
isBitmap = true;
|
||||
if (_isBitmap) return;
|
||||
_isBitmap = true;
|
||||
|
||||
if (bmp == null)
|
||||
{
|
||||
|
@ -67,13 +64,12 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
}
|
||||
|
||||
public bool IsBitmap { get { return isBitmap; } }
|
||||
bool isBitmap = false;
|
||||
bool _isBitmap;
|
||||
|
||||
public unsafe void FromBitmap(bool copy=true)
|
||||
{
|
||||
if (!isBitmap) return;
|
||||
isBitmap = false;
|
||||
if (!_isBitmap) return;
|
||||
_isBitmap = false;
|
||||
|
||||
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)
|
||||
{
|
||||
//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();
|
||||
}
|
||||
|
||||
public int* PixelPtr { get { return (int*)ptr; } }
|
||||
public IntPtr PixelIntPtr { get { return new IntPtr(ptr); } }
|
||||
public int Stride { get { return Width*4; } }
|
||||
public int OffsetOf(int x, int y) { return y * Stride + x*4; }
|
||||
public int* PixelPtr => (int*)ptr;
|
||||
public int Stride => Width * 4;
|
||||
|
||||
void* ptr;
|
||||
GCHandle handle;
|
||||
|
@ -133,52 +112,20 @@ namespace BizHawk.Client.EmuHawk
|
|||
ptr = handle.AddrOfPinnedObject().ToPointer();
|
||||
}
|
||||
|
||||
void UnlockPixels()
|
||||
private void UnlockPixels()
|
||||
{
|
||||
if(handle.IsAllocated) handle.Free();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// returns a new surface
|
||||
/// </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 int Width { get; }
|
||||
public int Height { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (bmp != null)
|
||||
bmp.Dispose();
|
||||
bmp?.Dispose();
|
||||
bmp = null;
|
||||
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.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Drawing;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Client.Common;
|
||||
using BizHawk.Client.EmuHawk.Filters;
|
||||
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
using BizHawk.Bizware.BizwareGL.Drivers.OpenTK;
|
||||
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk.FilterManager
|
||||
{
|
||||
|
@ -24,8 +15,8 @@ namespace BizHawk.Client.EmuHawk.FilterManager
|
|||
|
||||
public class SurfaceFormat
|
||||
{
|
||||
public SurfaceFormat(Size size) { this.Size = size; }
|
||||
public Size Size { get; private set; }
|
||||
public SurfaceFormat(Size size) { Size = size; }
|
||||
public Size Size { get; }
|
||||
}
|
||||
|
||||
public class SurfaceState
|
||||
|
@ -33,9 +24,10 @@ namespace BizHawk.Client.EmuHawk.FilterManager
|
|||
public SurfaceState() { }
|
||||
public SurfaceState(SurfaceFormat surfaceFormat, SurfaceDisposition surfaceDisposition = SurfaceDisposition.Unspecified)
|
||||
{
|
||||
this.SurfaceFormat = surfaceFormat;
|
||||
this.SurfaceDisposition = surfaceDisposition;
|
||||
SurfaceFormat = surfaceFormat;
|
||||
SurfaceDisposition = surfaceDisposition;
|
||||
}
|
||||
|
||||
public SurfaceFormat SurfaceFormat;
|
||||
public SurfaceDisposition SurfaceDisposition;
|
||||
}
|
||||
|
@ -47,16 +39,16 @@ namespace BizHawk.Client.EmuHawk.FilterManager
|
|||
|
||||
public class FilterProgram
|
||||
{
|
||||
private readonly Dictionary<string, BaseFilter> FilterNameIndex = new Dictionary<string, BaseFilter>();
|
||||
|
||||
public List<BaseFilter> Filters = new List<BaseFilter>();
|
||||
Dictionary<string, BaseFilter> FilterNameIndex = new Dictionary<string, BaseFilter>();
|
||||
public List<ProgramStep> Program = new List<ProgramStep>();
|
||||
|
||||
public BaseFilter this[string name]
|
||||
{
|
||||
get
|
||||
{
|
||||
BaseFilter ret;
|
||||
FilterNameIndex.TryGetValue(name, out ret);
|
||||
FilterNameIndex.TryGetValue(name, out var ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@ -79,7 +71,7 @@ namespace BizHawk.Client.EmuHawk.FilterManager
|
|||
{
|
||||
return RenderTargetProvider.Get(new Size(width, height));
|
||||
}
|
||||
|
||||
|
||||
public void AddFilter(BaseFilter filter, string name = "")
|
||||
{
|
||||
Filters.Add(filter);
|
||||
|
@ -128,10 +120,11 @@ namespace BizHawk.Client.EmuHawk.FilterManager
|
|||
{
|
||||
public ProgramStep(ProgramStepType type, object args, string comment = null)
|
||||
{
|
||||
this.Type = type;
|
||||
this.Args = args;
|
||||
this.Comment = comment;
|
||||
Type = type;
|
||||
Args = args;
|
||||
Comment = comment;
|
||||
}
|
||||
|
||||
public ProgramStepType Type;
|
||||
public object Args;
|
||||
public string Comment;
|
||||
|
@ -218,9 +211,11 @@ namespace BizHawk.Client.EmuHawk.FilterManager
|
|||
{
|
||||
if (currState == null)
|
||||
{
|
||||
currState = new SurfaceState();
|
||||
currState.SurfaceFormat = iosi.SurfaceFormat;
|
||||
currState.SurfaceDisposition = iosi.SurfaceDisposition;
|
||||
currState = new SurfaceState
|
||||
{
|
||||
SurfaceFormat = iosi.SurfaceFormat,
|
||||
SurfaceDisposition = iosi.SurfaceDisposition
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -1,19 +1,10 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Diagnostics;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Drawing;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Client.Common;
|
||||
using BizHawk.Client.EmuHawk.FilterManager;
|
||||
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
using BizHawk.Bizware.BizwareGL.Drivers.OpenTK;
|
||||
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
//Here's how to make a filter:
|
||||
//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 void SetInputFormat(string channel, SurfaceState state) { } //TODO - why a different param order than DeclareOutput?
|
||||
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;
|
||||
|
||||
//runtime signals
|
||||
|
@ -111,10 +102,10 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
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)
|
||||
if (iosi.Channel == channel && iosi.SurfaceDirection == direction)
|
||||
|
@ -135,5 +126,4 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
Input, Output
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,20 +1,9 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Diagnostics;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Drawing;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Client.Common;
|
||||
using BizHawk.Client.EmuHawk;
|
||||
using BizHawk.Client.EmuHawk.FilterManager;
|
||||
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
using BizHawk.Bizware.BizwareGL.Drivers.OpenTK;
|
||||
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk.Filters
|
||||
{
|
||||
|
@ -486,8 +475,7 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
|
||||
public override void Run()
|
||||
{
|
||||
if (RenderCallback == null) return;
|
||||
RenderCallback();
|
||||
RenderCallback?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,20 +1,7 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Diagnostics;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Drawing;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Client.Common;
|
||||
using BizHawk.Client.EmuHawk;
|
||||
using BizHawk.Client.EmuHawk.FilterManager;
|
||||
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
using BizHawk.Bizware.BizwareGL.Drivers.OpenTK;
|
||||
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk.Filters
|
||||
{
|
||||
|
@ -22,10 +9,10 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
{
|
||||
public SourceImage(Size size)
|
||||
{
|
||||
this.Size = size;
|
||||
Size = size;
|
||||
}
|
||||
|
||||
Size Size;
|
||||
private readonly Size Size;
|
||||
|
||||
public Texture2d Texture;
|
||||
|
||||
|
|
|
@ -1,11 +1,4 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Client.Common;
|
||||
|
||||
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
|
||||
/// sizes are available and keeping them cleaned up when they dont seem like theyll need to be used anymore
|
||||
/// </summary>
|
||||
class SwappableDisplaySurfaceSet
|
||||
public class SwappableDisplaySurfaceSet
|
||||
{
|
||||
DisplaySurface Pending, Current;
|
||||
bool IsPending;
|
||||
Queue<DisplaySurface> ReleasedSurfaces = new Queue<DisplaySurface>();
|
||||
private DisplaySurface Pending, Current;
|
||||
private bool IsPending;
|
||||
private readonly Queue<DisplaySurface> ReleasedSurfaces = new Queue<DisplaySurface>();
|
||||
|
||||
/// <summary>
|
||||
/// 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,17 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Client.Common;
|
||||
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
/// <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.
|
||||
/// When the dimensions dont match, a new one will be allocated
|
||||
/// When the dimensions don't match, a new one will be allocated
|
||||
/// </summary>
|
||||
public class TextureFrugalizer : IDisposable
|
||||
{
|
||||
|
@ -24,59 +19,56 @@ namespace BizHawk.Client.EmuHawk
|
|||
public void Dispose()
|
||||
{
|
||||
foreach (var ct in CurrentTextures)
|
||||
if(ct != null)
|
||||
ct.Dispose();
|
||||
{
|
||||
ct?.Dispose();
|
||||
}
|
||||
|
||||
ResetList();
|
||||
}
|
||||
|
||||
void ResetList()
|
||||
{
|
||||
CurrentTextures = new List<Texture2d>();
|
||||
CurrentTextures.Add(null);
|
||||
CurrentTextures.Add(null);
|
||||
CurrentTextures = new List<Texture2d> { null, null };
|
||||
}
|
||||
|
||||
IGL GL;
|
||||
List<Texture2d> CurrentTextures;
|
||||
private readonly IGL GL;
|
||||
private List<Texture2d> CurrentTextures;
|
||||
|
||||
public Texture2d Get(DisplaySurface ds)
|
||||
{
|
||||
using (var bb = new BitmapBuffer(ds.PeekBitmap(), new BitmapLoadOptions()))
|
||||
{
|
||||
return Get(bb);
|
||||
}
|
||||
using var bb = new BitmapBuffer(ds.PeekBitmap(), new BitmapLoadOptions());
|
||||
return Get(bb);
|
||||
}
|
||||
public Texture2d Get(BitmapBuffer bb)
|
||||
{
|
||||
//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)
|
||||
//we might need to deal with that in the future to fix some bugs.
|
||||
// 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.
|
||||
|
||||
//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...
|
||||
if (CurrentTexture != null)
|
||||
CurrentTexture.Dispose();
|
||||
currentTexture?.Dispose();
|
||||
//and make a new one
|
||||
CurrentTexture = GL.LoadTexture(bb);
|
||||
currentTexture = GL.LoadTexture(bb);
|
||||
}
|
||||
else
|
||||
{
|
||||
//its good! just load in the data
|
||||
GL.LoadTextureData(CurrentTexture, bb);
|
||||
GL.LoadTextureData(currentTexture, bb);
|
||||
}
|
||||
|
||||
//now shuffle the buffers
|
||||
CurrentTextures[0] = CurrentTextures[1];
|
||||
CurrentTextures[1] = CurrentTexture;
|
||||
CurrentTextures[1] = currentTexture;
|
||||
|
||||
//deterministic state, i guess
|
||||
CurrentTexture.SetFilterNearest();
|
||||
currentTexture.SetFilterNearest();
|
||||
|
||||
return CurrentTexture;
|
||||
return currentTexture;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,27 +1,23 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.IO.Pipes;
|
||||
using SlimDX;
|
||||
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
|
||||
{
|
||||
public static class IPCKeyInput
|
||||
{
|
||||
public static void Initialize()
|
||||
{
|
||||
var t = new Thread(IPCThread);
|
||||
t.IsBackground = true;
|
||||
var t = new Thread(IPCThread) { IsBackground = true };
|
||||
t.Start();
|
||||
}
|
||||
|
||||
|
||||
static List<KeyInput.KeyEvent> PendingEventList = new List<KeyInput.KeyEvent>();
|
||||
static List<KeyInput.KeyEvent> EventList = new List<KeyInput.KeyEvent>();
|
||||
private static readonly List<KeyInput.KeyEvent> PendingEventList = new List<KeyInput.KeyEvent>();
|
||||
private static readonly List<KeyInput.KeyEvent> EventList = new List<KeyInput.KeyEvent>();
|
||||
|
||||
static void IPCThread()
|
||||
{
|
||||
|
@ -30,24 +26,22 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
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();
|
||||
|
||||
BinaryReader br = new BinaryReader(pipe);
|
||||
|
||||
for (; ; )
|
||||
{
|
||||
int e = br.ReadInt32();
|
||||
bool pressed = (e & 0x80000000) != 0;
|
||||
lock (PendingEventList)
|
||||
PendingEventList.Add(new KeyInput.KeyEvent { Key = (Key)(e & 0x7FFFFFFF), Pressed = pressed });
|
||||
}
|
||||
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?
|
||||
sram = new byte[oldRam.Length];
|
||||
using (var reader = new BinaryReader(
|
||||
new FileStream(PathManager.SaveRamPath(Game), FileMode.Open, FileAccess.Read)))
|
||||
{
|
||||
reader.Read(sram, 0, sram.Length);
|
||||
}
|
||||
using var reader = new BinaryReader(
|
||||
new FileStream(PathManager.SaveRamPath(Game), FileMode.Open, FileAccess.Read));
|
||||
reader.Read(sram, 0, sram.Length);
|
||||
}
|
||||
|
||||
Emulator.AsSaveRam().StoreSaveRam(sram);
|
||||
|
|
|
@ -1,15 +1,9 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores;
|
||||
using BizHawk.Emulation.Cores.Libretro;
|
||||
using BizHawk.Client.Common;
|
||||
|
||||
|
@ -19,35 +13,29 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
public partial class OpenAdvancedChooser : Form
|
||||
{
|
||||
MainForm mainForm;
|
||||
private readonly MainForm _mainForm;
|
||||
|
||||
public AdvancedRomLoaderType Result;
|
||||
public string SuggestedExtensionFilter;
|
||||
|
||||
public OpenAdvancedChooser(MainForm mainForm)
|
||||
{
|
||||
this.mainForm = mainForm;
|
||||
_mainForm = mainForm;
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
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)
|
||||
{
|
||||
DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
DialogResult = DialogResult.Cancel;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void btnSetLibretroCore_Click(object sender, EventArgs e)
|
||||
{
|
||||
if(mainForm.RunLibretroCoreChooser())
|
||||
if(_mainForm.RunLibretroCoreChooser())
|
||||
RefreshLibretroCore(false);
|
||||
}
|
||||
|
||||
|
@ -73,26 +61,24 @@ namespace BizHawk.Client.EmuHawk
|
|||
////LibRetroEmulator should be able to survive having this stub corecomm
|
||||
//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
|
||||
var coreComm = new BizHawk.Emulation.Common.CoreComm(null, null);
|
||||
var coreComm = new CoreComm(null, null);
|
||||
CoreFileProvider.SyncCoreCommInputSignals(coreComm);
|
||||
using (var retro = new LibretroCore(coreComm, core))
|
||||
{
|
||||
btnLibretroLaunchGame.Enabled = true;
|
||||
if (retro.Description.SupportsNoGame)
|
||||
btnLibretroLaunchNoGame.Enabled = true;
|
||||
using var retro = new LibretroCore(coreComm, core);
|
||||
btnLibretroLaunchGame.Enabled = true;
|
||||
if (retro.Description.SupportsNoGame)
|
||||
btnLibretroLaunchNoGame.Enabled = true;
|
||||
|
||||
//print descriptive information
|
||||
var descr = retro.Description;
|
||||
CurrentDescription = descr;
|
||||
Console.WriteLine($"core name: {descr.LibraryName} version {descr.LibraryVersion}");
|
||||
Console.WriteLine($"extensions: {descr.ValidExtensions}");
|
||||
Console.WriteLine($"{nameof(descr.NeedsRomAsPath)}: {descr.NeedsRomAsPath}");
|
||||
Console.WriteLine($"{nameof(descr.NeedsArchives)}: {descr.NeedsArchives}");
|
||||
Console.WriteLine($"{nameof(descr.SupportsNoGame)}: {descr.SupportsNoGame}");
|
||||
//print descriptive information
|
||||
var descr = retro.Description;
|
||||
CurrentDescription = descr;
|
||||
Console.WriteLine($"core name: {descr.LibraryName} version {descr.LibraryVersion}");
|
||||
Console.WriteLine($"extensions: {descr.ValidExtensions}");
|
||||
Console.WriteLine($"{nameof(descr.NeedsRomAsPath)}: {descr.NeedsRomAsPath}");
|
||||
Console.WriteLine($"{nameof(descr.NeedsArchives)}: {descr.NeedsArchives}");
|
||||
Console.WriteLine($"{nameof(descr.SupportsNoGame)}: {descr.SupportsNoGame}");
|
||||
|
||||
foreach (var v in descr.Variables.Values)
|
||||
Console.WriteLine(v);
|
||||
}
|
||||
foreach (var v in descr.Variables.Values)
|
||||
Console.WriteLine(v);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -111,8 +97,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
sw.Write("*.{0};",ext);
|
||||
var filter = sw.ToString();
|
||||
filter = filter.Substring(0,filter.Length-1); //remove last semicolon
|
||||
List<string> args = new List<string>();
|
||||
args.Add("Rom Files");
|
||||
var args = new List<string> { "Rom Files" };
|
||||
if (!CurrentDescription.NeedsArchives)
|
||||
filter += ";%ARCH%";
|
||||
args.Add(filter);
|
||||
|
|
|
@ -1,10 +1,4 @@
|
|||
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 BizHawk.Emulation.Common;
|
||||
|
||||
|
|
|
@ -47,12 +47,10 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
public static IEnumerable<string> GetDeviceNames()
|
||||
{
|
||||
using (XAudio2 device = new XAudio2())
|
||||
{
|
||||
return Enumerable.Range(0, device.DeviceCount)
|
||||
.Select(n => device.GetDeviceDetails(n).DisplayName)
|
||||
.ToList(); // enumerate before local var device is disposed
|
||||
}
|
||||
using XAudio2 device = new XAudio2();
|
||||
return Enumerable.Range(0, device.DeviceCount)
|
||||
.Select(n => device.GetDeviceDetails(n).DisplayName)
|
||||
.ToList(); // enumerate before local var device is disposed
|
||||
}
|
||||
|
||||
private int BufferSizeSamples { get; set; }
|
||||
|
@ -126,8 +124,8 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
private class BufferPool : IDisposable
|
||||
{
|
||||
private List<BufferPoolItem> _availableItems = new List<BufferPoolItem>();
|
||||
private Queue<BufferPoolItem> _obtainedItems = new Queue<BufferPoolItem>();
|
||||
private readonly List<BufferPoolItem> _availableItems = new List<BufferPoolItem>();
|
||||
private readonly Queue<BufferPoolItem> _obtainedItems = new Queue<BufferPoolItem>();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
|
|
@ -40,10 +40,8 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
private static SizeF GetCurrentAutoScaleSize(AutoScaleMode autoScaleMode)
|
||||
{
|
||||
using (var form = new Form { AutoScaleMode = autoScaleMode })
|
||||
{
|
||||
return form.CurrentAutoScaleDimensions;
|
||||
}
|
||||
using var form = new Form { AutoScaleMode = autoScaleMode };
|
||||
return form.CurrentAutoScaleDimensions;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
using System.Windows.Forms;
|
||||
|
||||
using BizHawk.Emulation.Cores.Nintendo.SNES;
|
||||
using BizHawk.Client.Common;
|
||||
using BizHawk.Client.EmuHawk.WinFormExtensions;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Common.IEmulatorExtensions;
|
||||
using BizHawk.Client.Common;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
|
@ -18,13 +14,10 @@ namespace BizHawk.Client.EmuHawk
|
|||
[RequiredService]
|
||||
private IMemoryDomains MemoryDomains { get; set; }
|
||||
|
||||
private IMemoryCallbackSystem MemoryCallbacks { get { return Debuggable.MemoryCallbacks; } }
|
||||
private IMemoryCallbackSystem MemoryCallbacks => Debuggable.MemoryCallbacks;
|
||||
|
||||
|
||||
private RegisterValue PCRegister
|
||||
{
|
||||
get { return Debuggable.GetCpuFlagsAndRegisters()[Disassembler.PCRegisterName]; }
|
||||
}
|
||||
private RegisterValue PCRegister => Debuggable.GetCpuFlagsAndRegisters()[Disassembler.PCRegisterName];
|
||||
|
||||
#region Implementation checking
|
||||
|
||||
|
@ -161,15 +154,8 @@ namespace BizHawk.Client.EmuHawk
|
|||
EngageDebugger();
|
||||
}
|
||||
|
||||
public bool AskSaveChanges()
|
||||
{
|
||||
// TODO
|
||||
return true;
|
||||
}
|
||||
public bool AskSaveChanges() => true;
|
||||
|
||||
public bool UpdateBefore
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
public bool UpdateBefore => false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
|
|
|
@ -194,7 +194,6 @@
|
|||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Music Ripper";
|
||||
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.NESMusicRipper_FormClosed);
|
||||
this.Load += new System.EventHandler(this.NESMusicRipper_Load);
|
||||
this.groupBox1.ResumeLayout(false);
|
||||
this.groupBox1.PerformLayout();
|
||||
this.groupBox2.ResumeLayout(false);
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
public partial class NESMusicRipper : Form, IToolFormAutoConfig
|
||||
{
|
||||
[RequiredService]
|
||||
private NES nes { get; set; }
|
||||
private NES Nes { get; set; }
|
||||
|
||||
public NESMusicRipper()
|
||||
{
|
||||
|
@ -20,7 +20,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
SyncContents();
|
||||
}
|
||||
|
||||
public bool AskSaveChanges() { return true; }
|
||||
public bool AskSaveChanges() => true;
|
||||
public bool UpdateBefore => true;
|
||||
|
||||
public void Restart()
|
||||
|
@ -113,8 +113,10 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
Filter = "XRNS (*.xrns)|*.xrns"
|
||||
};
|
||||
if (sfd.ShowDialog() != System.Windows.Forms.DialogResult.OK)
|
||||
if (sfd.ShowDialog() != DialogResult.OK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//configuration:
|
||||
var outPath = sfd.FileName;
|
||||
|
@ -127,13 +129,11 @@ namespace BizHawk.Client.EmuHawk
|
|||
var zfTemplate = new ICSharpCode.SharpZipLib.Zip.ZipFile(templatePath);
|
||||
{
|
||||
int zfSongXmlIndex = zfTemplate.FindEntry("Song.xml", true);
|
||||
using (var zis = zfTemplate.GetInputStream(zfTemplate.GetEntry("Song.xml")))
|
||||
{
|
||||
byte[] buffer = new byte[4096]; // 4K is optimum
|
||||
ICSharpCode.SharpZipLib.Core.StreamUtils.Copy(zis, msSongXml, buffer);
|
||||
}
|
||||
using var zis = zfTemplate.GetInputStream(zfTemplate.GetEntry("Song.xml"));
|
||||
byte[] buffer = new byte[4096]; // 4K is optimum
|
||||
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
|
||||
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)
|
||||
//ftriangle = fCPU/(32*(tval + 1))
|
||||
|
||||
var apu = nes.apu;
|
||||
var apu = Nes.apu;
|
||||
|
||||
//evaluate the pitches
|
||||
int pulse0_period = apu.pulse[0].timer_reload_value;
|
||||
|
@ -475,16 +475,16 @@ namespace BizHawk.Client.EmuHawk
|
|||
if(IsRunning)
|
||||
{
|
||||
SyncContents();
|
||||
nes.apu.DebugCallback = null;
|
||||
nes.apu.DebugCallbackDivider = 0;
|
||||
Nes.apu.DebugCallback = null;
|
||||
Nes.apu.DebugCallbackDivider = 0;
|
||||
IsRunning = false;
|
||||
btnControl.Text = "Start";
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Clear();
|
||||
nes.apu.DebugCallback = DebugCallback;
|
||||
nes.apu.DebugCallbackDivider = int.Parse(txtDivider.Text);
|
||||
Nes.apu.DebugCallback = DebugCallback;
|
||||
Nes.apu.DebugCallbackDivider = int.Parse(txtDivider.Text);
|
||||
IsRunning = true;
|
||||
btnControl.Text = "Stop";
|
||||
}
|
||||
|
@ -497,15 +497,10 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
private void NESMusicRipper_FormClosed(object sender, FormClosedEventArgs e)
|
||||
{
|
||||
var apu = nes.apu;
|
||||
var apu = Nes.apu;
|
||||
apu.DebugCallbackDivider = 0;
|
||||
apu.DebugCallbackTimer = 0;
|
||||
apu.DebugCallback = null;
|
||||
}
|
||||
|
||||
private void NESMusicRipper_Load(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
get => _x;
|
||||
set
|
||||
{
|
||||
_x = RangeX.Constrain(value);
|
||||
_x = _rangeX.Constrain(value);
|
||||
SetAnalog();
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
get => _y;
|
||||
set
|
||||
{
|
||||
_y = RangeY.Constrain(value);
|
||||
_y = _rangeY.Constrain(value);
|
||||
SetAnalog();
|
||||
}
|
||||
}
|
||||
|
@ -42,13 +42,13 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
private IController _previous;
|
||||
|
||||
private sbyte UserRangePercentageX = 100;
|
||||
private sbyte UserRangePercentageY = 100;
|
||||
private sbyte _userRangePercentageX = 100;
|
||||
private sbyte _userRangePercentageY = 100;
|
||||
|
||||
public void SetUserRange(decimal rx, decimal ry)
|
||||
{
|
||||
UserRangePercentageX = (sbyte) rx;
|
||||
UserRangePercentageY = (sbyte) ry;
|
||||
_userRangePercentageX = (sbyte) rx;
|
||||
_userRangePercentageY = (sbyte) ry;
|
||||
|
||||
Rerange();
|
||||
Refresh();
|
||||
|
@ -56,42 +56,42 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
public void SetRangeX(float[] range)
|
||||
{
|
||||
ActualRangeX.Min = (int) range[0];
|
||||
ActualRangeX.Max = (int) range[2];
|
||||
_actualRangeX.Min = (int) range[0];
|
||||
_actualRangeX.Max = (int) range[2];
|
||||
|
||||
Rerange();
|
||||
}
|
||||
|
||||
public void SetRangeY(float[] range)
|
||||
{
|
||||
ActualRangeY.Min = (int) range[0];
|
||||
ActualRangeY.Max = (int) range[2];
|
||||
_actualRangeY.Min = (int) range[0];
|
||||
_actualRangeY.Max = (int) range[2];
|
||||
|
||||
Rerange();
|
||||
}
|
||||
|
||||
private readonly MutableIntRange RangeX = new MutableIntRange(-128, 127);
|
||||
private readonly MutableIntRange RangeY = new MutableIntRange(-128, 127);
|
||||
private readonly MutableIntRange ActualRangeX = new MutableIntRange(-128, 127);
|
||||
private readonly MutableIntRange ActualRangeY = new MutableIntRange(-128, 127);
|
||||
private readonly MutableIntRange _rangeX = new MutableIntRange(-128, 127);
|
||||
private readonly MutableIntRange _rangeY = new MutableIntRange(-128, 127);
|
||||
private readonly MutableIntRange _actualRangeX = new MutableIntRange(-128, 127);
|
||||
private readonly MutableIntRange _actualRangeY = new MutableIntRange(-128, 127);
|
||||
|
||||
private bool ReverseX;
|
||||
private bool ReverseY;
|
||||
private bool _reverseX;
|
||||
private bool _reverseY;
|
||||
|
||||
private void Rerange()
|
||||
{
|
||||
ReverseX = UserRangePercentageX < 0;
|
||||
ReverseY = UserRangePercentageY < 0;
|
||||
_reverseX = _userRangePercentageX < 0;
|
||||
_reverseY = _userRangePercentageY < 0;
|
||||
|
||||
var midX = (ActualRangeX.Min + ActualRangeX.Max) / 2.0;
|
||||
var halfRangeX = (ReverseX ? -1 : 1) * (ActualRangeX.Max - ActualRangeX.Min) * UserRangePercentageX / 200.0;
|
||||
RangeX.Min = (int) (midX - halfRangeX);
|
||||
RangeX.Max = (int) (midX + halfRangeX);
|
||||
var midX = (_actualRangeX.Min + _actualRangeX.Max) / 2.0;
|
||||
var halfRangeX = (_reverseX ? -1 : 1) * (_actualRangeX.Max - _actualRangeX.Min) * _userRangePercentageX / 200.0;
|
||||
_rangeX.Min = (int) (midX - halfRangeX);
|
||||
_rangeX.Max = (int) (midX + halfRangeX);
|
||||
|
||||
var midY = (ActualRangeY.Min + ActualRangeY.Max) / 2.0;
|
||||
var halfRangeY = (ReverseY ? -1 : 1) * (ActualRangeY.Max - ActualRangeY.Min) * UserRangePercentageY / 200.0;
|
||||
RangeY.Min = (int) (midY - halfRangeY);
|
||||
RangeY.Max = (int) (midY + halfRangeY);
|
||||
var midY = (_actualRangeY.Min + _actualRangeY.Max) / 2.0;
|
||||
var halfRangeY = (_reverseY ? -1 : 1) * (_actualRangeY.Max - _actualRangeY.Min) * _userRangePercentageY / 200.0;
|
||||
_rangeY.Min = (int) (midY - halfRangeY);
|
||||
_rangeY.Max = (int) (midY + halfRangeY);
|
||||
|
||||
// re-constrain after changing ranges
|
||||
X = X;
|
||||
|
@ -108,12 +108,12 @@ namespace BizHawk.Client.EmuHawk
|
|||
/// <remarks>
|
||||
/// min + (max - i) == max - (i - min) == min + max - i
|
||||
/// </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"/>
|
||||
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 PixelSizeY => (int)(RangeY.GetCount() * ScaleY);
|
||||
private int PixelSizeX => (int)(_rangeX.GetCount() * ScaleX);
|
||||
private int PixelSizeY => (int)(_rangeY.GetCount() * ScaleY);
|
||||
private int PixelMinX => (Size.Width - PixelSizeX) / 2;
|
||||
private int PixelMinY => (Size.Height - PixelSizeY) / 2;
|
||||
private int PixelMidX => PixelMinX + PixelSizeX / 2;
|
||||
|
@ -122,23 +122,23 @@ namespace BizHawk.Client.EmuHawk
|
|||
private int PixelMaxY => PixelMinY + PixelSizeY - 1;
|
||||
|
||||
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) =>
|
||||
PixelMinY + ((MaybeReversedInY(RangeY.Constrain(val)) - RangeY.Min) * ScaleY).RoundToInt();
|
||||
PixelMinY + ((MaybeReversedInY(_rangeY.Constrain(val)) - _rangeY.Min) * ScaleY).RoundToInt();
|
||||
|
||||
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) =>
|
||||
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 BluePen = new Pen(Brushes.Blue, 2);
|
||||
private readonly Pen GrayPen = new Pen(Brushes.Gray, 2);
|
||||
private readonly Pen _blackPen = new Pen(Brushes.Black);
|
||||
private readonly Pen _bluePen = new Pen(Brushes.Blue, 2);
|
||||
private readonly Pen _grayPen = new Pen(Brushes.Gray, 2);
|
||||
|
||||
private readonly Bitmap Dot = new Bitmap(7, 7);
|
||||
private readonly Bitmap GrayDot = new Bitmap(7, 7);
|
||||
private readonly Bitmap _dot = new Bitmap(7, 7);
|
||||
private readonly Bitmap _grayDot = new Bitmap(7, 7);
|
||||
|
||||
public Action ClearCallback { private get; set; }
|
||||
|
||||
|
@ -160,22 +160,18 @@ namespace BizHawk.Client.EmuHawk
|
|||
BorderStyle = BorderStyle.Fixed3D;
|
||||
|
||||
// Draw the dot into a bitmap
|
||||
using (var g = Graphics.FromImage(Dot))
|
||||
{
|
||||
g.Clear(Color.Transparent);
|
||||
var redBrush = Brushes.Red;
|
||||
g.FillRectangle(redBrush, 2, 0, 3, 7);
|
||||
g.FillRectangle(redBrush, 1, 1, 5, 5);
|
||||
g.FillRectangle(redBrush, 0, 2, 7, 3);
|
||||
}
|
||||
using var g = Graphics.FromImage(_dot);
|
||||
g.Clear(Color.Transparent);
|
||||
var redBrush = Brushes.Red;
|
||||
g.FillRectangle(redBrush, 2, 0, 3, 7);
|
||||
g.FillRectangle(redBrush, 1, 1, 5, 5);
|
||||
g.FillRectangle(redBrush, 0, 2, 7, 3);
|
||||
|
||||
using (var gg = Graphics.FromImage(GrayDot))
|
||||
{
|
||||
gg.Clear(Color.Transparent);
|
||||
gg.FillRectangle(Brushes.Gray, 2, 0, 3, 7);
|
||||
gg.FillRectangle(Brushes.Gray, 1, 1, 5, 5);
|
||||
gg.FillRectangle(Brushes.Gray, 0, 2, 7, 3);
|
||||
}
|
||||
using var gg = Graphics.FromImage(_grayDot);
|
||||
gg.Clear(Color.Transparent);
|
||||
gg.FillRectangle(Brushes.Gray, 2, 0, 3, 7);
|
||||
gg.FillRectangle(Brushes.Gray, 1, 1, 5, 5);
|
||||
gg.FillRectangle(Brushes.Gray, 0, 2, 7, 3);
|
||||
}
|
||||
|
||||
private void SetAnalog()
|
||||
|
@ -194,24 +190,24 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
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.DrawEllipse(BlackPen, PixelMinX, PixelMinY, PixelMaxX - PixelMinX - 2, PixelMaxY - PixelMinY - 3);
|
||||
e.Graphics.DrawLine(BlackPen, PixelMidX, 0, PixelMidX, PixelMaxY);
|
||||
e.Graphics.DrawLine(BlackPen, 0, PixelMidY, PixelMaxX, PixelMidY);
|
||||
e.Graphics.DrawEllipse(_blackPen, PixelMinX, PixelMinY, PixelMaxX - PixelMinX - 2, PixelMaxY - PixelMinY - 3);
|
||||
e.Graphics.DrawLine(_blackPen, PixelMidX, 0, PixelMidX, PixelMaxY);
|
||||
e.Graphics.DrawLine(_blackPen, 0, PixelMidY, PixelMaxX, PixelMidY);
|
||||
|
||||
// Previous frame
|
||||
if (_previous != null)
|
||||
{
|
||||
var pX = (int)_previous.GetFloat(XName);
|
||||
var pY = (int)_previous.GetFloat(YName);
|
||||
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.DrawLine(_grayPen, PixelMidX, PixelMidY, RealToGfxX(pX), RealToGfxY(pY));
|
||||
e.Graphics.DrawImage(_grayDot, RealToGfxX(pX) - 3, RealToGfxY(_rangeY.Max) - RealToGfxY(pY) - 3);
|
||||
}
|
||||
|
||||
// Line
|
||||
if (HasValue)
|
||||
{
|
||||
e.Graphics.DrawLine(BluePen, PixelMidX, PixelMidY, RealToGfxX(X), RealToGfxY(Y));
|
||||
e.Graphics.DrawImage(ReadOnly ? GrayDot : Dot, RealToGfxX(X) - 3, RealToGfxY(Y) - 3);
|
||||
e.Graphics.DrawLine(_bluePen, PixelMidX, PixelMidY, RealToGfxX(X), RealToGfxY(Y));
|
||||
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/=Prereqs/@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/=quicknes/@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/=vram/@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/=winforms/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=WSWAN/@EntryIndexedValue">True</s:Boolean>
|
||||
|
|
Loading…
Reference in New Issue