Merged machine settings into machine components.

Added save state support to all machine components.
Switched from xml serialization to binary serialization.
Refactored audio service for performance.
Bumped machine version to 0.9.0 for next release.
Miscellaneous cosmetic or minor changes.
This commit is contained in:
Sean Fausett 2010-11-29 09:08:11 +13:00
parent 18fa25759d
commit 0182641281
58 changed files with 1114 additions and 999 deletions

View File

@ -5,7 +5,7 @@ namespace Jellyfish.Library
{
public static class DispatcherExtensions
{
public static void CheckBeginInvoke(this Dispatcher dispatcher, Action action)
public static void Post(this Dispatcher dispatcher, Action action)
{
if (dispatcher == null)
{
@ -16,18 +16,10 @@ namespace Jellyfish.Library
throw new ArgumentNullException("action");
}
if (dispatcher.CheckAccess())
{
action();
}
else
{
dispatcher.BeginInvoke(action);
}
new DispatcherSynchronizationContext(dispatcher).Post(state => action(), null);
}
#if WINDOWS
public static void CheckInvoke(this Dispatcher dispatcher, Action action)
public static void Send(this Dispatcher dispatcher, Action action)
{
if (dispatcher == null)
{
@ -38,15 +30,7 @@ namespace Jellyfish.Library
throw new ArgumentNullException("action");
}
if (dispatcher.CheckAccess())
{
action();
}
else
{
dispatcher.Invoke(action);
}
new DispatcherSynchronizationContext(dispatcher).Send(state => action(), null);
}
#endif
}
}

View File

@ -65,9 +65,6 @@
<Reference Include="System.Windows" />
<Reference Include="System.Windows.Browser" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Serialization">
<Private>True</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\AssemblyCommentAttribute.cs">
@ -101,9 +98,6 @@
<Compile Include="..\WaveFormat.cs">
<Link>WaveFormat.cs</Link>
</Compile>
<Compile Include="..\XmlSerializerHelpers.cs">
<Link>XmlSerializerHelpers.cs</Link>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ApplicationBase.cs" />
<Compile Include="WaveMediaStreamSource.cs" />

View File

@ -60,7 +60,6 @@
<Reference Include="System.Net" />
<Reference Include="System.Windows" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Serialization" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\AssemblyCommentAttribute.cs">
@ -75,6 +74,9 @@
<Compile Include="..\..\IEnumerableExtensions.cs">
<Link>IEnumerableExtensions.cs</Link>
</Compile>
<Compile Include="..\..\Lazy.cs">
<Link>Lazy.cs</Link>
</Compile>
<Compile Include="..\..\MathHelpers.cs">
<Link>MathHelpers.cs</Link>
</Compile>
@ -90,9 +92,6 @@
<Compile Include="..\..\WaveFormat.cs">
<Link>WaveFormat.cs</Link>
</Compile>
<Compile Include="..\..\XmlSerializerHelpers.cs">
<Link>XmlSerializerHelpers.cs</Link>
</Compile>
<Compile Include="..\ApplicationBase.cs">
<Link>ApplicationBase.cs</Link>
</Compile>

View File

@ -11,9 +11,9 @@ using Jellyfish.Library;
[assembly: AssemblyCopyright("Copyright © 2009-2010 Digital Jellyfish Design Ltd")]
[assembly: AssemblyComment("Developed by Sean Fausett")]
[assembly: AssemblyVersion("0.1.3.0")]
[assembly: AssemblyFileVersion("0.1.3.0")]
[assembly: AssemblyInformationalVersion("0.1.3.0")]
[assembly: AssemblyVersion("0.2.0.0")]
[assembly: AssemblyFileVersion("0.2.0.0")]
[assembly: AssemblyInformationalVersion("0.2.0.0")]
[assembly: CLSCompliant(false)]
[assembly: ComVisible(false)]

View File

@ -11,9 +11,9 @@ using Jellyfish.Library;
[assembly: AssemblyCopyright("Copyright © 2009-2010 Digital Jellyfish Design Ltd")]
[assembly: AssemblyComment("Developed by Sean Fausett")]
[assembly: AssemblyVersion("0.1.3.0")]
[assembly: AssemblyFileVersion("0.1.3.0")]
[assembly: AssemblyInformationalVersion("0.1.3.0")]
[assembly: AssemblyVersion("0.2.0.0")]
[assembly: AssemblyFileVersion("0.2.0.0")]
[assembly: AssemblyInformationalVersion("0.2.0.0")]
[assembly: CLSCompliant(false)]
[assembly: ComVisible(false)]

View File

@ -51,7 +51,6 @@
<Reference Include="System.Core" />
<Reference Include="System.Xaml" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
@ -107,9 +106,6 @@
<Compile Include="..\WaveFormat.cs">
<Link>WaveFormat.cs</Link>
</Compile>
<Compile Include="..\XmlSerializerHelpers.cs">
<Link>XmlSerializerHelpers.cs</Link>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ApplicationBase.cs" />
<Compile Include="WindowExtensions.cs" />

View File

@ -11,9 +11,9 @@ using Jellyfish.Library;
[assembly: AssemblyCopyright("Copyright © 2009-2010 Digital Jellyfish Design Ltd")]
[assembly: AssemblyComment("Developed by Sean Fausett")]
[assembly: AssemblyVersion("0.1.3.0")]
[assembly: AssemblyFileVersion("0.1.3.0")]
[assembly: AssemblyInformationalVersion("0.1.3.0")]
[assembly: AssemblyVersion("0.2.0.0")]
[assembly: AssemblyFileVersion("0.2.0.0")]
[assembly: AssemblyInformationalVersion("0.2.0.0")]
[assembly: CLSCompliant(false)]
[assembly: ComVisible(false)]

View File

@ -1,5 +1,6 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
@ -21,9 +22,12 @@ namespace Jellyfish.Library
Content.RootDirectory = "Content";
GraphicsDeviceManager = new GraphicsDeviceManager(this);
#if WINDOWS_PHONE
GraphicsDeviceManager.IsFullScreen = true;
TargetElapsedTime = TimeSpan.FromTicks(333333); // 30 fps
#elif XBOX
Components.Add(new GamerServicesComponent(this));
#else
SynchronizationContext = new System.Windows.Forms.WindowsFormsSynchronizationContext();
#endif
GraphicsDeviceService = (IGraphicsDeviceService)Services.GetService(typeof(IGraphicsDeviceService));
@ -48,5 +52,8 @@ namespace Jellyfish.Library
public string Name { get; private set; }
public GraphicsDeviceManager GraphicsDeviceManager { get; private set; }
public IGraphicsDeviceService GraphicsDeviceService { get; private set; }
#if WINDOWS
public SynchronizationContext SynchronizationContext { get; private set; }
#endif
}
}

View File

@ -83,13 +83,6 @@
<Reference Include="System.Xml">
<Private>False</Private>
</Reference>
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
<Private>False</Private>
</Reference>
<Reference Include="System.Xml.Serialization">
<Private>False</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\AssemblyCommentAttribute.cs">
@ -116,9 +109,6 @@
<Compile Include="..\StringBuilderExtensions.cs">
<Link>StringBuilderExtensions.cs</Link>
</Compile>
<Compile Include="..\XmlSerializerHelpers.cs">
<Link>XmlSerializerHelpers.cs</Link>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="FrameRateCounter.cs" />
<Compile Include="GameBase.cs" />

View File

@ -98,13 +98,6 @@
<Reference Include="System.Xml">
<Private>False</Private>
</Reference>
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
<Private>False</Private>
</Reference>
<Reference Include="System.Xml.Serialization">
<Private>False</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\AssemblyCommentAttribute.cs">
@ -131,9 +124,6 @@
<Compile Include="..\StringBuilderExtensions.cs">
<Link>StringBuilderExtensions.cs</Link>
</Compile>
<Compile Include="..\XmlSerializerHelpers.cs">
<Link>XmlSerializerHelpers.cs</Link>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="FrameRateCounter.cs" />
<Compile Include="GameBase.cs" />

View File

@ -95,11 +95,10 @@
<RequiredTargetFramework>4.0</RequiredTargetFramework>
<Private>False</Private>
</Reference>
<Reference Include="System.Xml">
<Reference Include="System.Windows.Forms">
<Private>False</Private>
</Reference>
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
<Reference Include="System.Xml">
<Private>False</Private>
</Reference>
</ItemGroup>
@ -140,9 +139,6 @@
<Compile Include="..\StringBuilderExtensions.cs">
<Link>StringBuilderExtensions.cs</Link>
</Compile>
<Compile Include="..\XmlSerializerHelpers.cs">
<Link>XmlSerializerHelpers.cs</Link>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="FrameRateCounter.cs" />
<Compile Include="GameBase.cs" />

View File

@ -17,9 +17,9 @@ using Jellyfish.Library;
[assembly: AssemblyCopyright("Copyright © 2009-2010 Digital Jellyfish Design Ltd")]
[assembly: AssemblyComment("Developed by Sean Fausett")]
[assembly: AssemblyVersion("0.1.3.0")]
[assembly: AssemblyFileVersion("0.1.3.0")]
[assembly: AssemblyInformationalVersion("0.1.3.0")]
[assembly: AssemblyVersion("0.2.0.0")]
[assembly: AssemblyFileVersion("0.2.0.0")]
[assembly: AssemblyInformationalVersion("0.2.0.0")]
[assembly: CLSCompliant(false)]
[assembly: ComVisible(false)]

View File

@ -1,6 +1,7 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
namespace Jellyfish.Virtu
{
@ -144,16 +145,17 @@ namespace Jellyfish.Virtu
Execute65X02SedF8, Execute65C02SbcF9, Execute65C02PlxFA, Execute65C02NopFB,
Execute65C02NopFC, Execute65C02SbcFD, Execute65C02IncFE, Execute65C02NopFF
};
RS = 0xFF;
}
public override void Initialize()
{
_memory = Machine.Memory;
UpdateSettings();
Machine.Video.VSync += (sender, e) => UpdateSettings();
Is65C02 = true;
IsThrottled = true;
Multiplier = 1;
RS = 0xFF;
}
public override void Reset()
@ -161,15 +163,53 @@ namespace Jellyfish.Virtu
RS = (RS - 3) & 0xFF; // [4-14]
RPC = _memory.ReadRomRegionE0FF(0xFFFC) | (_memory.ReadRomRegionE0FF(0xFFFD) << 8);
RP |= (PB | PI);
if (Machine.Settings.Cpu.Is65C02) // [C-10]
if (Is65C02) // [C-10]
{
RP &= ~PD;
}
}
public override void LoadState(BinaryReader reader, Version version)
{
if (reader == null)
{
throw new ArgumentNullException("reader");
}
Is65C02 = reader.ReadBoolean();
IsThrottled = reader.ReadBoolean();
Multiplier = reader.ReadInt32();
RA = reader.ReadInt32();
RX = reader.ReadInt32();
RY = reader.ReadInt32();
RS = reader.ReadInt32();
RP = reader.ReadInt32();
RPC = reader.ReadInt32();
}
public override void SaveState(BinaryWriter writer)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
writer.Write(Is65C02);
writer.Write(IsThrottled);
writer.Write(Multiplier);
writer.Write(RA);
writer.Write(RX);
writer.Write(RY);
writer.Write(RS);
writer.Write(RP);
writer.Write(RPC);
}
public override string ToString()
{
return string.Format(CultureInfo.CurrentCulture, "A = 0x{0:X2} X = 0x{1:X2} Y = 0x{2:X2} P = 0x{3:X2} S = 0x01{4:X2} PC = 0x{5:X4} EA = 0x{6:X4} CC = {7}",
return string.Format(CultureInfo.InvariantCulture, "A = 0x{0:X2} X = 0x{1:X2} Y = 0x{2:X2} P = 0x{3:X2} S = 0x01{4:X2} PC = 0x{5:X4} EA = 0x{6:X4} CC = {7}",
RA, RX, RY, RP, RS, RPC, EA, CC);
}
@ -184,11 +224,6 @@ namespace Jellyfish.Virtu
return CC;
}
public void ToggleThrottle()
{
Machine.Settings.Cpu.IsThrottled ^= true;
}
#region Core Operand Actions
private void GetAddressAbs() // abs
{
@ -740,7 +775,7 @@ namespace Jellyfish.Virtu
Push(RPC & 0xFF);
Push(RP & ~PB);
RP |= PI;
if (Machine.Settings.Cpu.Is65C02) // [C-10]
if (Is65C02) // [C-10]
{
RP &= ~PD;
}
@ -830,7 +865,7 @@ namespace Jellyfish.Virtu
Push(RPC & 0xFF);
Push(RP & ~PB);
RP |= PI;
if (Machine.Settings.Cpu.Is65C02) // [C-10]
if (Is65C02) // [C-10]
{
RP &= ~PD;
}
@ -3203,10 +3238,9 @@ namespace Jellyfish.Virtu
}
#endregion
private void UpdateSettings()
{
_executeOpCode = Machine.Settings.Cpu.Is65C02 ? ExecuteOpCode65C02 : ExecuteOpCode65N02;
}
public bool Is65C02 { get { return _is65C02; } set { _is65C02 = value; _executeOpCode = _is65C02 ? ExecuteOpCode65C02 : ExecuteOpCode65N02; } }
public bool IsThrottled { get; set; }
public int Multiplier { get; set; }
public int RA { get; private set; }
public int RX { get; private set; }
@ -3221,6 +3255,7 @@ namespace Jellyfish.Virtu
private Memory _memory;
private bool _is65C02;
private Action[] _executeOpCode;
}
}

View File

@ -1,5 +1,6 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
namespace Jellyfish.Virtu
{
@ -35,6 +36,34 @@ namespace Jellyfish.Virtu
return null;
}
[SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "version")]
public static Disk525 LoadState(BinaryReader reader, Version version)
{
if (reader == null)
{
throw new ArgumentNullException("reader");
}
string name = reader.ReadString();
bool isWriteProtected = reader.ReadBoolean();
byte[] data = reader.ReadBytes(reader.ReadInt32());
return CreateDisk(name, data, isWriteProtected);
}
public void SaveState(BinaryWriter writer)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
writer.Write(Name);
writer.Write(IsWriteProtected);
writer.Write(Data.Length);
writer.Write(Data);
}
public abstract void ReadTrack(int number, int fraction, byte[] buffer);
public abstract void WriteTrack(int number, int fraction, byte[] buffer);

View File

