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 @@ public static void CheckBeginInvoke(this Dispatcher dispatcher, Action action)
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 @@ public static void CheckInvoke(this Dispatcher dispatcher, Action action)
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 @@
[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 @@
[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 @@
[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 @@ public GameBase(string name)
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 @@ protected override void Update(GameTime gameTime)
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 @@
[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 @@ public Cpu(Machine machine) :
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 @@ public override void Reset()
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 @@ public int Execute()
return CC;
}
public void ToggleThrottle()
{
Machine.Settings.Cpu.IsThrottled ^= true;
}
#region Core Operand Actions
private void GetAddressAbs() // abs
{
@ -740,7 +775,7 @@ private void ExecuteIrq(int cc)
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 @@ private void ExecuteNmi(int cc)
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 @@ private void Execute65C02Tsb0C() // tsb abs
}
#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 @@ private void UpdateSettings()
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 @@ public static Disk525 CreateDisk(string name, byte[] data, bool isWriteProtected
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 @@ public DiskIIController(Machine machine) :
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 @@ public override void Reset()
_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 @@ public DiskIIDrive()
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 @@ public override void Initialize()
{
_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 @@ public void TriggerTimers()
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 @@ private void ResetPaddle3StrobeEvent()
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 @@ public override void Initialize()
_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 @@ public int ReadLatch()
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 @@ public void ResetStrobe()
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 @@ public Machine()
{
Events = new MachineEvents();
Services = new MachineServices();
Settings = new MachineSettings();
Cpu = new Cpu(this);
Memory = new Memory(this);
@ -36,7 +37,7 @@ public Machine()
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 @@ public void Dispose()
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 @@ public void Stop()
Thread.Join();
}
State = MachineState.Stopped;
if (_storageService != null)
{
_storageService.Save(MachineSettings.FileName, stream => Settings.Serialize(stream));
}
}
public DiskIIController FindDiskIIController()
@ -104,10 +97,59 @@ public DiskIIController FindDiskIIController()
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 @@ private void Run() // machine thread
}
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 @@ private void Run() // machine thread
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 Reset()
{
}
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 @@ public MachineEvent(int delta, Action action)
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 @@ public Memory(Machine machine) :
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 @@ public override void Initialize()
_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 @@ public override void Reset() // [7-3]
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 @@ private void MapRegionC0CF()
_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 @@ private void MapRegionD0FF()
{
_regionWrite[RegionD0DF] = null;
_regionWrite[RegionE0FF] = null;
_writeRegion[RegionD0DF] = WriteRomRegionD0FF;
_writeRegion[RegionE0FF] = WriteRomRegionD0FF;
_writeRegion[RegionD0DF] = _writeRomRegionD0FF;
_writeRegion[RegionE0FF] = _writeRomRegionD0FF;
}
}
@ -1533,6 +1590,12 @@ private bool TestState(int mask, int value)
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 @@ public sealed class NoSlotClock : MachineComponent
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 @@ public void Write(int address)
}
}
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 @@ private int ReadClock(int data)
data = _clockRegister.ReadBit(Machine.Video.ReadFloatingBus());
if (_clockRegister.NextBit())
{
_clockRegisterEnabled = false;
_clockEnabled = false;
}
return data;
}
@ -70,13 +97,13 @@ private void WriteClock(int address)
return;
}
if (!_clockRegisterEnabled)
if (!_clockEnabled)
{
if ((_comparisonRegister.CompareBit(address)))
{
if (_comparisonRegister.NextBit())
{
_clockRegisterEnabled = true;
_clockEnabled = true;
PopulateClockRegister();
}
}
@ -89,7 +116,7 @@ private void WriteClock(int address)
else if (_clockRegister.NextBit())
{
// simulate writes, but our clock register is read-only
_clockRegisterEnabled = false;
_clockEnabled = false;
}
}
@ -133,18 +160,17 @@ private void PopulateClockRegister()
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 @@ public void WriteBits(int data, int count)
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 @@ public bool NextBit()
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 @@ public void Output(int data) // machine thread
_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 @@ public void Reset()
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 @@ protected void Update(int bufferSize, Action<byte[], int> updateBuffer) // audio
[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 virtual void Update() { } // main thread
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 @@ public IsolatedStorageService(Machine machine) :
{
}
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 @@ public override void Load(string path, Action<Stream> reader)
{
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 @@ public override void Load(string path, Action<Stream> reader)
}
}
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 @@ public override void Save(string path, Action<Stream> writer)
{
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 @@ public void AddService(Type serviceType, MachineService serviceProvider)
}
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 @@ public void AddService(Type serviceType, MachineService serviceProvider)
}
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 @@ protected StorageService(Machine machine) :
{
}
[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 @@ protected VideoService(Machine machine) :
{
}
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 @@ private void OnCompositionTargetRendering(object sender, EventArgs e)
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 @@ private void OnCompositionTargetRendering(object sender, EventArgs e)
//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.Resources;
using System.Runtime.InteropServices;
using Jellyfish.Library;
using Jellyfish.Virtu;
[assembly: AssemblyTitle("Virtu")]
[assembly: AssemblyDescription("Apple IIe Emulator")]
@ -11,9 +12,9 @@
[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.Resources;
using System.Runtime.InteropServices;
using Jellyfish.Library;
using Jellyfish.Virtu;
[assembly: AssemblyTitle("Virtu")]
[assembly: AssemblyDescription("Apple IIe Emulator")]
@ -11,9 +12,9 @@
[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 @@ public SilverlightAudioService(Machine machine, UserControl page, MediaElement m
#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 @@ private void OnMediaSourceUpdate(byte[] buffer, int bufferSize) // audio thread
// 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 @@ public SilverlightDebugService(Machine machine, MainPage page) :
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 @@ private void OnPageKeyUp(object sender, KeyEventArgs e)
}
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.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 @@ public SilverlightVideoService(Machine machine, UserControl page, Image image) :
_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 @@ public override void SetPixel(int x, int y, uint color)
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 @@ private void SetImageSize(bool swapOrientation = false)
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 @@ public override void Initialize()
{
_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 @@ public override void Reset()
_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 @@ private void FlushOutputEvent()
_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 @@ private void UpdateCycles()
_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 @@ public override void Initialize()
_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 @@ public override void Reset()
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 @@ public void SetCharSet()
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 @@ private void DrawText40(int data, int x, int y)
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 @@ private void DrawText80(int data, int x, int y)
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 @@ private void DrawLores(int data, int x, int y)
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 @@ private void Draw7MLores(int data, int x, int y)
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 @@ private void DrawDLores(int data, int x, int y)
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 @@ private void DrawHires(int address, int x, int y)
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 @@ private void DrawNDHires(int address, int x, int y)
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 @@ private void DrawDHiresA(int address, int x, int y)
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 @@ private void LeaveVBlankEvent()
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 @@ private void UpdateSettings()
_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 @@ private void UpdateSettings()
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 @@ private void OnCompositionTargetRendering(object sender, EventArgs e)
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.Runtime.InteropServices;
using System.Windows;
using Jellyfish.Library;
using Jellyfish.Virtu;
[assembly: AssemblyTitle("Virtu")]
[assembly: AssemblyDescription("Apple IIe Emulator")]
@ -12,9 +13,9 @@
[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 @@ public WpfAudioService(Machine machine, UserControl page) :
};
}
public override void SetVolume(double volume) // machine thread
public override void SetVolume(double volume)
{
_directSound.SetVolume(volume);
}
@ -50,7 +50,8 @@ private void OnDirectSoundUpdate(IntPtr buffer, int bufferSize) // audio thread
// 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 @@ public WpfDebugService(Machine machine, MainPage page) :
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 @@ private void OnPageKeyUp(object sender, KeyEventArgs e)
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.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Jellyfish.Library;
namespace Jellyfish.Virtu.Services
{
@ -29,6 +30,30 @@ public WpfVideoService(Machine machine, UserControl page, Image image) :
_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 @@ public override void SetPixel(int x, int y, uint color)
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 @@ private void SetImageSize()
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.Resources;
using System.Runtime.InteropServices;
using Jellyfish.Library;
using Jellyfish.Virtu;
[assembly: AssemblyTitle("Virtu")]
[assembly: AssemblyDescription("Apple IIe Emulator")]
@ -17,9 +18,9 @@
[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 @@ public XnaAudioService(Machine machine, GameBase game) :
_dynamicSoundEffect.Play();
}
public override void SetVolume(double volume) // machine thread
public override void SetVolume(double volume)
{
_dynamicSoundEffect.Volume = (float)volume;
}
@ -45,7 +45,8 @@ private void OnDynamicSoundEffectBufferNeeded(object sender, EventArgs e) // aud
// 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 @@ public override void Update() // main thread
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 @@ public override void Update() // main thread
}
}
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 @@ private void OnKeyUp(Keys key, bool gamePadControl)
}
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 @@ public XnaStorageService(Machine machine, GameBase game) :
_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 @@ public override void Load(string path, Action<Stream> reader)
{
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 @@ public override void Load(string path, Action<Stream> reader)
}
}
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 @@ public override void Save(string path, Action<Stream> writer)
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 @@ public XnaVideoService(Machine machine, GameBase game) :
_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 @@ public override void SetPixel(int x, int y, uint color)
public override void Update() // main thread
{
#if WINDOWS
if (_game.GraphicsDeviceManager.IsFullScreen != IsFullScreen)
{
_game.GraphicsDeviceManager.ToggleFullScreen();
}
#endif
if (_pixelsDirty)
{
_pixelsDirty = false;