diff --git a/.github/workflows/make.yml b/.github/workflows/make.yml index d97f56737f6..0d8ee890a28 100644 --- a/.github/workflows/make.yml +++ b/.github/workflows/make.yml @@ -60,6 +60,7 @@ jobs: git submodule update --init gpgx/Genesis-Plus-GX; git submodule update --init ../submodules/sameboy/libsameboy; git submodule update --init uae/libretro-uae; + git submodule update --init stella/core; - name: Download compiled waterbox uses: actions/download-artifact@v4 with: @@ -100,6 +101,7 @@ jobs: Assets/dll/turbo.wbx.zst Assets/dll/uzem.wbx.zst Assets/dll/vb.wbx.zst + Assets/dll/stella.wbx.zst Assets/dll/virtualjaguar.wbx.zst build-mame: diff --git a/.gitmodules b/.gitmodules index c83cab73849..94dba5e69cf 100644 --- a/.gitmodules +++ b/.gitmodules @@ -74,6 +74,10 @@ path = waterbox/gpgx/Genesis-Plus-GX url = https://github.com/TASEmulators/Genesis-Plus-GX.git branch = tasvideos-2.2 +[submodule "waterbox/stella/core"] + path = waterbox/stella/core + url = https://github.com/TASEmulators/stella.git + branch = tasvideos-1 [submodule "waterbox/uae/libretro-uae"] path = waterbox/uae/libretro-uae url = https://github.com/TASEmulators/libretro-uae.git diff --git a/Assets/dll/stella.wbx.zst b/Assets/dll/stella.wbx.zst new file mode 100644 index 00000000000..f7654360177 Binary files /dev/null and b/Assets/dll/stella.wbx.zst differ diff --git a/src/BizHawk.Client.Common/config/Config.cs b/src/BizHawk.Client.Common/config/Config.cs index c0daeb3b1b3..66577fc48ac 100644 --- a/src/BizHawk.Client.Common/config/Config.cs +++ b/src/BizHawk.Client.Common/config/Config.cs @@ -25,6 +25,8 @@ public class Config /// public static readonly IReadOnlyList<(string[] AppliesTo, string[] CoreNames)> CorePickerUIData = new List<(string[], string[])> { + ([ VSystemID.Raw.A26 ], + [ CoreNames.Stella, CoreNames.Atari2600Hawk ]), ([ VSystemID.Raw.Satellaview ], [ CoreNames.Bsnes115, CoreNames.SubBsnes115 ]), ([ VSystemID.Raw.GB, VSystemID.Raw.GBC ], @@ -49,6 +51,7 @@ public class Config [ CoreNames.Snes9X, CoreNames.Bsnes115, CoreNames.SubBsnes115, CoreNames.Faust, CoreNames.Bsnes ]), ([ VSystemID.Raw.TI83 ], [ CoreNames.Emu83, CoreNames.TI83Hawk ]), + }; public static Dictionary GenDefaultCorePreferences() diff --git a/src/BizHawk.Emulation.Common/Enums.cs b/src/BizHawk.Emulation.Common/Enums.cs index 2319010244f..0d86005d2d6 100644 --- a/src/BizHawk.Emulation.Common/Enums.cs +++ b/src/BizHawk.Emulation.Common/Enums.cs @@ -7,7 +7,8 @@ public enum DisplayType { NTSC, PAL, - Dendy + Dendy, + SECAM } /// diff --git a/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/LibStella.cs b/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/LibStella.cs new file mode 100644 index 00000000000..5565ac83600 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/LibStella.cs @@ -0,0 +1,80 @@ +using System.Runtime.InteropServices; + +using BizHawk.BizInvoke; + +namespace BizHawk.Emulation.Cores.Consoles.Atari.Stella +{ + public abstract class CInterface + { + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate int load_archive_cb(string filename, IntPtr buffer, int maxsize); + + [StructLayout(LayoutKind.Sequential)] + public class InitSettings + { + public uint dummy; + } + + [BizImport(CallingConvention.Cdecl)] + public abstract void stella_get_audio(ref int n, ref IntPtr buffer); + + [BizImport(CallingConvention.Cdecl)] + public abstract int stella_get_region(); + + [BizImport(CallingConvention.Cdecl)] + public abstract bool stella_init( + string fileName, + load_archive_cb feload_archive_cb, + [In]InitSettings settings); + + [BizImport(CallingConvention.Cdecl)] + public abstract void stella_frame_advance(int port1, int port2, bool reset, bool power, bool leftDiffToggled, bool rightDiffToggled); + + [BizImport(CallingConvention.Cdecl)] + public abstract void stella_get_video(out int w, out int h, out int pitch, ref IntPtr buffer); + + [BizImport(CallingConvention.Cdecl)] + public abstract void stella_get_frame_rate(out int fps); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void input_cb(); + + [BizImport(CallingConvention.Cdecl)] + public abstract void stella_set_input_callback(input_cb cb); + + [BizImport(CallingConvention.Cdecl)] + public abstract byte stella_peek_tia(uint addr); + + [BizImport(CallingConvention.Cdecl)] + public abstract void stella_poke_tia(uint addr, byte value); + + [BizImport(CallingConvention.Cdecl)] + public abstract byte stella_peek_m6532(uint addr); + + [BizImport(CallingConvention.Cdecl)] + public abstract void stella_poke_m6532(uint addr, byte value); + + [BizImport(CallingConvention.Cdecl)] + public abstract byte stella_peek_systembus(uint addr); + + [BizImport(CallingConvention.Cdecl)] + public abstract void stella_poke_systembus(uint addr, byte value); + + [BizImport(CallingConvention.Cdecl)] + public abstract uint stella_get_cartram_size(); + + [BizImport(CallingConvention.Cdecl)] + public abstract byte stella_peek_cartram(uint addr); + + [BizImport(CallingConvention.Cdecl)] + public abstract void stella_poke_cartram(uint addr, byte value); + + [BizImport(CallingConvention.Cdecl)] + public abstract void stella_get_mainram_ptr(ref IntPtr addr); + + [BizImport(CallingConvention.Cdecl)] + public abstract IntPtr stella_get_cart_type(); + + } +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.Core.cs b/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.Core.cs new file mode 100644 index 00000000000..85d8f36362b --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.Core.cs @@ -0,0 +1,99 @@ +using BizHawk.Emulation.Cores.Components.M6502; +using System.Runtime.CompilerServices; + +namespace BizHawk.Emulation.Cores.Atari.Stella +{ + public partial class Stella + { + internal struct CpuLink : IMOS6502XLink + { + public byte DummyReadMemory(ushort address) { return 0; } + + public void OnExecFetch(ushort address) { } + + public byte PeekMemory(ushort address) { return 0; } + + public byte ReadMemory(ushort address) { return 0; } + + public void WriteMemory(ushort address, byte value) { } + } + + internal byte BaseReadMemory(ushort addr) + { + return 0; + } + + internal byte BasePeekMemory(ushort addr) + { + + return 0; + } + + internal void BaseWriteMemory(ushort addr, byte value) + { + } + + internal void BasePokeMemory(ushort addr, byte value) + { + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private byte ReadMemory(ushort addr) + { + return 0; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void WriteMemory(ushort addr, byte value) + { + } + + internal void PokeMemory(ushort addr, byte value) + { + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ExecFetch(ushort addr) + { + } + + private void RebootCore() + { + } + + private void HardReset() + { + } + + private void Cycle() + { + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal byte ReadControls1(bool peek) + { + return 0; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal byte ReadControls2(bool peek) + { + return 0; + } + + internal int ReadPot1(int pot) + { + return 0; + } + + internal int ReadPot2(int pot) + { + return 0; + } + + internal byte ReadConsoleSwitches(bool peek) + { + return 0; + } + } +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.IEmulator.cs b/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.IEmulator.cs new file mode 100644 index 00000000000..31c40c9c5f8 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.IEmulator.cs @@ -0,0 +1,65 @@ +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Atari.Stella +{ + public partial class Stella : IEmulator + { + public IEmulatorServiceProvider ServiceProvider { get; } + + public ControllerDefinition ControllerDefinition => _controllerDeck.Definition; + + private bool _leftDifficultyToggled = false; + private bool _rightDifficultyToggled = false; + + public bool FrameAdvance(IController controller, bool render, bool renderSound) + { + + int port1 = _controllerDeck.ReadPort1(controller); + int port2 = _controllerDeck.ReadPort2(controller); + + // Handle all the console controls here + bool powerPressed = false; + bool resetPressed = false; + if (controller.IsPressed("Power")) powerPressed = true; + if (controller.IsPressed("Reset")) resetPressed = true; + if (controller.IsPressed("Toggle Left Difficulty")) _leftDifficultyToggled = !_leftDifficultyToggled; + if (controller.IsPressed("Toggle Right Difficulty")) _rightDifficultyToggled = !_rightDifficultyToggled; + + IsLagFrame = true; + + Core.stella_frame_advance(port1, port2, resetPressed, powerPressed, _leftDifficultyToggled, _rightDifficultyToggled); + + if (IsLagFrame) + LagCount++; + + if (render) + UpdateVideo(); + + if (renderSound) + update_audio(); + + _frame++; + + return true; + } + + public int _frame; + + public int Frame => _frame; + + public string SystemId => VSystemID.Raw.A26; + + public bool DeterministicEmulation => true; + + public void ResetCounters() + { + _frame = 0; + LagCount = 0; + IsLagFrame = false; + } + + public void Dispose() + { + } + } +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.IInputPollable.cs b/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.IInputPollable.cs new file mode 100644 index 00000000000..c6fcff0b9e0 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.IInputPollable.cs @@ -0,0 +1,24 @@ +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Cores.Consoles.Atari.Stella; + +namespace BizHawk.Emulation.Cores.Atari.Stella +{ + public partial class Stella : IInputPollable + { + public int LagCount { get; set; } + + public bool IsLagFrame { get; set; } + + public IInputCallbackSystem InputCallbacks => _inputCallbacks; + + private readonly CInterface.input_cb _inputCallback; + + private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem(); + + private void input_callback() + { + InputCallbacks.Call(); + IsLagFrame = false; + } + } +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.IMemoryDomains.cs b/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.IMemoryDomains.cs new file mode 100644 index 00000000000..0000036c9ea --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.IMemoryDomains.cs @@ -0,0 +1,64 @@ +using System.Collections.Generic; + +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Atari.Stella +{ + public partial class Stella + { + internal IMemoryDomains MemoryDomains; + private uint _cartMemSize; + + private void SetupMemoryDomains() + { + _cartMemSize = Core.stella_get_cartram_size(); + var mainRamAddress = IntPtr.Zero; + var cartDPCRamAddress = IntPtr.Zero; + Core.stella_get_mainram_ptr(ref mainRamAddress); + + var domains = new List + { + new MemoryDomainDelegate( + "TIA", + 16, + MemoryDomain.Endian.Little, + addr => Core.stella_peek_tia((uint)addr), + (addr, value) => Core.stella_poke_tia((uint)addr, value), + 1), + + new MemoryDomainDelegate( + "PIA", + 1024, + MemoryDomain.Endian.Little, + addr => Core.stella_peek_m6532((uint)addr), + (addr, value) => Core.stella_poke_m6532((uint)addr, value), + 1), + + new MemoryDomainDelegate( + "System Bus", + 65536, + MemoryDomain.Endian.Little, + addr => Core.stella_peek_systembus((uint) addr), + (addr, value) => Core.stella_poke_systembus((uint) addr, value), + 1) + }; + + if (_cartMemSize > 0) + { + domains.Add(new MemoryDomainDelegate( + "Cart Ram", + _cartMemSize, + MemoryDomain.Endian.Little, + addr => Core.stella_peek_cartram((uint)addr), + (addr, value) => Core.stella_poke_cartram((uint)addr, value), + 1)); + } + + MemoryDomainIntPtrMonitor mainRAM = new("Main RAM", MemoryDomain.Endian.Little, mainRamAddress, 128, true, 1, _elf); + domains.Add(mainRAM); + + MemoryDomains = new MemoryDomainList(domains) { MainMemory = mainRAM }; + ((BasicServiceProvider)ServiceProvider).Register(MemoryDomains); + } + } +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.ISettable.cs b/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.ISettable.cs new file mode 100644 index 00000000000..10c6a8db935 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.ISettable.cs @@ -0,0 +1,206 @@ +using System.ComponentModel; +using System.Drawing; + +using Newtonsoft.Json; + +using BizHawk.Emulation.Common; +using BizHawk.Common; +using BizHawk.Emulation.Cores.Consoles.Atari.Stella; + +namespace BizHawk.Emulation.Cores.Atari.Stella +{ + public partial class Stella : ISettable + { + public A2600Settings GetSettings() + { + return Settings.Clone(); + } + + public A2600SyncSettings GetSyncSettings() + { + return SyncSettings.Clone(); + } + + public PutSettingsDirtyBits PutSettings(A2600Settings o) + { + Settings = o; + return PutSettingsDirtyBits.None; + } + + public PutSettingsDirtyBits PutSyncSettings(A2600SyncSettings o) + { + bool ret = A2600SyncSettings.NeedsReboot(SyncSettings, o); + SyncSettings = o; + return ret ? PutSettingsDirtyBits.RebootCore : PutSettingsDirtyBits.None; + } + + internal A2600Settings Settings { get; private set; } + internal A2600SyncSettings SyncSettings { get; private set; } + + [CoreSettings] + public class A2600Settings + { + [JsonIgnore] + private int _ntscTopLine; + + [JsonIgnore] + private int _ntscBottomLine; + + [JsonIgnore] + private int _palTopLine; + + [JsonIgnore] + private int _palBottomLine; + + [DisplayName("Show Background")] + [Description("Sets whether or not the Background layer will be displayed")] + [DefaultValue(true)] + public bool ShowBG { get; set; } + + [DisplayName("Show Player 1")] + [Description("Sets whether or not the Player 1 layer will be displayed")] + [DefaultValue(true)] + public bool ShowPlayer1 { get; set; } + + [DisplayName("Show Player 2")] + [Description("Sets whether or not the Player 2 layer will be displayed")] + [DefaultValue(true)] + public bool ShowPlayer2 { get; set; } + + [DisplayName("Show Missle 1")] + [Description("Sets whether or not the Missle 1 layer will be displayed")] + [DefaultValue(true)] + public bool ShowMissle1 { get; set; } + + [DisplayName("Show Missle 2")] + [Description("Sets whether or not the Missle 2 layer will be displayed")] + [DefaultValue(true)] + public bool ShowMissle2 { get; set; } + + [DisplayName("Show Ball")] + [Description("Sets whether or not the Ball layer will be displayed")] + [DefaultValue(true)] + public bool ShowBall { get; set; } + + [DisplayName("Show Playfield")] + [Description("Sets whether or not the Playfield layer will be displayed")] + [DefaultValue(true)] + public bool ShowPlayfield { get; set; } + + [DisplayName("SECAM Colors")] + [Description("If true, PAL mode will show with SECAM (French) colors.")] + [DefaultValue(false)] + public bool SECAMColors { get; set; } + + [DisplayName("NTSC Top Line")] + [Description("First line of the video image to display in NTSC mode.")] + [DefaultValue(24)] + public int NTSCTopLine + { + get => _ntscTopLine; + set => _ntscTopLine = Math.Min(64, Math.Max(value, 0)); + } + + [DisplayName("NTSC Bottom Line")] + [Description("Last line of the video image to display in NTSC mode.")] + [DefaultValue(248)] + public int NTSCBottomLine + { + get => _ntscBottomLine; + set => _ntscBottomLine = Math.Min(260, Math.Max(value, 192)); + } + + [DisplayName("PAL Top Line")] + [Description("First line of the video image to display in PAL mode.")] + [DefaultValue(24)] + public int PALTopLine + { + get => _palTopLine; + set => _palTopLine = Math.Min(64, Math.Max(value, 0)); + } + + [DisplayName("PAL Bottom Line")] + [Description("Last line of the video image to display in PAL mode.")] + [DefaultValue(296)] + public int PALBottomLine + { + get => _palBottomLine; + set => _palBottomLine = Math.Min(310, Math.Max(value, 192)); + } + + [DisplayName("Background Color")] + [DefaultValue(typeof(Color), "Black")] + public Color BackgroundColor { get; set; } + + public A2600Settings Clone() + { + return (A2600Settings)MemberwiseClone(); + } + + public A2600Settings() + { + SettingsUtil.SetDefaultValues(this); + } + } + + [CoreSettings] + public class A2600SyncSettings + { + [DefaultValue(Atari2600ControllerTypes.Joystick)] + [DisplayName("Port 1 Device")] + [Description("The type of controller plugged into the first controller port")] + [TypeConverter(typeof(DescribableEnumConverter))] + public Atari2600ControllerTypes Port1 { get; set; } = Atari2600ControllerTypes.Joystick; + + [DefaultValue(Atari2600ControllerTypes.Joystick)] + [DisplayName("Port 2 Device")] + [Description("The type of controller plugged into the second controller port")] + [TypeConverter(typeof(DescribableEnumConverter))] + public Atari2600ControllerTypes Port2 { get; set; } = Atari2600ControllerTypes.Joystick; + + [DisplayName("Black and White Mode")] + [Description("Set the TV Type switch on the console to B&W or Color. This only affects the displayed image if the game supports it.")] + [DefaultValue(false)] + public bool BW { get; set; } + + [DisplayName("Left Difficulty")] + [Description("Set the Left Difficulty switch on the console")] + [DefaultValue(true)] + public bool LeftDifficulty { get; set; } + + [DisplayName("Right Difficulty")] + [Description("Set the Right Difficulty switch on the console")] + [DefaultValue(true)] + public bool RightDifficulty { get; set; } + + [DisplayName("Super Charger BIOS Skip")] + [Description("On Super Charger carts, this will skip the BIOS intro")] + [DefaultValue(false)] + public bool FastScBios { get; set; } + + + public CInterface.InitSettings GetNativeSettings(GameInfo game) + { + return new CInterface.InitSettings + { + dummy = 1 + }; + } + + public A2600SyncSettings Clone() + { + return (A2600SyncSettings)MemberwiseClone(); + } + + public A2600SyncSettings() + { + SettingsUtil.SetDefaultValues(this); + } + + public static bool NeedsReboot(A2600SyncSettings x, A2600SyncSettings y) + { + return !DeepEquality.DeepEquals(x, y); + } + } + } +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.ISoundProvider.cs b/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.ISoundProvider.cs new file mode 100644 index 00000000000..72a599dfd20 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.ISoundProvider.cs @@ -0,0 +1,53 @@ +using BizHawk.Emulation.Common; +using System.Runtime.InteropServices; +using BizHawk.Common; + +namespace BizHawk.Emulation.Cores.Atari.Stella +{ + public partial class Stella : ISoundProvider + { + private readonly short[] _samples = new short[4096]; + private int _nsamp; + + public bool CanProvideAsync => false; + + public void GetSamplesSync(out short[] samples, out int nsamp) + { + nsamp = _nsamp; + samples = _samples; + _nsamp = 0; + } + + public void DiscardSamples() + { + _nsamp = 0; + } + + public void SetSyncMode(SyncSoundMode mode) + { + if (mode == SyncSoundMode.Async) + { + throw new NotSupportedException("Async mode is not supported."); + } + + } + public SyncSoundMode SyncMode => SyncSoundMode.Sync; + + public void GetSamplesAsync(short[] samples) + { + throw new InvalidOperationException("Async mode is not supported."); + } + + private void update_audio() + { + IntPtr src = IntPtr.Zero; + Core.stella_get_audio(ref _nsamp, ref src); + + if (src != IntPtr.Zero) + { + using (_elf.EnterExit()) + Marshal.Copy(src, _samples, 0, _nsamp * 2); + } + } + } +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.IStatable.cs b/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.IStatable.cs new file mode 100644 index 00000000000..d8d562fc4a3 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.IStatable.cs @@ -0,0 +1,31 @@ +using System.IO; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Atari.Stella +{ + public partial class Stella : IStatable + { + public bool AvoidRewind => false; + + public void LoadStateBinary(BinaryReader reader) + { + _elf.LoadStateBinary(reader); + // other variables + _frame = reader.ReadInt32(); + LagCount = reader.ReadInt32(); + IsLagFrame = reader.ReadBoolean(); + // any managed pointers that we sent to the core need to be resent now! + Core.stella_set_input_callback(_inputCallback); + UpdateVideo(); + } + + public void SaveStateBinary(BinaryWriter writer) + { + _elf.SaveStateBinary(writer); + // other variables + writer.Write(Frame); + writer.Write(LagCount); + writer.Write(IsLagFrame); + } + } +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.IVideoProvider.cs b/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.IVideoProvider.cs new file mode 100644 index 00000000000..43a7afee942 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.IVideoProvider.cs @@ -0,0 +1,81 @@ +using BizHawk.Emulation.Common; +using BizHawk.Common; + +namespace BizHawk.Emulation.Cores.Atari.Stella +{ + public partial class Stella : IVideoProvider + { + public int[] GetVideoBuffer() => _vidBuff; + + public int VirtualWidth => 160; + + public int VirtualHeight => 192; + + public int BufferWidth => _vwidth; + + public int BufferHeight => _vheight; + + public int BackgroundColor => unchecked((int)0xff000000); + + public int VsyncNumerator { get; } + + public int VsyncDenominator { get; } + + private int[] _vidBuff = new int[0]; + private int _vwidth; + private int _vheight; + + private void UpdateVideoInitial() + { + // hack: you should call update_video() here, but that gives you 256x192 on frame 0 + // and we know that we only use GPGX to emulate genesis games that will always be 320x224 immediately afterwards + + // so instead, just assume a 320x224 size now; if that happens to be wrong, it'll be fixed soon enough. + + _vwidth = 320; + _vheight = 224; + _vidBuff = new int[_vwidth * _vheight]; + for (int i = 0; i < _vidBuff.Length; i++) + { + _vidBuff[i] = unchecked((int)0xff000000); + } + } + + private readonly byte[] TwoBitToEightBitTable = new byte[] { 0, 85, 171, 255 }; + private readonly byte[] ThreeBitToEightBitTable = new byte[] { 0, 36, 73, 109, 146, 182, 219, 255 }; + + private unsafe void UpdateVideo() + { + if (Frame == 0) + { + UpdateVideoInitial(); + return; + } + + using (_elf.EnterExit()) + { + IntPtr src = IntPtr.Zero; + + Core.stella_get_video(out var width, out var height, out var pitch, ref src); + + _vwidth = width; + _vheight = height; + + byte* buffer = (byte*)src.ToPointer(); + + if (_vidBuff.Length < _vwidth * _vheight) + _vidBuff = new int[_vwidth * _vheight]; + + if (Region == DisplayType.NTSC) + for (int i = 0; i < _vidBuff.Length; i++) _vidBuff[i] = NTSCPalette[buffer[i]]; + + if (Region == DisplayType.PAL) + for (int i = 0; i < _vidBuff.Length; i++) _vidBuff[i] = PALPalette[buffer[i]]; + + if (Region == DisplayType.SECAM) + for (int i = 0; i < _vidBuff.Length; i++) _vidBuff[i] = SecamPalette[buffer[i]]; + } + } + + } +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.Pallete.cs b/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.Pallete.cs new file mode 100644 index 00000000000..e181fa57db7 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.Pallete.cs @@ -0,0 +1,207 @@ +namespace BizHawk.Emulation.Cores.Atari.Stella +{ + public partial class Stella + { + private static readonly int[] PALPalette = + { + 0x000000, 0x000000, 0x2b2b2b, 0x2b2b2b, + 0x525252, 0x525252, 0x767676, 0x767676, + 0x979797, 0x979797, 0xb6b6b6, 0xb6b6b6, + 0xd2d2d2, 0xd2d2d2, 0xececec, 0xececec, + + 0x000000, 0x000000, 0x2b2b2b, 0x2b2b2b, + 0x525252, 0x525252, 0x767676, 0x767676, + 0x979797, 0x979797, 0xb6b6b6, 0xb6b6b6, + 0xd2d2d2, 0xd2d2d2, 0xececec, 0xececec, + + 0x805800, 0x000000, 0x96711a, 0x2b2b2b, + 0xab8732, 0x525252, 0xbe9c48, 0x767676, + 0xcfaf5c, 0x979797, 0xdfc06f, 0xb6b6b6, + 0xeed180, 0xd2d2d2, 0xfce090, 0xececec, + + 0x445c00, 0x000000, 0x5e791a, 0x2b2b2b, + 0x769332, 0x525252, 0x8cac48, 0x767676, + 0xa0c25c, 0x979797, 0xb3d76f, 0xb6b6b6, + 0xc4ea80, 0xd2d2d2, 0xd4fc90, 0xececec, + + 0x703400, 0x000000, 0x89511a, 0x2b2b2b, + 0xa06b32, 0x525252, 0xb68448, 0x767676, + 0xc99a5c, 0x979797, 0xdcaf6f, 0xb6b6b6, + 0xecc280, 0xd2d2d2, 0xfcd490, 0xececec, + + 0x006414, 0x000000, 0x1a8035, 0x2b2b2b, + 0x329852, 0x525252, 0x48b06e, 0x767676, + 0x5cc587, 0x979797, 0x6fd99e, 0xb6b6b6, + 0x80ebb4, 0xd2d2d2, 0x90fcc8, 0xececec, + + 0x700014, 0x000000, 0x891a35, 0x2b2b2b, + 0xa03252, 0x525252, 0xb6486e, 0x767676, + 0xc95c87, 0x979797, 0xdc6f9e, 0xb6b6b6, + 0xec80b4, 0xd2d2d2, 0xfc90c8, 0xececec, + + 0x005c5c, 0x000000, 0x1a7676, 0x2b2b2b, + 0x328e8e, 0x525252, 0x48a4a4, 0x767676, + 0x5cb8b8, 0x979797, 0x6fcbcb, 0xb6b6b6, + 0x80dcdc, 0xd2d2d2, 0x90ecec, 0xececec, + + 0x70005c, 0x000000, 0x841a74, 0x2b2b2b, + 0x963289, 0x525252, 0xa8489e, 0x767676, + 0xb75cb0, 0x979797, 0xc66fc1, 0xb6b6b6, + 0xd380d1, 0xd2d2d2, 0xe090e0, 0xececec, + + 0x003c70, 0x000000, 0x195a89, 0x2b2b2b, + 0x2f75a0, 0x525252, 0x448eb6, 0x767676, + 0x57a5c9, 0x979797, 0x68badc, 0xb6b6b6, + 0x79ceec, 0xd2d2d2, 0x88e0fc, 0xececec, + + 0x580070, 0x000000, 0x6e1a89, 0x2b2b2b, + 0x8332a0, 0x525252, 0x9648b6, 0x767676, + 0xa75cc9, 0x979797, 0xb76fdc, 0xb6b6b6, + 0xc680ec, 0xd2d2d2, 0xd490fc, 0xececec, + + 0x002070, 0x000000, 0x193f89, 0x2b2b2b, + 0x2f5aa0, 0x525252, 0x4474b6, 0x767676, + 0x578bc9, 0x979797, 0x68a1dc, 0xb6b6b6, + 0x79b5ec, 0xd2d2d2, 0x88c8fc, 0xececec, + + 0x340080, 0x000000, 0x4a1a96, 0x2b2b2b, + 0x5f32ab, 0x525252, 0x7248be, 0x767676, + 0x835ccf, 0x979797, 0x936fdf, 0xb6b6b6, + 0xa280ee, 0xd2d2d2, 0xb090fc, 0xececec, + + 0x000088, 0x000000, 0x1a1a9d, 0x2b2b2b, + 0x3232b0, 0x525252, 0x4848c2, 0x767676, + 0x5c5cd2, 0x979797, 0x6f6fe1, 0xb6b6b6, + 0x8080ef, 0xd2d2d2, 0x9090fc, 0xececec, + + 0x000000, 0x000000, 0x2b2b2b, 0x2b2b2b, + 0x525252, 0x525252, 0x767676, 0x767676, + 0x979797, 0x979797, 0xb6b6b6, 0xb6b6b6, + 0xd2d2d2, 0xd2d2d2, 0xececec, 0xececec, + + 0x000000, 0x000000, 0x2b2b2b, 0x2b2b2b, + 0x525252, 0x525252, 0x767676, 0x767676, + 0x979797, 0x979797, 0xb6b6b6, 0xb6b6b6, + 0xd2d2d2, 0xd2d2d2, 0xececec, 0xececec + }; + + private static readonly int[] NTSCPalette = + { + 0x000000, 0, 0x4a4a4a, 0, 0x6f6f6f, 0, 0x8e8e8e, 0, + 0xaaaaaa, 0, 0xc0c0c0, 0, 0xd6d6d6, 0, 0xececec, 0, + 0x484800, 0, 0x69690f, 0, 0x86861d, 0, 0xa2a22a, 0, + 0xbbbb35, 0, 0xd2d240, 0, 0xe8e84a, 0, 0xfcfc54, 0, + 0x7c2c00, 0, 0x904811, 0, 0xa26221, 0, 0xb47a30, 0, + 0xc3903d, 0, 0xd2a44a, 0, 0xdfb755, 0, 0xecc860, 0, + 0x901c00, 0, 0xa33915, 0, 0xb55328, 0, 0xc66c3a, 0, + 0xd5824a, 0, 0xe39759, 0, 0xf0aa67, 0, 0xfcbc74, 0, + 0x940000, 0, 0xa71a1a, 0, 0xb83232, 0, 0xc84848, 0, + 0xd65c5c, 0, 0xe46f6f, 0, 0xf08080, 0, 0xfc9090, 0, + 0x840064, 0, 0x97197a, 0, 0xa8308f, 0, 0xb846a2, 0, + 0xc659b3, 0, 0xd46cc3, 0, 0xe07cd2, 0, 0xec8ce0, 0, + 0x500084, 0, 0x68199a, 0, 0x7d30ad, 0, 0x9246c0, 0, + 0xa459d0, 0, 0xb56ce0, 0, 0xc57cee, 0, 0xd48cfc, 0, + 0x140090, 0, 0x331aa3, 0, 0x4e32b5, 0, 0x6848c6, 0, + 0x7f5cd5, 0, 0x956fe3, 0, 0xa980f0, 0, 0xbc90fc, 0, + 0x000094, 0, 0x181aa7, 0, 0x2d32b8, 0, 0x4248c8, 0, + 0x545cd6, 0, 0x656fe4, 0, 0x7580f0, 0, 0x8490fc, 0, + 0x001c88, 0, 0x183b9d, 0, 0x2d57b0, 0, 0x4272c2, 0, + 0x548ad2, 0, 0x65a0e1, 0, 0x75b5ef, 0, 0x84c8fc, 0, + 0x003064, 0, 0x185080, 0, 0x2d6d98, 0, 0x4288b0, 0, + 0x54a0c5, 0, 0x65b7d9, 0, 0x75cceb, 0, 0x84e0fc, 0, + 0x004030, 0, 0x18624e, 0, 0x2d8169, 0, 0x429e82, 0, + 0x54b899, 0, 0x65d1ae, 0, 0x75e7c2, 0, 0x84fcd4, 0, + 0x004400, 0, 0x1a661a, 0, 0x328432, 0, 0x48a048, 0, + 0x5cba5c, 0, 0x6fd26f, 0, 0x80e880, 0, 0x90fc90, 0, + 0x143c00, 0, 0x355f18, 0, 0x527e2d, 0, 0x6e9c42, 0, + 0x87b754, 0, 0x9ed065, 0, 0xb4e775, 0, 0xc8fc84, 0, + 0x303800, 0, 0x505916, 0, 0x6d762b, 0, 0x88923e, 0, + 0xa0ab4f, 0, 0xb7c25f, 0, 0xccd86e, 0, 0xe0ec7c, 0, + 0x482c00, 0, 0x694d14, 0, 0x866a26, 0, 0xa28638, 0, + 0xbb9f47, 0, 0xd2b656, 0, 0xe8cc63, 0, 0xfce070, 0 + }; + + private static readonly int[] SecamPalette = + { + 0x000000, 0x000000, 0x2121FF, 0x2121FF, + 0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF, + 0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF, + 0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff, + + 0x000000, 0x000000, 0x2121FF, 0x2121FF, + 0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF, + 0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF, + 0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff, + + 0x000000, 0x000000, 0x2121FF, 0x2121FF, + 0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF, + 0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF, + 0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff, + + 0x000000, 0x000000, 0x2121FF, 0x2121FF, + 0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF, + 0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF, + 0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff, + + 0x000000, 0x000000, 0x2121FF, 0x2121FF, + 0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF, + 0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF, + 0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff, + + 0x000000, 0x000000, 0x2121FF, 0x2121FF, + 0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF, + 0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF, + 0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff, + + 0x000000, 0x000000, 0x2121FF, 0x2121FF, + 0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF, + 0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF, + 0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff, + + 0x000000, 0x000000, 0x2121FF, 0x2121FF, + 0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF, + 0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF, + 0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff, + + 0x000000, 0x000000, 0x2121FF, 0x2121FF, + 0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF, + 0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF, + 0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff, + + 0x000000, 0x000000, 0x2121FF, 0x2121FF, + 0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF, + 0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF, + 0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff, + + 0x000000, 0x000000, 0x2121FF, 0x2121FF, + 0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF, + 0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF, + 0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff, + + 0x000000, 0x000000, 0x2121FF, 0x2121FF, + 0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF, + 0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF, + 0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff, + + 0x000000, 0x000000, 0x2121FF, 0x2121FF, + 0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF, + 0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF, + 0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff, + + 0x000000, 0x000000, 0x2121FF, 0x2121FF, + 0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF, + 0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF, + 0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff, + + 0x000000, 0x000000, 0x2121FF, 0x2121FF, + 0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF, + 0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF, + 0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff, + + 0x000000, 0x000000, 0x2121FF, 0x2121FF, + 0xF03C79, 0xF03C79, 0xFF50FF, 0xFF50FF, + 0x7FFF00, 0x7FFF00, 0x7FFFFF, 0x7FFFFF, + 0xFFFF3F, 0xFFFF3F, 0xffffff, 0xffffff + }; + } +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.cs b/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.cs new file mode 100644 index 00000000000..593c831af28 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/Stella.cs @@ -0,0 +1,185 @@ +using System.Linq; +using System.Runtime.InteropServices; +using BizHawk.BizInvoke; +using BizHawk.Common; +using BizHawk.Common.PathExtensions; +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Cores.Consoles.Atari.Stella; +using BizHawk.Emulation.Cores.Waterbox; + +namespace BizHawk.Emulation.Cores.Atari.Stella +{ + [PortedCore( + name: CoreNames.Stella, + author: "The Stella Team", +// portedVersion: "", //TODO + portedUrl: "https://stella-emu.github.io")] + [ServiceNotApplicable(new[] { typeof(IDriveLight), typeof(ISaveRam) })] + public partial class Stella : IEmulator, IVideoProvider, IInputPollable, IRomInfo, IRegionable, + ICreateGameDBEntries, ISettable + { + internal static class RomChecksums + { + public const string CongoBongo = "SHA1:3A77DB43B6583E8689435F0F14AA04B9E57BDDED"; + + public const string KangarooNotInGameDB = "SHA1:982B8016B393A9AA7DD110295A53C4612ECF2141"; + + public const string Tapper = "SHA1:E986E1818E747BEB9B33CE4DFF1CDC6B55BDB620"; + } + + [CoreConstructor(VSystemID.Raw.A26)] + public Stella(CoreLoadParameters lp) + { + var ser = new BasicServiceProvider(this); + ServiceProvider = ser; + SyncSettings = lp.SyncSettings ?? new A2600SyncSettings(); + Settings = lp.Settings ?? new A2600Settings(); + _controllerDeck = new Atari2600ControllerDeck(SyncSettings.Port1, SyncSettings.Port2); + + _elf = new WaterboxHost(new WaterboxOptions + { + Path = PathUtils.DllDirectoryPath, + Filename = "stella.wbx", + SbrkHeapSizeKB = 4 * 1024, + SealedHeapSizeKB = 4 * 1024, + InvisibleHeapSizeKB = 4 * 1024, + PlainHeapSizeKB = 4 * 1024, + MmapHeapSizeKB = 4 * 1024, + SkipCoreConsistencyCheck = lp.Comm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxCoreConsistencyCheck), + SkipMemoryConsistencyCheck = lp.Comm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxMemoryConsistencyCheck), + }); + + LoadCallback = load_archive; + _inputCallback = input_callback; + + var callingConventionAdapter = CallingConventionAdapters.MakeWaterbox(new Delegate[] + { + LoadCallback, _inputCallback + }, _elf); + + using (_elf.EnterExit()) + { + Core = BizInvoker.GetInvoker(_elf, _elf, callingConventionAdapter); + SyncSettings = lp.SyncSettings ?? new A2600SyncSettings(); + Settings = lp.Settings ?? new A2600Settings(); + + CoreComm = lp.Comm; + + _romfile = lp.Roms.FirstOrDefault()?.RomData; + string romPath = lp.Roms.FirstOrDefault()?.RomPath; + + var initResult = Core.stella_init(romPath, LoadCallback, SyncSettings.GetNativeSettings(lp.Game)); + + if (!initResult) throw new Exception($"{nameof(Core.stella_init)}() failed"); + + Core.stella_get_frame_rate(out int fps); + + int regionId = Core.stella_get_region(); + if (regionId == 0) _region = DisplayType.NTSC; + if (regionId == 1) _region = DisplayType.PAL; + if (regionId == 2) _region = DisplayType.SECAM; + + VsyncNumerator = fps; + VsyncDenominator = 1; + + Core.stella_set_input_callback(_inputCallback); + + // Getting cartridge type + var ptr = Core.stella_get_cart_type(); + string _cartType = Marshal.PtrToStringAnsi(ptr); + Console.WriteLine("[Stella] Cart type loaded: {0} (string size: {1}, ptr: {2})", _cartType, _cartType.Length, ptr); + + _elf.Seal(); + } + + // pull the default video size from the core + UpdateVideo(); + + // Registering memory domains + SetupMemoryDomains(); + } + + // IRegionable + public DisplayType Region => _region; + + private DisplayType _region; + + private CInterface.load_archive_cb LoadCallback; + + private readonly byte[] _romfile; + private readonly CInterface Core; + private readonly WaterboxHost _elf; + private string _cartType { get; } + + private CoreComm CoreComm { get; } + + public string RomDetails { get; private set; } + + private readonly Atari2600ControllerDeck _controllerDeck; + + private ITraceable Tracer { get; } + + // ICreateGameDBEntries + public CompactGameInfo GenerateGameDbEntry() + { + return new CompactGameInfo + { + }; + } + + // IBoardInfo + private static bool DetectPal(GameInfo game, byte[] rom) + { + return true; + } + + /// + /// core callback for file loading + /// + /// string identifying file to be loaded + /// buffer to load file to + /// maximum length buffer can hold + /// actual size loaded, or 0 on failure + private int load_archive(string filename, IntPtr buffer, int maxsize) + { + byte[] srcdata = null; + + if (buffer == IntPtr.Zero) + { + Console.WriteLine("Couldn't satisfy firmware request {0} because buffer == NULL", filename); + return 0; + } + + if (filename == "PRIMARY_ROM") + { + if (_romfile == null) + { + Console.WriteLine("Couldn't satisfy firmware request PRIMARY_ROM because none was provided."); + return 0; + } + srcdata = _romfile; + } + + if (srcdata != null) + { + if (srcdata.Length > maxsize) + { + Console.WriteLine("Couldn't satisfy firmware request {0} because {1} > {2}", filename, srcdata.Length, maxsize); + return 0; + } + else + { + Console.WriteLine("Copying Data from " + srcdata + " to " + buffer + " Size: " + srcdata.Length); + Marshal.Copy(srcdata, 0, buffer, srcdata.Length); + Console.WriteLine("Firmware request {0} satisfied at size {1}", filename, srcdata.Length); + return srcdata.Length; + } + } + else + { + throw new InvalidOperationException("Unknown error processing firmware"); + } + + } + } +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/StellaControllerDeck.cs b/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/StellaControllerDeck.cs new file mode 100644 index 00000000000..289b776c193 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/StellaControllerDeck.cs @@ -0,0 +1,83 @@ +using System.Collections.Generic; +using System.Linq; + +using BizHawk.Common; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Atari.Stella +{ + public class Atari2600ControllerDeck + { + + public Atari2600ControllerDeck(Atari2600ControllerTypes controller1, Atari2600ControllerTypes controller2) + { + Port1 = ControllerCtors[controller1](1); + Port2 = ControllerCtors[controller2](2); + + Definition = new("Atari 2600 Basic Controller") + { + BoolButtons = Port1.Definition.BoolButtons + .Concat(Port2.Definition.BoolButtons) + .Concat(new[] + { + "Reset", "Select", "Power", "Toggle Left Difficulty", "Toggle Right Difficulty" + }) + .ToList() + }; + + foreach (var kvp in Port1.Definition.Axes) Definition.Axes.Add(kvp); + foreach (var kvp in Port2.Definition.Axes) Definition.Axes.Add(kvp); + + Definition.MakeImmutable(); + } + + public byte ReadPort1(IController c) + { + return Port1.Read(c); + } + + public byte ReadPort2(IController c) + { + return Port2.Read(c); + } + + public int ReadPot1(IController c, int pot) + { + return Port1.Read_Pot(c, pot); + } + + public int ReadPot2(IController c, int pot) + { + return Port2.Read_Pot(c, pot); + } + + public ControllerDefinition Definition { get; } + + public void SyncState(Serializer ser) + { + ser.BeginSection(nameof(Port1)); + Port1.SyncState(ser); + ser.EndSection(); + + ser.BeginSection(nameof(Port2)); + Port2.SyncState(ser); + ser.EndSection(); + } + + private readonly IPort Port1; + private readonly IPort Port2; + + private static IReadOnlyDictionary> _controllerCtors; + + public static IReadOnlyDictionary> ControllerCtors => _controllerCtors + ??= new Dictionary> + { + [Atari2600ControllerTypes.Unplugged] = portNum => new UnpluggedController(portNum), + [Atari2600ControllerTypes.Joystick] = portNum => new StandardController(portNum), + [Atari2600ControllerTypes.Paddle] = portNum => new PaddleController(portNum), + [Atari2600ControllerTypes.BoostGrip] = portNum => new BoostGripController(portNum), + [Atari2600ControllerTypes.Driving] = portNum => new DrivingController(portNum), + [Atari2600ControllerTypes.Keyboard] = portNum => new KeyboardController(portNum) + }; + } +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/StellaControllers.cs b/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/StellaControllers.cs new file mode 100644 index 00000000000..4dad8d299f4 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Atari/Stella/StellaControllers.cs @@ -0,0 +1,375 @@ +using System.Linq; + +using BizHawk.Common; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Atari.Stella +{ + public enum Atari2600ControllerTypes + { + Unplugged, + Joystick, + Paddle, + BoostGrip, + Driving, + Keyboard + } + + /// + /// Represents a controller plugged into a controller port on the 2600 + /// + public interface IPort + { + byte Read(IController c); + + int Read_Pot(IController c, int pot); + + ControllerDefinition Definition { get; } + + void SyncState(Serializer ser); + + int PortNum { get; } + } + + public class UnpluggedController : IPort + { + public UnpluggedController(int portNum) + { + PortNum = portNum; + Definition = new("(Atari 2600 Basic Controller fragment)"); + } + + public byte Read(IController c) + { + return 0xFF; + } + + public int Read_Pot(IController c, int pot) + { + return -1; // indicates not applicable + } + + public ControllerDefinition Definition { get; } + + public void SyncState(Serializer ser) + { + // Do nothing + } + + public int PortNum { get; } + } + + public class StandardController : IPort + { + public StandardController(int portNum) + { + PortNum = portNum; + Definition = new("(Atari 2600 Basic Controller fragment)") + { + BoolButtons = BaseDefinition + .Select(b => $"P{PortNum} " + b) + .ToList() + }; + } + + public ControllerDefinition Definition { get; } + + public void SyncState(Serializer ser) + { + // Nothing todo, I think + } + + public int PortNum { get; } + + public byte Read(IController c) + { + byte result = 0xFF; + + if (c.IsPressed($"P{PortNum} Up")) { result &= 0xEF; } + if (c.IsPressed($"P{PortNum} Down")) { result &= 0xDF; } + if (c.IsPressed($"P{PortNum} Left")) { result &= 0xBF; } + if (c.IsPressed($"P{PortNum} Right")) { result &= 0x7F; } + if (c.IsPressed($"P{PortNum} Button")) { result &= 0xF7; } + + return result; + } + + public int Read_Pot(IController c, int pot) + { + return -1; // indicates not applicable + } + + private static readonly string[] BaseDefinition = + { + "Up", "Down", "Left", "Right", "Button" + }; + } + + public class PaddleController : IPort + { + public PaddleController(int portNum) + { + PortNum = portNum; + Definition = new ControllerDefinition("(Atari 2600 Basic Controller fragment)") + { + BoolButtons = BaseDefinition + .Select(b => $"P{PortNum} " + b) + .ToList() + }.AddAxis($"P{PortNum} Paddle X 1", (-127).RangeTo(127), 0) + .AddAxis($"P{PortNum} Paddle X 2", (-127).RangeTo(127), 0) + .MakeImmutable(); + } + + public int PortNum { get; } + + public void SyncState(Serializer ser) + { + // Nothing todo, I think + } + + public ControllerDefinition Definition { get; } + + private static readonly string[] BaseDefinition = + { + "Button 1", + "Button 2" + }; + + public byte Read(IController c) + { + byte result = 0xF0; + + if (c.IsPressed($"P{PortNum} Button 1")) { result &= 0x70; } + if (c.IsPressed($"P{PortNum} Button 2")) { result &= 0xB0; } + + return result; + } + + public int Read_Pot(IController c, int pot) + { + int x = c.AxisValue(Definition.Axes[pot]); + + x = -x; + x += 127; + + x = x * 64 + 10; + + return x; + } + } + + public class BoostGripController : IPort + { + public BoostGripController(int portNum) + { + PortNum = portNum; + Definition = new("(Atari 2600 Basic Controller fragment)") + { + BoolButtons = BaseDefinition + .Select(b => $"P{PortNum} " + b) + .ToList() + }; + } + + public int PortNum { get; } + + public void SyncState(Serializer ser) + { + // Nothing todo, I think + } + + public ControllerDefinition Definition { get; } + + private static readonly string[] BaseDefinition = + { + "Up", "Down", "Left", "Right", "Button", + "Button 1", + "Button 2" + }; + + public byte Read(IController c) + { + byte result = 0xFF; + + if (c.IsPressed($"P{PortNum} Up")) { result &= 0xEF; } + if (c.IsPressed($"P{PortNum} Down")) { result &= 0xDF; } + if (c.IsPressed($"P{PortNum} Left")) { result &= 0xBF; } + if (c.IsPressed($"P{PortNum} Right")) { result &= 0x7F; } + if (c.IsPressed($"P{PortNum} Button")) { result &= 0xF7; } + + return result; + } + + public int Read_Pot(IController c, int pot) + { + bool is_pressed = false; + + if (pot == 0) + { + is_pressed = c.IsPressed($"P{PortNum} Button 1"); + } + else + { + is_pressed = c.IsPressed($"P{PortNum} Button 2"); + } + + if (is_pressed) + { + return 10; + } + + return 65535; + } + } + + public class DrivingController : IPort + { + public DrivingController(int portNum) + { + PortNum = portNum; + Definition = new ControllerDefinition("(Atari 2600 Basic Controller fragment)") + { + BoolButtons = BaseDefinition + .Select(b => $"P{PortNum} " + b) + .ToList() + }.AddAxis($"P{PortNum} Wheel X 1", (-127).RangeTo(127), 0) + .AddAxis($"P{PortNum} Wheel X 2", (-127).RangeTo(127), 0) + .MakeImmutable(); + } + + public int PortNum { get; } + + public void SyncState(Serializer ser) + { + // Nothing todo, I think + } + + public ControllerDefinition Definition { get; } + + private static readonly string[] BaseDefinition = + { + "Button" + }; + + public byte Read(IController c) + { + byte result = 0xFF; + + if (c.IsPressed($"P{PortNum} Button")) { result &= 0xF7; } + + float x = c.AxisValue(Definition.Axes[0]); + float y = c.AxisValue(Definition.Axes[1]); + + float angle = CalcDirection(x, y); + + byte temp2 = 0; + + int temp1 = (int)Math.Floor(angle / 45); + temp1 %= 4; + + if (temp1 == 0) + { + temp2 = 0xEF; + } + + if (temp1 == 1) + { + temp2 = 0xCF; + } + if (temp1 == 2) + { + temp2 = 0xDF; + } + + if (temp1 == 3) + { + temp2 = 0xFF; + } + + + result &= temp2; + + + return result; + } + + public int Read_Pot(IController c, int pot) + { + return -1; // indicates not applicable + } + + private static float CalcDirection(float x, float y) + { + y = -y; // vflip to match the arrangement of FloatControllerButtons + + // the wheel is arranged in a grey coded configuration of sensitivity ~2.5 degrees + // for each signal + // so overall the value returned changes every 1.25 degrees + + float angle = (float)(Math.Atan2(y, x) * 180.0 / Math.PI); + + if (angle < 0) + { + angle = 360 + angle; + } + + return angle; + } + } + + public class KeyboardController : IPort + { + public KeyboardController(int portNum) + { + PortNum = portNum; + Definition = new("(Atari 2600 Basic Controller fragment)") + { + BoolButtons = BaseDefinition + .Select(b => $"P{PortNum} " + b) + .ToList() + }; + } + + public ControllerDefinition Definition { get; } + + public void SyncState(Serializer ser) + { + // Nothing todo, I think + } + + public int PortNum { get; } + + public byte Read(IController c) + { + byte result = 0xFF; + + if (c.IsPressed($"P{PortNum} 0")) { result = 0x00; } + if (c.IsPressed($"P{PortNum} 1")) { result = 0x01; } + if (c.IsPressed($"P{PortNum} 2")) { result = 0x02; } + if (c.IsPressed($"P{PortNum} 3")) { result = 0x03; } + if (c.IsPressed($"P{PortNum} 4")) { result = 0x04; } + if (c.IsPressed($"P{PortNum} 5")) { result = 0x05; } + if (c.IsPressed($"P{PortNum} 6")) { result = 0x06; } + if (c.IsPressed($"P{PortNum} 7")) { result = 0x07; } + if (c.IsPressed($"P{PortNum} 8")) { result = 0x08; } + if (c.IsPressed($"P{PortNum} 9")) { result = 0x09; } + if (c.IsPressed($"P{PortNum} *")) { result = 0x0A; } + if (c.IsPressed($"P{PortNum} #")) { result = 0x0B; } + + return result; + } + + public int Read_Pot(IController c, int pot) + { + return -2; // indicates keyboard + } + + private static readonly string[] BaseDefinition = + { + "1", "2", "3", + "4", "5", "6", + "7", "8", "9", + "*", "0", "#" + }; + } +} diff --git a/src/BizHawk.Emulation.Cores/CoreNames.cs b/src/BizHawk.Emulation.Cores/CoreNames.cs index 3dd44477c88..8c90317d99b 100644 --- a/src/BizHawk.Emulation.Cores/CoreNames.cs +++ b/src/BizHawk.Emulation.Cores/CoreNames.cs @@ -52,6 +52,7 @@ public static class CoreNames public const string Saturnus = "Saturnus"; public const string SMSHawk = "SMSHawk"; public const string Snes9X = "Snes9x"; + public const string Stella = "Stella"; public const string SubBsnes115 = "SubBSNESv115+"; public const string SubGbHawk = "SubGBHawk"; public const string SubNesHawk = "SubNESHawk"; diff --git a/waterbox/common.mak b/waterbox/common.mak index 28b3ba0718b..53d0448d5e1 100644 --- a/waterbox/common.mak +++ b/waterbox/common.mak @@ -46,8 +46,14 @@ CXXFLAGS_RELEASE := -O3 -flto -DNDEBUG CXXFLAGS_RELEASE_ASONLY := -O3 EXTRA_LIBS := -L $(SYSROOT)/lib/linux -lclang_rt.builtins-x86_64 $(EXTRA_LIBS) +CPP_EXTRA_LIBS := -lc++ -lc++abi -lunwind $(EXTRA_LIBS) + ifneq ($(filter %.cpp,$(SRCS)),) -EXTRA_LIBS := -lc++ -lc++abi -lunwind $(EXTRA_LIBS) +EXTRA_LIBS += $(CPP_EXTRA_LIBS) +endif + +ifneq ($(filter %.cxx,$(SRCS)),) +EXTRA_LIBS += $(CPP_EXTRA_LIBS) endif _OBJS := $(addsuffix .o,$(abspath $(SRCS))) @@ -62,6 +68,10 @@ $(OBJ_DIR)/%.cpp.o: %.cpp @echo cxx $< @mkdir -p $(@D) @$(CC) -c -o $@ $< $(CXXFLAGS) $(CXXFLAGS_RELEASE) $(PER_FILE_FLAGS_$<) +$(OBJ_DIR)/%.cxx.o: %.cxx + @echo cxx $< + @mkdir -p $(@D) + @$(CC) -c -o $@ $< $(CXXFLAGS) $(CXXFLAGS_RELEASE) $(PER_FILE_FLAGS_$<) $(DOBJ_DIR)/%.c.o: %.c @echo cc $< @mkdir -p $(@D) @@ -70,6 +80,10 @@ $(DOBJ_DIR)/%.cpp.o: %.cpp @echo cxx $< @mkdir -p $(@D) @$(CC) -c -o $@ $< $(CXXFLAGS) $(CXXFLAGS_DEBUG) $(PER_FILE_FLAGS_$<) +$(DOBJ_DIR)/%.cxx.o: %.cxx + @echo cxx $< + @mkdir -p $(@D) + @$(CC) -c -o $@ $< $(CXXFLAGS) $(CXXFLAGS_DEBUG) $(PER_FILE_FLAGS_$<) $(OBJ_DIR)/%.c.s: %.c @echo cc -S $< @mkdir -p $(@D) @@ -78,6 +92,10 @@ $(OBJ_DIR)/%.cpp.s: %.cpp @echo cxx -S $< @mkdir -p $(@D) @$(CC) -c -S -o $@ $< $(CXXFLAGS) $(CXXFLAGS_RELEASE_ASONLY) $(PER_FILE_FLAGS_$<) +$(OBJ_DIR)/%.cxx.s: %.cxx + @echo cxx -S $< + @mkdir -p $(@D) + @$(CC) -c -S -o $@ $< $(CXXFLAGS) $(CXXFLAGS_RELEASE_ASONLY) $(PER_FILE_FLAGS_$<) ifndef NO_WBX_TARGETS diff --git a/waterbox/make-all-cores.sh b/waterbox/make-all-cores.sh index d98001f416a..7965f6e71ec 100755 --- a/waterbox/make-all-cores.sh +++ b/waterbox/make-all-cores.sh @@ -9,6 +9,7 @@ cd gpgx && make -f Makefile $1 -j && cd - cd libsnes && make -f Makefile $1 -j && cd - cd melon && make -f Makefile $1 -j && cd - cd picodrive && make -f Makefile $1 -j && cd - +cd stella && make -f Makefile $1 -j && cd - cd snes9x && make -f Makefile $1 -j && cd - cd tic80 && make -f Makefile $1 -j && cd - cd uae && make -f Makefile $1 -j && cd - diff --git a/waterbox/readme.txt b/waterbox/readme.txt index be2471bbc63..d8096c0aea2 100644 --- a/waterbox/readme.txt +++ b/waterbox/readme.txt @@ -37,6 +37,7 @@ It consists of a modified musl libc, and build scripts to tie it all together. * waterbox/snes9x (required for Snes9x) * waterbox/gpgx/Genesis-Plus-GX (required for gpgx) * waterbox/uae/libretro-uae (required for puae) + * waterbox/stella/core (required for stella) * none of these submodules need to be cloned recursively 3. Consider whether it is time to update your build environment (i.e. sudo apt-get upgrade). Build environment tools are generally best kept at the latest version, to ensure top performance for our users. @@ -76,6 +77,7 @@ It consists of a modified musl libc, and build scripts to tie it all together. cd nyma && make -f shock.mak install cd nyma && make -f vb.mak install cd picodrive && make install + cd stella && make install cd snes9x && make install cd tic80 && make install cd uae && make install diff --git a/waterbox/stella/BizhawkInterface.cxx b/waterbox/stella/BizhawkInterface.cxx new file mode 100644 index 00000000000..50325479914 --- /dev/null +++ b/waterbox/stella/BizhawkInterface.cxx @@ -0,0 +1,224 @@ +#include +#include +#include "Cart.hxx" +#include "BizhawkInterface.hxx" +#include "OSystem.hxx" +#include "Settings.hxx" +#include "MediaFactory.hxx" +#include "Serializer.hxx" +#include "StateManager.hxx" +#include "Console.hxx" +#include "Control.hxx" +#include "Switches.hxx" +#include "M6532.hxx" +#include "TIA.hxx" + +#define SOUND_BUFFER_SIZE 1024*1024 + +uint16_t* soundbuffer; +int nsamples; + +struct InitSettings +{ + uint32_t dummy; +}; + +std::unique_ptr _a2600; + +void printRAM() +{ + printf("[] Ram Pointer: %p\n", _a2600->console().riot().getRAM()); + printf("[] Memory Contents:\n"); + for (int i = 0; i < 8; i++) + { + for (int j = 0; j < 16; j++) + { + printf("%02X ", _a2600->console().riot().getRAM()[i*16 + j]); + } + printf("\n"); + } +} + +enum regionType +{ + ntsc = 0, + pal = 1, + secam = 2 +}; + +ECL_EXPORT int stella_get_region() +{ + const auto regionString = _a2600->console().getFormatString(); + + if (regionString == "NTSC" || regionString == "NTSC50") return regionType::ntsc; + if (regionString == "PAL" || regionString == "PAL60") return regionType::pal; + if (regionString == "SECAM" || regionString == "SECAM60") return regionType::secam; + + return -1; +} + +ECL_EXPORT void stella_get_frame_rate(int& fps) +{ + fps = _a2600->console().gameRefreshRate(); +} + +void printFrameBuffer() +{ + auto frameBuffer = _a2600->console().tia().frameBuffer(); + auto height = _a2600->console().tia().height(); + auto width = _a2600->console().tia().width(); + + printf("[] Frame Buffer Pointer: %p\n", frameBuffer); + // printf("[] Frame Buffer Contents:\n"); + + uint64_t checkSum = 0; + for (int i = 0; i < height; i++) + { + for (int j = 0; j < width; j++) + { + // printf("%02X ", frameBuffer[i*height + j]); + checkSum += frameBuffer[i*height + j]; + } + // printf("\n"); + } + + printf("[] Frame Buffer Checksum: 0x%lX\n", checkSum); +} + +ECL_EXPORT const char* stella_get_cart_type() +{ + return _a2600->console().cartridge().detectedType().c_str(); +} + +ECL_EXPORT uint8_t stella_peek_tia(uint32_t address) +{ + return _a2600->console().tia().peek(address); +} + +ECL_EXPORT void stella_poke_tia(uint32_t address, uint8_t value) +{ + _a2600->console().tia().poke(address, value); +} + +ECL_EXPORT uint8_t stella_peek_m6532(uint32_t address) +{ + return _a2600->console().riot().peek(address); +} + +ECL_EXPORT void stella_poke_m6532(uint32_t address, uint8_t value) +{ + _a2600->console().riot().poke(address, value); +} + +ECL_EXPORT uint8_t stella_peek_systembus(uint32_t address) +{ + return _a2600->console().system().peek(address); +} + +ECL_EXPORT void stella_poke_systembus(uint32_t address, uint8_t value) +{ + _a2600->console().system().poke(address, value); +} + +ECL_EXPORT uint32_t stella_get_cartram_size() +{ + return _a2600->console().cartridge().internalRamSize(); +} + +ECL_EXPORT uint8_t stella_peek_cartram(uint32_t address) +{ + return _a2600->console().cartridge().peek(address); +} + +ECL_EXPORT void stella_poke_cartram(uint32_t address, uint8_t value) +{ + _a2600->console().cartridge().poke(address, value); +} + +ECL_EXPORT void stella_get_mainram_ptr(void** ptr) +{ + *ptr = (void*) _a2600->console().riot().getRAM(); +} + +ECL_EXPORT void stella_get_audio(int *n, void **buffer) +{ + if (n) + *n = nsamples; + if (buffer) + *buffer = soundbuffer; +} + +ECL_EXPORT void stella_get_video(int& w, int& h, int& pitch, uint8_t*& buffer) +{ + w = _a2600->console().tia().width(); + h = _a2600->console().tia().height(); + buffer = _a2600->console().tia().frameBuffer(); + pitch = _a2600->console().tia().width(); +} + + +ECL_EXPORT void stella_frame_advance(uint8_t port1, uint8_t port2, bool reset, bool power, bool leftDiffToggled, bool rightDiffToggled) +{ + _a2600->console().switches().setLeftDifficultyA(leftDiffToggled); + _a2600->console().switches().setRightDifficultyA(rightDiffToggled); + _a2600->console().switches().setReset(!reset); + if (power) _a2600->console().system().reset(true); + + _a2600->console().leftController().write(::Controller::DigitalPin::One, port1 & 0b00010000); // Up + _a2600->console().leftController().write(::Controller::DigitalPin::Two, port1 & 0b00100000); // Down + _a2600->console().leftController().write(::Controller::DigitalPin::Three, port1 & 0b01000000); // Left + _a2600->console().leftController().write(::Controller::DigitalPin::Four, port1 & 0b10000000); // Right + _a2600->console().leftController().write(::Controller::DigitalPin::Six, port1 & 0b00001000); // Button + + _a2600->console().rightController().write(::Controller::DigitalPin::One, port2 & 0b00010000); // Up + _a2600->console().rightController().write(::Controller::DigitalPin::Two, port2 & 0b00100000); // Down + _a2600->console().rightController().write(::Controller::DigitalPin::Three, port2 & 0b01000000); // Left + _a2600->console().rightController().write(::Controller::DigitalPin::Four, port2 & 0b10000000); // Right + _a2600->console().rightController().write(::Controller::DigitalPin::Six, port2 & 0b00001000); // Button + + nsamples = 0; + _a2600->dispatchEmulation(); + // printRAM(); + // printFrameBuffer(); +} + +ECL_ENTRY void (*input_callback_cb)(void); + +void real_input_callback(void) +{ + if (input_callback_cb) + input_callback_cb(); +} + +ECL_EXPORT void stella_set_input_callback(ECL_ENTRY void (*fecb)(void)) +{ + input_callback_cb = fecb; +} + + +ECL_EXPORT int stella_init( + const char* romFileName, + ECL_ENTRY int (*feload_archive_cb)(const char *filename, unsigned char *buffer, int maxsize), + struct InitSettings *settings) +{ + fprintf(stderr, "Initializing Stella core...\n"); + + // Allocating sound buffer + soundbuffer = (uint16_t*) alloc_invisible(SOUND_BUFFER_SIZE); + + Settings::Options opts; + _a2600 = MediaFactory::createOSystem(); + if(!_a2600->initialize(opts)) { fprintf(stderr, "ERROR: Couldn't create A2600 System\n"); return 0; } + + uint8_t* buf = (uint8_t*) calloc(1, BUFFER_SIZE); + int size = feload_archive_cb("PRIMARY_ROM", buf, BUFFER_SIZE); + const FSNode romnode(romFileName, buf, size); + + auto error = _a2600->createConsole(romnode); + if (error != "") { fprintf(stderr, "ERROR: Couldn't create A2600 Console. Reason: '%s'\n", error.c_str()); return 0; } + + printf("A2600 console created successfully\n"); + + return 1; +} + diff --git a/waterbox/stella/BizhawkInterface.hxx b/waterbox/stella/BizhawkInterface.hxx new file mode 100644 index 00000000000..03d40022558 --- /dev/null +++ b/waterbox/stella/BizhawkInterface.hxx @@ -0,0 +1,8 @@ +#pragma once + +#include +#include +#include + +extern uint16_t* soundbuffer; +extern int nsamples; \ No newline at end of file diff --git a/waterbox/stella/Makefile b/waterbox/stella/Makefile new file mode 100644 index 00000000000..359cc57b720 --- /dev/null +++ b/waterbox/stella/Makefile @@ -0,0 +1,200 @@ +STELLA_DIR := core + +CCFLAGS := \ + -ISDL/include \ + -ISDL/src + +CXXFLAGS := \ + -I. \ + -Iport \ + -Icore/src/emucore \ + -Icore/src/common \ + -Icore/src/common/tv_filters \ + -Icore/src/emucore/tia \ + -Icore/src/emucore/tia/frame-manager \ + -Icore/src/lib/json \ + -Icore/src/common/repository/sqlite \ + -Icore/src/os/unix \ + -Icore/src/gui \ + -Icore/src/lib/httplib \ + -Icore/src/lib/sqlite \ + -ISDL/include/SDL2 \ + -ISDL/include \ + -ISDL/src \ + -DUNIX \ + -DSOUND_SUPPORT \ + -DSDL_ENABLE_OLD_NAMES \ + -D_REENTRANT \ + -D__USE_BIZHAWK \ + -std=gnu++17 \ + -Wno-multichar \ + +LDFLAGS := + +TARGET := stella.wbx + +SRCS = \ + BizhawkInterface.cxx \ + port/EventHandlerBizhawk.cxx \ + port/FBBackendBizhawk.cxx \ + port/FBSurfaceBizhawk.cxx \ + port/OSystemBizhawk.cxx \ + port/SoundBizhawk.cxx \ + core/src/emucore/OSystem.cxx \ + core/src/emucore/Switches.cxx \ + core/src/emucore/FrameBuffer.cxx \ + core/src/emucore/Console.cxx \ + core/src/common/Logger.cxx \ + core/src/common/tv_filters/NTSCFilter.cxx \ + core/src/common/tv_filters/AtariNTSC.cxx \ + core/src/common/AudioSettings.cxx \ + core/src/common/VideoModeHandler.cxx \ + core/src/common/PhysicalJoystick.cxx \ + core/src/common/ThreadDebugging.cxx \ + core/src/common/TimerManager.cxx \ + core/src/common/PKeyboardHandler.cxx \ + core/src/common/PhosphorHandler.cxx \ + core/src/common/JoyMap.cxx \ + core/src/common/ZipHandler.cxx \ + core/src/common/MouseControl.cxx \ + core/src/common/PJoystickHandler.cxx \ + core/src/common/JPGLibrary.cxx \ + core/src/common/AudioQueue.cxx \ + core/src/common/StateManager.cxx \ + core/src/common/DevSettingsHandler.cxx \ + core/src/common/FpsMeter.cxx \ + core/src/common/audio/ConvolutionBuffer.cxx \ + core/src/common/audio/HighPass.cxx \ + core/src/common/audio/SimpleResampler.cxx \ + core/src/common/audio/LanczosResampler.cxx \ + core/src/common/StaggeredLogger.cxx \ + core/src/common/Base.cxx \ + core/src/common/FSNodeZIP.cxx \ + core/src/common/KeyMap.cxx \ + core/src/common/repository/KeyValueRepositoryJsonFile.cxx \ + core/src/common/repository/CompositeKVRJsonAdapter.cxx \ + core/src/common/repository/sqlite/SqliteDatabase.cxx \ + core/src/common/repository/sqlite/SqliteStatement.cxx \ + core/src/common/repository/sqlite/SqliteTransaction.cxx \ + core/src/common/repository/sqlite/AbstractKeyValueRepositorySqlite.cxx \ + core/src/common/repository/sqlite/KeyValueRepositorySqlite.cxx \ + core/src/common/repository/sqlite/StellaDb.cxx \ + core/src/common/repository/sqlite/CompositeKeyValueRepositorySqlite.cxx \ + core/src/common/repository/KeyValueRepositoryPropertyFile.cxx \ + core/src/common/repository/CompositeKeyValueRepository.cxx \ + core/src/common/repository/KeyValueRepositoryConfigfile.cxx \ + core/src/common/Bezel.cxx \ + core/src/common/PNGLibrary.cxx \ + core/src/common/PaletteHandler.cxx \ + core/src/common/RewindManager.cxx \ + core/src/emucore/Genesis.cxx \ + core/src/emucore/Bankswitch.cxx \ + core/src/emucore/Cart03E0.cxx \ + core/src/emucore/CartF0.cxx \ + core/src/emucore/Cart4K.cxx \ + core/src/emucore/CartWD.cxx \ + core/src/emucore/Cart4A50.cxx \ + core/src/emucore/CartBF.cxx \ + core/src/emucore/EmulationWorker.cxx \ + core/src/emucore/CartF6.cxx \ + core/src/emucore/Cart.cxx \ + core/src/emucore/CartF4SC.cxx \ + core/src/emucore/CartCTY.cxx \ + core/src/emucore/CartF8SC.cxx \ + core/src/emucore/CartDetector.cxx \ + core/src/emucore/CartDFSC.cxx \ + core/src/emucore/Serializer.cxx \ + core/src/emucore/Cart0840.cxx \ + core/src/emucore/CartFA.cxx \ + core/src/emucore/CartX07.cxx \ + core/src/emucore/Cart2K.cxx \ + core/src/emucore/Cart3EX.cxx \ + core/src/emucore/CartDPCPlus.cxx \ + core/src/emucore/CartBFSC.cxx \ + core/src/emucore/CartCM.cxx \ + core/src/emucore/CartEF.cxx \ + core/src/emucore/CartSB.cxx \ + core/src/emucore/MD5.cxx \ + core/src/emucore/Settings.cxx \ + core/src/emucore/CartBUS.cxx \ + core/src/emucore/SaveKey.cxx \ + core/src/emucore/CartDPC.cxx \ + core/src/emucore/CompuMate.cxx \ + core/src/emucore/TIASurface.cxx \ + core/src/emucore/Paddles.cxx \ + core/src/emucore/CartEFSC.cxx \ + core/src/emucore/Joystick.cxx \ + core/src/emucore/Lightgun.cxx \ + core/src/emucore/KidVid.cxx \ + core/src/emucore/CartAR.cxx \ + core/src/emucore/CartFC.cxx \ + core/src/emucore/Cart3F.cxx \ + core/src/emucore/FBSurface.cxx \ + core/src/emucore/Cart3E.cxx \ + core/src/emucore/GlobalKeyHandler.cxx \ + core/src/emucore/PointingDevice.cxx \ + core/src/emucore/CartTVBoy.cxx \ + core/src/emucore/CartCreator.cxx \ + core/src/emucore/CartF6SC.cxx \ + core/src/emucore/Cart4KSC.cxx \ + core/src/emucore/Props.cxx \ + core/src/emucore/Thumbulator.cxx \ + core/src/emucore/DispatchResult.cxx \ + core/src/emucore/EmulationTiming.cxx \ + core/src/emucore/PlusROM.cxx \ + core/src/emucore/CartGL.cxx \ + core/src/emucore/Cart0FA0.cxx \ + core/src/emucore/CartMVC.cxx \ + core/src/emucore/Keyboard.cxx \ + core/src/emucore/CartFA2.cxx \ + core/src/emucore/QuadTari.cxx \ + core/src/emucore/CartFE.cxx \ + core/src/emucore/CartMDM.cxx \ + core/src/emucore/CartF4.cxx \ + core/src/emucore/CartF8.cxx \ + core/src/emucore/CartCV.cxx \ + core/src/emucore/EventHandler.cxx \ + core/src/emucore/Driving.cxx \ + core/src/emucore/M6532.cxx \ + core/src/emucore/System.cxx \ + core/src/emucore/M6502.cxx \ + core/src/emucore/Joy2BPlus.cxx \ + core/src/emucore/CartE7.cxx \ + core/src/emucore/OSystemStandalone.cxx \ + core/src/emucore/tia/Player.cxx \ + core/src/emucore/tia/LatchedInput.cxx \ + core/src/emucore/tia/Missile.cxx \ + core/src/emucore/tia/frame-manager/FrameLayoutDetector.cxx \ + core/src/emucore/tia/frame-manager/AbstractFrameManager.cxx \ + core/src/emucore/tia/frame-manager/FrameManager.cxx \ + core/src/emucore/tia/frame-manager/JitterEmulation.cxx \ + core/src/emucore/tia/AnalogReadout.cxx \ + core/src/emucore/tia/Background.cxx \ + core/src/emucore/tia/DrawCounterDecodes.cxx \ + core/src/emucore/tia/TIA.cxx \ + core/src/emucore/tia/Playfield.cxx \ + core/src/emucore/tia/Audio.cxx \ + core/src/emucore/tia/AudioChannel.cxx \ + core/src/emucore/tia/Ball.cxx \ + core/src/emucore/CartARM.cxx \ + core/src/emucore/PropsSet.cxx \ + core/src/emucore/ProfilingRunner.cxx \ + core/src/emucore/CartUA.cxx \ + core/src/emucore/CartE0.cxx \ + core/src/emucore/Booster.cxx \ + core/src/emucore/CartEnhanced.cxx \ + core/src/emucore/FSNode.cxx \ + core/src/emucore/CartCDF.cxx \ + core/src/emucore/ControllerDetector.cxx \ + core/src/emucore/MindLink.cxx \ + core/src/emucore/Cart3EPlus.cxx \ + core/src/emucore/MT24LC256.cxx \ + core/src/emucore/CartDF.cxx \ + core/src/emucore/Control.cxx \ + core/src/emucore/AtariVox.cxx \ + core/src/os/unix/SerialPortUNIX.cxx \ + core/src/lib/tinyexif/tinyexif.cxx \ + core/src/lib/sqlite/sqlite3.c \ + core/src/lib/nanojpeg/nanojpeg.c \ + +include ../common.mak diff --git a/waterbox/stella/core b/waterbox/stella/core new file mode 160000 index 00000000000..48734d5c38c --- /dev/null +++ b/waterbox/stella/core @@ -0,0 +1 @@ +Subproject commit 48734d5c38c12e3988959ebcb6efee4a570268e3 diff --git a/waterbox/stella/port/EventHandlerBizhawk.cxx b/waterbox/stella/port/EventHandlerBizhawk.cxx new file mode 100644 index 00000000000..30ec94ba15c --- /dev/null +++ b/waterbox/stella/port/EventHandlerBizhawk.cxx @@ -0,0 +1,43 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#include "Logger.hxx" +#include "OSystem.hxx" +#include "EventHandlerBizhawk.hxx" + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +EventHandlerBizhawk::EventHandlerBizhawk(OSystem& osystem) + : EventHandler{osystem} +{ + +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +EventHandlerBizhawk::~EventHandlerBizhawk() +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void EventHandlerBizhawk::enableTextEvents(bool enable) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void EventHandlerBizhawk::pollEvent() +{ +} + diff --git a/waterbox/stella/port/EventHandlerBizhawk.hxx b/waterbox/stella/port/EventHandlerBizhawk.hxx new file mode 100644 index 00000000000..16304a859f3 --- /dev/null +++ b/waterbox/stella/port/EventHandlerBizhawk.hxx @@ -0,0 +1,57 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#pragma once + +#include "EventHandler.hxx" + +/** + This class handles event collection from the point of view of the specific + backend toolkit (Bizhawk). It converts from Bizhawk-specific events into events + that the Stella core can understand. + + @author Stephen Anthony +*/ +class EventHandlerBizhawk : public EventHandler +{ + public: + /** + Create a new Bizhawk event handler object + */ + explicit EventHandlerBizhawk(OSystem& osystem); + ~EventHandlerBizhawk() override; + + private: + /** + Enable/disable text events (distinct from single-key events). + */ + void enableTextEvents(bool enable) override; + + /** + Collects and dispatches any pending Bizhawk events. + */ + void pollEvent() override; + + private: + // Following constructors and assignment operators not supported + EventHandlerBizhawk() = delete; + EventHandlerBizhawk(const EventHandlerBizhawk&) = delete; + EventHandlerBizhawk(EventHandlerBizhawk&&) = delete; + EventHandlerBizhawk& operator=(const EventHandlerBizhawk&) = delete; + EventHandlerBizhawk& operator=(EventHandlerBizhawk&&) = delete; +}; + diff --git a/waterbox/stella/port/FBBackendBizhawk.cxx b/waterbox/stella/port/FBBackendBizhawk.cxx new file mode 100644 index 00000000000..6fd8f49f186 --- /dev/null +++ b/waterbox/stella/port/FBBackendBizhawk.cxx @@ -0,0 +1,171 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#include + +#include "bspf.hxx" +#include "Logger.hxx" + +#include "Console.hxx" +#include "OSystem.hxx" +#include "Settings.hxx" + +#include "ThreadDebugging.hxx" +#include "FBSurfaceBizhawk.hxx" +#include "FBBackendBizhawk.hxx" + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +FBBackendBIZHAWK::FBBackendBIZHAWK(OSystem& osystem) + : myOSystem{osystem} +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +FBBackendBIZHAWK::~FBBackendBIZHAWK() +{ + +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBBackendBIZHAWK::queryHardware(vector& fullscreenRes, + vector& windowedRes, + VariantList& renderers) +{ + +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool FBBackendBIZHAWK::isCurrentWindowPositioned() const +{ + return true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Common::Point FBBackendBIZHAWK::getCurrentWindowPos() const +{ + Common::Point pos; + + + return pos; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Int32 FBBackendBIZHAWK::getCurrentDisplayIndex() const +{ + + + return 0; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool FBBackendBIZHAWK::setVideoMode(const VideoModeHandler::Mode& mode, + int winIdx, const Common::Point& winPos) +{ + + return true; +} + + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool FBBackendBIZHAWK::createRenderer(const VideoModeHandler::Mode& mode) +{ + + return true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBBackendBIZHAWK::setTitle(string_view title) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string FBBackendBIZHAWK::about() const +{ + return ""; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBBackendBIZHAWK::showCursor(bool show) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBBackendBIZHAWK::grabMouse(bool grab) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool FBBackendBIZHAWK::fullScreen() const +{ + return true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int FBBackendBIZHAWK::refreshRate() const +{ + return 0; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBBackendBIZHAWK::renderToScreen() +{ + +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBBackendBIZHAWK::setWindowIcon() +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +unique_ptr FBBackendBIZHAWK::createSurface( + uInt32 w, + uInt32 h, + ScalingInterpolation inter, + const uInt32* data +) const +{ + return make_unique + (const_cast(*this), w, h, inter, data); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBBackendBIZHAWK::readPixels(uInt8* buffer, size_t pitch, + const Common::Rect& rect) const +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBBackendBIZHAWK::clear() +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBBackendBIZHAWK::detectFeatures() +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool FBBackendBIZHAWK::detectRenderTargetSupport() +{ + return 0; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBBackendBIZHAWK::determineDimensions() +{ +} diff --git a/waterbox/stella/port/FBBackendBizhawk.hxx b/waterbox/stella/port/FBBackendBizhawk.hxx new file mode 100644 index 00000000000..b189c113cc1 --- /dev/null +++ b/waterbox/stella/port/FBBackendBizhawk.hxx @@ -0,0 +1,273 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#ifndef FB_BACKEND_BIZHAWK_HXX +#define FB_BACKEND_BIZHAWK_HXX + +class OSystem; +class FBSurfaceBIZHAWK; + +#include "bspf.hxx" +#include "FBBackend.hxx" + +/** + This class implements a standard BIZHAWK 2D, hardware accelerated framebuffer + backend. Behind the scenes, it may be using Direct3D, OpenGL(ES), etc. + + @author Stephen Anthony +*/ +class FBBackendBIZHAWK : public FBBackend +{ + public: + /** + Creates a new BIZHAWK framebuffer + */ + explicit FBBackendBIZHAWK(OSystem& osystem); + ~FBBackendBIZHAWK() override; + + public: + + /** + Is the renderer initialized? + */ + bool isInitialized() const { return true; } + + /** + Does the renderer support render targets? + */ + bool hasRenderTargetSupport() const { return true;; } + + /** + Transform from window to renderer coordinates, x direction + */ + int scaleX(int x) const override { return 1; } + + /** + Transform from window to renderer coordinates, y direction + */ + int scaleY(int y) const override { return 1; } + + protected: + /** + Updates window title. + + @param title The title of the application / window + */ + void setTitle(string_view title) override; + + /** + Shows or hides the cursor based on the given boolean value. + */ + void showCursor(bool show) override; + + /** + Answers if the display is currently in fullscreen mode. + */ + bool fullScreen() const override; + + /** + This method is called to retrieve the R/G/B data from the given pixel. + + @param pixel The pixel containing R/G/B data + @param r The red component of the color + @param g The green component of the color + @param b The blue component of the color + */ + FORCE_INLINE void getRGB(uInt32 pixel, uInt8* r, uInt8* g, uInt8* b) const override + { } + + /** + This method is called to retrieve the R/G/B/A data from the given pixel. + + @param pixel The pixel containing R/G/B data + @param r The red component of the color + @param g The green component of the color + @param b The blue component of the color + @param a The alpha component of the color. + */ + FORCE_INLINE void getRGBA(uInt32 pixel, uInt8* r, uInt8* g, uInt8* b, uInt8* a) const override + { } + + /** + This method is called to map a given R/G/B triple to the screen palette. + + @param r The red component of the color. + @param g The green component of the color. + @param b The blue component of the color. + */ + inline uInt32 mapRGB(uInt8 r, uInt8 g, uInt8 b) const override + { return 0; } + + /** + This method is called to map a given R/G/B/A triple to the screen palette. + + @param r The red component of the color. + @param g The green component of the color. + @param b The blue component of the color. + @param a The alpha component of the color. + */ + inline uInt32 mapRGBA(uInt8 r, uInt8 g, uInt8 b, uInt8 a) const override + { return 0; } + + /** + This method is called to get a copy of the specified ARGB data from the + viewable FrameBuffer area. Note that this isn't the same as any + internal surfaces that may be in use; it should return the actual data + as it is currently seen onscreen. + + @param buffer A copy of the pixel data in ARGB8888 format + @param pitch The pitch (in bytes) for the pixel data + @param rect The bounding rectangle for the buffer + */ + void readPixels(uInt8* buffer, size_t pitch, + const Common::Rect& rect) const override; + + /** + This method is called to query if the current window is not centered + or fullscreen. + + @return True, if the current window is positioned + */ + bool isCurrentWindowPositioned() const override; + + /** + This method is called to query the video hardware for position of + the current window + + @return The position of the currently displayed window + */ + Common::Point getCurrentWindowPos() const override; + + /** + This method is called to query the video hardware for the index + of the display the current window is displayed on + + @return the current display index or a negative value if no + window is displayed + */ + Int32 getCurrentDisplayIndex() const override; + + /** + Clear the frame buffer. + */ + void clear() override; + + /** + This method is called to query and initialize the video hardware + for desktop and fullscreen resolution information. Since several + monitors may be attached, we need the resolution for all of them. + + @param fullscreenRes Maximum resolution supported in fullscreen mode + @param windowedRes Maximum resolution supported in windowed mode + @param renderers List of renderer names (internal name -> end-user name) + */ + void queryHardware(vector& fullscreenRes, + vector& windowedRes, + VariantList& renderers) override; + + /** + This method is called to change to the given video mode. + + @param mode The video mode to use + @param winIdx The display/monitor that the window last opened on + @param winPos The position that the window last opened at + + @return False on any errors, else true + */ + bool setVideoMode(const VideoModeHandler::Mode& mode, + int winIdx, const Common::Point& winPos) override; + + /** + This method is called to create a surface with the given attributes. + + @param w The requested width of the new surface. + @param h The requested height of the new surface. + @param inter Interpolation mode + @param data If non-null, use the given data values as a static surface + */ + unique_ptr + createSurface( + uInt32 w, + uInt32 h, + ScalingInterpolation inter, + const uInt32* data + ) const override; + + /** + Grabs or ungrabs the mouse based on the given boolean value. + */ + void grabMouse(bool grab) override; + + /** + This method is called to provide information about the backend. + */ + string about() const override; + + /** + Create a new renderer if required. + + @return False on any errors, else true + */ + bool createRenderer(const VideoModeHandler::Mode& mode); + + /** + This method must be called after all drawing is done, and indicates + that the buffers should be pushed to the physical screen. + */ + void renderToScreen() override; + + /** + Retrieve the current display's refresh rate, or 0 if no window. + */ + int refreshRate() const override; + + /** + After the renderer has been created, detect the features it supports. + */ + void detectFeatures(); + + /** + Detect render target support. + */ + bool detectRenderTargetSupport(); + + /** + Determine window and renderer dimensions. + */ + void determineDimensions(); + + /** + Set the icon for the main SDL window. + */ + void setWindowIcon(); + + private: + OSystem& myOSystem; + + // Center setting of current window + bool myCenter{false}; + + private: + // Following constructors and assignment operators not supported + FBBackendBIZHAWK() = delete; + FBBackendBIZHAWK(const FBBackendBIZHAWK&) = delete; + FBBackendBIZHAWK(FBBackendBIZHAWK&&) = delete; + FBBackendBIZHAWK& operator=(const FBBackendBIZHAWK&) = delete; + FBBackendBIZHAWK& operator=(FBBackendBIZHAWK&&) = delete; +}; + +#endif diff --git a/waterbox/stella/port/FBSurfaceBizhawk.cxx b/waterbox/stella/port/FBSurfaceBizhawk.cxx new file mode 100644 index 00000000000..241f0523e7c --- /dev/null +++ b/waterbox/stella/port/FBSurfaceBizhawk.cxx @@ -0,0 +1,152 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#include "FBSurfaceBizhawk.hxx" + +#include "Logger.hxx" +#include "ThreadDebugging.hxx" + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +FBSurfaceBIZHAWK::FBSurfaceBIZHAWK(FBBackendBIZHAWK& backend, + uInt32 width, uInt32 height, + ScalingInterpolation inter, + const uInt32* staticData) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +FBSurfaceBIZHAWK::~FBSurfaceBIZHAWK() +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBSurfaceBIZHAWK::fillRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h, ColorId color) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt32 FBSurfaceBIZHAWK::width() const +{ + return 0; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt32 FBSurfaceBIZHAWK::height() const +{ + return 0; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const Common::Rect& FBSurfaceBIZHAWK::srcRect() const +{ + Common::Rect a; + return a; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const Common::Rect& FBSurfaceBIZHAWK::dstRect() const +{ + Common::Rect a; + return a; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBSurfaceBIZHAWK::setSrcPos(uInt32 x, uInt32 y) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBSurfaceBIZHAWK::setSrcSize(uInt32 w, uInt32 h) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBSurfaceBIZHAWK::setSrcRect(const Common::Rect& r) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBSurfaceBIZHAWK::setDstPos(uInt32 x, uInt32 y) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBSurfaceBIZHAWK::setDstSize(uInt32 w, uInt32 h) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBSurfaceBIZHAWK::setDstRect(const Common::Rect& r) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBSurfaceBIZHAWK::setVisible(bool visible) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBSurfaceBIZHAWK::translateCoords(Int32& x, Int32& y) const +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool FBSurfaceBIZHAWK::render() +{ + return true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBSurfaceBIZHAWK::invalidate() +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBSurfaceBIZHAWK::invalidateRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBSurfaceBIZHAWK::reload() +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBSurfaceBIZHAWK::resize(uInt32 width, uInt32 height) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBSurfaceBIZHAWK::createSurface(uInt32 width, uInt32 height, + const uInt32* data) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBSurfaceBIZHAWK::reinitializeBlitter(bool force) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBSurfaceBIZHAWK::applyAttributes() +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBSurfaceBIZHAWK::setScalingInterpolation(ScalingInterpolation interpolation) +{ +} diff --git a/waterbox/stella/port/FBSurfaceBizhawk.hxx b/waterbox/stella/port/FBSurfaceBizhawk.hxx new file mode 100644 index 00000000000..33bec5bcf53 --- /dev/null +++ b/waterbox/stella/port/FBSurfaceBizhawk.hxx @@ -0,0 +1,89 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#ifndef FBSURFACE_BIZHAWK_HXX +#define FBSURFACE_BIZHAWK_HXX + +#include "bspf.hxx" +#include "FBSurface.hxx" +#include "FBBackendBizhawk.hxx" + +/** + An FBSurface suitable for the BIZHAWK Render2D API, making use of hardware + acceleration behind the scenes. + + @author Stephen Anthony +*/ +class FBSurfaceBIZHAWK : public FBSurface +{ + public: + FBSurfaceBIZHAWK(FBBackendBIZHAWK& backend, uInt32 width, uInt32 height, + ScalingInterpolation inter, const uInt32* staticData); + ~FBSurfaceBIZHAWK() override; + + // Most of the surface drawing primitives are implemented in FBSurface; + // the ones implemented here use SDL-specific code for extra performance + // + void fillRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h, ColorId color) override; + + uInt32 width() const override; + uInt32 height() const override; + + const Common::Rect& srcRect() const override; + const Common::Rect& dstRect() const override; + void setSrcPos(uInt32 x, uInt32 y) override; + void setSrcSize(uInt32 w, uInt32 h) override; + void setSrcRect(const Common::Rect& r) override; + void setDstPos(uInt32 x, uInt32 y) override; + void setDstSize(uInt32 w, uInt32 h) override; + void setDstRect(const Common::Rect& r) override; + + void setVisible(bool visible) override; + + void translateCoords(Int32& x, Int32& y) const override; + bool render() override; + void invalidate() override; + void invalidateRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h) override; + + void reload() override; + void resize(uInt32 width, uInt32 height) override; + + void setScalingInterpolation(ScalingInterpolation) override; + + protected: + void applyAttributes() override; + + void createSurface(uInt32 width, uInt32 height, const uInt32* data); + + void reinitializeBlitter(bool force = false); + + // Following constructors and assignment operators not supported + FBSurfaceBIZHAWK() = delete; + FBSurfaceBIZHAWK(const FBSurfaceBIZHAWK&) = delete; + FBSurfaceBIZHAWK(FBSurfaceBIZHAWK&&) = delete; + FBSurfaceBIZHAWK& operator=(const FBSurfaceBIZHAWK&) = delete; + FBSurfaceBIZHAWK& operator=(FBSurfaceBIZHAWK&&) = delete; + + private: + + bool myIsVisible{true}; + bool myIsStatic{false}; + + Common::Rect mySrcGUIR, myDstGUIR; +}; + +#endif diff --git a/waterbox/stella/port/OSystemBizhawk.cxx b/waterbox/stella/port/OSystemBizhawk.cxx new file mode 100644 index 00000000000..dac13155b8a --- /dev/null +++ b/waterbox/stella/port/OSystemBizhawk.cxx @@ -0,0 +1,31 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#include + +#include "FSNode.hxx" +#include "OSystemBizhawk.hxx" + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void OSystemBIZHAWK::getBaseDirectories(string& basedir, string& homedir, + bool useappdir, string_view usedir) +{ +} + +void OSystemBIZHAWK::initPersistence(FSNode& basedir) {} + +string OSystemBIZHAWK::describePresistence() { return ""; }; \ No newline at end of file diff --git a/waterbox/stella/port/OSystemBizhawk.hxx b/waterbox/stella/port/OSystemBizhawk.hxx new file mode 100644 index 00000000000..7adc73110e8 --- /dev/null +++ b/waterbox/stella/port/OSystemBizhawk.hxx @@ -0,0 +1,62 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#pragma once + +#include "OSystemStandalone.hxx" + +/** + This class defines an OSystem object for UNIX-like OS's (Linux). + It is responsible for completely implementing getBaseDirectories(), + to set the base directory and various other save/load locations. + + @author Stephen Anthony +*/ +class OSystemBIZHAWK : public OSystemStandalone +{ + public: + OSystemBIZHAWK() = default; + ~OSystemBIZHAWK() override = default; + + /** + Determine the base directory and home directory from the derived + class. It can also use hints, as described below. + + @param basedir The base directory for all configuration files + @param homedir The default directory to store various other files + @param useappdir A hint that the base dir should be set to the + app directory; not all ports can do this, so + they are free to ignore it + @param usedir A hint that the base dir should be set to this + parameter; not all ports can do this, so + they are free to ignore it + */ + void getBaseDirectories(string& basedir, string& homedir, + bool useappdir, string_view usedir) override; + + void initPersistence(FSNode& basedir) override; + + string describePresistence() override; + + private: + // Following constructors and assignment operators not supported + OSystemBIZHAWK(const OSystemBIZHAWK&) = delete; + OSystemBIZHAWK(OSystemBIZHAWK&&) = delete; + OSystemBIZHAWK& operator=(const OSystemBIZHAWK&) = delete; + OSystemBIZHAWK& operator=(OSystemBIZHAWK&&) = delete; +}; + diff --git a/waterbox/stella/port/SoundBizhawk.cxx b/waterbox/stella/port/SoundBizhawk.cxx new file mode 100644 index 00000000000..a44d10c6f3c --- /dev/null +++ b/waterbox/stella/port/SoundBizhawk.cxx @@ -0,0 +1,131 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#ifdef SOUND_SUPPORT + +#include +#include "Logger.hxx" +#include "FrameBuffer.hxx" +#include "OSystem.hxx" +#include "Console.hxx" +#include "AudioQueue.hxx" +#include "EmulationTiming.hxx" +#include "AudioSettings.hxx" +#include "audio/SimpleResampler.hxx" +#include "audio/LanczosResampler.hxx" +#include "ThreadDebugging.hxx" +#include "SoundBizhawk.hxx" + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +SoundBizhawk::SoundBizhawk(OSystem& osystem, AudioSettings& audioSettings) + : Sound{osystem}, + myAudioSettings{audioSettings} +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +SoundBizhawk::~SoundBizhawk() +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void SoundBizhawk::queryHardware(VariantList& devices) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool SoundBizhawk::openDevice() +{ + return true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void SoundBizhawk::setEnabled(bool enable) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void SoundBizhawk::open(shared_ptr audioQueue, + EmulationTiming* emulationTiming) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void SoundBizhawk::mute(bool enable) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void SoundBizhawk::toggleMute() +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool SoundBizhawk::pause(bool enable) +{ + return false; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void SoundBizhawk::setVolume(uInt32 volume) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void SoundBizhawk::adjustVolume(int direction) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string SoundBizhawk::about() const +{ + ostringstream buf; + return buf.str(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void SoundBizhawk::initResampler() +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void SoundBizhawk::callback(void* object, uInt8* stream, int len) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool SoundBizhawk::playWav(const string& fileName, const uInt32 position, + const uInt32 length) +{ + return true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void SoundBizhawk::stopWav() +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt32 SoundBizhawk::wavSize() const +{ + return 0; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + +#endif // SOUND_SUPPORT diff --git a/waterbox/stella/port/SoundBizhawk.hxx b/waterbox/stella/port/SoundBizhawk.hxx new file mode 100644 index 00000000000..82f25bb9460 --- /dev/null +++ b/waterbox/stella/port/SoundBizhawk.hxx @@ -0,0 +1,174 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#ifdef SOUND_SUPPORT + +#ifndef SOUND_SDL2_HXX +#define SOUND_SDL2_HXX + +class OSystem; +class AudioQueue; +class EmulationTiming; +class AudioSettings; +class Resampler; + +#include "bspf.hxx" +#include "Sound.hxx" + +/** + This class implements the sound API for SDL. + + @author Stephen Anthony and Christian Speckner (DirtyHairy) +*/ +class SoundBizhawk : public Sound +{ + public: + /** + Create a new sound object. The init method must be invoked before + using the object. + */ + SoundBizhawk(OSystem& osystem, AudioSettings& audioSettings); + + /** + Destructor + */ + ~SoundBizhawk() override; + + public: + /** + Enables/disables the sound subsystem. + + @param enable Either true or false, to enable or disable the sound system + */ + void setEnabled(bool enable) override; + + /** + Initializes the sound device. This must be called before any + calls are made to derived methods. + */ + void open(shared_ptr audioQueue, + EmulationTiming* emulationTiming) override; + + /** + Sets the sound mute state; sound processing continues. When enabled, + sound volume is 0; when disabled, sound volume returns to previously + set level. + + @param enable Mutes sound if true, unmute if false + */ + void mute(bool enable) override; + + /** + Toggles the sound mute state; sound processing continues. + Switches between mute(true) and mute(false). + */ + void toggleMute() override; + + /** + Set the pause state of the sound object. While paused, sound is + neither played nor processed (ie, the sound subsystem is temporarily + disabled). + + @param enable Pause sound if true, unpause if false + + @return The previous (old) pause state + */ + bool pause(bool enable) override; + + /** + Sets the volume of the sound device to the specified level. The + volume is given as a range from 0 to 100 (0 indicates mute). Values + outside this range indicate that the volume shouldn't be changed at all. + + @param volume The new volume level for the sound device + */ + void setVolume(uInt32 volume) override; + + /** + Adjusts the volume of the sound device based on the given direction. + + @param direction +1 indicates increase, -1 indicates decrease. + */ + void adjustVolume(int direction = 1) override; + + /** + This method is called to provide information about the sound device. + */ + string about() const override; + + /** + Play a WAV file. + + @param fileName The name of the WAV file + @param position The position to start playing + @param length The played length + + @return True if the WAV file can be played, else false + */ + bool playWav(const string& fileName, const uInt32 position = 0, + const uInt32 length = 0) override; + + /** + Stop any currently playing WAV file. + */ + void stopWav() override; + + /** + Get the size of the WAV file which remains to be played. + + @return The remaining number of bytes + */ + uInt32 wavSize() const override; + + private: + /** + This method is called to query the audio devices. + + @param devices List of device names + */ + void queryHardware(VariantList& devices) override; + + /** + The actual sound device is opened only when absolutely necessary. + Typically this will only happen once per program run, but it can also + happen dynamically when changing sample rate and/or fragment size. + */ + bool openDevice(); + + void initResampler(); + + private: + AudioSettings& myAudioSettings; + + // Audio specification structure + static float myVolumeFactor; // Current volume level (0 - 100) + + private: + // Callback functions invoked by the SDL Audio library when it needs data + static void callback(void* object, uInt8* stream, int len); + + // Following constructors and assignment operators not supported + SoundBizhawk() = delete; + SoundBizhawk(const SoundBizhawk&) = delete; + SoundBizhawk(SoundBizhawk&&) = delete; + SoundBizhawk& operator=(const SoundBizhawk&) = delete; + SoundBizhawk& operator=(SoundBizhawk&&) = delete; +}; + +#endif + +#endif // SOUND_SUPPORT