using System; using System.Drawing; using System.Drawing.Imaging; using System.Collections.Generic; using System.Runtime.InteropServices; using BizHawk.Common; using BizHawk.Client.Common; namespace BizHawk.Client.EmuHawk { /// /// This is a wrapper for a Bitmap, basically, which can also be a int[]. /// It should be phased out, in favor of BitmapBuffer and Texture2d's /// public unsafe class DisplaySurface : IDisposable { Bitmap bmp; BitmapData bmpdata; int[] pixels; public unsafe void Clear() { FromBitmap(false); Util.Memset(PixelPtr, 0, Stride * Height); } public Bitmap PeekBitmap() { ToBitmap(); return bmp; } /// /// returns a Graphics object used to render to this surface. be sure to dispose it! /// public Graphics GetGraphics() { ToBitmap(); return Graphics.FromImage(bmp); } public unsafe void ToBitmap(bool copy=true) { if (isBitmap) return; isBitmap = true; if (bmp == null) { bmp = new Bitmap(Width, Height, PixelFormat.Format32bppArgb); } if (copy) { bmpdata = bmp.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); int w = Width; int h = Height; int stride = bmpdata.Stride / 4; int* bmpbuf = (int*)bmpdata.Scan0.ToPointer(); for (int y = 0, i = 0; y < h; y++) for (int x = 0; x < w; x++) bmpbuf[y * stride + x] = pixels[i++]; bmp.UnlockBits(bmpdata); } } public bool IsBitmap { get { return isBitmap; } } bool isBitmap = false; public unsafe void FromBitmap(bool copy=true) { if (!isBitmap) return; isBitmap = false; if (copy) { bmpdata = bmp.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); int w = Width; int h = Height; int stride = bmpdata.Stride / 4; int* bmpbuf = (int*)bmpdata.Scan0.ToPointer(); for (int y = 0, i = 0; y < h; y++) for (int x = 0; x < w; x++) pixels[i++] = bmpbuf[y * stride + x]; bmp.UnlockBits(bmpdata); } } public static DisplaySurface DisplaySurfaceWrappingBitmap(Bitmap bmp) { DisplaySurface ret = new DisplaySurface(); ret.Width = bmp.Width; ret.Height = bmp.Height; ret.bmp = bmp; ret.isBitmap = true; return ret; } private DisplaySurface() { } public DisplaySurface(int width, int height) { //can't create a bitmap with zero dimensions, so for now, just bump it up to one if (width == 0) width = 1; if (height == 0) height = 1; Width = width; Height = height; pixels = new int[width * height]; LockPixels(); } public int* PixelPtr { get { return (int*)ptr; } } public IntPtr PixelIntPtr { get { return new IntPtr(ptr); } } public int Stride { get { return Width*4; } } public int OffsetOf(int x, int y) { return y * Stride + x*4; } void* ptr; GCHandle handle; void LockPixels() { UnlockPixels(); handle = GCHandle.Alloc(pixels, GCHandleType.Pinned); ptr = handle.AddrOfPinnedObject().ToPointer(); } void UnlockPixels() { if(handle.IsAllocated) handle.Free(); } /// /// returns a new surface /// public DisplaySurface ToPaddedSurface(int xpad0, int ypad0, int xpad1, int ypad1) { int new_width = Width + xpad0 + xpad1; int new_height = Height + ypad0 + ypad1; DisplaySurface ret = new DisplaySurface(new_width, new_height); int* dptr = ret.PixelPtr; int* sptr = PixelPtr; int dstride = ret.Stride / 4; int sstride = Stride / 4; for (int y = 0; y < Height; y++) for (int x = 0; x < Width; x++) { dptr[(y + ypad0) * dstride + x + xpad0] = sptr[y * sstride + x]; } return ret; } public int Width { get; private set; } public int Height { get; private set; } public void Dispose() { if (bmp != null) bmp.Dispose(); bmp = null; UnlockPixels(); } //public unsafe int[] ToIntArray() { } public void AcceptIntArray(int[] newpixels) { FromBitmap(false); UnlockPixels(); pixels = newpixels; LockPixels(); } } }