Essgee.Unity/Assets/Plugins/Essgee/Emulation/Video/SegaGGVDP.cs
2025-01-02 17:55:16 +08:00

121 lines
3.1 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Essgee.EventArguments;
using Essgee.Utilities;
using static Essgee.Emulation.Utilities;
namespace Essgee.Emulation.Video
{
/* Sega 315-5378, Game Gear */
public class SegaGGVDP : SegaSMSVDP
{
protected override int numTotalScanlines => NumTotalScanlinesNtsc;
public override (int X, int Y, int Width, int Height) Viewport => (0, 0, 160, 144);
[StateRequired]
ushort cramLatch;
public SegaGGVDP() : base()
{
cram = new byte[0x40];
}
public override void Reset()
{
base.Reset();
cramLatch = 0x0000;
}
public override void SetRevision(int rev)
{
// TODO: can GG VDP be detected by software? if so, implement diffs as revision
base.SetRevision(rev);
}
protected override void ReconfigureTimings()
{
/* Calculate cycles/line */
clockCyclesPerLine = (int)Math.Round((clockRate / refreshRate) / numTotalScanlines);
/* Create arrays */
screenUsage = new byte[numVisiblePixels * numVisibleScanlines];
outputFramebuffer = new byte[Viewport.Width * Viewport.Height * 4];
/* Update resolution/display timing */
UpdateResolution();
}
protected override void PrepareRenderScreen()
{
OnRenderScreen(new RenderScreenEventArgs(Viewport.Width, Viewport.Height, outputFramebuffer.Clone() as byte[]));
}
private bool ModifyAndVerifyCoordinates(ref int x, ref int y)
{
// TODO: correctly derive from timing/resolution values
x -= 61;
y -= 51;
return x >= 0 && x < Viewport.Width && y >= 0 && y < Viewport.Height;
}
protected override void SetPixel(int y, int x, int palette, int color)
{
if (!ModifyAndVerifyCoordinates(ref x, ref y)) return;
WriteColorToFramebuffer(palette, color, ((y * Viewport.Width) + (x % Viewport.Width)) * 4);
}
protected override void SetPixel(int y, int x, byte b, byte g, byte r)
{
if (!ModifyAndVerifyCoordinates(ref x, ref y)) return;
WriteColorToFramebuffer(b, g, r, ((y * Viewport.Width) + (x % Viewport.Width)) * 4);
}
protected override void WriteColorToFramebuffer(int palette, int color, int address)
{
int cramAddress = ((palette * 32) + (color * 2));
WriteColorToFramebuffer((ushort)(cram[cramAddress + 1] << 8 | cram[cramAddress]), address);
}
protected override void WriteColorToFramebuffer(ushort colorValue, int address)
{
RGB444toBGRA8888(colorValue, ref outputFramebuffer, address);
}
protected override void WriteDataPort(byte value)
{
isSecondControlWrite = false;
readBuffer = value;
switch (codeRegister)
{
case 0x00:
case 0x01:
case 0x02:
vram[addressRegister] = value;
break;
case 0x03:
if ((addressRegister & 0x0001) != 0)
{
cramLatch = (ushort)((cramLatch & 0x00FF) | (value << 8));
cram[(addressRegister & 0x003E) | 0x0000] = (byte)((cramLatch >> 0) & 0xFF);
cram[(addressRegister & 0x003E) | 0x0001] = (byte)((cramLatch >> 8) & 0xFF);
}
else
cramLatch = (ushort)((cramLatch & 0xFF00) | (value << 0));
break;
}
addressRegister++;
}
}
}