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++; } } }