mirror of
https://github.com/BluestormDNA/ProjectPSX.git
synced 2025-04-02 10:52:34 -04:00
Gdi (#18)
* Push Interop * GDI Render: UI * Gdi: Add BltMode * Winform GDI: Handle y ranges This is badly handled and X still left
This commit is contained in:
parent
8912d88da4
commit
2f79a50d36
9 changed files with 350 additions and 112 deletions
8
ProjectPSX.WinForms/Interop/ExternDll.cs
Normal file
8
ProjectPSX.WinForms/Interop/ExternDll.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace ProjectPSX
|
||||
{
|
||||
internal static class ExternDll
|
||||
{
|
||||
public const string Gdi32 = "gdi32.dll";
|
||||
public const string User32 = "user32.dll";
|
||||
}
|
||||
}
|
121
ProjectPSX.WinForms/Interop/Gdi32.cs
Normal file
121
ProjectPSX.WinForms/Interop/Gdi32.cs
Normal file
|
@ -0,0 +1,121 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
|
||||
namespace ProjectPSX.Interop.Gdi32
|
||||
{
|
||||
internal enum BitmapCompression : uint
|
||||
{
|
||||
BI_RGB = 0,
|
||||
BI_RLE8 = 1,
|
||||
BI_RLE4 = 2,
|
||||
BI_BITFIELDS = 3,
|
||||
BI_JPEG = 4,
|
||||
BI_PNG = 5,
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct BitmapInfoHeader
|
||||
{
|
||||
public uint biSize;
|
||||
public int biWidth;
|
||||
public int biHeight;
|
||||
public ushort biPlanes;
|
||||
public ushort biBitCount;
|
||||
public BitmapCompression biCompression;
|
||||
public uint biSizeImage;
|
||||
public int biXPelsPerMeter;
|
||||
public int biYPelsPerMeter;
|
||||
public uint biClrUsed;
|
||||
public uint biClrImportant;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct RgbQuad
|
||||
{
|
||||
public byte rgbBlue;
|
||||
public byte rgbGreen;
|
||||
public byte rgbRed;
|
||||
public byte rgbReserved;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct BitmapInfo
|
||||
{
|
||||
public BitmapInfoHeader bmiHeader;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
||||
public uint[] bmiColors;
|
||||
}
|
||||
|
||||
internal enum ColorUsage : uint
|
||||
{
|
||||
DIB_RGB_COLORS = 0, /* color table in RGBs */
|
||||
DIB_PAL_COLORS = 1, /* color table in palette indices */
|
||||
}
|
||||
|
||||
internal enum RasterOp : uint
|
||||
{
|
||||
SRCCOPY = 0x00CC0020, // dest = source
|
||||
SRCPAINT = 0x00EE0086, // dest = source OR dest
|
||||
SRCAND = 0x008800C6, // dest = source AND dest
|
||||
SRCINVERT = 0x00660046, // dest = source XOR dest
|
||||
SRCERASE = 0x00440328, // dest = source AND (NOT dest )
|
||||
NOTSRCCOPY = 0x00330008, // dest = (NOT source)
|
||||
NOTSRCERASE = 0x001100A6, // dest = (NOT src) AND (NOT dest
|
||||
MERGECOPY = 0x00C000CA, // dest = (source AND pattern)
|
||||
MERGEPAINT = 0x00BB0226, // dest = (NOT source) OR dest
|
||||
PATCOPY = 0x00F00021, // dest = pattern
|
||||
PATPAINT = 0x00FB0A09, // dest = DPSnoo
|
||||
PATINVERT = 0x005A0049, // dest = pattern XOR dest
|
||||
DSTINVERT = 0x00550009, // dest = (NOT dest)
|
||||
BLACKNESS = 0x00000042, // dest = BLACK
|
||||
WHITENESS = 0x00FF0062, // dest = WHITE
|
||||
NOMIRRORBITMAP = 0x80000000, // Do not Mirror the bitmap in this call
|
||||
CAPTUREBLT = 0x40000000, // Include layered windows
|
||||
}
|
||||
|
||||
internal enum BltMode : uint {
|
||||
STRETCH_ANDSCANS = 0x01,
|
||||
STRETCH_ORSCANS = 0x02,
|
||||
STRETCH_DELETESCANS = 0x03,
|
||||
STRETCH_HALFTONE = 0x04,
|
||||
}
|
||||
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
internal static class NativeMethods
|
||||
{
|
||||
[DllImport(ExternDll.Gdi32)]
|
||||
internal static extern IntPtr CreateCompatibleDC(IntPtr hdc);
|
||||
|
||||
[DllImport(ExternDll.Gdi32)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool DeleteDC(IntPtr hdc);
|
||||
|
||||
[DllImport(ExternDll.Gdi32)]
|
||||
internal static extern IntPtr CreateDIBSection(IntPtr hdc, [In] in BitmapInfo pbmi, ColorUsage usage,
|
||||
out IntPtr ppvBits, IntPtr hSection, uint offset);
|
||||
|
||||
[DllImport(ExternDll.Gdi32)]
|
||||
internal static extern IntPtr SelectObject(IntPtr hdc, IntPtr h);
|
||||
|
||||
[DllImport(ExternDll.Gdi32)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool DeleteObject(IntPtr ho);
|
||||
|
||||
[DllImport(ExternDll.Gdi32)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool StretchBlt(IntPtr hdcDest, int xDest, int yDest, int wDest, int hDest,
|
||||
IntPtr hdcSrc, int xSrc, int ySrc, int wSrc, int hSrc,
|
||||
RasterOp rop);
|
||||
|
||||
[DllImport(ExternDll.Gdi32)]
|
||||
internal static extern int SetStretchBltMode(IntPtr hdc, BltMode mode);
|
||||
|
||||
[DllImport(ExternDll.Gdi32)]
|
||||
internal static extern int StretchDIBits(IntPtr hdc, int xDest, int yDest, int DestWidth, int DestHeight,
|
||||
int xSrc, int ySrc, int SrcWidth, int SrcHeight, IntPtr lpBits,
|
||||
[In] ref BitmapInfo lpbmi, ColorUsage iUsage, RasterOp rop);
|
||||
}
|
||||
}
|
||||
|
105
ProjectPSX.WinForms/Interop/GdiBitmap.cs
Normal file
105
ProjectPSX.WinForms/Interop/GdiBitmap.cs
Normal file
|
@ -0,0 +1,105 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using ProjectPSX.Interop.Gdi32;
|
||||
|
||||
using Gdi32 = ProjectPSX.Interop.Gdi32.NativeMethods;
|
||||
|
||||
namespace ProjectPSX
|
||||
{
|
||||
internal class GdiBitmap : IDisposable
|
||||
{
|
||||
public readonly int BytesPerPixel = 4;
|
||||
|
||||
public readonly IntPtr DeviceContext;
|
||||
public readonly IntPtr BitmapHandle;
|
||||
|
||||
public readonly int Width;
|
||||
public readonly int Height;
|
||||
|
||||
public readonly IntPtr BitmapData;
|
||||
|
||||
private readonly IntPtr _oldObject;
|
||||
|
||||
private bool _disposed = false;
|
||||
|
||||
public GdiBitmap(int width, int height)
|
||||
{
|
||||
Width = width;
|
||||
Height = height;
|
||||
|
||||
DeviceContext = Gdi32.CreateCompatibleDC(IntPtr.Zero);
|
||||
|
||||
var bitmapHeader = new BitmapInfoHeader
|
||||
{
|
||||
biSize = (uint)Marshal.SizeOf<BitmapInfoHeader>(),
|
||||
biWidth = width,
|
||||
biHeight = -height, // negative, top-down bitmap
|
||||
biPlanes = 1,
|
||||
biBitCount = (ushort)(8 * BytesPerPixel),
|
||||
biCompression = BitmapCompression.BI_RGB,
|
||||
};
|
||||
|
||||
var bitmapInfo = new BitmapInfo
|
||||
{
|
||||
bmiHeader = bitmapHeader,
|
||||
};
|
||||
|
||||
BitmapHandle = Gdi32.CreateDIBSection(DeviceContext, in bitmapInfo, ColorUsage.DIB_RGB_COLORS,
|
||||
out BitmapData, IntPtr.Zero, 0);
|
||||
|
||||
_oldObject = Gdi32.SelectObject(DeviceContext, BitmapHandle);
|
||||
}
|
||||
|
||||
public unsafe void DrawPixel(int x, int y, int color) {
|
||||
int* pixel = (int*)BitmapData;
|
||||
pixel += x + (y * Width);
|
||||
*pixel = color;
|
||||
}
|
||||
|
||||
public unsafe int GetPixel(int x, int y) {
|
||||
int* pixel = (int*)BitmapData;
|
||||
pixel += x + (y * Width);
|
||||
return *pixel;
|
||||
}
|
||||
|
||||
~GdiBitmap()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
// This code added to correctly implement the disposable pattern.
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// TODO: dispose managed state (managed objects).
|
||||
}
|
||||
|
||||
if (_oldObject != IntPtr.Zero)
|
||||
{
|
||||
Gdi32.SelectObject(DeviceContext, _oldObject);
|
||||
}
|
||||
|
||||
if (BitmapHandle != IntPtr.Zero)
|
||||
{
|
||||
Gdi32.DeleteObject(BitmapHandle);
|
||||
}
|
||||
|
||||
if (DeviceContext != IntPtr.Zero)
|
||||
{
|
||||
Gdi32.DeleteDC(DeviceContext);
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
28
ProjectPSX.WinForms/Interop/GdiDeviceContext.cs
Normal file
28
ProjectPSX.WinForms/Interop/GdiDeviceContext.cs
Normal file
|
@ -0,0 +1,28 @@
|
|||
using System;
|
||||
|
||||
using User32 = ProjectPSX.Interop.User32.NativeMethods;
|
||||
|
||||
namespace ProjectPSX
|
||||
{
|
||||
internal readonly ref struct GdiDeviceContext
|
||||
{
|
||||
private readonly IntPtr _handle;
|
||||
private readonly IntPtr _hdc;
|
||||
|
||||
public GdiDeviceContext(IntPtr handle)
|
||||
{
|
||||
_handle = handle;
|
||||
_hdc = User32.GetDC(handle);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
User32.ReleaseDC(_handle, _hdc);
|
||||
}
|
||||
|
||||
public static implicit operator IntPtr(GdiDeviceContext dc)
|
||||
{
|
||||
return dc._hdc;
|
||||
}
|
||||
}
|
||||
}
|
33
ProjectPSX.WinForms/Interop/User32.cs
Normal file
33
ProjectPSX.WinForms/Interop/User32.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
|
||||
namespace ProjectPSX.Interop.User32
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct Message
|
||||
{
|
||||
public IntPtr hWnd;
|
||||
public uint msg;
|
||||
public IntPtr wParam;
|
||||
public IntPtr lParam;
|
||||
public uint time;
|
||||
public Point p;
|
||||
}
|
||||
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
internal static class NativeMethods
|
||||
{
|
||||
[DllImport(ExternDll.User32)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool PeekMessage(out Message msg, IntPtr hWnd, uint messageFilterMin,
|
||||
uint messageFilterMax, uint flags);
|
||||
|
||||
[DllImport(ExternDll.User32)]
|
||||
internal static extern IntPtr GetDC(IntPtr hWnd);
|
||||
|
||||
[DllImport(ExternDll.User32)]
|
||||
internal static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
|
||||
}
|
||||
}
|
|
@ -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,6 @@ 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 +109,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 +138,20 @@ 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 horizontalEnd = horizontalRes;
|
||||
int verticalEnd = verticalRes;
|
||||
|
||||
if (isVramViewer) {
|
||||
Buffer.BlockCopy(vram, 0, display.Bits, 0, 0x200000);
|
||||
horizontalEnd = 1024;
|
||||
verticalEnd = 512;
|
||||
|
||||
Marshal.Copy(vram, 0, display.BitmapData, 0x80000);
|
||||
} else if (is24BitDepth) {
|
||||
blit24bpp(vram);
|
||||
} else {
|
||||
|
@ -150,16 +159,18 @@ namespace ProjectPSX {
|
|||
}
|
||||
|
||||
fps++;
|
||||
screen.Invalidate();
|
||||
|
||||
using var deviceContext = new GdiDeviceContext(screen.Handle);
|
||||
|
||||
Gdi32.StretchBlt(deviceContext, 0, 0, screen.Width, screen.Height,
|
||||
display.DeviceContext, 0, 0, horizontalEnd, verticalEnd,
|
||||
RasterOp.SRCCOPY);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void blit24bpp(int[] vramBits) {
|
||||
int range = (240 - (displayY2 - displayY1)) / 2;
|
||||
|
||||
int yRangeOffset;
|
||||
if (range < 0) yRangeOffset = 0;
|
||||
else yRangeOffset = range;
|
||||
int yRangeOffset = (240 - (displayY2 - displayY1)) >> (verticalRes == 480 ? 0 : 1);
|
||||
if (yRangeOffset < 0) yRangeOffset = 0;
|
||||
|
||||
for (int y = yRangeOffset; y < verticalRes - yRangeOffset; y++) {
|
||||
int offset = 0;
|
||||
|
@ -185,29 +196,27 @@ 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)]
|
||||
private void blit16bpp(int[] vramBits) {
|
||||
//Console.WriteLine($"x1 {displayX1} x2 {displayX2} y1 {displayY1} y2 {displayY2}");
|
||||
//Console.WriteLine($"Display Height {display.Height} Width {display.Width}");
|
||||
int range = (240 - (displayY2 - displayY1)) / 2;
|
||||
|
||||
int yRangeOffset;
|
||||
if (range < 0) yRangeOffset = 0;
|
||||
else yRangeOffset = range;
|
||||
int yRangeOffset = (240 - (displayY2 - displayY1)) >> (verticalRes == 480 ? 0 : 1);
|
||||
if (yRangeOffset < 0) yRangeOffset = 0;
|
||||
|
||||
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)]
|
||||
|
@ -233,19 +242,13 @@ namespace ProjectPSX {
|
|||
this.horizontalRes = horizontalRes;
|
||||
this.verticalRes = verticalRes;
|
||||
|
||||
clearDisplay();
|
||||
//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 +256,6 @@ namespace ProjectPSX {
|
|||
}
|
||||
|
||||
public void SetVerticalRange(ushort displayY1, ushort displayY2) {
|
||||
//if (isVramViewer) return;
|
||||
|
||||
this.displayY1 = displayY1;
|
||||
this.displayY2 = displayY2;
|
||||
|
||||
|
@ -262,28 +263,29 @@ 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;
|
||||
clearDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe void clearDisplay() {
|
||||
Span<uint> span = new Span<uint>(display.BitmapData.ToPointer(), 0x80000);
|
||||
span.Clear();
|
||||
}
|
||||
|
||||
public void Play(byte[] samples) {
|
||||
buffer.AddSamples(samples, 0, samples.Length);
|
||||
|
||||
|
@ -294,7 +296,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 +311,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