@ -1,7 +1,8 @@
using System.Diagnostics.CodeAnalysis;
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using Jellyfish.Library;
using Jellyfish.Virtu.Services;
using Jellyfish.Virtu.Settings;
namespace Jellyfish.Virtu
{
@ -14,21 +15,8 @@ namespace Jellyfish.Virtu
public override void Initialize()
{
var romStream = StorageService.GetResourceStream("Roms/DiskII.rom", 0x0100);
romStream.ReadBlock(_romRegionC1C7, 0x0000, 0x0100);
_drives[0].InsertDisk("Default.dsk", StorageService.GetResourceStream("Disks/Default.dsk", 0x23000), false);
#if WINDOWS
var settings = Machine.Settings.DiskII;
if (settings.Disk1.Name.Length > 0)
{
_drives[0].InsertDisk(settings.Disk1.Name, settings.Disk1.IsWriteProtected);
}
if (settings.Disk2.Name.Length > 0)
{
_drives[1].InsertDisk(settings.Disk2.Name, settings.Disk2.IsWriteProtected);
}
#endif
StorageService.LoadResource("Roms/DiskII.rom", 0x0100, stream => stream.ReadBlock(_romRegionC1C7, 0, 0x0100));
StorageService.LoadResource("Disks/Default.dsk", 0x23000, stream => _drives[0].InsertDisk("Default.dsk", stream, false));
}
public override void Reset()
@ -40,9 +28,38 @@ namespace Jellyfish.Virtu
_writeMode = false;
}
public override void Uninitialize()
public override void LoadState(BinaryReader reader, Version version)
{
Flush();
if (reader == null)
{
throw new ArgumentNullException("reader");
}
_latch = reader.ReadInt32();
_phaseStates = reader.ReadInt32();
_motorOn = reader.ReadBoolean();
_driveNumber = reader.ReadInt32();
_loadMode = reader.ReadBoolean();
_writeMode = reader.ReadBoolean();
_driveSpin = reader.ReadBoolean();
_drives.ForEach(drive => drive.LoadState(reader, version));
}
public override void SaveState(BinaryWriter writer)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
writer.Write(_latch);
writer.Write(_phaseStates);
writer.Write(_motorOn);
writer.Write(_driveNumber);
writer.Write(_loadMode);
writer.Write(_writeMode);
writer.Write(_driveSpin);
_drives.ForEach(drive => drive.SaveState(writer));
}
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]

View File

@ -1,7 +1,7 @@
using System;
using System.IO;
using System.Security;
using Jellyfish.Library;
using Jellyfish.Virtu.Services;
namespace Jellyfish.Virtu
{
@ -15,13 +15,49 @@ namespace Jellyfish.Virtu
DriveArmStepDelta[3] = new int[] { 0, 1, 0, 1, -1, 0, -1, 0, 0, 1, 0, 1, -1, 0, -1, 0 }; // phase 3
}
[SecurityCritical]
public void LoadState(BinaryReader reader, Version version)
{
if (reader == null)
{
throw new ArgumentNullException("reader");
}
_trackLoaded = reader.ReadBoolean();
_trackChanged = reader.ReadBoolean();
_trackNumber = reader.ReadInt32();
_trackOffset = reader.ReadInt32();
if (_trackLoaded)
{
reader.Read(_trackData, 0, _trackData.Length);
}
_disk = reader.ReadBoolean() ? Disk525.LoadState(reader, version) : null;
}
public void SaveState(BinaryWriter writer)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
writer.Write(_trackLoaded);
writer.Write(_trackChanged);
writer.Write(_trackNumber);
writer.Write(_trackOffset);
if (_trackLoaded)
{
writer.Write(_trackData);
}
writer.Write(_disk != null);
if (_disk != null)
{
_disk.SaveState(writer);
}
}
public void InsertDisk(string fileName, bool isWriteProtected)
{
using (var stream = File.OpenRead(fileName))
{
InsertDisk(fileName, stream, isWriteProtected);
}
StorageService.LoadFile(fileName, stream => InsertDisk(fileName, stream, isWriteProtected));
}
public void InsertDisk(string name, Stream stream, bool isWriteProtected)

View File

@ -1,5 +1,6 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using Jellyfish.Library;
using Jellyfish.Virtu.Services;
@ -20,30 +21,88 @@ namespace Jellyfish.Virtu
{
_keyboardService = Machine.Services.GetService<KeyboardService>();
_gamePortService = Machine.Services.GetService<GamePortService>();
JoystickDeadZone = 0.4;
}
public override void LoadState(BinaryReader reader, Version version)
{
if (reader == null)
{
throw new ArgumentNullException("reader");
}
JoystickDeadZone = reader.ReadDouble();
UseKeyboard = reader.ReadBoolean();
Joystick0UpLeftKey = reader.ReadInt32();
Joystick0UpKey = reader.ReadInt32();
Joystick0UpRightKey = reader.ReadInt32();
Joystick0LeftKey = reader.ReadInt32();
Joystick0RightKey = reader.ReadInt32();
Joystick0DownLeftKey = reader.ReadInt32();
Joystick0DownKey = reader.ReadInt32();
Joystick0DownRightKey = reader.ReadInt32();
Joystick1UpLeftKey = reader.ReadInt32();
Joystick1UpKey = reader.ReadInt32();
Joystick1UpRightKey = reader.ReadInt32();
Joystick1LeftKey = reader.ReadInt32();
Joystick1RightKey = reader.ReadInt32();
Joystick1DownLeftKey = reader.ReadInt32();
Joystick1DownKey = reader.ReadInt32();
Joystick1DownRightKey = reader.ReadInt32();
Button0Key = reader.ReadInt32();
Button1Key = reader.ReadInt32();
Button2Key = reader.ReadInt32();
}
public override void SaveState(BinaryWriter writer)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
writer.Write(JoystickDeadZone);
writer.Write(UseKeyboard);
writer.Write(Joystick0UpLeftKey);
writer.Write(Joystick0UpKey);
writer.Write(Joystick0UpRightKey);
writer.Write(Joystick0LeftKey);
writer.Write(Joystick0RightKey);
writer.Write(Joystick0DownLeftKey);
writer.Write(Joystick0DownKey);
writer.Write(Joystick0DownRightKey);
writer.Write(Joystick1UpLeftKey);
writer.Write(Joystick1UpKey);
writer.Write(Joystick1UpRightKey);
writer.Write(Joystick1LeftKey);
writer.Write(Joystick1RightKey);
writer.Write(Joystick1DownLeftKey);
writer.Write(Joystick1DownKey);
writer.Write(Joystick1DownRightKey);
writer.Write(Button0Key);
writer.Write(Button1Key);
writer.Write(Button2Key);
}
public bool ReadButton0()
{
var settings = Machine.Settings.GamePort;
return (_gamePortService.IsButton0Down || _keyboardService.IsOpenAppleKeyDown ||
(settings.UseKeyboard && (settings.Key.Button0 > 0) && _keyboardService.IsKeyDown(settings.Key.Button0)));
(UseKeyboard && (Button0Key > 0) && _keyboardService.IsKeyDown(Button0Key)));
}
public bool ReadButton1()
{
var settings = Machine.Settings.GamePort;
return (_gamePortService.IsButton1Down || _keyboardService.IsCloseAppleKeyDown ||
(settings.UseKeyboard && (settings.Key.Button1 > 0) && _keyboardService.IsKeyDown(settings.Key.Button1)));
(UseKeyboard && (Button1Key > 0) && _keyboardService.IsKeyDown(Button1Key)));
}
public bool ReadButton2()
{
var settings = Machine.Settings.GamePort;
return (_gamePortService.IsButton2Down || !_keyboardService.IsShiftKeyDown || // Shift' [TN9]
(settings.UseKeyboard && (settings.Key.Button2 > 0) && _keyboardService.IsKeyDown(settings.Key.Button2)));
(UseKeyboard && (Button2Key > 0) && _keyboardService.IsKeyDown(Button2Key)));
}
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
@ -54,55 +113,53 @@ namespace Jellyfish.Virtu
int paddle2 = _gamePortService.Paddle2;
int paddle3 = _gamePortService.Paddle3;
var settings = Machine.Settings.GamePort;
if (settings.UseKeyboard) // override
if (UseKeyboard) // override
{
if (((settings.Key.Joystick0.UpLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.UpLeft)) ||
((settings.Key.Joystick0.Left > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.Left)) ||
((settings.Key.Joystick0.DownLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.DownLeft)))
if (((Joystick0UpLeftKey > 0) && _keyboardService.IsKeyDown(Joystick0UpLeftKey)) ||
((Joystick0LeftKey > 0) && _keyboardService.IsKeyDown(Joystick0LeftKey)) ||
((Joystick0DownLeftKey > 0) && _keyboardService.IsKeyDown(Joystick0DownLeftKey)))
{
paddle0 -= 128;
}
if (((settings.Key.Joystick0.UpRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.UpRight)) ||
((settings.Key.Joystick0.Right > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.Right)) ||
((settings.Key.Joystick0.DownRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.DownRight)))
if (((Joystick0UpRightKey > 0) && _keyboardService.IsKeyDown(Joystick0UpRightKey)) ||
((Joystick0RightKey > 0) && _keyboardService.IsKeyDown(Joystick0RightKey)) ||
((Joystick0DownRightKey > 0) && _keyboardService.IsKeyDown(Joystick0DownRightKey)))
{
paddle0 += 128;
}
if (((settings.Key.Joystick0.UpLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.UpLeft)) ||
((settings.Key.Joystick0.Up > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.Up)) ||
((settings.Key.Joystick0.UpRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.UpRight)))
if (((Joystick0UpLeftKey > 0) && _keyboardService.IsKeyDown(Joystick0UpLeftKey)) ||
((Joystick0UpKey > 0) && _keyboardService.IsKeyDown(Joystick0UpKey)) ||
((Joystick0UpRightKey > 0) && _keyboardService.IsKeyDown(Joystick0UpRightKey)))
{
paddle1 -= 128;
}
if (((settings.Key.Joystick0.DownLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.DownLeft)) ||
((settings.Key.Joystick0.Down > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.Down)) ||
((settings.Key.Joystick0.DownRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.DownRight)))
if (((Joystick0DownLeftKey > 0) && _keyboardService.IsKeyDown(Joystick0DownLeftKey)) ||
((Joystick0DownKey > 0) && _keyboardService.IsKeyDown(Joystick0DownKey)) ||
((Joystick0DownRightKey > 0) && _keyboardService.IsKeyDown(Joystick0DownRightKey)))
{
paddle1 += 128;
}
if (((settings.Key.Joystick1.UpLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.UpLeft)) ||
((settings.Key.Joystick1.Left > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.Left)) ||
((settings.Key.Joystick1.DownLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.DownLeft)))
if (((Joystick1UpLeftKey > 0) && _keyboardService.IsKeyDown(Joystick1UpLeftKey)) ||
((Joystick1LeftKey > 0) && _keyboardService.IsKeyDown(Joystick1LeftKey)) ||
((Joystick1DownLeftKey > 0) && _keyboardService.IsKeyDown(Joystick1DownLeftKey)))
{
paddle2 -= 128;
}
if (((settings.Key.Joystick1.UpRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.UpRight)) ||
((settings.Key.Joystick1.Right > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.Right)) ||
((settings.Key.Joystick1.DownRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.DownRight)))
if (((Joystick1UpRightKey > 0) && _keyboardService.IsKeyDown(Joystick1UpRightKey)) ||
((Joystick1RightKey > 0) && _keyboardService.IsKeyDown(Joystick1RightKey)) ||
((Joystick1DownRightKey > 0) && _keyboardService.IsKeyDown(Joystick1DownRightKey)))
{
paddle2 += 128;
}
if (((settings.Key.Joystick1.UpLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.UpLeft)) ||
((settings.Key.Joystick1.Up > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.Up)) ||
((settings.Key.Joystick1.UpRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.UpRight)))
if (((Joystick1UpLeftKey > 0) && _keyboardService.IsKeyDown(Joystick1UpLeftKey)) ||
((Joystick1UpKey > 0) && _keyboardService.IsKeyDown(Joystick1UpKey)) ||
((Joystick1UpRightKey > 0) && _keyboardService.IsKeyDown(Joystick1UpRightKey)))
{
paddle3 -= 128;
}
if (((settings.Key.Joystick1.DownLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.DownLeft)) ||
((settings.Key.Joystick1.Down > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.Down)) ||
((settings.Key.Joystick1.DownRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.DownRight)))
if (((Joystick1DownLeftKey > 0) && _keyboardService.IsKeyDown(Joystick1DownLeftKey)) ||
((Joystick1DownKey > 0) && _keyboardService.IsKeyDown(Joystick1DownKey)) ||
((Joystick1DownRightKey > 0) && _keyboardService.IsKeyDown(Joystick1DownRightKey)))
{
paddle3 += 128;
}
@ -139,6 +196,29 @@ namespace Jellyfish.Virtu
Paddle3Strobe = false;
}
public double JoystickDeadZone { get; set; }
public bool UseKeyboard { get; set; }
public int Joystick0UpLeftKey { get; set; }
public int Joystick0UpKey { get; set; }
public int Joystick0UpRightKey { get; set; }
public int Joystick0LeftKey { get; set; }
public int Joystick0RightKey { get; set; }
public int Joystick0DownLeftKey { get; set; }
public int Joystick0DownKey { get; set; }
public int Joystick0DownRightKey { get; set; }
public int Joystick1UpLeftKey { get; set; }
public int Joystick1UpKey { get; set; }
public int Joystick1UpRightKey { get; set; }
public int Joystick1LeftKey { get; set; }
public int Joystick1RightKey { get; set; }
public int Joystick1DownLeftKey { get; set; }
public int Joystick1DownKey { get; set; }
public int Joystick1DownRightKey { get; set; }
public int Button0Key { get; set; }
public int Button1Key { get; set; }
public int Button2Key { get; set; }
public bool Paddle0Strobe { get; private set; }
public bool Paddle1Strobe { get; private set; }
public bool Paddle2Strobe { get; private set; }

View File

@ -1,4 +1,6 @@
using System.Diagnostics.CodeAnalysis;
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using Jellyfish.Virtu.Services;
namespace Jellyfish.Virtu
@ -16,6 +18,64 @@ namespace Jellyfish.Virtu
_gamePortService = Machine.Services.GetService<GamePortService>();
}
public override void LoadState(BinaryReader reader, Version version)
{
if (reader == null)
{
throw new ArgumentNullException("reader");
}
UseGamePort = reader.ReadBoolean();
Joystick0UpLeftKey = reader.ReadInt32();
Joystick0UpKey = reader.ReadInt32();
Joystick0UpRightKey = reader.ReadInt32();
Joystick0LeftKey = reader.ReadInt32();
Joystick0RightKey = reader.ReadInt32();
Joystick0DownLeftKey = reader.ReadInt32();
Joystick0DownKey = reader.ReadInt32();
Joystick0DownRightKey = reader.ReadInt32();
Joystick1UpLeftKey = reader.ReadInt32();
Joystick1UpKey = reader.ReadInt32();
Joystick1UpRightKey = reader.ReadInt32();
Joystick1LeftKey = reader.ReadInt32();
Joystick1RightKey = reader.ReadInt32();
Joystick1DownLeftKey = reader.ReadInt32();
Joystick1DownKey = reader.ReadInt32();
Joystick1DownRightKey = reader.ReadInt32();
Button0Key = reader.ReadInt32();
Button1Key = reader.ReadInt32();
Button2Key = reader.ReadInt32();
}
public override void SaveState(BinaryWriter writer)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
writer.Write(UseGamePort);
writer.Write(Joystick0UpLeftKey);
writer.Write(Joystick0UpKey);
writer.Write(Joystick0UpRightKey);
writer.Write(Joystick0LeftKey);
writer.Write(Joystick0RightKey);
writer.Write(Joystick0DownLeftKey);
writer.Write(Joystick0DownKey);
writer.Write(Joystick0DownRightKey);
writer.Write(Joystick1UpLeftKey);
writer.Write(Joystick1UpKey);
writer.Write(Joystick1UpRightKey);
writer.Write(Joystick1LeftKey);
writer.Write(Joystick1RightKey);
writer.Write(Joystick1DownLeftKey);
writer.Write(Joystick1DownKey);
writer.Write(Joystick1DownRightKey);
writer.Write(Button0Key);
writer.Write(Button1Key);
writer.Write(Button2Key);
}
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
public int ReadLatch()
{
@ -24,87 +84,85 @@ namespace Jellyfish.Virtu
return Latch;
}
var settings = Machine.Settings.Keyboard;
if (settings.UseGamePort)
if (UseGamePort)
{
if ((settings.Key.Joystick0.UpLeft > 0) && _gamePortService.Joystick0.IsUp && _gamePortService.Joystick0.IsLeft)
if ((Joystick0UpLeftKey > 0) && _gamePortService.IsJoystick0Up && _gamePortService.IsJoystick0Left)
{
Latch = settings.Key.Joystick0.UpLeft;
Latch = Joystick0UpLeftKey;
}
else if ((settings.Key.Joystick0.UpRight > 0) && _gamePortService.Joystick0.IsUp && _gamePortService.Joystick0.IsRight)
else if ((Joystick0UpRightKey > 0) && _gamePortService.IsJoystick0Up && _gamePortService.IsJoystick0Right)
{
Latch = settings.Key.Joystick0.UpRight;
Latch = Joystick0UpRightKey;
}
else if ((settings.Key.Joystick0.DownLeft > 0) && _gamePortService.Joystick0.IsDown && _gamePortService.Joystick0.IsLeft)
else if ((Joystick0DownLeftKey > 0) && _gamePortService.IsJoystick0Down && _gamePortService.IsJoystick0Left)
{
Latch = settings.Key.Joystick0.DownLeft;
Latch = Joystick0DownLeftKey;
}
else if ((settings.Key.Joystick0.DownRight > 0) && _gamePortService.Joystick0.IsDown && _gamePortService.Joystick0.IsRight)
else if ((Joystick0DownRightKey > 0) && _gamePortService.IsJoystick0Down && _gamePortService.IsJoystick0Right)
{
Latch = settings.Key.Joystick0.DownRight;
Latch = Joystick0DownRightKey;
}
else if ((settings.Key.Joystick0.Up > 0) && _gamePortService.Joystick0.IsUp)
else if ((Joystick0UpKey > 0) && _gamePortService.IsJoystick0Up)
{
Latch = settings.Key.Joystick0.Up;
Latch = Joystick0UpKey;
}
else if ((settings.Key.Joystick0.Left > 0) && _gamePortService.Joystick0.IsLeft)
else if ((Joystick0LeftKey > 0) && _gamePortService.IsJoystick0Left)
{
Latch = settings.Key.Joystick0.Left;
Latch = Joystick0LeftKey;
}
else if ((settings.Key.Joystick0.Right > 0) && _gamePortService.Joystick0.IsRight)
else if ((Joystick0RightKey > 0) && _gamePortService.IsJoystick0Right)
{
Latch = settings.Key.Joystick0.Right;
Latch = Joystick0RightKey;
}
else if ((settings.Key.Joystick0.Down > 0) && _gamePortService.Joystick0.IsDown)
else if ((Joystick0DownKey > 0) && _gamePortService.IsJoystick0Down)
{
Latch = settings.Key.Joystick0.Down;
Latch = Joystick0DownKey;
}
if ((settings.Key.Joystick1.UpLeft > 0) && _gamePortService.Joystick1.IsUp && _gamePortService.Joystick1.IsLeft) // override
if ((Joystick1UpLeftKey > 0) && _gamePortService.IsJoystick1Up && _gamePortService.IsJoystick1Left) // override
{
Latch = settings.Key.Joystick1.UpLeft;
Latch = Joystick1UpLeftKey;
}
else if ((settings.Key.Joystick1.UpRight > 0) && _gamePortService.Joystick1.IsUp && _gamePortService.Joystick1.IsRight)
else if ((Joystick1UpRightKey > 0) && _gamePortService.IsJoystick1Up && _gamePortService.IsJoystick1Right)
{
Latch = settings.Key.Joystick1.UpRight;
Latch = Joystick1UpRightKey;
}
else if ((settings.Key.Joystick1.DownLeft > 0) && _gamePortService.Joystick1.IsDown && _gamePortService.Joystick1.IsLeft)
else if ((Joystick1DownLeftKey > 0) && _gamePortService.IsJoystick1Down && _gamePortService.IsJoystick1Left)
{
Latch = settings.Key.Joystick1.DownLeft;
Latch = Joystick1DownLeftKey;
}
else if ((settings.Key.Joystick1.DownRight > 0) && _gamePortService.Joystick1.IsDown && _gamePortService.Joystick1.IsRight)
else if ((Joystick1DownRightKey > 0) && _gamePortService.IsJoystick1Down && _gamePortService.IsJoystick1Right)
{
Latch = settings.Key.Joystick1.DownRight;
Latch = Joystick1DownRightKey;
}
else if ((settings.Key.Joystick1.Up > 0) && _gamePortService.Joystick1.IsUp)
else if ((Joystick1UpKey > 0) && _gamePortService.IsJoystick1Up)
{
Latch = settings.Key.Joystick1.Up;
Latch = Joystick1UpKey;
}
else if ((settings.Key.Joystick1.Left > 0) && _gamePortService.Joystick1.IsLeft)
else if ((Joystick1LeftKey > 0) && _gamePortService.IsJoystick1Left)
{
Latch = settings.Key.Joystick1.Left;
Latch = Joystick1LeftKey;
}
else if ((settings.Key.Joystick1.Right > 0) && _gamePortService.Joystick1.IsRight)
else if ((Joystick1RightKey > 0) && _gamePortService.IsJoystick1Right)
{
Latch = settings.Key.Joystick1.Right;
Latch = Joystick1RightKey;
}
else if ((settings.Key.Joystick1.Down > 0) && _gamePortService.Joystick1.IsDown)
else if ((Joystick1DownKey > 0) && _gamePortService.IsJoystick1Down)
{
Latch = settings.Key.Joystick1.Down;
Latch = Joystick1DownKey;
}
if ((settings.Key.Button0 > 0) && _gamePortService.IsButton0Down) // override
if ((Button0Key > 0) && _gamePortService.IsButton0Down) // override
{
Latch = settings.Key.Button0;
Latch = Button0Key;
}
else if ((settings.Key.Button1 > 0) && _gamePortService.IsButton1Down)
else if ((Button1Key > 0) && _gamePortService.IsButton1Down)
{
Latch = settings.Key.Button1;
Latch = Button1Key;
}
else if ((settings.Key.Button2 > 0) && _gamePortService.IsButton2Down)
else if ((Button2Key > 0) && _gamePortService.IsButton2Down)
{
Latch = settings.Key.Button2;
Latch = Button2Key;
}
}
@ -116,6 +174,27 @@ namespace Jellyfish.Virtu
Strobe = false;
}
public bool UseGamePort { get; set; }
public int Joystick0UpLeftKey { get; set; }
public int Joystick0UpKey { get; set; }
public int Joystick0UpRightKey { get; set; }
public int Joystick0LeftKey { get; set; }
public int Joystick0RightKey { get; set; }
public int Joystick0DownLeftKey { get; set; }
public int Joystick0DownKey { get; set; }
public int Joystick0DownRightKey { get; set; }
public int Joystick1UpLeftKey { get; set; }
public int Joystick1UpKey { get; set; }
public int Joystick1UpRightKey { get; set; }
public int Joystick1LeftKey { get; set; }
public int Joystick1RightKey { get; set; }
public int Joystick1DownLeftKey { get; set; }
public int Joystick1DownKey { get; set; }
public int Joystick1DownRightKey { get; set; }
public int Button0Key { get; set; }
public int Button1Key { get; set; }
public int Button2Key { get; set; }
public bool IsAnyKeyDown { get { return _keyboardService.IsAnyKeyDown; } }
public int Latch { get { return _latch; } set { _latch = value; Strobe = true; } }
public bool Strobe { get; private set; }

View File

@ -1,9 +1,11 @@
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Threading;
using Jellyfish.Library;
using Jellyfish.Virtu.Services;
using Jellyfish.Virtu.Settings;
namespace Jellyfish.Virtu
{
@ -15,7 +17,6 @@ namespace Jellyfish.Virtu
{
Events = new MachineEvents();
Services = new MachineServices();
Settings = new MachineSettings();
Cpu = new Cpu(this);
Memory = new Memory(this);
@ -36,7 +37,7 @@ namespace Jellyfish.Virtu
Slot7 = emptySlot;
Slots = new Collection<PeripheralCard> { null, Slot1, Slot2, Slot3, Slot4, Slot5, Slot6, Slot7 };
Components = new Collection<MachineComponent> { Cpu, Memory, Keyboard, GamePort, Cassette, Speaker, Video, Slot1, Slot2, Slot3, Slot4, Slot5, Slot6, Slot7 };
Components = new Collection<MachineComponent> { Cpu, Memory, Keyboard, GamePort, Cassette, Speaker, Video, NoSlotClock, Slot1, Slot2, Slot3, Slot4, Slot5, Slot6, Slot7 };
Thread = new Thread(Run) { Name = "Machine" };
}
@ -49,14 +50,11 @@ namespace Jellyfish.Virtu
public void Reset()
{
Components.ForEach(component => component.Reset()); // while machine starting or paused
Components.ForEach(component => component.Reset());
}
public void Start()
{
_storageService = Services.GetService<StorageService>();
_storageService.Load(MachineSettings.FileName, stream => Settings.Deserialize(stream));
State = MachineState.Starting;
Thread.Start();
}
@ -83,11 +81,6 @@ namespace Jellyfish.Virtu
Thread.Join();
}
State = MachineState.Stopped;
if (_storageService != null)
{
_storageService.Save(MachineSettings.FileName, stream => Settings.Serialize(stream));
}
}
public DiskIIController FindDiskIIController()
@ -104,10 +97,59 @@ namespace Jellyfish.Virtu
return null;
}
private void Run() // machine thread
private void Initialize()
{
Components.ForEach(component => component.Initialize());
}
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
private void LoadState()
{
var storageService = Services.GetService<StorageService>();
storageService.Load(Machine.LastStateFileName, stream =>
{
try
{
var version = new Version(Version);
using (var reader = new BinaryReader(stream))
{
version = new Version(reader.ReadString());
Components.ForEach(component => component.LoadState(reader, version));
}
}
catch (Exception)
{
if (Debugger.IsAttached)
{
Debugger.Break();
}
}
});
}
private void Uninitialize()
{
Components.ForEach(component => component.Uninitialize());
}
private void SaveState()
{
var storageService = Services.GetService<StorageService>();
storageService.Save(Machine.LastStateFileName, stream =>
{
using (var writer = new BinaryWriter(stream))
{
writer.Write(Version);
Components.ForEach(component => component.SaveState(writer));
}
});
}
private void Run() // machine thread
{
Initialize();
Reset();
LoadState();
State = MachineState.Running;
do
@ -126,12 +168,14 @@ namespace Jellyfish.Virtu
}
while (State != MachineState.Stopping);
Components.ForEach(component => component.Uninitialize());
SaveState();
Uninitialize();
}
public const string Version = "0.9.0.0";
public MachineEvents Events { get; private set; }
public MachineServices Services { get; private set; }
public MachineSettings Settings { get; private set; }
public MachineState State { get; private set; }
public Cpu Cpu { get; private set; }
@ -156,9 +200,9 @@ namespace Jellyfish.Virtu
public Thread Thread { get; private set; }
private const string LastStateFileName = "LastState.bin";
private AutoResetEvent _pauseEvent = new AutoResetEvent(false);
private AutoResetEvent _unpauseEvent = new AutoResetEvent(false);
private StorageService _storageService;
}
}

View File

@ -1,4 +1,7 @@
namespace Jellyfish.Virtu
using System;
using System.IO;
namespace Jellyfish.Virtu
{
public abstract class MachineComponent
{
@ -15,10 +18,18 @@
{
}
public virtual void LoadState(BinaryReader reader, Version version)
{
}
public virtual void Uninitialize()
{
}
public virtual void SaveState(BinaryWriter writer)
{
}
protected Machine Machine { get; private set; }
}
}

View File

@ -14,7 +14,7 @@ namespace Jellyfish.Virtu
public override string ToString()
{
return string.Format(CultureInfo.CurrentCulture, "Delta = {0} Action = {{{1}.{2}}}", Delta, Action.Method.DeclaringType.Name, Action.Method.Name);
return string.Format(CultureInfo.InvariantCulture, "Delta = {0} Action = {{{1}.{2}}}", Delta, Action.Method.DeclaringType.Name, Action.Method.Name);
}
public int Delta { get; set; }

View File

@ -1,408 +0,0 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Xml;
using System.Xml.Linq;
namespace Jellyfish.Virtu.Settings
{
public sealed class MachineSettings
{
public MachineSettings()
{
Cpu = new CpuSettings { Is65C02 = true, IsThrottled = true, Multiplier = 1 };
DiskII = new DiskIISettings
{
Disk1 = new DiskSettings { Name = string.Empty, IsWriteProtected = false },
Disk2 = new DiskSettings { Name = string.Empty, IsWriteProtected = false }
};
Keyboard = new KeyboardSettings
{
UseGamePort = false,
Key = new KeySettings
{
Joystick0 = new JoystickSettings { UpLeft = 0, Up = 'I', UpRight = 0, Left = 'J', Right = 'L', DownLeft = 0, Down = 'K', DownRight = 0 },
Joystick1 = new JoystickSettings { UpLeft = 0, Up = 'E', UpRight = 0, Left = 'S', Right = 'F', DownLeft = 0, Down = 'D', DownRight = 0 },
Button0 = 0, Button1 = 0, Button2 = 0
}
};
GamePort = new GamePortSettings
{
UseKeyboard = false,
Key = new KeySettings
{
Joystick0 = new JoystickSettings { UpLeft = 0, Up = 0, UpRight = 0, Left = 0, Right = 0, DownLeft = 0, Down = 0, DownRight = 0 },
Joystick1 = new JoystickSettings { UpLeft = 0, Up = 0, UpRight = 0, Left = 0, Right = 0, DownLeft = 0, Down = 0, DownRight = 0 },
Button0 = 0, Button1 = 0, Button2 = 0
}
};
Audio = new AudioSettings { Volume = 0.5 };
Video = new VideoSettings
{
IsFullScreen = false, IsMonochrome = false, ScannerOptions = ScannerOptions.None,
Color = new ColorSettings
{
Black = 0xFF000000, // BGRA
DarkBlue = 0xFF000099,
DarkGreen = 0xFF117722,
MediumBlue = 0xFF0000FF,
Brown = 0xFF885500,
LightGrey = 0xFF99AAAA,
Green = 0xFF00EE11,
Aquamarine = 0xFF55FFAA,
DeepRed = 0xFFFF1111,
Purple = 0xFFDD00DD,
DarkGrey = 0xFF445555,
LightBlue = 0xFF33AAFF,
Orange = 0xFFFF4411,
Pink = 0xFFFF9988,
Yellow = 0xFFFFFF11,
White = 0xFFFFFFFF,
Monochrome = 0xFF00AA00
}
};
}
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
public void Deserialize(Stream stream)
{
try
{
using (var reader = XmlReader.Create(stream))
{
var ns = Namespace;
var root = XElement.Load(reader);
var cpu = root.Element(ns + "Cpu");
Cpu = new CpuSettings
{
Is65C02 = (bool)cpu.Attribute("Is65C02"),
IsThrottled = (bool)cpu.Attribute("IsThrottled"),
Multiplier = (int)cpu.Attribute("Multiplier")
};
var diskII = root.Element(ns + "DiskII");
var disk1 = diskII.Element(ns + "Disk1");
var disk2 = diskII.Element(ns + "Disk2");
DiskII = new DiskIISettings
{
Disk1 = new DiskSettings
{
Name = (string)disk1.Attribute("Name") ?? string.Empty,
IsWriteProtected = (bool)disk1.Attribute("IsWriteProtected")
},
Disk2 = new DiskSettings
{
Name = (string)disk2.Attribute("Name") ?? string.Empty,
IsWriteProtected = (bool)disk2.Attribute("IsWriteProtected")
},
};
var keyboard = root.Element(ns + "Keyboard");
var key = keyboard.Element(ns + "Key");
var joystick0 = key.Element(ns + "Joystick0");
var joystick1 = key.Element(ns + "Joystick1");
var buttons = key.Element(ns + "Buttons");
Keyboard = new KeyboardSettings
{
UseGamePort = (bool)keyboard.Attribute("UseGamePort"),
Key = new KeySettings
{
Joystick0 = new JoystickSettings
{
UpLeft = (int)joystick0.Attribute("UpLeft"),
Up = (int)joystick0.Attribute("Up"),
UpRight = (int)joystick0.Attribute("UpRight"),
Left = (int)joystick0.Attribute("Left"),
Right = (int)joystick0.Attribute("Right"),
DownLeft = (int)joystick0.Attribute("DownLeft"),
Down = (int)joystick0.Attribute("Down"),
DownRight = (int)joystick0.Attribute("DownRight")
},
Joystick1 = new JoystickSettings
{
UpLeft = (int)joystick1.Attribute("UpLeft"),
Up = (int)joystick1.Attribute("Up"),
UpRight = (int)joystick1.Attribute("UpRight"),
Left = (int)joystick1.Attribute("Left"),
Right = (int)joystick1.Attribute("Right"),
DownLeft = (int)joystick1.Attribute("DownLeft"),
Down = (int)joystick1.Attribute("Down"),
DownRight = (int)joystick1.Attribute("DownRight")
},
Button0 = (int)buttons.Attribute("Button0"),
Button1 = (int)buttons.Attribute("Button1"),
Button2 = (int)buttons.Attribute("Button2")
}
};
var gamePort = root.Element(ns + "GamePort");
key = gamePort.Element(ns + "Key");
joystick0 = key.Element(ns + "Joystick0");
joystick1 = key.Element(ns + "Joystick1");
buttons = key.Element(ns + "Buttons");
GamePort = new GamePortSettings
{
UseKeyboard = (bool)gamePort.Attribute("UseKeyboard"),
Key = new KeySettings
{
Joystick0 = new JoystickSettings
{
UpLeft = (int)joystick0.Attribute("UpLeft"),
Up = (int)joystick0.Attribute("Up"),
UpRight = (int)joystick0.Attribute("UpRight"),
Left = (int)joystick0.Attribute("Left"),
Right = (int)joystick0.Attribute("Right"),
DownLeft = (int)joystick0.Attribute("DownLeft"),
Down = (int)joystick0.Attribute("Down"),
DownRight = (int)joystick0.Attribute("DownRight")
},
Joystick1 = new JoystickSettings
{
UpLeft = (int)joystick1.Attribute("UpLeft"),
Up = (int)joystick1.Attribute("Up"),
UpRight = (int)joystick1.Attribute("UpRight"),
Left = (int)joystick1.Attribute("Left"),
Right = (int)joystick1.Attribute("Right"),
DownLeft = (int)joystick1.Attribute("DownLeft"),
Down = (int)joystick1.Attribute("Down"),
DownRight = (int)joystick1.Attribute("DownRight")
},
Button0 = (int)buttons.Attribute("Button0"),
Button1 = (int)buttons.Attribute("Button1"),
Button2 = (int)buttons.Attribute("Button2")
}
};
var audio = root.Element(ns + "Audio");
Audio = new AudioSettings
{
Volume = (double)audio.Attribute("Volume")
};
var video = root.Element(ns + "Video");
var color = video.Element(ns + "Color");
Video = new VideoSettings
{
IsFullScreen = (bool)video.Attribute("IsFullScreen"),
IsMonochrome = (bool)video.Attribute("IsMonochrome"),
ScannerOptions = (ScannerOptions)Enum.Parse(typeof(ScannerOptions), (string)video.Attribute("ScannerOptions"), true),
Color = new ColorSettings
{
Black = (uint)color.Attribute("Black"),
DarkBlue = (uint)color.Attribute("DarkBlue"),
DarkGreen = (uint)color.Attribute("DarkGreen"),
MediumBlue = (uint)color.Attribute("MediumBlue"),
Brown = (uint)color.Attribute("Brown"),
LightGrey = (uint)color.Attribute("LightGrey"),
Green = (uint)color.Attribute("Green"),
Aquamarine = (uint)color.Attribute("Aquamarine"),
DeepRed = (uint)color.Attribute("DeepRed"),
Purple = (uint)color.Attribute("Purple"),
DarkGrey = (uint)color.Attribute("DarkGrey"),
LightBlue = (uint)color.Attribute("LightBlue"),
Orange = (uint)color.Attribute("Orange"),
Pink = (uint)color.Attribute("Pink"),
Yellow = (uint)color.Attribute("Yellow"),
White = (uint)color.Attribute("White"),
Monochrome = (uint)color.Attribute("Monochrome")
}
};
}
}
catch (Exception)
{
}
}
public void Serialize(Stream stream)
{
var ns = Namespace;
var xml = new XElement(ns + "MachineSettings",
new XElement(ns + "Cpu",
new XAttribute("Is65C02", Cpu.Is65C02),
new XAttribute("IsThrottled", Cpu.IsThrottled),
new XAttribute("Multiplier", Cpu.Multiplier)),
new XElement(ns + "DiskII",
new XElement(ns + "Disk1",
new XAttribute("Name", DiskII.Disk1.Name),
new XAttribute("IsWriteProtected", DiskII.Disk1.IsWriteProtected)),
new XElement(ns + "Disk2",
new XAttribute("Name", DiskII.Disk2.Name),
new XAttribute("IsWriteProtected", DiskII.Disk2.IsWriteProtected))),
new XElement(ns + "Keyboard",
new XAttribute("UseGamePort", Keyboard.UseGamePort),
new XElement(ns + "Key",
new XElement(ns + "Joystick0",
new XAttribute("UpLeft", Keyboard.Key.Joystick0.UpLeft),
new XAttribute("Up", Keyboard.Key.Joystick0.Up),
new XAttribute("UpRight", Keyboard.Key.Joystick0.UpRight),
new XAttribute("Left", Keyboard.Key.Joystick0.Left),
new XAttribute("Right", Keyboard.Key.Joystick0.Right),
new XAttribute("DownLeft", Keyboard.Key.Joystick0.DownLeft),
new XAttribute("Down", Keyboard.Key.Joystick0.Down),
new XAttribute("DownRight", Keyboard.Key.Joystick0.DownRight)),
new XElement(ns + "Joystick1",
new XAttribute("UpLeft", Keyboard.Key.Joystick1.UpLeft),
new XAttribute("Up", Keyboard.Key.Joystick1.Up),
new XAttribute("UpRight", Keyboard.Key.Joystick1.UpRight),
new XAttribute("Left", Keyboard.Key.Joystick1.Left),
new XAttribute("Right", Keyboard.Key.Joystick1.Right),
new XAttribute("DownLeft", Keyboard.Key.Joystick1.DownLeft),
new XAttribute("Down", Keyboard.Key.Joystick1.Down),
new XAttribute("DownRight", Keyboard.Key.Joystick1.DownRight)),
new XElement(ns + "Buttons",
new XAttribute("Button0", Keyboard.Key.Button0),
new XAttribute("Button1", Keyboard.Key.Button1),
new XAttribute("Button2", Keyboard.Key.Button2)))),
new XElement(ns + "GamePort",
new XAttribute("UseKeyboard", GamePort.UseKeyboard),
new XElement(ns + "Key",
new XElement(ns + "Joystick0",
new XAttribute("UpLeft", GamePort.Key.Joystick0.UpLeft),
new XAttribute("Up", GamePort.Key.Joystick0.Up),
new XAttribute("UpRight", GamePort.Key.Joystick0.UpRight),
new XAttribute("Left", GamePort.Key.Joystick0.Left),
new XAttribute("Right", GamePort.Key.Joystick0.Right),
new XAttribute("DownLeft", GamePort.Key.Joystick0.DownLeft),
new XAttribute("Down", GamePort.Key.Joystick0.Down),
new XAttribute("DownRight", GamePort.Key.Joystick0.DownRight)),
new XElement(ns + "Joystick1",
new XAttribute("UpLeft", GamePort.Key.Joystick1.UpLeft),
new XAttribute("Up", GamePort.Key.Joystick1.Up),
new XAttribute("UpRight", GamePort.Key.Joystick1.UpRight),
new XAttribute("Left", GamePort.Key.Joystick1.Left),
new XAttribute("Right", GamePort.Key.Joystick1.Right),
new XAttribute("DownLeft", GamePort.Key.Joystick1.DownLeft),
new XAttribute("Down", GamePort.Key.Joystick1.Down),
new XAttribute("DownRight", GamePort.Key.Joystick1.DownRight)),
new XElement(ns + "Buttons",
new XAttribute("Button0", Keyboard.Key.Button0),
new XAttribute("Button1", Keyboard.Key.Button1),
new XAttribute("Button2", Keyboard.Key.Button2)))),
new XElement(ns + "Audio",
new XAttribute("Volume", Audio.Volume)),
new XElement(ns + "Video",
new XAttribute("IsFullScreen", Video.IsFullScreen),
new XAttribute("IsMonochrome", Video.IsMonochrome),
new XAttribute("ScannerOptions", Video.ScannerOptions),
new XElement(ns + "Color",
new XAttribute("Black", Video.Color.Black),
new XAttribute("DarkBlue", Video.Color.DarkBlue),
new XAttribute("DarkGreen", Video.Color.DarkGreen),
new XAttribute("MediumBlue", Video.Color.MediumBlue),
new XAttribute("Brown", Video.Color.Brown),
new XAttribute("LightGrey", Video.Color.LightGrey),
new XAttribute("Green", Video.Color.Green),
new XAttribute("Aquamarine", Video.Color.Aquamarine),
new XAttribute("DeepRed", Video.Color.DeepRed),
new XAttribute("Purple", Video.Color.Purple),
new XAttribute("DarkGrey", Video.Color.DarkGrey),
new XAttribute("LightBlue", Video.Color.LightBlue),
new XAttribute("Orange", Video.Color.Orange),
new XAttribute("Pink", Video.Color.Pink),
new XAttribute("Yellow", Video.Color.Yellow),
new XAttribute("White", Video.Color.White),
new XAttribute("Monochrome", Video.Color.Monochrome))));
using (var writer = XmlWriter.Create(stream))
{
xml.WriteTo(writer);
}
}
public CpuSettings Cpu { get; set; }
public DiskIISettings DiskII { get; set; }
public KeyboardSettings Keyboard { get; set; }
public GamePortSettings GamePort { get; set; }
public AudioSettings Audio { get; set; }
public VideoSettings Video { get; set; }
public const string FileName = "Settings.xml";
[SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
public static readonly XNamespace Namespace = "http://schemas.jellyfish.co.nz/virtu/settings";
}
public sealed class CpuSettings
{
public bool Is65C02 { get; set; }
public bool IsThrottled { get; set; }
public int Multiplier { get; set; }
}
public sealed class DiskSettings
{
public string Name { get; set; }
public bool IsWriteProtected { get; set; }
};
public sealed class DiskIISettings
{
public DiskSettings Disk1 { get; set; }
public DiskSettings Disk2 { get; set; }
};
public sealed class JoystickSettings
{
public int UpLeft { get; set; }
public int Up { get; set; }
public int UpRight { get; set; }
public int Left { get; set; }
public int Right { get; set; }
public int DownLeft { get; set; }
public int Down { get; set; }
public int DownRight { get; set; }
};
public sealed class KeySettings
{
public JoystickSettings Joystick0 { get; set; }
public JoystickSettings Joystick1 { get; set; }
public int Button0 { get; set; }
public int Button1 { get; set; }
public int Button2 { get; set; }
};
public sealed class KeyboardSettings
{
public bool UseGamePort { get; set; }
public KeySettings Key { get; set; }
}
public sealed class GamePortSettings
{
public bool UseKeyboard { get; set; }
public KeySettings Key { get; set; }
}
public sealed class AudioSettings
{
public double Volume { get; set; }
};
public sealed class ColorSettings
{
public uint Black { get; set; }
public uint DarkBlue { get; set; }
public uint DarkGreen { get; set; }
public uint MediumBlue { get; set; }
public uint Brown { get; set; }
public uint LightGrey { get; set; }
public uint Green { get; set; }
public uint Aquamarine { get; set; }
public uint DeepRed { get; set; }
public uint Purple { get; set; }
public uint DarkGrey { get; set; }
public uint LightBlue { get; set; }
public uint Orange { get; set; }
public uint Pink { get; set; }
public uint Yellow { get; set; }
public uint White { get; set; }
public uint Monochrome { get; set; }
}
[Flags]
public enum ScannerOptions { None = 0x0, AppleII = 0x1, Pal = 0x2 } // defaults to AppleIIe, Ntsc
public sealed class VideoSettings
{
public bool IsFullScreen { get; set; }
public bool IsMonochrome { get; set; }
public ScannerOptions ScannerOptions { get; set; }
public ColorSettings Color { get; set; }
};
}

View File

@ -77,6 +77,12 @@ namespace Jellyfish.Virtu
WriteRamModeBankRegion[Video.ModeF][BankAux][Region080B] = WriteRamModeFAuxRegion080B;
WriteRamModeBankRegion[Video.ModeF][BankAux][Region203F] = WriteRamModeFAuxRegion203F;
WriteRamModeBankRegion[Video.ModeF][BankAux][Region405F] = WriteRamModeFAuxRegion405F;
_writeIoRegionC0C0 = WriteIoRegionC0C0; // cache delegates; avoids garbage
_writeIoRegionC1C7 = WriteIoRegionC1C7;
_writeIoRegionC3C3 = WriteIoRegionC3C3;
_writeIoRegionC8CF = WriteIoRegionC8CF;
_writeRomRegionD0FF = WriteRomRegionD0FF;
}
public override void Initialize()
@ -88,11 +94,13 @@ namespace Jellyfish.Virtu
_video = Machine.Video;
_noSlotClock = Machine.NoSlotClock;
var romStream = StorageService.GetResourceStream("Roms/AppleIIe.rom", 0x4000);
romStream.Seek(0x0100, SeekOrigin.Current);
romStream.ReadBlock(_romInternalRegionC1CF, 0x0000, 0x0F00);
romStream.ReadBlock(_romRegionD0DF, 0x0000, 0x1000);
romStream.ReadBlock(_romRegionE0FF, 0x0000, 0x2000);
StorageService.LoadResource("Roms/AppleIIe.rom", 0x4000, stream =>
{
stream.Seek(0x0100, SeekOrigin.Current);
stream.ReadBlock(_romInternalRegionC1CF, 0, _romInternalRegionC1CF.Length);
stream.ReadBlock(_romRegionD0DF, 0, _romRegionD0DF.Length);
stream.ReadBlock(_romRegionE0FF, 0, _romRegionE0FF.Length);
});
if ((ReadRomRegionE0FF(0xFBB3) == 0x06) && (ReadRomRegionE0FF(0xFBBF) == 0xC1))
{
@ -116,6 +124,55 @@ namespace Jellyfish.Virtu
MapRegionD0FF();
}
public override void LoadState(BinaryReader reader, Version version)
{
if (reader == null)
{
throw new ArgumentNullException("reader");
}
_state = reader.ReadInt32();
_slotRegionC8CF = reader.ReadInt32();
reader.Read(_ramMainRegion0001, 0, _ramMainRegion0001.Length);
reader.Read(_ramMainRegion02BF, 0, _ramMainRegion02BF.Length);
reader.Read(_ramMainBank1RegionD0DF, 0, _ramMainBank1RegionD0DF.Length);
reader.Read(_ramMainBank2RegionD0DF, 0, _ramMainBank2RegionD0DF.Length);
reader.Read(_ramMainRegionE0FF, 0, _ramMainRegionE0FF.Length);
reader.Read(_ramAuxRegion0001, 0, _ramAuxRegion0001.Length);
reader.Read(_ramAuxRegion02BF, 0, _ramAuxRegion02BF.Length);
reader.Read(_ramAuxBank1RegionD0DF, 0, _ramAuxBank1RegionD0DF.Length);
reader.Read(_ramAuxBank2RegionD0DF, 0, _ramAuxBank2RegionD0DF.Length);
reader.Read(_ramAuxRegionE0FF, 0, _ramAuxRegionE0FF.Length);
MapRegion0001();
MapRegion02BF();
MapRegionC0CF();
MapRegionD0FF();
}
public override void SaveState(BinaryWriter writer)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
writer.Write(_state);
writer.Write(_slotRegionC8CF);
writer.Write(_ramMainRegion0001);
writer.Write(_ramMainRegion02BF);
writer.Write(_ramMainBank1RegionD0DF);
writer.Write(_ramMainBank2RegionD0DF);
writer.Write(_ramMainRegionE0FF);
writer.Write(_ramAuxRegion0001);
writer.Write(_ramAuxRegion02BF);
writer.Write(_ramAuxBank1RegionD0DF);
writer.Write(_ramAuxBank2RegionD0DF);
writer.Write(_ramAuxRegionE0FF);
}
#region Core Read & Write
public int Read(int address)
{
@ -1203,10 +1260,10 @@ namespace Jellyfish.Virtu
_regionWrite[RegionC1C7] = null;
_regionWrite[RegionC3C3] = null;
_regionWrite[RegionC8CF] = null;
_writeRegion[RegionC0C0] = WriteIoRegionC0C0;
_writeRegion[RegionC1C7] = WriteIoRegionC1C7;
_writeRegion[RegionC3C3] = WriteIoRegionC3C3;
_writeRegion[RegionC8CF] = WriteIoRegionC8CF;
_writeRegion[RegionC0C0] = _writeIoRegionC0C0;
_writeRegion[RegionC1C7] = _writeIoRegionC1C7;
_writeRegion[RegionC3C3] = _writeIoRegionC3C3;
_writeRegion[RegionC8CF] = _writeIoRegionC8CF;
}
private void MapRegionD0FF()
@ -1248,8 +1305,8 @@ namespace Jellyfish.Virtu
{
_regionWrite[RegionD0DF] = null;
_regionWrite[RegionE0FF] = null;
_writeRegion[RegionD0DF] = WriteRomRegionD0FF;
_writeRegion[RegionE0FF] = WriteRomRegionD0FF;
_writeRegion[RegionD0DF] = _writeRomRegionD0FF;
_writeRegion[RegionE0FF] = _writeRomRegionD0FF;
}
}
@ -1533,6 +1590,12 @@ namespace Jellyfish.Virtu
public MonitorType Monitor { get; private set; }
public int VideoMode { get { return StateVideoMode[_state & StateVideo]; } }
private Action<int, byte> _writeIoRegionC0C0;
private Action<int, byte> _writeIoRegionC1C7;
private Action<int, byte> _writeIoRegionC3C3;
private Action<int, byte> _writeIoRegionC8CF;
private Action<int, byte> _writeRomRegionD0FF;
private Keyboard _keyboard;
private GamePort _gamePort;
private Cassette _cassette;

