diff --git a/BizHawk.Client.Common/QuickBmpFile.cs b/BizHawk.Client.Common/QuickBmpFile.cs index b8234cd896..cb281ec6ae 100644 --- a/BizHawk.Client.Common/QuickBmpFile.cs +++ b/BizHawk.Client.Common/QuickBmpFile.cs @@ -24,6 +24,14 @@ namespace BizHawk.Client.Common { bfSize = (uint)Marshal.SizeOf(this); } + + public static BITMAPFILEHEADER FromStream(Stream s) + { + var ret = GetObject(s); + if (ret.bfSize != Marshal.SizeOf(typeof(BITMAPFILEHEADER))) + throw new InvalidOperationException(); + return ret; + } } [StructLayout(LayoutKind.Sequential)] @@ -45,6 +53,14 @@ namespace BizHawk.Client.Common { biSize = (uint)Marshal.SizeOf(this); } + + public static BITMAPINFOHEADER FromStream(Stream s) + { + var ret = GetObject(s); + if (ret.biSize != Marshal.SizeOf(typeof(BITMAPINFOHEADER))) + throw new InvalidOperationException(); + return ret; + } } enum BitmapCompressionMode : uint @@ -68,6 +84,57 @@ namespace BizHawk.Client.Common return ret; } + private unsafe static T GetObject(Stream s) + { + byte[] tmp = new byte[Marshal.SizeOf(typeof(T))]; + s.Read(tmp, 0, tmp.Length); + fixed (byte* p = tmp) + { + return (T)Marshal.PtrToStructure((IntPtr)p, typeof(T)); + } + } + + public unsafe static bool Load(IVideoProvider v, Stream s) + { + var bf = BITMAPFILEHEADER.FromStream(s); + var bi = BITMAPINFOHEADER.FromStream(s); + if (bf.bfType != 0x4d42 + || bf.bfOffBits != bf.bfSize + bi.biSize + || bi.biPlanes != 1 + || bi.biBitCount != 32 + || bi.biCompression != BitmapCompressionMode.BI_RGB) + return false; + int in_w = bi.biWidth; + int in_h = bi.biHeight; + + byte[] src = new byte[in_w * in_h * 4]; + s.Read(src, 0, src.Length); + int[] dst = v.GetVideoBuffer(); + + fixed (byte *srcp = src) + fixed (int* dstp = dst) + { + int w = v.BufferWidth; + int h = v.BufferHeight; + + int* sp = (int*)srcp; + int* dp = dstp; + + // vflip along the way + for (int j = h - 1; j >= 0; j--) + { + sp = (int*)srcp + in_w * (j * in_h / h); + for (int i = 0; i < w; i++) + { + dp[i] = sp[i * in_w / w]; + } + dp += w; + } + } + + return true; + } + public unsafe static void Save(IVideoProvider v, Stream s, int w, int h) { var bf = new BITMAPFILEHEADER(); diff --git a/BizHawk.Client.Common/SavestateManager.cs b/BizHawk.Client.Common/SavestateManager.cs index 6063f4fffc..aa47bf3eaa 100644 --- a/BizHawk.Client.Common/SavestateManager.cs +++ b/BizHawk.Client.Common/SavestateManager.cs @@ -59,22 +59,31 @@ namespace BizHawk.Client.Common public static void PopulateFramebuffer(BinaryReader br) { - var buff = Global.Emulator.VideoProvider().GetVideoBuffer(); try { - for (int i = 0; i < buff.Length; i++) - { - int j = br.ReadInt32(); - buff[i] = j; - } + QuickBmpFile.Load(Global.Emulator.VideoProvider(), br.BaseStream); + } + catch + { + var buff = Global.Emulator.VideoProvider().GetVideoBuffer(); + try + { + for (int i = 0; i < buff.Length; i++) + { + int j = br.ReadInt32(); + buff[i] = j; + } + } + catch (EndOfStreamException) { } } - catch (EndOfStreamException) { } } - public static void DumpFramebuffer(BinaryWriter bw) + public static void DumpFramebuffer(Stream s) { - bw.Write(Global.Emulator.VideoProvider().GetVideoBuffer()); + //bw.Write(Global.Emulator.VideoProvider().GetVideoBuffer()); + QuickBmpFile.Save(Global.Emulator.VideoProvider(), s, r.Next(50, 500), r.Next(50, 500)); } + static Random r = new Random(); public static bool LoadStateFile(string path, string name) {