diff --git a/src/BizHawk.Bizware.BizwareGL/Art.cs b/src/BizHawk.Bizware.BizwareGL/Art.cs index d933a8a6a9..33e496cf7c 100644 --- a/src/BizHawk.Bizware.BizwareGL/Art.cs +++ b/src/BizHawk.Bizware.BizwareGL/Art.cs @@ -5,7 +5,7 @@ namespace BizHawk.Bizware.BizwareGL /// 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; diff --git a/src/BizHawk.Bizware.BizwareGL/ArtManager.cs b/src/BizHawk.Bizware.BizwareGL/ArtManager.cs index 75609d7eff..2fee78e871 100644 --- a/src/BizHawk.Bizware.BizwareGL/ArtManager.cs +++ b/src/BizHawk.Bizware.BizwareGL/ArtManager.cs @@ -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 } /// @@ -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(); - 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 /// /// Throws an exception if the instance is not open /// - 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 /// /// Physical texture resources, which exist after this ArtManager has been closed /// - private readonly List ManagedTextures = new List(); + private readonly List ManagedTextures = new(); /// /// All the Arts managed by this instance /// - private readonly List ManagedArts = new List(); + private readonly List ManagedArts = new(); } } \ No newline at end of file diff --git a/src/BizHawk.Bizware.BizwareGL/BitmapBuffer.cs b/src/BizHawk.Bizware.BizwareGL/BitmapBuffer.cs index c4f6b72d9a..6508d4f83e 100644 --- a/src/BizHawk.Bizware.BizwareGL/BitmapBuffer.cs +++ b/src/BizHawk.Bizware.BizwareGL/BitmapBuffer.cs @@ -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 { /// @@ -28,7 +27,7 @@ namespace BizHawk.Bizware.BizwareGL /// 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; + } } + } } /// @@ -177,15 +186,16 @@ namespace BizHawk.Bizware.BizwareGL /// 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 /// 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); + } } - /// /// Initializes a BitmapBuffer --WRAPPED-- from the supplied parameters, which should definitely have a stride==width and be in the standard color format /// @@ -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 /// 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(); + } } /// @@ -412,10 +447,10 @@ namespace BizHawk.Bizware.BizwareGL /// 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 /// /// Makes a new bitmap buffer, in ??? state /// - public BitmapBuffer() { } + public BitmapBuffer() + { + } /// /// initializes an empty BitmapBuffer, cleared to all 0 @@ -449,24 +486,24 @@ namespace BizHawk.Bizware.BizwareGL /// 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++; } + } } } diff --git a/src/BizHawk.Bizware.BizwareGL/GDIPTextureWrapper.cs b/src/BizHawk.Bizware.BizwareGL/GDIPTextureWrapper.cs index 4c22333f13..c0ec9763f7 100644 --- a/src/BizHawk.Bizware.BizwareGL/GDIPTextureWrapper.cs +++ b/src/BizHawk.Bizware.BizwareGL/GDIPTextureWrapper.cs @@ -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) diff --git a/src/BizHawk.Bizware.BizwareGL/GDIPlusGuiRenderer.cs b/src/BizHawk.Bizware.BizwareGL/GDIPlusGuiRenderer.cs index c976459ac1..8dbcdb3a2a 100644 --- a/src/BizHawk.Bizware.BizwareGL/GDIPlusGuiRenderer.cs +++ b/src/BizHawk.Bizware.BizwareGL/GDIPlusGuiRenderer.cs @@ -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 } /// is 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) { } diff --git a/src/BizHawk.Bizware.BizwareGL/IBlendState.cs b/src/BizHawk.Bizware.BizwareGL/IBlendState.cs index dbaca9a006..0f29eb2d7d 100644 --- a/src/BizHawk.Bizware.BizwareGL/IBlendState.cs +++ b/src/BizHawk.Bizware.BizwareGL/IBlendState.cs @@ -1,4 +1,6 @@ namespace BizHawk.Bizware.BizwareGL { - public interface IBlendState {} + public interface IBlendState + { + } } diff --git a/src/BizHawk.Bizware.BizwareGL/IGL.cs b/src/BizHawk.Bizware.BizwareGL/IGL.cs index d6353bf10d..769f12fa76 100644 --- a/src/BizHawk.Bizware.BizwareGL/IGL.cs +++ b/src/BizHawk.Bizware.BizwareGL/IGL.cs @@ -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 /// /// Sets a uniform value /// - void SetPipelineUniformMatrix(PipelineUniform uniform, Matrix4 mat, bool transpose); + void SetPipelineUniformMatrix(PipelineUniform uniform, Matrix4x4 mat, bool transpose); /// /// Sets a uniform value /// - void SetPipelineUniformMatrix(PipelineUniform uniform, ref Matrix4 mat, bool transpose); + void SetPipelineUniformMatrix(PipelineUniform uniform, ref Matrix4x4 mat, bool transpose); /// /// sets a uniform value @@ -219,24 +220,24 @@ namespace BizHawk.Bizware.BizwareGL /// /// generates a proper 2d othographic projection for the given destination size, suitable for use in a GUI /// - Matrix4 CreateGuiProjectionMatrix(int w, int h); + Matrix4x4 CreateGuiProjectionMatrix(int w, int h); /// /// generates a proper 2d othographic projection for the given destination size, suitable for use in a GUI /// - Matrix4 CreateGuiProjectionMatrix(Size dims); + Matrix4x4 CreateGuiProjectionMatrix(Size dims); /// /// 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 /// - Matrix4 CreateGuiViewMatrix(int w, int h, bool autoflip = true); + Matrix4x4 CreateGuiViewMatrix(int w, int h, bool autoflip = true); /// /// 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 /// - Matrix4 CreateGuiViewMatrix(Size dims, bool autoflip = true); + Matrix4x4 CreateGuiViewMatrix(Size dims, bool autoflip = true); /// /// Creates a render target. Only includes a color buffer. Pixel format control TBD diff --git a/src/BizHawk.Bizware.BizwareGL/IGL_GdiPlus.cs b/src/BizHawk.Bizware.BizwareGL/IGL_GdiPlus.cs index c0491a837e..51f3f9e7b6 100644 --- a/src/BizHawk.Bizware.BizwareGL/IGL_GdiPlus.cs +++ b/src/BizHawk.Bizware.BizwareGL/IGL_GdiPlus.cs @@ -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 _createGLControlWrapper; public IGL_GdiPlus(Func 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 + } } diff --git a/src/BizHawk.Bizware.BizwareGL/IGuiRenderer.cs b/src/BizHawk.Bizware.BizwareGL/IGuiRenderer.cs index 5c415e9636..af342fd527 100644 --- a/src/BizHawk.Bizware.BizwareGL/IGuiRenderer.cs +++ b/src/BizHawk.Bizware.BizwareGL/IGuiRenderer.cs @@ -1,4 +1,6 @@ using System; +using System.Drawing; +using System.Numerics; namespace BizHawk.Bizware.BizwareGL { @@ -9,7 +11,7 @@ namespace BizHawk.Bizware.BizwareGL /// void Begin(); - void Begin(System.Drawing.Size size); + void Begin(Size size); /// /// begin rendering, initializing viewport and projections to the given dimensions @@ -51,7 +53,6 @@ namespace BizHawk.Bizware.BizwareGL /// void Draw(Texture2d tex, float x, float y); - /// /// draws the specified Art resource with the given flip flags /// @@ -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); /// @@ -96,7 +102,9 @@ namespace BizHawk.Bizware.BizwareGL /// Restores the pipeline to the default /// void SetDefaultPipeline(); - void SetModulateColor(System.Drawing.Color color); + + void SetModulateColor(Color color); + void SetModulateColorWhite(); /// diff --git a/src/BizHawk.Bizware.BizwareGL/MatrixStack.cs b/src/BizHawk.Bizware.BizwareGL/MatrixStack.cs index 90b76d7029..b6b0f25372 100644 --- a/src/BizHawk.Bizware.BizwareGL/MatrixStack.cs +++ b/src/BizHawk.Bizware.BizwareGL/MatrixStack.cs @@ -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 stack = new Stack(); + private readonly Stack stack = new(); /// /// This is made public for performance reasons, to avoid lame copies of the matrix when necessary. Don't mess it up! /// - public Matrix4 Top; + public Matrix4x4 Top; /// /// Resets the matrix stack to an empty identity matrix stack @@ -51,41 +55,143 @@ namespace BizHawk.Bizware.BizwareGL /// /// Clears the matrix stack and loads the specified value /// - 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; + } } } \ No newline at end of file diff --git a/src/BizHawk.Bizware.BizwareGL/Pipeline.cs b/src/BizHawk.Bizware.BizwareGL/Pipeline.cs index ce51253a65..78c6eb0cef 100644 --- a/src/BizHawk.Bizware.BizwareGL/Pipeline.cs +++ b/src/BizHawk.Bizware.BizwareGL/Pipeline.cs @@ -10,9 +10,9 @@ namespace BizHawk.Bizware.BizwareGL /// public class Pipeline : IDisposable { - public string Memo; + public readonly string Memo; - public Pipeline(IGL owner, object opaque, bool available, VertexLayout vertexLayout, IEnumerable uniforms, string memo) + public Pipeline(IGL owner, object opaque, bool available, VertexLayout vertexLayout, IReadOnlyList 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 /// - private class SpecialWorkingDictionary : Dictionary + private class UniformWorkingDictionary : Dictionary { - 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 Uniforms => UniformsDictionary; public IEnumerable GetUniforms() => Uniforms.Values; diff --git a/src/BizHawk.Bizware.BizwareGL/PipelineUniform.cs b/src/BizHawk.Bizware.BizwareGL/PipelineUniform.cs index 8191c11343..fb2464d80e 100644 --- a/src/BizHawk.Bizware.BizwareGL/PipelineUniform.cs +++ b/src/BizHawk.Bizware.BizwareGL/PipelineUniform.cs @@ -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 UniformInfos => _UniformInfos; - private readonly List _UniformInfos = new List(); + public IEnumerable UniformInfos => _uniformInfos; + + private readonly List _uniformInfos = new(); /// the first and only /// more than one exists @@ -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); } diff --git a/src/BizHawk.Bizware.BizwareGL/RenderTargetWrapper.cs b/src/BizHawk.Bizware.BizwareGL/RenderTargetWrapper.cs index b936438464..774fb6343e 100644 --- a/src/BizHawk.Bizware.BizwareGL/RenderTargetWrapper.cs +++ b/src/BizHawk.Bizware.BizwareGL/RenderTargetWrapper.cs @@ -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 getBufferedGraphicsContext, @@ -15,6 +18,7 @@ namespace BizHawk.Bizware.BizwareGL public void Dispose() { + MyBufferedGraphics?.Dispose(); } private readonly Func _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 } } } diff --git a/src/BizHawk.Bizware.BizwareGL/RetroShader.cs b/src/BizHawk.Bizware.BizwareGL/RetroShader.cs index 109fd16260..9b9ec0b02a 100644 --- a/src/BizHawk.Bizware.BizwareGL/RetroShader.cs +++ b/src/BizHawk.Bizware.BizwareGL/RetroShader.cs @@ -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; } } \ No newline at end of file diff --git a/src/BizHawk.Bizware.BizwareGL/StringRenderer.cs b/src/BizHawk.Bizware.BizwareGL/StringRenderer.cs index 75a9419b6e..21f423b0ed 100644 --- a/src/BizHawk.Bizware.BizwareGL/StringRenderer.cs +++ b/src/BizHawk.Bizware.BizwareGL/StringRenderer.cs @@ -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 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 TexturePages = new List(); + private List TexturePages = new(); } } \ No newline at end of file diff --git a/src/BizHawk.Bizware.BizwareGL/TexAtlas.cs b/src/BizHawk.Bizware.BizwareGL/TexAtlas.cs index c79bdbb1a7..9b39b779f1 100644 --- a/src/BizHawk.Bizware.BizwareGL/TexAtlas.cs +++ b/src/BizHawk.Bizware.BizwareGL/TexAtlas.cs @@ -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 nodes = new List(); } - public static int MaxSizeBits = 16; + public const int MaxSizeBits = 16; /// /// packs the supplied RectItems into an atlas. Modifies the RectItems with x/y values of location in new atlas. /// - public static IReadOnlyList<(Size Size, List Items)> PackAtlas(IReadOnlyCollection items) + public static IReadOnlyList<(Size Size, List Items)> PackAtlas(IEnumerable items) { - static void AddAtlas(ICollection<(Size, List)> atlases, IReadOnlyCollection initItems) + static void AddAtlas(ICollection<(Size, List)> atlases, IEnumerable initItems) { List currentItems = new(initItems); List 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(); - 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(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 /// Computes the ratio of used surface area. 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; /// The surface area used by the subtree rooted at node. - 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 /// Inserts a new rectangle in the subtree rooted at the given node. - 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; diff --git a/src/BizHawk.Bizware.BizwareGL/VertexLayout.cs b/src/BizHawk.Bizware.BizwareGL/VertexLayout.cs index 52f918a988..44535a688d 100644 --- a/src/BizHawk.Bizware.BizwareGL/VertexLayout.cs +++ b/src/BizHawk.Bizware.BizwareGL/VertexLayout.cs @@ -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 }; } /// @@ -66,7 +71,7 @@ namespace BizHawk.Bizware.BizwareGL public AttribUsage Usage { get; internal set; } } - public class MyDictionary : WorkingDictionary + public class LayoutItemWorkingDictionary : WorkingDictionary { 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; } } \ No newline at end of file diff --git a/src/BizHawk.Bizware.BizwareGL/math/Matrix4.cs b/src/BizHawk.Bizware.BizwareGL/math/Matrix4.cs deleted file mode 100644 index aedbf112f8..0000000000 --- a/src/BizHawk.Bizware.BizwareGL/math/Matrix4.cs +++ /dev/null @@ -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); - - /// a representing a rotation of radians CCW around the given - 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)); - } - - /// a representing a rotation of radians CCW around the X-axis - 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; - } - - /// a representing a rotation of radians CCW around the Y-axis - 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; - } - - /// a representing a rotation of radians CCW around the Z-axis - 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; - } - - /// a representing a scaling - 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; - } - - /// a representing a scaling - 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; - } - - /// a representing a translation - 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; - } - - /// a representing a translation - 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); - - /// Matrix multiplication - /// left-hand operand - /// right-hand operand - /// A new Matrix4 which holds the result of the multiplication - 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; - } - - /// transformed by - 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)); - - /// Top row of the matrix. - public Vector4 Row0; - - /// 2nd row of the matrix. - public Vector4 Row1; - - /// 3rd row of the matrix. - public Vector4 Row2; - - /// Bottom row of the matrix. - public Vector4 Row3; - - /// Top row of the matrix. - /// Second row of the matrix. - /// Third row of the matrix. - /// Bottom row of the matrix. - 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; - } - } - - /// an inverted copy of this instance, or an identical copy if it is singular - 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); - } -} diff --git a/src/BizHawk.Bizware.BizwareGL/math/Vector2.cs b/src/BizHawk.Bizware.BizwareGL/math/Vector2.cs deleted file mode 100644 index 4d5e81dda8..0000000000 --- a/src/BizHawk.Bizware.BizwareGL/math/Vector2.cs +++ /dev/null @@ -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})"; - } -} diff --git a/src/BizHawk.Bizware.BizwareGL/math/Vector3.cs b/src/BizHawk.Bizware.BizwareGL/math/Vector3.cs deleted file mode 100644 index bdcd5ff08a..0000000000 --- a/src/BizHawk.Bizware.BizwareGL/math/Vector3.cs +++ /dev/null @@ -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})"; - } -} diff --git a/src/BizHawk.Bizware.BizwareGL/math/Vector4.cs b/src/BizHawk.Bizware.BizwareGL/math/Vector4.cs deleted file mode 100644 index a15920f7a3..0000000000 --- a/src/BizHawk.Bizware.BizwareGL/math/Vector4.cs +++ /dev/null @@ -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})"; - } -} diff --git a/src/BizHawk.Bizware.Graphics/D3D9/IGL_D3D9.cs b/src/BizHawk.Bizware.Graphics/D3D9/IGL_D3D9.cs index 782d8f8eea..92ccf17bd8 100644 --- a/src/BizHawk.Bizware.Graphics/D3D9/IGL_D3D9.cs +++ b/src/BizHawk.Bizware.Graphics/D3D9/IGL_D3D9.cs @@ -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; } diff --git a/src/BizHawk.Bizware.Graphics/D3D9/SharpDXExtensions.cs b/src/BizHawk.Bizware.Graphics/D3D9/SharpDXExtensions.cs index a0b086d2d8..ee650588a6 100644 --- a/src/BizHawk.Bizware.Graphics/D3D9/SharpDXExtensions.cs +++ b/src/BizHawk.Bizware.Graphics/D3D9/SharpDXExtensions.cs @@ -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 }; } diff --git a/src/BizHawk.Bizware.Graphics/GuiRenderer.cs b/src/BizHawk.Bizware.Graphics/GuiRenderer.cs index 1c3efcb6b9..f48bd85040 100644 --- a/src/BizHawk.Bizware.Graphics/GuiRenderer.cs +++ b/src/BizHawk.Bizware.Graphics/GuiRenderer.cs @@ -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 /// no pipeline set (need to call ) 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 } /// is 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; diff --git a/src/BizHawk.Bizware.Graphics/OpenGL/IGL_OpenGL.cs b/src/BizHawk.Bizware.Graphics/OpenGL/IGL_OpenGL.cs index eba1c8b004..5419e60628 100644 --- a/src/BizHawk.Bizware.Graphics/OpenGL/IGL_OpenGL.cs +++ b/src/BizHawk.Bizware.Graphics/OpenGL/IGL_OpenGL.cs @@ -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; } diff --git a/src/BizHawk.Client.Common/DisplayManager/DisplayManagerBase.cs b/src/BizHawk.Client.Common/DisplayManager/DisplayManagerBase.cs index abf64ac7fc..2b29be8b9b 100644 --- a/src/BizHawk.Client.Common/DisplayManager/DisplayManagerBase.cs +++ b/src/BizHawk.Client.Common/DisplayManager/DisplayManagerBase.cs @@ -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 /// /// custom fonts that don't need to be installed on the user side /// - 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(); 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 properties) + private static void AppendRetroShaderChain(FilterProgram program, string name, RetroShaderChain retroChain, Dictionary 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); /// /// 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 /// 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(); /// /// 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 /// 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(); - 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; } - - /// always - public int VsyncNumerator => throw new InvalidOperationException(); - - /// always - 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 /// 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 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 _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 /// already unlocked 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); diff --git a/src/BizHawk.Client.Common/DisplayManager/FilterManager.cs b/src/BizHawk.Client.Common/DisplayManager/FilterManager.cs index 095ab38bd6..903e1d936a 100644 --- a/src/BizHawk.Client.Common/DisplayManager/FilterManager.cs +++ b/src/BizHawk.Client.Common/DisplayManager/FilterManager.cs @@ -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 _filterNameIndex = new Dictionary(); + private readonly Dictionary _filterNameIndex = new(); public readonly IList Filters = new List(); public readonly IList Program = new List(); @@ -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 /// 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; } } diff --git a/src/BizHawk.Client.Common/DisplayManager/Filters/BaseFilter.cs b/src/BizHawk.Client.Common/DisplayManager/Filters/BaseFilter.cs index fc452ba3b0..a373513ad3 100644 --- a/src/BizHawk.Client.Common/DisplayManager/Filters/BaseFilter.cs +++ b/src/BizHawk.Client.Common/DisplayManager/Filters/BaseFilter.cs @@ -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 Parameters = new Dictionary(); - 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 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 _ioSurfaceInfos = new List(); + private readonly List _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 diff --git a/src/BizHawk.Client.Common/DisplayManager/Filters/Gui.cs b/src/BizHawk.Client.Common/DisplayManager/Filters/Gui.cs index 903a789aa6..3c23c3f5c0 100644 --- a/src/BizHawk.Client.Common/DisplayManager/Filters/Gui.cs +++ b/src/BizHawk.Client.Common/DisplayManager/Filters/Gui.cs @@ -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 /// /// In case you want to do it yourself /// - 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 trials = stackalloc Vector2[3]; + Span 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 /// 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; diff --git a/src/BizHawk.Client.Common/DisplayManager/Filters/Retro.cs b/src/BizHawk.Client.Common/DisplayManager/Filters/Retro.cs index 75a5ab8541..8c4110482b 100644 --- a/src/BizHawk.Client.Common/DisplayManager/Filters/Retro.cs +++ b/src/BizHawk.Client.Common/DisplayManager/Filters/Retro.cs @@ -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 Shaders = Array.Empty(); public readonly RetroShaderPreset.ShaderPass[] Passes; @@ -122,55 +132,70 @@ namespace BizHawk.Client.Common.Filters var content = new StreamReader(stream).ReadToEnd(); var dict = new Dictionary(); - //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 Passes { get; set; } = new List(); - + public List 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 dict, string key, bool @default) + private static bool FetchBool(IDictionary 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) { diff --git a/src/BizHawk.Client.Common/DisplayManager/Filters/Utils.cs b/src/BizHawk.Client.Common/DisplayManager/Filters/Utils.cs index 0f4eb131ff..e0852b5592 100644 --- a/src/BizHawk.Client.Common/DisplayManager/Filters/Utils.cs +++ b/src/BizHawk.Client.Common/DisplayManager/Filters/Utils.cs @@ -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); } } } \ No newline at end of file diff --git a/src/BizHawk.Client.EmuHawk/GraphicsImplementations/GLControlWrapper_GdiPlus.cs b/src/BizHawk.Client.EmuHawk/GraphicsImplementations/GLControlWrapper_GdiPlus.cs index e2d39000d3..6412d2b61a 100644 --- a/src/BizHawk.Client.EmuHawk/GraphicsImplementations/GLControlWrapper_GdiPlus.cs +++ b/src/BizHawk.Client.EmuHawk/GraphicsImplementations/GLControlWrapper_GdiPlus.cs @@ -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; - - /// /// the render target for rendering to this control /// @@ -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;