Updated graphics renderer to allow for pixel perfect resizing

This commit is contained in:
2026-04-24 14:47:10 +01:00
parent 2842af182f
commit dce4240842
2 changed files with 57 additions and 24 deletions

View File

@@ -18,6 +18,7 @@ namespace Desktop
private TapManager _tapManager = null!;
private DebuggerForm? _debugger = null;
private BeeperDevice _beeper = null!;
private Bitmap _screenBitmap = null!;
private string _baseTitle = "";
private bool _isRunning = false;
private bool _isPaused = false;
@@ -34,6 +35,8 @@ namespace Desktop
public Form1()
{
InitializeComponent();
this.DoubleBuffered = true;
this.ResizeRedraw = true;
InitializeEmulator();
}
@@ -173,7 +176,10 @@ namespace Desktop
{
this.BeginInvoke((MethodInvoker)delegate
{
UpdateScreenBitmap();
UpdateScreenBitmap(); // Your existing method that writes the ULA data to _screenBitmap
this.Invalidate(); // Tells Windows: "The bitmap changed, please run OnPaint()!"
this.Text = $"{_baseTitle} - FPS: {FramesPerSecond:F1}";
});
}
@@ -181,10 +187,13 @@ namespace Desktop
}
else
{
this.Invoke((MethodInvoker)delegate
this.BeginInvoke((MethodInvoker)delegate
{
UpdateScreenBitmap();
this.Text = $"{_baseTitle} - FPS: {FramesPerSecond:F1} - Tape Loaded: {tapeLoaded.ToString()}";
UpdateScreenBitmap(); // Your existing method that writes the ULA data to _screenBitmap
this.Invalidate(); // Tells Windows: "The bitmap changed, please run OnPaint()!"
this.Text = $"{_baseTitle} - FPS: {FramesPerSecond:F1}";
});
}
@@ -225,6 +234,40 @@ namespace Desktop
});
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
// If we don't have a screen bitmap yet, just paint the background black and exit
if (_screenBitmap == null)
{
e.Graphics.Clear(Color.Black);
return;
}
// 1. Calculate the scaling factor to fit the window while preserving aspect ratio
float scaleX = (float)this.ClientSize.Width / _screenBitmap.Width;
float scaleY = (float)this.ClientSize.Height / _screenBitmap.Height;
float scale = Math.Min(scaleX, scaleY); // Pick the smallest scale so it fits inside
int newWidth = (int)(_screenBitmap.Width * scale);
int newHeight = (int)(_screenBitmap.Height * scale);
// 2. Center the image horizontally and vertically (Pillarboxing/Letterboxing)
int posX = (this.ClientSize.Width - newWidth) / 2;
int posY = (this.ClientSize.Height - newHeight) / 2;
// 3. RETRO MAGIC: Force Nearest-Neighbor interpolation for razor-sharp pixels!
e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
// PixelOffsetMode.Half is a GDI+ trick required to make NearestNeighbor perfectly accurate
e.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half;
// 4. Paint the black borders (if any) and draw the screen
e.Graphics.Clear(Color.Black);
e.Graphics.DrawImage(_screenBitmap, posX, posY, newWidth, newHeight);
}
private void HandleInstantTapeLoad()
{
byte[] block = _tapManager.GetNextBlock(); // Your original Queue.Dequeue() method
@@ -271,7 +314,7 @@ namespace Desktop
_cpu.SP++;
_cpu.PC = (ushort)((pcHigh << 8) | pcLow);
}
private void UpdateScreenBitmap()
{
@@ -286,8 +329,14 @@ namespace Desktop
Marshal.Copy(_ula.FrameBuffer, 0, bmpData.Scan0, _ula.FrameBuffer.Length);
bmp.UnlockBits(bmpData);
if (picScreen.Image != null) picScreen.Image.Dispose();
picScreen.Image = bmp;
// Dispose of the old frame to prevent massive RAM leaks!
if (_screenBitmap != null)
{
_screenBitmap.Dispose();
}
// Save the new frame so OnPaint() can draw it
_screenBitmap = bmp;
}
private void loadTAPToolStripMenuItem_Click(object sender, EventArgs e)