View File

@ -1,5 +1,5 @@
using System;
using System.Collections;
using System.IO;
namespace Jellyfish.Virtu
{
@ -8,7 +8,42 @@ namespace Jellyfish.Virtu
public NoSlotClock(Machine machine) :
base(machine)
{
ResetClock();
}
public override void Initialize()
{
_clockEnabled = false;
_writeEnabled = true;
_clockRegister = new RingRegister(0x0, 0x1);
_comparisonRegister = new RingRegister(ClockInitSequence, 0x1);
}
public override void LoadState(BinaryReader reader, Version version)
{
if (reader == null)
{
throw new ArgumentNullException("reader");
}
_clockEnabled = reader.ReadBoolean();
_writeEnabled = reader.ReadBoolean();
_clockRegister = new RingRegister(reader.ReadUInt64(), reader.ReadUInt64());
_comparisonRegister = new RingRegister(reader.ReadUInt64(), reader.ReadUInt64());
}
public override void SaveState(BinaryWriter writer)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
writer.Write(_clockEnabled);
writer.Write(_writeEnabled);
writer.Write(_clockRegister.Data);
writer.Write(_clockRegister.Mask);
writer.Write(_comparisonRegister.Data);
writer.Write(_comparisonRegister.Mask);
}
public int Read(int address, int data)
@ -36,18 +71,10 @@ namespace Jellyfish.Virtu
}
}
private void ResetClock()
{
// SmartWatch reset - whether tied to system reset is component specific
_comparisonRegister.Reset();
_clockRegisterEnabled = false;
_writeEnabled = true;
}
private int ReadClock(int data)
{
// for a ROM, A2 high = read, and data out (if any) is on D0
if (!_clockRegisterEnabled)
if (!_clockEnabled)
{
_comparisonRegister.Reset();
_writeEnabled = true;
@ -57,7 +84,7 @@ namespace Jellyfish.Virtu
data = _clockRegister.ReadBit(Machine.Video.ReadFloatingBus());
if (_clockRegister.NextBit())
{
_clockRegisterEnabled = false;
_clockEnabled = false;
}
return data;
}
@ -70,13 +97,13 @@ namespace Jellyfish.Virtu
return;
}
if (!_clockRegisterEnabled)
if (!_clockEnabled)
{
if ((_comparisonRegister.CompareBit(address)))
{
if (_comparisonRegister.NextBit())
{
_clockRegisterEnabled = true;
_clockEnabled = true;
PopulateClockRegister();
}
}
@ -89,7 +116,7 @@ namespace Jellyfish.Virtu
else if (_clockRegister.NextBit())
{
// simulate writes, but our clock register is read-only
_clockRegisterEnabled = false;
_clockEnabled = false;
}
}
@ -133,18 +160,17 @@ namespace Jellyfish.Virtu
private const ulong ClockInitSequence = 0x5CA33AC55CA33AC5;
private bool _clockRegisterEnabled;
private bool _clockEnabled;
private bool _writeEnabled;
private RingRegister _clockRegister = new RingRegister();
private RingRegister _comparisonRegister = new RingRegister(ClockInitSequence);
private RingRegister _clockRegister;
private RingRegister _comparisonRegister;
private sealed class RingRegister
private struct RingRegister
{
public RingRegister(ulong data = 0)
public RingRegister(ulong data, ulong mask)
{
_register = data;
Reset();
_data = data;
_mask = mask;
}
public void Reset()
@ -169,17 +195,17 @@ namespace Jellyfish.Virtu
public void WriteBit(int data)
{
_register = ((data & 0x1) != 0) ? (_register | _mask) : (_register & ~_mask);
_data = ((data & 0x1) != 0) ? (_data | _mask) : (_data & ~_mask);
}
public int ReadBit(int data)
{
return ((_register & _mask) != 0) ? (data | 0x1) : (data & ~0x1);
return ((_data & _mask) != 0) ? (data | 0x1) : (data & ~0x1);
}
public bool CompareBit(int data)
{
return (((_register & _mask) != 0) == ((data & 0x1) != 0));
return (((_data & _mask) != 0) == ((data & 0x1) != 0));
}
public bool NextBit()
@ -192,8 +218,11 @@ namespace Jellyfish.Virtu
return false;
}
public ulong Data { get { return _data; } } // no auto props
public ulong Mask { get { return _mask; } }
private ulong _data;
private ulong _mask;
private ulong _register;
}
}
}

View File

@ -27,8 +27,7 @@ namespace Jellyfish.Virtu.Services
_index = (_index + 2) % SampleSize;
if (_index == 0)
{
_readEvent.Set();
if (Machine.Settings.Cpu.IsThrottled)
if (Machine.Cpu.IsThrottled)
{
_writeEvent.WaitOne(SampleLatency * 2); // allow timeout; avoids deadlock
}
@ -40,18 +39,10 @@ namespace Jellyfish.Virtu.Services
Buffer.BlockCopy(SampleZero, 0, _buffer, 0, SampleSize);
}
public abstract void SetVolume(double volume); // machine thread
public abstract void SetVolume(double volume);
protected void Update(int bufferSize, Action<byte[], int> updateBuffer) // audio thread
protected void Update() // audio thread
{
if (Machine.State == MachineState.Running)
{
_readEvent.WaitOne(SampleLatency * 2); // allow timeout; avoids deadlock
}
if (updateBuffer != null)
{
updateBuffer(_buffer, bufferSize);
}
_writeEvent.Set();
}
@ -64,10 +55,12 @@ namespace Jellyfish.Virtu.Services
[SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")]
protected static readonly byte[] SampleZero = new byte[SampleSize];
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
protected byte[] Source { get { return _buffer; } }
private byte[] _buffer = new byte[SampleSize];
private int _index;
private AutoResetEvent _readEvent = new AutoResetEvent(false);
private AutoResetEvent _writeEvent = new AutoResetEvent(false);
}
}

View File

@ -1,53 +1,5 @@
namespace Jellyfish.Virtu.Services
{
public struct Joystick
{
public Joystick(bool isUp, bool isLeft, bool isRight, bool isDown)
{
_isUp = isUp;
_isLeft = isLeft;
_isRight = isRight;
_isDown = isDown;
}
public override bool Equals(object obj)
{
return ((obj is Joystick) && (this == (Joystick)obj));
}
public override int GetHashCode()
{
return (_isUp.GetHashCode() ^ _isLeft.GetHashCode() ^ _isRight.GetHashCode() ^ _isDown.GetHashCode());
}
public override string ToString()
{
return !(_isUp || _isDown || _isLeft || _isRight) ? "Position = Center" :
string.Concat("Position = ", _isUp ? "Up" : _isDown ? "Down" : string.Empty, _isLeft ? "Left" : _isRight ? "Right" : string.Empty);
}
public static bool operator ==(Joystick joystick1, Joystick joystick2)
{
return ((joystick1._isUp == joystick2._isUp) && (joystick1._isLeft == joystick2._isLeft) &&
(joystick1._isRight == joystick2._isRight) && (joystick1._isDown == joystick2._isDown));
}
public static bool operator !=(Joystick joystick1, Joystick joystick2)
{
return !(joystick1 == joystick2);
}
public bool IsUp { get { return _isUp; } } // no auto props
public bool IsLeft { get { return _isLeft; } }
public bool IsRight { get { return _isRight; } }
public bool IsDown { get { return _isDown; } }
private bool _isUp;
private bool _isLeft;
private bool _isRight;
private bool _isDown;
}
public class GamePortService : MachineService
{
public GamePortService(Machine machine) :
@ -63,8 +15,15 @@
public int Paddle2 { get; protected set; }
public int Paddle3 { get; protected set; }
public Joystick Joystick0 { get; protected set; }
public Joystick Joystick1 { get; protected set; }
public bool IsJoystick0Up { get; protected set; }
public bool IsJoystick0Left { get; protected set; }
public bool IsJoystick0Right { get; protected set; }
public bool IsJoystick0Down { get; protected set; }
public bool IsJoystick1Up { get; protected set; }
public bool IsJoystick1Left { get; protected set; }
public bool IsJoystick1Right { get; protected set; }
public bool IsJoystick1Down { get; protected set; }
public bool IsButton0Down { get; protected set; }
public bool IsButton1Down { get; protected set; }

View File

@ -12,7 +12,7 @@ namespace Jellyfish.Virtu.Services
{
}
public override void Load(string path, Action<Stream> reader)
public override void Load(string fileName, Action<Stream> reader)
{
if (reader == null)
{
@ -23,7 +23,7 @@ namespace Jellyfish.Virtu.Services
{
using (var store = GetStore())
{
using (var stream = new IsolatedStorageFileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, store))
using (var stream = store.OpenFile(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
reader(stream);
}
@ -37,7 +37,7 @@ namespace Jellyfish.Virtu.Services
}
}
public override void Save(string path, Action<Stream> writer)
public override void Save(string fileName, Action<Stream> writer)
{
if (writer == null)
{
@ -48,7 +48,7 @@ namespace Jellyfish.Virtu.Services
{
using (var store = GetStore())
{
using (var stream = new IsolatedStorageFileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, store))
using (var stream = store.OpenFile(fileName, FileMode.Create, FileAccess.Write, FileShare.None))
{
writer(stream);
}

View File

@ -16,7 +16,7 @@ namespace Jellyfish.Virtu.Services
}
if (_serviceProviders.ContainsKey(serviceType))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Strings.ServiceAlreadyPresent, serviceType.FullName), "serviceType");
throw new ArgumentException(string.Format(CultureInfo.CurrentUICulture, Strings.ServiceAlreadyPresent, serviceType.FullName), "serviceType");
}
if (serviceProvider == null)
{
@ -24,7 +24,7 @@ namespace Jellyfish.Virtu.Services
}
if (!serviceType.IsAssignableFrom(serviceProvider.GetType()))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Strings.ServiceMustBeAssignable, serviceType.FullName, serviceProvider.GetType().FullName));
throw new ArgumentException(string.Format(CultureInfo.CurrentUICulture, Strings.ServiceMustBeAssignable, serviceType.FullName, serviceProvider.GetType().FullName));
}
_serviceProviders.Add(serviceType, serviceProvider);

View File

