GB Printer support for Gambatte, output color improvements
This commit is contained in:
parent
148e40b504
commit
200ab8f8d8
|
@ -19,10 +19,10 @@ namespace BizHawk.Client.EmuHawk
|
||||||
{
|
{
|
||||||
const int PaperWidth = 160;
|
const int PaperWidth = 160;
|
||||||
|
|
||||||
// the lightest color
|
// the bg color
|
||||||
private static readonly uint PaperColor = (uint)Color.AntiqueWhite.ToArgb();
|
private static readonly uint PaperColor = (uint)Color.AntiqueWhite.ToArgb();
|
||||||
// the darkest color
|
|
||||||
private static readonly uint InkColor = (uint)Color.DarkSlateGray.ToArgb();
|
private ColorMatrix PaperAdjustment;
|
||||||
|
|
||||||
[RequiredService]
|
[RequiredService]
|
||||||
public IGameboyCommon Gb { get; private set; }
|
public IGameboyCommon Gb { get; private set; }
|
||||||
|
@ -37,6 +37,15 @@ namespace BizHawk.Client.EmuHawk
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
// adjust the color of the printed output to be more papery
|
||||||
|
PaperAdjustment = new ColorMatrix();
|
||||||
|
PaperAdjustment.Matrix00 = (0xFA - 0x10) / 255F;
|
||||||
|
PaperAdjustment.Matrix40 = 0x10 / 255F;
|
||||||
|
PaperAdjustment.Matrix11 = (0xEB - 0x10) / 255F;
|
||||||
|
PaperAdjustment.Matrix41 = 0x10 / 255F;
|
||||||
|
PaperAdjustment.Matrix22 = (0xD7 - 0x18) / 255F;
|
||||||
|
PaperAdjustment.Matrix42 = 0x18 / 255F;
|
||||||
|
|
||||||
paperView.ChangeBitmapSize(PaperWidth, PaperWidth);
|
paperView.ChangeBitmapSize(PaperWidth, PaperWidth);
|
||||||
|
|
||||||
ClearPaper();
|
ClearPaper();
|
||||||
|
@ -87,7 +96,6 @@ namespace BizHawk.Client.EmuHawk
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void OnPrint(IntPtr image, byte height, byte topMargin, byte bottomMargin, byte exposure)
|
void OnPrint(IntPtr image, byte height, byte topMargin, byte bottomMargin, byte exposure)
|
||||||
{
|
{
|
||||||
return;
|
|
||||||
// In this implementation:
|
// In this implementation:
|
||||||
// the bottom margin and top margin are just white lines at the top and bottom
|
// the bottom margin and top margin are just white lines at the top and bottom
|
||||||
// exposure is ignored
|
// exposure is ignored
|
||||||
|
@ -112,12 +120,18 @@ namespace BizHawk.Client.EmuHawk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
page.UnlockBits(bmp);
|
||||||
|
|
||||||
// add it to the bottom of the history
|
// add it to the bottom of the history
|
||||||
int oldHeight = printerHistory.Height;
|
int oldHeight = printerHistory.Height;
|
||||||
ResizeHistory(printerHistory.Height + page.Height + topMargin + bottomMargin);
|
ResizeHistory(printerHistory.Height + page.Height + topMargin + bottomMargin);
|
||||||
using (var g = Graphics.FromImage(printerHistory))
|
using (var g = Graphics.FromImage(printerHistory))
|
||||||
{
|
{
|
||||||
g.DrawImage(page, new Point(0, oldHeight + topMargin));
|
// Make it brown
|
||||||
|
ImageAttributes a = new ImageAttributes();
|
||||||
|
a.SetColorMatrix(PaperAdjustment);
|
||||||
|
|
||||||
|
g.DrawImage(page, new Rectangle(0, oldHeight + topMargin, page.Width, page.Height), 0F, 0F, page.Width, page.Height, GraphicsUnit.Pixel, a);
|
||||||
g.Flush();
|
g.Flush();
|
||||||
}
|
}
|
||||||
RefreshView();
|
RefreshView();
|
||||||
|
@ -159,7 +173,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
printerHistory = newHistory;
|
printerHistory = newHistory;
|
||||||
|
|
||||||
// Update scrollbar, viewport is a square
|
// Update scrollbar, viewport is a square
|
||||||
paperScroll.Maximum = Math.Max(0, PaperWidth - height);
|
paperScroll.Maximum = Math.Max(0, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RefreshView()
|
void RefreshView()
|
||||||
|
@ -167,7 +181,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
using (Graphics g = Graphics.FromImage(paperView.BMP))
|
using (Graphics g = Graphics.FromImage(paperView.BMP))
|
||||||
{
|
{
|
||||||
g.Clear(Color.FromArgb((int)PaperColor));
|
g.Clear(Color.FromArgb((int)PaperColor));
|
||||||
g.DrawImage(printerHistory, new Point(0, paperScroll.Value));
|
g.DrawImage(printerHistory, new Point(0, -paperScroll.Value));
|
||||||
g.Flush();
|
g.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -512,6 +512,7 @@
|
||||||
<Compile Include="Consoles\Nintendo\Gameboy\GambatteLink.IVideoProvider.cs">
|
<Compile Include="Consoles\Nintendo\Gameboy\GambatteLink.IVideoProvider.cs">
|
||||||
<DependentUpon>GambatteLink.cs</DependentUpon>
|
<DependentUpon>GambatteLink.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Consoles\Nintendo\Gameboy\GambattePrinter.cs" />
|
||||||
<Compile Include="Consoles\Nintendo\Gameboy\GamebatteLink.ISoundProvider.cs">
|
<Compile Include="Consoles\Nintendo\Gameboy\GamebatteLink.ISoundProvider.cs">
|
||||||
<DependentUpon>GambatteLink.cs</DependentUpon>
|
<DependentUpon>GambatteLink.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|
|
@ -497,6 +497,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GambattePrinter printer;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// set up Printer callback
|
/// set up Printer callback
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -508,7 +510,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
return; // not sure how this is being reached. tried the debugger...
|
return; // not sure how this is being reached. tried the debugger...
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this
|
if (callback != null)
|
||||||
|
{
|
||||||
|
printer = new GambattePrinter(this, callback);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printer.Disconnect();
|
||||||
|
printer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LibGambatte.ScanlineCallback scanlinecb;
|
LibGambatte.ScanlineCallback scanlinecb;
|
||||||
|
|
|
@ -0,0 +1,314 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy;
|
||||||
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
|
namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Emulate the gameboy printer in managed code
|
||||||
|
/// </summary>
|
||||||
|
public class GambattePrinter
|
||||||
|
{
|
||||||
|
// A loose c->c# port of SameBoy's printer code
|
||||||
|
|
||||||
|
enum CommandState : byte
|
||||||
|
{
|
||||||
|
GB_PRINTER_COMMAND_MAGIC1,
|
||||||
|
GB_PRINTER_COMMAND_MAGIC2,
|
||||||
|
GB_PRINTER_COMMAND_ID,
|
||||||
|
GB_PRINTER_COMMAND_COMPRESSION,
|
||||||
|
GB_PRINTER_COMMAND_LENGTH_LOW,
|
||||||
|
GB_PRINTER_COMMAND_LENGTH_HIGH,
|
||||||
|
GB_PRINTER_COMMAND_DATA,
|
||||||
|
GB_PRINTER_COMMAND_CHECKSUM_LOW,
|
||||||
|
GB_PRINTER_COMMAND_CHECKSUM_HIGH,
|
||||||
|
GB_PRINTER_COMMAND_ACTIVE,
|
||||||
|
GB_PRINTER_COMMAND_STATUS,
|
||||||
|
}
|
||||||
|
enum CommandID : byte
|
||||||
|
{
|
||||||
|
GB_PRINTER_INIT_COMMAND = 1,
|
||||||
|
GB_PRINTER_START_COMMAND = 2,
|
||||||
|
GB_PRINTER_DATA_COMMAND = 4,
|
||||||
|
GB_PRINTER_NOP_COMMAND = 0xF,
|
||||||
|
}
|
||||||
|
|
||||||
|
const int GB_PRINTER_MAX_COMMAND_LENGTH = 0x280;
|
||||||
|
const int GB_PRINTER_DATA_SIZE = 0x280;
|
||||||
|
|
||||||
|
const ushort SerialIRQAddress = 0x58;
|
||||||
|
|
||||||
|
Gameboy gb;
|
||||||
|
PrinterCallback callback;
|
||||||
|
LibGambatte.LinkCallback linkCallback;
|
||||||
|
|
||||||
|
CommandState command_state;
|
||||||
|
CommandID command_id;
|
||||||
|
|
||||||
|
bool compression;
|
||||||
|
ushort length_left;
|
||||||
|
byte[] command_data = new byte[GB_PRINTER_MAX_COMMAND_LENGTH];
|
||||||
|
ushort command_length;
|
||||||
|
ushort checksum;
|
||||||
|
byte status;
|
||||||
|
|
||||||
|
byte[] image = new byte[160 * 200];
|
||||||
|
ushort image_offset;
|
||||||
|
|
||||||
|
byte compression_run_lenth;
|
||||||
|
bool compression_run_is_compressed;
|
||||||
|
|
||||||
|
public GambattePrinter(Gameboy gb, PrinterCallback callback)
|
||||||
|
{
|
||||||
|
this.gb = gb;
|
||||||
|
this.callback = callback;
|
||||||
|
|
||||||
|
linkCallback = OnSerial;
|
||||||
|
LibGambatte.gambatte_setlinkcallback(gb.GambatteState, linkCallback);
|
||||||
|
|
||||||
|
// connect the cable
|
||||||
|
LibGambatte.gambatte_linkstatus(gb.GambatteState, 259);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Disconnect()
|
||||||
|
{
|
||||||
|
if (gb.GambatteState != IntPtr.Zero)
|
||||||
|
LibGambatte.gambatte_setlinkcallback(gb.GambatteState, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnSerial()
|
||||||
|
{
|
||||||
|
if (LibGambatte.gambatte_linkstatus(gb.GambatteState, 256) != 0) // ClockTrigger
|
||||||
|
{
|
||||||
|
LibGambatte.gambatte_linkstatus(gb.GambatteState, 257); // ack
|
||||||
|
|
||||||
|
byte output = HandleSerial((byte)LibGambatte.gambatte_linkstatus(gb.GambatteState, 258)); // GetOut
|
||||||
|
LibGambatte.gambatte_linkstatus(gb.GambatteState, output); // ShiftIn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
byte HandleSerial(byte byte_received)
|
||||||
|
{
|
||||||
|
byte byte_to_send = 0;
|
||||||
|
|
||||||
|
switch (command_state)
|
||||||
|
{
|
||||||
|
case CommandState.GB_PRINTER_COMMAND_MAGIC1:
|
||||||
|
if (byte_received != 0x88)
|
||||||
|
{
|
||||||
|
return byte_to_send;
|
||||||
|
}
|
||||||
|
status &= 254;
|
||||||
|
command_length = 0;
|
||||||
|
checksum = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CommandState.GB_PRINTER_COMMAND_MAGIC2:
|
||||||
|
if (byte_received != 0x33)
|
||||||
|
{
|
||||||
|
if (byte_received != 0x88)
|
||||||
|
{
|
||||||
|
command_state = CommandState.GB_PRINTER_COMMAND_MAGIC1;
|
||||||
|
}
|
||||||
|
return byte_to_send;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CommandState.GB_PRINTER_COMMAND_ID:
|
||||||
|
command_id = (CommandID)(byte_received & 0xF);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CommandState.GB_PRINTER_COMMAND_COMPRESSION:
|
||||||
|
compression = (byte_received & 1) != 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CommandState.GB_PRINTER_COMMAND_LENGTH_LOW:
|
||||||
|
length_left = byte_received;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CommandState.GB_PRINTER_COMMAND_LENGTH_HIGH:
|
||||||
|
length_left |= (ushort)((byte_received & 3) << 8);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CommandState.GB_PRINTER_COMMAND_DATA:
|
||||||
|
if (command_length != GB_PRINTER_MAX_COMMAND_LENGTH)
|
||||||
|
{
|
||||||
|
if (compression)
|
||||||
|
{
|
||||||
|
if (compression_run_lenth == 0)
|
||||||
|
{
|
||||||
|
compression_run_is_compressed = (byte_received & 0x80) != 0;
|
||||||
|
compression_run_lenth = (byte)((byte_received & 0x7F) + 1 + (compression_run_is_compressed ? 1 : 0));
|
||||||
|
}
|
||||||
|
else if (compression_run_is_compressed)
|
||||||
|
{
|
||||||
|
while (compression_run_lenth > 0)
|
||||||
|
{
|
||||||
|
command_data[command_length++] = byte_received;
|
||||||
|
compression_run_lenth--;
|
||||||
|
if (command_length == GB_PRINTER_MAX_COMMAND_LENGTH)
|
||||||
|
{
|
||||||
|
compression_run_lenth = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
command_data[command_length++] = byte_received;
|
||||||
|
compression_run_lenth--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
command_data[command_length++] = byte_received;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
length_left--;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CommandState.GB_PRINTER_COMMAND_CHECKSUM_LOW:
|
||||||
|
checksum ^= byte_received;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CommandState.GB_PRINTER_COMMAND_CHECKSUM_HIGH:
|
||||||
|
checksum ^= (ushort)(byte_received << 8);
|
||||||
|
if (checksum != 0)
|
||||||
|
{
|
||||||
|
status |= 1; /* Checksum error*/
|
||||||
|
command_state = CommandState.GB_PRINTER_COMMAND_MAGIC1;
|
||||||
|
return byte_to_send;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CommandState.GB_PRINTER_COMMAND_ACTIVE:
|
||||||
|
byte_to_send = 0x81;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CommandState.GB_PRINTER_COMMAND_STATUS:
|
||||||
|
|
||||||
|
if (((int)command_id & 0xF) == (byte)CommandID.GB_PRINTER_INIT_COMMAND)
|
||||||
|
{
|
||||||
|
/* Games expect INIT commands to return 0? */
|
||||||
|
byte_to_send = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
byte_to_send = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Printing is done instantly, but let the game recieve a 6 (Printing) status at least once, for compatibility */
|
||||||
|
if (status == 6)
|
||||||
|
{
|
||||||
|
status = 4; /* Done */
|
||||||
|
}
|
||||||
|
|
||||||
|
command_state = CommandState.GB_PRINTER_COMMAND_MAGIC1;
|
||||||
|
HandleCommand();
|
||||||
|
return byte_to_send;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command_state >= CommandState.GB_PRINTER_COMMAND_ID && command_state < CommandState.GB_PRINTER_COMMAND_CHECKSUM_LOW)
|
||||||
|
{
|
||||||
|
checksum += byte_received;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command_state != CommandState.GB_PRINTER_COMMAND_DATA)
|
||||||
|
{
|
||||||
|
command_state++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command_state == CommandState.GB_PRINTER_COMMAND_DATA)
|
||||||
|
{
|
||||||
|
if (length_left == 0)
|
||||||
|
{
|
||||||
|
command_state++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return byte_to_send;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleCommand()
|
||||||
|
{
|
||||||
|
switch (command_id)
|
||||||
|
{
|
||||||
|
case CommandID.GB_PRINTER_INIT_COMMAND:
|
||||||
|
status = 0;
|
||||||
|
image_offset = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CommandID.GB_PRINTER_START_COMMAND:
|
||||||
|
if (command_length == 4)
|
||||||
|
{
|
||||||
|
status = 6; /* Printing */
|
||||||
|
uint[] outputImage = new uint[image_offset];
|
||||||
|
|
||||||
|
int palette = command_data[2];
|
||||||
|
uint[] colors = new uint[] {
|
||||||
|
0xFFFFFFFFU,
|
||||||
|
0xFFAAAAAAU,
|
||||||
|
0xFF555555U,
|
||||||
|
0xFF000000U
|
||||||
|
};
|
||||||
|
for (int i = 0; i < image_offset; i++)
|
||||||
|
{
|
||||||
|
outputImage[i] = colors[(palette >> (image[i] * 2)) & 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callback != null)
|
||||||
|
{
|
||||||
|
// The native-friendly callback almost seems silly now :P
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (uint* imagePtr = outputImage)
|
||||||
|
{
|
||||||
|
callback((IntPtr)imagePtr, (byte)(image_offset / 160),
|
||||||
|
(byte)(command_data[1] >> 4), (byte)(command_data[1] & 7),
|
||||||
|
(byte)(command_data[3] & 0x7F));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
image_offset = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CommandID.GB_PRINTER_DATA_COMMAND:
|
||||||
|
if (command_length == GB_PRINTER_DATA_SIZE)
|
||||||
|
{
|
||||||
|
image_offset %= (ushort)image.Length;
|
||||||
|
status = 8; /* Received 0x280 bytes */
|
||||||
|
|
||||||
|
int data_index = 0;
|
||||||
|
|
||||||
|
for (int row = 2; row > 0; row--)
|
||||||
|
{
|
||||||
|
for (int tile_x = 0; tile_x < 160 / 8; tile_x++)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < 8; y++, data_index += 2)
|
||||||
|
{
|
||||||
|
for (int x_pixel = 0; x_pixel < 8; x_pixel++)
|
||||||
|
{
|
||||||
|
image[image_offset + tile_x * 8 + x_pixel + y * 160] =
|
||||||
|
(byte)((command_data[data_index] >> 7) | ((command_data[data_index + 1] >> 7) << 1));
|
||||||
|
command_data[data_index] <<= 1;
|
||||||
|
command_data[data_index + 1] <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
image_offset += 8 * 160;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -265,6 +265,20 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||||
public static extern void gambatte_setrtccallback(IntPtr core, RTCCallback callback);
|
public static extern void gambatte_setrtccallback(IntPtr core, RTCCallback callback);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// type of the link data sent callback
|
||||||
|
/// </summary>
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void LinkCallback();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// sets the Link data sent callback.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="core">opaque state pointer</param>
|
||||||
|
/// <param name="callback">the callback</param>
|
||||||
|
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void gambatte_setlinkcallback(IntPtr core, LinkCallback callback);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns true if the currently loaded ROM image is treated as having CGB support.
|
/// Returns true if the currently loaded ROM image is treated as having CGB support.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -110,6 +110,7 @@ public:
|
||||||
void setTraceCallback(void (*callback)(void *));
|
void setTraceCallback(void (*callback)(void *));
|
||||||
void setScanlineCallback(void (*callback)(), int sl);
|
void setScanlineCallback(void (*callback)(), int sl);
|
||||||
void setRTCCallback(std::uint32_t (*callback)());
|
void setRTCCallback(std::uint32_t (*callback)());
|
||||||
|
void setLinkCallback(void (*callback)());
|
||||||
|
|
||||||
/** Returns true if the currently loaded ROM image is treated as having CGB support. */
|
/** Returns true if the currently loaded ROM image is treated as having CGB support. */
|
||||||
bool isCgb() const;
|
bool isCgb() const;
|
||||||
|
|
|
@ -109,6 +109,11 @@ GBEXPORT void gambatte_setrtccallback(GB *g, unsigned int (*callback)())
|
||||||
g->setRTCCallback(callback);
|
g->setRTCCallback(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GBEXPORT void gambatte_setlinkcallback(GB *g, void (*callback)())
|
||||||
|
{
|
||||||
|
g->setLinkCallback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
GBEXPORT int gambatte_iscgb(GB *g)
|
GBEXPORT int gambatte_iscgb(GB *g)
|
||||||
{
|
{
|
||||||
return g->isCgb();
|
return g->isCgb();
|
||||||
|
|
|
@ -96,6 +96,10 @@ public:
|
||||||
memory.setRTCCallback(callback);
|
memory.setRTCCallback(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setLinkCallback(void (*callback)()) {
|
||||||
|
memory.setLinkCallback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
void reset_bios(int setting) {
|
void reset_bios(int setting) {
|
||||||
memory.bios_reset(setting);
|
memory.bios_reset(setting);
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,6 +141,10 @@ void GB::setRTCCallback(std::uint32_t (*callback)()) {
|
||||||
p_->cpu.setRTCCallback(callback);
|
p_->cpu.setRTCCallback(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GB::setLinkCallback(void(*callback)()) {
|
||||||
|
p_->cpu.setLinkCallback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
int GB::load(const char *romfiledata, unsigned romfilelength, const char *biosfiledata, unsigned biosfilelength, const std::uint32_t now, const unsigned flags) {
|
int GB::load(const char *romfiledata, unsigned romfilelength, const char *biosfiledata, unsigned biosfilelength, const std::uint32_t now, const unsigned flags) {
|
||||||
//if (p_->cpu.loaded())
|
//if (p_->cpu.loaded())
|
||||||
// p_->cpu.saveSavedata();
|
// p_->cpu.saveSavedata();
|
||||||
|
|
|
@ -29,6 +29,7 @@ Memory::Memory(const Interrupter &interrupter_in)
|
||||||
writeCallback(0),
|
writeCallback(0),
|
||||||
execCallback(0),
|
execCallback(0),
|
||||||
cdCallback(0),
|
cdCallback(0),
|
||||||
|
linkCallback(0),
|
||||||
getInput(0),
|
getInput(0),
|
||||||
divLastUpdate(0),
|
divLastUpdate(0),
|
||||||
lastOamDmaUpdate(DISABLED_TIME),
|
lastOamDmaUpdate(DISABLED_TIME),
|
||||||
|
@ -123,6 +124,8 @@ void Memory::updateSerial(const unsigned long cc) {
|
||||||
if (intreq.eventTime(SERIAL) <= cc) {
|
if (intreq.eventTime(SERIAL) <= cc) {
|
||||||
linkClockTrigger = true;
|
linkClockTrigger = true;
|
||||||
intreq.setEventTime<SERIAL>(DISABLED_TIME);
|
intreq.setEventTime<SERIAL>(DISABLED_TIME);
|
||||||
|
if (linkCallback)
|
||||||
|
linkCallback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ class Memory {
|
||||||
void (*writeCallback)(unsigned);
|
void (*writeCallback)(unsigned);
|
||||||
void (*execCallback)(unsigned);
|
void (*execCallback)(unsigned);
|
||||||
CDCallback cdCallback;
|
CDCallback cdCallback;
|
||||||
|
void (*linkCallback)();
|
||||||
|
|
||||||
unsigned (*getInput)();
|
unsigned (*getInput)();
|
||||||
unsigned long divLastUpdate;
|
unsigned long divLastUpdate;
|
||||||
|
@ -275,6 +276,10 @@ public:
|
||||||
cart.setRTCCallback(callback);
|
cart.setRTCCallback(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setLinkCallback(void (*callback)()) {
|
||||||
|
this->linkCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
void setEndtime(unsigned long cc, unsigned long inc);
|
void setEndtime(unsigned long cc, unsigned long inc);
|
||||||
|
|
||||||
void setSoundBuffer(uint_least32_t *const buf) { sound.setBuffer(buf); }
|
void setSoundBuffer(uint_least32_t *const buf) { sound.setBuffer(buf); }
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue