BizHawk/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Pizza.cs

170 lines
4.5 KiB
C#

using BizHawk.Common;
using BizHawk.Common.BizInvoke;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Waterbox;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy
{
[CoreAttributes("Pizza Boy", "Davide Berra", true, false, "c7bc6ee376028b3766de8d7a02e60ab794841f45",
"https://github.com/davideberra/emu-pizza/", false)]
public class Pizza : WaterboxCore, IGameboyCommon
{
private LibPizza _pizza;
private readonly bool _sgb;
[CoreConstructor("SGB")]
public Pizza(byte[] rom, CoreComm comm)
: this(rom, comm, true)
{ }
[CoreConstructor("GB")]
public Pizza(CoreComm comm, byte[] rom)
: this(rom, comm, false)
{ }
public Pizza(byte[] rom, CoreComm comm, bool sgb)
: base(comm, new Configuration
{
DefaultWidth = 160,
DefaultHeight = 144,
MaxWidth = 256,
MaxHeight = 224,
MaxSamples = 1024,
DefaultFpsNumerator = TICKSPERSECOND,
DefaultFpsDenominator = TICKSPERFRAME
})
{
if (sgb && (rom[0x143] & 0xc0) == 0xc0)
{
throw new CGBNotSupportedException();
}
_pizza = PreInit<LibPizza>(new PeRunnerOptions
{
Filename = "pizza.wbx",
SbrkHeapSizeKB = 128,
InvisibleHeapSizeKB = 16,
SealedHeapSizeKB = 5 * 1024,
PlainHeapSizeKB = 16,
MmapHeapSizeKB = 0
});
var spc = sgb
? Util.DecompressGzipFile(new MemoryStream(Properties.Resources.SgbCartPresent_SPC))
: new byte[0];
_sgb = sgb;
if (!_pizza.Init(rom, rom.Length, _sgb, spc, spc.Length))
{
throw new InvalidOperationException("Core rejected the rom!");
}
PostInit();
if (_sgb)
{
VsyncNumerator = TICKSPERSECOND_SGB;
BufferWidth = 256;
BufferHeight = 224;
}
InitializeRtc(new DateTime(2010, 1, 1)); // TODO: connect to syncsettings
Console.WriteLine("Pizza Initialized: CGB {0} SGB {1}", IsCGBMode(), IsSGBMode());
}
/// <summary>
/// the nominal length of one frame
/// </summary>
private const int TICKSPERFRAME = 35112;
/// <summary>
/// number of ticks per second (GB, CGB)
/// </summary>
private const int TICKSPERSECOND = 2097152;
/// <summary>
/// number of ticks per second (SGB)
/// </summary>
private const int TICKSPERSECOND_SGB = 2147727;
#region Controller
private static readonly ControllerDefinition _gbDefinition;
private static readonly ControllerDefinition _sgbDefinition;
public override ControllerDefinition ControllerDefinition => _sgb ? _sgbDefinition : _gbDefinition;
private static ControllerDefinition CreateControllerDefinition(int p)
{
var ret = new ControllerDefinition { Name = "Gameboy Controller" };
for (int i = 0; i < p; i++)
{
ret.BoolButtons.AddRange(
new[] { "Up", "Down", "Left", "Right", "A", "B", "Select", "Start" }
.Select(s => $"P{i + 1} {s}"));
}
return ret;
}
static Pizza()
{
_gbDefinition = CreateControllerDefinition(1);
_sgbDefinition = CreateControllerDefinition(4);
}
private LibPizza.Buttons GetButtons(IController c)
{
LibPizza.Buttons b = 0;
for (int i = _sgb ? 4 : 1; i > 0; i--)
{
if (c.IsPressed($"P{i} Up"))
b |= LibPizza.Buttons.UP;
if (c.IsPressed($"P{i} Down"))
b |= LibPizza.Buttons.DOWN;
if (c.IsPressed($"P{i} Left"))
b |= LibPizza.Buttons.LEFT;
if (c.IsPressed($"P{i} Right"))
b |= LibPizza.Buttons.RIGHT;
if (c.IsPressed($"P{i} A"))
b |= LibPizza.Buttons.A;
if (c.IsPressed($"P{i} B"))
b |= LibPizza.Buttons.B;
if (c.IsPressed($"P{i} Select"))
b |= LibPizza.Buttons.SELECT;
if (c.IsPressed($"P{i} Start"))
b |= LibPizza.Buttons.START;
if (i != 1)
b = (LibPizza.Buttons)((uint)b << 8);
}
return b;
}
#endregion
LibPizza.FrameInfo _tmp; // TODO: clean this up so it's not so hacky
protected override LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller, bool render, bool rendersound)
{
return _tmp = new LibPizza.FrameInfo
{
Time = GetRtcTime(false),
Keys = GetButtons(controller)
};
}
protected override void FrameAdvancePost()
{
//Console.WriteLine(_tmp.Cycles);
_tmp = null;
}
public bool IsCGBMode() => _pizza.IsCGB();
public bool IsSGBMode() => _sgb;
public override string SystemId => _sgb ? "SGB" : "GB";
}
}