Remove Bizware Vector2/3/4 and Matrix4 in favor of System.Numerics's implementation
Many many cleanups in BizwareGL and DisplayManager and GDI+ code
This commit is contained in:
parent
bb96825c60
commit
59fcdb04cd
|
@ -5,7 +5,7 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
/// </summary>
|
||||
public class Art
|
||||
{
|
||||
//bleh, didnt mean to have this here, but I need it now
|
||||
// bleh, didnt mean to have this here, but I need it now
|
||||
public Art(Texture2d tex)
|
||||
{
|
||||
BaseTexture = tex;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace BizHawk.Bizware.BizwareGL
|
||||
{
|
||||
|
@ -18,7 +19,7 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
//todo
|
||||
// todo
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -27,7 +28,11 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
public void Open()
|
||||
{
|
||||
AssertIsOpen(false);
|
||||
if (IsClosedForever) throw new InvalidOperationException($"{nameof(ArtManager)} instance has been closed forever!");
|
||||
if (IsClosedForever)
|
||||
{
|
||||
throw new InvalidOperationException($"{nameof(ArtManager)} instance has been closed forever!");
|
||||
}
|
||||
|
||||
IsOpened = true;
|
||||
}
|
||||
|
||||
|
@ -52,7 +57,7 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
{
|
||||
AssertIsOpen(true);
|
||||
|
||||
Art a = new Art(this);
|
||||
var a = new Art(this);
|
||||
ArtLooseTextureAssociation.Add((a, tex));
|
||||
ManagedArts.Add(a);
|
||||
|
||||
|
@ -72,16 +77,16 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
|
||||
// first, cleanup old stuff
|
||||
foreach (var tex in ManagedTextures)
|
||||
{
|
||||
tex.Dispose();
|
||||
}
|
||||
ManagedTextures.Clear();
|
||||
|
||||
// prepare input for atlas process and perform atlas
|
||||
// add 2 extra pixels for padding on all sides
|
||||
var atlasItems = new List<TexAtlas.RectItem>();
|
||||
foreach (var kvp in ArtLooseTextureAssociation)
|
||||
{
|
||||
atlasItems.Add(new TexAtlas.RectItem(kvp.Bitmap.Width + 2, kvp.Bitmap.Height + 2, kvp));
|
||||
}
|
||||
var atlasItems = ArtLooseTextureAssociation
|
||||
.Select(kvp => new TexAtlas.RectItem(kvp.Bitmap.Width + 2, kvp.Bitmap.Height + 2, kvp))
|
||||
.ToList();
|
||||
var results = TexAtlas.PackAtlas(atlasItems);
|
||||
|
||||
// this isn't supported yet:
|
||||
|
@ -89,27 +94,28 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
throw new InvalidOperationException("Art files too big for atlas");
|
||||
|
||||
// prepare the output buffer
|
||||
BitmapBuffer bmpResult = new BitmapBuffer(results[0].Size);
|
||||
var bmpResult = new BitmapBuffer(results[0].Size);
|
||||
|
||||
//for each item, copy it into the output buffer and set the tex parameters on them
|
||||
for (int i = 0; i < atlasItems.Count; i++)
|
||||
for (var i = 0; i < atlasItems.Count; i++)
|
||||
{
|
||||
var item = results[0].Items[i];
|
||||
var (art, bitmap) = ((Art, BitmapBuffer)) item.Item;
|
||||
int w = bitmap.Width;
|
||||
int h = bitmap.Height;
|
||||
int dx = item.X + 1;
|
||||
int dy = item.Y + 1;
|
||||
for (int y = 0; y < h; y++)
|
||||
for (int x = 0; x < w; x++)
|
||||
var w = bitmap.Width;
|
||||
var h = bitmap.Height;
|
||||
var dx = item.X + 1;
|
||||
var dy = item.Y + 1;
|
||||
for (var y = 0; y < h; y++)
|
||||
{
|
||||
for (var x = 0; x < w; x++)
|
||||
{
|
||||
int pixel = bitmap.GetPixel(x, y);
|
||||
var pixel = bitmap.GetPixel(x, y);
|
||||
bmpResult.SetPixel(x+dx,y+dy,pixel);
|
||||
}
|
||||
}
|
||||
|
||||
var myDestBitmap = bmpResult;
|
||||
float myDestWidth = (float)myDestBitmap.Width;
|
||||
float myDestHeight = (float)myDestBitmap.Height;
|
||||
var myDestWidth = (float)bmpResult.Width;
|
||||
var myDestHeight = (float)bmpResult.Height;
|
||||
|
||||
art.u0 = dx / myDestWidth;
|
||||
art.v0 = dy / myDestHeight;
|
||||
|
@ -138,7 +144,13 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
/// <summary>
|
||||
/// Throws an exception if the instance is not open
|
||||
/// </summary>
|
||||
private void AssertIsOpen(bool state) { if (IsOpened != state) throw new InvalidOperationException($"{nameof(ArtManager)} instance is not open!"); }
|
||||
private void AssertIsOpen(bool state)
|
||||
{
|
||||
if (IsOpened != state)
|
||||
{
|
||||
throw new InvalidOperationException($"{nameof(ArtManager)} instance is not open!");
|
||||
}
|
||||
}
|
||||
|
||||
public IGL Owner { get; }
|
||||
|
||||
|
@ -153,11 +165,11 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
/// <summary>
|
||||
/// Physical texture resources, which exist after this ArtManager has been closed
|
||||
/// </summary>
|
||||
private readonly List<Texture2d> ManagedTextures = new List<Texture2d>();
|
||||
private readonly List<Texture2d> ManagedTextures = new();
|
||||
|
||||
/// <summary>
|
||||
/// All the Arts managed by this instance
|
||||
/// </summary>
|
||||
private readonly List<Art> ManagedArts = new List<Art>();
|
||||
private readonly List<Art> ManagedArts = new();
|
||||
}
|
||||
}
|
|
@ -1,15 +1,14 @@
|
|||
//TODO - introduce Trim for ArtManager
|
||||
//TODO - add a small buffer reuse manager.. small images can be stored in larger buffers which we happen to have held. use a timer to wait to free it until some time has passed
|
||||
// TODO - introduce Trim for ArtManager
|
||||
// TODO - add a small buffer reuse manager.. small images can be stored in larger buffers which we happen to have held. use a timer to wait to free it until some time has passed
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.IO;
|
||||
|
||||
using sd = System.Drawing;
|
||||
|
||||
namespace BizHawk.Bizware.BizwareGL
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -28,7 +27,7 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
/// </summary>
|
||||
public bool HasAlpha = true;
|
||||
|
||||
public Size Size => new Size(Width, Height);
|
||||
public Size Size => new(Width, Height);
|
||||
|
||||
private readonly Bitmap WrappedBitmap;
|
||||
private GCHandle CurrLockHandle;
|
||||
|
@ -48,7 +47,7 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
}
|
||||
|
||||
CurrLockHandle = GCHandle.Alloc(Pixels, GCHandleType.Pinned);
|
||||
CurrLock = new BitmapData
|
||||
CurrLock = new()
|
||||
{
|
||||
Height = Height,
|
||||
Width = Width,
|
||||
|
@ -82,16 +81,15 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
|
||||
public void YFlip()
|
||||
{
|
||||
//TODO - could be faster
|
||||
// TODO - could be faster
|
||||
var bmpdata = LockBits();
|
||||
int[] newPixels = new int[Width * Height];
|
||||
int todo = Width * Height;
|
||||
int* s = (int*)bmpdata.Scan0.ToPointer();
|
||||
var newPixels = new int[Width * Height];
|
||||
var s = (int*)bmpdata.Scan0.ToPointer();
|
||||
fixed (int* d = newPixels)
|
||||
{
|
||||
for (int y = 0, si = 0, di = (Height - 1) * Width; y < Height; y++)
|
||||
{
|
||||
for (int x = 0; x < Width; x++, si++, di++)
|
||||
for (var x = 0; x < Width; x++, si++, di++)
|
||||
{
|
||||
d[di] = s[si];
|
||||
}
|
||||
|
@ -110,16 +108,15 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
public void Normalize(bool yflip)
|
||||
{
|
||||
var bmpdata = LockBits();
|
||||
int[] newPixels = new int[Width * Height];
|
||||
int todo = Width*Height;
|
||||
int* s = (int*)bmpdata.Scan0.ToPointer();
|
||||
var newPixels = new int[Width * Height];
|
||||
var s = (int*)bmpdata.Scan0.ToPointer();
|
||||
fixed (int* d = newPixels)
|
||||
{
|
||||
if (yflip)
|
||||
{
|
||||
for (int y = 0, si = 0, di = (Height - 1) * Width; y < Height; y++)
|
||||
{
|
||||
for (int x = 0; x < Width; x++, si++, di++)
|
||||
for (var x = 0; x < Width; x++, si++, di++)
|
||||
{
|
||||
d[di] = s[si] | unchecked((int)0xFF000000);
|
||||
}
|
||||
|
@ -130,7 +127,7 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
{
|
||||
for (int y = 0, i=0; y < Height; y++)
|
||||
{
|
||||
for (int x = 0; x < Width; x++, i++)
|
||||
for (var x = 0; x < Width; x++, i++)
|
||||
{
|
||||
d[i] = s[i] | unchecked((int)0xFF000000);
|
||||
}
|
||||
|
@ -143,11 +140,19 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
Pixels = newPixels;
|
||||
}
|
||||
|
||||
public int GetPixel(int x, int y) { return Pixels[Width * y + x]; }
|
||||
public void SetPixel(int x, int y, int value) { Pixels[Width * y + x] = value; }
|
||||
public int GetPixel(int x, int y)
|
||||
{
|
||||
return Pixels[Width * y + x];
|
||||
}
|
||||
|
||||
public void SetPixel(int x, int y, int value)
|
||||
{
|
||||
Pixels[Width * y + x] = value;
|
||||
}
|
||||
|
||||
public Color GetPixelAsColor(int x, int y)
|
||||
{
|
||||
int c = Pixels[Width * y + x];
|
||||
var c = Pixels[Width * y + x];
|
||||
return Color.FromArgb(c);
|
||||
}
|
||||
|
||||
|
@ -157,11 +162,15 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
public void Alphafy(int tcol)
|
||||
{
|
||||
for (int y = 0, idx = 0; y < Height; y++)
|
||||
for (int x = 0; x < Width; x++, idx++)
|
||||
{
|
||||
for (var x = 0; x < Width; x++, idx++)
|
||||
{
|
||||
if (Pixels[idx] == tcol)
|
||||
{
|
||||
Pixels[idx] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -177,15 +186,16 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
/// </summary>
|
||||
public BitmapBuffer Trim(out int xofs, out int yofs)
|
||||
{
|
||||
int minx = int.MaxValue;
|
||||
int maxx = int.MinValue;
|
||||
int miny = int.MaxValue;
|
||||
int maxy = int.MinValue;
|
||||
for (int y = 0; y < Height; y++)
|
||||
for (int x = 0; x < Width; x++)
|
||||
var minx = int.MaxValue;
|
||||
var maxx = int.MinValue;
|
||||
var miny = int.MaxValue;
|
||||
var maxy = int.MinValue;
|
||||
for (var y = 0; y < Height; y++)
|
||||
{
|
||||
for (var x = 0; x < Width; x++)
|
||||
{
|
||||
int pixel = GetPixel(x, y);
|
||||
int a = (pixel >> 24) & 0xFF;
|
||||
var pixel = GetPixel(x, y);
|
||||
var a = (pixel >> 24) & 0xFF;
|
||||
if (a != 0)
|
||||
{
|
||||
minx = Math.Min(minx, x);
|
||||
|
@ -194,21 +204,24 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
maxy = Math.Max(maxy, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (minx == int.MaxValue || maxx == int.MinValue || miny == int.MaxValue || minx == int.MinValue)
|
||||
{
|
||||
xofs = yofs = 0;
|
||||
return new BitmapBuffer(0, 0);
|
||||
return new(0, 0);
|
||||
}
|
||||
|
||||
int w = maxx - minx + 1;
|
||||
int h = maxy - miny + 1;
|
||||
BitmapBuffer bbRet = new BitmapBuffer(w, h);
|
||||
for (int y = 0; y < h; y++)
|
||||
for (int x = 0; x < w; x++)
|
||||
var w = maxx - minx + 1;
|
||||
var h = maxy - miny + 1;
|
||||
var bbRet = new BitmapBuffer(w, h);
|
||||
for (var y = 0; y < h; y++)
|
||||
{
|
||||
for (var x = 0; x < w; x++)
|
||||
{
|
||||
bbRet.SetPixel(x, y, GetPixel(x + minx, y + miny));
|
||||
}
|
||||
}
|
||||
|
||||
xofs = minx;
|
||||
yofs = miny;
|
||||
|
@ -220,15 +233,18 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
/// </summary>
|
||||
public void Pad()
|
||||
{
|
||||
int widthRound = NextHigher(Width);
|
||||
int heightRound = NextHigher(Height);
|
||||
var widthRound = NextHigher(Width);
|
||||
var heightRound = NextHigher(Height);
|
||||
if (widthRound == Width && heightRound == Height) return;
|
||||
int[] NewPixels = new int[heightRound * widthRound];
|
||||
var NewPixels = new int[heightRound * widthRound];
|
||||
|
||||
for (int y = 0, sptr = 0, dptr = 0; y < Height; y++)
|
||||
{
|
||||
for (int x = 0; x < Width; x++)
|
||||
for (var x = 0; x < Width; x++)
|
||||
{
|
||||
NewPixels[dptr++] = Pixels[sptr++];
|
||||
}
|
||||
|
||||
dptr += (widthRound - Width);
|
||||
}
|
||||
|
||||
|
@ -265,10 +281,12 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
Height = bitmap.Height;
|
||||
WrappedBitmap = bitmap;
|
||||
}
|
||||
else LoadInternal(null, bitmap, options);
|
||||
else
|
||||
{
|
||||
LoadInternal(null, bitmap, options);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a BitmapBuffer --WRAPPED-- from the supplied parameters, which should definitely have a stride==width and be in the standard color format
|
||||
/// </summary>
|
||||
|
@ -290,82 +308,89 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
|
||||
private void LoadInternal(Stream stream, Bitmap bitmap, BitmapLoadOptions options)
|
||||
{
|
||||
bool cleanup = options.CleanupAlpha0;
|
||||
bool needsPad = true;
|
||||
var cleanup = options.CleanupAlpha0;
|
||||
var needsPad = true;
|
||||
|
||||
var colorKey24bpp = options.ColorKey24bpp;
|
||||
using (Bitmap loadedBmp = bitmap == null ? new Bitmap(stream) : null) //sneaky!
|
||||
using (var loadedBmp = bitmap == null ? new Bitmap(stream) : null) // sneaky!
|
||||
{
|
||||
Bitmap bmp = loadedBmp;
|
||||
if (bmp == null)
|
||||
bmp = bitmap;
|
||||
var bmp = loadedBmp ?? bitmap;
|
||||
|
||||
//if we have a 24bpp image and a colorkey callback, the callback can choose a colorkey color and we'll use that
|
||||
// if we have a 24bpp image and a colorkey callback, the callback can choose a colorkey color and we'll use that
|
||||
if (bmp.PixelFormat == PixelFormat.Format24bppRgb && colorKey24bpp != null)
|
||||
{
|
||||
int colorKey = colorKey24bpp(bmp);
|
||||
int w = bmp.Width;
|
||||
int h = bmp.Height;
|
||||
var colorKey = colorKey24bpp(bmp);
|
||||
var w = bmp.Width;
|
||||
var h = bmp.Height;
|
||||
InitSize(w, h);
|
||||
BitmapData bmpdata = bmp.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
|
||||
Color[] palette = bmp.Palette.Entries;
|
||||
int* ptr = (int*)bmpdata.Scan0.ToPointer();
|
||||
int stride = bmpdata.Stride;
|
||||
var bmpdata = bmp.LockBits(new(0, 0, w, h), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
|
||||
var ptr = (int*)bmpdata.Scan0.ToPointer();
|
||||
fixed (int* pPtr = &Pixels[0])
|
||||
{
|
||||
for (int idx = 0, y = 0; y < h; y++)
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
for (var x = 0; x < w; x++)
|
||||
{
|
||||
int srcPixel = ptr[idx];
|
||||
var srcPixel = ptr[idx];
|
||||
if (srcPixel == colorKey)
|
||||
{
|
||||
srcPixel = 0;
|
||||
}
|
||||
|
||||
pPtr[idx++] = srcPixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bmp.UnlockBits(bmpdata);
|
||||
}
|
||||
if (bmp.PixelFormat == PixelFormat.Format8bppIndexed || bmp.PixelFormat == PixelFormat.Format4bppIndexed)
|
||||
if (bmp.PixelFormat is PixelFormat.Format8bppIndexed or PixelFormat.Format4bppIndexed)
|
||||
{
|
||||
int w = bmp.Width;
|
||||
int h = bmp.Height;
|
||||
var w = bmp.Width;
|
||||
var h = bmp.Height;
|
||||
InitSize(w, h);
|
||||
BitmapData bmpdata = bmp.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);
|
||||
Color[] palette = bmp.Palette.Entries;
|
||||
byte* ptr = (byte*)bmpdata.Scan0.ToPointer();
|
||||
var bmpdata = bmp.LockBits(new(0, 0, w, h), ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);
|
||||
var palette = bmp.Palette.Entries;
|
||||
var ptr = (byte*)bmpdata.Scan0.ToPointer();
|
||||
fixed (int* pPtr = &Pixels[0])
|
||||
{
|
||||
for (int idx = 0, y = 0; y < h; y++)
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
for (var x = 0; x < w; x++)
|
||||
{
|
||||
int srcPixel = ptr[idx];
|
||||
if (srcPixel != 0)
|
||||
{
|
||||
int color = palette[srcPixel].ToArgb();
|
||||
var color = palette[srcPixel].ToArgb();
|
||||
|
||||
//make transparent pixels turn into black to avoid filtering issues and other annoying issues with stray junk in transparent pixels.
|
||||
//(yes, we can have palette entries with transparency in them (PNGs support this, annoyingly))
|
||||
// make transparent pixels turn into black to avoid filtering issues and other annoying issues with stray junk in transparent pixels.
|
||||
// (yes, we can have palette entries with transparency in them (PNGs support this, annoyingly))
|
||||
if (cleanup)
|
||||
{
|
||||
if ((color & 0xFF000000) == 0) color = 0;
|
||||
if ((color & 0xFF000000) == 0)
|
||||
{
|
||||
color = 0;
|
||||
}
|
||||
|
||||
pPtr[idx] = color;
|
||||
}
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bmp.UnlockBits(bmpdata);
|
||||
}
|
||||
else
|
||||
{
|
||||
//dump the supplied bitmap into our pixels array
|
||||
int width = bmp.Width;
|
||||
int height = bmp.Height;
|
||||
// dump the supplied bitmap into our pixels array
|
||||
var width = bmp.Width;
|
||||
var height = bmp.Height;
|
||||
InitSize(width, height);
|
||||
BitmapData bmpdata = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
|
||||
int* ptr = (int*)bmpdata.Scan0;
|
||||
int stride = bmpdata.Stride / 4;
|
||||
var bmpdata = bmp.LockBits(new(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
|
||||
var ptr = (int*)bmpdata.Scan0;
|
||||
var stride = bmpdata.Stride / 4;
|
||||
LoadFrom(width, stride, height, (byte*)ptr, options);
|
||||
bmp.UnlockBits(bmpdata);
|
||||
needsPad = false;
|
||||
|
@ -373,7 +398,9 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
}
|
||||
|
||||
if (needsPad && options.Pad)
|
||||
{
|
||||
Pad();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -382,29 +409,37 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
/// </summary>
|
||||
public void LoadFrom(int width, int stride, int height, byte* data, BitmapLoadOptions options)
|
||||
{
|
||||
bool cleanup = options.CleanupAlpha0;
|
||||
var cleanup = options.CleanupAlpha0;
|
||||
Width = width;
|
||||
Height = height;
|
||||
Pixels = new int[width * height];
|
||||
fixed (int* pPtr = &Pixels[0])
|
||||
{
|
||||
for (int idx = 0, y = 0; y < Height; y++)
|
||||
for (int x = 0; x < Width; x++)
|
||||
{
|
||||
for (var x = 0; x < Width; x++)
|
||||
{
|
||||
int src = y * stride + x;
|
||||
int srcVal = ((int*)data)[src];
|
||||
|
||||
//make transparent pixels turn into black to avoid filtering issues and other annoying issues with stray junk in transparent pixels
|
||||
var src = y * stride + x;
|
||||
var srcVal = ((int*)data)[src];
|
||||
|
||||
// make transparent pixels turn into black to avoid filtering issues and other annoying issues with stray junk in transparent pixels
|
||||
if (cleanup)
|
||||
{
|
||||
if ((srcVal & 0xFF000000) == 0) srcVal = 0;
|
||||
if ((srcVal & 0xFF000000) == 0)
|
||||
{
|
||||
srcVal = 0;
|
||||
}
|
||||
|
||||
pPtr[idx++] = srcVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (options.Pad)
|
||||
{
|
||||
Pad();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -412,10 +447,10 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
/// </summary>
|
||||
public static int PremultiplyColor(int srcVal)
|
||||
{
|
||||
int b = (srcVal >> 0) & 0xFF;
|
||||
int g = (srcVal >> 8) & 0xFF;
|
||||
int r = (srcVal >> 16) & 0xFF;
|
||||
int a = (srcVal >> 24) & 0xFF;
|
||||
var b = (srcVal >> 0) & 0xFF;
|
||||
var g = (srcVal >> 8) & 0xFF;
|
||||
var r = (srcVal >> 16) & 0xFF;
|
||||
var a = (srcVal >> 24) & 0xFF;
|
||||
r = (r * a) >> 8;
|
||||
g = (g * a) >> 8;
|
||||
b = (b * a) >> 8;
|
||||
|
@ -434,7 +469,9 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
/// <summary>
|
||||
/// Makes a new bitmap buffer, in ??? state
|
||||
/// </summary>
|
||||
public BitmapBuffer() { }
|
||||
public BitmapBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// initializes an empty BitmapBuffer, cleared to all 0
|
||||
|
@ -449,24 +486,24 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
/// </summary>
|
||||
public void ClearWithoutAlloc()
|
||||
{
|
||||
//http://techmikael.blogspot.com/2009/12/filling-array-with-default-value.html
|
||||
//this guy says its faster
|
||||
// http://techmikael.blogspot.com/2009/12/filling-array-with-default-value.html
|
||||
// this guy says its faster
|
||||
|
||||
int size = Width * Height;
|
||||
byte fillValue = 0;
|
||||
ulong fillValueLong = 0;
|
||||
var size = Width * Height;
|
||||
const byte fillValue = 0;
|
||||
const ulong fillValueLong = 0;
|
||||
|
||||
fixed (int* ptr = &Pixels[0])
|
||||
{
|
||||
ulong* dest = (ulong*)ptr;
|
||||
int length = size;
|
||||
var dest = (ulong*)ptr;
|
||||
var length = size;
|
||||
while (length >= 8)
|
||||
{
|
||||
*dest = fillValueLong;
|
||||
dest++;
|
||||
length -= 8;
|
||||
}
|
||||
byte* bDest = (byte*)dest;
|
||||
var bDest = (byte*)dest;
|
||||
for (byte i = 0; i < length; i++)
|
||||
{
|
||||
*bDest = fillValue;
|
||||
|
@ -488,9 +525,12 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
private static int NextHigher(int k)
|
||||
{
|
||||
k--;
|
||||
for (int i = 1; i < 32; i <<= 1)
|
||||
for (var i = 1; i < 32; i <<= 1)
|
||||
{
|
||||
k = k | k >> i;
|
||||
int candidate = k + 1;
|
||||
}
|
||||
|
||||
var candidate = k + 1;
|
||||
return candidate;
|
||||
}
|
||||
|
||||
|
@ -501,11 +541,12 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
public Bitmap ToSysdrawingBitmap()
|
||||
{
|
||||
if (WrappedBitmap != null)
|
||||
{
|
||||
return (Bitmap)WrappedBitmap.Clone();
|
||||
var pf = PixelFormat.Format32bppArgb;
|
||||
if (!HasAlpha)
|
||||
pf = PixelFormat.Format24bppRgb;
|
||||
Bitmap bmp = new Bitmap(Width, Height, pf);
|
||||
}
|
||||
|
||||
var pf = HasAlpha ? PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb;
|
||||
var bmp = new Bitmap(Width, Height, pf);
|
||||
ToSysdrawingBitmap(bmp);
|
||||
return bmp;
|
||||
}
|
||||
|
@ -519,30 +560,33 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
if (WrappedBitmap != null)
|
||||
{
|
||||
using var g = Graphics.FromImage(bmp);
|
||||
g.CompositingMode = sd.Drawing2D.CompositingMode.SourceCopy;
|
||||
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed;
|
||||
g.CompositingMode = CompositingMode.SourceCopy;
|
||||
g.CompositingQuality = CompositingQuality.HighSpeed;
|
||||
g.DrawImageUnscaled(WrappedBitmap, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
//note: we lock it as 32bpp even if the bitmap is 24bpp so we can write to it more conveniently.
|
||||
var bmpdata = bmp.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
|
||||
var bmpdata = bmp.LockBits(new(0, 0, Width, Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
|
||||
|
||||
if(bmpdata.Stride == bmpdata.Width*4)
|
||||
if (bmpdata.Stride == bmpdata.Width * 4)
|
||||
{
|
||||
Marshal.Copy(Pixels, 0, bmpdata.Scan0, Width * Height);
|
||||
}
|
||||
else if (bmp.Width != 0 && bmp.Height != 0)
|
||||
{
|
||||
int* ptr = (int*)bmpdata.Scan0.ToPointer();
|
||||
int stride = bmpdata.Stride;
|
||||
var ptr = (int*)bmpdata.Scan0.ToPointer();
|
||||
fixed (int* pPtr = &Pixels[0])
|
||||
{
|
||||
for (int idx = 0, y = 0; y < Height; y++)
|
||||
for (int x = 0; x < Width; x++)
|
||||
{
|
||||
for (var x = 0; x < Width; x++)
|
||||
{
|
||||
int srcPixel = pPtr[idx];
|
||||
var srcPixel = pPtr[idx];
|
||||
ptr[idx] = srcPixel;
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace BizHawk.Bizware.BizwareGL
|
||||
{
|
||||
public class GDIPTextureWrapper : IDisposable
|
||||
{
|
||||
public System.Drawing.Bitmap SDBitmap;
|
||||
public Bitmap SDBitmap;
|
||||
public TextureMinFilter MinFilter = TextureMinFilter.Nearest;
|
||||
public TextureMagFilter MagFilter = TextureMagFilter.Nearest;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (SDBitmap != null)
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
//this is full of bugs probably, related to state from old rendering sessions being all messed up. its only barely good enough to work at all
|
||||
// this is full of bugs probably, related to state from old rendering sessions being all messed up. its only barely good enough to work at all
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
|
||||
using sd = System.Drawing;
|
||||
using System.Numerics;
|
||||
|
||||
namespace BizHawk.Bizware.BizwareGL
|
||||
{
|
||||
|
@ -14,7 +15,13 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
public GDIPlusGuiRenderer(IGL_GdiPlus gl)
|
||||
=> Gdi = gl;
|
||||
|
||||
private readonly Vector4[] CornerColors = { new(1.0f, 1.0f, 1.0f, 1.0f), new(1.0f, 1.0f, 1.0f, 1.0f), new(1.0f, 1.0f, 1.0f, 1.0f), new(1.0f, 1.0f, 1.0f, 1.0f) };
|
||||
private readonly Vector4[] CornerColors =
|
||||
{
|
||||
new(1.0f, 1.0f, 1.0f, 1.0f),
|
||||
new(1.0f, 1.0f, 1.0f, 1.0f),
|
||||
new(1.0f, 1.0f, 1.0f, 1.0f),
|
||||
new(1.0f, 1.0f, 1.0f, 1.0f)
|
||||
};
|
||||
|
||||
public void SetCornerColor(int which, Vector4 color)
|
||||
{
|
||||
|
@ -25,9 +32,16 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
public void SetCornerColors(Vector4[] colors)
|
||||
{
|
||||
Flush(); //don't really need to flush with current implementation. we might as well roll modulate color into it too.
|
||||
if (colors.Length != 4) throw new ArgumentException("array must be size 4", nameof(colors));
|
||||
for (int i = 0; i < 4; i++)
|
||||
|
||||
if (colors.Length != 4)
|
||||
{
|
||||
throw new ArgumentException("array must be size 4", nameof(colors));
|
||||
}
|
||||
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
CornerColors[i] = colors[i];
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
@ -45,30 +59,31 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
|
||||
public void SetModulateColorWhite()
|
||||
{
|
||||
SetModulateColor(sd.Color.White);
|
||||
SetModulateColor(Color.White);
|
||||
}
|
||||
|
||||
private ImageAttributes CurrentImageAttributes;
|
||||
public void SetModulateColor(sd.Color color)
|
||||
|
||||
public void SetModulateColor(Color color)
|
||||
{
|
||||
//white is really no color at all
|
||||
if (color.ToArgb() == sd.Color.White.ToArgb())
|
||||
// white is really no color at all
|
||||
if (color.ToArgb() == Color.White.ToArgb())
|
||||
{
|
||||
CurrentImageAttributes.ClearColorMatrix(ColorAdjustType.Bitmap);
|
||||
return;
|
||||
}
|
||||
|
||||
float r = color.R / 255.0f;
|
||||
float g = color.G / 255.0f;
|
||||
float b = color.B / 255.0f;
|
||||
float a = color.A / 255.0f;
|
||||
var r = color.R / 255.0f;
|
||||
var g = color.G / 255.0f;
|
||||
var b = color.B / 255.0f;
|
||||
var a = color.A / 255.0f;
|
||||
|
||||
float[][] colorMatrixElements =
|
||||
{
|
||||
new float[] { r, 0, 0, 0, 0 },
|
||||
new float[] { 0, g, 0, 0, 0 },
|
||||
new float[] { 0, 0, b, 0, 0 },
|
||||
new float[] { 0, 0, 0, a, 0 },
|
||||
new[] { r, 0, 0, 0, 0 },
|
||||
new[] { 0, g, 0, 0, 0 },
|
||||
new[] { 0, 0, b, 0, 0 },
|
||||
new[] { 0, 0, 0, a, 0 },
|
||||
new float[] { 0, 0, 0, 0, 1 },
|
||||
};
|
||||
|
||||
|
@ -76,15 +91,15 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
CurrentImageAttributes.SetColorMatrix(colorMatrix,ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
|
||||
}
|
||||
|
||||
private sd.Color CurrentModulateColor = sd.Color.White;
|
||||
|
||||
private IBlendState CurrentBlendState;
|
||||
|
||||
public void SetBlendState(IBlendState rsBlend)
|
||||
{
|
||||
CurrentBlendState = rsBlend;
|
||||
}
|
||||
|
||||
private MatrixStack _Projection, _Modelview;
|
||||
|
||||
public MatrixStack Projection
|
||||
{
|
||||
get => _Projection;
|
||||
|
@ -94,6 +109,7 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
_Projection.IsDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public MatrixStack Modelview
|
||||
{
|
||||
get => _Modelview;
|
||||
|
@ -104,8 +120,10 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
}
|
||||
}
|
||||
|
||||
public void Begin(sd.Size size) { Begin(size.Width, size.Height); }
|
||||
|
||||
public void Begin(Size size)
|
||||
{
|
||||
Begin(size.Width, size.Height);
|
||||
}
|
||||
|
||||
public void Begin(int width, int height)
|
||||
{
|
||||
|
@ -117,31 +135,29 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
Modelview = Owner.CreateGuiViewMatrix(width, height);
|
||||
}
|
||||
|
||||
|
||||
public void Begin()
|
||||
{
|
||||
//uhhmmm I want to throw an exception if its already active, but its annoying.
|
||||
// uhhmmm I want to throw an exception if its already active, but its annoying.
|
||||
IsActive = true;
|
||||
CurrentImageAttributes = new ImageAttributes();
|
||||
CurrentImageAttributes = new();
|
||||
}
|
||||
|
||||
|
||||
public void Flush()
|
||||
{
|
||||
//no batching, nothing to do here yet
|
||||
// no batching, nothing to do here yet
|
||||
}
|
||||
|
||||
/// <exception cref="InvalidOperationException"><see cref="IsActive"/> is <see langword="false"/></exception>
|
||||
public void End()
|
||||
{
|
||||
if (!IsActive)
|
||||
throw new InvalidOperationException($"{nameof(GDIPlusGuiRenderer)} is not active!");
|
||||
IsActive = false;
|
||||
if (CurrentImageAttributes != null)
|
||||
{
|
||||
CurrentImageAttributes.Dispose();
|
||||
CurrentImageAttributes = null;
|
||||
throw new InvalidOperationException($"{nameof(GDIPlusGuiRenderer)} is not active!");
|
||||
}
|
||||
|
||||
IsActive = false;
|
||||
CurrentImageAttributes?.Dispose();
|
||||
CurrentImageAttributes = null;
|
||||
}
|
||||
|
||||
public void RectFill(float x, float y, float w, float h)
|
||||
|
@ -150,24 +166,26 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
|
||||
public void DrawSubrect(Texture2d tex, float x, float y, float w, float h, float u0, float v0, float u1, float v1)
|
||||
{
|
||||
var tw = tex.Opaque as GDIPTextureWrapper;
|
||||
var tw = (GDIPTextureWrapper)tex.Opaque;
|
||||
var g = Gdi.GetCurrentGraphics();
|
||||
|
||||
PrepDraw(g, tex);
|
||||
SetupMatrix(g);
|
||||
|
||||
float x0 = u0 * tex.Width;
|
||||
float y0 = v0 * tex.Height;
|
||||
float x1 = u1 * tex.Width;
|
||||
float y1 = v1 * tex.Height;
|
||||
var x0 = u0 * tex.Width;
|
||||
var y0 = v0 * tex.Height;
|
||||
var x1 = u1 * tex.Width;
|
||||
var y1 = v1 * tex.Height;
|
||||
|
||||
sd.PointF[] destPoints = {
|
||||
new sd.PointF(x,y),
|
||||
new sd.PointF(x+w,y),
|
||||
new sd.PointF(x,y+h),
|
||||
PointF[] destPoints =
|
||||
{
|
||||
new(x, y),
|
||||
new(x+w, y),
|
||||
new(x, y+h),
|
||||
};
|
||||
|
||||
g.DrawImage(tw.SDBitmap, destPoints, new sd.RectangleF(x0, y0, x1 - x0, y1 - y0), sd.GraphicsUnit.Pixel, CurrentImageAttributes);
|
||||
g.Transform = new sd.Drawing2D.Matrix(); //.Reset() doesnt work ? ?
|
||||
g.DrawImage(tw.SDBitmap, destPoints, new(x0, y0, x1 - x0, y1 - y0), GraphicsUnit.Pixel, CurrentImageAttributes);
|
||||
g.Transform = new(); // .Reset() doesnt work?
|
||||
}
|
||||
|
||||
|
||||
|
@ -184,47 +202,49 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
DrawInternal(art, x, y, width, height);
|
||||
}
|
||||
|
||||
private void PrepDraw(sd.Graphics g, Texture2d tex)
|
||||
private void PrepDraw(Graphics g, Texture2d tex)
|
||||
{
|
||||
var tw = tex.Opaque as GDIPTextureWrapper;
|
||||
//TODO - we can support bicubic for the final presentation..
|
||||
var tw = (GDIPTextureWrapper)tex.Opaque;
|
||||
|
||||
// TODO - we can support bicubic for the final presentation...
|
||||
if ((int)tw.MagFilter != (int)tw.MinFilter)
|
||||
{
|
||||
throw new InvalidOperationException($"{nameof(tw)}.{nameof(tw.MagFilter)} != {nameof(tw)}.{nameof(tw.MinFilter)}");
|
||||
if (tw.MagFilter == TextureMagFilter.Linear)
|
||||
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Bilinear;
|
||||
if (tw.MagFilter == TextureMagFilter.Nearest)
|
||||
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
|
||||
}
|
||||
|
||||
|
||||
//---------
|
||||
g.InterpolationMode = tw.MagFilter switch
|
||||
{
|
||||
TextureMagFilter.Linear => InterpolationMode.Bilinear,
|
||||
TextureMagFilter.Nearest => InterpolationMode.NearestNeighbor,
|
||||
_ => g.InterpolationMode
|
||||
};
|
||||
|
||||
if (CurrentBlendState == Gdi.BlendNormal)
|
||||
{
|
||||
g.CompositingMode = sd.Drawing2D.CompositingMode.SourceOver;
|
||||
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.Default; //?
|
||||
g.CompositingMode = CompositingMode.SourceOver;
|
||||
g.CompositingQuality = CompositingQuality.Default; // ?
|
||||
|
||||
//CurrentImageAttributes.ClearColorMatrix(ColorAdjustType.Bitmap);
|
||||
// CurrentImageAttributes.ClearColorMatrix(ColorAdjustType.Bitmap);
|
||||
}
|
||||
else
|
||||
//if(CurrentBlendState == Gdi.BlendNoneCopy)
|
||||
//if(CurrentBlendState == Gdi.BlendNoneOpaque)
|
||||
// if (CurrentBlendState == Gdi.BlendNoneCopy)
|
||||
// if (CurrentBlendState == Gdi.BlendNoneOpaque)
|
||||
{
|
||||
g.CompositingMode = sd.Drawing2D.CompositingMode.SourceCopy;
|
||||
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed;
|
||||
g.CompositingMode = CompositingMode.SourceCopy;
|
||||
g.CompositingQuality = CompositingQuality.HighSpeed;
|
||||
|
||||
//WARNING : DO NOT USE COLOR MATRIX TO WIPE THE ALPHA
|
||||
//ITS SOOOOOOOOOOOOOOOOOOOOOOOOOOOO SLOW
|
||||
//instead, we added kind of hacky support for 24bpp images
|
||||
// WARNING : DO NOT USE COLOR MATRIX TO WIPE THE ALPHA
|
||||
// ITS SOOOOOOOOOOOOOOOOOOOOOOOOOOOO SLOW
|
||||
// instead, we added kind of hacky support for 24bpp images
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void SetupMatrix(sd.Graphics g)
|
||||
private void SetupMatrix(Graphics g)
|
||||
{
|
||||
//projection is always identity, so who cares i guess
|
||||
//Matrix4 mat = Projection.Top * Modelview.Top;
|
||||
Matrix4 mat = Modelview.Top;
|
||||
g.Transform = new sd.Drawing2D.Matrix(mat.Row0.X, mat.Row0.Y, mat.Row1.X, mat.Row1.Y, mat.Row3.X, mat.Row3.Y);
|
||||
// projection is always identity, so who cares i guess
|
||||
// var mat = Projection.Top * Modelview.Top;
|
||||
var mat = Modelview.Top;
|
||||
g.Transform = new(mat.M11, mat.M12, mat.M21, mat.M22, mat.M41, mat.M42);
|
||||
}
|
||||
|
||||
private void DrawInternal(Art art, float x, float y, float w, float h)
|
||||
|
@ -244,26 +264,27 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
|
||||
SetupMatrix(g);
|
||||
|
||||
sd.PointF[] destPoints = {
|
||||
new sd.PointF(x,y),
|
||||
new sd.PointF(x+w,y),
|
||||
new sd.PointF(x,y+h),
|
||||
PointF[] destPoints =
|
||||
{
|
||||
new(x, y),
|
||||
new(x+w, y),
|
||||
new(x, y+h),
|
||||
};
|
||||
|
||||
float sx = tex.Width * u0;
|
||||
float sy = tex.Height * v0;
|
||||
float sx2 = tex.Width * u1;
|
||||
float sy2 = tex.Height * v1;
|
||||
float sw = sx2 - sx;
|
||||
float sh = sy2 - sy;
|
||||
var sx = tex.Width * u0;
|
||||
var sy = tex.Height * v0;
|
||||
var sx2 = tex.Width * u1;
|
||||
var sy2 = tex.Height * v1;
|
||||
var sw = sx2 - sx;
|
||||
var sh = sy2 - sy;
|
||||
|
||||
var tw = tex.Opaque as GDIPTextureWrapper;
|
||||
g.PixelOffsetMode = sd.Drawing2D.PixelOffsetMode.Half;
|
||||
g.DrawImage(tw.SDBitmap, destPoints, new sd.RectangleF(sx, sy, sw, sh), sd.GraphicsUnit.Pixel, CurrentImageAttributes);
|
||||
g.Transform = new sd.Drawing2D.Matrix(); //.Reset() doesn't work ? ?
|
||||
var tw = (GDIPTextureWrapper)tex.Opaque;
|
||||
g.PixelOffsetMode = PixelOffsetMode.Half;
|
||||
g.DrawImage(tw.SDBitmap, destPoints, new(sx, sy, sw, sh), GraphicsUnit.Pixel, CurrentImageAttributes);
|
||||
g.Transform = new(); // .Reset() doesn't work ? ?
|
||||
}
|
||||
|
||||
private void DrawInternal(Art art, float x, float y, float w, float h, bool fx, bool fy)
|
||||
private static void DrawInternal(Art art, float x, float y, float w, float h, bool fx, bool fy)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
namespace BizHawk.Bizware.BizwareGL
|
||||
{
|
||||
public interface IBlendState {}
|
||||
public interface IBlendState
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Drawing;
|
||||
using System.Numerics;
|
||||
|
||||
namespace BizHawk.Bizware.BizwareGL
|
||||
{
|
||||
|
@ -55,12 +56,12 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
/// <summary>
|
||||
/// Sets a uniform value
|
||||
/// </summary>
|
||||
void SetPipelineUniformMatrix(PipelineUniform uniform, Matrix4 mat, bool transpose);
|
||||
void SetPipelineUniformMatrix(PipelineUniform uniform, Matrix4x4 mat, bool transpose);
|
||||
|
||||
/// <summary>
|
||||
/// Sets a uniform value
|
||||
/// </summary>
|
||||
void SetPipelineUniformMatrix(PipelineUniform uniform, ref Matrix4 mat, bool transpose);
|
||||
void SetPipelineUniformMatrix(PipelineUniform uniform, ref Matrix4x4 mat, bool transpose);
|
||||
|
||||
/// <summary>
|
||||
/// sets a uniform value
|
||||
|
@ -219,24 +220,24 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
/// <summary>
|
||||
/// generates a proper 2d othographic projection for the given destination size, suitable for use in a GUI
|
||||
/// </summary>
|
||||
Matrix4 CreateGuiProjectionMatrix(int w, int h);
|
||||
Matrix4x4 CreateGuiProjectionMatrix(int w, int h);
|
||||
|
||||
/// <summary>
|
||||
/// generates a proper 2d othographic projection for the given destination size, suitable for use in a GUI
|
||||
/// </summary>
|
||||
Matrix4 CreateGuiProjectionMatrix(Size dims);
|
||||
Matrix4x4 CreateGuiProjectionMatrix(Size dims);
|
||||
|
||||
/// <summary>
|
||||
/// generates a proper view transform for a standard 2d ortho projection, including half-pixel jitter if necessary and
|
||||
/// re-establishing of a normal 2d graphics top-left origin. suitable for use in a GUI
|
||||
/// </summary>
|
||||
Matrix4 CreateGuiViewMatrix(int w, int h, bool autoflip = true);
|
||||
Matrix4x4 CreateGuiViewMatrix(int w, int h, bool autoflip = true);
|
||||
|
||||
/// <summary>
|
||||
/// generates a proper view transform for a standard 2d ortho projection, including half-pixel jitter if necessary and
|
||||
/// re-establishing of a normal 2d graphics top-left origin. suitable for use in a GUI
|
||||
/// </summary>
|
||||
Matrix4 CreateGuiViewMatrix(Size dims, bool autoflip = true);
|
||||
Matrix4x4 CreateGuiViewMatrix(Size dims, bool autoflip = true);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a render target. Only includes a color buffer. Pixel format control TBD
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Drawing;
|
||||
|
||||
using sd = System.Drawing;
|
||||
using sdi = System.Drawing.Imaging;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Numerics;
|
||||
|
||||
//TODO - maybe a layer to cache Graphics parameters (notably, filtering) ?
|
||||
namespace BizHawk.Bizware.BizwareGL
|
||||
|
@ -12,22 +11,25 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
{
|
||||
public EDispMethod DispMethodEnum => EDispMethod.GdiPlus;
|
||||
|
||||
#if false
|
||||
// rendering state
|
||||
private RenderTarget _currRenderTarget;
|
||||
#endif
|
||||
|
||||
private readonly Func<IGL_GdiPlus, IGraphicsControl> _createGLControlWrapper;
|
||||
|
||||
public IGL_GdiPlus(Func<IGL_GdiPlus, IGraphicsControl> createGLControlWrapper)
|
||||
=> _createGLControlWrapper = createGLControlWrapper;
|
||||
|
||||
void IDisposable.Dispose()
|
||||
public void Dispose()
|
||||
{
|
||||
MyBufferedGraphicsContext.Dispose();
|
||||
}
|
||||
|
||||
public void Clear(ClearBufferMask mask)
|
||||
{
|
||||
var g = GetCurrentGraphics();
|
||||
if((mask & ClearBufferMask.ColorBufferBit) != 0)
|
||||
if ((mask & ClearBufferMask.ColorBufferBit) != 0)
|
||||
{
|
||||
g.Clear(_currentClearColor);
|
||||
}
|
||||
|
@ -41,31 +43,39 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
return null;
|
||||
}
|
||||
|
||||
private sd.Color _currentClearColor = Color.Transparent;
|
||||
public void SetClearColor(sd.Color color)
|
||||
private Color _currentClearColor = Color.Transparent;
|
||||
|
||||
public void SetClearColor(Color color)
|
||||
{
|
||||
_currentClearColor = color;
|
||||
}
|
||||
|
||||
public void BindArrayData(IntPtr pData) {}
|
||||
|
||||
public void BindArrayData(IntPtr pData)
|
||||
{
|
||||
}
|
||||
|
||||
public void FreeTexture(Texture2d tex)
|
||||
{
|
||||
var tw = tex.Opaque as GDIPTextureWrapper;
|
||||
var tw = (GDIPTextureWrapper)tex.Opaque;
|
||||
tw.Dispose();
|
||||
}
|
||||
|
||||
public Shader CreateFragmentShader(string source, string entry, bool required) => null;
|
||||
public Shader CreateVertexShader(string source, string entry, bool required) => null;
|
||||
public Shader CreateFragmentShader(string source, string entry, bool required)
|
||||
=> null;
|
||||
|
||||
public Shader CreateVertexShader(string source, string entry, bool required)
|
||||
=> null;
|
||||
|
||||
public void SetBlendState(IBlendState rsBlend)
|
||||
{
|
||||
//TODO for real
|
||||
// TODO for real
|
||||
}
|
||||
|
||||
private class MyBlendState : IBlendState { }
|
||||
private class EmptyBlendState : IBlendState
|
||||
{
|
||||
}
|
||||
|
||||
private static readonly MyBlendState _rsBlendNoneVerbatim = new MyBlendState(), _rsBlendNoneOpaque = new MyBlendState(), _rsBlendNormal = new MyBlendState();
|
||||
private static readonly EmptyBlendState _rsBlendNoneVerbatim = new(), _rsBlendNoneOpaque = new(), _rsBlendNormal = new();
|
||||
|
||||
public IBlendState BlendNoneCopy => _rsBlendNoneVerbatim;
|
||||
public IBlendState BlendNoneOpaque => _rsBlendNoneOpaque;
|
||||
|
@ -76,9 +86,12 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
return null;
|
||||
}
|
||||
|
||||
public void FreePipeline(Pipeline pipeline) {}
|
||||
public void FreePipeline(Pipeline pipeline)
|
||||
{
|
||||
}
|
||||
|
||||
public VertexLayout CreateVertexLayout() => new VertexLayout(this, new IntPtr(0));
|
||||
public VertexLayout CreateVertexLayout()
|
||||
=> new(this, null);
|
||||
|
||||
public void SetTextureWrapMode(Texture2d tex, bool clamp)
|
||||
{
|
||||
|
@ -102,11 +115,11 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
|
||||
}
|
||||
|
||||
public void SetPipelineUniformMatrix(PipelineUniform uniform, Matrix4 mat, bool transpose)
|
||||
public void SetPipelineUniformMatrix(PipelineUniform uniform, Matrix4x4 mat, bool transpose)
|
||||
{
|
||||
}
|
||||
|
||||
public void SetPipelineUniformMatrix(PipelineUniform uniform, ref Matrix4 mat, bool transpose)
|
||||
public void SetPipelineUniformMatrix(PipelineUniform uniform, ref Matrix4x4 mat, bool transpose)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -131,97 +144,98 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
|
||||
}
|
||||
|
||||
public void SetMinFilter(Texture2d texture, Bizware.BizwareGL.TextureMinFilter minFilter)
|
||||
public void SetMinFilter(Texture2d texture, TextureMinFilter minFilter)
|
||||
=> ((GDIPTextureWrapper) texture.Opaque).MinFilter = minFilter;
|
||||
|
||||
public void SetMagFilter(Texture2d texture, Bizware.BizwareGL.TextureMagFilter magFilter)
|
||||
public void SetMagFilter(Texture2d texture, TextureMagFilter magFilter)
|
||||
=> ((GDIPTextureWrapper) texture.Opaque).MagFilter = magFilter;
|
||||
|
||||
public Texture2d LoadTexture(Bitmap bitmap)
|
||||
{
|
||||
var sdBitmap = (Bitmap)bitmap.Clone();
|
||||
GDIPTextureWrapper tw = new GDIPTextureWrapper { SDBitmap = sdBitmap };
|
||||
return new Texture2d(this, tw, bitmap.Width, bitmap.Height);
|
||||
var tw = new GDIPTextureWrapper { SDBitmap = sdBitmap };
|
||||
return new(this, tw, bitmap.Width, bitmap.Height);
|
||||
}
|
||||
|
||||
public Texture2d LoadTexture(Stream stream)
|
||||
{
|
||||
using var bmp = new BitmapBuffer(stream, new BitmapLoadOptions());
|
||||
return (this as IGL).LoadTexture(bmp);
|
||||
using var bmp = new BitmapBuffer(stream, new());
|
||||
return LoadTexture(bmp);
|
||||
}
|
||||
|
||||
public Texture2d CreateTexture(int width, int height) => null;
|
||||
public Texture2d CreateTexture(int width, int height)
|
||||
=> null;
|
||||
|
||||
public Texture2d WrapGLTexture2d(IntPtr glTexId, int width, int height)
|
||||
{
|
||||
// TODO - need to rip the texture data. we had code for that somewhere...
|
||||
// only used for OpenGL
|
||||
return null;
|
||||
}
|
||||
|
||||
public void LoadTextureData(Texture2d tex, BitmapBuffer bmp)
|
||||
{
|
||||
var tw = tex.Opaque as GDIPTextureWrapper;
|
||||
var tw = (GDIPTextureWrapper)tex.Opaque;
|
||||
bmp.ToSysdrawingBitmap(tw.SDBitmap);
|
||||
}
|
||||
|
||||
|
||||
public Texture2d LoadTexture(BitmapBuffer bmp)
|
||||
{
|
||||
// definitely needed (by TextureFrugalizer at least)
|
||||
var sdBitmap = bmp.ToSysdrawingBitmap();
|
||||
var tw = new GDIPTextureWrapper { SDBitmap = sdBitmap };
|
||||
return new Texture2d(this, tw, bmp.Width, bmp.Height);
|
||||
return new(this, tw, bmp.Width, bmp.Height);
|
||||
}
|
||||
|
||||
public BitmapBuffer ResolveTexture2d(Texture2d tex)
|
||||
{
|
||||
var tw = tex.Opaque as GDIPTextureWrapper;
|
||||
var tw = (GDIPTextureWrapper)tex.Opaque;
|
||||
var blow = new BitmapLoadOptions
|
||||
{
|
||||
AllowWrap = false // must be an independent resource
|
||||
};
|
||||
|
||||
var bb = new BitmapBuffer(tw.SDBitmap, blow);
|
||||
return bb;
|
||||
}
|
||||
|
||||
public Texture2d LoadTexture(string path)
|
||||
{
|
||||
//todo
|
||||
//using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
// return (this as IGL).LoadTexture(fs);
|
||||
return null;
|
||||
using var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
return LoadTexture(fs);
|
||||
}
|
||||
|
||||
public Matrix4 CreateGuiProjectionMatrix(int w, int h)
|
||||
public Matrix4x4 CreateGuiProjectionMatrix(int w, int h)
|
||||
{
|
||||
return CreateGuiProjectionMatrix(new Size(w, h));
|
||||
return CreateGuiProjectionMatrix(new(w, h));
|
||||
}
|
||||
|
||||
public Matrix4 CreateGuiViewMatrix(int w, int h, bool autoFlip)
|
||||
public Matrix4x4 CreateGuiViewMatrix(int w, int h, bool autoFlip)
|
||||
{
|
||||
return CreateGuiViewMatrix(new Size(w, h), autoFlip);
|
||||
return CreateGuiViewMatrix(new(w, h), autoFlip);
|
||||
}
|
||||
|
||||
public Matrix4 CreateGuiProjectionMatrix(Size dims)
|
||||
public Matrix4x4 CreateGuiProjectionMatrix(Size dims)
|
||||
{
|
||||
//see CreateGuiViewMatrix for more
|
||||
return Matrix4.Identity;
|
||||
// see CreateGuiViewMatrix for more
|
||||
return Matrix4x4.Identity;
|
||||
}
|
||||
|
||||
public Matrix4 CreateGuiViewMatrix(Size dims, bool autoFlip)
|
||||
public Matrix4x4 CreateGuiViewMatrix(Size dims, bool autoFlip)
|
||||
{
|
||||
//on account of gdi+ working internally with a default view exactly like we want, we don't need to setup a new one here
|
||||
//furthermore, we _cant_, without inverting the GuiView and GuiProjection before drawing, to completely undo it
|
||||
//this might be feasible, but its kind of slow and annoying and worse, seemingly numerically unstable
|
||||
//if (autoFlip && _CurrRenderTarget != null)
|
||||
//{
|
||||
// Matrix4 ret = Matrix4.Identity;
|
||||
// ret.M22 = -1;
|
||||
// ret.M42 = dims.Height;
|
||||
// return ret;
|
||||
//}
|
||||
//else
|
||||
return Matrix4.Identity;
|
||||
// on account of gdi+ working internally with a default view exactly like we want, we don't need to setup a new one here
|
||||
// furthermore, we _cant_, without inverting the GuiView and GuiProjection before drawing, to completely undo it
|
||||
// this might be feasible, but its kind of slow and annoying and worse, seemingly numerically unstable
|
||||
#if false
|
||||
if (autoFlip && _currRenderTarget != null)
|
||||
{
|
||||
Matrix4 ret = Matrix4.Identity;
|
||||
ret.M22 = -1;
|
||||
ret.M42 = dims.Height;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
return Matrix4x4.Identity;
|
||||
}
|
||||
|
||||
public void SetViewport(int x, int y, int width, int height)
|
||||
|
@ -242,15 +256,11 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
CurrentControl = control;
|
||||
}
|
||||
|
||||
public void EndControl(IGraphicsControl control)
|
||||
public void EndControl()
|
||||
{
|
||||
CurrentControl = null;
|
||||
}
|
||||
|
||||
public void SwapControl(IGraphicsControl control)
|
||||
{
|
||||
}
|
||||
|
||||
public void BeginScene()
|
||||
{
|
||||
}
|
||||
|
@ -265,17 +275,15 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
public IGraphicsControl Internal_CreateGraphicsControl()
|
||||
{
|
||||
var ret = _createGLControlWrapper(this);
|
||||
|
||||
// create a render target for this control
|
||||
var rtw = new RenderTargetWrapper(() => MyBufferedGraphicsContext, ret);
|
||||
ret.RenderTargetWrapper = rtw;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void FreeRenderTarget(RenderTarget rt)
|
||||
{
|
||||
var rtw = rt.Opaque as RenderTargetWrapper;
|
||||
var rtw = (RenderTargetWrapper)rt.Opaque;
|
||||
rtw.Dispose();
|
||||
}
|
||||
|
||||
|
@ -283,7 +291,7 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
{
|
||||
var tw = new GDIPTextureWrapper
|
||||
{
|
||||
SDBitmap = new Bitmap(w, h, sdi.PixelFormat.Format32bppArgb)
|
||||
SDBitmap = new(w, h, PixelFormat.Format32bppArgb)
|
||||
};
|
||||
var tex = new Texture2d(this, tw, w, h);
|
||||
|
||||
|
@ -295,46 +303,55 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
|
||||
public void BindRenderTarget(RenderTarget rt)
|
||||
{
|
||||
if (_CurrentOffscreenGraphics != null)
|
||||
if (_currOffscreenGraphics != null)
|
||||
{
|
||||
_CurrentOffscreenGraphics.Dispose();
|
||||
_CurrentOffscreenGraphics = null;
|
||||
_currOffscreenGraphics.Dispose();
|
||||
_currOffscreenGraphics = null;
|
||||
}
|
||||
|
||||
#if false
|
||||
_currRenderTarget = rt;
|
||||
if (CurrentRenderTargetWrapper != null)
|
||||
{
|
||||
if (CurrentRenderTargetWrapper == CurrentControl.RenderTargetWrapper)
|
||||
{
|
||||
//don't do anything til swapbuffers
|
||||
// don't do anything til swapbuffers
|
||||
}
|
||||
else
|
||||
{
|
||||
//CurrentRenderTargetWrapper.MyBufferedGraphics.Render();
|
||||
// CurrentRenderTargetWrapper.MyBufferedGraphics.Render();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (rt == null)
|
||||
{
|
||||
//null means to use the default RT for the current control
|
||||
// null means to use the default RT for the current control
|
||||
CurrentRenderTargetWrapper = CurrentControl.RenderTargetWrapper;
|
||||
}
|
||||
else
|
||||
{
|
||||
var tw = rt.Texture2d.Opaque as GDIPTextureWrapper;
|
||||
CurrentRenderTargetWrapper = rt.Opaque as RenderTargetWrapper;
|
||||
_CurrentOffscreenGraphics = Graphics.FromImage(tw.SDBitmap);
|
||||
//if (CurrentRenderTargetWrapper.MyBufferedGraphics == null)
|
||||
// CurrentRenderTargetWrapper.CreateGraphics();
|
||||
var tw = (GDIPTextureWrapper)rt.Texture2d.Opaque;
|
||||
CurrentRenderTargetWrapper = (RenderTargetWrapper)rt.Opaque;
|
||||
_currOffscreenGraphics = Graphics.FromImage(tw.SDBitmap);
|
||||
#if false
|
||||
if (CurrentRenderTargetWrapper.MyBufferedGraphics == null)
|
||||
{
|
||||
CurrentRenderTargetWrapper.CreateGraphics();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private Graphics _CurrentOffscreenGraphics;
|
||||
private Graphics _currOffscreenGraphics;
|
||||
|
||||
public Graphics GetCurrentGraphics()
|
||||
{
|
||||
if (_CurrentOffscreenGraphics != null)
|
||||
return _CurrentOffscreenGraphics;
|
||||
if (_currOffscreenGraphics != null)
|
||||
{
|
||||
return _currOffscreenGraphics;
|
||||
}
|
||||
|
||||
var rtw = CurrentRenderTargetWrapper;
|
||||
return rtw.MyBufferedGraphics.Graphics;
|
||||
}
|
||||
|
@ -343,7 +360,5 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
public RenderTargetWrapper CurrentRenderTargetWrapper;
|
||||
|
||||
public readonly BufferedGraphicsContext MyBufferedGraphicsContext = new();
|
||||
|
||||
|
||||
} //class IGL_GdiPlus
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.Numerics;
|
||||
|
||||
namespace BizHawk.Bizware.BizwareGL
|
||||
{
|
||||
|
@ -9,7 +11,7 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
/// </summary>
|
||||
void Begin();
|
||||
|
||||
void Begin(System.Drawing.Size size);
|
||||
void Begin(Size size);
|
||||
|
||||
/// <summary>
|
||||
/// begin rendering, initializing viewport and projections to the given dimensions
|
||||
|
@ -51,7 +53,6 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
/// </summary>
|
||||
void Draw(Texture2d tex, float x, float y);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// draws the specified Art resource with the given flip flags
|
||||
/// </summary>
|
||||
|
@ -74,10 +75,15 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
void Flush();
|
||||
|
||||
bool IsActive { get; }
|
||||
|
||||
MatrixStack Modelview { get; set; }
|
||||
|
||||
IGL Owner { get; }
|
||||
|
||||
MatrixStack Projection { get; set; }
|
||||
|
||||
void RectFill(float x, float y, float w, float h);
|
||||
|
||||
void SetBlendState(IBlendState rsBlend);
|
||||
|
||||
/// <summary>
|
||||
|
@ -96,7 +102,9 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
/// Restores the pipeline to the default
|
||||
/// </summary>
|
||||
void SetDefaultPipeline();
|
||||
void SetModulateColor(System.Drawing.Color color);
|
||||
|
||||
void SetModulateColor(Color color);
|
||||
|
||||
void SetModulateColorWhite();
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
using System.Drawing;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
|
||||
namespace BizHawk.Bizware.BizwareGL
|
||||
{
|
||||
//note: the sense of these matrices, as well as pre- and post- multiplying may be all mixed up.
|
||||
//conceptually here is how we should be working, in the example of spinning a sprite in place
|
||||
//1. sprite starts with top left at origin
|
||||
//2. translate half size, to center sprite at origin
|
||||
//3. rotate around Z
|
||||
//4. translate to position in world
|
||||
//this class is designed to make that work, that way. the takeaways:
|
||||
//* Use the scale, translate, rotate methods in the order given above
|
||||
//* Use PostMultiplyMatrix to apply more work to a prior matrix (in the manner described above) since I am calling this all post-work
|
||||
// note: the sense of these matrices, as well as pre- and post- multiplying may be all mixed up.
|
||||
// conceptually here is how we should be working, in the example of spinning a sprite in place
|
||||
// 1. sprite starts with top left at origin
|
||||
// 2. translate half size, to center sprite at origin
|
||||
// 3. rotate around Z
|
||||
// 4. translate to position in world
|
||||
// this class is designed to make that work, that way. the takeaways:
|
||||
// * Use the scale, translate, rotate methods in the order given above
|
||||
// * Use PostMultiplyMatrix to apply more work to a prior matrix (in the manner described above) since I am calling this all post-work
|
||||
public class MatrixStack
|
||||
{
|
||||
private const float DEG_TO_RAD_FACTOR = (float) System.Math.PI / 180.0f;
|
||||
|
@ -24,19 +25,22 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
IsDirty = false;
|
||||
}
|
||||
|
||||
public static implicit operator Matrix4(MatrixStack ms) { return ms.Top; }
|
||||
public static implicit operator MatrixStack(Matrix4 m) { return new MatrixStack(m); }
|
||||
public static implicit operator Matrix4x4(MatrixStack ms) { return ms.Top; }
|
||||
public static implicit operator MatrixStack(Matrix4x4 m) { return new(m); }
|
||||
|
||||
public MatrixStack(Matrix4 matrix) { LoadMatrix(matrix); }
|
||||
public MatrixStack(Matrix4x4 matrix)
|
||||
{
|
||||
LoadMatrix(matrix);
|
||||
}
|
||||
|
||||
public bool IsDirty;
|
||||
|
||||
private readonly Stack<Matrix4> stack = new Stack<Matrix4>();
|
||||
private readonly Stack<Matrix4x4> stack = new();
|
||||
|
||||
/// <summary>
|
||||
/// This is made public for performance reasons, to avoid lame copies of the matrix when necessary. Don't mess it up!
|
||||
/// </summary>
|
||||
public Matrix4 Top;
|
||||
public Matrix4x4 Top;
|
||||
|
||||
/// <summary>
|
||||
/// Resets the matrix stack to an empty identity matrix stack
|
||||
|
@ -51,41 +55,143 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
/// <summary>
|
||||
/// Clears the matrix stack and loads the specified value
|
||||
/// </summary>
|
||||
public void Clear(Matrix4 value)
|
||||
public void Clear(Matrix4x4 value)
|
||||
{
|
||||
stack.Clear();
|
||||
Top = value;
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
public void LoadMatrix(Matrix4 value) { Top = value; IsDirty = true; }
|
||||
public void LoadMatrix(Matrix4x4 value)
|
||||
{
|
||||
Top = value;
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
public void LoadIdentity() { Top = Matrix4.Identity; IsDirty = true; }
|
||||
public void LoadIdentity()
|
||||
{
|
||||
Top = Matrix4x4.Identity;
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
public void Pop() { Top = stack.Pop(); IsDirty = true; }
|
||||
public void Push() { stack.Push(Top); IsDirty = true; }
|
||||
public void Pop()
|
||||
{
|
||||
Top = stack.Pop();
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
public void RotateAxis(Vector3 axisRotation, float angle) { PostMultiplyMatrix(Matrix4.CreateFromAxisAngle(in axisRotation, angle)); IsDirty = true; }
|
||||
public void Push()
|
||||
{
|
||||
stack.Push(Top);
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
public void Scale(Vector3 scale) { PostMultiplyMatrix(Matrix4.CreateScale(in scale)); IsDirty = true; }
|
||||
public void Scale(Vector2 scale) { PostMultiplyMatrix(Matrix4.CreateScale(scale.X, scale.Y, 1)); IsDirty = true; }
|
||||
public void Scale(float x, float y, float z) { PostMultiplyMatrix(Matrix4.CreateScale(x, y, z)); IsDirty = true; }
|
||||
public void Scale(float ratio) { Scale(ratio, ratio, ratio); IsDirty = true; }
|
||||
public void Scale(float x, float y) { Scale(x, y, 1); IsDirty = true; }
|
||||
public void RotateAxis(Vector3 axisRotation, float angle)
|
||||
{
|
||||
PostMultiplyMatrix(Matrix4x4.CreateFromAxisAngle(axisRotation, angle));
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
public void RotateAxis(float x, float y, float z, float degrees) { PostMultiplyMatrix(Matrix4.CreateFromAxisAngle(new Vector3(x, y, z), DegreesToRadians(degrees))); IsDirty = true; }
|
||||
public void RotateY(float degrees) { PostMultiplyMatrix(Matrix4.CreateRotationY(DegreesToRadians(degrees))); IsDirty = true; }
|
||||
public void RotateX(float degrees) { PostMultiplyMatrix(Matrix4.CreateRotationX(DegreesToRadians(degrees))); IsDirty = true; }
|
||||
public void RotateZ(float degrees) { PostMultiplyMatrix(Matrix4.CreateRotationZ(DegreesToRadians(degrees))); IsDirty = true; }
|
||||
public void Scale(Vector3 scale)
|
||||
{
|
||||
PostMultiplyMatrix(Matrix4x4.CreateScale(scale));
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
public void Translate(Vector2 v) { Translate(v.X, v.Y, 0); IsDirty = true; }
|
||||
public void Translate(Vector3 trans) { PostMultiplyMatrix(Matrix4.CreateTranslation(in trans)); IsDirty = true; }
|
||||
public void Translate(float x, float y, float z) { PostMultiplyMatrix(Matrix4.CreateTranslation(x, y, z)); IsDirty = true; }
|
||||
public void Translate(float x, float y) { Translate(x, y, 0); IsDirty = true; }
|
||||
public void Translate(Point pt) { Translate(pt.X, pt.Y, 0); IsDirty = true; }
|
||||
public void Scale(Vector2 scale)
|
||||
{
|
||||
PostMultiplyMatrix(Matrix4x4.CreateScale(scale.X, scale.Y, 1));
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
public void PostMultiplyMatrix(MatrixStack ms) { PostMultiplyMatrix(ms.Top); IsDirty = true; }
|
||||
public void PostMultiplyMatrix(Matrix4 value) { Top = Top * value; IsDirty = true; }
|
||||
public void PreMultiplyMatrix(Matrix4 value) { Top = value * Top; IsDirty = true; }
|
||||
public void Scale(float x, float y, float z)
|
||||
{
|
||||
PostMultiplyMatrix(Matrix4x4.CreateScale(x, y, z));
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
public void Scale(float ratio)
|
||||
{
|
||||
Scale(ratio, ratio, ratio);
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
public void Scale(float x, float y)
|
||||
{
|
||||
Scale(x, y, 1);
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
public void RotateAxis(float x, float y, float z, float degrees)
|
||||
{
|
||||
PostMultiplyMatrix(Matrix4x4.CreateFromAxisAngle(new(x, y, z), DegreesToRadians(degrees)));
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
public void RotateY(float degrees)
|
||||
{
|
||||
PostMultiplyMatrix(Matrix4x4.CreateRotationY(DegreesToRadians(degrees)));
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
public void RotateX(float degrees)
|
||||
{
|
||||
PostMultiplyMatrix(Matrix4x4.CreateRotationX(DegreesToRadians(degrees)));
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
public void RotateZ(float degrees)
|
||||
{
|
||||
PostMultiplyMatrix(Matrix4x4.CreateRotationZ(DegreesToRadians(degrees)));
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
public void Translate(Vector2 v)
|
||||
{
|
||||
Translate(v.X, v.Y, 0);
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
public void Translate(Vector3 trans)
|
||||
{
|
||||
PostMultiplyMatrix(Matrix4x4.CreateTranslation(trans));
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
public void Translate(float x, float y, float z)
|
||||
{
|
||||
PostMultiplyMatrix(Matrix4x4.CreateTranslation(x, y, z));
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
public void Translate(float x, float y)
|
||||
{
|
||||
Translate(x, y, 0);
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
public void Translate(Point pt)
|
||||
{
|
||||
Translate(pt.X, pt.Y, 0);
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
public void PostMultiplyMatrix(MatrixStack ms)
|
||||
{
|
||||
PostMultiplyMatrix(ms.Top);
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
public void PostMultiplyMatrix(Matrix4x4 value)
|
||||
{
|
||||
Top *= value;
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
public void PreMultiplyMatrix(Matrix4x4 value)
|
||||
{
|
||||
Top = value * Top;
|
||||
IsDirty = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,9 +10,9 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
/// </summary>
|
||||
public class Pipeline : IDisposable
|
||||
{
|
||||
public string Memo;
|
||||
public readonly string Memo;
|
||||
|
||||
public Pipeline(IGL owner, object opaque, bool available, VertexLayout vertexLayout, IEnumerable<UniformInfo> uniforms, string memo)
|
||||
public Pipeline(IGL owner, object opaque, bool available, VertexLayout vertexLayout, IReadOnlyList<UniformInfo> uniforms, string memo)
|
||||
{
|
||||
Memo = memo;
|
||||
Owner = owner;
|
||||
|
@ -24,10 +24,10 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
if(!Available)
|
||||
return;
|
||||
|
||||
UniformsDictionary = new SpecialWorkingDictionary(this);
|
||||
UniformsDictionary = new(this);
|
||||
foreach (var ui in uniforms)
|
||||
{
|
||||
UniformsDictionary[ui.Name] = new PipelineUniform(this);
|
||||
UniformsDictionary[ui.Name] = new(this);
|
||||
}
|
||||
|
||||
foreach (var ui in uniforms)
|
||||
|
@ -40,9 +40,9 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
/// Allows us to create PipelineUniforms on the fly, in case a non-existing one has been requested.
|
||||
/// Shader compilers will optimize out unused uniforms, and we wont have a record of it in the uniforms population loop
|
||||
/// </summary>
|
||||
private class SpecialWorkingDictionary : Dictionary<string, PipelineUniform>
|
||||
private class UniformWorkingDictionary : Dictionary<string, PipelineUniform>
|
||||
{
|
||||
public SpecialWorkingDictionary(Pipeline owner)
|
||||
public UniformWorkingDictionary(Pipeline owner)
|
||||
{
|
||||
Owner = owner;
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
}
|
||||
}
|
||||
|
||||
private readonly SpecialWorkingDictionary UniformsDictionary;
|
||||
private readonly UniformWorkingDictionary UniformsDictionary;
|
||||
private IDictionary<string, PipelineUniform> Uniforms => UniformsDictionary;
|
||||
|
||||
public IEnumerable<PipelineUniform> GetUniforms() => Uniforms.Values;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
|
||||
namespace BizHawk.Bizware.BizwareGL
|
||||
{
|
||||
|
@ -12,17 +13,16 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
internal PipelineUniform(Pipeline owner)
|
||||
{
|
||||
Owner = owner;
|
||||
//Opaque = info.Opaque;
|
||||
//SamplerIndex = info.SamplerIndex;
|
||||
}
|
||||
|
||||
internal void AddUniformInfo(UniformInfo ui)
|
||||
{
|
||||
_UniformInfos.Add(ui);
|
||||
_uniformInfos.Add(ui);
|
||||
}
|
||||
|
||||
public IEnumerable<UniformInfo> UniformInfos => _UniformInfos;
|
||||
private readonly List<UniformInfo> _UniformInfos = new List<UniformInfo>();
|
||||
public IEnumerable<UniformInfo> UniformInfos => _uniformInfos;
|
||||
|
||||
private readonly List<UniformInfo> _uniformInfos = new();
|
||||
|
||||
/// <returns>the first and only <see cref="UniformInfo"/></returns>
|
||||
/// <exception cref="InvalidOperationException">more than one <see cref="UniformInfo"/> exists</exception>
|
||||
|
@ -30,14 +30,18 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
{
|
||||
get
|
||||
{
|
||||
if (_UniformInfos.Count != 1) throw new InvalidOperationException();
|
||||
return _UniformInfos[0];
|
||||
if (_uniformInfos.Count != 1)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
return _uniformInfos[0];
|
||||
}
|
||||
}
|
||||
|
||||
public Pipeline Owner { get; }
|
||||
|
||||
public void Set(Matrix4 mat, bool transpose = false)
|
||||
public void Set(Matrix4x4 mat, bool transpose = false)
|
||||
{
|
||||
Owner?.Owner.SetPipelineUniformMatrix(this, mat, transpose);
|
||||
}
|
||||
|
@ -62,7 +66,7 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
Owner?.Owner.SetPipelineUniform(this, vecs);
|
||||
}
|
||||
|
||||
public void Set(ref Matrix4 mat, bool transpose = false)
|
||||
public void Set(ref Matrix4x4 mat, bool transpose = false)
|
||||
{
|
||||
Owner?.Owner.SetPipelineUniformMatrix(this, ref mat, transpose);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
#if false
|
||||
using System.Drawing.Drawing2D;
|
||||
#endif
|
||||
|
||||
namespace BizHawk.Bizware.BizwareGL
|
||||
{
|
||||
public class RenderTargetWrapper
|
||||
public class RenderTargetWrapper : IDisposable
|
||||
{
|
||||
public RenderTargetWrapper(
|
||||
Func<BufferedGraphicsContext> getBufferedGraphicsContext,
|
||||
|
@ -15,6 +18,7 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
MyBufferedGraphics?.Dispose();
|
||||
}
|
||||
|
||||
private readonly Func<BufferedGraphicsContext> _getBufferedGraphicsContext;
|
||||
|
@ -31,7 +35,7 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
|
||||
public BufferedGraphics MyBufferedGraphics;
|
||||
|
||||
public Graphics refGraphics; //?? hacky?
|
||||
public Graphics refGraphics; // ?? hacky?
|
||||
|
||||
public void CreateGraphics()
|
||||
{
|
||||
|
@ -43,19 +47,21 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
}
|
||||
else
|
||||
{
|
||||
var tw = Target.Texture2d.Opaque as GDIPTextureWrapper;
|
||||
var tw = (GDIPTextureWrapper)Target.Texture2d.Opaque;
|
||||
r = Target.Texture2d.Rectangle;
|
||||
refGraphics = Graphics.FromImage(tw.SDBitmap);
|
||||
}
|
||||
|
||||
MyBufferedGraphics?.Dispose();
|
||||
MyBufferedGraphics = _getBufferedGraphicsContext().Allocate(refGraphics, r);
|
||||
// MyBufferedGraphics.Graphics.PixelOffsetMode = PixelOffsetMode.HighSpeed;
|
||||
#if false
|
||||
MyBufferedGraphics.Graphics.PixelOffsetMode = PixelOffsetMode.HighSpeed;
|
||||
|
||||
//not sure about this stuff...
|
||||
//it will wreck alpha blending, for one thing
|
||||
// MyBufferedGraphics.Graphics.CompositingMode = CompositingMode.SourceCopy;
|
||||
// MyBufferedGraphics.Graphics.CompositingQuality = CompositingQuality.HighSpeed;
|
||||
// not sure about this stuff...
|
||||
// it will wreck alpha blending, for one thing
|
||||
MyBufferedGraphics.Graphics.CompositingMode = CompositingMode.SourceCopy;
|
||||
MyBufferedGraphics.Graphics.CompositingQuality = CompositingQuality.HighSpeed;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.Numerics;
|
||||
|
||||
namespace BizHawk.Bizware.BizwareGL
|
||||
{
|
||||
|
@ -20,9 +21,8 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
VertexLayout.DefineVertexAttribute("tex", 2, 2, VertexAttribPointerType.Float, AttribUsage.Texcoord0, false, 40, 32);
|
||||
VertexLayout.Close();
|
||||
|
||||
string defines = "";
|
||||
string vsSource = $"#define VERTEX\r\n{defines}{source}";
|
||||
string psSource = $"#define FRAGMENT\r\n{defines}{source}";
|
||||
var vsSource = $"#define VERTEX\r\n{source}";
|
||||
var psSource = $"#define FRAGMENT\r\n{source}";
|
||||
var vs = owner.CreateVertexShader(vsSource, "main_vertex", debug);
|
||||
var ps = owner.CreateFragmentShader(psSource, "main_fragment", debug);
|
||||
Pipeline = Owner.CreatePipeline(VertexLayout, vs, ps, debug, "retro");
|
||||
|
@ -39,7 +39,7 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
sampler0 = Pipeline.TryGetUniform("s_p");
|
||||
if (sampler0 == null)
|
||||
{
|
||||
//sampler wasn't named correctly. this can happen on some retroarch shaders
|
||||
// sampler wasn't named correctly. this can happen on some retroarch shaders
|
||||
foreach (var u in Pipeline.GetUniforms())
|
||||
{
|
||||
if (u.Sole.IsSampler && u.Sole.SamplerIndex == 0)
|
||||
|
@ -50,11 +50,8 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
}
|
||||
}
|
||||
|
||||
//if a sampler isn't available, we can't do much, although this does interfere with debugging (shaders just returning colors will malfunction)
|
||||
if (sampler0 == null)
|
||||
return;
|
||||
|
||||
Available = true;
|
||||
// if a sampler isn't available, we can't do much, although this does interfere with debugging (shaders just returning colors will malfunction)
|
||||
Available = sampler0 != null;
|
||||
}
|
||||
|
||||
public bool Available { get; }
|
||||
|
@ -69,16 +66,13 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
|
||||
public void Bind()
|
||||
{
|
||||
//lame...
|
||||
// lame...
|
||||
Owner.BindPipeline(Pipeline);
|
||||
}
|
||||
|
||||
public unsafe void Run(Texture2d tex, Size InputSize, Size OutputSize, bool flip)
|
||||
{
|
||||
flip = false;
|
||||
//test
|
||||
|
||||
//ack! make sure to set the pipeline before setting uniforms
|
||||
// ack! make sure to set the pipeline before setting uniforms
|
||||
Bind();
|
||||
|
||||
Pipeline["IN.video_size"].Set(new Vector2(InputSize.Width, InputSize.Height));
|
||||
|
@ -87,10 +81,9 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
Pipeline["IN.frame_count"].Set(1); //todo
|
||||
Pipeline["IN.frame_direction"].Set(1); //todo
|
||||
|
||||
|
||||
var Projection = Owner.CreateGuiProjectionMatrix(OutputSize);
|
||||
var Modelview = Owner.CreateGuiViewMatrix(OutputSize);
|
||||
var mat = Matrix4.Transpose(Modelview * Projection);
|
||||
var mat = Matrix4x4.Transpose(Modelview * Projection);
|
||||
Pipeline["modelViewProj"].Set(mat, true);
|
||||
|
||||
Owner.SetTextureWrapMode(tex, true);
|
||||
|
@ -98,16 +91,26 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
sampler0.Set(tex);
|
||||
Owner.SetViewport(OutputSize);
|
||||
|
||||
float time = DateTime.Now.Second + (float)DateTime.Now.Millisecond / 1000;
|
||||
var time = DateTime.Now.Second + (float)DateTime.Now.Millisecond / 1000;
|
||||
Pipeline["Time"].Set(time);
|
||||
|
||||
int w = OutputSize.Width;
|
||||
int h = OutputSize.Height;
|
||||
float v0,v1;
|
||||
if (flip) { v0 = 1; v1 = 0; }
|
||||
else { v0 = 0; v1 = 1; }
|
||||
float* pData = stackalloc float[10*4];
|
||||
int i=0;
|
||||
var w = OutputSize.Width;
|
||||
var h = OutputSize.Height;
|
||||
|
||||
float v0, v1;
|
||||
if (flip)
|
||||
{
|
||||
v0 = 1;
|
||||
v1 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
v0 = 0;
|
||||
v1 = 1;
|
||||
}
|
||||
|
||||
var pData = stackalloc float[10 * 4];
|
||||
var i = 0;
|
||||
pData[i++] = 0; pData[i++] = 0; pData[i++] = 0; pData[i++] = 1; //topleft vert
|
||||
pData[i++] = 0; pData[i++] = 0; pData[i++] = 0; pData[i++] = 0; //useless color
|
||||
pData[i++] = 0; pData[i++] = v0;
|
||||
|
@ -119,7 +122,7 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
pData[i++] = 0; pData[i++] = v1;
|
||||
pData[i++] = w; pData[i++] = h; pData[i++] = 0; pData[i++] = 1; //bottomright vert
|
||||
pData[i++] = 0; pData[i++] = 0; pData[i++] = 0; pData[i++] = 0; //useless color
|
||||
pData[i++] = 1; pData[i++] = v1;
|
||||
pData[i++] = 1; pData[i] = v1;
|
||||
|
||||
Owner.SetBlendState(Owner.BlendNoneCopy);
|
||||
Owner.BindArrayData(new(pData));
|
||||
|
@ -130,6 +133,6 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
public IGL Owner { get; }
|
||||
|
||||
private readonly VertexLayout VertexLayout;
|
||||
public Pipeline Pipeline;
|
||||
public readonly Pipeline Pipeline;
|
||||
}
|
||||
}
|
|
@ -3,9 +3,10 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
|
||||
using Cyotek.Drawing.BitmapFont;
|
||||
using sd=System.Drawing;
|
||||
|
||||
namespace BizHawk.Bizware.BizwareGL
|
||||
{
|
||||
|
@ -18,7 +19,7 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
FontInfo.LoadXml(xml);
|
||||
|
||||
// load textures
|
||||
for(int i=0;i<FontInfo.Pages.Length;i++)
|
||||
for (var i=0; i<FontInfo.Pages.Length; i++)
|
||||
{
|
||||
TexturePages.Add(owner.LoadTexture(textures[i]));
|
||||
}
|
||||
|
@ -27,25 +28,30 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
public void Dispose()
|
||||
{
|
||||
foreach (var tex in TexturePages)
|
||||
{
|
||||
tex.Dispose();
|
||||
}
|
||||
|
||||
TexturePages = null;
|
||||
}
|
||||
|
||||
public sd.SizeF Measure(string str)
|
||||
public SizeF Measure(string str)
|
||||
{
|
||||
float x = 0;
|
||||
float y = FontInfo.LineHeight;
|
||||
float ox = x;
|
||||
int len = str.Length;
|
||||
var ox = x;
|
||||
var len = str.Length;
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
for (var i = 0; i < len; i++)
|
||||
{
|
||||
var c = str[i];
|
||||
|
||||
if (c == '\r')
|
||||
{
|
||||
if (i != len - 1 && str[i + 1] == '\n')
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (c == '\r')
|
||||
|
@ -56,33 +62,42 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
if (c == '\n')
|
||||
{
|
||||
if (x > ox)
|
||||
{
|
||||
ox = x;
|
||||
}
|
||||
|
||||
x = 0;
|
||||
y += FontInfo.LineHeight;
|
||||
continue;
|
||||
}
|
||||
|
||||
var bfc = FontInfo[c];
|
||||
|
||||
x += bfc.XAdvance;
|
||||
}
|
||||
|
||||
return new sd.SizeF(Math.Max(x, ox), y);
|
||||
return new(Math.Max(x, ox), y);
|
||||
}
|
||||
|
||||
public void RenderString(IGuiRenderer renderer, float x, float y, string str)
|
||||
{
|
||||
float ox = x;
|
||||
int len = str.Length;
|
||||
if (Owner != renderer.Owner)
|
||||
{
|
||||
throw new InvalidOperationException("Owner mismatch!");
|
||||
}
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
var ox = x;
|
||||
var len = str.Length;
|
||||
|
||||
for (var i = 0; i < len; i++)
|
||||
{
|
||||
var c = str[i];
|
||||
|
||||
if (c == '\r')
|
||||
{
|
||||
if (i != len - 1 && str[i + 1] == '\n')
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (c == '\r')
|
||||
|
@ -90,7 +105,7 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
c = '\n';
|
||||
}
|
||||
|
||||
if(c == '\n')
|
||||
if (c == '\n')
|
||||
{
|
||||
x = ox;
|
||||
y += FontInfo.LineHeight;
|
||||
|
@ -98,19 +113,19 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
}
|
||||
|
||||
var bfc = FontInfo[c];
|
||||
|
||||
// calculate texcoords (we shouldve already had this cached, but im speedcoding now)
|
||||
Texture2d tex = TexturePages[bfc.TexturePage];
|
||||
float w = tex.Width;
|
||||
float h = tex.Height;
|
||||
sd.Rectangle bounds = new(bfc.X, bfc.Y, bfc.Width, bfc.Height);
|
||||
float u0 = bounds.Left / w;
|
||||
float v0 = bounds.Top / h;
|
||||
float u1 = bounds.Right / w;
|
||||
float v1 = bounds.Bottom / h;
|
||||
|
||||
float gx = x + bfc.XOffset;
|
||||
float gy = y + bfc.YOffset;
|
||||
// calculate texcoords (we shouldve already had this cached, but im speedcoding now)
|
||||
var tex = TexturePages[bfc.TexturePage];
|
||||
var w = tex.Width;
|
||||
var h = tex.Height;
|
||||
var bounds = new Rectangle(bfc.X, bfc.Y, bfc.Width, bfc.Height);
|
||||
var u0 = bounds.Left / w;
|
||||
var v0 = bounds.Top / h;
|
||||
var u1 = bounds.Right / w;
|
||||
var v1 = bounds.Bottom / h;
|
||||
|
||||
var gx = x + bfc.XOffset;
|
||||
var gy = y + bfc.YOffset;
|
||||
renderer.DrawSubrect(tex, gx, gy, bfc.Width, bfc.Height, u0, v0, u1, v1);
|
||||
|
||||
x += bfc.XAdvance;
|
||||
|
@ -120,6 +135,6 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
public IGL Owner { get; }
|
||||
|
||||
private readonly BitmapFont FontInfo;
|
||||
private List<Texture2d> TexturePages = new List<Texture2d>();
|
||||
private List<Texture2d> TexturePages = new();
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
Height = height;
|
||||
Item = item;
|
||||
}
|
||||
|
||||
public int X, Y;
|
||||
public int Width, Height;
|
||||
public int TexIndex;
|
||||
|
@ -31,14 +32,14 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
public readonly List<RectangleBinPack.Node> nodes = new List<RectangleBinPack.Node>();
|
||||
}
|
||||
|
||||
public static int MaxSizeBits = 16;
|
||||
public const int MaxSizeBits = 16;
|
||||
|
||||
/// <summary>
|
||||
/// packs the supplied RectItems into an atlas. Modifies the RectItems with x/y values of location in new atlas.
|
||||
/// </summary>
|
||||
public static IReadOnlyList<(Size Size, List<RectItem> Items)> PackAtlas(IReadOnlyCollection<RectItem> items)
|
||||
public static IReadOnlyList<(Size Size, List<RectItem> Items)> PackAtlas(IEnumerable<RectItem> items)
|
||||
{
|
||||
static void AddAtlas(ICollection<(Size, List<RectItem>)> atlases, IReadOnlyCollection<RectItem> initItems)
|
||||
static void AddAtlas(ICollection<(Size, List<RectItem>)> atlases, IEnumerable<RectItem> initItems)
|
||||
{
|
||||
List<RectItem> currentItems = new(initItems);
|
||||
List<RectItem> remainItems = new();
|
||||
|
@ -50,13 +51,13 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
// we run this every time we make an atlas, in case we want to variably control the maximum texture output size.
|
||||
// ALSO - we accumulate data in there, so we need to refresh it each time. ... lame.
|
||||
var todoSizes = new List<TryFitParam>();
|
||||
for (int i = 3; i <= MaxSizeBits; i++)
|
||||
for (var i = 3; i <= MaxSizeBits; i++)
|
||||
{
|
||||
for (int j = 3; j <= MaxSizeBits; j++)
|
||||
for (var j = 3; j <= MaxSizeBits; j++)
|
||||
{
|
||||
int w = 1 << i;
|
||||
int h = 1 << j;
|
||||
TryFitParam tfp = new TryFitParam(w, h);
|
||||
var w = 1 << i;
|
||||
var h = 1 << j;
|
||||
var tfp = new TryFitParam(w, h);
|
||||
todoSizes.Add(tfp);
|
||||
}
|
||||
}
|
||||
|
@ -68,9 +69,10 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
rbp.Init(16384, 16384);
|
||||
param.rbp.Init(param.w, param.h);
|
||||
|
||||
// ReSharper disable once AccessToModifiedClosure
|
||||
foreach (var ri in currentItems)
|
||||
{
|
||||
RectangleBinPack.Node node = param.rbp.Insert(ri.Width, ri.Height);
|
||||
var node = param.rbp.Insert(ri.Width, ri.Height);
|
||||
if (node == null)
|
||||
{
|
||||
param.ok = false;
|
||||
|
@ -83,35 +85,50 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
}
|
||||
});
|
||||
|
||||
//find the best fit among the potential sizes that worked
|
||||
// find the best fit among the potential sizes that worked
|
||||
var best = long.MaxValue;
|
||||
tfpFinal = todoSizes[0];
|
||||
foreach (var tfp in todoSizes)
|
||||
{
|
||||
if (!tfp.ok) continue;
|
||||
if (!tfp.ok)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var area = tfp.w * (long) tfp.h;
|
||||
if (area > best) continue; // larger than best, not interested
|
||||
if (area > best)
|
||||
{
|
||||
continue; // larger than best, not interested
|
||||
}
|
||||
|
||||
if (area == best) // same area, compare perimeter as tie-breaker (to create squares, which are nicer to look at)
|
||||
{
|
||||
if (tfp.w + tfp.h >= tfpFinal.w + tfpFinal.h) continue;
|
||||
if (tfp.w + tfp.h >= tfpFinal.w + tfpFinal.h)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
best = area;
|
||||
tfpFinal = tfp;
|
||||
}
|
||||
|
||||
//did we find any fit?
|
||||
if (best < long.MaxValue) break;
|
||||
if (best < long.MaxValue)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
//nope - move an item to the remaining list and try again
|
||||
remainItems.Add(currentItems[currentItems.Count - 1]);
|
||||
currentItems.RemoveAt(currentItems.Count - 1);
|
||||
}
|
||||
|
||||
//we found a fit. setup this atlas in the result and drop the items into it
|
||||
atlases.Add((new Size(tfpFinal.w, tfpFinal.h), new List<RectItem>(currentItems)));
|
||||
atlases.Add((new(tfpFinal.w, tfpFinal.h), new(currentItems)));
|
||||
foreach (var item in currentItems)
|
||||
{
|
||||
object o = item.Item;
|
||||
var node = tfpFinal.nodes.Find((x) => x.ri == item);
|
||||
var node = tfpFinal.nodes.Find(x => x.ri == item);
|
||||
item.X = node.x;
|
||||
item.Y = node.y;
|
||||
item.TexIndex = atlases.Count - 1;
|
||||
|
@ -157,7 +174,7 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
{
|
||||
binWidth = width;
|
||||
binHeight = height;
|
||||
root = new Node();
|
||||
root = new();
|
||||
root.left = root.right = null;
|
||||
root.x = root.y = 0;
|
||||
root.width = width;
|
||||
|
@ -176,8 +193,8 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
/// <summary>Computes the ratio of used surface area.</summary>
|
||||
private float Occupancy()
|
||||
{
|
||||
int totalSurfaceArea = binWidth * binHeight;
|
||||
int usedSurfaceArea = UsedSurfaceArea(root);
|
||||
var totalSurfaceArea = binWidth * binHeight;
|
||||
var usedSurfaceArea = UsedSurfaceArea(root);
|
||||
|
||||
return (float)usedSurfaceArea / totalSurfaceArea;
|
||||
}
|
||||
|
@ -189,11 +206,11 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
private int binHeight;
|
||||
|
||||
/// <returns>The surface area used by the subtree rooted at node.</returns>
|
||||
private int UsedSurfaceArea(Node node)
|
||||
private static int UsedSurfaceArea(Node node)
|
||||
{
|
||||
if (node.left != null || node.right != null)
|
||||
{
|
||||
int usedSurfaceArea = node.width * node.height;
|
||||
var usedSurfaceArea = node.width * node.height;
|
||||
if (node.left != null)
|
||||
usedSurfaceArea += UsedSurfaceArea(node.left);
|
||||
if (node.right != null)
|
||||
|
@ -208,7 +225,7 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
|
||||
|
||||
/// <summary>Inserts a new rectangle in the subtree rooted at the given node.</summary>
|
||||
private Node Insert(Node node, int width, int height)
|
||||
private static Node Insert(Node node, int width, int height)
|
||||
{
|
||||
|
||||
// If this node is an internal node, try both leaves for possible space.
|
||||
|
@ -217,13 +234,13 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
{
|
||||
if (node.left != null)
|
||||
{
|
||||
Node newNode = Insert(node.left, width, height);
|
||||
var newNode = Insert(node.left, width, height);
|
||||
if (newNode != null)
|
||||
return newNode;
|
||||
}
|
||||
if (node.right != null)
|
||||
{
|
||||
Node newNode = Insert(node.right, width, height);
|
||||
var newNode = Insert(node.right, width, height);
|
||||
if (newNode != null)
|
||||
return newNode;
|
||||
}
|
||||
|
@ -236,10 +253,10 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
|
||||
// The new cell will fit, split the remaining space along the shorter axis,
|
||||
// that is probably more optimal.
|
||||
int w = node.width - width;
|
||||
int h = node.height - height;
|
||||
node.left = new Node();
|
||||
node.right = new Node();
|
||||
var w = node.width - width;
|
||||
var h = node.height - height;
|
||||
node.left = new();
|
||||
node.right = new();
|
||||
if (w <= h) // Split the remaining space in horizontal direction.
|
||||
{
|
||||
node.left.x = node.x + width;
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
{
|
||||
Owner = owner;
|
||||
Opaque = opaque;
|
||||
Items = new MyDictionary();
|
||||
Items = new();
|
||||
}
|
||||
|
||||
public object Opaque { get; }
|
||||
|
@ -29,8 +29,10 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
RefCount--;
|
||||
if (RefCount <= 0)
|
||||
{
|
||||
//nothing like this yet
|
||||
//Available = false;
|
||||
// nothing like this yet
|
||||
#if false
|
||||
Available = false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,8 +45,11 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
public void DefineVertexAttribute(string name, int index, int components, VertexAttribPointerType attribType, AttribUsage usage, bool normalized, int stride, int offset = 0)
|
||||
{
|
||||
if (Closed)
|
||||
{
|
||||
throw new InvalidOperationException("Type is Closed and is now immutable.");
|
||||
Items[index] = new LayoutItem { Name = name, Components = components, AttribType = attribType, Usage = usage, Normalized = normalized, Stride = stride, Offset = offset };
|
||||
}
|
||||
|
||||
Items[index] = new() { Name = name, Components = components, AttribType = attribType, Usage = usage, Normalized = normalized, Stride = stride, Offset = offset };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -66,7 +71,7 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
public AttribUsage Usage { get; internal set; }
|
||||
}
|
||||
|
||||
public class MyDictionary : WorkingDictionary<int, LayoutItem>
|
||||
public class LayoutItemWorkingDictionary : WorkingDictionary<int, LayoutItem>
|
||||
{
|
||||
public new LayoutItem this[int key]
|
||||
{
|
||||
|
@ -75,8 +80,8 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
}
|
||||
}
|
||||
|
||||
public MyDictionary Items { get; }
|
||||
private bool Closed = false;
|
||||
public LayoutItemWorkingDictionary Items { get; }
|
||||
private bool Closed;
|
||||
|
||||
}
|
||||
}
|
|
@ -1,323 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace BizHawk.Bizware.BizwareGL
|
||||
{
|
||||
public struct Matrix4
|
||||
{
|
||||
public static readonly Matrix4 Identity = new(new(1.0f, 0.0f, 0.0f, 0.0f), new(0.0f, 1.0f, 0.0f, 0.0f), new(0.0f, 0.0f, 1.0f, 0.0f), new(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
|
||||
public static bool AreEqual(in Matrix4 a, in Matrix4 b) => Vector4.AreEqual(in a.Row0, in b.Row0) && Vector4.AreEqual(in a.Row1, in b.Row1) && Vector4.AreEqual(in a.Row2, in b.Row2) && Vector4.AreEqual(in a.Row3, in b.Row3);
|
||||
|
||||
/// <returns>a <see cref="Matrix4"/> representing a rotation of <paramref name="angle"/> radians CCW around the given <paramref name="axis"/></returns>
|
||||
public static Matrix4 CreateFromAxisAngle(in Vector3 axis, float angle)
|
||||
{
|
||||
var num0 = (float) (1.0 / Math.Sqrt(axis.X * (double) axis.X + axis.Y * (double) axis.Y + axis.Z * (double) axis.Z));
|
||||
var x = axis.X * num0;
|
||||
var y = axis.Y * num0;
|
||||
var z = axis.Z * num0;
|
||||
var num1 = (float) Math.Cos(-(double) angle);
|
||||
var num2 = (float) Math.Sin(-(double) angle);
|
||||
var num3 = 1.0f - num1;
|
||||
var num4 = num3 * x * x;
|
||||
var num5 = num3 * x * y;
|
||||
var num6 = num3 * x * z;
|
||||
var num7 = num3 * y * y;
|
||||
var num8 = num3 * y * z;
|
||||
var num9 = num3 * z * z;
|
||||
var num10 = num2 * x;
|
||||
var num11 = num2 * y;
|
||||
var num12 = num2 * z;
|
||||
return new(
|
||||
new(num4 + num1, num5 - num12, num6 + num11, 0.0f),
|
||||
new(num5 + num12, num7 + num1, num8 - num10, 0.0f),
|
||||
new(num6 - num11, num8 + num10, num9 + num1, 0.0f),
|
||||
new(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
}
|
||||
|
||||
/// <returns>a <see cref="Matrix4"/> representing a rotation of <paramref name="angle"/> radians CCW around the X-axis</returns>
|
||||
public static Matrix4 CreateRotationX(float angle)
|
||||
{
|
||||
var num1 = (float) Math.Cos(angle);
|
||||
var num2 = (float) Math.Sin(angle);
|
||||
var result = Identity; // copy
|
||||
result.Row1.Y = num1;
|
||||
result.Row1.Z = num2;
|
||||
result.Row2.Y = -num2;
|
||||
result.Row2.Z = num1;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <returns>a <see cref="Matrix4"/> representing a rotation of <paramref name="angle"/> radians CCW around the Y-axis</returns>
|
||||
public static Matrix4 CreateRotationY(float angle)
|
||||
{
|
||||
var num1 = (float) Math.Cos(angle);
|
||||
var num2 = (float) Math.Sin(angle);
|
||||
var result = Identity; // copy
|
||||
result.Row0.X = num1;
|
||||
result.Row0.Z = -num2;
|
||||
result.Row2.X = num2;
|
||||
result.Row2.Z = num1;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <returns>a <see cref="Matrix4"/> representing a rotation of <paramref name="angle"/> radians CCW around the Z-axis</returns>
|
||||
public static Matrix4 CreateRotationZ(float angle)
|
||||
{
|
||||
var num1 = (float) Math.Cos(angle);
|
||||
var num2 = (float) Math.Sin(angle);
|
||||
var result = Identity; // copy
|
||||
result.Row0.X = num1;
|
||||
result.Row0.Y = num2;
|
||||
result.Row1.X = -num2;
|
||||
result.Row1.Y = num1;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <returns>a <see cref="Matrix4"/> representing a scaling</returns>
|
||||
public static Matrix4 CreateScale(float x, float y, float z)
|
||||
{
|
||||
var result = Identity; // copy
|
||||
result.Row0.X = x;
|
||||
result.Row1.Y = y;
|
||||
result.Row2.Z = z;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <returns>a <see cref="Matrix4"/> representing a scaling</returns>
|
||||
public static Matrix4 CreateScale(in Vector3 scale)
|
||||
{
|
||||
var result = Identity; // copy
|
||||
result.Row0.X = scale.X;
|
||||
result.Row1.Y = scale.Y;
|
||||
result.Row2.Z = scale.Z;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <returns>a <see cref="Matrix4"/> representing a translation</returns>
|
||||
public static Matrix4 CreateTranslation(float x, float y, float z)
|
||||
{
|
||||
var result = Identity; // copy
|
||||
result.Row3.X = x;
|
||||
result.Row3.Y = y;
|
||||
result.Row3.Z = z;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <returns>a <see cref="Matrix4"/> representing a translation</returns>
|
||||
public static Matrix4 CreateTranslation(in Vector3 vector)
|
||||
{
|
||||
var result = Identity; // copy
|
||||
result.Row3.X = vector.X;
|
||||
result.Row3.Y = vector.Y;
|
||||
result.Row3.Z = vector.Z;
|
||||
return result;
|
||||
}
|
||||
|
||||
private static float GetDeterminant(in Matrix4 m)
|
||||
{
|
||||
var x1 = (double) m.Row0.X;
|
||||
var y1 = (double) m.Row0.Y;
|
||||
var z1 = (double) m.Row0.Z;
|
||||
var w1 = (double) m.Row0.W;
|
||||
var x2 = (double) m.Row1.X;
|
||||
var y2 = (double) m.Row1.Y;
|
||||
var z2 = (double) m.Row1.Z;
|
||||
var w2 = (double) m.Row1.W;
|
||||
var x3 = (double) m.Row2.X;
|
||||
var y3 = (double) m.Row2.Y;
|
||||
var z3 = (double) m.Row2.Z;
|
||||
var w3 = (double) m.Row2.W;
|
||||
var x4 = (double) m.Row3.X;
|
||||
var y4 = (double) m.Row3.Y;
|
||||
var z4 = (double) m.Row3.Z;
|
||||
var w4 = (double) m.Row3.W;
|
||||
return (float) (x1 * y2 * z3 * w4
|
||||
- x1 * y2 * w3 * z4
|
||||
+ x1 * z2 * w3 * y4
|
||||
- x1 * z2 * y3 * w4
|
||||
+ x1 * w2 * y3 * z4
|
||||
- x1 * w2 * z3 * y4
|
||||
- y1 * z2 * w3 * x4
|
||||
+ y1 * z2 * x3 * w4
|
||||
- y1 * w2 * x3 * z4
|
||||
+ y1 * w2 * z3 * x4
|
||||
- y1 * x2 * z3 * w4
|
||||
+ y1 * x2 * w3 * z4
|
||||
+ z1 * w2 * x3 * y4
|
||||
- z1 * w2 * y3 * x4
|
||||
+ z1 * x2 * y3 * w4
|
||||
- z1 * x2 * w3 * y4
|
||||
+ z1 * y2 * w3 * x4
|
||||
- z1 * y2 * x3 * w4
|
||||
- w1 * x2 * y3 * z4
|
||||
+ w1 * x2 * z3 * y4
|
||||
- w1 * y2 * z3 * x4
|
||||
+ w1 * y2 * x3 * z4
|
||||
- w1 * z2 * x3 * y4
|
||||
+ w1 * z2 * y3 * x4);
|
||||
}
|
||||
|
||||
private static unsafe Matrix4 Invert(in Matrix4 mat)
|
||||
{
|
||||
var pDbTemp = stackalloc double[16];
|
||||
fixed (Matrix4* pMatIn = &mat)
|
||||
{
|
||||
var pFlIn = (float*) pMatIn;
|
||||
for (var i = 0; i < 16; i++) pDbTemp[i] = pFlIn[i];
|
||||
}
|
||||
Matrix4 result = default;
|
||||
ref var refResult = ref result;
|
||||
fixed (Matrix4* pMatOut = &refResult)
|
||||
{
|
||||
var pFlOut = (float*) pMatOut;
|
||||
pFlOut[0] = (float) (pDbTemp[5] * pDbTemp[10] * pDbTemp[15] - pDbTemp[5] * pDbTemp[11] * pDbTemp[14] - pDbTemp[9] * pDbTemp[6] * pDbTemp[15] + pDbTemp[9] * pDbTemp[7] * pDbTemp[14] + pDbTemp[13] * pDbTemp[6] * pDbTemp[11] - pDbTemp[13] * pDbTemp[7] * pDbTemp[10]);
|
||||
pFlOut[4] = (float) (-pDbTemp[4] * pDbTemp[10] * pDbTemp[15] + pDbTemp[4] * pDbTemp[11] * pDbTemp[14] + pDbTemp[8] * pDbTemp[6] * pDbTemp[15] - pDbTemp[8] * pDbTemp[7] * pDbTemp[14] - pDbTemp[12] * pDbTemp[6] * pDbTemp[11] + pDbTemp[12] * pDbTemp[7] * pDbTemp[10]);
|
||||
pFlOut[8] = (float) (pDbTemp[4] * pDbTemp[9] * pDbTemp[15] - pDbTemp[4] * pDbTemp[11] * pDbTemp[13] - pDbTemp[8] * pDbTemp[5] * pDbTemp[15] + pDbTemp[8] * pDbTemp[7] * pDbTemp[13] + pDbTemp[12] * pDbTemp[5] * pDbTemp[11] - pDbTemp[12] * pDbTemp[7] * pDbTemp[9]);
|
||||
pFlOut[12] = (float) (-pDbTemp[4] * pDbTemp[9] * pDbTemp[14] + pDbTemp[4] * pDbTemp[10] * pDbTemp[13] + pDbTemp[8] * pDbTemp[5] * pDbTemp[14] - pDbTemp[8] * pDbTemp[6] * pDbTemp[13] - pDbTemp[12] * pDbTemp[5] * pDbTemp[10] + pDbTemp[12] * pDbTemp[6] * pDbTemp[9]);
|
||||
pFlOut[1] = (float) (-pDbTemp[1] * pDbTemp[10] * pDbTemp[15] + pDbTemp[1] * pDbTemp[11] * pDbTemp[14] + pDbTemp[9] * pDbTemp[2] * pDbTemp[15] - pDbTemp[9] * pDbTemp[3] * pDbTemp[14] - pDbTemp[13] * pDbTemp[2] * pDbTemp[11] + pDbTemp[13] * pDbTemp[3] * pDbTemp[10]);
|
||||
pFlOut[5] = (float) (pDbTemp[0] * pDbTemp[10] * pDbTemp[15] - pDbTemp[0] * pDbTemp[11] * pDbTemp[14] - pDbTemp[8] * pDbTemp[2] * pDbTemp[15] + pDbTemp[8] * pDbTemp[3] * pDbTemp[14] + pDbTemp[12] * pDbTemp[2] * pDbTemp[11] - pDbTemp[12] * pDbTemp[3] * pDbTemp[10]);
|
||||
pFlOut[9] = (float) (-pDbTemp[0] * pDbTemp[9] * pDbTemp[15] + pDbTemp[0] * pDbTemp[11] * pDbTemp[13] + pDbTemp[8] * pDbTemp[1] * pDbTemp[15] - pDbTemp[8] * pDbTemp[3] * pDbTemp[13] - pDbTemp[12] * pDbTemp[1] * pDbTemp[11] + pDbTemp[12] * pDbTemp[3] * pDbTemp[9]);
|
||||
pFlOut[13] = (float) (pDbTemp[0] * pDbTemp[9] * pDbTemp[14] - pDbTemp[0] * pDbTemp[10] * pDbTemp[13] - pDbTemp[8] * pDbTemp[1] * pDbTemp[14] + pDbTemp[8] * pDbTemp[2] * pDbTemp[13] + pDbTemp[12] * pDbTemp[1] * pDbTemp[10] - pDbTemp[12] * pDbTemp[2] * pDbTemp[9]);
|
||||
pFlOut[2] = (float) (pDbTemp[1] * pDbTemp[6] * pDbTemp[15] - pDbTemp[1] * pDbTemp[7] * pDbTemp[14] - pDbTemp[5] * pDbTemp[2] * pDbTemp[15] + pDbTemp[5] * pDbTemp[3] * pDbTemp[14] + pDbTemp[13] * pDbTemp[2] * pDbTemp[7] - pDbTemp[13] * pDbTemp[3] * pDbTemp[6]);
|
||||
pFlOut[6] = (float) (-pDbTemp[0] * pDbTemp[6] * pDbTemp[15] + pDbTemp[0] * pDbTemp[7] * pDbTemp[14] + pDbTemp[4] * pDbTemp[2] * pDbTemp[15] - pDbTemp[4] * pDbTemp[3] * pDbTemp[14] - pDbTemp[12] * pDbTemp[2] * pDbTemp[7] + pDbTemp[12] * pDbTemp[3] * pDbTemp[6]);
|
||||
pFlOut[10] = (float) (pDbTemp[0] * pDbTemp[5] * pDbTemp[15] - pDbTemp[0] * pDbTemp[7] * pDbTemp[13] - pDbTemp[4] * pDbTemp[1] * pDbTemp[15] + pDbTemp[4] * pDbTemp[3] * pDbTemp[13] + pDbTemp[12] * pDbTemp[1] * pDbTemp[7] - pDbTemp[12] * pDbTemp[3] * pDbTemp[5]);
|
||||
pFlOut[14] = (float) (-pDbTemp[0] * pDbTemp[5] * pDbTemp[14] + pDbTemp[0] * pDbTemp[6] * pDbTemp[13] + pDbTemp[4] * pDbTemp[1] * pDbTemp[14] - pDbTemp[4] * pDbTemp[2] * pDbTemp[13] - pDbTemp[12] * pDbTemp[1] * pDbTemp[6] + pDbTemp[12] * pDbTemp[2] * pDbTemp[5]);
|
||||
pFlOut[3] = (float) (-pDbTemp[1] * pDbTemp[6] * pDbTemp[11] + pDbTemp[1] * pDbTemp[7] * pDbTemp[10] + pDbTemp[5] * pDbTemp[2] * pDbTemp[11] - pDbTemp[5] * pDbTemp[3] * pDbTemp[10] - pDbTemp[9] * pDbTemp[2] * pDbTemp[7] + pDbTemp[9] * pDbTemp[3] * pDbTemp[6]);
|
||||
pFlOut[7] = (float) (pDbTemp[0] * pDbTemp[6] * pDbTemp[11] - pDbTemp[0] * pDbTemp[7] * pDbTemp[10] - pDbTemp[4] * pDbTemp[2] * pDbTemp[11] + pDbTemp[4] * pDbTemp[3] * pDbTemp[10] + pDbTemp[8] * pDbTemp[2] * pDbTemp[7] - pDbTemp[8] * pDbTemp[3] * pDbTemp[6]);
|
||||
pFlOut[11] = (float) (-pDbTemp[0] * pDbTemp[5] * pDbTemp[11] + pDbTemp[0] * pDbTemp[7] * pDbTemp[9] + pDbTemp[4] * pDbTemp[1] * pDbTemp[11] - pDbTemp[4] * pDbTemp[3] * pDbTemp[9] - pDbTemp[8] * pDbTemp[1] * pDbTemp[7] + pDbTemp[8] * pDbTemp[3] * pDbTemp[5]);
|
||||
pFlOut[15] = (float) (pDbTemp[0] * pDbTemp[5] * pDbTemp[10] - pDbTemp[0] * pDbTemp[6] * pDbTemp[9] - pDbTemp[4] * pDbTemp[1] * pDbTemp[10] + pDbTemp[4] * pDbTemp[2] * pDbTemp[9] + pDbTemp[8] * pDbTemp[1] * pDbTemp[6] - pDbTemp[8] * pDbTemp[2] * pDbTemp[5]);
|
||||
var num1 = (float) (pDbTemp[0] * pFlOut[0] + pDbTemp[1] * pFlOut[4] + pDbTemp[2] * pFlOut[8] + pDbTemp[3] * pFlOut[12]);
|
||||
if (num1 == 0.0f) throw new InvalidOperationException("Matrix is singular and cannot be inverted.");
|
||||
var num2 = 1.0f / num1;
|
||||
for (var i = 0; i < 16; i++) pFlOut[i] *= num2;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Matrix4 Transpose(in Matrix4 mat) => new(
|
||||
new(mat.Row0.X, mat.Row1.X, mat.Row2.X, mat.Row3.X),
|
||||
new(mat.Row0.Y, mat.Row1.Y, mat.Row2.Y, mat.Row3.Y),
|
||||
new(mat.Row0.Z, mat.Row1.Z, mat.Row2.Z, mat.Row3.Z),
|
||||
new(mat.Row0.W, mat.Row1.W, mat.Row2.W, mat.Row3.W));
|
||||
|
||||
public static bool operator ==(in Matrix4 a, in Matrix4 b) => AreEqual(in a, in b);
|
||||
|
||||
public static bool operator !=(in Matrix4 a, in Matrix4 b) => !AreEqual(in a, in b);
|
||||
|
||||
/// <summary>Matrix multiplication</summary>
|
||||
/// <param name="left">left-hand operand</param>
|
||||
/// <param name="right">right-hand operand</param>
|
||||
/// <returns>A new Matrix4 which holds the result of the multiplication</returns>
|
||||
public static Matrix4 operator *(in Matrix4 left, in Matrix4 right)
|
||||
{
|
||||
var x1 = (double) left.Row0.X;
|
||||
var y1 = (double) left.Row0.Y;
|
||||
var z1 = (double) left.Row0.Z;
|
||||
var w1 = (double) left.Row0.W;
|
||||
var x2 = (double) left.Row1.X;
|
||||
var y2 = (double) left.Row1.Y;
|
||||
var z2 = (double) left.Row1.Z;
|
||||
var w2 = (double) left.Row1.W;
|
||||
var x3 = (double) left.Row2.X;
|
||||
var y3 = (double) left.Row2.Y;
|
||||
var z3 = (double) left.Row2.Z;
|
||||
var w3 = (double) left.Row2.W;
|
||||
var x4 = (double) left.Row3.X;
|
||||
var y4 = (double) left.Row3.Y;
|
||||
var z4 = (double) left.Row3.Z;
|
||||
var w4 = (double) left.Row3.W;
|
||||
var x5 = (double) right.Row0.X;
|
||||
var y5 = (double) right.Row0.Y;
|
||||
var z5 = (double) right.Row0.Z;
|
||||
var w5 = (double) right.Row0.W;
|
||||
var x6 = (double) right.Row1.X;
|
||||
var y6 = (double) right.Row1.Y;
|
||||
var z6 = (double) right.Row1.Z;
|
||||
var w6 = (double) right.Row1.W;
|
||||
var x7 = (double) right.Row2.X;
|
||||
var y7 = (double) right.Row2.Y;
|
||||
var z7 = (double) right.Row2.Z;
|
||||
var w7 = (double) right.Row2.W;
|
||||
var x8 = (double) right.Row3.X;
|
||||
var y8 = (double) right.Row3.Y;
|
||||
var z8 = (double) right.Row3.Z;
|
||||
var w8 = (double) right.Row3.W;
|
||||
Matrix4 result;
|
||||
result.Row0.X = (float) (x1 * x5 + y1 * x6 + z1 * x7 + w1 * x8);
|
||||
result.Row0.Y = (float) (x1 * y5 + y1 * y6 + z1 * y7 + w1 * y8);
|
||||
result.Row0.Z = (float) (x1 * z5 + y1 * z6 + z1 * z7 + w1 * z8);
|
||||
result.Row0.W = (float) (x1 * w5 + y1 * w6 + z1 * w7 + w1 * w8);
|
||||
result.Row1.X = (float) (x2 * x5 + y2 * x6 + z2 * x7 + w2 * x8);
|
||||
result.Row1.Y = (float) (x2 * y5 + y2 * y6 + z2 * y7 + w2 * y8);
|
||||
result.Row1.Z = (float) (x2 * z5 + y2 * z6 + z2 * z7 + w2 * z8);
|
||||
result.Row1.W = (float) (x2 * w5 + y2 * w6 + z2 * w7 + w2 * w8);
|
||||
result.Row2.X = (float) (x3 * x5 + y3 * x6 + z3 * x7 + w3 * x8);
|
||||
result.Row2.Y = (float) (x3 * y5 + y3 * y6 + z3 * y7 + w3 * y8);
|
||||
result.Row2.Z = (float) (x3 * z5 + y3 * z6 + z3 * z7 + w3 * z8);
|
||||
result.Row2.W = (float) (x3 * w5 + y3 * w6 + z3 * w7 + w3 * w8);
|
||||
result.Row3.X = (float) (x4 * x5 + y4 * x6 + z4 * x7 + w4 * x8);
|
||||
result.Row3.Y = (float) (x4 * y5 + y4 * y6 + z4 * y7 + w4 * y8);
|
||||
result.Row3.Z = (float) (x4 * z5 + y4 * z6 + z4 * z7 + w4 * z8);
|
||||
result.Row3.W = (float) (x4 * w5 + y4 * w6 + z4 * w7 + w4 * w8);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <returns><paramref name="vec"/> transformed by <paramref name="mat"/></returns>
|
||||
public static Vector4 operator *(in Vector4 vec, in Matrix4 mat) => new(
|
||||
(float) (vec.X * (double) mat.Row0.X + vec.Y * (double) mat.Row1.X + vec.Z * (double) mat.Row2.X + vec.W * (double) mat.Row3.X),
|
||||
(float) (vec.X * (double) mat.Row0.Y + vec.Y * (double) mat.Row1.Y + vec.Z * (double) mat.Row2.Y + vec.W * (double) mat.Row3.Y),
|
||||
(float) (vec.X * (double) mat.Row0.Z + vec.Y * (double) mat.Row1.Z + vec.Z * (double) mat.Row2.Z + vec.W * (double) mat.Row3.Z),
|
||||
(float) (vec.X * (double) mat.Row0.W + vec.Y * (double) mat.Row1.W + vec.Z * (double) mat.Row2.W + vec.W * (double) mat.Row3.W));
|
||||
|
||||
/// <summary>Top row of the matrix.</summary>
|
||||
public Vector4 Row0;
|
||||
|
||||
/// <summary>2nd row of the matrix.</summary>
|
||||
public Vector4 Row1;
|
||||
|
||||
/// <summary>3rd row of the matrix.</summary>
|
||||
public Vector4 Row2;
|
||||
|
||||
/// <summary>Bottom row of the matrix.</summary>
|
||||
public Vector4 Row3;
|
||||
|
||||
/// <param name="row0">Top row of the matrix.</param>
|
||||
/// <param name="row1">Second row of the matrix.</param>
|
||||
/// <param name="row2">Third row of the matrix.</param>
|
||||
/// <param name="row3">Bottom row of the matrix.</param>
|
||||
public Matrix4(Vector4 row0, Vector4 row1, Vector4 row2, Vector4 row3)
|
||||
{
|
||||
Row0 = row0;
|
||||
Row1 = row1;
|
||||
Row2 = row2;
|
||||
Row3 = row3;
|
||||
}
|
||||
|
||||
public unsafe float this[int rowIndex, int columnIndex]
|
||||
{
|
||||
readonly get
|
||||
{
|
||||
if (rowIndex is < 0 or > 3) throw new ArgumentOutOfRangeException(paramName: nameof(rowIndex), rowIndex, message: "index out of range");
|
||||
if (columnIndex is < 0 or > 3) throw new ArgumentOutOfRangeException(paramName: nameof(columnIndex), columnIndex, message: "index out of range");
|
||||
var i = rowIndex * 4 + columnIndex;
|
||||
fixed (Matrix4* p = &this) return ((float*) p)[i];
|
||||
}
|
||||
set
|
||||
{
|
||||
if (rowIndex is < 0 or > 3) throw new ArgumentOutOfRangeException(paramName: nameof(rowIndex), rowIndex, message: "index out of range");
|
||||
if (columnIndex is < 0 or > 3) throw new ArgumentOutOfRangeException(paramName: nameof(columnIndex), columnIndex, message: "index out of range");
|
||||
var i = rowIndex * 4 + columnIndex;
|
||||
fixed (Matrix4* p = &this) ((float*) p)[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <returns>an inverted copy of this instance, or an identical copy if it is singular</returns>
|
||||
public readonly Matrix4 Inverted() => GetDeterminant(in this) == 0.0f ? this : Invert(in this);
|
||||
|
||||
public override readonly bool Equals(object obj) => obj is Matrix4 other && AreEqual(in this, in other);
|
||||
|
||||
public override readonly int GetHashCode() => ((Row0.GetHashCode() * 397 ^ Row1.GetHashCode()) * 397 ^ Row2.GetHashCode()) * 397 ^ Row3.GetHashCode();
|
||||
|
||||
public override readonly string ToString() => string.Join("\n", Row0, Row1, Row2, Row3);
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
namespace BizHawk.Bizware.BizwareGL
|
||||
{
|
||||
public struct Vector2
|
||||
{
|
||||
public static bool AreEqual(in Vector2 a, in Vector2 b) => a.X == b.X && a.Y == b.Y;
|
||||
|
||||
public static bool operator ==(in Vector2 a, in Vector2 b) => AreEqual(in a, in b);
|
||||
|
||||
public static bool operator !=(in Vector2 a, in Vector2 b) => !AreEqual(in a, in b);
|
||||
|
||||
public static Vector2 operator +(in Vector2 left, in Vector2 right) => new(left.X + right.X, left.Y + right.Y);
|
||||
|
||||
public float X;
|
||||
|
||||
public float Y;
|
||||
|
||||
public Vector2(float x, float y)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
}
|
||||
|
||||
public override readonly bool Equals(object obj) => obj is Vector2 other && AreEqual(in this, in other);
|
||||
|
||||
public override readonly int GetHashCode() => X.GetHashCode() * 397 ^ Y.GetHashCode();
|
||||
|
||||
public override readonly string ToString() => $"({X}, {Y})";
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
namespace BizHawk.Bizware.BizwareGL
|
||||
{
|
||||
public readonly struct Vector3
|
||||
{
|
||||
public static bool AreEqual(in Vector3 a, in Vector3 b) => a.X == b.X && a.Y == b.Y && a.Z == b.Z;
|
||||
|
||||
public static bool operator ==(in Vector3 a, in Vector3 b) => AreEqual(in a, in b);
|
||||
|
||||
public static bool operator !=(in Vector3 a, in Vector3 b) => !AreEqual(in a, in b);
|
||||
|
||||
public readonly float X;
|
||||
|
||||
public readonly float Y;
|
||||
|
||||
public readonly float Z;
|
||||
|
||||
public Vector3(float x, float y, float z)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Z = z;
|
||||
}
|
||||
|
||||
public override readonly bool Equals(object obj) => obj is Vector3 other && AreEqual(in this, in other);
|
||||
|
||||
public override readonly int GetHashCode() => (X.GetHashCode() * 397 ^ Y.GetHashCode()) * 397 ^ Z.GetHashCode();
|
||||
|
||||
public override readonly string ToString() => $"({X}, {Y}, {Z})";
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
namespace BizHawk.Bizware.BizwareGL
|
||||
{
|
||||
public struct Vector4
|
||||
{
|
||||
public static bool AreEqual(in Vector4 a, in Vector4 b) => a.X == b.X && a.Y == b.Y && a.Z == b.Z && a.W == b.W;
|
||||
|
||||
public static bool operator ==(in Vector4 a, in Vector4 b) => AreEqual(in a, in b);
|
||||
|
||||
public static bool operator !=(in Vector4 a, in Vector4 b) => !AreEqual(in a, in b);
|
||||
|
||||
public float X;
|
||||
|
||||
public float Y;
|
||||
|
||||
public float Z;
|
||||
|
||||
public float W;
|
||||
|
||||
public Vector4(float x, float y, float z, float w)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Z = z;
|
||||
W = w;
|
||||
}
|
||||
|
||||
public override readonly bool Equals(object obj) => obj is Vector4 other && AreEqual(in this, in other);
|
||||
|
||||
public override readonly int GetHashCode() => ((X.GetHashCode() * 397 ^ Y.GetHashCode()) * 397 ^ Z.GetHashCode()) * 397 ^ W.GetHashCode();
|
||||
|
||||
public override readonly string ToString() => $"({X}, {Y}, {Z}, {W})";
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
@ -573,10 +574,10 @@ namespace BizHawk.Bizware.Graphics
|
|||
}
|
||||
}
|
||||
|
||||
public void SetPipelineUniformMatrix(PipelineUniform uniform, Matrix4 mat, bool transpose)
|
||||
public void SetPipelineUniformMatrix(PipelineUniform uniform, Matrix4x4 mat, bool transpose)
|
||||
=> SetPipelineUniformMatrix(uniform, ref mat, transpose);
|
||||
|
||||
public void SetPipelineUniformMatrix(PipelineUniform uniform, ref Matrix4 mat, bool transpose)
|
||||
public void SetPipelineUniformMatrix(PipelineUniform uniform, ref Matrix4x4 mat, bool transpose)
|
||||
{
|
||||
foreach (var ui in uniform.UniformInfos)
|
||||
{
|
||||
|
@ -755,32 +756,32 @@ namespace BizHawk.Bizware.Graphics
|
|||
return LoadTexture(fs);
|
||||
}
|
||||
|
||||
public Matrix4 CreateGuiProjectionMatrix(int w, int h)
|
||||
public Matrix4x4 CreateGuiProjectionMatrix(int w, int h)
|
||||
{
|
||||
return CreateGuiProjectionMatrix(new(w, h));
|
||||
}
|
||||
|
||||
public Matrix4 CreateGuiViewMatrix(int w, int h, bool autoFlip)
|
||||
public Matrix4x4 CreateGuiViewMatrix(int w, int h, bool autoFlip)
|
||||
{
|
||||
return CreateGuiViewMatrix(new(w, h), autoFlip);
|
||||
}
|
||||
|
||||
public Matrix4 CreateGuiProjectionMatrix(Size dims)
|
||||
public Matrix4x4 CreateGuiProjectionMatrix(Size dims)
|
||||
{
|
||||
var ret = Matrix4.Identity;
|
||||
ret.Row0.X = 2.0f / dims.Width;
|
||||
ret.Row1.Y = 2.0f / dims.Height;
|
||||
var ret = Matrix4x4.Identity;
|
||||
ret.M11 = 2.0f / dims.Width;
|
||||
ret.M22 = 2.0f / dims.Height;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public Matrix4 CreateGuiViewMatrix(Size dims, bool autoFlip)
|
||||
public Matrix4x4 CreateGuiViewMatrix(Size dims, bool autoFlip)
|
||||
{
|
||||
var ret = Matrix4.Identity;
|
||||
ret.Row1.Y = -1.0f;
|
||||
ret.Row3.X = -dims.Width * 0.5f - 0.5f;
|
||||
ret.Row3.Y = dims.Height * 0.5f + 0.5f;
|
||||
var ret = Matrix4x4.Identity;
|
||||
ret.M22 = -1.0f;
|
||||
ret.M41 = -dims.Width * 0.5f - 0.5f;
|
||||
ret.M42 = dims.Height * 0.5f + 0.5f;
|
||||
|
||||
// auto-flipping isn't needed on d3d
|
||||
// auto-flipping isn't needed on D3D
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System.Drawing;
|
||||
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
using System.Numerics;
|
||||
|
||||
using SharpDX.Mathematics.Interop;
|
||||
|
||||
|
@ -8,21 +7,21 @@ namespace BizHawk.Bizware.Graphics
|
|||
{
|
||||
internal static class SharpDXExtensions
|
||||
{
|
||||
// SharpDX RawMatrix and BizwareGL Matrix are identical in structure
|
||||
public static RawMatrix ToSharpDXMatrix(this Matrix4 m, bool transpose)
|
||||
// SharpDX RawMatrix and Numerics Matrix4x4 are identical in structure
|
||||
public static RawMatrix ToSharpDXMatrix(this Matrix4x4 m, bool transpose)
|
||||
{
|
||||
// Transpose call could be inlined to reduce 2 sets of copies to 1
|
||||
if (transpose)
|
||||
{
|
||||
m = Matrix4.Transpose(in m);
|
||||
m = Matrix4x4.Transpose(m);
|
||||
}
|
||||
|
||||
return new()
|
||||
{
|
||||
M11 = m.Row0.X, M12 = m.Row0.Y, M13 = m.Row0.Z, M14 = m.Row0.W,
|
||||
M21 = m.Row1.X, M22 = m.Row1.Y, M23 = m.Row1.Z, M24 = m.Row1.W,
|
||||
M31 = m.Row2.X, M32 = m.Row2.Y, M33 = m.Row2.Z, M34 = m.Row2.W,
|
||||
M41 = m.Row3.X, M42 = m.Row3.Y, M43 = m.Row3.Z, M44 = m.Row3.W
|
||||
M11 = m.M11, M12 = m.M12, M13 = m.M13, M14 = m.M14,
|
||||
M21 = m.M21, M22 = m.M22, M23 = m.M23, M24 = m.M24,
|
||||
M31 = m.M31, M32 = m.M32, M33 = m.M33, M34 = m.M34,
|
||||
M41 = m.M41, M42 = m.M42, M43 = m.M43, M44 = m.M44
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ using System;
|
|||
using System.Diagnostics;
|
||||
#endif
|
||||
using System.Drawing;
|
||||
using System.Numerics;
|
||||
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
|
||||
|
@ -153,7 +154,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
/// <exception cref="InvalidOperationException">no pipeline set (need to call <see cref="SetPipeline"/>)</exception>
|
||||
public void Begin()
|
||||
{
|
||||
//uhhmmm I want to throw an exception if its already active, but its annoying.
|
||||
// uhhmmm I want to throw an exception if its already active, but its annoying.
|
||||
|
||||
if (CurrPipeline == null)
|
||||
throw new InvalidOperationException("Pipeline hasn't been set!");
|
||||
|
@ -176,14 +177,17 @@ namespace BizHawk.Bizware.Graphics
|
|||
|
||||
public void Flush()
|
||||
{
|
||||
//no batching, nothing to do here yet
|
||||
// no batching, nothing to do here yet
|
||||
}
|
||||
|
||||
/// <exception cref="InvalidOperationException"><see cref="IsActive"/> is <see langword="false"/></exception>
|
||||
public void End()
|
||||
{
|
||||
if (!IsActive)
|
||||
{
|
||||
throw new InvalidOperationException($"{nameof(GuiRenderer)} is not active!");
|
||||
}
|
||||
|
||||
IsActive = false;
|
||||
}
|
||||
|
||||
|
@ -199,26 +203,40 @@ namespace BizHawk.Bizware.Graphics
|
|||
DrawSubrectInternal(tex, x, y, w, h, u0, v0, u1, v1);
|
||||
}
|
||||
|
||||
public void Draw(Art art)
|
||||
{
|
||||
DrawInternal(art, 0, 0, art.Width, art.Height, false, false);
|
||||
}
|
||||
|
||||
public void Draw(Art art) { DrawInternal(art, 0, 0, art.Width, art.Height, false, false); }
|
||||
public void Draw(Art art, float x, float y)
|
||||
{
|
||||
DrawInternal(art, x, y, art.Width, art.Height, false, false);
|
||||
}
|
||||
|
||||
public void Draw(Art art, float x, float y, float width, float height)
|
||||
{
|
||||
DrawInternal(art, x, y, width, height, false, false);
|
||||
}
|
||||
|
||||
public void Draw(Art art, float x, float y) { DrawInternal(art, x, y, art.Width, art.Height, false, false); }
|
||||
public void Draw(Art art, Vector2 pos)
|
||||
{
|
||||
DrawInternal(art, pos.X, pos.Y, art.Width, art.Height, false, false);
|
||||
}
|
||||
|
||||
public void Draw(Texture2d tex)
|
||||
{
|
||||
DrawInternal(tex, 0, 0, tex.Width, tex.Height);
|
||||
}
|
||||
|
||||
public void Draw(Art art, float x, float y, float width, float height) { DrawInternal(art, x, y, width, height, false, false); }
|
||||
public void Draw(Texture2d tex, float x, float y)
|
||||
{
|
||||
DrawInternal(tex, x, y, tex.Width, tex.Height);
|
||||
}
|
||||
|
||||
|
||||
public void Draw(Art art, Vector2 pos) { DrawInternal(art, pos.X, pos.Y, art.Width, art.Height, false, false); }
|
||||
|
||||
|
||||
public void Draw(Texture2d tex) { DrawInternal(tex, 0, 0, tex.Width, tex.Height); }
|
||||
|
||||
|
||||
public void Draw(Texture2d tex, float x, float y) { DrawInternal(tex, x, y, tex.Width, tex.Height); }
|
||||
|
||||
|
||||
public void DrawFlipped(Art art, bool xflip, bool yflip) { DrawInternal(art, 0, 0, art.Width, art.Height, xflip, yflip); }
|
||||
public void DrawFlipped(Art art, bool xflip, bool yflip)
|
||||
{
|
||||
DrawInternal(art, 0, 0, art.Width, art.Height, xflip, yflip);
|
||||
}
|
||||
|
||||
public void Draw(Texture2d art, float x, float y, float width, float height)
|
||||
{
|
||||
|
@ -441,7 +459,7 @@ void main()
|
|||
vCornerColor = aColor * uModulateColor;
|
||||
}";
|
||||
|
||||
public readonly string DefaultPixelShader_gl = @"
|
||||
public const string DefaultPixelShader_gl = @"
|
||||
//opengl 2.0 ~ 2004
|
||||
#version 110
|
||||
uniform bool uSamplerEnable;
|
||||
|
|
|
@ -7,9 +7,10 @@
|
|||
// glBindAttribLocation (programID, 0, "vertexPosition_modelspace");
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
using BizHawk.Common;
|
||||
|
@ -445,14 +446,14 @@ namespace BizHawk.Bizware.Graphics
|
|||
GL.Uniform1((int)uniform.Sole.Opaque, value ? 1 : 0);
|
||||
}
|
||||
|
||||
public unsafe void SetPipelineUniformMatrix(PipelineUniform uniform, Matrix4 mat, bool transpose)
|
||||
public unsafe void SetPipelineUniformMatrix(PipelineUniform uniform, Matrix4x4 mat, bool transpose)
|
||||
{
|
||||
GL.UniformMatrix4((int)uniform.Sole.Opaque, 1, transpose, (float*)&mat);
|
||||
}
|
||||
|
||||
public unsafe void SetPipelineUniformMatrix(PipelineUniform uniform, ref Matrix4 mat, bool transpose)
|
||||
public unsafe void SetPipelineUniformMatrix(PipelineUniform uniform, ref Matrix4x4 mat, bool transpose)
|
||||
{
|
||||
fixed (Matrix4* pMat = &mat)
|
||||
fixed (Matrix4x4* pMat = &mat)
|
||||
{
|
||||
GL.UniformMatrix4((int)uniform.Sole.Opaque, 1, transpose, (float*)pMat);
|
||||
}
|
||||
|
@ -646,35 +647,36 @@ namespace BizHawk.Bizware.Graphics
|
|||
return LoadTexture(fs);
|
||||
}
|
||||
|
||||
public Matrix4 CreateGuiProjectionMatrix(int w, int h)
|
||||
public Matrix4x4 CreateGuiProjectionMatrix(int w, int h)
|
||||
{
|
||||
return CreateGuiProjectionMatrix(new(w, h));
|
||||
}
|
||||
|
||||
public Matrix4 CreateGuiViewMatrix(int w, int h, bool autoflip)
|
||||
public Matrix4x4 CreateGuiViewMatrix(int w, int h, bool autoflip)
|
||||
{
|
||||
return CreateGuiViewMatrix(new(w, h), autoflip);
|
||||
}
|
||||
|
||||
public Matrix4 CreateGuiProjectionMatrix(Size dims)
|
||||
public Matrix4x4 CreateGuiProjectionMatrix(Size dims)
|
||||
{
|
||||
var ret = Matrix4.Identity;
|
||||
ret.Row0.X = 2.0f / dims.Width;
|
||||
ret.Row1.Y = 2.0f / dims.Height;
|
||||
var ret = Matrix4x4.Identity;
|
||||
ret.M11 = 2.0f / dims.Width;
|
||||
ret.M22 = 2.0f / dims.Height;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public Matrix4 CreateGuiViewMatrix(Size dims, bool autoflip)
|
||||
public Matrix4x4 CreateGuiViewMatrix(Size dims, bool autoflip)
|
||||
{
|
||||
var ret = Matrix4.Identity;
|
||||
ret.Row1.Y = -1.0f;
|
||||
ret.Row3.X = dims.Width * -0.5f;
|
||||
ret.Row3.Y = dims.Height * 0.5f;
|
||||
var ret = Matrix4x4.Identity;
|
||||
ret.M22 = -1.0f;
|
||||
ret.M41 = dims.Width * -0.5f;
|
||||
ret.M42 = dims.Height * 0.5f;
|
||||
if (autoflip && _currRenderTarget is not null) // flip as long as we're not a final render target
|
||||
{
|
||||
ret.Row1.Y = 1.0f;
|
||||
ret.Row3.Y *= -1;
|
||||
ret.M22 = 1.0f;
|
||||
ret.M42 *= -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ using System.Collections.Generic;
|
|||
using System.Drawing;
|
||||
using System.Drawing.Text;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
|
@ -52,7 +52,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
private IEmulator GlobalEmulator;
|
||||
|
||||
public DisplayManagerBase(
|
||||
protected DisplayManagerBase(
|
||||
Config config,
|
||||
IEmulator emulator,
|
||||
InputManager inputManager,
|
||||
|
@ -63,58 +63,58 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
GlobalConfig = config;
|
||||
GlobalEmulator = emulator;
|
||||
OSD = new OSDManager(config, emulator, inputManager, movieSession);
|
||||
OSD = new(config, emulator, inputManager, movieSession);
|
||||
_gl = gl;
|
||||
_renderer = renderer;
|
||||
|
||||
// it's sort of important for these to be initialized to something nonzero
|
||||
_currEmuWidth = _currEmuHeight = 1;
|
||||
|
||||
_videoTextureFrugalizer = new TextureFrugalizer(_gl);
|
||||
_videoTextureFrugalizer = new(_gl);
|
||||
|
||||
_shaderChainFrugalizers = new RenderTargetFrugalizer[16]; // hacky hardcoded limit.. need some other way to manage these
|
||||
for (int i = 0; i < 16; i++)
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
_shaderChainFrugalizers[i] = new RenderTargetFrugalizer(_gl);
|
||||
_shaderChainFrugalizers[i] = new(_gl);
|
||||
}
|
||||
|
||||
{
|
||||
using var xml = ReflectionCache.EmbeddedResourceStream("Resources.courier16px.fnt");
|
||||
using var tex = ReflectionCache.EmbeddedResourceStream("Resources.courier16px_0.png");
|
||||
_theOneFont = new StringRenderer(_gl, xml, tex);
|
||||
_theOneFont = new(_gl, xml, tex);
|
||||
using var gens = ReflectionCache.EmbeddedResourceStream("Resources.gens.ttf");
|
||||
LoadCustomFont(gens);
|
||||
using var fceux = ReflectionCache.EmbeddedResourceStream("Resources.fceux.ttf");
|
||||
LoadCustomFont(fceux);
|
||||
}
|
||||
|
||||
if (dispMethod == EDispMethod.OpenGL || dispMethod == EDispMethod.D3D9)
|
||||
if (dispMethod is EDispMethod.OpenGL or EDispMethod.D3D9)
|
||||
{
|
||||
var fiHq2x = new FileInfo(Path.Combine(PathUtils.ExeDirectoryPath, "Shaders/BizHawk/hq2x.cgp"));
|
||||
if (fiHq2x.Exists)
|
||||
{
|
||||
using var stream = fiHq2x.OpenRead();
|
||||
_shaderChainHq2X = new RetroShaderChain(_gl, new RetroShaderPreset(stream), Path.Combine(PathUtils.ExeDirectoryPath, "Shaders/BizHawk"));
|
||||
_shaderChainHq2X = new(_gl, new(stream), Path.Combine(PathUtils.ExeDirectoryPath, "Shaders/BizHawk"));
|
||||
}
|
||||
var fiScanlines = new FileInfo(Path.Combine(PathUtils.ExeDirectoryPath, "Shaders/BizHawk/BizScanlines.cgp"));
|
||||
if (fiScanlines.Exists)
|
||||
{
|
||||
using var stream = fiScanlines.OpenRead();
|
||||
_shaderChainScanlines = new RetroShaderChain(_gl, new RetroShaderPreset(stream), Path.Combine(PathUtils.ExeDirectoryPath, "Shaders/BizHawk"));
|
||||
_shaderChainScanlines = new(_gl, new(stream), Path.Combine(PathUtils.ExeDirectoryPath, "Shaders/BizHawk"));
|
||||
}
|
||||
var bicubicPath = dispMethod == EDispMethod.D3D9 ? "Shaders/BizHawk/bicubic-normal.cgp" : "Shaders/BizHawk/bicubic-fast.cgp";
|
||||
var fiBicubic = new FileInfo(Path.Combine(PathUtils.ExeDirectoryPath, bicubicPath));
|
||||
if (fiBicubic.Exists)
|
||||
{
|
||||
using var stream = fiBicubic.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
_shaderChainBicubic = new RetroShaderChain(_gl, new RetroShaderPreset(stream), Path.Combine(PathUtils.ExeDirectoryPath, "Shaders/BizHawk"));
|
||||
_shaderChainBicubic = new(_gl, new(stream), Path.Combine(PathUtils.ExeDirectoryPath, "Shaders/BizHawk"));
|
||||
}
|
||||
}
|
||||
|
||||
_apiHawkSurfaceSets[DisplaySurfaceID.EmuCore] = new(CreateDisplaySurface);
|
||||
_apiHawkSurfaceSets[DisplaySurfaceID.Client] = new(CreateDisplaySurface);
|
||||
_apiHawkSurfaceFrugalizers[DisplaySurfaceID.EmuCore] = new TextureFrugalizer(_gl);
|
||||
_apiHawkSurfaceFrugalizers[DisplaySurfaceID.Client] = new TextureFrugalizer(_gl);
|
||||
_apiHawkSurfaceFrugalizers[DisplaySurfaceID.EmuCore] = new(_gl);
|
||||
_apiHawkSurfaceFrugalizers[DisplaySurfaceID.Client] = new(_gl);
|
||||
|
||||
RefreshUserShader();
|
||||
}
|
||||
|
@ -130,7 +130,11 @@ namespace BizHawk.Client.Common
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Disposed) return;
|
||||
if (Disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Disposed = true;
|
||||
|
||||
// OpenGL context needs to be active when Dispose()'ing
|
||||
|
@ -185,7 +189,7 @@ namespace BizHawk.Client.Common
|
|||
/// <summary>
|
||||
/// custom fonts that don't need to be installed on the user side
|
||||
/// </summary>
|
||||
public PrivateFontCollection CustomFonts { get; } = new PrivateFontCollection();
|
||||
public PrivateFontCollection CustomFonts { get; } = new();
|
||||
|
||||
private readonly TextureFrugalizer _videoTextureFrugalizer;
|
||||
|
||||
|
@ -193,11 +197,11 @@ namespace BizHawk.Client.Common
|
|||
|
||||
protected readonly RenderTargetFrugalizer[] _shaderChainFrugalizers;
|
||||
|
||||
private RetroShaderChain _shaderChainHq2X;
|
||||
private readonly RetroShaderChain _shaderChainHq2X;
|
||||
|
||||
private RetroShaderChain _shaderChainScanlines;
|
||||
private readonly RetroShaderChain _shaderChainScanlines;
|
||||
|
||||
private RetroShaderChain _shaderChainBicubic;
|
||||
private readonly RetroShaderChain _shaderChainBicubic;
|
||||
|
||||
private RetroShaderChain _shaderChainUser;
|
||||
|
||||
|
@ -214,7 +218,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
var fi = new FileInfo(GlobalConfig.DispUserFilterPath);
|
||||
using var stream = fi.OpenRead();
|
||||
_shaderChainUser = new RetroShaderChain(_gl, new RetroShaderPreset(stream), Path.GetDirectoryName(GlobalConfig.DispUserFilterPath));
|
||||
_shaderChainUser = new(_gl, new(stream), Path.GetDirectoryName(GlobalConfig.DispUserFilterPath));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -261,26 +265,24 @@ namespace BizHawk.Client.Common
|
|||
// select user special FX shader chain
|
||||
var selectedChainProperties = new Dictionary<string, object>();
|
||||
RetroShaderChain selectedChain = null;
|
||||
if (GlobalConfig.TargetDisplayFilter == 1 && _shaderChainHq2X != null && _shaderChainHq2X.Available)
|
||||
switch (GlobalConfig.TargetDisplayFilter)
|
||||
{
|
||||
selectedChain = _shaderChainHq2X;
|
||||
}
|
||||
|
||||
if (GlobalConfig.TargetDisplayFilter == 2 && _shaderChainScanlines != null && _shaderChainScanlines.Available)
|
||||
{
|
||||
selectedChain = _shaderChainScanlines;
|
||||
selectedChainProperties["uIntensity"] = 1.0f - GlobalConfig.TargetScanlineFilterIntensity / 256.0f;
|
||||
}
|
||||
|
||||
if (GlobalConfig.TargetDisplayFilter == 3 && _shaderChainUser != null && _shaderChainUser.Available)
|
||||
{
|
||||
selectedChain = _shaderChainUser;
|
||||
case 1 when _shaderChainHq2X is { Available: true }:
|
||||
selectedChain = _shaderChainHq2X;
|
||||
break;
|
||||
case 2 when _shaderChainScanlines is { Available: true }:
|
||||
selectedChain = _shaderChainScanlines;
|
||||
selectedChainProperties["uIntensity"] = 1.0f - GlobalConfig.TargetScanlineFilterIntensity / 256.0f;
|
||||
break;
|
||||
case 3 when _shaderChainUser is { Available: true }:
|
||||
selectedChain = _shaderChainUser;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!includeUserFilters)
|
||||
selectedChain = null;
|
||||
|
||||
BaseFilter fCoreScreenControl = CreateCoreScreenControl();
|
||||
var fCoreScreenControl = CreateCoreScreenControl();
|
||||
|
||||
var fPresent = new FinalPresentation(chainOutSize);
|
||||
var fInput = new SourceImage(chainInSize);
|
||||
|
@ -311,7 +313,9 @@ namespace BizHawk.Client.Common
|
|||
chain.AddFilter(fInput, "input");
|
||||
|
||||
if (fCoreScreenControl != null)
|
||||
{
|
||||
chain.AddFilter(fCoreScreenControl, "CoreScreenControl");
|
||||
}
|
||||
|
||||
// if a non-zero padding is required, add a filter to allow for that
|
||||
// note, we have two sources of padding right now.. one can come from the VideoProvider and one from the user.
|
||||
|
@ -322,35 +326,37 @@ namespace BizHawk.Client.Common
|
|||
if (padding != (0, 0, 0, 0))
|
||||
{
|
||||
// TODO - add another filter just for this, its cumbersome to use final presentation... I think. but maybe there's enough similarities to justify it.
|
||||
Size size = chainInSize;
|
||||
var size = chainInSize;
|
||||
size.Width += padding.Left + padding.Right;
|
||||
size.Height += padding.Top + padding.Bottom;
|
||||
|
||||
//in case the user requested so much padding that the dimensions are now negative, just turn it to something small
|
||||
// in case the user requested so much padding that the dimensions are now negative, just turn it to something small
|
||||
if (size.Width < 1) size.Width = 1;
|
||||
if (size.Height < 1) size.Height = 1;
|
||||
|
||||
FinalPresentation fPadding = new FinalPresentation(size);
|
||||
var fPadding = new FinalPresentation(size);
|
||||
chain.AddFilter(fPadding, "padding");
|
||||
fPadding.GuiRenderer = _renderer;
|
||||
fPadding.GL = _gl;
|
||||
fPadding.Config_PadOnly = true;
|
||||
fPadding.Padding = padding;
|
||||
}
|
||||
|
||||
//add lua layer 'emu'
|
||||
// add lua layer 'emu'
|
||||
AppendApiHawkLayer(chain, DisplaySurfaceID.EmuCore);
|
||||
|
||||
if(includeUserFilters)
|
||||
if (includeUserFilters)
|
||||
{
|
||||
if (GlobalConfig.DispPrescale != 1)
|
||||
{
|
||||
var fPrescale = new PrescaleFilter() { Scale = GlobalConfig.DispPrescale };
|
||||
chain.AddFilter(fPrescale, "user_prescale");
|
||||
}
|
||||
}
|
||||
|
||||
// add user-selected retro shader
|
||||
if (selectedChain != null)
|
||||
{
|
||||
AppendRetroShaderChain(chain, "retroShader", selectedChain, selectedChainProperties);
|
||||
}
|
||||
|
||||
// AutoPrescale makes no sense for a None final filter
|
||||
if (GlobalConfig.DispAutoPrescale && GlobalConfig.DispFinalFilter != (int)FinalPresentation.eFilterOption.None)
|
||||
|
@ -359,22 +365,18 @@ namespace BizHawk.Client.Common
|
|||
chain.AddFilter(apf, "auto_prescale");
|
||||
}
|
||||
|
||||
//choose final filter
|
||||
var finalFilter = FinalPresentation.eFilterOption.None;
|
||||
if (GlobalConfig.DispFinalFilter == 1)
|
||||
// choose final filter
|
||||
var finalFilter = GlobalConfig.DispFinalFilter switch
|
||||
{
|
||||
finalFilter = FinalPresentation.eFilterOption.Bilinear;
|
||||
}
|
||||
1 => FinalPresentation.eFilterOption.Bilinear,
|
||||
2 => FinalPresentation.eFilterOption.Bicubic,
|
||||
_ => FinalPresentation.eFilterOption.None
|
||||
};
|
||||
|
||||
if (GlobalConfig.DispFinalFilter == 2)
|
||||
{
|
||||
finalFilter = FinalPresentation.eFilterOption.Bicubic;
|
||||
}
|
||||
|
||||
//if bicubic is selected and unavailable, don't use it. use bilinear instead I guess
|
||||
// if bicubic is selected and unavailable, don't use it. use bilinear instead I guess
|
||||
if (finalFilter == FinalPresentation.eFilterOption.Bicubic)
|
||||
{
|
||||
if (_shaderChainBicubic == null || !_shaderChainBicubic.Available)
|
||||
if (_shaderChainBicubic is not { Available: true })
|
||||
{
|
||||
finalFilter = FinalPresentation.eFilterOption.Bilinear;
|
||||
}
|
||||
|
@ -398,18 +400,20 @@ namespace BizHawk.Client.Common
|
|||
// and OSD goes on top of that
|
||||
// TODO - things break if this isn't present (the final presentation filter gets messed up when used with prescaling)
|
||||
// so, always include it (we'll handle this flag in the callback to do no rendering)
|
||||
if (true /*includeOSD*/) chain.AddFilter(fOSD, "osd");
|
||||
if (true /*includeOSD*/)
|
||||
{
|
||||
chain.AddFilter(fOSD, "osd");
|
||||
}
|
||||
|
||||
return chain;
|
||||
}
|
||||
|
||||
private void AppendRetroShaderChain(FilterProgram program, string name, RetroShaderChain retroChain, Dictionary<string, object> properties)
|
||||
private static void AppendRetroShaderChain(FilterProgram program, string name, RetroShaderChain retroChain, Dictionary<string, object> properties)
|
||||
{
|
||||
for (int i = 0; i < retroChain.Passes.Length; i++)
|
||||
for (var i = 0; i < retroChain.Passes.Length; i++)
|
||||
{
|
||||
var pass = retroChain.Passes[i];
|
||||
var rsp = new RetroShaderPass(retroChain, i);
|
||||
string fname = $"{name}[{i}]";
|
||||
var fname = $"{name}[{i}]";
|
||||
program.AddFilter(rsp, fname);
|
||||
rsp.Parameters = properties;
|
||||
}
|
||||
|
@ -423,13 +427,13 @@ namespace BizHawk.Client.Common
|
|||
return;
|
||||
}
|
||||
|
||||
Texture2d luaNativeTexture = _apiHawkSurfaceFrugalizers[surfaceID].Get(luaNativeSurface);
|
||||
var luaNativeTexture = _apiHawkSurfaceFrugalizers[surfaceID].Get(luaNativeSurface);
|
||||
var fLuaLayer = new LuaLayer();
|
||||
fLuaLayer.SetTexture(luaNativeTexture);
|
||||
chain.AddFilter(fLuaLayer, surfaceID.GetName());
|
||||
}
|
||||
|
||||
protected virtual Point GraphicsControlPointToClient(Point p) => throw new NotImplementedException();
|
||||
protected abstract Point GraphicsControlPointToClient(Point p);
|
||||
|
||||
/// <summary>
|
||||
/// Using the current filter program, turn a mouse coordinate from window space to the original emulator screen space.
|
||||
|
@ -454,7 +458,7 @@ namespace BizHawk.Client.Common
|
|||
/// </summary>
|
||||
public Point TransformPoint(Point p)
|
||||
{
|
||||
//now, if there's no filter program active, just give up
|
||||
// now, if there's no filter program active, just give up
|
||||
if (_currentFilterProgram == null)
|
||||
{
|
||||
return p;
|
||||
|
@ -466,9 +470,9 @@ namespace BizHawk.Client.Common
|
|||
return new((int)v.X, (int)v.Y);
|
||||
}
|
||||
|
||||
public virtual Size GetPanelNativeSize() => throw new NotImplementedException();
|
||||
public abstract Size GetPanelNativeSize();
|
||||
|
||||
protected virtual Size GetGraphicsControlSize() => throw new NotImplementedException();
|
||||
protected abstract Size GetGraphicsControlSize();
|
||||
|
||||
/// <summary>
|
||||
/// This will receive an emulated output frame from an IVideoProvider and run it through the complete frame processing pipeline
|
||||
|
@ -476,7 +480,7 @@ namespace BizHawk.Client.Common
|
|||
/// </summary>
|
||||
public void UpdateSource(IVideoProvider videoProvider)
|
||||
{
|
||||
bool displayNothing = GlobalConfig.DispSpeedupFeatures == 0;
|
||||
var displayNothing = GlobalConfig.DispSpeedupFeatures == 0;
|
||||
var job = new JobInfo
|
||||
{
|
||||
VideoProvider = videoProvider,
|
||||
|
@ -485,6 +489,7 @@ namespace BizHawk.Client.Common
|
|||
IncludeOSD = true,
|
||||
IncludeUserFilters = true
|
||||
};
|
||||
|
||||
UpdateSourceInternal(job);
|
||||
}
|
||||
|
||||
|
@ -512,6 +517,7 @@ namespace BizHawk.Client.Common
|
|||
IncludeOSD = includeOSD,
|
||||
IncludeUserFilters = true,
|
||||
};
|
||||
|
||||
UpdateSourceInternal(job);
|
||||
return job.OffscreenBb;
|
||||
}
|
||||
|
@ -524,37 +530,42 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
VideoProvider = videoProvider,
|
||||
Simulate = false,
|
||||
ChainOutsize = new Size(videoProvider.BufferWidth, videoProvider.BufferHeight),
|
||||
ChainOutsize = new(videoProvider.BufferWidth, videoProvider.BufferHeight),
|
||||
Offscreen = true,
|
||||
IncludeOSD = false,
|
||||
IncludeUserFilters = false,
|
||||
};
|
||||
|
||||
UpdateSourceInternal(job);
|
||||
return job.OffscreenBb;
|
||||
}
|
||||
|
||||
private class FakeVideoProvider : IVideoProvider
|
||||
{
|
||||
public FakeVideoProvider(int bw, int bh, int vw, int vh)
|
||||
{
|
||||
BufferWidth = bw;
|
||||
BufferHeight = bh;
|
||||
VirtualWidth = vw;
|
||||
VirtualHeight = vh;
|
||||
}
|
||||
|
||||
public int[] GetVideoBuffer()
|
||||
=> Array.Empty<int>();
|
||||
|
||||
public int VirtualWidth { get; set; }
|
||||
public int VirtualHeight { get; set; }
|
||||
public int VirtualWidth { get; }
|
||||
public int VirtualHeight { get; }
|
||||
public int BufferWidth { get; }
|
||||
public int BufferHeight { get; }
|
||||
public int BackgroundColor => 0;
|
||||
|
||||
public int BufferWidth { get; set; }
|
||||
public int BufferHeight { get; set; }
|
||||
public int BackgroundColor { get; set; }
|
||||
|
||||
/// <exception cref="InvalidOperationException">always</exception>
|
||||
public int VsyncNumerator => throw new InvalidOperationException();
|
||||
|
||||
/// <exception cref="InvalidOperationException">always</exception>
|
||||
public int VsyncDenominator => throw new InvalidOperationException();
|
||||
public int VsyncNumerator => throw new NotImplementedException();
|
||||
public int VsyncDenominator => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void FixRatio(float x, float y, int inw, int inh, out int outW, out int outH)
|
||||
private static void FixRatio(float x, float y, int inw, int inh, out int outW, out int outH)
|
||||
{
|
||||
float ratio = x / y;
|
||||
var ratio = x / y;
|
||||
if (ratio <= 1)
|
||||
{
|
||||
// taller. weird. expand height.
|
||||
|
@ -576,17 +587,17 @@ namespace BizHawk.Client.Common
|
|||
/// </summary>
|
||||
public Size CalculateClientSize(IVideoProvider videoProvider, int zoom)
|
||||
{
|
||||
bool arActive = GlobalConfig.DispFixAspectRatio;
|
||||
bool arSystem = GlobalConfig.DispManagerAR == EDispManagerAR.System;
|
||||
bool arCustom = GlobalConfig.DispManagerAR == EDispManagerAR.CustomSize;
|
||||
bool arCustomRatio = GlobalConfig.DispManagerAR == EDispManagerAR.CustomRatio;
|
||||
bool arCorrect = arSystem || arCustom || arCustomRatio;
|
||||
bool arInteger = GlobalConfig.DispFixScaleInteger;
|
||||
var arActive = GlobalConfig.DispFixAspectRatio;
|
||||
var arSystem = GlobalConfig.DispManagerAR == EDispManagerAR.System;
|
||||
var arCustom = GlobalConfig.DispManagerAR == EDispManagerAR.CustomSize;
|
||||
var arCustomRatio = GlobalConfig.DispManagerAR == EDispManagerAR.CustomRatio;
|
||||
var arCorrect = arSystem || arCustom || arCustomRatio;
|
||||
var arInteger = GlobalConfig.DispFixScaleInteger;
|
||||
|
||||
int bufferWidth = videoProvider.BufferWidth;
|
||||
int bufferHeight = videoProvider.BufferHeight;
|
||||
int virtualWidth = videoProvider.VirtualWidth;
|
||||
int virtualHeight = videoProvider.VirtualHeight;
|
||||
var bufferWidth = videoProvider.BufferWidth;
|
||||
var bufferHeight = videoProvider.BufferHeight;
|
||||
var virtualWidth = videoProvider.VirtualWidth;
|
||||
var virtualHeight = videoProvider.VirtualHeight;
|
||||
|
||||
if (arCustom)
|
||||
{
|
||||
|
@ -596,17 +607,18 @@ namespace BizHawk.Client.Common
|
|||
|
||||
if (arCustomRatio)
|
||||
{
|
||||
FixRatio(GlobalConfig.DispCustomUserArx, GlobalConfig.DispCustomUserAry, videoProvider.BufferWidth, videoProvider.BufferHeight, out virtualWidth, out virtualHeight);
|
||||
FixRatio(GlobalConfig.DispCustomUserArx, GlobalConfig.DispCustomUserAry,
|
||||
videoProvider.BufferWidth, videoProvider.BufferHeight, out virtualWidth, out virtualHeight);
|
||||
}
|
||||
|
||||
//TODO: it is bad that this is happening outside the filter chain
|
||||
//the filter chain has the ability to add padding...
|
||||
//for now, we have to have some hacks. this could be improved by refactoring the filter setup hacks to be in one place only though
|
||||
//could the PADDING be done as filters too? that would be nice.
|
||||
// TODO: it is bad that this is happening outside the filter chain
|
||||
// the filter chain has the ability to add padding...
|
||||
// for now, we have to have some hacks. this could be improved by refactoring the filter setup hacks to be in one place only though
|
||||
// could the PADDING be done as filters too? that would be nice.
|
||||
var fCoreScreenControl = CreateCoreScreenControl();
|
||||
if(fCoreScreenControl != null)
|
||||
if (fCoreScreenControl != null)
|
||||
{
|
||||
var sz = fCoreScreenControl.PresizeInput("default", new Size(bufferWidth, bufferHeight));
|
||||
var sz = fCoreScreenControl.PresizeInput("default", new(bufferWidth, bufferHeight));
|
||||
virtualWidth = bufferWidth = sz.Width;
|
||||
virtualHeight = bufferHeight = sz.Height;
|
||||
}
|
||||
|
@ -619,21 +631,14 @@ namespace BizHawk.Client.Common
|
|||
bufferWidth += padding.Horizontal;
|
||||
bufferHeight += padding.Vertical;
|
||||
|
||||
//in case the user requested so much padding that the dimensions are now negative, just turn it to something small.
|
||||
// in case the user requested so much padding that the dimensions are now negative, just turn it to something small.
|
||||
if (virtualWidth < 1) virtualWidth = 1;
|
||||
if (virtualHeight < 1) virtualHeight = 1;
|
||||
if (bufferWidth < 1) bufferWidth = 1;
|
||||
if (bufferHeight < 1) bufferHeight = 1;
|
||||
|
||||
// old stuff
|
||||
var fvp = new FakeVideoProvider
|
||||
{
|
||||
BufferWidth = bufferWidth,
|
||||
BufferHeight = bufferHeight,
|
||||
VirtualWidth = virtualWidth,
|
||||
VirtualHeight = virtualHeight
|
||||
};
|
||||
|
||||
var fvp = new FakeVideoProvider(bufferWidth, bufferHeight, virtualWidth, virtualHeight);
|
||||
Size chainOutsize;
|
||||
|
||||
if (arActive)
|
||||
|
@ -643,51 +648,45 @@ namespace BizHawk.Client.Common
|
|||
if (arInteger)
|
||||
{
|
||||
// ALERT COPYPASTE LAUNDROMAT
|
||||
Vector2 AR = new(virtualWidth / (float) bufferWidth, virtualHeight / (float) bufferHeight);
|
||||
float targetPar = AR.X / AR.Y;
|
||||
var AR = new Vector2(virtualWidth / (float) bufferWidth, virtualHeight / (float) bufferHeight);
|
||||
var targetPar = AR.X / AR.Y;
|
||||
|
||||
// this would malfunction for AR <= 0.5 or AR >= 2.0
|
||||
// EDIT - in fact, we have AR like that coming from PSX, sometimes, so maybe we should solve this better
|
||||
Vector2 PS = new Vector2(1, 1);
|
||||
var PS = Vector2.One; // this would malfunction for AR <= 0.5 or AR >= 2.0
|
||||
|
||||
// here's how we define zooming, in this case:
|
||||
// make sure each step is an increment of zoom for at least one of the dimensions (or maybe both of them)
|
||||
// look for the increment which helps the AR the best
|
||||
//TODO - this cant possibly support scale factors like 1.5x
|
||||
//TODO - also, this might be messing up zooms and stuff, we might need to run this on the output size of the filter chain
|
||||
for (int i = 1; i < zoom;i++)
|
||||
// TODO - this cant possibly support scale factors like 1.5x
|
||||
// TODO - also, this might be messing up zooms and stuff, we might need to run this on the output size of the filter chain
|
||||
|
||||
Span<Vector2> trials = stackalloc Vector2[3];
|
||||
for (var i = 1; i < zoom; i++)
|
||||
{
|
||||
//would not be good to run this per frame, but it seems to only run when the resolution changes, etc.
|
||||
Vector2[] trials =
|
||||
{
|
||||
PS + new Vector2(1, 0),
|
||||
PS + new Vector2(0, 1),
|
||||
PS + new Vector2(1, 1)
|
||||
};
|
||||
int bestIndex = -1;
|
||||
float bestValue = 1000.0f;
|
||||
for (int t = 0; t < trials.Length; t++)
|
||||
// would not be good to run this per frame, but it seems to only run when the resolution changes, etc.
|
||||
trials[0] = PS + Vector2.UnitX;
|
||||
trials[1] = PS + Vector2.UnitY;
|
||||
trials[2] = PS + Vector2.One;
|
||||
|
||||
var bestIndex = -1;
|
||||
var bestValue = 1000.0f;
|
||||
for (var t = 0; t < trials.Length; t++)
|
||||
{
|
||||
//I.
|
||||
float testAr = trials[t].X / trials[t].Y;
|
||||
var testAr = trials[t].X / trials[t].Y;
|
||||
|
||||
// II.
|
||||
//Vector2 calc = Vector2.Multiply(trials[t], VS);
|
||||
//float test_ar = calc.X / calc.Y;
|
||||
// var calc = Vector2.Multiply(trials[t], VS);
|
||||
// var test_ar = calc.X / calc.Y;
|
||||
|
||||
// not clear which approach is superior
|
||||
float deviationLinear = Math.Abs(testAr - targetPar);
|
||||
float deviationGeom = testAr / targetPar;
|
||||
if (deviationGeom < 1)
|
||||
{
|
||||
deviationGeom = 1.0f / deviationGeom;
|
||||
}
|
||||
|
||||
float value = deviationLinear;
|
||||
if (value < bestValue)
|
||||
var deviationLinear = Math.Abs(testAr - targetPar);
|
||||
if (deviationLinear < bestValue)
|
||||
{
|
||||
bestIndex = t;
|
||||
bestValue = value;
|
||||
bestValue = deviationLinear;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -699,26 +698,26 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
}
|
||||
|
||||
chainOutsize = new Size((int)(bufferWidth * PS.X), (int)(bufferHeight * PS.Y));
|
||||
chainOutsize = new((int)(bufferWidth * PS.X), (int)(bufferHeight * PS.Y));
|
||||
}
|
||||
else
|
||||
{
|
||||
// obey the AR, but allow free scaling: just zoom the virtual size
|
||||
chainOutsize = new Size(virtualWidth * zoom, virtualHeight * zoom);
|
||||
chainOutsize = new(virtualWidth * zoom, virtualHeight * zoom);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// ar_unity:
|
||||
// just choose to zoom the buffer (make no effort to incorporate AR)
|
||||
chainOutsize = new Size(bufferWidth * zoom, bufferHeight * zoom);
|
||||
chainOutsize = new(bufferWidth * zoom, bufferHeight * zoom);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// !ar_active:
|
||||
// just choose to zoom the buffer (make no effort to incorporate AR)
|
||||
chainOutsize = new Size(bufferWidth * zoom, bufferHeight * zoom);
|
||||
chainOutsize = new(bufferWidth * zoom, bufferHeight * zoom);
|
||||
}
|
||||
|
||||
chainOutsize.Width += ClientExtraPadding.Left + ClientExtraPadding.Right;
|
||||
|
@ -738,11 +737,10 @@ namespace BizHawk.Client.Common
|
|||
// we need some other more sensible client size.
|
||||
if (filterProgram == null)
|
||||
{
|
||||
return new Size(256, 192);
|
||||
return new(256, 192);
|
||||
}
|
||||
|
||||
var size = filterProgram.Filters.Last().FindOutput().SurfaceFormat.Size;
|
||||
|
||||
var size = filterProgram.Filters[filterProgram.Filters.Count - 1].FindOutput().SurfaceFormat.Size;
|
||||
return size;
|
||||
}
|
||||
|
||||
|
@ -795,10 +793,10 @@ namespace BizHawk.Client.Common
|
|||
var vw = videoProvider.VirtualWidth;
|
||||
var vh = videoProvider.VirtualHeight;
|
||||
|
||||
//TODO: it is bad that this is happening outside the filter chain
|
||||
//the filter chain has the ability to add padding...
|
||||
//for now, we have to have some hacks. this could be improved by refactoring the filter setup hacks to be in one place only though
|
||||
//could the PADDING be done as filters too? that would be nice.
|
||||
// TODO: it is bad that this is happening outside the filter chain
|
||||
// the filter chain has the ability to add padding...
|
||||
// for now, we have to have some hacks. this could be improved by refactoring the filter setup hacks to be in one place only though
|
||||
// could the PADDING be done as filters too? that would be nice.
|
||||
var fCoreScreenControl = CreateCoreScreenControl();
|
||||
if(fCoreScreenControl != null)
|
||||
{
|
||||
|
@ -809,25 +807,26 @@ namespace BizHawk.Client.Common
|
|||
|
||||
if (GlobalConfig.DispFixAspectRatio)
|
||||
{
|
||||
if (GlobalConfig.DispManagerAR == EDispManagerAR.None)
|
||||
switch (GlobalConfig.DispManagerAR)
|
||||
{
|
||||
vw = bufferWidth;
|
||||
vh = bufferHeight;
|
||||
}
|
||||
if (GlobalConfig.DispManagerAR == EDispManagerAR.System)
|
||||
{
|
||||
//Already set
|
||||
}
|
||||
if (GlobalConfig.DispManagerAR == EDispManagerAR.CustomSize)
|
||||
{
|
||||
//not clear what any of these other options mean for "screen controlled" systems
|
||||
vw = GlobalConfig.DispCustomUserARWidth;
|
||||
vh = GlobalConfig.DispCustomUserARHeight;
|
||||
}
|
||||
if (GlobalConfig.DispManagerAR == EDispManagerAR.CustomRatio)
|
||||
{
|
||||
//not clear what any of these other options mean for "screen controlled" systems
|
||||
FixRatio(GlobalConfig.DispCustomUserArx, GlobalConfig.DispCustomUserAry, videoProvider.BufferWidth, videoProvider.BufferHeight, out vw, out vh);
|
||||
case EDispManagerAR.None:
|
||||
vw = bufferWidth;
|
||||
vh = bufferHeight;
|
||||
break;
|
||||
case EDispManagerAR.System:
|
||||
// Already set
|
||||
break;
|
||||
case EDispManagerAR.CustomSize:
|
||||
// not clear what any of these other options mean for "screen controlled" systems
|
||||
vw = GlobalConfig.DispCustomUserARWidth;
|
||||
vh = GlobalConfig.DispCustomUserARHeight;
|
||||
break;
|
||||
case EDispManagerAR.CustomRatio:
|
||||
// not clear what any of these other options mean for "screen controlled" systems
|
||||
FixRatio(GlobalConfig.DispCustomUserArx, GlobalConfig.DispCustomUserAry, videoProvider.BufferWidth, videoProvider.BufferHeight, out vw, out vh);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -884,20 +883,9 @@ namespace BizHawk.Client.Common
|
|||
fPresent.VirtualTextureSize = new(vw, vh);
|
||||
fPresent.TextureSize = new(presenterTextureWidth, presenterTextureHeight);
|
||||
fPresent.BackgroundColor = videoProvider.BackgroundColor;
|
||||
fPresent.GuiRenderer = _renderer;
|
||||
fPresent.Config_FixAspectRatio = GlobalConfig.DispFixAspectRatio;
|
||||
fPresent.Config_FixScaleInteger = GlobalConfig.DispFixScaleInteger;
|
||||
fPresent.Padding = (ClientExtraPadding.Left, ClientExtraPadding.Top, ClientExtraPadding.Right, ClientExtraPadding.Bottom);
|
||||
fPresent.AutoPrescale = GlobalConfig.DispAutoPrescale;
|
||||
|
||||
fPresent.GL = _gl;
|
||||
}
|
||||
|
||||
//POOPY. why are we delivering the GL context this way? such bad
|
||||
if (filterProgram["CoreScreenControl"] is ScreenControlNDS fNDS)
|
||||
{
|
||||
fNDS.GuiRenderer = _renderer;
|
||||
fNDS.GL = _gl;
|
||||
}
|
||||
|
||||
filterProgram.Compile("default", chainInsize, chainOutsize, !job.Offscreen);
|
||||
|
@ -938,12 +926,12 @@ namespace BizHawk.Client.Common
|
|||
//GraphicsControl.Begin(); // CRITICAL POINT for yabause+GL
|
||||
|
||||
//TODO - auto-create and age these (and dispose when old)
|
||||
int rtCounter = 0;
|
||||
|
||||
var rtCounter = 0;
|
||||
// ReSharper disable once AccessToModifiedClosure
|
||||
_currentFilterProgram.RenderTargetProvider = new DisplayManagerRenderTargetProvider(size => _shaderChainFrugalizers[rtCounter++].Get(size));
|
||||
|
||||
_gl.BeginScene();
|
||||
RunFilterChainSteps(ref rtCounter, out var rtCurr, out var inFinalTarget);
|
||||
RunFilterChainSteps(ref rtCounter, out var rtCurr, out _);
|
||||
_gl.EndScene();
|
||||
|
||||
job.OffscreenBb = rtCurr.Texture2d.Resolve();
|
||||
|
@ -977,19 +965,25 @@ namespace BizHawk.Client.Common
|
|||
inFinalTarget = true;
|
||||
break;
|
||||
default:
|
||||
throw new Exception();
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadCustomFont(Stream fontStream)
|
||||
{
|
||||
IntPtr data = Marshal.AllocCoTaskMem((int)fontStream.Length);
|
||||
byte[] fontData = new byte[fontStream.Length];
|
||||
fontStream.Read(fontData, 0, (int)fontStream.Length);
|
||||
Marshal.Copy(fontData, 0, data, (int)fontStream.Length);
|
||||
CustomFonts.AddMemoryFont(data, fontData.Length);
|
||||
fontStream.Close();
|
||||
Marshal.FreeCoTaskMem(data);
|
||||
var data = Marshal.AllocCoTaskMem((int)fontStream.Length);
|
||||
try
|
||||
{
|
||||
var fontData = new byte[fontStream.Length];
|
||||
fontStream.Read(fontData, 0, (int)fontStream.Length);
|
||||
Marshal.Copy(fontData, 0, data, (int)fontStream.Length);
|
||||
CustomFonts.AddMemoryFont(data, fontData.Length);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeCoTaskMem(data);
|
||||
fontStream.Close();
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Dictionary<DisplaySurfaceID, IDisplaySurface> _apiHawkIDToSurface = new();
|
||||
|
@ -1041,8 +1035,12 @@ namespace BizHawk.Client.Common
|
|||
if (PeekApiHawkLockedSurface(kvp.Key) == null)
|
||||
{
|
||||
var surfLocked = LockApiHawkSurface(kvp.Key, true);
|
||||
if (surfLocked != null) UnlockApiHawkSurface(surfLocked);
|
||||
if (surfLocked != null)
|
||||
{
|
||||
UnlockApiHawkSurface(surfLocked);
|
||||
}
|
||||
}
|
||||
|
||||
_apiHawkSurfaceSets[kvp.Key].SetPending(null);
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
|
@ -1056,8 +1054,16 @@ namespace BizHawk.Client.Common
|
|||
/// <exception cref="InvalidOperationException">already unlocked</exception>
|
||||
public void UnlockApiHawkSurface(IDisplaySurface surface)
|
||||
{
|
||||
if (surface is not DisplaySurface dispSurfaceImpl) throw new ArgumentException("don't mix " + nameof(IDisplaySurface) + " implementations!", nameof(surface));
|
||||
if (!_apiHawkSurfaceToID.TryGetValue(dispSurfaceImpl, out var surfaceID)) throw new InvalidOperationException("Surface was not locked as a lua surface");
|
||||
if (surface is not DisplaySurface dispSurfaceImpl)
|
||||
{
|
||||
throw new ArgumentException("don't mix " + nameof(IDisplaySurface) + " implementations!", nameof(surface));
|
||||
}
|
||||
|
||||
if (!_apiHawkSurfaceToID.TryGetValue(dispSurfaceImpl, out var surfaceID))
|
||||
{
|
||||
throw new InvalidOperationException("Surface was not locked as a lua surface");
|
||||
}
|
||||
|
||||
_apiHawkSurfaceToID.Remove(dispSurfaceImpl);
|
||||
_apiHawkIDToSurface.Remove(surfaceID);
|
||||
_apiHawkSurfaceSets[surfaceID].SetPending(dispSurfaceImpl);
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
|
||||
using BizHawk.Client.Common.Filters;
|
||||
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
|
@ -14,21 +18,22 @@ namespace BizHawk.Client.Common.FilterManager
|
|||
|
||||
public class SurfaceFormat
|
||||
{
|
||||
public SurfaceFormat(Size size) => Size = size;
|
||||
public SurfaceFormat(Size size)
|
||||
=> Size = size;
|
||||
|
||||
public Size Size { get; }
|
||||
}
|
||||
|
||||
public class SurfaceState
|
||||
public readonly ref struct SurfaceState
|
||||
{
|
||||
public SurfaceState() { }
|
||||
public SurfaceState(SurfaceFormat surfaceFormat, SurfaceDisposition surfaceDisposition = SurfaceDisposition.Unspecified)
|
||||
{
|
||||
SurfaceFormat = surfaceFormat;
|
||||
SurfaceDisposition = surfaceDisposition;
|
||||
}
|
||||
|
||||
public SurfaceFormat SurfaceFormat { get; set; }
|
||||
public SurfaceDisposition SurfaceDisposition { get; set; }
|
||||
public readonly SurfaceFormat SurfaceFormat;
|
||||
public readonly SurfaceDisposition SurfaceDisposition;
|
||||
}
|
||||
|
||||
public interface IRenderTargetProvider
|
||||
|
@ -38,7 +43,7 @@ namespace BizHawk.Client.Common.FilterManager
|
|||
|
||||
public class FilterProgram
|
||||
{
|
||||
private readonly Dictionary<string, BaseFilter> _filterNameIndex = new Dictionary<string, BaseFilter>();
|
||||
private readonly Dictionary<string, BaseFilter> _filterNameIndex = new();
|
||||
|
||||
public readonly IList<BaseFilter> Filters = new List<BaseFilter>();
|
||||
public readonly IList<ProgramStep> Program = new List<ProgramStep>();
|
||||
|
@ -63,12 +68,12 @@ namespace BizHawk.Client.Common.FilterManager
|
|||
public IGuiRenderer GuiRenderer;
|
||||
public IGL GL;
|
||||
public IRenderTargetProvider RenderTargetProvider;
|
||||
public RenderTarget GetRenderTarget(string channel = "default") { return CurrRenderTarget; }
|
||||
|
||||
public RenderTarget CurrRenderTarget;
|
||||
|
||||
public RenderTarget GetTempTarget(int width, int height)
|
||||
{
|
||||
return RenderTargetProvider.Get(new Size(width, height));
|
||||
return RenderTargetProvider.Get(new(width, height));
|
||||
}
|
||||
|
||||
public void AddFilter(BaseFilter filter, string name = "")
|
||||
|
@ -98,22 +103,24 @@ namespace BizHawk.Client.Common.FilterManager
|
|||
/// </summary>
|
||||
public Vector2 TransformPoint(string channel, Vector2 point)
|
||||
{
|
||||
foreach (var filter in Filters)
|
||||
{
|
||||
point = filter.TransformPoint(channel, point);
|
||||
}
|
||||
|
||||
point = Filters.Aggregate(point, (current, filter) => filter.TransformPoint(channel, current));
|
||||
// we COULD handle the case where the output size is 0,0, but it's not mathematically sensible
|
||||
// it should be considered a bug to call this under those conditions
|
||||
// in case the output size is zero, transform all points to zero, since the above maths may have malfunctioned
|
||||
////var size = Filters[Filters.Count - 1].FindOutput().SurfaceFormat.Size;
|
||||
////if (size.Width == 0) point.X = 0;
|
||||
////if (size.Height == 0) point.Y = 0;
|
||||
#if false
|
||||
var size = Filters[Filters.Count - 1].FindOutput().SurfaceFormat.Size;
|
||||
if (size.Width == 0) point.X = 0;
|
||||
if (size.Height == 0) point.Y = 0;
|
||||
#endif
|
||||
return point;
|
||||
}
|
||||
|
||||
public class ProgramStep
|
||||
public readonly struct ProgramStep
|
||||
{
|
||||
public readonly ProgramStepType Type;
|
||||
public readonly object Args;
|
||||
public readonly string Comment;
|
||||
|
||||
public ProgramStep(ProgramStepType type, object args, string comment = null)
|
||||
{
|
||||
Type = type;
|
||||
|
@ -121,9 +128,6 @@ namespace BizHawk.Client.Common.FilterManager
|
|||
Comment = comment;
|
||||
}
|
||||
|
||||
public ProgramStepType Type;
|
||||
public object Args;
|
||||
public string Comment;
|
||||
public override string ToString()
|
||||
{
|
||||
return Type switch
|
||||
|
@ -148,30 +152,36 @@ namespace BizHawk.Client.Common.FilterManager
|
|||
}
|
||||
|
||||
//propagate input size forwards through filter chain to allow a 'flex' filter to determine what its input will be
|
||||
Size presize = inSize;
|
||||
var presize = inSize;
|
||||
foreach (var filter in Filters)
|
||||
{
|
||||
presize = filter.PresizeInput(channel, presize);
|
||||
}
|
||||
|
||||
//propagate output size backwards through filter chain to allow a 'flex' filter to determine its output based on the desired output needs
|
||||
// propagate output size backwards through filter chain to allow a 'flex' filter to determine its output based on the desired output needs
|
||||
presize = outsize;
|
||||
for (int i = Filters.Count - 1; i >= 0; i--)
|
||||
for (var i = Filters.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var filter = Filters[i];
|
||||
presize = filter.PresizeOutput(channel, presize);
|
||||
}
|
||||
|
||||
SurfaceState currState = null;
|
||||
var obtainedFirstOutput = false;
|
||||
var currState = new SurfaceState(null);
|
||||
|
||||
for (int i = 0; i < Filters.Count; i++)
|
||||
for (var i = 0; i < Filters.Count; i++)
|
||||
{
|
||||
BaseFilter f = Filters[i];
|
||||
var f = Filters[i];
|
||||
|
||||
// check whether this filter needs input. if so, notify it of the current pipeline state
|
||||
var iosi = f.FindInput(channel);
|
||||
if (iosi != null)
|
||||
{
|
||||
if (!obtainedFirstOutput)
|
||||
{
|
||||
throw new InvalidOperationException("Obtained input before first output in filter chain");
|
||||
}
|
||||
|
||||
iosi.SurfaceFormat = currState.SurfaceFormat;
|
||||
f.SetInputFormat(channel, currState);
|
||||
|
||||
|
@ -180,23 +190,29 @@ namespace BizHawk.Client.Common.FilterManager
|
|||
continue;
|
||||
}
|
||||
|
||||
// check if the desired disposition needs to change from texture to render target
|
||||
// (if so, insert a render filter)
|
||||
if (iosi.SurfaceDisposition == SurfaceDisposition.RenderTarget && currState.SurfaceDisposition == SurfaceDisposition.Texture)
|
||||
switch (iosi.SurfaceDisposition)
|
||||
{
|
||||
var renderer = new Render();
|
||||
Filters.Insert(i, renderer);
|
||||
Compile(channel, inSize, outsize, finalTarget);
|
||||
return;
|
||||
}
|
||||
// check if the desired disposition needs to change from a render target to a texture
|
||||
// (if so, the current render target gets resolved, and made no longer current
|
||||
else if (iosi.SurfaceDisposition == SurfaceDisposition.Texture && currState.SurfaceDisposition == SurfaceDisposition.RenderTarget)
|
||||
{
|
||||
var resolver = new Resolve();
|
||||
Filters.Insert(i, resolver);
|
||||
Compile(channel, inSize, outsize, finalTarget);
|
||||
return;
|
||||
// check if the desired disposition needs to change from texture to render target
|
||||
// (if so, insert a render filter)
|
||||
case SurfaceDisposition.RenderTarget when currState.SurfaceDisposition == SurfaceDisposition.Texture:
|
||||
{
|
||||
var renderer = new Render();
|
||||
Filters.Insert(i, renderer);
|
||||
Compile(channel, inSize, outsize, finalTarget);
|
||||
return;
|
||||
}
|
||||
// check if the desired disposition needs to change from a render target to a texture
|
||||
// (if so, the current render target gets resolved, and made no longer current
|
||||
case SurfaceDisposition.Texture when currState.SurfaceDisposition == SurfaceDisposition.RenderTarget:
|
||||
{
|
||||
var resolver = new Resolve();
|
||||
Filters.Insert(i, resolver);
|
||||
Compile(channel, inSize, outsize, finalTarget);
|
||||
return;
|
||||
}
|
||||
case SurfaceDisposition.Unspecified:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,13 +220,10 @@ namespace BizHawk.Client.Common.FilterManager
|
|||
iosi = f.FindOutput(channel);
|
||||
if (iosi != null)
|
||||
{
|
||||
if (currState == null)
|
||||
if (!obtainedFirstOutput)
|
||||
{
|
||||
currState = new SurfaceState
|
||||
{
|
||||
SurfaceFormat = iosi.SurfaceFormat,
|
||||
SurfaceDisposition = iosi.SurfaceDisposition
|
||||
};
|
||||
currState = new(iosi.SurfaceFormat, iosi.SurfaceDisposition);
|
||||
obtainedFirstOutput = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -220,29 +233,36 @@ namespace BizHawk.Client.Common.FilterManager
|
|||
iosi.SurfaceDisposition = currState.SurfaceDisposition;
|
||||
}
|
||||
|
||||
bool newTarget = false;
|
||||
var newTarget = false;
|
||||
if (iosi.SurfaceFormat.Size != currState.SurfaceFormat.Size)
|
||||
{
|
||||
newTarget = true;
|
||||
else if (currState.SurfaceDisposition == SurfaceDisposition.Texture && iosi.SurfaceDisposition == SurfaceDisposition.RenderTarget)
|
||||
}
|
||||
else if (currState.SurfaceDisposition == SurfaceDisposition.Texture &&
|
||||
iosi.SurfaceDisposition == SurfaceDisposition.RenderTarget)
|
||||
{
|
||||
newTarget = true;
|
||||
}
|
||||
|
||||
if (newTarget)
|
||||
{
|
||||
currState = new SurfaceState();
|
||||
iosi.SurfaceFormat = currState.SurfaceFormat = iosi.SurfaceFormat;
|
||||
iosi.SurfaceDisposition = currState.SurfaceDisposition = iosi.SurfaceDisposition;
|
||||
Program.Add(new ProgramStep(ProgramStepType.NewTarget, currState.SurfaceFormat.Size));
|
||||
currState = new(iosi.SurfaceFormat, iosi.SurfaceDisposition);
|
||||
Program.Add(new(ProgramStepType.NewTarget, currState.SurfaceFormat.Size));
|
||||
}
|
||||
else
|
||||
{
|
||||
currState.SurfaceDisposition = iosi.SurfaceDisposition;
|
||||
currState = new(currState.SurfaceFormat, iosi.SurfaceDisposition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Program.Add(new ProgramStep(ProgramStepType.Run, i, f.GetType().Name));
|
||||
Program.Add(new(ProgramStepType.Run, i, f.GetType().Name));
|
||||
}
|
||||
|
||||
} // filter loop
|
||||
if (!obtainedFirstOutput)
|
||||
{
|
||||
throw new InvalidOperationException("Did not obtain any output in filter chain");
|
||||
}
|
||||
|
||||
// if the current output disposition is a texture, we need to render it
|
||||
if (currState.SurfaceDisposition == SurfaceDisposition.Texture)
|
||||
|
@ -256,15 +276,14 @@ namespace BizHawk.Client.Common.FilterManager
|
|||
// patch the program so that the final RenderTarget set operation is the framebuffer instead
|
||||
if (finalTarget)
|
||||
{
|
||||
for (int i = Program.Count - 1; i >= 0; i--)
|
||||
for (var i = Program.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var ps = Program[i];
|
||||
if (ps.Type == ProgramStepType.NewTarget)
|
||||
{
|
||||
var size = (Size)ps.Args;
|
||||
Debug.Assert(size == outsize);
|
||||
ps.Type = ProgramStepType.FinalTarget;
|
||||
ps.Args = size;
|
||||
Program[i] = new(ProgramStepType.FinalTarget, size, ps.Comment);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using BizHawk.Client.Common.FilterManager;
|
||||
using System.Numerics;
|
||||
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
using BizHawk.Client.Common.FilterManager;
|
||||
|
||||
// Here's how to make a filter:
|
||||
// 1. Reset your state entirely in Initialize().
|
||||
|
@ -19,13 +20,30 @@ namespace BizHawk.Client.Common.Filters
|
|||
public class BaseFilter
|
||||
{
|
||||
// initialization stuff
|
||||
public void BeginInitialization(FilterProgram program) { _ioSurfaceInfos.Clear(); FilterProgram = program; }
|
||||
public virtual void Initialize() { }
|
||||
public virtual Size PresizeInput(string channel, Size size) => size;
|
||||
public virtual Size PresizeOutput(string channel, Size size) => 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; set; }
|
||||
public void BeginInitialization(FilterProgram program)
|
||||
{
|
||||
_ioSurfaceInfos.Clear();
|
||||
FilterProgram = program;
|
||||
}
|
||||
|
||||
public virtual void Initialize()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual Size PresizeInput(string channel, Size size)
|
||||
=> size;
|
||||
|
||||
public virtual Size PresizeOutput(string channel, Size size)
|
||||
=> size;
|
||||
|
||||
// TODO - why a different param order than DeclareOutput?
|
||||
public virtual void SetInputFormat(string channel, SurfaceState state)
|
||||
{
|
||||
}
|
||||
|
||||
public Dictionary<string, object> Parameters = new();
|
||||
|
||||
public bool IsNop { get; protected set; }
|
||||
|
||||
// runtime signals
|
||||
public virtual Vector2 UntransformPoint(string channel, Vector2 point)
|
||||
|
@ -38,6 +56,7 @@ namespace BizHawk.Client.Common.Filters
|
|||
point.X *= input.SurfaceFormat.Size.Width / (float)output.SurfaceFormat.Size.Width;
|
||||
point.Y *= input.SurfaceFormat.Size.Height / (float)output.SurfaceFormat.Size.Height;
|
||||
}
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
|
@ -51,6 +70,7 @@ namespace BizHawk.Client.Common.Filters
|
|||
point.X *= output.SurfaceFormat.Size.Width / (float)input.SurfaceFormat.Size.Width;
|
||||
point.Y *= output.SurfaceFormat.Size.Height / (float)input.SurfaceFormat.Size.Height;
|
||||
}
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
|
@ -58,8 +78,13 @@ namespace BizHawk.Client.Common.Filters
|
|||
{
|
||||
InputTexture = tex;
|
||||
}
|
||||
public virtual void Run() { }
|
||||
public Texture2d GetOutput() => _outputTexture;
|
||||
|
||||
public virtual void Run()
|
||||
{
|
||||
}
|
||||
|
||||
public Texture2d GetOutput()
|
||||
=> _outputTexture;
|
||||
|
||||
// filter actions
|
||||
protected void YieldOutput(Texture2d tex)
|
||||
|
@ -121,20 +146,12 @@ namespace BizHawk.Client.Common.Filters
|
|||
return iosi;
|
||||
}
|
||||
|
||||
private readonly List<IOSurfaceInfo> _ioSurfaceInfos = new List<IOSurfaceInfo>();
|
||||
private readonly List<IOSurfaceInfo> _ioSurfaceInfos = new();
|
||||
|
||||
|
||||
private IOSurfaceInfo FindIOSurfaceInfo(string channel, SurfaceDirection direction)
|
||||
{
|
||||
foreach (var iosi in _ioSurfaceInfos)
|
||||
{
|
||||
if (iosi.Channel == channel && iosi.SurfaceDirection == direction)
|
||||
{
|
||||
return iosi;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return _ioSurfaceInfos.Find(iosi => iosi.Channel == channel && iosi.SurfaceDirection == direction);
|
||||
}
|
||||
|
||||
public class IOSurfaceInfo
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.Numerics;
|
||||
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
using BizHawk.Client.Common.FilterManager;
|
||||
|
@ -28,19 +29,21 @@ namespace BizHawk.Client.Common.Filters
|
|||
/// <summary>
|
||||
/// In case you want to do it yourself
|
||||
/// </summary>
|
||||
public LetterboxingLogic() { }
|
||||
public LetterboxingLogic()
|
||||
{
|
||||
}
|
||||
|
||||
// do maths on the viewport and the native resolution and the user settings to get a display rectangle
|
||||
public LetterboxingLogic(bool maintainAspect, bool maintainInteger, int targetWidth, int targetHeight, int sourceWidth, int sourceHeight, Size textureSize, Size virtualSize)
|
||||
{
|
||||
int textureWidth = textureSize.Width;
|
||||
int textureHeight = textureSize.Height;
|
||||
int virtualWidth = virtualSize.Width;
|
||||
int virtualHeight = virtualSize.Height;
|
||||
var textureWidth = textureSize.Width;
|
||||
var textureHeight = textureSize.Height;
|
||||
var virtualWidth = virtualSize.Width;
|
||||
var virtualHeight = virtualSize.Height;
|
||||
|
||||
//zero 02-jun-2014 - we passed these in, but ignored them. kind of weird..
|
||||
int oldSourceWidth = sourceWidth;
|
||||
int oldSourceHeight = sourceHeight;
|
||||
// zero 02-jun-2014 - we passed these in, but ignored them. kind of weird..
|
||||
var oldSourceWidth = sourceWidth;
|
||||
var oldSourceHeight = sourceHeight;
|
||||
sourceWidth = virtualWidth;
|
||||
sourceHeight = virtualHeight;
|
||||
|
||||
|
@ -50,8 +53,8 @@ namespace BizHawk.Client.Common.Filters
|
|||
maintainInteger = false;
|
||||
}
|
||||
|
||||
float widthScale = (float)targetWidth / sourceWidth;
|
||||
float heightScale = (float)targetHeight / sourceHeight;
|
||||
var widthScale = (float)targetWidth / sourceWidth;
|
||||
var heightScale = (float)targetHeight / sourceHeight;
|
||||
|
||||
if (maintainAspect
|
||||
// zero 20-jul-2014 - hacks upon hacks, this function needs rewriting
|
||||
|
@ -68,61 +71,60 @@ namespace BizHawk.Client.Common.Filters
|
|||
// apply the zooming algorithm (pasted and reworked, for now)
|
||||
// ALERT COPYPASTE LAUNDROMAT
|
||||
|
||||
Vector2 AR = new(virtualWidth / (float) textureWidth, virtualHeight / (float) textureHeight);
|
||||
float targetPar = (AR.X / AR.Y);
|
||||
Vector2 PS = new Vector2(1, 1); //this would malfunction for AR <= 0.5 or AR >= 2.0
|
||||
var AR = new Vector2(virtualWidth / (float) textureWidth, virtualHeight / (float) textureHeight);
|
||||
var targetPar = AR.X / AR.Y;
|
||||
var PS = Vector2.One; // this would malfunction for AR <= 0.5 or AR >= 2.0
|
||||
|
||||
for(;;)
|
||||
Span<Vector2> trials = stackalloc Vector2[3];
|
||||
Span<bool> trialsLimited = stackalloc bool[3];
|
||||
while (true)
|
||||
{
|
||||
// TODO - would be good not to run this per frame....
|
||||
Vector2[] trials =
|
||||
{
|
||||
PS + new Vector2(1, 0),
|
||||
PS + new Vector2(0, 1),
|
||||
PS + new Vector2(1, 1)
|
||||
};
|
||||
trials[0] = PS + Vector2.UnitX;
|
||||
trials[1] = PS + Vector2.UnitY;
|
||||
trials[2] = PS + Vector2.One;
|
||||
|
||||
bool[] trialsLimited = { false, false, false };
|
||||
int bestIndex = -1;
|
||||
float bestValue = 1000.0f;
|
||||
for (int t = 0; t < trials.Length; t++)
|
||||
var bestIndex = -1;
|
||||
var bestValue = 1000.0f;
|
||||
for (var t = 0; t < trials.Length; t++)
|
||||
{
|
||||
Vector2 vTrial = trials[t];
|
||||
var vTrial = trials[t];
|
||||
trialsLimited[t] = false;
|
||||
|
||||
//check whether this is going to exceed our allotted area
|
||||
int testVw = (int)(vTrial.X * textureWidth);
|
||||
int testVh = (int)(vTrial.Y * textureHeight);
|
||||
var testVw = (int)(vTrial.X * textureWidth);
|
||||
var testVh = (int)(vTrial.Y * textureHeight);
|
||||
if (testVw > targetWidth) trialsLimited[t] = true;
|
||||
if (testVh > targetHeight) trialsLimited[t] = true;
|
||||
|
||||
// I.
|
||||
float testAr = vTrial.X / vTrial.Y;
|
||||
var testAr = vTrial.X / vTrial.Y;
|
||||
|
||||
// II.
|
||||
// Vector2 calc = Vector2.Multiply(trials[t], VS);
|
||||
// float test_ar = calc.X / calc.Y;
|
||||
// var calc = Vector2.Multiply(trials[t], VS);
|
||||
// var test_ar = calc.X / calc.Y;
|
||||
|
||||
// not clear which approach is superior
|
||||
float deviationLinear = Math.Abs(testAr - targetPar);
|
||||
float deviationGeom = testAr / targetPar;
|
||||
if (deviationGeom < 1) deviationGeom = 1.0f / deviationGeom;
|
||||
|
||||
float value = deviationLinear;
|
||||
if (value < bestValue)
|
||||
var deviationLinear = Math.Abs(testAr - targetPar);
|
||||
if (deviationLinear < bestValue)
|
||||
{
|
||||
bestIndex = t;
|
||||
bestValue = value;
|
||||
bestValue = deviationLinear;
|
||||
}
|
||||
}
|
||||
|
||||
// last result was best, so bail out
|
||||
if (bestIndex == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// if the winner ran off the edge, bail out
|
||||
if (trialsLimited[bestIndex])
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
PS = trials[bestIndex];
|
||||
}
|
||||
|
@ -132,8 +134,10 @@ namespace BizHawk.Client.Common.Filters
|
|||
// vh = (int)(PS.Y * oldSourceHeight);
|
||||
vw = (int)(PS.X * sourceWidth);
|
||||
vh = (int)(PS.Y * sourceHeight);
|
||||
#if false
|
||||
widthScale = PS.X;
|
||||
heightScale = PS.Y;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -154,17 +158,20 @@ namespace BizHawk.Client.Common.Filters
|
|||
vh = targetHeight;
|
||||
}
|
||||
|
||||
//determine letterboxing parameters
|
||||
// determine letterboxing parameters
|
||||
vx = (targetWidth - vw) / 2;
|
||||
vy = (targetHeight - vh) / 2;
|
||||
|
||||
// zero 09-oct-2014 - changed this for TransformPoint. scenario: basic 1x (but system-specified AR) NES window.
|
||||
// vw would be 293 but WidthScale would be 1.0. I think it should be something different.
|
||||
// FinalPresentation doesn't use the LL.WidthScale, so this is unlikely to be breaking anything old that depends on it
|
||||
// WidthScale = widthScale;
|
||||
// HeightScale = heightScale;
|
||||
#if false
|
||||
WidthScale = widthScale;
|
||||
HeightScale = heightScale;
|
||||
#else
|
||||
WidthScale = (float)vw / oldSourceWidth;
|
||||
HeightScale = (float)vh / oldSourceHeight;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -173,34 +180,26 @@ namespace BizHawk.Client.Common.Filters
|
|||
/// </summary>
|
||||
public class ScreenControlNDS : BaseFilter
|
||||
{
|
||||
public IGL GL;
|
||||
public IGuiRenderer GuiRenderer;
|
||||
private readonly NDS _nds;
|
||||
|
||||
private readonly NDS nds;
|
||||
// TODO: actually use this
|
||||
#if false
|
||||
private bool Nop = false;
|
||||
#endif
|
||||
|
||||
//TODO: actually use this
|
||||
private bool nop = false;
|
||||
// matrices used for transforming screens
|
||||
private Matrix4x4 matTop, matBot;
|
||||
private Matrix4x4 matTopInvert, matBotInvert;
|
||||
|
||||
//matrices used for transforming screens
|
||||
private Matrix4 matTop, matBot;
|
||||
private Matrix4 matTopInvert, matBotInvert;
|
||||
|
||||
//final output area size
|
||||
// final output area size
|
||||
private Size outputSize;
|
||||
|
||||
private static float Round(float f) { return (float)Math.Round(f); }
|
||||
|
||||
//TODO: put somewhere in extension methods useful for fixing deficiencies in opentk matrix types
|
||||
private static Vector2 Transform(Matrix4 m, Vector2 v)
|
||||
{
|
||||
var r = new Vector4(v.X,v.Y,0,1) * m;
|
||||
return new Vector2(r.X, r.Y);
|
||||
}
|
||||
private static float Round(float f)
|
||||
=> (float)Math.Round(f);
|
||||
|
||||
public ScreenControlNDS(NDS nds)
|
||||
{
|
||||
//not sure if we actually need this nds instance yet
|
||||
this.nds = nds;
|
||||
_nds = nds;
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
|
@ -211,63 +210,65 @@ namespace BizHawk.Client.Common.Filters
|
|||
|
||||
private void CrunchNumbers()
|
||||
{
|
||||
MatrixStack top = new MatrixStack(), bot = new MatrixStack();
|
||||
MatrixStack top = new(), bot = new();
|
||||
|
||||
//-----------------------------------
|
||||
//set up transforms for each screen based on screen control values
|
||||
//this will be TRICKY depending on how many features we have, but once it's done, everything should be easy
|
||||
// set up transforms for each screen based on screen control values
|
||||
// this will be TRICKY depending on how many features we have, but once it's done, everything should be easy
|
||||
|
||||
var settings = nds.GetSettings();
|
||||
var settings = _nds.GetSettings();
|
||||
|
||||
//gap only applies to vertical, I guess
|
||||
if (settings.ScreenLayout == NDS.ScreenLayoutKind.Vertical)
|
||||
switch (settings.ScreenLayout)
|
||||
{
|
||||
bot.Translate(0, 192);
|
||||
bot.Translate(0, settings.ScreenGap);
|
||||
}
|
||||
else if (settings.ScreenLayout == NDS.ScreenLayoutKind.Horizontal)
|
||||
{
|
||||
bot.Translate(256, 0);
|
||||
}
|
||||
else if (settings.ScreenLayout == NDS.ScreenLayoutKind.Top)
|
||||
{
|
||||
//do nothing here, we'll discard bottom screen
|
||||
//gap only applies to vertical, I guess
|
||||
case NDS.ScreenLayoutKind.Vertical:
|
||||
bot.Translate(0, 192);
|
||||
bot.Translate(0, settings.ScreenGap);
|
||||
break;
|
||||
case NDS.ScreenLayoutKind.Horizontal:
|
||||
bot.Translate(256, 0);
|
||||
break;
|
||||
case NDS.ScreenLayoutKind.Top:
|
||||
case NDS.ScreenLayoutKind.Bottom:
|
||||
// do nothing here, we'll discard the other screen
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
//this doesn't make any sense, it's likely to be too much for a monitor to gracefully handle too
|
||||
// this doesn't make any sense, it's likely to be too much for a monitor to gracefully handle too
|
||||
if (settings.ScreenLayout != NDS.ScreenLayoutKind.Horizontal)
|
||||
{
|
||||
int rot = 0;
|
||||
if (settings.ScreenRotation == NDS.ScreenRotationKind.Rotate90) rot = 90;
|
||||
if (settings.ScreenRotation == NDS.ScreenRotationKind.Rotate180) rot = 180;
|
||||
if (settings.ScreenRotation == NDS.ScreenRotationKind.Rotate270) rot = 270;
|
||||
var rot = settings.ScreenRotation switch
|
||||
{
|
||||
NDS.ScreenRotationKind.Rotate90 => 90,
|
||||
NDS.ScreenRotationKind.Rotate180 => 180,
|
||||
NDS.ScreenRotationKind.Rotate270 => 270,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
top.RotateZ(rot);
|
||||
bot.RotateZ(rot);
|
||||
}
|
||||
|
||||
//-----------------------------------
|
||||
|
||||
//TODO: refactor some of the below into a class that doesn't require having top and bottom replica code
|
||||
// TODO: refactor some of the below into a class that doesn't require having top and bottom replica code
|
||||
|
||||
matTop = top.Top;
|
||||
matBot = bot.Top;
|
||||
matTopInvert = matTop.Inverted();
|
||||
matBotInvert = matBot.Inverted();
|
||||
|
||||
//apply transforms from standard input screen positions to output screen positions
|
||||
Vector2 top_TL = Transform(matTop, new Vector2(0, 0));
|
||||
Vector2 top_TR = Transform(matTop, new Vector2(256, 0));
|
||||
Vector2 top_BL = Transform(matTop, new Vector2(0, 192));
|
||||
Vector2 top_BR = Transform(matTop, new Vector2(256, 192));
|
||||
Vector2 bot_TL = Transform(matBot, new Vector2(0, 0));
|
||||
Vector2 bot_TR = Transform(matBot, new Vector2(256, 0));
|
||||
Vector2 bot_BL = Transform(matBot, new Vector2(0, 192));
|
||||
Vector2 bot_BR = Transform(matBot, new Vector2(256, 192));
|
||||
// apply transforms from standard input screen positions to output screen positions
|
||||
var top_TL = Vector2.Transform(new(0, 0), matTop);
|
||||
var top_TR = Vector2.Transform(new(256, 0), matTop);
|
||||
var top_BL = Vector2.Transform(new(0, 192), matTop);
|
||||
var top_BR = Vector2.Transform(new(256, 192), matTop);
|
||||
var bot_TL = Vector2.Transform(new(0, 0), matBot);
|
||||
var bot_TR = Vector2.Transform(new(256, 0), matBot);
|
||||
var bot_BL = Vector2.Transform(new(0, 192), matBot);
|
||||
var bot_BR = Vector2.Transform(new(256, 192), matBot);
|
||||
|
||||
//in case of math errors in the transforms, we'll round this stuff.. although...
|
||||
//we're gonna use matrix transforms for drawing later, so it isn't extremely helpful
|
||||
// in case of math errors in the transforms, we'll round this stuff.. although...
|
||||
// we're gonna use matrix transforms for drawing later, so it isn't extremely helpful
|
||||
|
||||
//TODO - need more consideration of numerical precision here, because the typical case should be rock solid
|
||||
// TODO - need more consideration of numerical precision here, because the typical case should be rock solid
|
||||
top_TL.X = Round(top_TL.X); top_TL.Y = Round(top_TL.Y);
|
||||
top_TR.X = Round(top_TR.X); top_TR.Y = Round(top_TR.Y);
|
||||
top_BL.X = Round(top_BL.X); top_BL.Y = Round(top_BL.Y);
|
||||
|
@ -277,13 +278,15 @@ namespace BizHawk.Client.Common.Filters
|
|||
bot_BL.X = Round(bot_BL.X); bot_BL.Y = Round(bot_BL.Y);
|
||||
bot_BR.X = Round(bot_BR.X); bot_BR.Y = Round(bot_BR.Y);
|
||||
|
||||
////precalculate some useful metrics
|
||||
//top_width = (int)(top_TR.X - top_TL.X);
|
||||
//top_height = (int)(top_BR.Y - top_TR.Y);
|
||||
//bot_width = (int)(bot_TR.X - bot_TL.X);
|
||||
//bot_height = (int)(bot_BR.Y - bot_TR.Y);
|
||||
#if false
|
||||
// precalculate some useful metrics
|
||||
top_width = (int)(top_TR.X - top_TL.X);
|
||||
top_height = (int)(top_BR.Y - top_TR.Y);
|
||||
bot_width = (int)(bot_TR.X - bot_TL.X);
|
||||
bot_height = (int)(bot_BR.Y - bot_TR.Y);
|
||||
#endif
|
||||
|
||||
//the size can now be determined in a kind of fluffily magical way by transforming edges and checking the bounds
|
||||
// the size can now be determined in a kind of fluffily magical way by transforming edges and checking the bounds
|
||||
float fxmin = 100000, fymin = 100000, fxmax = -100000, fymax = -100000;
|
||||
if (settings.ScreenLayout != NDS.ScreenLayoutKind.Bottom)
|
||||
{
|
||||
|
@ -300,24 +303,37 @@ namespace BizHawk.Client.Common.Filters
|
|||
fymax = Math.Max(Math.Max(Math.Max(Math.Max(bot_TL.Y, bot_TR.Y), bot_BL.Y), bot_BR.Y), fymax);
|
||||
}
|
||||
|
||||
//relocate whatever we got back into the viewable area
|
||||
// relocate whatever we got back into the viewable area
|
||||
top.Translate(-fxmin, -fymin);
|
||||
bot.Translate(-fxmin, -fymin);
|
||||
matTop = top.Top;
|
||||
matBot = bot.Top;
|
||||
|
||||
//do some more rounding
|
||||
for (int r = 0; r < 4; r++)
|
||||
for (int c = 0; c < 4; c++)
|
||||
// do some more rounding
|
||||
unsafe
|
||||
{
|
||||
fixed (Matrix4x4* matTopP = &matTop, matBotP = &matBot)
|
||||
{
|
||||
if (Math.Abs(matTop[r, c]) < 0.0000001f) matTop[r, c] = 0;
|
||||
if (Math.Abs(matBot[r, c]) < 0.0000001f) matBot[r, c] = 0;
|
||||
float* matTopF = (float*)matTopP, matBotF = (float*)matBotP;
|
||||
for (var i = 0; i < 4 * 4; i++)
|
||||
{
|
||||
if (Math.Abs(matTopF[i]) < 0.0000001f)
|
||||
{
|
||||
matTopF[i] = 0;
|
||||
}
|
||||
|
||||
if (Math.Abs(matBotF[i]) < 0.0000001f)
|
||||
{
|
||||
matBotF[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
matTopInvert = matTop.Inverted();
|
||||
matBotInvert = matBot.Inverted();
|
||||
Matrix4x4.Invert(matTop, out matTopInvert);
|
||||
Matrix4x4.Invert(matBot, out matBotInvert);
|
||||
|
||||
outputSize = new Size((int)(fxmax-fxmin), (int)(fymax-fymin));
|
||||
outputSize = new((int)(fxmax - fxmin), (int)(fymax - fymin));
|
||||
}
|
||||
|
||||
public override Size PresizeInput(string channel, Size size)
|
||||
|
@ -335,86 +351,100 @@ namespace BizHawk.Client.Common.Filters
|
|||
public override void SetInputFormat(string channel, SurfaceState state)
|
||||
{
|
||||
CrunchNumbers();
|
||||
var ss = new SurfaceState(new SurfaceFormat(outputSize), SurfaceDisposition.RenderTarget);
|
||||
var ss = new SurfaceState(new(outputSize), SurfaceDisposition.RenderTarget);
|
||||
DeclareOutput(ss, channel);
|
||||
}
|
||||
|
||||
public override Vector2 UntransformPoint(string channel, Vector2 point)
|
||||
{
|
||||
var settings = nds.GetSettings();
|
||||
bool invert = settings.ScreenInvert
|
||||
var settings = _nds.GetSettings();
|
||||
var invert = settings.ScreenInvert
|
||||
&& settings.ScreenLayout != NDS.ScreenLayoutKind.Top
|
||||
&& settings.ScreenLayout != NDS.ScreenLayoutKind.Bottom;
|
||||
|
||||
point = Transform(invert ? matTopInvert : matBotInvert, point);
|
||||
point = Vector2.Transform(point, invert ? matTopInvert : matBotInvert);
|
||||
|
||||
//hack to accomodate input tracking system's float-point sense (based on the core's VideoBuffer height)
|
||||
//actually, this is needed for a reason similar to the "TouchScreenStart" that I removed.
|
||||
//So, something like that needs readding if we're to get rid of this hack.
|
||||
//(should redo it as a mouse coordinate offset or something.. but the key is to pipe it to the point where this is needed.. that is where MainForm does DisplayManager.UntransformPoint()
|
||||
// hack to accomodate input tracking system's float-point sense (based on the core's VideoBuffer height)
|
||||
// actually, this is needed for a reason similar to the "TouchScreenStart" that I removed.
|
||||
// So, something like that needs readding if we're to get rid of this hack.
|
||||
// (should redo it as a mouse coordinate offset or something.. but the key is to pipe it to the point where this is needed.. that is where MainForm does DisplayManager.UntransformPoint()
|
||||
point.Y *= 2;
|
||||
|
||||
//in case we're in this layout, we get confused, so fix it
|
||||
// in case we're in this layout, we get confused, so fix it
|
||||
if (settings.ScreenLayout == NDS.ScreenLayoutKind.Top) point = new(0.0f, 0.0f);
|
||||
|
||||
//TODO: we probably need more subtle logic here.
|
||||
//some capability to return -1,-1 perhaps in case the cursor is nowhere.
|
||||
//not sure about that
|
||||
// TODO: we probably need more subtle logic here.
|
||||
// some capability to return -1,-1 perhaps in case the cursor is nowhere.
|
||||
// not sure about that
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
public override Vector2 TransformPoint(string channel, Vector2 point)
|
||||
{
|
||||
point = Transform(matBot, point);
|
||||
return point;
|
||||
return Vector2.Transform(point, matTop);
|
||||
}
|
||||
|
||||
public override void Run()
|
||||
{
|
||||
if (nop)
|
||||
#if false
|
||||
if (Nop)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
//TODO: this could be more efficient (draw only in gap)
|
||||
GL.SetClearColor(Color.Black);
|
||||
GL.Clear(ClearBufferMask.ColorBufferBit);
|
||||
// TODO: this could be more efficient (draw only in gap)
|
||||
FilterProgram.GL.SetClearColor(Color.Black);
|
||||
FilterProgram.GL.Clear(ClearBufferMask.ColorBufferBit);
|
||||
|
||||
FilterProgram.GuiRenderer.Begin(outputSize);
|
||||
GuiRenderer.SetBlendState(GL.BlendNoneCopy);
|
||||
FilterProgram.GuiRenderer.SetBlendState(FilterProgram.GL.BlendNoneCopy);
|
||||
|
||||
//TODO: may depend on input, or other factors, not sure yet
|
||||
//watch out though... if we filter linear, then screens will bleed into each other.
|
||||
//so we will have to break them into render targets first.
|
||||
// TODO: may depend on input, or other factors, not sure yet
|
||||
// watch out though... if we filter linear, then screens will bleed into each other.
|
||||
// so we will have to break them into render targets first.
|
||||
InputTexture.SetFilterNearest();
|
||||
|
||||
//draw screens
|
||||
bool renderTop = false;
|
||||
bool renderBottom = false;
|
||||
var settings = nds.GetSettings();
|
||||
if (settings.ScreenLayout == NDS.ScreenLayoutKind.Bottom) renderBottom = true;
|
||||
if (settings.ScreenLayout == NDS.ScreenLayoutKind.Top) renderTop = true;
|
||||
if (settings.ScreenLayout == NDS.ScreenLayoutKind.Vertical) renderTop = renderBottom = true;
|
||||
if (settings.ScreenLayout == NDS.ScreenLayoutKind.Horizontal) renderTop = renderBottom = true;
|
||||
var renderTop = false;
|
||||
var renderBottom = false;
|
||||
var settings = _nds.GetSettings();
|
||||
switch (settings.ScreenLayout)
|
||||
{
|
||||
case NDS.ScreenLayoutKind.Bottom:
|
||||
renderBottom = true;
|
||||
break;
|
||||
case NDS.ScreenLayoutKind.Top:
|
||||
renderTop = true;
|
||||
break;
|
||||
case NDS.ScreenLayoutKind.Vertical:
|
||||
case NDS.ScreenLayoutKind.Horizontal:
|
||||
renderTop = renderBottom = true;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
bool invert = settings.ScreenInvert && renderTop && renderBottom;
|
||||
var invert = settings.ScreenInvert && renderTop && renderBottom;
|
||||
|
||||
if (renderTop)
|
||||
{
|
||||
GuiRenderer.Modelview.Push();
|
||||
GuiRenderer.Modelview.PreMultiplyMatrix(invert ? matBot : matTop);
|
||||
GuiRenderer.DrawSubrect(InputTexture, 0, 0, 256, 192, 0.0f, 0.0f, 1.0f, 0.5f);
|
||||
GuiRenderer.Modelview.Pop();
|
||||
FilterProgram.GuiRenderer.Modelview.Push();
|
||||
FilterProgram.GuiRenderer.Modelview.PreMultiplyMatrix(invert ? matBot : matTop);
|
||||
FilterProgram.GuiRenderer.DrawSubrect(InputTexture, 0, 0, 256, 192, 0.0f, 0.0f, 1.0f, 0.5f);
|
||||
FilterProgram.GuiRenderer.Modelview.Pop();
|
||||
}
|
||||
|
||||
if (renderBottom)
|
||||
{
|
||||
GuiRenderer.Modelview.Push();
|
||||
GuiRenderer.Modelview.PreMultiplyMatrix(invert ? matTop : matBot);
|
||||
GuiRenderer.DrawSubrect(InputTexture, 0, 0, 256, 192, 0.0f, 0.5f, 1.0f, 1.0f);
|
||||
GuiRenderer.Modelview.Pop();
|
||||
FilterProgram.GuiRenderer.Modelview.Push();
|
||||
FilterProgram.GuiRenderer.Modelview.PreMultiplyMatrix(invert ? matTop : matBot);
|
||||
FilterProgram.GuiRenderer.DrawSubrect(InputTexture, 0, 0, 256, 192, 0.0f, 0.5f, 1.0f, 1.0f);
|
||||
FilterProgram.GuiRenderer.Modelview.Pop();
|
||||
}
|
||||
|
||||
GuiRenderer.End();
|
||||
FilterProgram.GuiRenderer.End();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -505,12 +535,8 @@ namespace BizHawk.Client.Common.Filters
|
|||
private Size OutputSize, InputSize;
|
||||
public Size TextureSize, VirtualTextureSize;
|
||||
public int BackgroundColor;
|
||||
public bool AutoPrescale;
|
||||
public IGuiRenderer GuiRenderer;
|
||||
public IGL GL;
|
||||
private bool nop;
|
||||
private bool Nop;
|
||||
private LetterboxingLogic LL;
|
||||
private Size ContentSize;
|
||||
|
||||
public bool Config_FixAspectRatio, Config_FixScaleInteger, Config_PadOnly;
|
||||
|
||||
|
@ -522,7 +548,7 @@ namespace BizHawk.Client.Common.Filters
|
|||
public override void Initialize()
|
||||
{
|
||||
DeclareInput();
|
||||
nop = false;
|
||||
Nop = false;
|
||||
}
|
||||
|
||||
public override Size PresizeOutput(string channel, Size size)
|
||||
|
@ -533,6 +559,7 @@ namespace BizHawk.Client.Common.Filters
|
|||
size.Height = LL.vh;
|
||||
return size;
|
||||
}
|
||||
|
||||
return base.PresizeOutput(channel, size);
|
||||
}
|
||||
|
||||
|
@ -543,8 +570,8 @@ namespace BizHawk.Client.Common.Filters
|
|||
|
||||
if (Config_PadOnly)
|
||||
{
|
||||
//TODO - redundant fix
|
||||
LL = new LetterboxingLogic();
|
||||
// TODO - redundant fix
|
||||
LL = new();
|
||||
LL.vx += Padding.Left;
|
||||
LL.vy += Padding.Top;
|
||||
LL.vw = size.Width;
|
||||
|
@ -552,7 +579,7 @@ namespace BizHawk.Client.Common.Filters
|
|||
}
|
||||
else
|
||||
{
|
||||
LL = new LetterboxingLogic(Config_FixAspectRatio, Config_FixScaleInteger, OutputSize.Width, OutputSize.Height, size.Width, size.Height, TextureSize, VirtualTextureSize);
|
||||
LL = new(Config_FixAspectRatio, Config_FixScaleInteger, OutputSize.Width, OutputSize.Height, size.Width, size.Height, TextureSize, VirtualTextureSize);
|
||||
LL.vx += Padding.Left;
|
||||
LL.vy += Padding.Top;
|
||||
}
|
||||
|
@ -562,22 +589,20 @@ namespace BizHawk.Client.Common.Filters
|
|||
|
||||
public override void SetInputFormat(string channel, SurfaceState state)
|
||||
{
|
||||
bool need = state.SurfaceFormat.Size != OutputSize || FilterOption != eFilterOption.None;
|
||||
|
||||
var need = state.SurfaceFormat.Size != OutputSize || FilterOption != eFilterOption.None;
|
||||
if (!need)
|
||||
{
|
||||
nop = true;
|
||||
ContentSize = state.SurfaceFormat.Size;
|
||||
Nop = true;
|
||||
return;
|
||||
}
|
||||
|
||||
FindInput().SurfaceDisposition = SurfaceDisposition.Texture;
|
||||
DeclareOutput(new SurfaceState(new SurfaceFormat(OutputSize), SurfaceDisposition.RenderTarget));
|
||||
DeclareOutput(new SurfaceState(new(OutputSize), SurfaceDisposition.RenderTarget));
|
||||
InputSize = state.SurfaceFormat.Size;
|
||||
if (Config_PadOnly)
|
||||
{
|
||||
//TODO - redundant fix
|
||||
LL = new LetterboxingLogic();
|
||||
// TODO - redundant fix
|
||||
LL = new();
|
||||
LL.vx += Padding.Left;
|
||||
LL.vy += Padding.Top;
|
||||
LL.vw = InputSize.Width;
|
||||
|
@ -587,26 +612,28 @@ namespace BizHawk.Client.Common.Filters
|
|||
}
|
||||
else
|
||||
{
|
||||
int ow = OutputSize.Width;
|
||||
int oh = OutputSize.Height;
|
||||
var ow = OutputSize.Width;
|
||||
var oh = OutputSize.Height;
|
||||
ow -= Padding.Left + Padding.Right;
|
||||
oh -= Padding.Top + Padding.Bottom;
|
||||
LL = new LetterboxingLogic(Config_FixAspectRatio, Config_FixScaleInteger, ow, oh, InputSize.Width, InputSize.Height, TextureSize, VirtualTextureSize);
|
||||
LL = new(Config_FixAspectRatio, Config_FixScaleInteger, ow, oh, InputSize.Width, InputSize.Height, TextureSize, VirtualTextureSize);
|
||||
LL.vx += Padding.Left;
|
||||
LL.vy += Padding.Top;
|
||||
}
|
||||
ContentSize = new Size(LL.vw,LL.vh);
|
||||
|
||||
if (InputSize == OutputSize) //any reason we need to check vx and vy?
|
||||
IsNop = true;
|
||||
if (InputSize == OutputSize) // any reason we need to check vx and vy?
|
||||
{
|
||||
Nop = true;
|
||||
}
|
||||
}
|
||||
|
||||
public Size GetContentSize() => ContentSize;
|
||||
|
||||
public override Vector2 UntransformPoint(string channel, Vector2 point)
|
||||
{
|
||||
if (nop)
|
||||
if (Nop)
|
||||
{
|
||||
return point;
|
||||
}
|
||||
|
||||
point.X -= LL.vx;
|
||||
point.Y -= LL.vy;
|
||||
point.X /= LL.WidthScale;
|
||||
|
@ -616,8 +643,11 @@ namespace BizHawk.Client.Common.Filters
|
|||
|
||||
public override Vector2 TransformPoint(string channel, Vector2 point)
|
||||
{
|
||||
if (nop)
|
||||
if (Nop)
|
||||
{
|
||||
return point;
|
||||
}
|
||||
|
||||
point.X *= LL.WidthScale;
|
||||
point.Y *= LL.HeightScale;
|
||||
point.X += LL.vx;
|
||||
|
@ -627,31 +657,37 @@ namespace BizHawk.Client.Common.Filters
|
|||
|
||||
public override void Run()
|
||||
{
|
||||
if (nop)
|
||||
if (Nop)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GL.SetClearColor(Color.FromArgb(BackgroundColor));
|
||||
GL.Clear(ClearBufferMask.ColorBufferBit);
|
||||
FilterProgram.GL.SetClearColor(Color.FromArgb(BackgroundColor));
|
||||
FilterProgram.GL.Clear(ClearBufferMask.ColorBufferBit);
|
||||
|
||||
GuiRenderer.Begin(OutputSize.Width, OutputSize.Height);
|
||||
GuiRenderer.SetBlendState(GL.BlendNoneCopy);
|
||||
FilterProgram.GuiRenderer.Begin(OutputSize.Width, OutputSize.Height);
|
||||
FilterProgram.GuiRenderer.SetBlendState(FilterProgram.GL.BlendNoneCopy);
|
||||
|
||||
if(FilterOption != eFilterOption.None)
|
||||
if (FilterOption != eFilterOption.None)
|
||||
{
|
||||
InputTexture.SetFilterLinear();
|
||||
}
|
||||
else
|
||||
{
|
||||
InputTexture.SetFilterNearest();
|
||||
}
|
||||
|
||||
if (FilterOption == eFilterOption.Bicubic)
|
||||
{
|
||||
//this was handled earlier by another filter
|
||||
// this was handled earlier by another filter
|
||||
}
|
||||
|
||||
GuiRenderer.Draw(InputTexture, LL.vx, LL.vy, LL.vw, LL.vh);
|
||||
GuiRenderer.End();
|
||||
FilterProgram.GuiRenderer.Draw(InputTexture, LL.vx, LL.vy, LL.vw, LL.vh);
|
||||
FilterProgram.GuiRenderer.End();
|
||||
}
|
||||
}
|
||||
|
||||
//TODO - turn this into a NOP at 1x, just in case something accidentally activates it with 1x
|
||||
// TODO - turn this into a NOP at 1x, just in case something accidentally activates it with 1x
|
||||
public class PrescaleFilter : BaseFilter
|
||||
{
|
||||
public int Scale;
|
||||
|
@ -666,7 +702,7 @@ namespace BizHawk.Client.Common.Filters
|
|||
var outputSize = state.SurfaceFormat.Size;
|
||||
outputSize.Width *= Scale;
|
||||
outputSize.Height *= Scale;
|
||||
var ss = new SurfaceState(new SurfaceFormat(outputSize), SurfaceDisposition.RenderTarget);
|
||||
var ss = new SurfaceState(new(outputSize), SurfaceDisposition.RenderTarget);
|
||||
DeclareOutput(ss, channel);
|
||||
}
|
||||
|
||||
|
@ -683,7 +719,7 @@ namespace BizHawk.Client.Common.Filters
|
|||
|
||||
public class AutoPrescaleFilter : BaseFilter
|
||||
{
|
||||
private Size OutputSize, InputSize;
|
||||
private Size OutputSize;
|
||||
private int XIS, YIS;
|
||||
|
||||
public override void Initialize()
|
||||
|
@ -693,7 +729,7 @@ namespace BizHawk.Client.Common.Filters
|
|||
|
||||
public override void SetInputFormat(string channel, SurfaceState state)
|
||||
{
|
||||
//calculate integer scaling factors
|
||||
// calculate integer scaling factors
|
||||
XIS = OutputSize.Width / state.SurfaceFormat.Size.Width;
|
||||
YIS = OutputSize.Height / state.SurfaceFormat.Size.Height;
|
||||
|
||||
|
@ -712,11 +748,7 @@ namespace BizHawk.Client.Common.Filters
|
|||
OutputSize.Height *= YIS;
|
||||
}
|
||||
|
||||
DeclareOutput(new SurfaceState
|
||||
{
|
||||
SurfaceFormat = new SurfaceFormat(OutputSize),
|
||||
SurfaceDisposition = SurfaceDisposition.RenderTarget
|
||||
});
|
||||
DeclareOutput(new SurfaceState(new(OutputSize), SurfaceDisposition.RenderTarget));
|
||||
}
|
||||
|
||||
public override Size PresizeOutput(string channel, Size size)
|
||||
|
@ -727,7 +759,6 @@ namespace BizHawk.Client.Common.Filters
|
|||
|
||||
public override Size PresizeInput(string channel, Size inSize)
|
||||
{
|
||||
InputSize = inSize;
|
||||
return inSize;
|
||||
}
|
||||
|
||||
|
@ -748,6 +779,7 @@ namespace BizHawk.Client.Common.Filters
|
|||
{
|
||||
DeclareInput(SurfaceDisposition.RenderTarget);
|
||||
}
|
||||
|
||||
public override void SetInputFormat(string channel, SurfaceState state)
|
||||
{
|
||||
DeclareOutput(state);
|
||||
|
@ -772,19 +804,24 @@ namespace BizHawk.Client.Common.Filters
|
|||
|
||||
public class OSD : BaseFilter
|
||||
{
|
||||
//this class has the ability to disable its operations for higher performance when the callback is removed,
|
||||
//without having to take it out of the chain. although, its presence in the chain may slow down performance due to added resolves/renders
|
||||
//so, we should probably rebuild the chain.
|
||||
// this class has the ability to disable its operations for higher performance when the callback is removed,
|
||||
// without having to take it out of the chain. although, its presence in the chain may slow down performance due to added resolves/renders
|
||||
// so, we should probably rebuild the chain.
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
if (RenderCallback == null) return;
|
||||
DeclareInput(SurfaceDisposition.RenderTarget);
|
||||
if (RenderCallback != null)
|
||||
{
|
||||
DeclareInput(SurfaceDisposition.RenderTarget);
|
||||
}
|
||||
}
|
||||
|
||||
public override void SetInputFormat(string channel, SurfaceState state)
|
||||
{
|
||||
if (RenderCallback == null) return;
|
||||
DeclareOutput(state);
|
||||
if (RenderCallback != null)
|
||||
{
|
||||
DeclareOutput(state);
|
||||
}
|
||||
}
|
||||
|
||||
public Action RenderCallback;
|
||||
|
|
|
@ -4,9 +4,11 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
using BizHawk.Client.Common.FilterManager;
|
||||
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
|
@ -17,48 +19,56 @@ namespace BizHawk.Client.Common.Filters
|
|||
{
|
||||
public class RetroShaderChain : IDisposable
|
||||
{
|
||||
private static readonly Regex RxInclude = new Regex(@"^(\s)?\#include(\s)+(""|<)(.*)?(""|>)", RegexOptions.Multiline | RegexOptions.IgnoreCase);
|
||||
private static readonly Regex RxInclude = new(@"^(\s)?\#include(\s)+(""|<)(.*)?(""|>)", RegexOptions.Multiline | RegexOptions.IgnoreCase);
|
||||
|
||||
private static string ResolveIncludes(string content, string baseDirectory)
|
||||
{
|
||||
for (; ; )
|
||||
while (true)
|
||||
{
|
||||
var match = RxInclude.Match(content);
|
||||
if(match.Value == "") break;
|
||||
string fname = match.Groups[4].Value;
|
||||
if (match.Value == string.Empty)
|
||||
{
|
||||
return content;
|
||||
}
|
||||
|
||||
var fname = match.Groups[4].Value;
|
||||
fname = Path.Combine(baseDirectory,fname);
|
||||
string includedContent = ResolveIncludes(File.ReadAllText(fname),Path.GetDirectoryName(fname));
|
||||
var includedContent = ResolveIncludes(File.ReadAllText(fname),Path.GetDirectoryName(fname));
|
||||
content = content.Substring(0, match.Index) + includedContent + content.Substring(match.Index + match.Length);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
public RetroShaderChain(IGL owner, RetroShaderPreset preset, string baseDirectory, bool debug = false)
|
||||
{
|
||||
Owner = owner;
|
||||
Preset = preset;
|
||||
Passes = preset.Passes.ToArray();
|
||||
Errors = "";
|
||||
Errors = string.Empty;
|
||||
|
||||
//load up the shaders
|
||||
// load up the shaders
|
||||
var shaders = new RetroShader[preset.Passes.Count];
|
||||
for (var i = 0; i < preset.Passes.Count; i++)
|
||||
{
|
||||
//acquire content. we look for it in any reasonable filename so that one preset can bind to multiple shaders
|
||||
// acquire content. we look for it in any reasonable filename so that one preset can bind to multiple shaders
|
||||
string content;
|
||||
var path = Path.Combine(baseDirectory, preset.Passes[i].ShaderPath);
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
if (!Path.HasExtension(path))
|
||||
{
|
||||
path += ".cg";
|
||||
}
|
||||
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
if (owner.API == "OPENGL")
|
||||
path = Path.ChangeExtension(path, ".glsl");
|
||||
else
|
||||
path = Path.ChangeExtension(path, ".hlsl");
|
||||
path = owner.API switch
|
||||
{
|
||||
"OPENGL" => Path.ChangeExtension(path, ".glsl"),
|
||||
"D3D9" => Path.ChangeExtension(path, ".hlsl"),
|
||||
_ => throw new InvalidOperationException(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
content = ResolveIncludes(File.ReadAllText(path), Path.GetDirectoryName(path));
|
||||
|
@ -68,16 +78,17 @@ namespace BizHawk.Client.Common.Filters
|
|||
Errors += $"caught {nameof(DirectoryNotFoundException)}: {e.Message}\n";
|
||||
return;
|
||||
}
|
||||
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
Errors += $"could not read file {e.FileName}\n";
|
||||
return;
|
||||
}
|
||||
|
||||
var shader = shaders[i] = new RetroShader(Owner, content, debug);
|
||||
var shader = shaders[i] = new(Owner, content, debug);
|
||||
if (!shader.Available)
|
||||
{
|
||||
Errors += $"-------------------\r\nPass {i}:\r\n{(shader.Errors??"").Replace("\n","\r\n")}\n";
|
||||
Errors += $"-------------------\r\nPass {i}:\r\n{(shader.Errors ?? string.Empty).Replace("\n","\r\n")}\n";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -105,7 +116,6 @@ namespace BizHawk.Client.Common.Filters
|
|||
public readonly bool Available;
|
||||
public readonly string Errors;
|
||||
public readonly IGL Owner;
|
||||
public readonly RetroShaderPreset Preset;
|
||||
public readonly IReadOnlyList<RetroShader> Shaders = Array.Empty<RetroShader>();
|
||||
public readonly RetroShaderPreset.ShaderPass[] Passes;
|
||||
|
||||
|
@ -122,55 +132,70 @@ namespace BizHawk.Client.Common.Filters
|
|||
var content = new StreamReader(stream).ReadToEnd();
|
||||
var dict = new Dictionary<string, string>();
|
||||
|
||||
//parse the key-value-pair format of the file
|
||||
// parse the key-value-pair format of the file
|
||||
content = content.Replace("\r", "");
|
||||
foreach (var splitLine in content.Split('\n'))
|
||||
{
|
||||
var line = splitLine.Trim();
|
||||
if (line.Length is 0) continue;
|
||||
if (line.StartsWith('#')) continue; // comments
|
||||
int eq = line.IndexOf('=');
|
||||
if (line.Length is 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.StartsWith('#'))
|
||||
{
|
||||
continue; // comments
|
||||
}
|
||||
|
||||
var eq = line.IndexOf('=');
|
||||
var key = line.Substring(0, eq).Trim();
|
||||
var value = line.Substring(eq + 1).Trim();
|
||||
int quote = value.IndexOf('\"');
|
||||
var quote = value.IndexOf('\"');
|
||||
if (quote != -1)
|
||||
{
|
||||
value = value.Substring(quote + 1, value.IndexOf('\"', quote + 1) - (quote + 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
//remove comments from end of value. exclusive from above condition, since comments after quoted strings would be snipped by the quoted string extraction
|
||||
int hash = value.IndexOf('#');
|
||||
// remove comments from end of value. exclusive from above condition, since comments after quoted strings would be snipped by the quoted string extraction
|
||||
var hash = value.IndexOf('#');
|
||||
if (hash != -1)
|
||||
{
|
||||
value = value.Substring(0, hash);
|
||||
}
|
||||
|
||||
value = value.Trim();
|
||||
}
|
||||
|
||||
dict[key.ToLower()] = value;
|
||||
}
|
||||
|
||||
// process the keys
|
||||
int nShaders = FetchInt(dict, "shaders", 0);
|
||||
for (int i = 0; i < nShaders; i++)
|
||||
var nShaders = FetchInt(dict, "shaders", 0);
|
||||
for (var i = 0; i < nShaders; i++)
|
||||
{
|
||||
var sp = new ShaderPass { Index = i };
|
||||
Passes.Add(sp);
|
||||
|
||||
sp.InputFilterLinear = FetchBool(dict, $"filter_linear{i}", false); //Should this value not be defined, the filtering option is implementation defined.
|
||||
sp.InputFilterLinear = FetchBool(dict, $"filter_linear{i}", false); // Should this value not be defined, the filtering option is implementation defined.
|
||||
sp.OutputFloat = FetchBool(dict, $"float_framebuffer{i}", false);
|
||||
sp.FrameCountMod = FetchInt(dict, $"frame_count_mod{i}", 1);
|
||||
sp.ShaderPath = FetchString(dict, $"shader{i}", "?"); //todo - change extension to .cg for better compatibility? just change .cg to .glsl transparently at last second?
|
||||
sp.ShaderPath = FetchString(dict, $"shader{i}", "?"); // todo - change extension to .cg for better compatibility? just change .cg to .glsl transparently at last second?
|
||||
|
||||
// If no scale type is assumed, it is assumed that it is set to "source" with scaleN set to 1.0.
|
||||
// It is possible to set scale_type_xN and scale_type_yN to specialize the scaling type in either direction. scale_typeN however overrides both of these.
|
||||
sp.ScaleTypeX = (ScaleType)Enum.Parse(typeof(ScaleType), FetchString(dict, $"scale_type_x{i}", "Source"), true);
|
||||
sp.ScaleTypeY = (ScaleType)Enum.Parse(typeof(ScaleType), FetchString(dict, $"scale_type_y{i}", "Source"), true);
|
||||
ScaleType st = (ScaleType)Enum.Parse(typeof(ScaleType), FetchString(dict, $"scale_type{i}", "NotSet"), true);
|
||||
var st = (ScaleType)Enum.Parse(typeof(ScaleType), FetchString(dict, $"scale_type{i}", "NotSet"), true);
|
||||
if (st != ScaleType.NotSet)
|
||||
{
|
||||
sp.ScaleTypeX = sp.ScaleTypeY = st;
|
||||
}
|
||||
|
||||
// scaleN controls both scaling type in horizontal and vertical directions. If scaleN is defined, scale_xN and scale_yN have no effect.
|
||||
sp.Scale.X = FetchFloat(dict, $"scale_x{i}", 1);
|
||||
sp.Scale.Y = FetchFloat(dict, $"scale_y{i}", 1);
|
||||
float scale = FetchFloat(dict, $"scale{i}", -999);
|
||||
if (scale != -999)
|
||||
if (dict.ContainsValue($"scale{i}"))
|
||||
{
|
||||
sp.Scale.X = sp.Scale.Y = FetchFloat(dict, $"scale{i}", 1);
|
||||
}
|
||||
|
@ -179,8 +204,7 @@ namespace BizHawk.Client.Common.Filters
|
|||
}
|
||||
}
|
||||
|
||||
public List<ShaderPass> Passes { get; set; } = new List<ShaderPass>();
|
||||
|
||||
public List<ShaderPass> Passes { get; set; } = new();
|
||||
|
||||
public enum ScaleType
|
||||
{
|
||||
|
@ -214,19 +238,28 @@ namespace BizHawk.Client.Common.Filters
|
|||
return dict.TryGetValue(key, out var str) ? float.Parse(str) : @default;
|
||||
}
|
||||
|
||||
private bool FetchBool(IDictionary<string, string> dict, string key, bool @default)
|
||||
private static bool FetchBool(IDictionary<string, string> dict, string key, bool @default)
|
||||
{
|
||||
return dict.TryGetValue(key, out var str) ? ParseBool(str) : @default;
|
||||
}
|
||||
|
||||
private bool ParseBool(string value)
|
||||
private static bool ParseBool(string value)
|
||||
{
|
||||
if (value == "1") return true;
|
||||
if (value == "0") return false;
|
||||
value = value.ToLower();
|
||||
if (value == "true") return true;
|
||||
if (value == "false") return false;
|
||||
throw new InvalidOperationException("Unparsable bool in CGP file content");
|
||||
switch (value)
|
||||
{
|
||||
case "1":
|
||||
return true;
|
||||
case "0":
|
||||
return false;
|
||||
}
|
||||
|
||||
value = value.ToLowerInvariant();
|
||||
return value switch
|
||||
{
|
||||
"true" => true,
|
||||
"false" => false,
|
||||
_ => throw new InvalidOperationException("Unparsable bool in CGP file content")
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,17 +286,23 @@ namespace BizHawk.Client.Common.Filters
|
|||
|
||||
public override void SetInputFormat(string channel, SurfaceState state)
|
||||
{
|
||||
Size inSize = state.SurfaceFormat.Size;
|
||||
if (_sp.ScaleTypeX == RetroShaderPreset.ScaleType.Absolute) _outputSize.Width = (int)_sp.Scale.X;
|
||||
if (_sp.ScaleTypeY == RetroShaderPreset.ScaleType.Absolute) _outputSize.Height = (int)_sp.Scale.Y;
|
||||
if (_sp.ScaleTypeX == RetroShaderPreset.ScaleType.Source) _outputSize.Width = (int)(inSize.Width * _sp.Scale.X);
|
||||
if (_sp.ScaleTypeY == RetroShaderPreset.ScaleType.Source) _outputSize.Height = (int)(inSize.Height * _sp.Scale.Y);
|
||||
var inSize = state.SurfaceFormat.Size;
|
||||
|
||||
DeclareOutput(new SurfaceState
|
||||
_outputSize.Width = _sp.ScaleTypeX switch
|
||||
{
|
||||
SurfaceFormat = new SurfaceFormat(_outputSize),
|
||||
SurfaceDisposition = SurfaceDisposition.RenderTarget
|
||||
});
|
||||
RetroShaderPreset.ScaleType.Absolute => (int)_sp.Scale.X,
|
||||
RetroShaderPreset.ScaleType.Source => (int)(inSize.Width * _sp.Scale.X),
|
||||
_ => _outputSize.Width
|
||||
};
|
||||
|
||||
_outputSize.Height = _sp.ScaleTypeY switch
|
||||
{
|
||||
RetroShaderPreset.ScaleType.Absolute => (int)_sp.Scale.Y,
|
||||
RetroShaderPreset.ScaleType.Source => (int)(inSize.Height * _sp.Scale.Y),
|
||||
_ => _outputSize.Height
|
||||
};
|
||||
|
||||
DeclareOutput(new SurfaceState(new(_outputSize), SurfaceDisposition.RenderTarget));
|
||||
}
|
||||
|
||||
public override Size PresizeOutput(string channel, Size size)
|
||||
|
@ -274,11 +313,22 @@ namespace BizHawk.Client.Common.Filters
|
|||
|
||||
public override Size PresizeInput(string channel, Size inSize)
|
||||
{
|
||||
Size outsize = inSize;
|
||||
if (_sp.ScaleTypeX == RetroShaderPreset.ScaleType.Absolute) outsize.Width = (int)_sp.Scale.X;
|
||||
if (_sp.ScaleTypeY == RetroShaderPreset.ScaleType.Absolute) outsize.Height = (int)_sp.Scale.Y;
|
||||
if (_sp.ScaleTypeX == RetroShaderPreset.ScaleType.Source) outsize.Width = (int)(inSize.Width * _sp.Scale.X);
|
||||
if (_sp.ScaleTypeY == RetroShaderPreset.ScaleType.Source) outsize.Height = (int)(inSize.Height * _sp.Scale.Y);
|
||||
var outsize = inSize;
|
||||
|
||||
outsize.Width = _sp.ScaleTypeX switch
|
||||
{
|
||||
RetroShaderPreset.ScaleType.Absolute => (int)_sp.Scale.X,
|
||||
RetroShaderPreset.ScaleType.Source => (int)(inSize.Width * _sp.Scale.X),
|
||||
_ => outsize.Width
|
||||
};
|
||||
|
||||
outsize.Height = _sp.ScaleTypeY switch
|
||||
{
|
||||
RetroShaderPreset.ScaleType.Absolute => (int)_sp.Scale.Y,
|
||||
RetroShaderPreset.ScaleType.Source => (int)(inSize.Height * _sp.Scale.Y),
|
||||
_ => outsize.Height
|
||||
};
|
||||
|
||||
return outsize;
|
||||
}
|
||||
|
||||
|
@ -288,7 +338,7 @@ namespace BizHawk.Client.Common.Filters
|
|||
shader.Bind();
|
||||
|
||||
// apply all parameters to this shader.. even if it was meant for other shaders. kind of lame.
|
||||
if(Parameters != null)
|
||||
if (Parameters != null)
|
||||
{
|
||||
foreach (var (k, v) in Parameters)
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using System.Drawing;
|
||||
using BizHawk.Client.Common.FilterManager;
|
||||
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
using BizHawk.Client.Common.FilterManager;
|
||||
|
||||
namespace BizHawk.Client.Common.Filters
|
||||
{
|
||||
|
@ -23,7 +23,7 @@ namespace BizHawk.Client.Common.Filters
|
|||
|
||||
public override void Initialize()
|
||||
{
|
||||
DeclareOutput(new SurfaceState(new SurfaceFormat(_size), SurfaceDisposition.Texture));
|
||||
DeclareOutput(new SurfaceState(new(_size), SurfaceDisposition.Texture));
|
||||
}
|
||||
|
||||
public override void SetInputFormat(string channel, SurfaceState format)
|
||||
|
@ -71,7 +71,7 @@ namespace BizHawk.Client.Common.Filters
|
|||
|
||||
public override void Run()
|
||||
{
|
||||
YieldOutput(FilterProgram.GetRenderTarget().Texture2d);
|
||||
YieldOutput(FilterProgram.CurrRenderTarget.Texture2d);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
using System.Drawing.Drawing2D;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
|
@ -17,9 +18,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
private readonly IGL_GdiPlus _gdi;
|
||||
|
||||
public Control Control => this;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// the render target for rendering to this control
|
||||
/// </summary>
|
||||
|
@ -34,24 +32,29 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
_gdi.BeginControl(this);
|
||||
RenderTargetWrapper.CreateGraphics();
|
||||
//using (var g = CreateGraphics())
|
||||
// MyBufferedGraphics = Gdi.MyBufferedGraphicsContext.Allocate(g, ClientRectangle);
|
||||
//MyBufferedGraphics.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighSpeed;
|
||||
|
||||
////not sure about this stuff...
|
||||
////it will wreck alpha blending, for one thing
|
||||
//MyBufferedGraphics.Graphics.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
|
||||
//MyBufferedGraphics.Graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed;
|
||||
#if false
|
||||
using (var g = CreateGraphics())
|
||||
{
|
||||
MyBufferedGraphics = _gdi.MyBufferedGraphicsContext.Allocate(g, ClientRectangle);
|
||||
}
|
||||
|
||||
MyBufferedGraphics.Graphics.PixelOffsetMode = PixelOffsetMode.HighSpeed;
|
||||
|
||||
// not sure about this stuff...
|
||||
// it will wreck alpha blending, for one thing
|
||||
MyBufferedGraphics.Graphics.CompositingMode = CompositingMode.SourceCopy;
|
||||
MyBufferedGraphics.Graphics.CompositingQuality = CompositingQuality.HighSpeed;
|
||||
#endif
|
||||
}
|
||||
|
||||
public void End()
|
||||
{
|
||||
_gdi.EndControl(this);
|
||||
_gdi.EndControl();
|
||||
}
|
||||
|
||||
public void SwapBuffers()
|
||||
{
|
||||
_gdi.SwapControl(this);
|
||||
if (RenderTargetWrapper.MyBufferedGraphics == null)
|
||||
{
|
||||
return;
|
||||
|
|
Loading…
Reference in New Issue