@ -1,9 +1,9 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Resources;
using System.Security;
using Jellyfish.Library;
using Jellyfish.Virtu.Properties;
namespace Jellyfish.Virtu.Services
@ -15,24 +15,128 @@ namespace Jellyfish.Virtu.Services
{
}
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static Stream GetResourceStream(string resourceName, int resourceSize = 0)
public abstract void Load(string fileName, Action<Stream> reader);
#if !WINDOWS
[SecuritySafeCritical]
#endif
public static void LoadFile(string fileName, Action<Stream> reader)
{
var resourceManager = new ResourceManager("Jellyfish.Virtu.g", Assembly.GetExecutingAssembly()) { IgnoreCase = true };
var resourceStream = (Stream)resourceManager.GetObject(resourceName);
if (reader == null)
{
throw new ArgumentNullException("reader");
}
try
{
using (var stream = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
reader(stream);
}
}
catch (FileNotFoundException)
{
}
}
#if !WINDOWS
[SecuritySafeCritical]
#endif
public static void LoadFile(FileInfo fileInfo, Action<Stream> reader)
{
if (fileInfo == null)
{
throw new ArgumentNullException("fileInfo");
}
if (reader == null)
{
throw new ArgumentNullException("reader");
}
try
{
using (var stream = fileInfo.Open(FileMode.Open, FileAccess.Read, FileShare.Read))
{
reader(stream);
}
}
catch (SecurityException)
{
}
}
public static void LoadResource(string resourceName, int resourceSize, Action<Stream> reader)
{
if (reader == null)
{
throw new ArgumentNullException("reader");
}
try
{
using (var stream = GetResourceStream(resourceName, resourceSize))
{
reader(stream);
}
}
catch (FileNotFoundException)
{
}
}
public abstract void Save(string fileName, Action<Stream> writer);
#if !WINDOWS
[SecuritySafeCritical]
#endif
public static void SaveFile(string fileName, Action<Stream> writer)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
using (var stream = File.Open(fileName, FileMode.Create, FileAccess.Write, FileShare.None))
{
writer(stream);
}
}
#if !WINDOWS
[SecuritySafeCritical]
#endif
public static void SaveFile(FileInfo fileInfo, Action<Stream> writer)
{
if (fileInfo == null)
{
throw new ArgumentNullException("fileInfo");
}
if (writer == null)
{
throw new ArgumentNullException("writer");
}
using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write, FileShare.None))
{
writer(stream);
}
}
private static Stream GetResourceStream(string resourceName, int resourceSize)
{
var resourceStream = _resourceManager.Value.GetStream(resourceName, CultureInfo.CurrentUICulture);
if (resourceStream == null)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.ResourceNotFound, resourceName));
throw new FileNotFoundException(string.Format(CultureInfo.CurrentUICulture, Strings.ResourceNotFound, resourceName));
}
if ((resourceSize > 0) && (resourceStream.Length != resourceSize))
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.ResourceInvalid, resourceName));
throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, Strings.ResourceInvalid, resourceName));
}
return resourceStream;
}
public abstract void Load(string path, Action<Stream> reader);
public abstract void Save(string path, Action<Stream> writer);
private static Lazy<ResourceManager> _resourceManager = new Lazy<ResourceManager>(() => new ResourceManager("Jellyfish.Virtu.g", typeof(StorageService).Assembly) { IgnoreCase = true });
}
}

View File

@ -7,14 +7,8 @@
{
}
public abstract void SetFullScreen(bool isFullScreen);
public abstract void SetPixel(int x, int y, uint color);
public abstract void Update(); // main thread
public void ToggleFullScreen()
{
IsFullScreen ^= true;
}
public bool IsFullScreen { get; private set; }
}
}

View File

@ -92,9 +92,6 @@
<Reference Include="System.Windows.Browser" />
<Reference Include="System.Windows.Controls" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq">
<Private>True</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="MainApp.xaml">
@ -155,9 +152,6 @@
<Compile Include="..\MachineEvents.cs">
<Link>Core\MachineEvents.cs</Link>
</Compile>
<Compile Include="..\MachineSettings.cs">
<Link>Core\MachineSettings.cs</Link>
</Compile>
<Compile Include="..\Memory.cs">
<Link>Core\Memory.cs</Link>
</Compile>

View File

@ -66,20 +66,16 @@ namespace Jellyfish.Virtu
private void OnDiskButtonClick(int drive)
{
var dialog = new OpenFileDialog() { Filter = "Disk Files (*.dsk;*.nib)|*.dsk;*.nib|All Files (*.*)|*.*" };
bool? result = dialog.ShowDialog();
if (result.HasValue && result.Value)
{
using (var stream = dialog.File.OpenRead())
_machine.Pause();
var diskII = _machine.FindDiskIIController();
if (diskII != null)
{
_machine.Pause();
var diskII = _machine.FindDiskIIController();
if (diskII != null)
{
diskII.Drives[drive].InsertDisk(dialog.File.Name, stream, false);
}
_machine.Unpause();
StorageService.LoadFile(dialog.File, stream => diskII.Drives[drive].InsertDisk(dialog.File.Name, stream, false));
}
_machine.Unpause();
}
}

View File

@ -79,7 +79,6 @@
<Reference Include="System.Net" />
<Reference Include="System.Windows" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="MainApp.xaml">
@ -140,9 +139,6 @@
<Compile Include="..\..\MachineEvents.cs">
<Link>Core\MachineEvents.cs</Link>
</Compile>
<Compile Include="..\..\MachineSettings.cs">
<Link>Core\MachineSettings.cs</Link>
</Compile>
<Compile Include="..\..\Memory.cs">
<Link>Core\Memory.cs</Link>
</Compile>

View File

@ -66,16 +66,16 @@ namespace Jellyfish.Virtu
//private void OnDiskButtonClick(int drive) // TODO
//{
// var dialog = new OpenFileDialog() { Filter = "Disk Files (*.dsk;*.nib)|*.dsk;*.nib|All Files (*.*)|*.*" };
// bool? result = dialog.ShowDialog();
// if (result.HasValue && result.Value)
// {
// using (var stream = dialog.File.OpenRead())
// _machine.Pause();
// var diskII = _machine.FindDiskIIController();
// if (diskII != null)
// {
// _machine.Pause();
// _machine.DiskII.Drives[drive].InsertDisk(dialog.File.Name, stream, false);
// _machine.Unpause();
// StorageService.LoadFile(dialog.File, stream => diskII.Drives[drive].InsertDisk(dialog.File.Name, stream, false));
// }
// _machine.Unpause();
// }
//}

View File

@ -3,6 +3,7 @@ using System.Reflection;
using System.Resources;
using System.Runtime.InteropServices;
using Jellyfish.Library;
using Jellyfish.Virtu;
[assembly: AssemblyTitle("Virtu")]
[assembly: AssemblyDescription("Apple IIe Emulator")]
@ -11,9 +12,9 @@ using Jellyfish.Library;
[assembly: AssemblyCopyright("Copyright © 1995-2010 Digital Jellyfish Design Ltd")]
[assembly: AssemblyComment("Developed by Sean Fausett & Nick Westgate")]
[assembly: AssemblyVersion("0.8.3.0")]
[assembly: AssemblyFileVersion("0.8.3.0")]
[assembly: AssemblyInformationalVersion("0.8.3.0")]
[assembly: AssemblyVersion(Machine.Version)]
[assembly: AssemblyFileVersion(Machine.Version)]
[assembly: AssemblyInformationalVersion(Machine.Version)]
[assembly: CLSCompliant(false)]
[assembly: ComVisible(false)]

View File

@ -3,6 +3,7 @@ using System.Reflection;
using System.Resources;
using System.Runtime.InteropServices;
using Jellyfish.Library;
using Jellyfish.Virtu;
[assembly: AssemblyTitle("Virtu")]
[assembly: AssemblyDescription("Apple IIe Emulator")]
@ -11,9 +12,9 @@ using Jellyfish.Library;
[assembly: AssemblyCopyright("Copyright © 1995-2010 Digital Jellyfish Design Ltd")]
[assembly: AssemblyComment("Developed by Sean Fausett & Nick Westgate")]
[assembly: AssemblyVersion("0.8.3.0")]
[assembly: AssemblyFileVersion("0.8.3.0")]
[assembly: AssemblyInformationalVersion("0.8.3.0")]
[assembly: AssemblyVersion(Machine.Version)]
[assembly: AssemblyFileVersion(Machine.Version)]
[assembly: AssemblyInformationalVersion(Machine.Version)]
[assembly: CLSCompliant(false)]
[assembly: ComVisible(false)]

View File

@ -28,9 +28,9 @@ namespace Jellyfish.Virtu.Services
#endif
}
public override void SetVolume(double volume) // machine thread
public override void SetVolume(double volume)
{
_media.Dispatcher.BeginInvoke(() => _media.Volume = volume);
_media.Dispatcher.Send(() => _media.Volume = volume);
}
protected override void Dispose(bool disposing)
@ -50,7 +50,8 @@ namespace Jellyfish.Virtu.Services
// DebugService.WriteLine("OnMediaSourceUpdate");
//}
Update(bufferSize, (source, count) => Buffer.BlockCopy(source, 0, buffer, 0, count));
Buffer.BlockCopy(Source, 0, buffer, 0, bufferSize);
Update();
}
private MediaElement _media;

View File

@ -18,7 +18,7 @@ namespace Jellyfish.Virtu.Services
protected override void OnWriteLine(string message)
{
_page.Dispatcher.CheckBeginInvoke(() => _page.WriteLine(message + Environment.NewLine));
_page.Dispatcher.Post(() => _page.WriteLine(message + Environment.NewLine));
}
private MainPage _page;

View File

@ -93,17 +93,18 @@ namespace Jellyfish.Virtu.Services
}
else if (control && (e.Key == Key.Divide))
{
Machine.Cpu.ToggleThrottle();
Machine.Cpu.IsThrottled ^= true;
}
else if (control && (e.Key == Key.Multiply))
{
Machine.Video.ToggleMonochrome();
Machine.Video.IsMonochrome ^= true;
}
#if !WINDOWS_PHONE
else if (control && (e.Key == Key.Subtract))
{
Machine.Video.ToggleFullScreen();
Machine.Video.IsFullScreen ^= true;
}
#endif
Update();
}

View File

@ -3,6 +3,7 @@ using System.Diagnostics.CodeAnalysis;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using Jellyfish.Library;
#if WINDOWS_PHONE
using Microsoft.Phone.Controls;
#endif
@ -35,6 +36,24 @@ namespace Jellyfish.Virtu.Services
_page.SizeChanged += (sender, e) => SetImageSize();
}
public override void SetFullScreen(bool isFullScreen)
{
#if !WINDOWS_PHONE
_page.Dispatcher.Send(() =>
{
var application = Application.Current;
if (application.IsRunningOutOfBrowser)
{
var content = application.Host.Content;
if (content.IsFullScreen != isFullScreen)
{
content.IsFullScreen = isFullScreen;
}
}
});
#endif
}
[SuppressMessage("Microsoft.Usage", "CA2233:OperationsShouldNotOverflow")]
public override void SetPixel(int x, int y, uint color)
{
@ -44,13 +63,6 @@ namespace Jellyfish.Virtu.Services
public override void Update() // main thread
{
#if !WINDOWS_PHONE
var content = Application.Current.Host.Content;
if (Application.Current.IsRunningOutOfBrowser && (content.IsFullScreen != IsFullScreen))
{
Application.Current.RootVisual.Dispatcher.BeginInvoke(() => content.IsFullScreen = IsFullScreen); // queue to dispatcher; avoids crash!
}
#endif
if (_pixelsDirty)
{
_pixelsDirty = false;
@ -68,17 +80,17 @@ namespace Jellyfish.Virtu.Services
Math.Min((int)_page.RenderSize.Width / BitmapWidth, (int)_page.RenderSize.Height / BitmapHeight));
_image.Width = uniformScale * BitmapWidth;
_image.Height = uniformScale * BitmapHeight;
Machine.Video.DirtyScreen();
}
#if !WINDOWS_PHONE
private void SetWindowSizeToContent()
{
if (Application.Current.IsRunningOutOfBrowser && !_sizedToContent)
var application = Application.Current;
if (application.IsRunningOutOfBrowser && !_sizedToContent)
{
_sizedToContent = true;
var window = Application.Current.MainWindow;
var size = Application.Current.RootVisual.DesiredSize;
var window = application.MainWindow;
var size = application.RootVisual.DesiredSize;
window.Width = size.Width;
window.Height = size.Height;
}

View File

@ -1,4 +1,5 @@
using System;
using System.IO;
using Jellyfish.Virtu.Services;
namespace Jellyfish.Virtu
@ -15,10 +16,12 @@ namespace Jellyfish.Virtu
{
_audioService = Machine.Services.GetService<AudioService>();
UpdateSettings();
Machine.Video.VSync += (sender, e) => UpdateSettings();
Machine.Events.AddEvent(CyclesPerFlush * Machine.Settings.Cpu.Multiplier, _flushOutputEvent);
#if WINDOWS_PHONE
Volume = 0.85;
#else
Volume = 0.5;
#endif
Machine.Events.AddEvent(CyclesPerFlush * Machine.Cpu.Multiplier, _flushOutputEvent);
}
public override void Reset()
@ -28,6 +31,26 @@ namespace Jellyfish.Virtu
_highCycles = _totalCycles = 0;
}
public override void LoadState(BinaryReader reader, Version version)
{
if (reader == null)
{
throw new ArgumentNullException("reader");
}
Volume = reader.ReadDouble();
}
public override void SaveState(BinaryWriter writer)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
writer.Write(Volume);
}
public void ToggleOutput()
{
UpdateCycles();
@ -40,7 +63,7 @@ namespace Jellyfish.Virtu
_audioService.Output(_highCycles * short.MaxValue / _totalCycles); // quick and dirty decimation
_highCycles = _totalCycles = 0;
Machine.Events.AddEvent(CyclesPerFlush * Machine.Settings.Cpu.Multiplier, _flushOutputEvent);
Machine.Events.AddEvent(CyclesPerFlush * Machine.Cpu.Multiplier, _flushOutputEvent);
}
private void UpdateCycles()
@ -54,20 +77,18 @@ namespace Jellyfish.Virtu
_lastCycles = Machine.Cpu.Cycles;
}
private void UpdateSettings()
{
_audioService.SetVolume(Machine.Settings.Audio.Volume);
}
public double Volume { get { return _volume; } set { _volume = value; _audioService.SetVolume(_volume); } }
private const int CyclesPerFlush = 23;
private Action _flushOutputEvent;
private AudioService _audioService;
private bool _isHigh;
private int _highCycles;
private int _totalCycles;
private long _lastCycles;
private AudioService _audioService;
private double _volume;
}
}

View File

