Added VRAM Viewer and tried to fix noise channel
This commit is contained in:
100
Desktop/VramViewerForm.cs
Normal file
100
Desktop/VramViewerForm.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
using Core.Video;
|
||||
|
||||
namespace Desktop
|
||||
{
|
||||
public class VramViewerForm : Form
|
||||
{
|
||||
private readonly SmsVdp _vdp;
|
||||
private readonly System.Windows.Forms.Timer _refreshTimer;
|
||||
private readonly Bitmap _vramBitmap;
|
||||
private readonly int[] _pixelData;
|
||||
|
||||
public VramViewerForm(SmsVdp vdp)
|
||||
{
|
||||
_vdp = vdp;
|
||||
this.Text = "VRAM Viewer (512 Tiles)";
|
||||
|
||||
// 256x128 native resolution, scaled up by 2 for visibility!
|
||||
this.ClientSize = new Size(512, 256);
|
||||
this.DoubleBuffered = true;
|
||||
this.FormBorderStyle = FormBorderStyle.FixedToolWindow;
|
||||
|
||||
_vramBitmap = new Bitmap(256, 128, PixelFormat.Format32bppArgb);
|
||||
_pixelData = new int[256 * 128];
|
||||
|
||||
// Update the window 10 times a second so it doesn't drain CPU power
|
||||
_refreshTimer = new System.Windows.Forms.Timer();
|
||||
_refreshTimer.Interval = 100;
|
||||
_refreshTimer.Tick += (s, e) => UpdateVramImage();
|
||||
_refreshTimer.Start();
|
||||
}
|
||||
|
||||
private void UpdateVramImage()
|
||||
{
|
||||
if (_vdp == null) return;
|
||||
|
||||
// Loop through all 512 tiles in VRAM
|
||||
for (int tile = 0; tile < 512; tile++)
|
||||
{
|
||||
// Calculate grid position (32 columns, 16 rows)
|
||||
int tileX = (tile % 32) * 8;
|
||||
int tileY = (tile / 32) * 8;
|
||||
int tileAddress = tile * 32;
|
||||
|
||||
// Decode the 8x8 pixels
|
||||
for (int y = 0; y < 8; y++)
|
||||
{
|
||||
byte bp0 = _vdp.VRAM[tileAddress + (y * 4) + 0];
|
||||
byte bp1 = _vdp.VRAM[tileAddress + (y * 4) + 1];
|
||||
byte bp2 = _vdp.VRAM[tileAddress + (y * 4) + 2];
|
||||
byte bp3 = _vdp.VRAM[tileAddress + (y * 4) + 3];
|
||||
|
||||
for (int x = 0; x < 8; x++)
|
||||
{
|
||||
int shift = 7 - x;
|
||||
int colorIndex = ((bp0 >> shift) & 1) | (((bp1 >> shift) & 1) << 1) |
|
||||
(((bp2 >> shift) & 1) << 2) | (((bp3 >> shift) & 1) << 3);
|
||||
|
||||
// Use the Sprite Palette (Offset 16) so characters and enemies are colored correctly
|
||||
byte smsColor = _vdp.CRAM[16 + colorIndex];
|
||||
int r = (smsColor & 0x03) * 85;
|
||||
int g = ((smsColor >> 2) & 0x03) * 85;
|
||||
int b = ((smsColor >> 4) & 0x03) * 85;
|
||||
|
||||
// Background color (Index 0) is technically transparent for sprites, so we render it as magenta
|
||||
if (colorIndex == 0) { r = 255; g = 0; b = 255; }
|
||||
|
||||
_pixelData[((tileY + y) * 256) + (tileX + x)] = (255 << 24) | (r << 16) | (g << 8) | b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Blast the array into the Bitmap
|
||||
var data = _vramBitmap.LockBits(new Rectangle(0, 0, 256, 128), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
|
||||
Marshal.Copy(_pixelData, 0, data.Scan0, _pixelData.Length);
|
||||
_vramBitmap.UnlockBits(data);
|
||||
|
||||
this.Invalidate();
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
base.OnPaint(e);
|
||||
// Draw it chunky and pixel-perfect
|
||||
e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
|
||||
e.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half;
|
||||
e.Graphics.DrawImage(_vramBitmap, new Rectangle(0, 0, this.ClientSize.Width, this.ClientSize.Height));
|
||||
}
|
||||
|
||||
protected override void OnFormClosing(FormClosingEventArgs e)
|
||||
{
|
||||
_refreshTimer.Stop();
|
||||
base.OnFormClosing(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user