mirror of
https://github.com/BluestormDNA/ProjectPSX.git
synced 2025-04-02 10:52:34 -04:00
GDI Render: UI
This commit is contained in:
parent
eac81c8c59
commit
037a647f3a
4 changed files with 47 additions and 102 deletions
|
@ -7,6 +7,10 @@
|
|||
<DisableWinExeOutputInference>true</DisableWinExeOutputInference>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NAudio" Version="1.10.0" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
|
||||
namespace ProjectPSX {
|
||||
public class Display : IDisposable {
|
||||
public Bitmap Bitmap { get; set; }
|
||||
public Int32[] Bits { get; private set; }
|
||||
public bool Disposed { get; private set; }
|
||||
public int Height;
|
||||
public int Width;
|
||||
|
||||
protected GCHandle BitsHandle { get; private set; }
|
||||
|
||||
public Display(int width, int height) {
|
||||
Height = height;
|
||||
Width = width;
|
||||
Bits = new Int32[Width * Height];
|
||||
BitsHandle = GCHandle.Alloc(Bits, GCHandleType.Pinned);
|
||||
|
||||
Bitmap = new Bitmap(Width, Height, Width * 4, PixelFormat.Format32bppRgb, BitsHandle.AddrOfPinnedObject());
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void SetPixel(int x, int y, int color) {
|
||||
int index = x + (y * Width);
|
||||
Bits[index] = color;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public int GetPixelRGB888(int x, int y) {
|
||||
int index = x + (y * Width);
|
||||
return Bits[index];
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ushort GetPixelBGR555(int x, int y) {
|
||||
int index = x + (y * Width);
|
||||
int color = Bits[index];
|
||||
|
||||
byte m = (byte)((color & 0xFF000000) >> 24);
|
||||
byte r = (byte)((color & 0x00FF0000) >> 16 + 3);
|
||||
byte g = (byte)((color & 0x0000FF00) >> 8 + 3);
|
||||
byte b = (byte)((color & 0x000000FF) >> 3);
|
||||
|
||||
return (ushort)(m << 15 | b << 10 | g << 5 | r);
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
if (Disposed) return;
|
||||
Disposed = true;
|
||||
Bitmap.Dispose();
|
||||
BitsHandle.Free();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,12 +4,11 @@ namespace ProjectPSX.Util {
|
|||
public class DoubleBufferedPanel : Panel {
|
||||
|
||||
public DoubleBufferedPanel() {
|
||||
this.DoubleBuffered = true;
|
||||
this.BackgroundImageLayout = ImageLayout.Stretch;
|
||||
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
|
||||
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
|
||||
//this.SetStyle(ControlStyles.UserPaint, true);
|
||||
this.UpdateStyles();
|
||||
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
|
||||
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
|
||||
SetStyle(ControlStyles.UserPaint, false);
|
||||
|
||||
UpdateStyles();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,20 +11,26 @@ using System.Timers;
|
|||
using System.Threading.Tasks;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using ProjectPSX.Interop.Gdi32;
|
||||
using Gdi32 = ProjectPSX.Interop.Gdi32.NativeMethods;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace ProjectPSX {
|
||||
public class Window : Form, IHostWindow {
|
||||
|
||||
const int PSX_MHZ = 33868800;
|
||||
const int SYNC_CYCLES = 100;
|
||||
const int MIPS_UNDERCLOCK = 2;
|
||||
private const int PSX_MHZ = 33868800;
|
||||
private const int SYNC_CYCLES = 100;
|
||||
private const int MIPS_UNDERCLOCK = 2;
|
||||
|
||||
private const int cyclesPerFrame = PSX_MHZ / 60;
|
||||
private const int syncLoops = (cyclesPerFrame / (SYNC_CYCLES * MIPS_UNDERCLOCK)) + 1;
|
||||
private const int cycles = syncLoops * SYNC_CYCLES;
|
||||
|
||||
private Size vramSize = new Size(1024, 512);
|
||||
private Size _640x480 = new Size(640, 480);
|
||||
private readonly DoubleBufferedPanel screen = new DoubleBufferedPanel();
|
||||
|
||||
private Display display = new Display(640, 480);
|
||||
private Display vramViewer = new Display(1024, 512);
|
||||
private GdiBitmap display = new GdiBitmap(1024, 512);
|
||||
|
||||
private ProjectPSX psx;
|
||||
private int fps;
|
||||
|
@ -57,7 +63,7 @@ namespace ProjectPSX {
|
|||
FormBorderStyle = FormBorderStyle.FixedDialog;
|
||||
KeyUp += new KeyEventHandler(vramViewerToggle);
|
||||
|
||||
screen.BackgroundImage = display.Bitmap;// TESTING
|
||||
|
||||
screen.Size = _640x480;
|
||||
screen.Margin = new Padding(0);
|
||||
screen.MouseDoubleClick += new MouseEventHandler(toggleDebug);
|
||||
|
@ -104,8 +110,7 @@ namespace ProjectPSX {
|
|||
if (cla.Any(s => s.EndsWith(".bin") || s.EndsWith(".cue"))) {
|
||||
String filename = cla.First(s => s.EndsWith(".bin") || s.EndsWith(".cue"));
|
||||
return filename;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
//Show the user a dialog so they can pick the bin they want to load.
|
||||
var fileDialog = new OpenFileDialog();
|
||||
fileDialog.Filter = "BIN/CUE files (*.bin, *.cue)|*.bin;*.cue";
|
||||
|
@ -134,15 +139,22 @@ namespace ProjectPSX {
|
|||
psx.JoyPadDown(button.Value);
|
||||
}
|
||||
|
||||
private void toggleDebug(object sender, MouseEventArgs e) {
|
||||
psx.toggleDebug();
|
||||
}
|
||||
private void toggleDebug(object sender, MouseEventArgs e) => psx.toggleDebug();
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Render(int[] vram) {
|
||||
//Console.WriteLine($"x1 {displayX1} x2 {displayX2} y1 {displayY1} y2 {displayY2}");
|
||||
int horizontalStart = 0;
|
||||
int horizontalEnd = horizontalRes;
|
||||
int verticalStart = 0;
|
||||
int verticalEnd = verticalRes;
|
||||
|
||||
if (isVramViewer) {
|
||||
Buffer.BlockCopy(vram, 0, display.Bits, 0, 0x200000);
|
||||
horizontalEnd = 1024;
|
||||
verticalStart = 0;
|
||||
verticalEnd = 512;
|
||||
|
||||
Marshal.Copy(vram, 0, display.BitmapData, 0x80000);
|
||||
} else if (is24BitDepth) {
|
||||
blit24bpp(vram);
|
||||
} else {
|
||||
|
@ -150,7 +162,12 @@ namespace ProjectPSX {
|
|||
}
|
||||
|
||||
fps++;
|
||||
screen.Invalidate();
|
||||
|
||||
using var deviceContext = new GdiDeviceContext(screen.Handle);
|
||||
|
||||
Gdi32.StretchBlt(deviceContext, 0, 0, screen.Width, screen.Height,
|
||||
display.DeviceContext, horizontalStart, verticalStart, horizontalEnd, verticalEnd,
|
||||
RasterOp.SRCCOPY);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
@ -185,10 +202,11 @@ namespace ProjectPSX {
|
|||
int p0rgb24bpp = p0R << 16 | p0G << 8 | p0B;
|
||||
int p1rgb24bpp = p1R << 16 | p1G << 8 | p1B;
|
||||
|
||||
display.Bits[x + (y * horizontalRes)] = p0rgb24bpp;
|
||||
display.Bits[x + 1 + (y * horizontalRes)] = p1rgb24bpp;
|
||||
display.DrawPixel(x, y, p0rgb24bpp);
|
||||
display.DrawPixel(x + 1, y, p1rgb24bpp);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
@ -202,12 +220,12 @@ namespace ProjectPSX {
|
|||
else yRangeOffset = range;
|
||||
|
||||
for (int y = yRangeOffset; y < verticalRes - yRangeOffset; y++) {
|
||||
for (int x = 0; x < display.Width; x++) {
|
||||
for (int x = 0; x < horizontalRes; x++) {
|
||||
int pixel = vramBits[(x + displayVRAMXStart) + ((y - yRangeOffset + displayVRAMYStart) * 1024)];
|
||||
display.Bits[x + (y * horizontalRes)] = pixel;
|
||||
//Console.WriteLine(y + " " + x);
|
||||
display.DrawPixel(x, y, pixel);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
@ -234,18 +252,11 @@ namespace ProjectPSX {
|
|||
this.verticalRes = verticalRes;
|
||||
|
||||
//Console.WriteLine($"setDisplayMode {horizontalRes} {verticalRes} {is24BitDepth}");
|
||||
|
||||
if (!isVramViewer) {
|
||||
display = new Display(horizontalRes, verticalRes);
|
||||
screen.BackgroundImage = display.Bitmap;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void SetVRAMStart(ushort displayVRAMXStart, ushort displayVRAMYStart) {
|
||||
//if (isVramViewer) return;
|
||||
|
||||
this.displayVRAMXStart = displayVRAMXStart;
|
||||
this.displayVRAMYStart = displayVRAMYStart;
|
||||
|
||||
|
@ -253,8 +264,6 @@ namespace ProjectPSX {
|
|||
}
|
||||
|
||||
public void SetVerticalRange(ushort displayY1, ushort displayY2) {
|
||||
//if (isVramViewer) return;
|
||||
|
||||
this.displayY1 = displayY1;
|
||||
this.displayY2 = displayY2;
|
||||
|
||||
|
@ -262,25 +271,20 @@ namespace ProjectPSX {
|
|||
}
|
||||
|
||||
public void SetHorizontalRange(ushort displayX1, ushort displayX2) {
|
||||
//if (isVramViewer) return;
|
||||
|
||||
this.displayX1 = displayX1;
|
||||
this.displayX2 = displayX2;
|
||||
|
||||
//Console.WriteLine($"Horizontal Range {displayX1} {displayX2}");
|
||||
}
|
||||
|
||||
private void vramViewerToggle(object sender, KeyEventArgs e) { //this is very buggy but its only for debug purposes maybe disable it when unneded?
|
||||
private void vramViewerToggle(object sender, KeyEventArgs e) {
|
||||
if(e.KeyCode == Keys.Tab) {
|
||||
if (!isVramViewer) {
|
||||
display = vramViewer;
|
||||
screen.Size = vramSize;
|
||||
} else {
|
||||
display = new Display(horizontalRes, verticalRes);
|
||||
screen.Size = _640x480;
|
||||
}
|
||||
isVramViewer = !isVramViewer;
|
||||
screen.BackgroundImage = display.Bitmap;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -294,7 +298,7 @@ namespace ProjectPSX {
|
|||
}
|
||||
|
||||
private void OnTimedEvent(object sender, ElapsedEventArgs e) {
|
||||
Text = $"ProjectPSX | Cpu Speed {(int)((float)cpuCyclesCounter / (PSX_MHZ / MIPS_UNDERCLOCK) * SYNC_CYCLES)}% | Vps {GetVPS()}";
|
||||
Text = $"ProjectPSX | Cpu {(int)((float)cpuCyclesCounter / (PSX_MHZ / MIPS_UNDERCLOCK) * SYNC_CYCLES)}% | Vps {GetVPS()}";
|
||||
cpuCyclesCounter = 0;
|
||||
}
|
||||
|
||||
|
@ -309,9 +313,6 @@ namespace ProjectPSX {
|
|||
try {
|
||||
while (true) {
|
||||
psx.RunFrame();
|
||||
int cyclesPerFrame = PSX_MHZ / 60;
|
||||
int syncLoops = (cyclesPerFrame / (SYNC_CYCLES * MIPS_UNDERCLOCK)) + 1;
|
||||
int cycles = syncLoops * SYNC_CYCLES;
|
||||
cpuCyclesCounter += cycles;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
|
Loading…
Add table
Reference in a new issue