@ -1,9 +1,12 @@
using System;
using System.IO;
using Jellyfish.Virtu.Services;
using Jellyfish.Virtu.Settings;
namespace Jellyfish.Virtu
{
[Flags]
public enum ScannerOptions { None = 0x0, AppleII = 0x1, Pal = 0x2 } // defaults to AppleIIe, Ntsc
public sealed partial class Video : MachineComponent
{
public Video(Machine machine) :
@ -26,7 +29,29 @@ namespace Jellyfish.Virtu
_memory = Machine.Memory;
_videoService = Machine.Services.GetService<VideoService>();
UpdateSettings();
_colorBlack = 0xFF000000; // BGRA
_colorDarkBlue = 0xFF000099;
_colorDarkGreen = 0xFF117722;
_colorMediumBlue = 0xFF0000FF;
_colorBrown = 0xFF885500;
_colorLightGrey = 0xFF99AAAA;
_colorGreen = 0xFF00EE11;
_colorAquamarine = 0xFF55FFAA;
_colorDeepRed = 0xFFFF1111;
_colorPurple = 0xFFDD00DD;
_colorDarkGrey = 0xFF445555;
_colorLightBlue = 0xFF33AAFF;
_colorOrange = 0xFFFF4411;
_colorPink = 0xFFFF9988;
_colorYellow = 0xFFFFFF11;
_colorWhite = 0xFFFFFFFF;
_colorMonochrome = 0xFF00AA00;
SetPalette();
IsFullScreen = false;
IsMonochrome = false;
ScannerOptions = ScannerOptions.None;
IsVBlank = true;
Machine.Events.AddEvent(_cyclesPerVBlankPreset, _leaveVBlankEvent); // align flush events with scanner; assumes vcount preset at start of frame [3-15, 3-16]
@ -41,6 +66,71 @@ namespace Jellyfish.Virtu
FlushScreen();
}
public override void LoadState(BinaryReader reader, Version version)
{
if (reader == null)
{
throw new ArgumentNullException("reader");
}
_colorBlack = reader.ReadUInt32();
_colorDarkBlue = reader.ReadUInt32();
_colorDarkGreen = reader.ReadUInt32();
_colorMediumBlue = reader.ReadUInt32();
_colorBrown = reader.ReadUInt32();
_colorLightGrey = reader.ReadUInt32();
_colorGreen = reader.ReadUInt32();
_colorAquamarine = reader.ReadUInt32();
_colorDeepRed = reader.ReadUInt32();
_colorPurple = reader.ReadUInt32();
_colorDarkGrey = reader.ReadUInt32();
_colorLightBlue = reader.ReadUInt32();
_colorOrange = reader.ReadUInt32();
_colorPink = reader.ReadUInt32();
_colorYellow = reader.ReadUInt32();
_colorWhite = reader.ReadUInt32();
_colorMonochrome = reader.ReadUInt32();
SetPalette();
IsFullScreen = reader.ReadBoolean();
IsMonochrome = reader.ReadBoolean();
ScannerOptions = (ScannerOptions)reader.ReadInt32();
SetCharSet();
DirtyScreen();
FlushScreen();
}
public override void SaveState(BinaryWriter writer)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
writer.Write(_colorBlack);
writer.Write(_colorDarkBlue);
writer.Write(_colorDarkGreen);
writer.Write(_colorMediumBlue);
writer.Write(_colorBrown);
writer.Write(_colorLightGrey);
writer.Write(_colorGreen);
writer.Write(_colorAquamarine);
writer.Write(_colorDeepRed);
writer.Write(_colorPurple);
writer.Write(_colorDarkGrey);
writer.Write(_colorLightBlue);
writer.Write(_colorOrange);
writer.Write(_colorPink);
writer.Write(_colorYellow);
writer.Write(_colorWhite);
writer.Write(_colorMonochrome);
writer.Write(IsFullScreen);
writer.Write(IsMonochrome);
writer.Write((int)ScannerOptions);
}
public void DirtyCell(int addressOffset)
{
_isCellDirty[CellIndex[addressOffset]] = true;
@ -123,25 +213,10 @@ namespace Jellyfish.Virtu
DirtyScreenText();
}
public void ToggleFullScreen()
{
Machine.Settings.Video.IsFullScreen ^= true;
_videoService.ToggleFullScreen();
DirtyScreen();
FlushScreen();
}
public void ToggleMonochrome()
{
Machine.Settings.Video.IsMonochrome ^= true;
DirtyScreen();
FlushScreen();
}
#region Draw Methods
private void DrawText40(int data, int x, int y)
{
int color = Machine.Settings.Video.IsMonochrome ? ColorMono00 : ColorWhite00;
int color = IsMonochrome ? ColorMono00 : ColorWhite00;
int index = _charSet[data] * CharBitmapBytes;
int inverseMask = (_isTextInversed && !_memory.IsCharSetAlternate && (0x40 <= data) && (data <= 0x7F)) ? 0x7F : 0x00;
for (int i = 0; i < TextHeight; i++, y++)
@ -166,7 +241,7 @@ namespace Jellyfish.Virtu
private void DrawText80(int data, int x, int y)
{
int color = Machine.Settings.Video.IsMonochrome ? ColorMono00 : ColorWhite00;
int color = IsMonochrome ? ColorMono00 : ColorWhite00;
int index = _charSet[data] * CharBitmapBytes;
int mask = (_isTextInversed && !_memory.IsCharSetAlternate && (0x40 <= data) && (data <= 0x7F)) ? 0x7F : 0x00;
for (int i = 0; i < TextHeight; i++, y++)
@ -184,7 +259,7 @@ namespace Jellyfish.Virtu
private void DrawLores(int data, int x, int y)
{
if (Machine.Settings.Video.IsMonochrome)
if (IsMonochrome)
{
if ((x & 0x02) == 0x02) // odd cell
{
@ -268,7 +343,7 @@ namespace Jellyfish.Virtu
private void Draw7MLores(int data, int x, int y)
{
if (Machine.Settings.Video.IsMonochrome)
if (IsMonochrome)
{
if ((x & 0x02) == 0x02) // odd cell
{
@ -352,7 +427,7 @@ namespace Jellyfish.Virtu
private void DrawDLores(int data, int x, int y)
{
if (Machine.Settings.Video.IsMonochrome)
if (IsMonochrome)
{
if ((x & 0x01) == 0x00) // even half cell
{
@ -408,7 +483,7 @@ namespace Jellyfish.Virtu
private void DrawHires(int address, int x, int y)
{
if (Machine.Settings.Video.IsMonochrome)
if (IsMonochrome)
{
int data = _memory.ReadRamMainRegion02BF(address);
SetPixel(x + 0, y, data & 0x01);
@ -466,7 +541,7 @@ namespace Jellyfish.Virtu
private void DrawNDHires(int address, int x, int y)
{
if (Machine.Settings.Video.IsMonochrome)
if (IsMonochrome)
{
int data = _memory.ReadRamMainRegion02BF(address);
SetPixel(x + 0, y, data & 0x01);
@ -524,7 +599,7 @@ namespace Jellyfish.Virtu
private void DrawDHiresA(int address, int x, int y)
{
if (Machine.Settings.Video.IsMonochrome)
if (IsMonochrome)
{
if ((x & 0x2) == 0x00) // even cell
{
@ -592,7 +667,7 @@ namespace Jellyfish.Virtu
private void DrawDHiresM(int address, int x, int y)
{
if (Machine.Settings.Video.IsMonochrome)
if (IsMonochrome)
{
if ((x & 0x2) == 0x02) // odd cell
{
@ -919,64 +994,58 @@ namespace Jellyfish.Virtu
private void ResetVSyncEvent()
{
UpdateSettings();
var handler = VSync;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
Machine.Events.AddEvent(_cyclesPerVSync, _resetVSyncEvent);
}
private void SetPalette()
{
_colorPalette[ColorMono00] = _colorBlack;
_colorPalette[ColorMono01] = _colorMonochrome;
_colorPalette[ColorMono02] = _colorMonochrome;
_colorPalette[ColorMono04] = _colorMonochrome;
_colorPalette[ColorMono08] = _colorMonochrome;
_colorPalette[ColorMono10] = _colorMonochrome;
_colorPalette[ColorMono20] = _colorMonochrome;
_colorPalette[ColorMono40] = _colorMonochrome;
_colorPalette[ColorMono80] = _colorMonochrome;
_colorPalette[ColorWhite00] = _colorBlack;
_colorPalette[ColorWhite01] = _colorWhite;
_colorPalette[ColorWhite02] = _colorWhite;
_colorPalette[ColorWhite04] = _colorWhite;
_colorPalette[ColorWhite08] = _colorWhite;
_colorPalette[ColorWhite10] = _colorWhite;
_colorPalette[ColorWhite20] = _colorWhite;
_colorPalette[ColorWhite40] = _colorWhite;
_colorPalette[ColorWhite80] = _colorWhite;
_colorPalette[ColorDHires0] = _colorBlack;
_colorPalette[ColorDHires1] = _colorDarkBlue;
_colorPalette[ColorDHires2] = _colorDarkGreen;
_colorPalette[ColorDHires3] = _colorMediumBlue;
_colorPalette[ColorDHires4] = _colorBrown;
_colorPalette[ColorDHires5] = _colorLightGrey;
_colorPalette[ColorDHires6] = _colorGreen;
_colorPalette[ColorDHires7] = _colorAquamarine;
_colorPalette[ColorDHires8] = _colorDeepRed;
_colorPalette[ColorDHires9] = _colorPurple;
_colorPalette[ColorDHiresA] = _colorDarkGrey;
_colorPalette[ColorDHiresB] = _colorLightBlue;
_colorPalette[ColorDHiresC] = _colorOrange;
_colorPalette[ColorDHiresD] = _colorPink;
_colorPalette[ColorDHiresE] = _colorYellow;
_colorPalette[ColorDHiresF] = _colorWhite;
DirtyScreen();
}
private void SetPixel(int x, int y, int color)
{
_videoService.SetPixel(x, 2 * y, _colorPalette[color]);
}
private void UpdateSettings()
private void SetScanner()
{
var settings = Machine.Settings.Video;
_colorPalette[ColorMono00] = settings.Color.Black;
_colorPalette[ColorMono01] = settings.Color.Monochrome;
_colorPalette[ColorMono02] = settings.Color.Monochrome;
_colorPalette[ColorMono04] = settings.Color.Monochrome;
_colorPalette[ColorMono08] = settings.Color.Monochrome;
_colorPalette[ColorMono10] = settings.Color.Monochrome;
_colorPalette[ColorMono20] = settings.Color.Monochrome;
_colorPalette[ColorMono40] = settings.Color.Monochrome;
_colorPalette[ColorMono80] = settings.Color.Monochrome;
_colorPalette[ColorWhite00] = settings.Color.Black;
_colorPalette[ColorWhite01] = settings.Color.White;
_colorPalette[ColorWhite02] = settings.Color.White;
_colorPalette[ColorWhite04] = settings.Color.White;
_colorPalette[ColorWhite08] = settings.Color.White;
_colorPalette[ColorWhite10] = settings.Color.White;
_colorPalette[ColorWhite20] = settings.Color.White;
_colorPalette[ColorWhite40] = settings.Color.White;
_colorPalette[ColorWhite80] = settings.Color.White;
_colorPalette[ColorDHires0] = settings.Color.Black;
_colorPalette[ColorDHires1] = settings.Color.DarkBlue;
_colorPalette[ColorDHires2] = settings.Color.DarkGreen;
_colorPalette[ColorDHires3] = settings.Color.MediumBlue;
_colorPalette[ColorDHires4] = settings.Color.Brown;
_colorPalette[ColorDHires5] = settings.Color.LightGrey;
_colorPalette[ColorDHires6] = settings.Color.Green;
_colorPalette[ColorDHires7] = settings.Color.Aquamarine;
_colorPalette[ColorDHires8] = settings.Color.DeepRed;
_colorPalette[ColorDHires9] = settings.Color.Purple;
_colorPalette[ColorDHiresA] = settings.Color.DarkGrey;
_colorPalette[ColorDHiresB] = settings.Color.LightBlue;
_colorPalette[ColorDHiresC] = settings.Color.Orange;
_colorPalette[ColorDHiresD] = settings.Color.Pink;
_colorPalette[ColorDHiresE] = settings.Color.Yellow;
_colorPalette[ColorDHiresF] = settings.Color.White;
_scannerOptions = settings.ScannerOptions;
if ((_scannerOptions & ScannerOptions.Pal) != 0)
{
_vCountPreset = VCountPresetPal;
@ -992,17 +1061,31 @@ namespace Jellyfish.Virtu
_cyclesPerVBlankPreset = (_vLineLeaveVBlank - VLineTriggerPreset) * CyclesPerHSync; // cycles during vblank after vcount preset [3-15, 3-16]
_cyclesPerVSync = _vLineLeaveVBlank * CyclesPerHSync;
_cyclesPerFlash = VSyncsPerFlash * _cyclesPerVSync;
if (_videoService.IsFullScreen != settings.IsFullScreen)
{
_videoService.ToggleFullScreen();
}
}
public bool IsVBlank { get; private set; }
public long TicksPerVSync { get { return TimeSpan.FromSeconds((double)_cyclesPerVSync / CyclesPerSecond).Ticks; } }
public uint ColorBlack { get { return _colorBlack; } set { _colorBlack = value; SetPalette(); } }
public uint ColorDarkBlue { get { return _colorDarkBlue; } set { _colorDarkBlue = value; SetPalette(); } }
public uint ColorDarkGreen { get { return _colorDarkGreen; } set { _colorDarkGreen = value; SetPalette(); } }
public uint ColorMediumBlue { get { return _colorMediumBlue; } set { _colorMediumBlue = value; SetPalette(); } }
public uint ColorBrown { get { return _colorBrown; } set { _colorBrown = value; SetPalette(); } }
public uint ColorLightGrey { get { return _colorLightGrey; } set { _colorLightGrey = value; SetPalette(); } }
public uint ColorGreen { get { return _colorGreen; } set { _colorGreen = value; SetPalette(); } }
public uint ColorAquamarine { get { return _colorAquamarine; } set { _colorAquamarine = value; SetPalette(); } }
public uint ColorDeepRed { get { return _colorDeepRed; } set { _colorDeepRed = value; SetPalette(); } }
public uint ColorPurple { get { return _colorPurple; } set { _colorPurple = value; SetPalette(); } }
public uint ColorDarkGrey { get { return _colorDarkGrey; } set { _colorDarkGrey = value; SetPalette(); } }
public uint ColorLightBlue { get { return _colorLightBlue; } set { _colorLightBlue = value; SetPalette(); } }
public uint ColorOrange { get { return _colorOrange; } set { _colorOrange = value; SetPalette(); } }
public uint ColorPink { get { return _colorPink; } set { _colorPink = value; SetPalette(); } }
public uint ColorYellow { get { return _colorYellow; } set { _colorYellow = value; SetPalette(); } }
public uint ColorWhite { get { return _colorWhite; } set { _colorWhite = value; SetPalette(); } }
public uint ColorMonochrome { get { return _colorMonochrome; } set { _colorMonochrome = value; SetPalette(); } }
public event EventHandler VSync;
public bool IsFullScreen { get { return _isFullScreen; } set { _isFullScreen = value; _videoService.SetFullScreen(_isFullScreen); } }
public bool IsMonochrome { get { return _isMonochrome; } set { _isMonochrome = value; DirtyScreen(); } }
public ScannerOptions ScannerOptions { get { return _scannerOptions; } set { _scannerOptions = value; SetScanner(); } }
public bool IsVBlank { get; private set; }
private Action _flushRowEvent;
private Action _inverseTextEvent;
@ -1012,16 +1095,36 @@ namespace Jellyfish.Virtu
private Memory _memory;
private VideoService _videoService;
private ushort[] _charSet;
private uint[] _colorPalette = new uint[ColorPaletteCount];
private bool[] _isCellDirty = new bool[Height * CellColumns + 1]; // includes sentinel
private uint _colorBlack;
private uint _colorDarkBlue;
private uint _colorDarkGreen;
private uint _colorMediumBlue;
private uint _colorBrown;
private uint _colorLightGrey;
private uint _colorGreen;
private uint _colorAquamarine;
private uint _colorDeepRed;
private uint _colorPurple;
private uint _colorDarkGrey;
private uint _colorLightBlue;
private uint _colorOrange;
private uint _colorPink;
private uint _colorYellow;
private uint _colorWhite;
private uint _colorMonochrome;
private bool _isFullScreen;
private bool _isMonochrome;
private bool _isTextInversed;
private ScannerOptions _scannerOptions;
private int _cyclesPerVBlank;
private int _cyclesPerVBlankPreset;
private int _cyclesPerVSync;
private int _cyclesPerFlash;
private int _vCountPreset;
private int _vLineLeaveVBlank;
private ScannerOptions _scannerOptions;
private ushort[] _charSet;
private uint[] _colorPalette = new uint[ColorPaletteCount];
private bool[] _isCellDirty = new bool[Height * CellColumns + 1]; // includes sentinel
}
}

View File

@ -74,7 +74,6 @@
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
@ -145,9 +144,6 @@
<Compile Include="..\MachineEvents.cs">
<Link>Core\MachineEvents.cs</Link>
</Compile>
<Compile Include="..\MachineSettings.cs">
<Link>Core\MachineSettings.cs</Link>
</Compile>
<Compile Include="..\Memory.cs">
<Link>Core\Memory.cs</Link>
</Compile>

View File

@ -68,29 +68,16 @@ namespace Jellyfish.Virtu
private void OnDiskButtonClick(int drive)
{
var dialog = new OpenFileDialog() { Filter = "Disk Files (*.dsk;*.nib)|*.dsk;*.nib|All Files (*.*)|*.*" };
bool? result = dialog.ShowDialog();
if (result.HasValue && result.Value)
{
using (var stream = File.OpenRead(dialog.FileName))
_machine.Pause();
var diskII = _machine.FindDiskIIController();
if (diskII != null)
{
_machine.Pause();
var diskII = _machine.FindDiskIIController();
if (diskII != null)
{
diskII.Drives[drive].InsertDisk(dialog.FileName, stream, false);
var settings = _machine.Settings.DiskII;
if (drive == 0)
{
settings.Disk1.Name = dialog.FileName;
}
else
{
settings.Disk2.Name = dialog.FileName;
}
}
_machine.Unpause();
StorageService.LoadFile(dialog.FileName, stream => diskII.Drives[drive].InsertDisk(dialog.FileName, stream, false));
}
_machine.Unpause();
}
}

View File

@ -4,6 +4,7 @@ using System.Resources;
using System.Runtime.InteropServices;
using System.Windows;
using Jellyfish.Library;
using Jellyfish.Virtu;
[assembly: AssemblyTitle("Virtu")]
[assembly: AssemblyDescription("Apple IIe Emulator")]
@ -12,9 +13,9 @@ using Jellyfish.Library;
[assembly: AssemblyCopyright("Copyright © 1995-2010 Digital Jellyfish Design Ltd")]
[assembly: AssemblyComment("Developed by Sean Fausett & Nick Westgate")]
[assembly: AssemblyVersion("0.8.3.0")]
[assembly: AssemblyFileVersion("0.8.3.0")]
[assembly: AssemblyInformationalVersion("0.8.3.0")]
[assembly: AssemblyVersion(Machine.Version)]
[assembly: AssemblyFileVersion(Machine.Version)]
[assembly: AssemblyInformationalVersion(Machine.Version)]
[assembly: CLSCompliant(false)]
[assembly: ComVisible(false)]

View File

@ -28,7 +28,7 @@ namespace Jellyfish.Virtu.Services
};
}
public override void SetVolume(double volume) // machine thread
public override void SetVolume(double volume)
{
_directSound.SetVolume(volume);
}
@ -50,7 +50,8 @@ namespace Jellyfish.Virtu.Services
// DebugService.WriteLine("OnDirectSoundUpdate");
//}
Update(bufferSize, (source, count) => Marshal.Copy(source, 0, buffer, count));
Marshal.Copy(Source, 0, buffer, bufferSize);
Update();
}
private DirectSound _directSound;

View File

@ -18,7 +18,7 @@ namespace Jellyfish.Virtu.Services
protected override void OnWriteLine(string message)
{
_page.Dispatcher.CheckInvoke(() => _page.WriteLine(message + Environment.NewLine));
_page.Dispatcher.Post(() => _page.WriteLine(message + Environment.NewLine));
}
private MainPage _page;

View File

@ -88,15 +88,15 @@ namespace Jellyfish.Virtu.Services
if (control && (e.Key == Key.Divide))
{
Machine.Cpu.ToggleThrottle();
Machine.Cpu.IsThrottled ^= true;
}
else if (control && (e.Key == Key.Multiply))
{
Machine.Video.ToggleMonochrome();
Machine.Video.IsMonochrome ^= true;
}
else if (control && (e.Key == Key.Subtract))
{
Machine.Video.ToggleFullScreen();
Machine.Video.IsFullScreen ^= true;
}
Update();

View File

@ -4,6 +4,7 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Jellyfish.Library;
namespace Jellyfish.Virtu.Services
{
@ -29,6 +30,30 @@ namespace Jellyfish.Virtu.Services
_page.SizeChanged += (sender, e) => SetImageSize();
}
public override void SetFullScreen(bool isFullScreen)
{
if (_isFullScreen != isFullScreen)
{
_isFullScreen = isFullScreen;
_page.Dispatcher.Send(() =>
{
var window = Window.GetWindow(_page);
if (_isFullScreen)
{
window.ResizeMode = ResizeMode.NoResize;
window.WindowStyle = WindowStyle.None;
window.WindowState = WindowState.Maximized;
}
else
{
window.WindowState = WindowState.Normal;
window.WindowStyle = WindowStyle.SingleBorderWindow;
window.ResizeMode = ResizeMode.CanResize;
}
});
}
}
[SuppressMessage("Microsoft.Usage", "CA2233:OperationsShouldNotOverflow")]
public override void SetPixel(int x, int y, uint color)
{
@ -38,24 +63,6 @@ namespace Jellyfish.Virtu.Services
public override void Update() // main thread
{
if (_isFullScreen != IsFullScreen)
{
var window = Window.GetWindow(_page);
if (IsFullScreen)
{
window.ResizeMode = ResizeMode.NoResize;
window.WindowStyle = WindowStyle.None;
window.WindowState = WindowState.Maximized;
}
else
{
window.WindowState = WindowState.Normal;
window.WindowStyle = WindowStyle.SingleBorderWindow;
window.ResizeMode = ResizeMode.CanResize;
}
_isFullScreen = IsFullScreen;
}
if (_pixelsDirty)
{
_pixelsDirty = false;
@ -68,7 +75,6 @@ namespace Jellyfish.Virtu.Services
int uniformScale = Math.Max(1, Math.Min((int)_page.RenderSize.Width / BitmapWidth, (int)_page.RenderSize.Height / BitmapHeight));
_image.Width = uniformScale * BitmapWidth;
_image.Height = uniformScale * BitmapHeight;
Machine.Video.DirtyScreen();
}
private void SetWindowSizeToContent()

View File

@ -102,9 +102,6 @@
<Reference Include="System.Xml">
<Private>False</Private>
</Reference>
<Reference Include="System.Xml.Linq">
<Private>False</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\Cassette.cs">
@ -149,9 +146,6 @@
<Compile Include="..\MachineEvents.cs">
<Link>Core\MachineEvents.cs</Link>
</Compile>
<Compile Include="..\MachineSettings.cs">
<Link>Core\MachineSettings.cs</Link>
</Compile>
<Compile Include="..\Memory.cs">
<Link>Core\Memory.cs</Link>
</Compile>

View File

@ -108,9 +108,6 @@
<Reference Include="System.Xml">
<Private>False</Private>
</Reference>
<Reference Include="System.Xml.Linq">
<Private>False</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\Cassette.cs">
@ -155,9 +152,6 @@
<Compile Include="..\MachineEvents.cs">
<Link>Core\MachineEvents.cs</Link>
</Compile>
<Compile Include="..\MachineSettings.cs">
<Link>Core\MachineSettings.cs</Link>
</Compile>
<Compile Include="..\Memory.cs">
<Link>Core\Memory.cs</Link>
</Compile>

View File

@ -112,9 +112,6 @@
<Reference Include="System.Xml">
<Private>False</Private>
</Reference>
<Reference Include="System.Xml.Linq">
<Private>False</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\Cassette.cs">
@ -159,9 +156,6 @@
<Compile Include="..\MachineEvents.cs">
<Link>Core\MachineEvents.cs</Link>
</Compile>
<Compile Include="..\MachineSettings.cs">
<Link>Core\MachineSettings.cs</Link>
</Compile>
<Compile Include="..\Memory.cs">
<Link>Core\Memory.cs</Link>
</Compile>

View File

@ -3,6 +3,7 @@ using System.Reflection;
using System.Resources;
using System.Runtime.InteropServices;
using Jellyfish.Library;
using Jellyfish.Virtu;
[assembly: AssemblyTitle("Virtu")]
[assembly: AssemblyDescription("Apple IIe Emulator")]
@ -17,9 +18,9 @@ using Jellyfish.Library;
[assembly: AssemblyCopyright("Copyright © 1995-2010 Digital Jellyfish Design Ltd")]
[assembly: AssemblyComment("Developed by Sean Fausett & Nick Westgate")]
[assembly: AssemblyVersion("0.8.3.0")]
[assembly: AssemblyFileVersion("0.8.3.0")]
[assembly: AssemblyInformationalVersion("0.8.3.0")]
[assembly: AssemblyVersion(Machine.Version)]
[assembly: AssemblyFileVersion(Machine.Version)]
[assembly: AssemblyInformationalVersion(Machine.Version)]
[assembly: CLSCompliant(false)]
[assembly: ComVisible(false)]

View File

@ -23,7 +23,7 @@ namespace Jellyfish.Virtu.Services
_dynamicSoundEffect.Play();
}
public override void SetVolume(double volume) // machine thread
public override void SetVolume(double volume)
{
_dynamicSoundEffect.Volume = (float)volume;
}
@ -45,7 +45,8 @@ namespace Jellyfish.Virtu.Services
// DebugService.WriteLine("OnDynamicSoundEffectBufferNeeded");
//}
Update(SampleSize, (source, count) => _dynamicSoundEffect.SubmitBuffer(source, 0, count));
_dynamicSoundEffect.SubmitBuffer(Source, 0, SampleSize);
Update();
}
private GameBase _game;

View File

@ -20,14 +20,22 @@ namespace Jellyfish.Virtu.Services
var left = _state.ThumbSticks.Left;
var right = _state.ThumbSticks.Right;
var dpad = _state.DPad;
float joystickDeadZone = (float)Machine.GamePort.JoystickDeadZone;
Paddle0 = (int)((1 + left.X) * PaddleScale);
Paddle1 = (int)((1 - left.Y) * PaddleScale); // invert y
Paddle2 = (int)((1 + right.X) * PaddleScale);
Paddle3 = (int)((1 - right.Y) * PaddleScale); // invert y
Joystick0 = GetJoystick(ref left, ref dpad);
Joystick1 = GetJoystick(ref right);
IsJoystick0Up = ((left.Y > joystickDeadZone) || (dpad.Up == ButtonState.Pressed));
IsJoystick0Left = ((left.X < -joystickDeadZone) || (dpad.Left == ButtonState.Pressed));
IsJoystick0Right = ((left.X > joystickDeadZone) || (dpad.Right == ButtonState.Pressed));
IsJoystick0Down = ((left.Y < -joystickDeadZone) || (dpad.Down == ButtonState.Pressed));
IsJoystick1Up = (right.Y > joystickDeadZone);
IsJoystick1Left = (right.X < -joystickDeadZone);
IsJoystick1Right = (right.X > joystickDeadZone);
IsJoystick1Down = (right.Y < -joystickDeadZone);
IsButton0Down = ((_state.Buttons.A == ButtonState.Pressed) || (_state.Buttons.LeftShoulder == ButtonState.Pressed));
IsButton1Down = ((_state.Buttons.B == ButtonState.Pressed) || (_state.Buttons.RightShoulder == ButtonState.Pressed));
@ -35,28 +43,7 @@ namespace Jellyfish.Virtu.Services
}
}
private static Joystick GetJoystick(ref Vector2 thumbstick)
{
bool isUp = (thumbstick.Y > JoystickDeadZone);
bool isLeft = (thumbstick.X < -JoystickDeadZone);
bool isRight = (thumbstick.X > JoystickDeadZone);
bool isDown = (thumbstick.Y < -JoystickDeadZone);
return new Joystick(isUp, isLeft, isRight, isDown);
}
private static Joystick GetJoystick(ref Vector2 thumbstick, ref GamePadDPad dpad)
{
bool isUp = ((thumbstick.Y > JoystickDeadZone) || (dpad.Up == ButtonState.Pressed));
bool isLeft = ((thumbstick.X < -JoystickDeadZone) || (dpad.Left == ButtonState.Pressed));
bool isRight = ((thumbstick.X > JoystickDeadZone) || (dpad.Right == ButtonState.Pressed));
bool isDown = ((thumbstick.Y < -JoystickDeadZone) || (dpad.Down == ButtonState.Pressed));
return new Joystick(isUp, isLeft, isRight, isDown);
}
private const int PaddleScale = 128;
private const float JoystickDeadZone = 0.5f;
private GamePadState _state;
private GamePadState _lastState;

View File

@ -105,16 +105,16 @@ namespace Jellyfish.Virtu.Services
}
else if ((control && (key == Keys.Divide)) || (gamePadControl && (key == Keys.D8)))
{
Machine.Cpu.ToggleThrottle();
Machine.Cpu.IsThrottled ^= true;
}
else if ((control && (key == Keys.Multiply)) || (gamePadControl && (key == Keys.D9)))
{
Machine.Video.ToggleMonochrome();
Machine.Video.IsMonochrome ^= true;
}
#if WINDOWS
else if ((control && (key == Keys.Subtract)) || (gamePadControl && (key == Keys.D0)))
{
Machine.Video.ToggleFullScreen();
Machine.Video.IsFullScreen ^= true;
}
#endif
}

View File

@ -18,7 +18,7 @@ namespace Jellyfish.Virtu.Services
_game = game;
}
public override void Load(string path, Action<Stream> reader)
public override void Load(string fileName, Action<Stream> reader)
{
if (reader == null)
{
@ -29,7 +29,7 @@ namespace Jellyfish.Virtu.Services
{
using (var storageContainer = OpenContainer())
{
using (var stream = storageContainer.OpenFile(path, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var stream = storageContainer.OpenFile(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
reader(stream);
}
@ -40,7 +40,7 @@ namespace Jellyfish.Virtu.Services
}
}
public override void Save(string path, Action<Stream> writer)
public override void Save(string fileName, Action<Stream> writer)
{
if (writer == null)
{
@ -49,7 +49,7 @@ namespace Jellyfish.Virtu.Services
using (var storageContainer = OpenContainer())
{
using (var stream = storageContainer.OpenFile(path, FileMode.Create, FileAccess.Write, FileShare.None))
using (var stream = storageContainer.OpenFile(fileName, FileMode.Create, FileAccess.Write, FileShare.None))
{
writer(stream);
}

View File

@ -26,6 +26,18 @@ namespace Jellyfish.Virtu.Services
_game.GraphicsDeviceService.DeviceReset += (sender, e) => SetTexturePosition();
}
public override void SetFullScreen(bool isFullScreen)
{
#if WINDOWS
var graphicsDeviceManager = _game.GraphicsDeviceManager;
if (graphicsDeviceManager.IsFullScreen != isFullScreen)
{
graphicsDeviceManager.IsFullScreen = isFullScreen;
_game.SynchronizationContext.Send(state => graphicsDeviceManager.ApplyChanges(), null);
}
#endif
}
[SuppressMessage("Microsoft.Usage", "CA2233:OperationsShouldNotOverflow")]
public override void SetPixel(int x, int y, uint color)
{
@ -35,12 +47,6 @@ namespace Jellyfish.Virtu.Services
public override void Update() // main thread
{
#if WINDOWS
if (_game.GraphicsDeviceManager.IsFullScreen != IsFullScreen)
{
_game.GraphicsDeviceManager.ToggleFullScreen();
}
#endif
if (_pixelsDirty)
{
_pixelsDirty = false;