From ef4bb14d5989c3c5999e336af2a751ea6977b9de Mon Sep 17 00:00:00 2001 From: goyuken Date: Mon, 5 Nov 2012 15:58:51 +0000 Subject: [PATCH] gb gpu view: oam --- .../Consoles/Nintendo/Gameboy/Gambatte.cs | 9 +- .../Consoles/Nintendo/Gameboy/LibGambatte.cs | 2 +- BizHawk.MultiClient/GBtools/BmpView.cs | 13 +- .../GBtools/GBGPUView.Designer.cs | 23 +++ BizHawk.MultiClient/GBtools/GBGPUView.cs | 146 ++++++++++++++++-- 5 files changed, 177 insertions(+), 16 deletions(-) diff --git a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs index b0e1c719e5..33cb2ed4c3 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs @@ -151,13 +151,15 @@ namespace BizHawk.Emulation.Consoles.GB IntPtr vram = IntPtr.Zero; IntPtr bgpal = IntPtr.Zero; IntPtr sppal = IntPtr.Zero; + IntPtr oam = IntPtr.Zero; int unused = 0; if (!LibGambatte.gambatte_getmemoryarea(GambatteState, LibGambatte.MemoryAreas.vram, ref vram, ref unused) || !LibGambatte.gambatte_getmemoryarea(GambatteState, LibGambatte.MemoryAreas.bgpal, ref bgpal, ref unused) - || !LibGambatte.gambatte_getmemoryarea(GambatteState, LibGambatte.MemoryAreas.sppal, ref sppal, ref unused)) + || !LibGambatte.gambatte_getmemoryarea(GambatteState, LibGambatte.MemoryAreas.sppal, ref sppal, ref unused) + || !LibGambatte.gambatte_getmemoryarea(GambatteState, LibGambatte.MemoryAreas.oam, ref oam, ref unused)) throw new Exception(); - scanlinecallback(vram, IsCGBMode(), LibGambatte.gambatte_cpuread(GambatteState, 0xff40), bgpal, sppal); + scanlinecallback(vram, IsCGBMode(), LibGambatte.gambatte_cpuread(GambatteState, 0xff40), bgpal, sppal, oam); } LibGambatte.gambatte_runfor(GambatteState, VideoBuffer, 160, soundbuff, ref nsamp); @@ -599,7 +601,8 @@ namespace BizHawk.Emulation.Consoles.GB /// /// /// - public delegate void ScanlineCallback(IntPtr vram, bool cgb, int lcdc, IntPtr bgpal, IntPtr sppal); + /// + public delegate void ScanlineCallback(IntPtr vram, bool cgb, int lcdc, IntPtr bgpal, IntPtr sppal, IntPtr oam); ScanlineCallback scanlinecallback; diff --git a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/LibGambatte.cs b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/LibGambatte.cs index 6fee608d6f..17e248e7a7 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/LibGambatte.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/LibGambatte.cs @@ -316,7 +316,7 @@ namespace BizHawk.Emulation.Consoles.GB cartram = 3, oam = 4, hram = 5, - // these last two aren't returning native memory area data + // these last two aren't returning native memory area data, but instead converted RGB32 colors bgpal = 6, sppal = 7 } diff --git a/BizHawk.MultiClient/GBtools/BmpView.cs b/BizHawk.MultiClient/GBtools/BmpView.cs index f16dfa595e..981e4e234a 100644 --- a/BizHawk.MultiClient/GBtools/BmpView.cs +++ b/BizHawk.MultiClient/GBtools/BmpView.cs @@ -23,9 +23,15 @@ namespace BizHawk.MultiClient.GBtools SetStyle(ControlStyles.Opaque, true); this.BackColor = Color.Transparent; this.Paint += new PaintEventHandler(BmpView_Paint); + this.SizeChanged += new EventHandler(BmpView_SizeChanged); ChangeBitmapSize(1, 1); } + void BmpView_SizeChanged(object sender, EventArgs e) + { + scaled = !(bmp.Width == Width && bmp.Height == Height); + } + void BmpView_Paint(object sender, PaintEventArgs e) { if (scaled) @@ -48,9 +54,14 @@ namespace BizHawk.MultiClient.GBtools public void ChangeBitmapSize(int w, int h) { if (bmp != null) + { + if (w == bmp.Width && h == bmp.Height) + return; bmp.Dispose(); + } bmp = new Bitmap(w, h, System.Drawing.Imaging.PixelFormat.Format32bppArgb); - scaled = !(w == Width && h == Height); + BmpView_SizeChanged(null, null); + Refresh(); } public void Clear() diff --git a/BizHawk.MultiClient/GBtools/GBGPUView.Designer.cs b/BizHawk.MultiClient/GBtools/GBGPUView.Designer.cs index e09965dc02..d77fb0a528 100644 --- a/BizHawk.MultiClient/GBtools/GBGPUView.Designer.cs +++ b/BizHawk.MultiClient/GBtools/GBGPUView.Designer.cs @@ -40,6 +40,8 @@ this.bmpViewTiles1 = new BizHawk.MultiClient.GBtools.BmpView(); this.bmpViewWin = new BizHawk.MultiClient.GBtools.BmpView(); this.bmpViewBG = new BizHawk.MultiClient.GBtools.BmpView(); + this.bmpViewOAM = new BizHawk.MultiClient.GBtools.BmpView(); + this.label7 = new System.Windows.Forms.Label(); this.SuspendLayout(); // // label1 @@ -150,11 +152,30 @@ this.bmpViewBG.TabIndex = 4; this.bmpViewBG.Text = "bmpView1"; // + // bmpViewOAM + // + this.bmpViewOAM.BackColor = System.Drawing.Color.Transparent; + this.bmpViewOAM.Location = new System.Drawing.Point(12, 300); + this.bmpViewOAM.Name = "bmpViewOAM"; + this.bmpViewOAM.Size = new System.Drawing.Size(320, 16); + this.bmpViewOAM.TabIndex = 14; + // + // label7 + // + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(9, 284); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(31, 13); + this.label7.TabIndex = 15; + this.label7.Text = "OAM"; + // // GBGPUView // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(951, 414); + this.Controls.Add(this.label7); + this.Controls.Add(this.bmpViewOAM); this.Controls.Add(this.label6); this.Controls.Add(this.label5); this.Controls.Add(this.bmpViewSPPal); @@ -190,5 +211,7 @@ private BmpView bmpViewSPPal; private System.Windows.Forms.Label label5; private System.Windows.Forms.Label label6; + private BmpView bmpViewOAM; + private System.Windows.Forms.Label label7; } } \ No newline at end of file diff --git a/BizHawk.MultiClient/GBtools/GBGPUView.cs b/BizHawk.MultiClient/GBtools/GBGPUView.cs index 91d02f5c55..742d2216ec 100644 --- a/BizHawk.MultiClient/GBtools/GBGPUView.cs +++ b/BizHawk.MultiClient/GBtools/GBGPUView.cs @@ -22,6 +22,7 @@ namespace BizHawk.MultiClient.GBtools bmpViewTiles2.ChangeBitmapSize(128, 192); bmpViewBGPal.ChangeBitmapSize(8, 4); bmpViewSPPal.ChangeBitmapSize(8, 4); + bmpViewOAM.ChangeBitmapSize(320, 16); } public void Restart() @@ -62,7 +63,14 @@ namespace BizHawk.MultiClient.GBtools gb.SetScanlineCallback(null, 0); } - static unsafe void DrawTileDMG(byte* tile, int* dest, int pitch, int *pal) + /// + /// draw a single 2bpp tile + /// + /// 16 byte 2bpp 8x8 tile (gb format) + /// top left origin on 32bit bitmap + /// pitch of bitmap in 4 byte units + /// 4 palette colors + static unsafe void DrawTile(byte* tile, int* dest, int pitch, int *pal) { for (int y = 0; y < 8; y++) { @@ -82,7 +90,16 @@ namespace BizHawk.MultiClient.GBtools } } - static unsafe void DrawTileCGB(byte* tile, int* dest, int pitch, int* pal, bool hflip, bool vflip) + /// + /// draw a single 2bpp tile, with hflip and vflip + /// + /// 16 byte 2bpp 8x8 tile (gb format) + /// top left origin on 32bit bitmap + /// pitch of bitmap in 4 byte units + /// 4 palette colors + /// true to flip horizontally + /// true to flip vertically + static unsafe void DrawTileHV(byte* tile, int* dest, int pitch, int* pal, bool hflip, bool vflip) { if (vflip) dest += pitch * 7; @@ -115,6 +132,14 @@ namespace BizHawk.MultiClient.GBtools } } + /// + /// draw a bg map, cgb format + /// + /// bitmap to draw to, should be 256x256 + /// tilemap, 32x32 bytes. extended tilemap assumed to be @+8k + /// base tiledata location. second bank tiledata assumed to be @+8k + /// true if tileindexes are s8 (not u8) + /// 8 palettes (4 colors each) static unsafe void DrawBGCGB(Bitmap b, IntPtr _map, IntPtr _tiles, bool wrap, IntPtr _pal) { var lockdata = b.LockBits(new Rectangle(0, 0, 256, 256), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); @@ -137,7 +162,7 @@ namespace BizHawk.MultiClient.GBtools int* thispal = pal + 4 * (tileext & 7); - DrawTileCGB(tile, dest, pitch, thispal, tileext.Bit(5), tileext.Bit(6)); + DrawTileHV(tile, dest, pitch, thispal, tileext.Bit(5), tileext.Bit(6)); map++; dest += 8; } @@ -147,6 +172,14 @@ namespace BizHawk.MultiClient.GBtools b.UnlockBits(lockdata); } + /// + /// draw a bg map, dmg format + /// + /// bitmap to draw to, should be 256x256 + /// tilemap, 32x32 bytes + /// base tiledata location + /// true if tileindexes are s8 (not u8) + /// 1 palette (4 colors) static unsafe void DrawBGDMG(Bitmap b, IntPtr _map, IntPtr _tiles, bool wrap, IntPtr _pal) { var lockdata = b.LockBits(new Rectangle(0, 0, 256, 256), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); @@ -163,7 +196,7 @@ namespace BizHawk.MultiClient.GBtools if (wrap && tileindex >= 128) tileindex -= 256; byte* tile = (byte*)(_tiles + tileindex * 16); - DrawTileDMG(tile, dest, pitch, pal); + DrawTile(tile, dest, pitch, pal); map++; dest += 8; } @@ -173,6 +206,12 @@ namespace BizHawk.MultiClient.GBtools b.UnlockBits(lockdata); } + /// + /// draw a full bank of 384 tiles + /// + /// bitmap to draw to, should be 128x192 + /// base tile address + /// single palette to use on all tiles static unsafe void DrawTiles(Bitmap b, IntPtr _tiles, IntPtr _pal) { var lockdata = b.LockBits(new Rectangle(0, 0, 128, 192), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); @@ -185,7 +224,7 @@ namespace BizHawk.MultiClient.GBtools { for (int tx = 0; tx < 16; tx++) { - DrawTileDMG(tile, dest, pitch, pal); + DrawTile(tile, dest, pitch, pal); tile += 16; dest += 8; } @@ -195,14 +234,62 @@ namespace BizHawk.MultiClient.GBtools b.UnlockBits(lockdata); } - static unsafe void DrawPal(Bitmap b, IntPtr _pal) + /// + /// draw oam data + /// + /// bitmap to draw to. should be 320x8 (!tall), 320x16 (tall) + /// oam data, 4 * 40 bytes + /// base tiledata location. cgb: second bank tiledata assumed to be @+8k + /// 2 (dmg) or 8 (cgb) palettes + /// true for 8x16 sprites; else 8x8 + /// true for cgb (more palettes, second bank tiles) + static unsafe void DrawOam(Bitmap b, IntPtr _oam, IntPtr _tiles, IntPtr _pal, bool tall, bool cgb) { - var lockdata = b.LockBits(new Rectangle(0, 0, 8, 4), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + var lockdata = b.LockBits(new Rectangle(0, 0, 320, tall ? 16 : 8), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + int* dest = (int*)lockdata.Scan0; + int pitch = lockdata.Stride / sizeof(int); + int* pal = (int*)_pal; + byte *oam = (byte*)_oam; + + for (int s = 0; s < 40; s++) + { + oam += 2; // ypos, xpos + int tileindex = *oam++; + int flags = *oam++; + bool vflip = flags.Bit(6); + bool hflip = flags.Bit(5); + if (tall) + // i assume 8x16 vflip flips the whole thing, not just each tile? + if (vflip) + tileindex |= 1; + else + tileindex &= 0xfe; + byte* tile = (byte*)(_tiles + tileindex * 16); + int* thispal = pal + 4 * (cgb ? flags & 7 : flags >> 4 & 1); + if (cgb && flags.Bit(3)) + tile += 8192; + DrawTileHV(tile, dest, pitch, thispal, hflip, vflip); + if (tall) + DrawTileHV((byte*)((int)tile ^ 16), dest + pitch * 8, pitch, thispal, hflip, vflip); + dest += 8; + } + b.UnlockBits(lockdata); + } + + /// + /// draw a palette directly + /// + /// bitmap to draw to. should be numpals x 4 + /// start of palettes + /// number of palettes (not colors) + static unsafe void DrawPal(Bitmap b, IntPtr _pal, int numpals) + { + var lockdata = b.LockBits(new Rectangle(0, 0, numpals, 4), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); int* dest = (int*)lockdata.Scan0; int pitch = lockdata.Stride / sizeof(int); int* pal = (int*)_pal; - for (int px = 0; px < 8; px++) + for (int px = 0; px < numpals; px++) { for (int py = 0; py < 4; py++) { @@ -215,7 +302,7 @@ namespace BizHawk.MultiClient.GBtools b.UnlockBits(lockdata); } - void ScanlineCallback(IntPtr vram, bool cgb, int lcdc, IntPtr bgpal, IntPtr sppal) + void ScanlineCallback(IntPtr vram, bool cgb, int lcdc, IntPtr bgpal, IntPtr sppal, IntPtr oam) { // set alpha on all pixels unsafe @@ -276,10 +363,47 @@ namespace BizHawk.MultiClient.GBtools bmpViewTiles2.Refresh(); } - DrawPal(bmpViewBGPal.bmp, bgpal); - DrawPal(bmpViewSPPal.bmp, sppal); + // palettes + if (cgb) + { + bmpViewBGPal.ChangeBitmapSize(8, 4); + if (bmpViewBGPal.Width != 128) + bmpViewBGPal.Width = 128; + bmpViewSPPal.ChangeBitmapSize(8, 4); + if (bmpViewSPPal.Width != 128) + bmpViewSPPal.Width = 128; + DrawPal(bmpViewBGPal.bmp, bgpal, 8); + DrawPal(bmpViewSPPal.bmp, sppal, 8); + } + else + { + bmpViewBGPal.ChangeBitmapSize(1, 4); + if (bmpViewBGPal.Width != 16) + bmpViewBGPal.Width = 16; + bmpViewSPPal.ChangeBitmapSize(2, 4); + if (bmpViewSPPal.Width != 32) + bmpViewSPPal.Width = 32; + DrawPal(bmpViewBGPal.bmp, bgpal, 1); + DrawPal(bmpViewSPPal.bmp, sppal, 2); + } bmpViewBGPal.Refresh(); bmpViewSPPal.Refresh(); + + // oam + if (lcdc.Bit(2)) // 8x16 + { + bmpViewOAM.ChangeBitmapSize(320, 16); + if (bmpViewOAM.Height != 16) + bmpViewOAM.Height = 16; + } + else + { + bmpViewOAM.ChangeBitmapSize(320, 8); + if (bmpViewOAM.Height != 8) + bmpViewOAM.Height = 8; + } + DrawOam(bmpViewOAM.bmp, oam, vram, sppal, lcdc.Bit(2), cgb); + bmpViewOAM.Refresh(); } private void GBGPUView_FormClosed(object sender, FormClosedEventArgs e)