Implemenmted rendering priorities
This commit is contained in:
@@ -9,6 +9,7 @@ namespace Core.Video
|
|||||||
public byte[] CRAM { get; private set; } = new byte[0x20]; // 32 Bytes Color Palette
|
public byte[] CRAM { get; private set; } = new byte[0x20]; // 32 Bytes Color Palette
|
||||||
public byte[] Registers { get; private set; } = new byte[16]; // 11 Hardware Control Registers
|
public byte[] Registers { get; private set; } = new byte[16]; // 11 Hardware Control Registers
|
||||||
public int[] FrameBuffer { get; private set; } = new int[256 * 192];
|
public int[] FrameBuffer { get; private set; } = new int[256 * 192];
|
||||||
|
private bool[] _priorityBuffer = new bool[256 * 192]; // Tracks priority pixels!
|
||||||
|
|
||||||
// The Control Port State Machine (Port 0xBF)
|
// The Control Port State Machine (Port 0xBF)
|
||||||
private bool _isSecondControlByte = false;
|
private bool _isSecondControlByte = false;
|
||||||
@@ -131,18 +132,19 @@ namespace Core.Video
|
|||||||
private void RenderBackground()
|
private void RenderBackground()
|
||||||
{
|
{
|
||||||
ushort nameTableBase = (ushort)((Registers[2] & 0x0E) << 10);
|
ushort nameTableBase = (ushort)((Registers[2] & 0x0E) << 10);
|
||||||
|
|
||||||
byte scrollX = Registers[8];
|
byte scrollX = Registers[8];
|
||||||
byte scrollY = Registers[9];
|
byte scrollY = Registers[9];
|
||||||
|
|
||||||
bool lockRowScroll = (Registers[0] & 0x80) != 0; // Top 2 rows (Y < 16)
|
bool lockRowScroll = (Registers[0] & 0x80) != 0;
|
||||||
bool lockColScroll = (Registers[0] & 0x40) != 0; // Right 8 columns (X >= 192)
|
bool lockColScroll = (Registers[0] & 0x40) != 0;
|
||||||
|
|
||||||
|
// Clear the priority mask for the new frame!
|
||||||
|
Array.Clear(_priorityBuffer, 0, _priorityBuffer.Length);
|
||||||
|
|
||||||
for (int screenY = 0; screenY < 192; screenY++)
|
for (int screenY = 0; screenY < 192; screenY++)
|
||||||
{
|
{
|
||||||
for (int screenX = 0; screenX < 256; screenX++)
|
for (int screenX = 0; screenX < 256; screenX++)
|
||||||
{
|
{
|
||||||
// Apply Vertical Scrolling (Depends on X for column locking!)
|
|
||||||
int effectiveScrollY = scrollY;
|
int effectiveScrollY = scrollY;
|
||||||
if (lockColScroll && screenX >= 192) effectiveScrollY = 0;
|
if (lockColScroll && screenX >= 192) effectiveScrollY = 0;
|
||||||
|
|
||||||
@@ -150,7 +152,6 @@ namespace Core.Video
|
|||||||
int row = vdpY / 8;
|
int row = vdpY / 8;
|
||||||
int tileY = vdpY % 8;
|
int tileY = vdpY % 8;
|
||||||
|
|
||||||
// Apply Horizontal Scrolling (Depends on Y for row locking!)
|
|
||||||
int effectiveScrollX = scrollX;
|
int effectiveScrollX = scrollX;
|
||||||
if (lockRowScroll && screenY < 16) effectiveScrollX = 0;
|
if (lockRowScroll && screenY < 16) effectiveScrollX = 0;
|
||||||
|
|
||||||
@@ -158,31 +159,34 @@ namespace Core.Video
|
|||||||
int col = vdpX / 8;
|
int col = vdpX / 8;
|
||||||
int tileX = vdpX % 8;
|
int tileX = vdpX % 8;
|
||||||
|
|
||||||
// 1. Read the 16-bit Tile instruction from the Name Table
|
// 1. Read the 16-bit Tile instruction
|
||||||
ushort nameTableAddr = (ushort)(nameTableBase + (row * 64) + (col * 2));
|
ushort nameTableAddr = (ushort)(nameTableBase + (row * 64) + (col * 2));
|
||||||
byte lowByte = VRAM[nameTableAddr];
|
byte lowByte = VRAM[nameTableAddr];
|
||||||
byte highByte = VRAM[nameTableAddr + 1];
|
byte highByte = VRAM[nameTableAddr + 1];
|
||||||
ushort tileData = (ushort)((highByte << 8) | lowByte);
|
ushort tileData = (ushort)((highByte << 8) | lowByte);
|
||||||
|
|
||||||
// 2. Extract Tile Index and Palette Info
|
// 2. EXTRACT ALL THE HARDWARE BITS!
|
||||||
int tileIndex = tileData & 0x01FF;
|
int tileIndex = tileData & 0x01FF;
|
||||||
bool useSpritePalette = (tileData & 0x0800) != 0;
|
bool flipH = (tileData & 0x0200) != 0; // Bit 9
|
||||||
|
bool flipV = (tileData & 0x0400) != 0; // Bit 10
|
||||||
|
bool useSpritePalette = (tileData & 0x0800) != 0; // Bit 11
|
||||||
|
bool priority = (tileData & 0x1000) != 0; // Bit 12
|
||||||
|
|
||||||
// 3. Find the tile data in VRAM
|
// 3. Apply Vertical Flip (Read from the bottom of the tile instead of the top)
|
||||||
|
int readY = flipV ? (7 - tileY) : tileY;
|
||||||
ushort tileAddress = (ushort)(tileIndex * 32);
|
ushort tileAddress = (ushort)(tileIndex * 32);
|
||||||
|
|
||||||
// 4. Fetch the 4 bitplanes
|
byte bp0 = VRAM[tileAddress + (readY * 4) + 0];
|
||||||
byte bp0 = VRAM[tileAddress + (tileY * 4) + 0];
|
byte bp1 = VRAM[tileAddress + (readY * 4) + 1];
|
||||||
byte bp1 = VRAM[tileAddress + (tileY * 4) + 1];
|
byte bp2 = VRAM[tileAddress + (readY * 4) + 2];
|
||||||
byte bp2 = VRAM[tileAddress + (tileY * 4) + 2];
|
byte bp3 = VRAM[tileAddress + (readY * 4) + 3];
|
||||||
byte bp3 = VRAM[tileAddress + (tileY * 4) + 3];
|
|
||||||
|
|
||||||
// 5. Extract color index
|
// 4. Apply Horizontal Flip (Shift from right-to-left instead of left-to-right)
|
||||||
int shift = 7 - tileX;
|
int readX = flipH ? tileX : (7 - tileX);
|
||||||
int colorIndex = ((bp0 >> shift) & 1) |
|
int colorIndex = ((bp0 >> readX) & 1) |
|
||||||
(((bp1 >> shift) & 1) << 1) |
|
(((bp1 >> readX) & 1) << 1) |
|
||||||
(((bp2 >> shift) & 1) << 2) |
|
(((bp2 >> readX) & 1) << 2) |
|
||||||
(((bp3 >> shift) & 1) << 3);
|
(((bp3 >> readX) & 1) << 3);
|
||||||
|
|
||||||
int paletteOffset = useSpritePalette ? 16 : 0;
|
int paletteOffset = useSpritePalette ? 16 : 0;
|
||||||
byte smsColor = CRAM[paletteOffset + colorIndex];
|
byte smsColor = CRAM[paletteOffset + colorIndex];
|
||||||
@@ -191,7 +195,16 @@ namespace Core.Video
|
|||||||
int g = ((smsColor >> 2) & 0x03) * 85;
|
int g = ((smsColor >> 2) & 0x03) * 85;
|
||||||
int b = ((smsColor >> 4) & 0x03) * 85;
|
int b = ((smsColor >> 4) & 0x03) * 85;
|
||||||
|
|
||||||
FrameBuffer[(screenY * 256) + screenX] = (255 << 24) | (r << 16) | (g << 8) | b;
|
int screenAddress = (screenY * 256) + screenX;
|
||||||
|
FrameBuffer[screenAddress] = (255 << 24) | (r << 16) | (g << 8) | b;
|
||||||
|
|
||||||
|
// 5. FLAG THE PRIORITY PIXEL!
|
||||||
|
// If this tile has priority AND the pixel isn't transparent (color 0),
|
||||||
|
// tell the sprite renderer not to draw over it!
|
||||||
|
if (priority && colorIndex != 0)
|
||||||
|
{
|
||||||
|
_priorityBuffer[screenAddress] = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -262,6 +275,9 @@ namespace Core.Video
|
|||||||
// If the color index is 0, DO NOT draw it! Let the background show through.
|
// If the color index is 0, DO NOT draw it! Let the background show through.
|
||||||
if (colorIndex == 0) continue;
|
if (colorIndex == 0) continue;
|
||||||
|
|
||||||
|
// If the background tile at this exact pixel claimed priority, hide the sprite!
|
||||||
|
if (_priorityBuffer[(screenY * 256) + screenX]) continue;
|
||||||
|
|
||||||
// Sprites ALWAYS use the second half of CRAM (Palette 1: Indices 16-31)
|
// Sprites ALWAYS use the second half of CRAM (Palette 1: Indices 16-31)
|
||||||
byte smsColor = CRAM[16 + colorIndex];
|
byte smsColor = CRAM[16 + colorIndex];
|
||||||
|
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ namespace Desktop
|
|||||||
{
|
{
|
||||||
private readonly Z80 _cpu;
|
private readonly Z80 _cpu;
|
||||||
private readonly SmsMemoryBus _memoryBus;
|
private readonly SmsMemoryBus _memoryBus;
|
||||||
private readonly Form1 _mainForm;
|
private readonly ParsonsForm1 _mainForm;
|
||||||
|
|
||||||
public DebuggerForm(Z80 cpu, SmsMemoryBus memoryBus, Form1 mainForm)
|
public DebuggerForm(Z80 cpu, SmsMemoryBus memoryBus, ParsonsForm1 mainForm)
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
_cpu = cpu;
|
_cpu = cpu;
|
||||||
@@ -103,9 +103,9 @@ namespace Desktop
|
|||||||
lblIE.Text = $"Interrupt Mode: {_cpu.InterruptMode}";
|
lblIE.Text = $"Interrupt Mode: {_cpu.InterruptMode}";
|
||||||
lblFlags.Text = $"Flags: {_cpu.GetFlagsString()}";
|
lblFlags.Text = $"Flags: {_cpu.GetFlagsString()}";
|
||||||
lblTStates.Text = $"T-States: {_cpu.TotalTStates}";
|
lblTStates.Text = $"T-States: {_cpu.TotalTStates}";
|
||||||
//lblFrames.Text = $"Frames Rendered: {_mainForm.TotalFrameCount}";
|
lblFrames.Text = $"Frames Rendered: {_mainForm.TotalFrameCount}";
|
||||||
//lblFrameTime.Text = $"Frame Time: {((float)_mainForm.FrameTime):F1}ms";
|
lblFrameTime.Text = $"Frame Time: {((float)_mainForm.FrameTime):F1}ms";
|
||||||
//lblFPS.Text = $"FPS: {_mainForm.FramesPerSecond:F2}";
|
lblFPS.Text = $"FPS: {_mainForm.FramesPerSecond:F2}";
|
||||||
UpdateMemoryView();
|
UpdateMemoryView();
|
||||||
UpdateStackView();
|
UpdateStackView();
|
||||||
UpdateDisassemblyView();
|
UpdateDisassemblyView();
|
||||||
|
|||||||
20
Desktop/Form1.Designer.cs
generated
20
Desktop/Form1.Designer.cs
generated
@@ -1,6 +1,6 @@
|
|||||||
namespace Desktop
|
namespace Desktop
|
||||||
{
|
{
|
||||||
partial class Form1
|
partial class ParsonsForm1
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Required designer variable.
|
/// Required designer variable.
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
//
|
//
|
||||||
pbScreen.Location = new Point(12, 36);
|
pbScreen.Location = new Point(12, 36);
|
||||||
pbScreen.Name = "pbScreen";
|
pbScreen.Name = "pbScreen";
|
||||||
pbScreen.Size = new Size(762, 672);
|
pbScreen.Size = new Size(768, 576);
|
||||||
pbScreen.SizeMode = PictureBoxSizeMode.Zoom;
|
pbScreen.SizeMode = PictureBoxSizeMode.Zoom;
|
||||||
pbScreen.TabIndex = 1;
|
pbScreen.TabIndex = 1;
|
||||||
pbScreen.TabStop = false;
|
pbScreen.TabStop = false;
|
||||||
@@ -60,7 +60,7 @@
|
|||||||
menuStrip1.Items.AddRange(new ToolStripItem[] { fileToolStripMenuItem, viewToolStripMenuItem, machineToolStripMenuItem, helpToolStripMenuItem });
|
menuStrip1.Items.AddRange(new ToolStripItem[] { fileToolStripMenuItem, viewToolStripMenuItem, machineToolStripMenuItem, helpToolStripMenuItem });
|
||||||
menuStrip1.Location = new Point(0, 0);
|
menuStrip1.Location = new Point(0, 0);
|
||||||
menuStrip1.Name = "menuStrip1";
|
menuStrip1.Name = "menuStrip1";
|
||||||
menuStrip1.Size = new Size(785, 33);
|
menuStrip1.Size = new Size(791, 33);
|
||||||
menuStrip1.TabIndex = 2;
|
menuStrip1.TabIndex = 2;
|
||||||
menuStrip1.Text = "menuStrip1";
|
menuStrip1.Text = "menuStrip1";
|
||||||
//
|
//
|
||||||
@@ -75,27 +75,27 @@
|
|||||||
//
|
//
|
||||||
openToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { includedToolStripMenuItem, selectROMToolStripMenuItem1 });
|
openToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { includedToolStripMenuItem, selectROMToolStripMenuItem1 });
|
||||||
openToolStripMenuItem.Name = "openToolStripMenuItem";
|
openToolStripMenuItem.Name = "openToolStripMenuItem";
|
||||||
openToolStripMenuItem.Size = new Size(270, 34);
|
openToolStripMenuItem.Size = new Size(158, 34);
|
||||||
openToolStripMenuItem.Text = "Open";
|
openToolStripMenuItem.Text = "Open";
|
||||||
//
|
//
|
||||||
// includedToolStripMenuItem
|
// includedToolStripMenuItem
|
||||||
//
|
//
|
||||||
includedToolStripMenuItem.Name = "includedToolStripMenuItem";
|
includedToolStripMenuItem.Name = "includedToolStripMenuItem";
|
||||||
includedToolStripMenuItem.Size = new Size(270, 34);
|
includedToolStripMenuItem.Size = new Size(218, 34);
|
||||||
includedToolStripMenuItem.Text = "Included";
|
includedToolStripMenuItem.Text = "Included";
|
||||||
includedToolStripMenuItem.Click += includedToolStripMenuItem_Click;
|
includedToolStripMenuItem.Click += includedToolStripMenuItem_Click;
|
||||||
//
|
//
|
||||||
// selectROMToolStripMenuItem1
|
// selectROMToolStripMenuItem1
|
||||||
//
|
//
|
||||||
selectROMToolStripMenuItem1.Name = "selectROMToolStripMenuItem1";
|
selectROMToolStripMenuItem1.Name = "selectROMToolStripMenuItem1";
|
||||||
selectROMToolStripMenuItem1.Size = new Size(270, 34);
|
selectROMToolStripMenuItem1.Size = new Size(218, 34);
|
||||||
selectROMToolStripMenuItem1.Text = "Select ROM...";
|
selectROMToolStripMenuItem1.Text = "Select ROM...";
|
||||||
selectROMToolStripMenuItem1.Click += selectROMToolStripMenuItem_Click;
|
selectROMToolStripMenuItem1.Click += selectROMToolStripMenuItem_Click;
|
||||||
//
|
//
|
||||||
// exitToolStripMenuItem
|
// exitToolStripMenuItem
|
||||||
//
|
//
|
||||||
exitToolStripMenuItem.Name = "exitToolStripMenuItem";
|
exitToolStripMenuItem.Name = "exitToolStripMenuItem";
|
||||||
exitToolStripMenuItem.Size = new Size(270, 34);
|
exitToolStripMenuItem.Size = new Size(158, 34);
|
||||||
exitToolStripMenuItem.Text = "Exit";
|
exitToolStripMenuItem.Text = "Exit";
|
||||||
exitToolStripMenuItem.Click += exitToolStripMenuItem_Click;
|
exitToolStripMenuItem.Click += exitToolStripMenuItem_Click;
|
||||||
//
|
//
|
||||||
@@ -140,16 +140,16 @@
|
|||||||
aboutToolStripMenuItem.Size = new Size(164, 34);
|
aboutToolStripMenuItem.Size = new Size(164, 34);
|
||||||
aboutToolStripMenuItem.Text = "About";
|
aboutToolStripMenuItem.Text = "About";
|
||||||
//
|
//
|
||||||
// Form1
|
// ParsonsForm1
|
||||||
//
|
//
|
||||||
AutoScaleDimensions = new SizeF(10F, 25F);
|
AutoScaleDimensions = new SizeF(10F, 25F);
|
||||||
AutoScaleMode = AutoScaleMode.Font;
|
AutoScaleMode = AutoScaleMode.Font;
|
||||||
ClientSize = new Size(785, 719);
|
ClientSize = new Size(791, 622);
|
||||||
Controls.Add(pbScreen);
|
Controls.Add(pbScreen);
|
||||||
Controls.Add(menuStrip1);
|
Controls.Add(menuStrip1);
|
||||||
MainMenuStrip = menuStrip1;
|
MainMenuStrip = menuStrip1;
|
||||||
Margin = new Padding(4);
|
Margin = new Padding(4);
|
||||||
Name = "Form1";
|
Name = "ParsonsForm1";
|
||||||
Text = "Form1";
|
Text = "Form1";
|
||||||
((System.ComponentModel.ISupportInitialize)pbScreen).EndInit();
|
((System.ComponentModel.ISupportInitialize)pbScreen).EndInit();
|
||||||
menuStrip1.ResumeLayout(false);
|
menuStrip1.ResumeLayout(false);
|
||||||
|
|||||||
@@ -1,22 +1,26 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Reflection.PortableExecutable;
|
using System.Reflection.PortableExecutable;
|
||||||
using Core;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Drawing.Imaging;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
using Core;
|
||||||
|
|
||||||
namespace Desktop
|
namespace Desktop
|
||||||
{
|
{
|
||||||
public partial class Form1 : Form
|
public partial class ParsonsForm1 : Form
|
||||||
{
|
{
|
||||||
private SmsMachine _machine = null!;
|
private SmsMachine _machine = null!;
|
||||||
private DebuggerForm _debugger;
|
private DebuggerForm _debugger;
|
||||||
private Bitmap _screenBitmap = new Bitmap(256, 192, PixelFormat.Format32bppArgb);
|
private Bitmap _screenBitmap = new Bitmap(256, 192, PixelFormat.Format32bppArgb);
|
||||||
|
|
||||||
private Task _emulatorTask;
|
private Task _emulatorTask;
|
||||||
|
private double TargetFrameTime = 16.667f;
|
||||||
|
public int TotalFrameCount = 0;
|
||||||
|
public double FrameTime { get; private set; } = 0;
|
||||||
|
public double FramesPerSecond { get; private set; } = 0;
|
||||||
|
private string _currentRomName = "No ROM";
|
||||||
|
private Stopwatch _stopwatch = new System.Diagnostics.Stopwatch();
|
||||||
public bool IsRunning { get; private set; } = false;
|
public bool IsRunning { get; private set; } = false;
|
||||||
|
|
||||||
public ushort? Breakpoint
|
public ushort? Breakpoint
|
||||||
@@ -25,9 +29,10 @@ namespace Desktop
|
|||||||
set { if (_machine != null) _machine.Breakpoint = value; }
|
set { if (_machine != null) _machine.Breakpoint = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public Form1()
|
public ParsonsForm1()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
this.Text = $"Parsons Master System 2026 - {_currentRomName}";
|
||||||
_machine = new SmsMachine();
|
_machine = new SmsMachine();
|
||||||
|
|
||||||
PopulateIncludedRomsMenu();
|
PopulateIncludedRomsMenu();
|
||||||
@@ -46,32 +51,81 @@ namespace Desktop
|
|||||||
|
|
||||||
// Update the PictureBox
|
// Update the PictureBox
|
||||||
pbScreen.Image = _screenBitmap;
|
pbScreen.Image = _screenBitmap;
|
||||||
|
TotalFrameCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StartEmulator()
|
public void StartEmulator()
|
||||||
{
|
{
|
||||||
if (IsRunning) return;
|
if (IsRunning) return;
|
||||||
IsRunning = true;
|
IsRunning = true;
|
||||||
|
TotalFrameCount = 0;
|
||||||
|
|
||||||
|
double TargetFrameTime = 1000.0 / 60.0;
|
||||||
|
|
||||||
_emulatorTask = Task.Run(() =>
|
_emulatorTask = Task.Run(() =>
|
||||||
{
|
{
|
||||||
|
_stopwatch.Restart();
|
||||||
|
|
||||||
|
double nextFrameTargetTime = _stopwatch.Elapsed.TotalMilliseconds + TargetFrameTime;
|
||||||
|
double lastFpsUpdate = _stopwatch.Elapsed.TotalMilliseconds;
|
||||||
|
int framesThisSecond = 0;
|
||||||
|
|
||||||
while (IsRunning)
|
while (IsRunning)
|
||||||
{
|
{
|
||||||
|
// Mark exactly when the emulator starts thinking
|
||||||
|
double frameStartTime = _stopwatch.Elapsed.TotalMilliseconds;
|
||||||
|
|
||||||
|
// 1. Do the heavy lifting (Z80 and VDP)
|
||||||
_machine.RunFrame();
|
_machine.RunFrame();
|
||||||
|
|
||||||
Invoke((System.Windows.Forms.MethodInvoker)delegate { DrawScreen(); });
|
// 2. FIRE AND FORGET! Tell Windows to draw, but DO NOT WAIT for it to finish!
|
||||||
|
BeginInvoke((System.Windows.Forms.MethodInvoker)delegate { DrawScreen(); });
|
||||||
|
|
||||||
// Safety catch: If we hit a breakpoint while running, stop the loop!
|
// 3. Safety catch
|
||||||
if (_machine.Breakpoint.HasValue && _machine.Cpu.PC == _machine.Breakpoint.Value)
|
if (_machine.Breakpoint.HasValue && _machine.Cpu.PC == _machine.Breakpoint.Value)
|
||||||
{
|
{
|
||||||
IsRunning = false;
|
IsRunning = false;
|
||||||
|
BeginInvoke((System.Windows.Forms.MethodInvoker)delegate { _debugger?.uiUpdateTimer_Tick(null, EventArgs.Empty); });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Optional: Force the debugger UI to update immediately so you see it!
|
// 4. Calculate TRUE Frame Time (Compute Time) BEFORE we go to sleep!
|
||||||
Invoke((System.Windows.Forms.MethodInvoker)delegate { _debugger?.uiUpdateTimer_Tick(null, EventArgs.Empty); });
|
FrameTime = _stopwatch.Elapsed.TotalMilliseconds - frameStartTime;
|
||||||
|
|
||||||
|
// --- HIGH PRECISION THROTTLE ---
|
||||||
|
while (_stopwatch.Elapsed.TotalMilliseconds < nextFrameTargetTime)
|
||||||
|
{
|
||||||
|
if (nextFrameTargetTime - _stopwatch.Elapsed.TotalMilliseconds > 2.0)
|
||||||
|
{
|
||||||
|
Thread.Sleep(1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Only throttle the speed if we are actively running
|
Thread.SpinWait(10);
|
||||||
Thread.Sleep(8);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- METRICS MATH ---
|
||||||
|
double currentTime = _stopwatch.Elapsed.TotalMilliseconds;
|
||||||
|
TotalFrameCount++;
|
||||||
|
framesThisSecond++;
|
||||||
|
|
||||||
|
if (currentTime - lastFpsUpdate >= 1000.0)
|
||||||
|
{
|
||||||
|
FramesPerSecond = framesThisSecond / ((currentTime - lastFpsUpdate) / 1000.0);
|
||||||
|
framesThisSecond = 0;
|
||||||
|
lastFpsUpdate = currentTime;
|
||||||
|
|
||||||
|
BeginInvoke((System.Windows.Forms.MethodInvoker)delegate {
|
||||||
|
this.Text = $"Parsons Master System - {_currentRomName} [FPS/FT: {FramesPerSecond:F0}/{FrameTime:F1}]";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
nextFrameTargetTime += TargetFrameTime;
|
||||||
|
|
||||||
|
if (currentTime > nextFrameTargetTime + TargetFrameTime)
|
||||||
|
{
|
||||||
|
nextFrameTargetTime = currentTime + TargetFrameTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -102,8 +156,8 @@ namespace Desktop
|
|||||||
// 3. Jam it into the Sega Mapper
|
// 3. Jam it into the Sega Mapper
|
||||||
_machine.LoadCartridge(rom);
|
_machine.LoadCartridge(rom);
|
||||||
|
|
||||||
// 4. Update the Window title so it looks professional
|
_currentRomName = Path.GetFileNameWithoutExtension(filePath);
|
||||||
this.Text = $"Parsons Master System 2026 - {Path.GetFileNameWithoutExtension(filePath)}";
|
this.Text = $"Parsons Master System - {_currentRomName}";
|
||||||
|
|
||||||
// 5. Turn the power on!
|
// 5. Turn the power on!
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace Desktop
|
|||||||
// To customize application configuration such as set high DPI settings or default font,
|
// To customize application configuration such as set high DPI settings or default font,
|
||||||
// see https://aka.ms/applicationconfiguration.
|
// see https://aka.ms/applicationconfiguration.
|
||||||
ApplicationConfiguration.Initialize();
|
ApplicationConfiguration.Initialize();
|
||||||
Application.Run(new Form1());
|
Application.Run(new ParsonsForm1());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user