diff --git a/Assets/Plugins/StoicGooseUnity/AxiMemory.cs b/Assets/Plugins/StoicGooseUnity/AxiMemory.cs new file mode 100644 index 0000000..b11d0a5 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/AxiMemory.cs @@ -0,0 +1,180 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; + +namespace StoicGooseUnity +{ + public static class StoicGooseUnityAxiMem + { + public static void Init() => AxiMemoryEx.Init(); + public static void FreeAllGCHandle() => AxiMemoryEx.FreeAllGCHandle(); + } + internal unsafe static class AxiMemoryEx + { + static HashSet GCHandles = new HashSet(); + + public static void Init() + { + FreeAllGCHandle(); + set_TempBuffer = new byte[0x100000]; + } + + public static void GetObjectPtr(this object srcObj, ref GCHandle handle, ref uint* ptr) + { + GetObjectPtr(srcObj, ref handle, out IntPtr intptr); + ptr = (uint*)intptr; + } + + public static void GetObjectPtr(this object srcObj, ref GCHandle handle, ref short* ptr) + { + GetObjectPtr(srcObj, ref handle, out IntPtr intptr); + ptr = (short*)intptr; + } + public static void GetObjectPtr(this object srcObj, ref GCHandle handle, ref ushort* ptr) + { + GetObjectPtr(srcObj, ref handle, out IntPtr intptr); + ptr = (ushort*)intptr; + } + public static void GetObjectPtr(this object srcObj, ref GCHandle handle, ref int* ptr) + { + GetObjectPtr(srcObj, ref handle, out IntPtr intptr); + ptr = (int*)intptr; + } + public static void GetObjectPtr(this object srcObj, ref GCHandle handle, ref byte* ptr) + { + GetObjectPtr(srcObj, ref handle, out IntPtr intptr); + ptr = (byte*)intptr; + } + + public static void GetObjectPtr(this object srcObj, ref GCHandle handle, ref byte* ptr, out IntPtr intptr) + { + GetObjectPtr(srcObj, ref handle, out intptr); + ptr = (byte*)intptr; + } + + static void GetObjectPtr(this object srcObj, ref GCHandle handle, out IntPtr intptr) + { + ReleaseGCHandle(ref handle); + handle = GCHandle.Alloc(srcObj, GCHandleType.Pinned); + GCHandles.Add(handle); + intptr = handle.AddrOfPinnedObject(); + } + + public static void ReleaseGCHandle(this ref GCHandle handle) + { + if (handle.IsAllocated) + handle.Free(); + GCHandles.Remove(handle); + } + + public static void FreeAllGCHandle() + { + foreach (var handle in GCHandles) + { + if (handle.IsAllocated) + handle.Free(); + } + GCHandles.Clear(); + } + + #region 指针化 TempBuffer + static byte[] TempBuffer_src; + static GCHandle TempBuffer_handle; + public static byte* TempBuffer; + public static byte[] set_TempBuffer + { + set + { + TempBuffer_handle.ReleaseGCHandle(); + if (value == null) + return; + TempBuffer_src = value; + TempBuffer_src.GetObjectPtr(ref TempBuffer_handle, ref TempBuffer); + } + } + #endregion + + public static void Write(this BinaryWriter bw, byte* bufferPtr, int offset, int count) + { + // 使用指针复制数据到临时数组 + Buffer.MemoryCopy(bufferPtr + offset, TempBuffer, 0, count); + // 使用BinaryWriter写入临时数组 + bw.Write(TempBuffer_src, 0, count); + } + public static void Write(this FileStream fs, byte* bufferPtr, int offset, int count) + { + // 使用指针复制数据到临时数组 + Buffer.MemoryCopy(bufferPtr + offset, TempBuffer, 0, count); + // 使用BinaryWriter写入临时数组 + fs.Write(TempBuffer_src, 0, count); + } + public static int Read(this FileStream fs, byte* bufferPtr, int offset, int count) + { + // 使用BinaryWriter写入临时数组 + count = fs.Read(TempBuffer_src, offset, count); + // 使用指针复制数据到临时数组 + Buffer.MemoryCopy(TempBuffer, bufferPtr + offset, 0, count); + return count; + } + } + + internal unsafe static class AxiArray + { + + public static void Copy(byte* src, int srcindex, byte* target, int targetindex, int count) + { + int singlesize = sizeof(byte); + long totalBytesToCopy = count * singlesize; + Buffer.MemoryCopy(&src[srcindex], &target[targetindex], totalBytesToCopy, totalBytesToCopy); + } + public static void Copy(short* src, int srcindex, short* target, int targetindex, int count) + { + int singlesize = sizeof(short); + long totalBytesToCopy = count * singlesize; + Buffer.MemoryCopy(&src[srcindex], &target[targetindex], totalBytesToCopy, totalBytesToCopy); + } + public static void Copy(ushort* src, int srcindex, ushort* target, int targetindex, int count) + { + int singlesize = sizeof(ushort); + long totalBytesToCopy = count * singlesize; + Buffer.MemoryCopy(&src[srcindex], &target[targetindex], totalBytesToCopy, totalBytesToCopy); + } + + public static void Copy(byte* src, byte* target, int index, int count) + { + int singlesize = sizeof(byte); + long totalBytesToCopy = count * singlesize; + Buffer.MemoryCopy(&src[index], &target[index], totalBytesToCopy, totalBytesToCopy); + } + + public static void Copy(ushort* src, ushort* target, int index, int count) + { + int singlesize = sizeof(ushort); + long totalBytesToCopy = count * singlesize; + Buffer.MemoryCopy(&src[index], &target[index], totalBytesToCopy, totalBytesToCopy); + } + public static void Copy(ushort* src, ushort* target, int count) + { + int singlesize = sizeof(ushort); + long totalBytesToCopy = count * singlesize; + Buffer.MemoryCopy(src, target, totalBytesToCopy, totalBytesToCopy); + } + public static void Copy(byte* src, byte* target, int count) + { + int singlesize = sizeof(byte); + long totalBytesToCopy = count * singlesize; + Buffer.MemoryCopy(src, target, totalBytesToCopy, totalBytesToCopy); + } + public static void Clear(byte* data, int index, int lenght) + { + for (int i = index; i < lenght; i++, index++) + data[index] = 0; + } + public static void Clear(ushort* data, int index, int lenght) + { + for (int i = index; i < lenght; i++, index++) + data[index] = 0; + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/AxiMemory.cs.meta b/Assets/Plugins/StoicGooseUnity/AxiMemory.cs.meta new file mode 100644 index 0000000..236e26b --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/AxiMemory.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 920eb4ce49315964e9537a20e38e6151 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Log.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Log.cs index c88aea4..37fafa2 100644 --- a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Log.cs +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Log.cs @@ -1,11 +1,8 @@ -using System; -using System.Collections.Generic; -using System.IO; -using StoicGoose.Common.Extensions; +using System.Collections.Generic; namespace StoicGoose.Common.Utilities { - public enum LogSeverity { Verbose, Debug, Information, Warning, Error, Fatal } + public enum LogSeverity { Verbose, Debug, Information, Warning, Error, Fatal } public enum LogType { Debug, Warning, Error } public interface IStoicGooseLogger diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/AswanDisplayController.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/AswanDisplayController.cs index 7449805..13edb2b 100644 --- a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/AswanDisplayController.cs +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/AswanDisplayController.cs @@ -4,7 +4,7 @@ using static StoicGoose.Common.Utilities.BitHandling; namespace StoicGoose.Core.Display { - public sealed class AswanDisplayController : DisplayControllerCommon + public sealed unsafe class AswanDisplayController : DisplayControllerCommon { public AswanDisplayController(IMachine machine) : base(machine) { } diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayControllerCommon.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayControllerCommon.cs index be60c60..1124921 100644 --- a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayControllerCommon.cs +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayControllerCommon.cs @@ -1,743 +1,773 @@ using System; +using System.Runtime.InteropServices; using StoicGoose.Common.Attributes; using StoicGoose.Core.Interfaces; using StoicGoose.Core.Machines; - +using StoicGooseUnity; using static StoicGoose.Common.Utilities.BitHandling; namespace StoicGoose.Core.Display { - public abstract class DisplayControllerCommon : IPortAccessComponent - { - public const int HorizontalDisp = 224; - public const int HorizontalBlank = 32; - public const int HorizontalTotal = HorizontalDisp + HorizontalBlank; - public const double HorizontalClock = MachineCommon.CpuClock / HorizontalTotal; + public unsafe abstract class DisplayControllerCommon : IPortAccessComponent + { + public const int HorizontalDisp = 224; + public const int HorizontalBlank = 32; + public const int HorizontalTotal = HorizontalDisp + HorizontalBlank; + public const double HorizontalClock = MachineCommon.CpuClock / HorizontalTotal; - public const int VerticalDisp = 144; - public const int VerticalBlank = 15; - public const int VerticalTotal = VerticalDisp + VerticalBlank; - public const double VerticalClock = 12000.0 / VerticalTotal; + public const int VerticalDisp = 144; + public const int VerticalBlank = 15; + public const int VerticalTotal = VerticalDisp + VerticalBlank; + public const double VerticalClock = 12000.0 / VerticalTotal; - public const int ScreenWidth = HorizontalDisp; - public const int ScreenHeight = VerticalDisp; + public const int ScreenWidth = HorizontalDisp; + public const int ScreenHeight = VerticalDisp; - protected const int maxSpriteCount = 128; - protected const int maxSpritesPerLine = 32; + protected const int maxSpriteCount = 128; + protected const int maxSpritesPerLine = 32; - [Flags] - public enum DisplayInterrupts - { - None = 0, - LineCompare = 1 << 0, - VBlankTimer = 1 << 1, - VBlank = 1 << 2, - HBlankTimer = 1 << 3 - } + [Flags] + public enum DisplayInterrupts + { + None = 0, + LineCompare = 1 << 0, + VBlankTimer = 1 << 1, + VBlank = 1 << 2, + HBlankTimer = 1 << 3 + } - protected readonly uint[] spriteData = new uint[maxSpriteCount]; - protected readonly uint[] spriteDataNextFrame = new uint[maxSpriteCount]; - protected readonly uint[] activeSpritesOnLine = new uint[maxSpritesPerLine]; + protected readonly uint[] spriteData = new uint[maxSpriteCount]; + protected readonly uint[] spriteDataNextFrame = new uint[maxSpriteCount]; + protected readonly uint[] activeSpritesOnLine = new uint[maxSpritesPerLine]; - protected readonly bool[] isUsedBySCR2 = new bool[HorizontalDisp * VerticalDisp]; + protected readonly bool[] isUsedBySCR2 = new bool[HorizontalDisp * VerticalDisp]; - protected int spriteCountNextFrame = 0, activeSpriteCountOnLine = 0; + protected int spriteCountNextFrame = 0, activeSpriteCountOnLine = 0; - protected int cycleCount = 0; - protected readonly byte[] outputFramebuffer = new byte[ScreenWidth * ScreenHeight * 4]; + protected int cycleCount = 0; + //protected readonly byte[] outputFramebuffer = new byte[ScreenWidth * ScreenHeight * 4]; - public Action SendFramebuffer { get; set; } = default; - protected readonly IMachine machine = default; + #region //指针化 outputFramebuffer + protected byte[] outputFramebuffer_src; + protected GCHandle outputFramebuffer_handle; + protected IntPtr outputFramebuffer_IntPtr; + protected byte* outputFramebuffer; + protected int outputFramebufferLength; + protected bool outputFramebuffer_IsNull => outputFramebuffer == null; + protected byte[] outputFramebuffer_set + { + set + { + outputFramebuffer_handle.ReleaseGCHandle(); + outputFramebuffer_src = value; + outputFramebufferLength = value.Length; + outputFramebuffer_src.GetObjectPtr(ref outputFramebuffer_handle, ref outputFramebuffer, out outputFramebuffer_IntPtr); + } + } + #endregion - /* REG_DISP_CTRL */ - protected bool scr1Enable, scr2Enable, sprEnable, sprWindowEnable, scr2WindowDisplayOutside, scr2WindowEnable; - /* REG_BACK_COLOR */ - protected byte backColorIndex; - /* REG_LINE_xxx */ - protected int lineCurrent, lineCompare; - /* REG_SPR_xxx */ - protected int sprBase, sprFirst, sprCount; - /* REG_MAP_BASE */ - protected int scr1Base, scr2Base; - /* REG_SCR2_WIN_xx */ - protected int scr2WinX0, scr2WinY0, scr2WinX1, scr2WinY1; - /* REG_SPR_WIN_xx */ - protected int sprWinX0, sprWinY0, sprWinX1, sprWinY1; - /* REG_SCR1_xx */ - protected int scr1ScrollX, scr1ScrollY; - /* REG_SCR2_xx */ - protected int scr2ScrollX, scr2ScrollY; - /* REG_LCD_xxx */ - protected bool lcdActive; - protected bool iconSleep, iconVertical, iconHorizontal, iconAux1, iconAux2, iconAux3; - protected int vtotal, vsync; - /* REG_PALMONO_POOL_x */ - protected readonly byte[] palMonoPools = default; - /* REG_PALMONO_x */ - protected readonly byte[][] palMonoData = default; - /* REG_xTMR_xxx */ - protected readonly DisplayTimer hBlankTimer = new(), vBlankTimer = new(); - public DisplayControllerCommon(IMachine machine) - { - this.machine = machine; - palMonoPools = new byte[8]; - palMonoData = new byte[16][]; - for (var i = 0; i < palMonoData.GetLength(0); i++) palMonoData[i] = new byte[4]; - } + //public Action SendFramebuffer { get; set; } = default; + public Action SendFramebuffer { get; set; } = default; - public void Reset() - { - cycleCount = 0; + protected readonly IMachine machine = default; - Array.Fill(outputFramebuffer, 255); + /* REG_DISP_CTRL */ + protected bool scr1Enable, scr2Enable, sprEnable, sprWindowEnable, scr2WindowDisplayOutside, scr2WindowEnable; + /* REG_BACK_COLOR */ + protected byte backColorIndex; + /* REG_LINE_xxx */ + protected int lineCurrent, lineCompare; + /* REG_SPR_xxx */ + protected int sprBase, sprFirst, sprCount; + /* REG_MAP_BASE */ + protected int scr1Base, scr2Base; + /* REG_SCR2_WIN_xx */ + protected int scr2WinX0, scr2WinY0, scr2WinX1, scr2WinY1; + /* REG_SPR_WIN_xx */ + protected int sprWinX0, sprWinY0, sprWinX1, sprWinY1; + /* REG_SCR1_xx */ + protected int scr1ScrollX, scr1ScrollY; + /* REG_SCR2_xx */ + protected int scr2ScrollX, scr2ScrollY; + /* REG_LCD_xxx */ + protected bool lcdActive; + protected bool iconSleep, iconVertical, iconHorizontal, iconAux1, iconAux2, iconAux3; + protected int vtotal, vsync; + /* REG_PALMONO_POOL_x */ + protected readonly byte[] palMonoPools = default; + /* REG_PALMONO_x */ + protected readonly byte[][] palMonoData = default; + /* REG_xTMR_xxx */ + protected readonly DisplayTimer hBlankTimer = new(), vBlankTimer = new(); - Array.Fill(isUsedBySCR2, false); + public DisplayControllerCommon(IMachine machine) + { + this.machine = machine; - Array.Fill(spriteData, 0); - Array.Fill(spriteDataNextFrame, 0); - Array.Fill(activeSpritesOnLine, 0); + //初始化指针 + outputFramebuffer_set = new byte[ScreenWidth * ScreenHeight * 4]; - spriteCountNextFrame = 0; - activeSpriteCountOnLine = 0; + palMonoPools = new byte[8]; + palMonoData = new byte[16][]; + for (var i = 0; i < palMonoData.GetLength(0); i++) palMonoData[i] = new byte[4]; + } - ResetRegisters(); - } + public void Reset() + { + cycleCount = 0; - protected virtual void ResetRegisters() - { - scr1Enable = scr2Enable = sprEnable = sprWindowEnable = scr2WindowDisplayOutside = scr2WindowEnable = false; - backColorIndex = 0; - lineCurrent = lineCompare = 0; - sprBase = sprFirst = sprCount = 0; - scr1Base = scr2Base = 0; - scr2WinX0 = scr2WinY0 = scr2WinX1 = scr2WinY1 = 0; - sprWinX0 = sprWinY0 = sprWinX1 = sprWinY1 = 0; - scr1ScrollX = scr1ScrollY = 0; - scr2ScrollX = scr2ScrollY = 0; - lcdActive = true; /* NOTE: Final Lap 2000 depends on bootstrap doing this, otherwise LCD stays off? */ - iconSleep = iconVertical = iconHorizontal = iconAux1 = iconAux2 = iconAux3 = false; - vtotal = VerticalTotal - 1; - vsync = VerticalTotal - 4; /* NOTE: Full usage/meaning unknown, so we're ignoring it for now */ - Array.Fill(palMonoPools, 0); - for (var i = 0; i < palMonoData.GetLength(0); i++) Array.Fill(palMonoData[i], 0); - hBlankTimer.Reset(); - vBlankTimer.Reset(); - } + //Array.Fill(outputFramebuffer, 255); + for (var i = 0; i < outputFramebufferLength; i++) + outputFramebuffer[i] = 255; - public void Shutdown() - { - /* Nothing to do... */ - } + Array.Fill(isUsedBySCR2, false); - public DisplayInterrupts Step(int clockCyclesInStep) - { - var interrupt = DisplayInterrupts.None; + Array.Fill(spriteData, 0); + Array.Fill(spriteDataNextFrame, 0); + Array.Fill(activeSpritesOnLine, 0); - cycleCount += clockCyclesInStep; + spriteCountNextFrame = 0; + activeSpriteCountOnLine = 0; - if (cycleCount >= HorizontalTotal) - { - /* Sprite fetch */ - if (lineCurrent == VerticalDisp - 2) - { - spriteCountNextFrame = 0; - for (var j = sprFirst; j < sprFirst + Math.Min(maxSpriteCount, sprCount); j++) - { - var k = (uint)((sprBase << 9) + (j << 2)); - spriteDataNextFrame[spriteCountNextFrame++] = (uint)(machine.ReadMemory(k + 3) << 24 | machine.ReadMemory(k + 2) << 16 | machine.ReadMemory(k + 1) << 8 | machine.ReadMemory(k + 0)); - } - } + ResetRegisters(); + } - /* Render pixels */ - for (var x = 0; x < HorizontalDisp; x++) - RenderPixel(lineCurrent, x); + protected virtual void ResetRegisters() + { + scr1Enable = scr2Enable = sprEnable = sprWindowEnable = scr2WindowDisplayOutside = scr2WindowEnable = false; + backColorIndex = 0; + lineCurrent = lineCompare = 0; + sprBase = sprFirst = sprCount = 0; + scr1Base = scr2Base = 0; + scr2WinX0 = scr2WinY0 = scr2WinX1 = scr2WinY1 = 0; + sprWinX0 = sprWinY0 = sprWinX1 = sprWinY1 = 0; + scr1ScrollX = scr1ScrollY = 0; + scr2ScrollX = scr2ScrollY = 0; + lcdActive = true; /* NOTE: Final Lap 2000 depends on bootstrap doing this, otherwise LCD stays off? */ + iconSleep = iconVertical = iconHorizontal = iconAux1 = iconAux2 = iconAux3 = false; + vtotal = VerticalTotal - 1; + vsync = VerticalTotal - 4; /* NOTE: Full usage/meaning unknown, so we're ignoring it for now */ + Array.Fill(palMonoPools, 0); + for (var i = 0; i < palMonoData.GetLength(0); i++) Array.Fill(palMonoData[i], 0); + hBlankTimer.Reset(); + vBlankTimer.Reset(); + } - /* Line compare interrupt */ - if (lineCurrent == lineCompare) - interrupt |= DisplayInterrupts.LineCompare; + public void Shutdown() + { + /* Nothing to do... */ + } - /* H-timer interrupt */ - if (hBlankTimer.Step()) - interrupt |= DisplayInterrupts.HBlankTimer; + public DisplayInterrupts Step(int clockCyclesInStep) + { + var interrupt = DisplayInterrupts.None; - /* V-blank interrupt */ - if (lineCurrent == VerticalDisp) - { - interrupt |= DisplayInterrupts.VBlank; + cycleCount += clockCyclesInStep; - /* V-timer interrupt */ - if (vBlankTimer.Step()) - interrupt |= DisplayInterrupts.VBlankTimer; + if (cycleCount >= HorizontalTotal) + { + /* Sprite fetch */ + if (lineCurrent == VerticalDisp - 2) + { + spriteCountNextFrame = 0; + for (var j = sprFirst; j < sprFirst + Math.Min(maxSpriteCount, sprCount); j++) + { + var k = (uint)((sprBase << 9) + (j << 2)); + spriteDataNextFrame[spriteCountNextFrame++] = (uint)(machine.ReadMemory(k + 3) << 24 | machine.ReadMemory(k + 2) << 16 | machine.ReadMemory(k + 1) << 8 | machine.ReadMemory(k + 0)); + } + } - /* Transfer framebuffer */ - SendFramebuffer?.Invoke(outputFramebuffer.Clone() as byte[]); - } + /* Render pixels */ + for (var x = 0; x < HorizontalDisp; x++) + RenderPixel(lineCurrent, x); - /* Advance scanline */ - lineCurrent++; + /* Line compare interrupt */ + if (lineCurrent == lineCompare) + interrupt |= DisplayInterrupts.LineCompare; - /* Is frame finished? */ - if (lineCurrent > Math.Max(VerticalDisp, vtotal)) - { - /* Copy sprite data for next frame */ - for (int j = 0, k = spriteCountNextFrame - 1; k >= 0; j++, k--) spriteData[j] = spriteDataNextFrame[k]; - Array.Fill(spriteDataNextFrame, 0); + /* H-timer interrupt */ + if (hBlankTimer.Step()) + interrupt |= DisplayInterrupts.HBlankTimer; - /* Reset variables */ - lineCurrent = 0; - Array.Fill(isUsedBySCR2, false); - } + /* V-blank interrupt */ + if (lineCurrent == VerticalDisp) + { + interrupt |= DisplayInterrupts.VBlank; - /* End of scanline */ - cycleCount = 0; - } + /* V-timer interrupt */ + if (vBlankTimer.Step()) + interrupt |= DisplayInterrupts.VBlankTimer; - return interrupt; - } + /* Transfer framebuffer */ + //SendFramebuffer?.Invoke(outputFramebuffer.Clone() as byte[]); + SendFramebuffer?.Invoke(outputFramebuffer_IntPtr, outputFramebufferLength); + } - protected void RenderPixel(int y, int x) - { - if (y < 0 || y >= VerticalDisp || x < 0 || x >= HorizontalDisp) return; + /* Advance scanline */ + lineCurrent++; - if (lcdActive) - { - RenderBackColor(y, x); - RenderSCR1(y, x); - RenderSCR2(y, x); - RenderSprites(y, x); - } - else - { - /* LCD sleeping */ - RenderSleep(y, x); - } - } + /* Is frame finished? */ + if (lineCurrent > Math.Max(VerticalDisp, vtotal)) + { + /* Copy sprite data for next frame */ + for (int j = 0, k = spriteCountNextFrame - 1; k >= 0; j++, k--) spriteData[j] = spriteDataNextFrame[k]; + Array.Fill(spriteDataNextFrame, 0); - protected abstract void RenderSleep(int y, int x); - protected abstract void RenderBackColor(int y, int x); - protected abstract void RenderSCR1(int y, int x); - protected abstract void RenderSCR2(int y, int x); - protected abstract void RenderSprites(int y, int x); + /* Reset variables */ + lineCurrent = 0; + Array.Fill(isUsedBySCR2, false); + } - protected static void ValidateWindowCoordinates(ref int x0, ref int x1, ref int y0, ref int y1) - { - /* Thank you for this fix, for the encouragement and hints and advice, for just having been there... Thank you for everything, Near. + /* End of scanline */ + cycleCount = 0; + } + + return interrupt; + } + + protected void RenderPixel(int y, int x) + { + if (y < 0 || y >= VerticalDisp || x < 0 || x >= HorizontalDisp) return; + + if (lcdActive) + { + RenderBackColor(y, x); + RenderSCR1(y, x); + RenderSCR2(y, x); + RenderSprites(y, x); + } + else + { + /* LCD sleeping */ + RenderSleep(y, x); + } + } + + protected abstract void RenderSleep(int y, int x); + protected abstract void RenderBackColor(int y, int x); + protected abstract void RenderSCR1(int y, int x); + protected abstract void RenderSCR2(int y, int x); + protected abstract void RenderSprites(int y, int x); + + protected static void ValidateWindowCoordinates(ref int x0, ref int x1, ref int y0, ref int y1) + { + /* Thank you for this fix, for the encouragement and hints and advice, for just having been there... Thank you for everything, Near. * https://forum.fobby.net/index.php?t=msg&goto=6085 */ - if (x0 > x1) - (x1, x0) = (x0, x1); - - if (y0 > y1) - (y1, y0) = (y0, y1); - } - - protected bool IsInsideSCR2Window(int y, int x) - { - var x0 = scr2WinX0; - var x1 = scr2WinX1; - var y0 = scr2WinY0; - var y1 = scr2WinY1; - - ValidateWindowCoordinates(ref x0, ref x1, ref y0, ref y1); - - return ((x >= x0 && x <= x1) || (x >= x1 && x <= x0)) && - ((y >= y0 && y <= y1) || (y >= y1 && y <= y0)); - } - - protected bool IsOutsideSCR2Window(int y, int x) - { - var x0 = scr2WinX0; - var x1 = scr2WinX1; - var y0 = scr2WinY0; - var y1 = scr2WinY1; - - ValidateWindowCoordinates(ref x0, ref x1, ref y0, ref y1); - - return x < x0 || x > x1 || y < y0 || y > y1; - } - - protected bool IsInsideSPRWindow(int y, int x) - { - var x0 = sprWinX0; - var x1 = sprWinX1; - var y0 = sprWinY0; - var y1 = sprWinY1; - - ValidateWindowCoordinates(ref x0, ref x1, ref y0, ref y1); - - return ((x >= x0 && x <= x1) || (x >= x1 && x <= x0)) && - ((y >= y0 && y <= y1) || (y >= y1 && y <= y0)); - } - - protected byte ReadMemory8(uint address) => machine.ReadMemory(address); - protected ushort ReadMemory16(uint address) => (ushort)(machine.ReadMemory(address + 1) << 8 | machine.ReadMemory(address)); - protected uint ReadMemory32(uint address) => (uint)(machine.ReadMemory(address + 3) << 24 | machine.ReadMemory(address + 2) << 16 | machine.ReadMemory(address + 1) << 8 | machine.ReadMemory(address)); - - public virtual byte ReadPort(ushort port) - { - var retVal = (byte)0; - - switch (port) - { - case 0x00: - /* REG_DISP_CTRL */ - ChangeBit(ref retVal, 0, scr1Enable); - ChangeBit(ref retVal, 1, scr2Enable); - ChangeBit(ref retVal, 2, sprEnable); - ChangeBit(ref retVal, 3, sprWindowEnable); - ChangeBit(ref retVal, 4, scr2WindowDisplayOutside); - ChangeBit(ref retVal, 5, scr2WindowEnable); - break; - - case 0x02: - /* REG_LINE_CUR */ - retVal |= (byte)(lineCurrent & 0xFF); - break; - - case 0x03: - /* REG_LINE_CMP */ - retVal |= (byte)(lineCompare & 0xFF); - break; - - case 0x05: - /* REG_SPR_FIRST */ - retVal |= (byte)(sprFirst & 0x7F); - break; - - case 0x06: - /* REG_SPR_COUNT */ - retVal |= (byte)(sprCount & 0xFF); - break; - - case 0x08: - /* REG_SCR2_WIN_X0 */ - retVal |= (byte)(scr2WinX0 & 0xFF); - break; - - case 0x09: - /* REG_SCR2_WIN_Y0 */ - retVal |= (byte)(scr2WinY0 & 0xFF); - break; - - case 0x0A: - /* REG_SCR2_WIN_X1 */ - retVal |= (byte)(scr2WinX1 & 0xFF); - break; - - case 0x0B: - /* REG_SCR2_WIN_Y1 */ - retVal |= (byte)(scr2WinY1 & 0xFF); - break; - - case 0x0C: - /* REG_SPR_WIN_X0 */ - retVal |= (byte)(sprWinX0 & 0xFF); - break; - - case 0x0D: - /* REG_SPR_WIN_Y0 */ - retVal |= (byte)(sprWinY0 & 0xFF); - break; - - case 0x0E: - /* REG_SPR_WIN_X1 */ - retVal |= (byte)(sprWinX1 & 0xFF); - break; - - case 0x0F: - /* REG_SPR_WIN_Y1 */ - retVal |= (byte)(sprWinY1 & 0xFF); - break; - - case 0x10: - /* REG_SCR1_X */ - retVal |= (byte)(scr1ScrollX & 0xFF); - break; - - case 0x11: - /* REG_SCR1_Y */ - retVal |= (byte)(scr1ScrollY & 0xFF); - break; - - case 0x12: - /* REG_SCR2_X */ - retVal |= (byte)(scr2ScrollX & 0xFF); - break; - - case 0x13: - /* REG_SCR2_Y */ - retVal |= (byte)(scr2ScrollY & 0xFF); - break; - - case 0x15: - /* REG_LCD_ICON */ - ChangeBit(ref retVal, 0, iconSleep); - ChangeBit(ref retVal, 1, iconVertical); - ChangeBit(ref retVal, 2, iconHorizontal); - ChangeBit(ref retVal, 3, iconAux1); - ChangeBit(ref retVal, 4, iconAux2); - ChangeBit(ref retVal, 5, iconAux3); - break; - - case 0x16: - /* REG_LCD_VTOTAL */ - retVal |= (byte)(vtotal & 0xFF); - break; - - case 0x17: - /* REG_LCD_VSYNC */ - retVal |= (byte)(vsync & 0xFF); - break; - - case 0x1C: - case 0x1D: - case 0x1E: - case 0x1F: - /* REG_PALMONO_POOL_x */ - retVal |= (byte)(palMonoPools[((port & 0b11) << 1) | 0] << 0); - retVal |= (byte)(palMonoPools[((port & 0b11) << 1) | 1] << 4); - break; - - case ushort _ when port >= 0x20 && port <= 0x3F: - /* REG_PALMONO_x */ - retVal |= (byte)(palMonoData[(port >> 1) & 0b1111][((port & 0b1) << 1) | 0] << 0); - retVal |= (byte)(palMonoData[(port >> 1) & 0b1111][((port & 0b1) << 1) | 1] << 4); - break; - - case 0xA2: - /* REG_TMR_CTRL */ - ChangeBit(ref retVal, 0, hBlankTimer.Enable); - ChangeBit(ref retVal, 1, hBlankTimer.Repeating); - ChangeBit(ref retVal, 2, vBlankTimer.Enable); - ChangeBit(ref retVal, 3, vBlankTimer.Repeating); - break; - - case 0xA4: - case 0xA5: - /* REG_HTMR_FREQ */ - retVal |= (byte)((hBlankTimer.Frequency >> ((port & 0b1) * 8)) & 0xFF); - break; - - case 0xA6: - case 0xA7: - /* REG_VTMR_FREQ */ - retVal |= (byte)((vBlankTimer.Frequency >> ((port & 0b1) * 8)) & 0xFF); - break; - - case 0xA8: - case 0xA9: - /* REG_HTMR_CTR */ - retVal |= (byte)((hBlankTimer.Counter >> ((port & 0b1) * 8)) & 0xFF); - break; - - case 0xAA: - case 0xAB: - /* REG_VTMR_CTR */ - retVal |= (byte)((vBlankTimer.Counter >> ((port & 0b1) * 8)) & 0xFF); - break; - } - - return retVal; - } - - public virtual void WritePort(ushort port, byte value) - { - switch (port) - { - case 0x00: - /* REG_DISP_CTRL */ - scr1Enable = IsBitSet(value, 0); - scr2Enable = IsBitSet(value, 1); - sprEnable = IsBitSet(value, 2); - sprWindowEnable = IsBitSet(value, 3); - scr2WindowDisplayOutside = IsBitSet(value, 4); - scr2WindowEnable = IsBitSet(value, 5); - break; - - case 0x03: - /* REG_LINE_CMP */ - lineCompare = (byte)(value & 0xFF); - break; - - case 0x05: - /* REG_SPR_FIRST */ - sprFirst = (byte)(value & 0x7F); - break; - - case 0x06: - /* REG_SPR_COUNT */ - sprCount = (byte)(value & 0xFF); - break; - - case 0x08: - /* REG_SCR2_WIN_X0 */ - scr2WinX0 = (byte)(value & 0xFF); - break; - - case 0x09: - /* REG_SCR2_WIN_Y0 */ - scr2WinY0 = (byte)(value & 0xFF); - break; - - case 0x0A: - /* REG_SCR2_WIN_X1 */ - scr2WinX1 = (byte)(value & 0xFF); - break; - - case 0x0B: - /* REG_SCR2_WIN_Y1 */ - scr2WinY1 = (byte)(value & 0xFF); - break; - - case 0x0C: - /* REG_SPR_WIN_X0 */ - sprWinX0 = (byte)(value & 0xFF); - break; - - case 0x0D: - /* REG_SPR_WIN_Y0 */ - sprWinY0 = (byte)(value & 0xFF); - break; - - case 0x0E: - /* REG_SPR_WIN_X1 */ - sprWinX1 = (byte)(value & 0xFF); - break; - - case 0x0F: - /* REG_SPR_WIN_Y1 */ - sprWinY1 = (byte)(value & 0xFF); - break; - - case 0x10: - /* REG_SCR1_X */ - scr1ScrollX = (byte)(value & 0xFF); - break; - - case 0x11: - /* REG_SCR1_Y */ - scr1ScrollY = (byte)(value & 0xFF); - break; - - case 0x12: - /* REG_SCR2_X */ - scr2ScrollX = (byte)(value & 0xFF); - break; - - case 0x13: - /* REG_SCR2_Y */ - scr2ScrollY = (byte)(value & 0xFF); - break; - - case 0x15: - /* REG_LCD_ICON */ - iconSleep = IsBitSet(value, 0); - iconVertical = IsBitSet(value, 1); - iconHorizontal = IsBitSet(value, 2); - iconAux1 = IsBitSet(value, 3); - iconAux2 = IsBitSet(value, 4); - iconAux3 = IsBitSet(value, 5); - break; - - case 0x16: - /* REG_LCD_VTOTAL */ - vtotal = (byte)(value & 0xFF); - break; - - case 0x17: - /* REG_LCD_VSYNC */ - vsync = (byte)(value & 0xFF); - break; - - case 0x1C: - case 0x1D: - case 0x1E: - case 0x1F: - /* REG_PALMONO_POOL_x */ - palMonoPools[((port & 0b11) << 1) | 0] = (byte)((value >> 0) & 0b1111); - palMonoPools[((port & 0b11) << 1) | 1] = (byte)((value >> 4) & 0b1111); - break; - - case ushort _ when port >= 0x20 && port <= 0x3F: - /* REG_PALMONO_x */ - palMonoData[(port >> 1) & 0b1111][((port & 0b1) << 1) | 0] = (byte)((value >> 0) & 0b111); - palMonoData[(port >> 1) & 0b1111][((port & 0b1) << 1) | 1] = (byte)((value >> 4) & 0b111); - break; - - case 0xA2: - /* REG_TMR_CTRL */ - hBlankTimer.Enable = IsBitSet(value, 0); - hBlankTimer.Repeating = IsBitSet(value, 1); - vBlankTimer.Enable = IsBitSet(value, 2); - vBlankTimer.Repeating = IsBitSet(value, 3); - break; - - case 0xA4: - /* REG_HTMR_FREQ (low) */ - hBlankTimer.Frequency = (ushort)((hBlankTimer.Frequency & 0xFF00) | value); - hBlankTimer.Counter = (ushort)((hBlankTimer.Counter & 0xFF00) | value); - break; - - case 0xA5: - /* REG_HTMR_FREQ (high) */ - hBlankTimer.Frequency = (ushort)((hBlankTimer.Frequency & 0x00FF) | (value << 8)); - hBlankTimer.Counter = (ushort)((hBlankTimer.Counter & 0x00FF) | (value << 8)); - break; - - case 0xA6: - /* REG_VTMR_FREQ (low) */ - vBlankTimer.Frequency = (ushort)((vBlankTimer.Frequency & 0xFF00) | value); - vBlankTimer.Counter = (ushort)((vBlankTimer.Counter & 0xFF00) | value); - break; - - case 0xA7: - /* REG_VTMR_FREQ (high) */ - vBlankTimer.Frequency = (ushort)((vBlankTimer.Frequency & 0x00FF) | (value << 8)); - vBlankTimer.Counter = (ushort)((vBlankTimer.Counter & 0x00FF) | (value << 8)); - break; - } - } - - [Port("REG_DISP_CTRL", 0x000)] - [BitDescription("SCR1 enable", 0)] - public bool Scr1Enable => scr1Enable; - [Port("REG_DISP_CTRL", 0x000)] - [BitDescription("SCR2 enable", 1)] - public bool Scr2Enable => scr2Enable; - [Port("REG_DISP_CTRL", 0x000)] - [BitDescription("SPR enable", 2)] - public bool SprEnable => sprEnable; - [Port("REG_DISP_CTRL", 0x000)] - [BitDescription("SPR window enable", 3)] - public bool SprWindowEnable => sprWindowEnable; - [Port("REG_DISP_CTRL", 0x000)] - [BitDescription("SCR2 window mode; display outside?", 4)] - public bool Scr2WindowDisplayOutside => scr2WindowDisplayOutside; - [Port("REG_DISP_CTRL", 0x000)] - [BitDescription("SCR2 window enable", 5)] - public bool Scr2WindowEnable => scr2WindowEnable; - [Port("REG_BACK_COLOR", 0x001)] - [BitDescription("Background color pool index", 0, 2)] - public virtual byte BackColorIndex => backColorIndex; - [Port("REG_LINE_CUR", 0x002)] - [BitDescription("Current line being drawn")] - public int LineCurrent => lineCurrent; - [Port("REG_LINE_CMP", 0x003)] - [BitDescription("Line compare interrupt line")] - public int LineCompare => lineCompare; - [Port("REG_SPR_BASE", 0x004)] - [BitDescription("Sprite table base address", 0, 4)] - [Format("X4", 9)] - public virtual int SprBase => sprBase; - [Port("REG_SPR_FIRST", 0x005)] - [BitDescription("First sprite to draw", 0, 6)] - public int SprFirst => sprFirst; - [Port("REG_SPR_COUNT", 0x006)] - [BitDescription("Number of sprites to draw")] - public int SprCount => sprCount; - [Port("REG_MAP_BASE", 0x007)] - [BitDescription("SCR1 base address", 0, 2)] - [Format("X4", 11)] - public virtual int Scr1Base => scr1Base; - [Port("REG_MAP_BASE", 0x007)] - [BitDescription("SCR2 base address", 4, 6)] - [Format("X4", 11)] - public virtual int Scr2Base => scr2Base; - [Port("REG_SCR2_WIN_X0", 0x008)] - [BitDescription("Top-left X of SCR2 window")] - public int Scr2WinX0 => scr2WinX0; - [Port("REG_SCR2_WIN_Y0", 0x009)] - [BitDescription("Top-left Y of SCR2 window")] - public int Scr2WinY0 => scr2WinY0; - [Port("REG_SCR2_WIN_X1", 0x00A)] - [BitDescription("Bottom-right X of SCR2 window")] - public int Scr2WinX1 => scr2WinX1; - [Port("REG_SCR2_WIN_Y1", 0x00B)] - [BitDescription("Bottom-right Y of SCR2 window")] - public int Scr2WinY1 => scr2WinY1; - [Port("REG_SPR_WIN_X0", 0x00C)] - [BitDescription("Top-left X of SPR window")] - public int SprWinX0 => sprWinX0; - [Port("REG_SPR_WIN_Y0", 0x00D)] - [BitDescription("Top-left Y of SPR window")] - public int SprWinY0 => sprWinY0; - [Port("REG_SPR_WIN_X1", 0x00E)] - [BitDescription("Bottom-right X of SPR window")] - public int SprWinX1 => sprWinX1; - [Port("REG_SPR_WIN_Y1", 0x00F)] - [BitDescription("Bottom-right Y of SPR window")] - public int SprWinY1 => sprWinY1; - [Port("REG_SCR1_X", 0x010)] - [BitDescription("SCR1 X scroll")] - public int Scr1ScrollX => scr1ScrollX; - [Port("REG_SCR1_Y", 0x011)] - [BitDescription("SCR1 Y scroll")] - public int Scr1ScrollY => scr1ScrollY; - [Port("REG_SCR2_X", 0x012)] - [BitDescription("SCR2 X scroll")] - public int Scr2ScrollX => scr2ScrollX; - [Port("REG_SCR2_Y", 0x013)] - [BitDescription("SCR2 Y scroll")] - public int Scr2ScrollY => scr2ScrollY; - [Port("REG_LCD_CTRL", 0x014)] - [BitDescription("LCD sleep mode; is LCD active?", 0)] - public bool LcdActive => lcdActive; - [Port("REG_LCD_ICON", 0x015)] - [BitDescription("Sleep indicator", 0)] - public bool IconSleep => iconSleep; - [Port("REG_LCD_ICON", 0x015)] - [BitDescription("Vertical orientation indicator", 1)] - public bool IconVertical => iconVertical; - [Port("REG_LCD_ICON", 0x015)] - [BitDescription("Horizontal orientation indicator", 2)] - public bool IconHorizontal => iconHorizontal; - [Port("REG_LCD_ICON", 0x015)] - [BitDescription("Auxiliary 1 (Small circle)", 3)] - public bool IconAux1 => iconAux1; - [Port("REG_LCD_ICON", 0x015)] - [BitDescription("Auxiliary 2 (Medium circle)", 4)] - public bool IconAux2 => iconAux2; - [Port("REG_LCD_ICON", 0x015)] - [BitDescription("Auxiliary 3 (Big circle)", 5)] - public bool IconAux3 => iconAux3; - [Port("REG_LCD_VTOTAL", 0x016)] - [BitDescription("Display VTOTAL")] - public int VTotal => vtotal; - [Port("REG_LCD_VSYNC", 0x017)] - [BitDescription("VSYNC line position")] - public int VSync => vsync; - [Port("REG_TMR_CTRL", 0x0A2)] - [BitDescription("H-blank timer enable", 0)] - public bool HBlankTimerEnable => hBlankTimer.Enable; - [Port("REG_TMR_CTRL", 0x0A2)] - [BitDescription("H-blank timer mode; is repeating?", 1)] - public bool HBlankTimerRepeating => hBlankTimer.Repeating; - [Port("REG_TMR_CTRL", 0x0A2)] - [BitDescription("V-blank timer enable", 2)] - public bool VBlankTimerEnable => vBlankTimer.Enable; - [Port("REG_TMR_CTRL", 0x0A2)] - [BitDescription("V-blank timer mode; is repeating?", 3)] - public bool VBlankTimerRepeating => vBlankTimer.Repeating; - [Port("REG_HTMR_FREQ", 0x0A4, 0x0A5)] - [BitDescription("H-blank timer frequency")] - public ushort HBlankTimerFrequency => hBlankTimer.Frequency; - [Port("REG_VTMR_FREQ", 0x0A6, 0x0A7)] - [BitDescription("V-blank timer frequency")] - public ushort VBlankTimerFrequency => vBlankTimer.Frequency; - [Port("REG_HTMR_CTR", 0x0A8, 0x0A9)] - [BitDescription("H-blank timer counter")] - public ushort HBlankTimerCounter => hBlankTimer.Counter; - [Port("REG_VTMR_CTR", 0x0AA, 0x0AB)] - [BitDescription("V-blank timer counter")] - public ushort VBlankTimerCounter => vBlankTimer.Counter; - - // TODO: reorganize palmono stuff & add attributes - - public byte[] PalMonoPools => palMonoPools; - public byte[][] PalMonoData => palMonoData; - } + if (x0 > x1) + (x1, x0) = (x0, x1); + + if (y0 > y1) + (y1, y0) = (y0, y1); + } + + protected bool IsInsideSCR2Window(int y, int x) + { + var x0 = scr2WinX0; + var x1 = scr2WinX1; + var y0 = scr2WinY0; + var y1 = scr2WinY1; + + ValidateWindowCoordinates(ref x0, ref x1, ref y0, ref y1); + + return ((x >= x0 && x <= x1) || (x >= x1 && x <= x0)) && + ((y >= y0 && y <= y1) || (y >= y1 && y <= y0)); + } + + protected bool IsOutsideSCR2Window(int y, int x) + { + var x0 = scr2WinX0; + var x1 = scr2WinX1; + var y0 = scr2WinY0; + var y1 = scr2WinY1; + + ValidateWindowCoordinates(ref x0, ref x1, ref y0, ref y1); + + return x < x0 || x > x1 || y < y0 || y > y1; + } + + protected bool IsInsideSPRWindow(int y, int x) + { + var x0 = sprWinX0; + var x1 = sprWinX1; + var y0 = sprWinY0; + var y1 = sprWinY1; + + ValidateWindowCoordinates(ref x0, ref x1, ref y0, ref y1); + + return ((x >= x0 && x <= x1) || (x >= x1 && x <= x0)) && + ((y >= y0 && y <= y1) || (y >= y1 && y <= y0)); + } + + protected byte ReadMemory8(uint address) => machine.ReadMemory(address); + protected ushort ReadMemory16(uint address) => (ushort)(machine.ReadMemory(address + 1) << 8 | machine.ReadMemory(address)); + protected uint ReadMemory32(uint address) => (uint)(machine.ReadMemory(address + 3) << 24 | machine.ReadMemory(address + 2) << 16 | machine.ReadMemory(address + 1) << 8 | machine.ReadMemory(address)); + + public virtual byte ReadPort(ushort port) + { + var retVal = (byte)0; + + switch (port) + { + case 0x00: + /* REG_DISP_CTRL */ + ChangeBit(ref retVal, 0, scr1Enable); + ChangeBit(ref retVal, 1, scr2Enable); + ChangeBit(ref retVal, 2, sprEnable); + ChangeBit(ref retVal, 3, sprWindowEnable); + ChangeBit(ref retVal, 4, scr2WindowDisplayOutside); + ChangeBit(ref retVal, 5, scr2WindowEnable); + break; + + case 0x02: + /* REG_LINE_CUR */ + retVal |= (byte)(lineCurrent & 0xFF); + break; + + case 0x03: + /* REG_LINE_CMP */ + retVal |= (byte)(lineCompare & 0xFF); + break; + + case 0x05: + /* REG_SPR_FIRST */ + retVal |= (byte)(sprFirst & 0x7F); + break; + + case 0x06: + /* REG_SPR_COUNT */ + retVal |= (byte)(sprCount & 0xFF); + break; + + case 0x08: + /* REG_SCR2_WIN_X0 */ + retVal |= (byte)(scr2WinX0 & 0xFF); + break; + + case 0x09: + /* REG_SCR2_WIN_Y0 */ + retVal |= (byte)(scr2WinY0 & 0xFF); + break; + + case 0x0A: + /* REG_SCR2_WIN_X1 */ + retVal |= (byte)(scr2WinX1 & 0xFF); + break; + + case 0x0B: + /* REG_SCR2_WIN_Y1 */ + retVal |= (byte)(scr2WinY1 & 0xFF); + break; + + case 0x0C: + /* REG_SPR_WIN_X0 */ + retVal |= (byte)(sprWinX0 & 0xFF); + break; + + case 0x0D: + /* REG_SPR_WIN_Y0 */ + retVal |= (byte)(sprWinY0 & 0xFF); + break; + + case 0x0E: + /* REG_SPR_WIN_X1 */ + retVal |= (byte)(sprWinX1 & 0xFF); + break; + + case 0x0F: + /* REG_SPR_WIN_Y1 */ + retVal |= (byte)(sprWinY1 & 0xFF); + break; + + case 0x10: + /* REG_SCR1_X */ + retVal |= (byte)(scr1ScrollX & 0xFF); + break; + + case 0x11: + /* REG_SCR1_Y */ + retVal |= (byte)(scr1ScrollY & 0xFF); + break; + + case 0x12: + /* REG_SCR2_X */ + retVal |= (byte)(scr2ScrollX & 0xFF); + break; + + case 0x13: + /* REG_SCR2_Y */ + retVal |= (byte)(scr2ScrollY & 0xFF); + break; + + case 0x15: + /* REG_LCD_ICON */ + ChangeBit(ref retVal, 0, iconSleep); + ChangeBit(ref retVal, 1, iconVertical); + ChangeBit(ref retVal, 2, iconHorizontal); + ChangeBit(ref retVal, 3, iconAux1); + ChangeBit(ref retVal, 4, iconAux2); + ChangeBit(ref retVal, 5, iconAux3); + break; + + case 0x16: + /* REG_LCD_VTOTAL */ + retVal |= (byte)(vtotal & 0xFF); + break; + + case 0x17: + /* REG_LCD_VSYNC */ + retVal |= (byte)(vsync & 0xFF); + break; + + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + /* REG_PALMONO_POOL_x */ + retVal |= (byte)(palMonoPools[((port & 0b11) << 1) | 0] << 0); + retVal |= (byte)(palMonoPools[((port & 0b11) << 1) | 1] << 4); + break; + + case ushort _ when port >= 0x20 && port <= 0x3F: + /* REG_PALMONO_x */ + retVal |= (byte)(palMonoData[(port >> 1) & 0b1111][((port & 0b1) << 1) | 0] << 0); + retVal |= (byte)(palMonoData[(port >> 1) & 0b1111][((port & 0b1) << 1) | 1] << 4); + break; + + case 0xA2: + /* REG_TMR_CTRL */ + ChangeBit(ref retVal, 0, hBlankTimer.Enable); + ChangeBit(ref retVal, 1, hBlankTimer.Repeating); + ChangeBit(ref retVal, 2, vBlankTimer.Enable); + ChangeBit(ref retVal, 3, vBlankTimer.Repeating); + break; + + case 0xA4: + case 0xA5: + /* REG_HTMR_FREQ */ + retVal |= (byte)((hBlankTimer.Frequency >> ((port & 0b1) * 8)) & 0xFF); + break; + + case 0xA6: + case 0xA7: + /* REG_VTMR_FREQ */ + retVal |= (byte)((vBlankTimer.Frequency >> ((port & 0b1) * 8)) & 0xFF); + break; + + case 0xA8: + case 0xA9: + /* REG_HTMR_CTR */ + retVal |= (byte)((hBlankTimer.Counter >> ((port & 0b1) * 8)) & 0xFF); + break; + + case 0xAA: + case 0xAB: + /* REG_VTMR_CTR */ + retVal |= (byte)((vBlankTimer.Counter >> ((port & 0b1) * 8)) & 0xFF); + break; + } + + return retVal; + } + + public virtual void WritePort(ushort port, byte value) + { + switch (port) + { + case 0x00: + /* REG_DISP_CTRL */ + scr1Enable = IsBitSet(value, 0); + scr2Enable = IsBitSet(value, 1); + sprEnable = IsBitSet(value, 2); + sprWindowEnable = IsBitSet(value, 3); + scr2WindowDisplayOutside = IsBitSet(value, 4); + scr2WindowEnable = IsBitSet(value, 5); + break; + + case 0x03: + /* REG_LINE_CMP */ + lineCompare = (byte)(value & 0xFF); + break; + + case 0x05: + /* REG_SPR_FIRST */ + sprFirst = (byte)(value & 0x7F); + break; + + case 0x06: + /* REG_SPR_COUNT */ + sprCount = (byte)(value & 0xFF); + break; + + case 0x08: + /* REG_SCR2_WIN_X0 */ + scr2WinX0 = (byte)(value & 0xFF); + break; + + case 0x09: + /* REG_SCR2_WIN_Y0 */ + scr2WinY0 = (byte)(value & 0xFF); + break; + + case 0x0A: + /* REG_SCR2_WIN_X1 */ + scr2WinX1 = (byte)(value & 0xFF); + break; + + case 0x0B: + /* REG_SCR2_WIN_Y1 */ + scr2WinY1 = (byte)(value & 0xFF); + break; + + case 0x0C: + /* REG_SPR_WIN_X0 */ + sprWinX0 = (byte)(value & 0xFF); + break; + + case 0x0D: + /* REG_SPR_WIN_Y0 */ + sprWinY0 = (byte)(value & 0xFF); + break; + + case 0x0E: + /* REG_SPR_WIN_X1 */ + sprWinX1 = (byte)(value & 0xFF); + break; + + case 0x0F: + /* REG_SPR_WIN_Y1 */ + sprWinY1 = (byte)(value & 0xFF); + break; + + case 0x10: + /* REG_SCR1_X */ + scr1ScrollX = (byte)(value & 0xFF); + break; + + case 0x11: + /* REG_SCR1_Y */ + scr1ScrollY = (byte)(value & 0xFF); + break; + + case 0x12: + /* REG_SCR2_X */ + scr2ScrollX = (byte)(value & 0xFF); + break; + + case 0x13: + /* REG_SCR2_Y */ + scr2ScrollY = (byte)(value & 0xFF); + break; + + case 0x15: + /* REG_LCD_ICON */ + iconSleep = IsBitSet(value, 0); + iconVertical = IsBitSet(value, 1); + iconHorizontal = IsBitSet(value, 2); + iconAux1 = IsBitSet(value, 3); + iconAux2 = IsBitSet(value, 4); + iconAux3 = IsBitSet(value, 5); + break; + + case 0x16: + /* REG_LCD_VTOTAL */ + vtotal = (byte)(value & 0xFF); + break; + + case 0x17: + /* REG_LCD_VSYNC */ + vsync = (byte)(value & 0xFF); + break; + + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + /* REG_PALMONO_POOL_x */ + palMonoPools[((port & 0b11) << 1) | 0] = (byte)((value >> 0) & 0b1111); + palMonoPools[((port & 0b11) << 1) | 1] = (byte)((value >> 4) & 0b1111); + break; + + case ushort _ when port >= 0x20 && port <= 0x3F: + /* REG_PALMONO_x */ + palMonoData[(port >> 1) & 0b1111][((port & 0b1) << 1) | 0] = (byte)((value >> 0) & 0b111); + palMonoData[(port >> 1) & 0b1111][((port & 0b1) << 1) | 1] = (byte)((value >> 4) & 0b111); + break; + + case 0xA2: + /* REG_TMR_CTRL */ + hBlankTimer.Enable = IsBitSet(value, 0); + hBlankTimer.Repeating = IsBitSet(value, 1); + vBlankTimer.Enable = IsBitSet(value, 2); + vBlankTimer.Repeating = IsBitSet(value, 3); + break; + + case 0xA4: + /* REG_HTMR_FREQ (low) */ + hBlankTimer.Frequency = (ushort)((hBlankTimer.Frequency & 0xFF00) | value); + hBlankTimer.Counter = (ushort)((hBlankTimer.Counter & 0xFF00) | value); + break; + + case 0xA5: + /* REG_HTMR_FREQ (high) */ + hBlankTimer.Frequency = (ushort)((hBlankTimer.Frequency & 0x00FF) | (value << 8)); + hBlankTimer.Counter = (ushort)((hBlankTimer.Counter & 0x00FF) | (value << 8)); + break; + + case 0xA6: + /* REG_VTMR_FREQ (low) */ + vBlankTimer.Frequency = (ushort)((vBlankTimer.Frequency & 0xFF00) | value); + vBlankTimer.Counter = (ushort)((vBlankTimer.Counter & 0xFF00) | value); + break; + + case 0xA7: + /* REG_VTMR_FREQ (high) */ + vBlankTimer.Frequency = (ushort)((vBlankTimer.Frequency & 0x00FF) | (value << 8)); + vBlankTimer.Counter = (ushort)((vBlankTimer.Counter & 0x00FF) | (value << 8)); + break; + } + } + + [Port("REG_DISP_CTRL", 0x000)] + [BitDescription("SCR1 enable", 0)] + public bool Scr1Enable => scr1Enable; + [Port("REG_DISP_CTRL", 0x000)] + [BitDescription("SCR2 enable", 1)] + public bool Scr2Enable => scr2Enable; + [Port("REG_DISP_CTRL", 0x000)] + [BitDescription("SPR enable", 2)] + public bool SprEnable => sprEnable; + [Port("REG_DISP_CTRL", 0x000)] + [BitDescription("SPR window enable", 3)] + public bool SprWindowEnable => sprWindowEnable; + [Port("REG_DISP_CTRL", 0x000)] + [BitDescription("SCR2 window mode; display outside?", 4)] + public bool Scr2WindowDisplayOutside => scr2WindowDisplayOutside; + [Port("REG_DISP_CTRL", 0x000)] + [BitDescription("SCR2 window enable", 5)] + public bool Scr2WindowEnable => scr2WindowEnable; + [Port("REG_BACK_COLOR", 0x001)] + [BitDescription("Background color pool index", 0, 2)] + public virtual byte BackColorIndex => backColorIndex; + [Port("REG_LINE_CUR", 0x002)] + [BitDescription("Current line being drawn")] + public int LineCurrent => lineCurrent; + [Port("REG_LINE_CMP", 0x003)] + [BitDescription("Line compare interrupt line")] + public int LineCompare => lineCompare; + [Port("REG_SPR_BASE", 0x004)] + [BitDescription("Sprite table base address", 0, 4)] + [Format("X4", 9)] + public virtual int SprBase => sprBase; + [Port("REG_SPR_FIRST", 0x005)] + [BitDescription("First sprite to draw", 0, 6)] + public int SprFirst => sprFirst; + [Port("REG_SPR_COUNT", 0x006)] + [BitDescription("Number of sprites to draw")] + public int SprCount => sprCount; + [Port("REG_MAP_BASE", 0x007)] + [BitDescription("SCR1 base address", 0, 2)] + [Format("X4", 11)] + public virtual int Scr1Base => scr1Base; + [Port("REG_MAP_BASE", 0x007)] + [BitDescription("SCR2 base address", 4, 6)] + [Format("X4", 11)] + public virtual int Scr2Base => scr2Base; + [Port("REG_SCR2_WIN_X0", 0x008)] + [BitDescription("Top-left X of SCR2 window")] + public int Scr2WinX0 => scr2WinX0; + [Port("REG_SCR2_WIN_Y0", 0x009)] + [BitDescription("Top-left Y of SCR2 window")] + public int Scr2WinY0 => scr2WinY0; + [Port("REG_SCR2_WIN_X1", 0x00A)] + [BitDescription("Bottom-right X of SCR2 window")] + public int Scr2WinX1 => scr2WinX1; + [Port("REG_SCR2_WIN_Y1", 0x00B)] + [BitDescription("Bottom-right Y of SCR2 window")] + public int Scr2WinY1 => scr2WinY1; + [Port("REG_SPR_WIN_X0", 0x00C)] + [BitDescription("Top-left X of SPR window")] + public int SprWinX0 => sprWinX0; + [Port("REG_SPR_WIN_Y0", 0x00D)] + [BitDescription("Top-left Y of SPR window")] + public int SprWinY0 => sprWinY0; + [Port("REG_SPR_WIN_X1", 0x00E)] + [BitDescription("Bottom-right X of SPR window")] + public int SprWinX1 => sprWinX1; + [Port("REG_SPR_WIN_Y1", 0x00F)] + [BitDescription("Bottom-right Y of SPR window")] + public int SprWinY1 => sprWinY1; + [Port("REG_SCR1_X", 0x010)] + [BitDescription("SCR1 X scroll")] + public int Scr1ScrollX => scr1ScrollX; + [Port("REG_SCR1_Y", 0x011)] + [BitDescription("SCR1 Y scroll")] + public int Scr1ScrollY => scr1ScrollY; + [Port("REG_SCR2_X", 0x012)] + [BitDescription("SCR2 X scroll")] + public int Scr2ScrollX => scr2ScrollX; + [Port("REG_SCR2_Y", 0x013)] + [BitDescription("SCR2 Y scroll")] + public int Scr2ScrollY => scr2ScrollY; + [Port("REG_LCD_CTRL", 0x014)] + [BitDescription("LCD sleep mode; is LCD active?", 0)] + public bool LcdActive => lcdActive; + [Port("REG_LCD_ICON", 0x015)] + [BitDescription("Sleep indicator", 0)] + public bool IconSleep => iconSleep; + [Port("REG_LCD_ICON", 0x015)] + [BitDescription("Vertical orientation indicator", 1)] + public bool IconVertical => iconVertical; + [Port("REG_LCD_ICON", 0x015)] + [BitDescription("Horizontal orientation indicator", 2)] + public bool IconHorizontal => iconHorizontal; + [Port("REG_LCD_ICON", 0x015)] + [BitDescription("Auxiliary 1 (Small circle)", 3)] + public bool IconAux1 => iconAux1; + [Port("REG_LCD_ICON", 0x015)] + [BitDescription("Auxiliary 2 (Medium circle)", 4)] + public bool IconAux2 => iconAux2; + [Port("REG_LCD_ICON", 0x015)] + [BitDescription("Auxiliary 3 (Big circle)", 5)] + public bool IconAux3 => iconAux3; + [Port("REG_LCD_VTOTAL", 0x016)] + [BitDescription("Display VTOTAL")] + public int VTotal => vtotal; + [Port("REG_LCD_VSYNC", 0x017)] + [BitDescription("VSYNC line position")] + public int VSync => vsync; + [Port("REG_TMR_CTRL", 0x0A2)] + [BitDescription("H-blank timer enable", 0)] + public bool HBlankTimerEnable => hBlankTimer.Enable; + [Port("REG_TMR_CTRL", 0x0A2)] + [BitDescription("H-blank timer mode; is repeating?", 1)] + public bool HBlankTimerRepeating => hBlankTimer.Repeating; + [Port("REG_TMR_CTRL", 0x0A2)] + [BitDescription("V-blank timer enable", 2)] + public bool VBlankTimerEnable => vBlankTimer.Enable; + [Port("REG_TMR_CTRL", 0x0A2)] + [BitDescription("V-blank timer mode; is repeating?", 3)] + public bool VBlankTimerRepeating => vBlankTimer.Repeating; + [Port("REG_HTMR_FREQ", 0x0A4, 0x0A5)] + [BitDescription("H-blank timer frequency")] + public ushort HBlankTimerFrequency => hBlankTimer.Frequency; + [Port("REG_VTMR_FREQ", 0x0A6, 0x0A7)] + [BitDescription("V-blank timer frequency")] + public ushort VBlankTimerFrequency => vBlankTimer.Frequency; + [Port("REG_HTMR_CTR", 0x0A8, 0x0A9)] + [BitDescription("H-blank timer counter")] + public ushort HBlankTimerCounter => hBlankTimer.Counter; + [Port("REG_VTMR_CTR", 0x0AA, 0x0AB)] + [BitDescription("V-blank timer counter")] + public ushort VBlankTimerCounter => vBlankTimer.Counter; + + // TODO: reorganize palmono stuff & add attributes + + public byte[] PalMonoPools => palMonoPools; + public byte[][] PalMonoData => palMonoData; + } } diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayUtilities.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayUtilities.cs index 13597c0..eccecc0 100644 --- a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayUtilities.cs +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayUtilities.cs @@ -50,16 +50,24 @@ namespace StoicGoose.Core.Display private static byte DuplicateBits(int value) => (byte)((value & 0b1111) | (value & 0b1111) << 4); - public static (byte r, byte g, byte b) GeneratePixel(byte data) => (DuplicateBits(data), DuplicateBits(data), DuplicateBits(data)); + public static (byte r, byte g, byte b) GeneratePixel(byte data) => (DuplicateBits(data), DuplicateBits(data), DuplicateBits(data)); public static (byte r, byte g, byte b) GeneratePixel(ushort data) => (DuplicateBits(data >> 8), DuplicateBits(data >> 4), DuplicateBits(data >> 0)); - public static void CopyPixel((byte r, byte g, byte b) pixel, byte[] data, int x, int y, int stride) => CopyPixel(pixel, data, ((y * stride) + x) * 4); - public static void CopyPixel((byte r, byte g, byte b) pixel, byte[] data, long address) - { - data[address + 0] = pixel.r; - data[address + 1] = pixel.g; - data[address + 2] = pixel.b; - data[address + 3] = 255; - } - } + public static unsafe void CopyPixel((byte r, byte g, byte b) pixel, byte* data, int x, int y, int stride) => CopyPixel(pixel, data, ((y * stride) + x) * 4); + public static unsafe void CopyPixel((byte r, byte g, byte b) pixel, byte* data, long address) + { + data[address + 0] = pixel.r; + data[address + 1] = pixel.g; + data[address + 2] = pixel.b; + data[address + 3] = 255; + } + //public static void CopyPixel((byte r, byte g, byte b) pixel, byte[] data, int x, int y, int stride) => CopyPixel(pixel, data, ((y * stride) + x) * 4); + //public static void CopyPixel((byte r, byte g, byte b) pixel, byte[] data, long address) + //{ + // data[address + 0] = pixel.r; + // data[address + 1] = pixel.g; + // data[address + 2] = pixel.b; + // data[address + 3] = 255; + //} + } } diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/SphinxDisplayController.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/SphinxDisplayController.cs index 3ecba73..ac993b1 100644 --- a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/SphinxDisplayController.cs +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/SphinxDisplayController.cs @@ -5,7 +5,7 @@ using static StoicGoose.Common.Utilities.BitHandling; namespace StoicGoose.Core.Display { - public sealed class SphinxDisplayController : DisplayControllerCommon + public sealed unsafe class SphinxDisplayController : DisplayControllerCommon { // TODO: reimplement high contrast mode; also, get a WSC, figure out how it's supposed to look? diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IMachine.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IMachine.cs index 9c60613..b371c27 100644 --- a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IMachine.cs +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IMachine.cs @@ -43,9 +43,11 @@ namespace StoicGoose.Core.Interfaces SoundControllerCommon SoundController { get; } EEPROM InternalEeprom { get; } - Func<(List buttonsPressed, List buttonsHeld)> ReceiveInput { get; set; } + //Func<(List buttonsPressed, List buttonsHeld)> ReceiveInput { get; set; } + + Func ReceiveInput { get; set; } - Func ReadMemoryCallback { get; set; } + Func ReadMemoryCallback { get; set; } Action WriteMemoryCallback { get; set; } Func ReadPortCallback { get; set; } Action WritePortCallback { get; set; } diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/MachineCommon.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/MachineCommon.cs index 6e0aa92..1991f34 100644 --- a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/MachineCommon.cs +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/MachineCommon.cs @@ -53,9 +53,10 @@ namespace StoicGoose.Core.Machines public abstract int BootstrapRomAddress { get; } public abstract int BootstrapRomSize { get; } - public Func<(List buttonsPressed, List buttonsHeld)> ReceiveInput { get; set; } = default; + //public Func<(List buttonsPressed, List buttonsHeld)> ReceiveInput { get; set; } = default; + public Func ReceiveInput { get; set; } = default; - public Func ReadMemoryCallback { get; set; } = default; + public Func ReadMemoryCallback { get; set; } = default; public Action WriteMemoryCallback { get; set; } = default; public Func ReadPortCallback { get; set; } = default; public Action WritePortCallback { get; set; } = default; diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwan.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwan.cs index d122b10..ebc82dd 100644 --- a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwan.cs +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwan.cs @@ -4,7 +4,7 @@ using StoicGoose.Common.Attributes; using StoicGoose.Core.Display; using StoicGoose.Core.Serial; using StoicGoose.Core.Sound; - +using StoicGooseUnity; using static StoicGoose.Common.Utilities.BitHandling; namespace StoicGoose.Core.Machines @@ -143,37 +143,68 @@ namespace StoicGoose.Core.Machines ChangeBit(ref retVal, 5, keypadXEnable); ChangeBit(ref retVal, 6, keypadButtonEnable); - /* Get input from UI */ - var buttonsHeld = ReceiveInput?.Invoke().buttonsHeld; - if (buttonsHeld != null) - { - if (buttonsHeld.Count > 0) - RaiseInterrupt(1); + /* Get input from UI */ + var buttonsHeld = ReceiveInput?.Invoke(); + if (buttonsHeld != null) + { + if (buttonsHeld > 0) + RaiseInterrupt(1); - if (keypadYEnable) - { - if (buttonsHeld.Contains("Y1")) ChangeBit(ref retVal, 0, true); - if (buttonsHeld.Contains("Y2")) ChangeBit(ref retVal, 1, true); - if (buttonsHeld.Contains("Y3")) ChangeBit(ref retVal, 2, true); - if (buttonsHeld.Contains("Y4")) ChangeBit(ref retVal, 3, true); - } + if (keypadYEnable) + { + if ((buttonsHeld.Value & (ushort)StoicGooseKey.Y1) > 0) ChangeBit(ref retVal, 0, true); + if ((buttonsHeld.Value & (ushort)StoicGooseKey.Y2) > 0) ChangeBit(ref retVal, 1, true); + if ((buttonsHeld.Value & (ushort)StoicGooseKey.Y3) > 0) ChangeBit(ref retVal, 2, true); + if ((buttonsHeld.Value & (ushort)StoicGooseKey.Y4) > 0) ChangeBit(ref retVal, 3, true); + } - if (keypadXEnable) - { - if (buttonsHeld.Contains("X1")) ChangeBit(ref retVal, 0, true); - if (buttonsHeld.Contains("X2")) ChangeBit(ref retVal, 1, true); - if (buttonsHeld.Contains("X3")) ChangeBit(ref retVal, 2, true); - if (buttonsHeld.Contains("X4")) ChangeBit(ref retVal, 3, true); - } + if (keypadXEnable) + { + if ((buttonsHeld.Value & (ushort)StoicGooseKey.X1) > 0) ChangeBit(ref retVal, 0, true); + if ((buttonsHeld.Value & (ushort)StoicGooseKey.X2) > 0) ChangeBit(ref retVal, 1, true); + if ((buttonsHeld.Value & (ushort)StoicGooseKey.X3) > 0) ChangeBit(ref retVal, 2, true); + if ((buttonsHeld.Value & (ushort)StoicGooseKey.X4) > 0) ChangeBit(ref retVal, 3, true); + } - if (keypadButtonEnable) - { - if (buttonsHeld.Contains("Start")) ChangeBit(ref retVal, 1, true); - if (buttonsHeld.Contains("A")) ChangeBit(ref retVal, 2, true); - if (buttonsHeld.Contains("B")) ChangeBit(ref retVal, 3, true); - } - } - break; + if (keypadButtonEnable) + { + if ((buttonsHeld.Value & (ushort)StoicGooseKey.Start) > 0) ChangeBit(ref retVal, 1, true); + if ((buttonsHeld.Value & (ushort)StoicGooseKey.A) > 0) ChangeBit(ref retVal, 2, true); + if ((buttonsHeld.Value & (ushort)StoicGooseKey.B) > 0) ChangeBit(ref retVal, 3, true); + } + } + //var buttonsHeld = ReceiveInput?.Invoke().buttonsHeld; + //if (buttonsHeld != null) + //{ + // if (buttonsHeld.Count > 0) + // RaiseInterrupt(1); + + // if (keypadYEnable) + // { + + + // if (buttonsHeld.Contains("Y1")) ChangeBit(ref retVal, 0, true); + // if (buttonsHeld.Contains("Y2")) ChangeBit(ref retVal, 1, true); + // if (buttonsHeld.Contains("Y3")) ChangeBit(ref retVal, 2, true); + // if (buttonsHeld.Contains("Y4")) ChangeBit(ref retVal, 3, true); + // } + + // if (keypadXEnable) + // { + // if (buttonsHeld.Contains("X1")) ChangeBit(ref retVal, 0, true); + // if (buttonsHeld.Contains("X2")) ChangeBit(ref retVal, 1, true); + // if (buttonsHeld.Contains("X3")) ChangeBit(ref retVal, 2, true); + // if (buttonsHeld.Contains("X4")) ChangeBit(ref retVal, 3, true); + // } + + // if (keypadButtonEnable) + // { + // if (buttonsHeld.Contains("Start")) ChangeBit(ref retVal, 1, true); + // if (buttonsHeld.Contains("A")) ChangeBit(ref retVal, 2, true); + // if (buttonsHeld.Contains("B")) ChangeBit(ref retVal, 3, true); + // } + //} + break; case 0xB6: /* REG_INT_ACK */ diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwanColor.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwanColor.cs index 828a41f..9e4dc8c 100644 --- a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwanColor.cs +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwanColor.cs @@ -5,7 +5,7 @@ using StoicGoose.Core.Display; using StoicGoose.Core.DMA; using StoicGoose.Core.Serial; using StoicGoose.Core.Sound; - +using StoicGooseUnity; using static StoicGoose.Common.Utilities.BitHandling; namespace StoicGoose.Core.Machines @@ -189,36 +189,65 @@ namespace StoicGoose.Core.Machines ChangeBit(ref retVal, 6, keypadButtonEnable); /* Get input from UI */ - var buttonsHeld = ReceiveInput?.Invoke().buttonsHeld; - if (buttonsHeld != null) - { - if (buttonsHeld.Count > 0) - RaiseInterrupt(1); + var buttonsHeld = ReceiveInput?.Invoke(); + if (buttonsHeld != null) + { + if (buttonsHeld > 0) + RaiseInterrupt(1); - if (keypadYEnable) - { - if (buttonsHeld.Contains("Y1")) ChangeBit(ref retVal, 0, true); - if (buttonsHeld.Contains("Y2")) ChangeBit(ref retVal, 1, true); - if (buttonsHeld.Contains("Y3")) ChangeBit(ref retVal, 2, true); - if (buttonsHeld.Contains("Y4")) ChangeBit(ref retVal, 3, true); - } + if (keypadYEnable) + { + if ((buttonsHeld.Value & (ushort)StoicGooseKey.Y1) > 0) ChangeBit(ref retVal, 0, true); + if ((buttonsHeld.Value & (ushort)StoicGooseKey.Y2) > 0) ChangeBit(ref retVal, 1, true); + if ((buttonsHeld.Value & (ushort)StoicGooseKey.Y3) > 0) ChangeBit(ref retVal, 2, true); + if ((buttonsHeld.Value & (ushort)StoicGooseKey.Y4) > 0) ChangeBit(ref retVal, 3, true); + } - if (keypadXEnable) - { - if (buttonsHeld.Contains("X1")) ChangeBit(ref retVal, 0, true); - if (buttonsHeld.Contains("X2")) ChangeBit(ref retVal, 1, true); - if (buttonsHeld.Contains("X3")) ChangeBit(ref retVal, 2, true); - if (buttonsHeld.Contains("X4")) ChangeBit(ref retVal, 3, true); - } + if (keypadXEnable) + { + if ((buttonsHeld.Value & (ushort)StoicGooseKey.X1) > 0) ChangeBit(ref retVal, 0, true); + if ((buttonsHeld.Value & (ushort)StoicGooseKey.X2) > 0) ChangeBit(ref retVal, 1, true); + if ((buttonsHeld.Value & (ushort)StoicGooseKey.X3) > 0) ChangeBit(ref retVal, 2, true); + if ((buttonsHeld.Value & (ushort)StoicGooseKey.X4) > 0) ChangeBit(ref retVal, 3, true); + } - if (keypadButtonEnable) - { - if (buttonsHeld.Contains("Start")) ChangeBit(ref retVal, 1, true); - if (buttonsHeld.Contains("A")) ChangeBit(ref retVal, 2, true); - if (buttonsHeld.Contains("B")) ChangeBit(ref retVal, 3, true); - } - } - break; + if (keypadButtonEnable) + { + if ((buttonsHeld.Value & (ushort)StoicGooseKey.Start) > 0) ChangeBit(ref retVal, 1, true); + if ((buttonsHeld.Value & (ushort)StoicGooseKey.A) > 0) ChangeBit(ref retVal, 2, true); + if ((buttonsHeld.Value & (ushort)StoicGooseKey.B) > 0) ChangeBit(ref retVal, 3, true); + } + } + //var buttonsHeld = ReceiveInput?.Invoke().buttonsHeld; + //if (buttonsHeld != null) + //{ + // if (buttonsHeld.Count > 0) + // RaiseInterrupt(1); + + // if (keypadYEnable) + // { + // if (buttonsHeld.Contains("Y1")) ChangeBit(ref retVal, 0, true); + // if (buttonsHeld.Contains("Y2")) ChangeBit(ref retVal, 1, true); + // if (buttonsHeld.Contains("Y3")) ChangeBit(ref retVal, 2, true); + // if (buttonsHeld.Contains("Y4")) ChangeBit(ref retVal, 3, true); + // } + + // if (keypadXEnable) + // { + // if (buttonsHeld.Contains("X1")) ChangeBit(ref retVal, 0, true); + // if (buttonsHeld.Contains("X2")) ChangeBit(ref retVal, 1, true); + // if (buttonsHeld.Contains("X3")) ChangeBit(ref retVal, 2, true); + // if (buttonsHeld.Contains("X4")) ChangeBit(ref retVal, 3, true); + // } + + // if (keypadButtonEnable) + // { + // if (buttonsHeld.Contains("Start")) ChangeBit(ref retVal, 1, true); + // if (buttonsHeld.Contains("A")) ChangeBit(ref retVal, 2, true); + // if (buttonsHeld.Contains("B")) ChangeBit(ref retVal, 3, true); + // } + //} + break; case 0xB6: /* REG_INT_ACK */ diff --git a/Assets/Plugins/StoicGooseUnity/StoicGooseKey.cs b/Assets/Plugins/StoicGooseUnity/StoicGooseKey.cs new file mode 100644 index 0000000..a52006e --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGooseKey.cs @@ -0,0 +1,20 @@ +using System; + +namespace StoicGooseUnity +{ + [Flags] + public enum StoicGooseKey : ushort + { + X1 = 1, + X2 = 2, + X3 = 4, + X4 = 8, + Y1 = 16, + Y2 = 32, + Y3 = 64, + Y4 = 128, + Start = 256, + A = 512, + B = 1024 + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGooseKey.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGooseKey.cs.meta new file mode 100644 index 0000000..ab8e45b --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGooseKey.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 5e6310aac38e03548983e7e42f83018b \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGooseUnity.asmdef b/Assets/Plugins/StoicGooseUnity/StoicGooseUnity.asmdef new file mode 100644 index 0000000..fd78c03 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGooseUnity.asmdef @@ -0,0 +1,14 @@ +{ + "name": "StoicGooseUnity", + "rootNamespace": "", + "references": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": true, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGooseUnity.asmdef.meta b/Assets/Plugins/StoicGooseUnity/StoicGooseUnity.asmdef.meta new file mode 100644 index 0000000..57f393e --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGooseUnity.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 28e943ec033eb584b994cc1198ac76be +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/StoicGooseUnity/Handlers.meta b/Assets/Resources.meta similarity index 77% rename from Assets/Plugins/StoicGooseUnity/Handlers.meta rename to Assets/Resources.meta index cf8328a..c43702c 100644 --- a/Assets/Plugins/StoicGooseUnity/Handlers.meta +++ b/Assets/Resources.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: f08bda821691d2a41a751fae22728b71 +guid: 4e849eb07879d114a8cef36f1a3a9267 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/Resources/StoicGooseUnity.meta b/Assets/Resources/StoicGooseUnity.meta new file mode 100644 index 0000000..750c3c6 --- /dev/null +++ b/Assets/Resources/StoicGooseUnity.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e38b0e24f0e41b54fb38be7507821d5c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/StoicGooseUnity/emu.meta b/Assets/Resources/StoicGooseUnity/emu.meta new file mode 100644 index 0000000..d0afd9e --- /dev/null +++ b/Assets/Resources/StoicGooseUnity/emu.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c002056b1a3ebd541ba56af40fe41ac2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/StoicGooseUnity/emu/Dat.meta b/Assets/Resources/StoicGooseUnity/emu/Dat.meta new file mode 100644 index 0000000..93c82f9 --- /dev/null +++ b/Assets/Resources/StoicGooseUnity/emu/Dat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: baecae65d43245441a7e7e2b16e96ae9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/StoicGooseUnity/emu/Dat/Bandai - WonderSwan Color.dat.bytes b/Assets/Resources/StoicGooseUnity/emu/Dat/Bandai - WonderSwan Color.dat.bytes new file mode 100644 index 0000000..c8c5af5 --- /dev/null +++ b/Assets/Resources/StoicGooseUnity/emu/Dat/Bandai - WonderSwan Color.dat.bytes @@ -0,0 +1,479 @@ + + +
+ 51 + Bandai - WonderSwan Color + Bandai - WonderSwan Color + 20230827-003018 + C. V. Reynolds, Gefflon, Hiccup, omonim2007, PPLToast, rarenight, relax, sCZther, SonGoku, xuom2 + No-Intro + https://www.no-intro.org + +
+ + [BIOS] SwanCrystal Boot ROM (Japan) (En) + + + + [BIOS] WonderSwan Color Boot ROM (Japan) (En) + + + + Alchemist Marie & Elie - Futari no Atelier (Japan) + + + + Another Heaven - Memory of those Days (Japan) + + + + Arc the Lad - Kishin Fukkatsu (Japan) + + + + Battle Spirit - Digimon Frontier (Japan) (Rev 1) + + + + Blue Wing Blitz (Japan) + + + + Cardinal Sins - Recycle Edition (World) (v1.02) (WonderWitch Conversion) + + + + Dark Eyes - Battle Gate (Japan) + + + + Dicing Knight. (Japan) + + + + Digimon - Anode Tamer & Cathode Tamer - Veedramon Version (Hong Kong) (En) + + + + Digimon - Anode Tamer & Cathode Tamer - Veedramon Version (Korea) (En) + + + + Digimon Adventure 02 - D1 Tamers (Japan) + + + + Digimon Adventure 02 - D1 Tamers (Japan) (Rev 1) + + + + Digimon Tamers - Battle Spirit (Japan, Korea) (En,Ja) + + + + Digimon Tamers - Battle Spirit Ver. 1.5 (Japan) + + + + Digimon Tamers - Brave Tamer (Japan) (Rev 1) + + + + Digimon Tamers - Digimon Medley (Japan) + + + + Digimon Tamers - Digimon Medley (Japan) (Rev 1) + + + + Digital Monster - D-Project (Japan) + + + + Digital Monster - D-Project (Japan) (Rev 1) + + + + Digital Monster - D-Project (Japan) (Rev 2) + + + + Digital Monster Card Game - Ver. WonderSwan Color (Japan) + + + + Digital Monster Card Game - Ver. WonderSwan Color (Japan) (Rev 2) + + + + Dokodemo Hamster 3 - Odekake Saffron (Japan) (Rev 2) + + + + Dragon Ball (Japan) + + + + Final Fantasy (Japan) + + + + Final Fantasy II (Japan) + + + + Final Fantasy IV (Japan) + + + + Final Lap Special - GT & Formula Machine (Japan) + + + + Flash Koibito-kun (Japan) + + + + Flash Masta Firmware (USA) (2016-08-29) (Unl) + + + + Flash Masta Firmware (USA) (2016-05-13) (Unl) + + + + From TV Animation One Piece - Chopper no Daibouken (Japan) + + + + From TV Animation One Piece - Grand Battle Swan Colosseum (Japan) + + + + From TV Animation One Piece - Grand Battle Swan Colosseum (Japan) (Sample) + + + + From TV Animation One Piece - Niji no Shima Densetsu (Japan) + + + + From TV Animation One Piece - Treasure Wars (Japan) + + + + From TV Animation One Piece - Treasure Wars (Japan) (Rev 1) + + + + From TV Animation One Piece - Treasure Wars 2 - Buggy Land e Youkoso (Japan) + + + + Front Mission (Japan) + + + + Gekitou! Crash Gear Turbo - Gear Champion League (Japan) + + + + Gensou Maden Saiyuuki Retribution - Hi no Ataru Basho de (Japan) (Rev 2) + + + + Golden Axe (Japan) + + + + Gransta Chronicle (Japan) + + + + Guilty Gear Petit (Japan) + + + + Guilty Gear Petit 2 (Japan) + + + + GunPey EX (Japan) + + + + Hanjuku Hero - Ah, Sekai yo Hanjuku Nare...!! (Japan) (Rev 1) + + + + Hataraku Chocobo (Japan) + + + + Hunter X Hunter - Greed Island (Japan) + + + + Hunter X Hunter - Greed Island (Japan) (Rev 1) + + + + Hunter X Hunter - Michibikareshi Mono (Japan) + + + + Hunter X Hunter - Sorezore no Ketsui (Japan) + + + + Inuyasha - Fuuun Emaki (Japan) + + + + Inuyasha - Kagome no Sengoku Nikki (Japan) + + + + Inuyasha - Kagome no Yume Nikki (Japan) + + + + Judgement Silversword - Rebirth Edition (Japan) (Rev 4321) + + + + Judgement Silversword - Rebirth Edition (Japan) (Rev 5C21) + + + + Kidou Senshi Gundam - Giren no Yabou - Tokubetsu Hen - Aoki Hoshi no Hasha (Japan) + + + + Kidou Senshi Gundam Seed (Japan) + + + + Kidou Senshi Gundam Vol. 1 - Side 7 (Japan) + + + + Kidou Senshi Gundam Vol. 2 - Jaburo (Japan) + + + + Kidou Senshi Gundam Vol. 3 - A Baoa Qu (Japan) + + + + Kinnikuman II-Sei - Choujin Seisenshi (Japan) + + + + Kinnikuman II-Sei - Dream Tag Match (Japan) + + + + Kurupara! (Japan) (Rev 1) + + + + Last Alive (Japan) + + + + Makai Toushi Sa-Ga (Japan) + + + + mama Mitte (Japan) (Program) + + + + mama Mitte (Japan) (Rev D) (Program) + + + + Meitantei Conan - Yuugure no Oujo (Japan) + + + + Memories Off - Festa (Japan) + + + + Mikeneko Holmes - Ghost Panic (Japan) + + + + Mr. Driller (Japan) + + + + Namco Super Wars (Japan) + + + + Naruto - Konoha Ninpouchou (Japan) + + + + NAVI GET 400 Million (Japan) (Version 1.0) (Program) + + + + NAVI GET 400 Million (Japan) (Version 3.0) (Program) + + + + NAVI GET 400 Million (Japan) (Version 2.1) (Program) + + + + NAVI GET 400 Million (Japan) (Version 9) (Program) + + + + Pocket no Naka no Doraemon (Japan) + + + + Raku Jongg (Japan) + + + + Rhyme Rider Kerorican (Japan) + + + + Riviera - Yakusoku no Chi Riviera (Japan) + + + + Rockman EXE - N1 Battle (Japan) (Rev 1) + + + + Rockman EXE WS (Japan) + + + + Romancing Sa-Ga (Japan) + + + + RUN=DIM - Return to Earth (Japan) + + + + Saint Seiya - Ougon Densetsu Hen - Perfect Edition (Japan) + + + + SD Gundam - Operation U.C. (Japan) + + + + SD Gundam Eiyuu Den - Kishi Densetsu (Japan) + + + + SD Gundam Eiyuu Den - Musha Densetsu (Japan) + + + + SD Gundam G Generation - Gather Beat 2 (Japan) + + + + Games + SD Gundam G Generation - Mono-Eye Gundams (Japan) + + + + Games + SD Gundam G Generation - Mono-Eye Gundams (Japan) (Rev 2) + + + + Senkaiden Ni - TV Animation Senkaiden Houshin Engi Yori (Japan) + + + + Shaman King - Asu e no Ishi (Japan) + + + + Shaman King - Asu e no Ishi (Japan) (Rev 1) + + + + Sorobang (Japan) (Rev 1) + + + + Star Hearts - Hoshi to Daichi no Shisha (Japan) + + + + Star Hearts - Hoshi to Daichi no Shisha - Taikenban (Japan) (Not For Sale) + + + + Super Robot Taisen Compact 3 (Japan) (Rev 5) + + + + Super Robot Taisen Compact 3 (Japan) (Rev 6) + + + + Super Robot Taisen Compact for WonderSwan Color (Japan) + + + + Terrors 2 (Japan) + + + + Tetris (Japan) + + + + Tonpuusou (Japan) + + + + Uchuu Senkan Yamato (Japan) + + + + Ultraman - Hikari no Kuni no Shisha (Japan) + + + + Wild Card (Japan) + + + + With You - Mitsumete Itai (Japan) + + + + Wizardry Scenario 1 - Proving Grounds of the Mad Overlord (Japan) + + + + Wonder Classic (Japan) + + + + X - Card of Fate (Japan) + + + + XI Little (Japan) + + +
diff --git a/Assets/Resources/StoicGooseUnity/emu/Dat/Bandai - WonderSwan Color.dat.bytes.meta b/Assets/Resources/StoicGooseUnity/emu/Dat/Bandai - WonderSwan Color.dat.bytes.meta new file mode 100644 index 0000000..048f479 --- /dev/null +++ b/Assets/Resources/StoicGooseUnity/emu/Dat/Bandai - WonderSwan Color.dat.bytes.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: af2f9150b8258834096b238494c8da95 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/StoicGooseUnity/emu/Dat/Bandai - WonderSwan.dat.bytes b/Assets/Resources/StoicGooseUnity/emu/Dat/Bandai - WonderSwan.dat.bytes new file mode 100644 index 0000000..1fe7764 --- /dev/null +++ b/Assets/Resources/StoicGooseUnity/emu/Dat/Bandai - WonderSwan.dat.bytes @@ -0,0 +1,561 @@ + + +
+ 50 + Bandai - WonderSwan + Bandai - WonderSwan + 20230717-110112 + C. V. Reynolds, Gefflon, gigadeath, Hiccup, kazumi213, MeguCocoa, omonim2007, PPLToast, RetroUprising, sCZther, SonGoku, xuom2 + No-Intro + https://www.no-intro.org + +
+ + [BIOS] WonderSwan Boot ROM (Japan) (En) + + + + Anchorz Field (Japan) + + + + Armored Unit (Japan) + + + + Bakusou Dekotora Densetsu for WonderSwan (Japan) + + + + BANDAI Default Splash Screen (Japan) (Program) + + + + beatmania for WonderSwan (Japan) + + + + Buffers Evolution (Japan) + + + + Cardcaptor Sakura - Sakura to Fushigi na Clow Card (Japan) + + + + Chaos Gear - Michibikareshi Mono (Japan) + + + + Chocobo no Fushigi na Dungeon for WonderSwan (Japan) (Rev 2) + + + + Chocobo no Fushigi na Dungeon for WonderSwan (Japan) (Rev 1) + + + + Chocobo no Fushigi na Dungeon for WonderSwan (Japan) (Rev 3) + + + + Chou Aniki - Otoko no Tamafuda (Japan) (Rev 4) + + + + Chou Denki Card Battle - Youfu Makai (Japan) (Rev 3) + + + + Clock Tower for WonderSwan (Japan) (Rev 1) + + + + Crazy Climber (Japan) + + + + D's Garage 21 Koubo Game - Tane o Maku Tori (Japan) + + + + Densha de Go! (Japan) (Rev 1) + + + + Densha de Go! 2 (Japan) + + + + Digimon - Ver. WonderSwan (Hong Kong) (En) + + + + Digimon Adventure - Anode Tamer (Japan) (Rev 1) + + + + Digimon Adventure - Anode Tamer (Japan) + + + + Digimon Adventure - Cathode Tamer (Japan) + + + + Digimon Adventure 02 - Tag Tamers (Japan) (Rev 1) + + + + Digimon Adventure 02 - Tag Tamers (Japan) + + + + Digital Monster - Ver. WonderSwan (Japan) (Rev 1) + + + + Digital Partner (Japan) + + + + Dokodemo Hamster (Japan) + + + + Engacho! for WonderSwan (Japan) + + + + Fever - Sankyo Koushiki Pachinko Simulation for WonderSwan (Japan) + + + + Final Lap 2000 (Japan) + + + + Fire Pro Wrestling for WonderSwan (Japan) (Rev 5) + + + + Fishing Freaks - Bass Rise for WonderSwan (Japan) + + + + From TV Animation One Piece - Mezase Kaizoku Ou! (Japan) + + + + Ganso Jajamaru-kun (Japan) + + + + Glocal Hexcite (Japan) + + + + Gomoku Narabe & Reversi - Touryuumon (Japan) + + + + Goraku Ou Tango! (Japan) (Rev 2) + + + + GunPey (Japan) + + + + Hanafuda Shiyouyo (Japan) + + + + Harobots (Japan) + + + + Harobots (Japan) (Rev 1) + + + + Hunter X Hunter - Ishi o Tsugu Mono (Japan) (Rev 2) + + + + Hunter X Hunter - Ishi o Tsugu Mono (Japan) (Rev 1) + + + + Kakutou Ryouri Densetsu Bistro Recipe - Wonder Battle Hen (Japan) + + + + Kaze no Klonoa - Moonlight Museum (Japan) + + + + Keiba Yosou Shien Soft - Yosou Shinkaron (Japan) + + + + Kiss Yori... - Seaside Serenade (Japan) (Rev 2) + + + + Kosodate Quiz - Dokodemo My Angel (Japan) + + + + Kyousouba Ikusei Simulation - Keiba (Japan) (Rev 1) + + + + Langrisser Millennium WS - The Last Century (Japan) (Rev 1) + + + + Last Stand (Japan) + + + + Lode Runner for WonderSwan (Japan) + + + + Macross - True Love Song (Japan) + + + + Magical Drop for WonderSwan (Japan) + + + + Mahjong Touryuumon (Japan) (Rev 3) + + + + Mahjong Touryuumon (Japan) (Rev 1) + + + + Makaimura for WonderSwan (Japan) + + + + Medarot Perfect Edition - Kabuto Version (Japan) + + + + Medarot Perfect Edition - Kuwagata Version (Japan) + + + + Meitantei Conan - Majutsushi no Chousenjou! (Japan) + + + + Meitantei Conan - Nishi no Meitantei Saidai no Kiki! (Japan) + + + + Metakomi Theraphy - Nee Kiite! (Japan) + + + + Mingle Magnet (Japan) (En,Ja) (Rev 1) + + + + Mobile Suit Gundam MSVS (Japan) + + + + MobileWonderGate (Japan) (Rev 1) + + + + Moero!! Pro Yakyuu Rookies (Japan) + + + + Morita Shougi for WonderSwan (Japan) + + + + Nazo Ou Pocket (Japan) + + + + Neon Genesis Evangelion - Shito Ikusei (Japan) + + + + Nice On (Japan) (Rev 1) + + + + Nihon Pro Mahjong Renmei Kounin - Tetsuman (Japan) (Rev 2) + + + + Nobunaga no Yabou for WonderSwan (Japan) + + + + Ou-chan no Oekaki Logic (Japan) + + + + Pocket Fighter (Japan) + + + + Pro Mahjong Kiwame for WonderSwan (Japan) (Rev 1) + + + + Puyo Puyo Tsuu (Japan) + + + + Puzzle Bobble (Japan) + + + + Rainbow Islands - Putty's Party (Japan) + + + + Ring Infinity (Japan) + + + + Robot Works (Japan) + + + + Robot Works (Hong Kong) (En,Ja) (Rev 1) + + + + Rockman & Forte - Mirai Kara no Chousensha (Japan) + + + + Sangokushi for WonderSwan (Japan) + + + + Sangokushi II for WonderSwan (Japan) + + + + SD Gundam - Emotional Jam (Japan) (Rev 3) + + + + SD Gundam - Emotional Jam (Japan) (Rev 2) + + + + SD Gundam G Generation - Gather Beat (Japan) + + + + SD Gundam Gashapon Senki - Episode 1 (Japan) + + + + SD Gundam Gashapon Senki - Episode 1 (Japan) (Alt) + + + + Senkaiden - TV Animation Senkaiden Houshin Engi Yori (Japan) + + + + Sennou Millennium (Japan) + + + + Shanghai Pocket (Japan) + + + + Shin Nihon Pro Wrestling - Toukon Retsuden (Japan) (Rev 1) + + + + Shougi Touryuumon (Japan) + + + + Side Pocket for WonderSwan (Japan) + + + + Slither Link (Japan) + + + + Soccer Yarou! - Challenge the World (Japan) + + + + Sotsugyou for WonderSwan (Japan) (Rev 1) + + + + Space Invaders (Japan) + + + + Super Robot Taisen Compact (Japan) (Rev 2) + + + + Super Robot Taisen Compact (Japan) + + + + Super Robot Taisen Compact (Japan) (Rev 1) + + + + Super Robot Taisen Compact 2 - Dai-1-bu - Chijou Gekidou Hen (Japan) + + + + Super Robot Taisen Compact 2 - Dai-2-bu - Uchuu Gekishin Hen (Japan) (Rev 4) + + + + Super Robot Taisen Compact 2 - Dai-3-bu - Ginga Kessen Hen (Japan) (Rev 2) + + + + Taikyoku Igo - Heisei Kiin (Japan) + + + + Tanjou Debut for WonderSwan (Japan) (Rev 1) + + + + Tare Panda no GunPey (Japan) + + + + Tekken Card Challenge (Japan) + + + + Tenori-on (Japan) (En) + + + + Terrors (Japan) + + + + Tetsujin 28 Gou (Japan) + + + + Time Bokan Series - Bokan Densetsu - Buta mo Odaterya Doronboo (Japan) + + + + Tokyo Majin Gakuen - Fuju Houroku (Japan) + + + + Trump Collection - Bottom-Up Teki Trump Seikatsu (Japan) (Rev 1) + + + + Trump Collection 2 - Bottom-Up Teki Sekaiisshuu no Tabi (Japan) (Rev 1) + + + + Turntablist - DJ Battle (Japan) + + + + Umizuri ni Ikou! (Japan) + + + + Uzumaki - Denshi Kaiki Hen (Japan) (Rev 4) + + + + Uzumaki - Noroi Simulation (Japan) + + + + Vaitz Blade (Japan) (Rev 1) + + + + Wasabi Produce - Street Dancer (Japan) + + + + Wonder Stadium (Japan) + + + + Wonder Stadium '99 (Japan) + + + + WonderSwan Handy Sonar (Japan) (Rev 1) + + + + WonderSwan Handy Sonar (Japan) (Rev 2) + + + + WonderWitch (Japan) (FreyaOS 1.0.0) (Program) + + + + WonderWitch (Japan) (FreyaOS 1.2.0) (Program) + + + + WonderWitch (Japan) (FreyaOS 1.1.5) (Program) + + + + WonderWitch (Japan) (FreyaOS 1.0.2) (Program) + + + + WonderWitch (Japan) (FreyaOS 1.0.3) (Program) + + + + WonderWitch (Japan) (FreyaOS 1.1.1) (Program) + + + + WonderWitch (Japan) (FreyaOS 1.1.2) (Program) + + + + WonderWitch (Japan) (FreyaOS 1.1.3) (Program) + + + + WonderWitch (Japan) (FreyaOS 1.1.4) (Program) + + + + WonderWitch (Japan) (FreyaOS 1.1.6b1) (Program) + + +
diff --git a/Assets/Resources/StoicGooseUnity/emu/Dat/Bandai - WonderSwan.dat.bytes.meta b/Assets/Resources/StoicGooseUnity/emu/Dat/Bandai - WonderSwan.dat.bytes.meta new file mode 100644 index 0000000..b4f0702 --- /dev/null +++ b/Assets/Resources/StoicGooseUnity/emu/Dat/Bandai - WonderSwan.dat.bytes.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 8c7855ba6b3026744bae333b09af339f +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/SampleScene.unity b/Assets/Scenes/SampleScene.unity index ccd80d4..aa79519 100644 --- a/Assets/Scenes/SampleScene.unity +++ b/Assets/Scenes/SampleScene.unity @@ -273,7 +273,7 @@ GameObject: m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 - m_IsActive: 1 + m_IsActive: 0 --- !u!108 &410087040 Light: m_ObjectHideFlags: 0 @@ -377,6 +377,63 @@ MonoBehaviour: m_LightCookieSize: {x: 1, y: 1} m_LightCookieOffset: {x: 0, y: 0} m_SoftShadowQuality: 1 +--- !u!1001 &650240201 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 70883439141109485, guid: 20e1ff69d8c691b4299757181385f497, type: 3} + propertyPath: m_Name + value: StoicGooseUnity + objectReference: {fileID: 0} + - target: {fileID: 1697793132499616605, guid: 20e1ff69d8c691b4299757181385f497, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1697793132499616605, guid: 20e1ff69d8c691b4299757181385f497, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1697793132499616605, guid: 20e1ff69d8c691b4299757181385f497, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1697793132499616605, guid: 20e1ff69d8c691b4299757181385f497, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 1697793132499616605, guid: 20e1ff69d8c691b4299757181385f497, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1697793132499616605, guid: 20e1ff69d8c691b4299757181385f497, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1697793132499616605, guid: 20e1ff69d8c691b4299757181385f497, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1697793132499616605, guid: 20e1ff69d8c691b4299757181385f497, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1697793132499616605, guid: 20e1ff69d8c691b4299757181385f497, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1697793132499616605, guid: 20e1ff69d8c691b4299757181385f497, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 20e1ff69d8c691b4299757181385f497, type: 3} --- !u!1 &832575517 GameObject: m_ObjectHideFlags: 0 @@ -433,3 +490,4 @@ SceneRoots: - {fileID: 330585546} - {fileID: 410087041} - {fileID: 832575519} + - {fileID: 650240201} diff --git a/Assets/Scenes/StoicGooseUnity.prefab b/Assets/Scenes/StoicGooseUnity.prefab new file mode 100644 index 0000000..3276f67 --- /dev/null +++ b/Assets/Scenes/StoicGooseUnity.prefab @@ -0,0 +1,365 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &70883439141109485 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1697793132499616605} + - component: {fileID: 8208523459577044397} + - component: {fileID: 1761025800639127157} + - component: {fileID: 175477975286986780} + - component: {fileID: 8490678488192273632} + - component: {fileID: 6011412303868462633} + m_Layer: 0 + m_Name: StoicGooseUnity + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1697793132499616605 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 70883439141109485} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 4829774629647575852} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &8208523459577044397 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 70883439141109485} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b7e1a8282bc4d764c81f63e62fd7aec8, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!114 &1761025800639127157 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 70883439141109485} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e8778828cf820b640b9d26ae977cdaba, type: 3} + m_Name: + m_EditorClassIdentifier: + mWidth: 0 + mHeight: 0 + mDataLenght: 0 + m_rawBufferWarper: {fileID: 0} + m_drawCanvas: {fileID: 1415903496979242101} + m_drawCanvasrect: {fileID: 4829774629647575852} +--- !u!114 &175477975286986780 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 70883439141109485} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 925771571ae9709429297d42587ce36d, type: 3} + m_Name: + m_EditorClassIdentifier: + m_as: {fileID: 6011412303868462633} +--- !u!114 &8490678488192273632 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 70883439141109485} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 54c184e653057e64da4b9be96f4d876d, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!82 &6011412303868462633 +AudioSource: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 70883439141109485} + m_Enabled: 1 + serializedVersion: 4 + OutputAudioMixerGroup: {fileID: 0} + m_audioClip: {fileID: 0} + m_Resource: {fileID: 0} + m_PlayOnAwake: 0 + m_Volume: 1 + m_Pitch: 1 + Loop: 1 + Mute: 0 + Spatialize: 0 + SpatializePostEffects: 0 + Priority: 128 + DopplerLevel: 1 + MinDistance: 1 + MaxDistance: 500 + Pan2D: 0 + rolloffMode: 0 + BypassEffects: 0 + BypassListenerEffects: 0 + BypassReverbZones: 0 + rolloffCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + panLevelCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + spreadCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + reverbZoneMixCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 +--- !u!1 &2203418964758308711 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 153069469667130431} + - component: {fileID: 1996193783355217829} + - component: {fileID: 1415903496979242101} + m_Layer: 5 + m_Name: GameRawImage + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &153069469667130431 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2203418964758308711} + m_LocalRotation: {x: 1, y: 0, z: 0, w: 0} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 4829774629647575852} + m_LocalEulerAnglesHint: {x: 180, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1996193783355217829 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2203418964758308711} + m_CullTransparentMesh: 1 +--- !u!114 &1415903496979242101 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2203418964758308711} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Texture: {fileID: 0} + m_UVRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 +--- !u!1 &5558964681998005947 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4829774629647575852} + - component: {fileID: 6904606342347745421} + - component: {fileID: 2921482546112766419} + - component: {fileID: 7864505849399022799} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4829774629647575852 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5558964681998005947} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 153069469667130431} + m_Father: {fileID: 1697793132499616605} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!223 &6904606342347745421 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5558964681998005947} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_VertexColorAlwaysGammaSpace: 0 + m_AdditionalShaderChannelsFlag: 0 + m_UpdateRectTransformForStandalone: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!114 &2921482546112766419 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5558964681998005947} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 0 +--- !u!114 &7864505849399022799 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5558964681998005947} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 diff --git a/Assets/Scenes/StoicGooseUnity.prefab.meta b/Assets/Scenes/StoicGooseUnity.prefab.meta new file mode 100644 index 0000000..2a3ab2a --- /dev/null +++ b/Assets/Scenes/StoicGooseUnity.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 20e1ff69d8c691b4299757181385f497 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Configuration.cs b/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Configuration.cs index d1e0e30..45b2bfb 100644 --- a/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Configuration.cs +++ b/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Configuration.cs @@ -1,90 +1,89 @@ using StoicGoose.Common.Utilities; using System.Collections.Generic; -using System.ComponentModel; public sealed class Configuration : ConfigurationBase { - [DisplayName("General")] - [Description("General settings.")] + //[DisplayName("General")] + //[Description("General settings.")] public GeneralConfiguration General { get; set; } = new GeneralConfiguration(); - [DisplayName("Video")] - [Description("Settings related to video output.")] + //[DisplayName("Video")] + //[Description("Settings related to video output.")] public VideoConfiguration Video { get; set; } = new VideoConfiguration(); - [DisplayName("Sound")] - [Description("Settings related to sound output.")] + //[DisplayName("Sound")] + //[Description("Settings related to sound output.")] public SoundConfiguration Sound { get; set; } = new SoundConfiguration(); - [DisplayName("Input")] - [Description("Settings related to emulation input.")] + //[DisplayName("Input")] + //[Description("Settings related to emulation input.")] public InputConfiguration Input { get; set; } = new InputConfiguration(); } public sealed class GeneralConfiguration : ConfigurationBase { - [DisplayName("Prefer Original WS")] - [Description("Prefer emulation of the original non-Color system.")] + //[DisplayName("Prefer Original WS")] + //[Description("Prefer emulation of the original non-Color system.")] public bool PreferOriginalWS { get; set; } = false; - [DisplayName("Use Bootstrap ROM")] - [Description("Toggle using WonderSwan bootstrap ROM images.")] + //[DisplayName("Use Bootstrap ROM")] + //[Description("Toggle using WonderSwan bootstrap ROM images.")] public bool UseBootstrap { get; set; } = false; - [DisplayName("WS Bootstrap ROM Path")] - [Description("Path to the WonderSwan bootstrap ROM image to use.")] + //[DisplayName("WS Bootstrap ROM Path")] + //[Description("Path to the WonderSwan bootstrap ROM image to use.")] public string BootstrapFile { get; set; } = string.Empty; - [DisplayName("WSC Bootstrap ROM Path")] - [Description("Path to the WonderSwan Color bootstrap ROM image to use.")] + //[DisplayName("WSC Bootstrap ROM Path")] + //[Description("Path to the WonderSwan Color bootstrap ROM image to use.")] public string BootstrapFileWSC { get; set; } = string.Empty; - [DisplayName("Limit FPS")] - [Description("Toggle limiting the framerate to the system's native ~75.47 Hz.")] + //[DisplayName("Limit FPS")] + //[Description("Toggle limiting the framerate to the system's native ~75.47 Hz.")] public bool LimitFps { get; set; } = true; - [DisplayName("Enable Cheats")] - [Description("Toggle using the cheat system.")] + //[DisplayName("Enable Cheats")] + //[Description("Toggle using the cheat system.")] public bool EnableCheats { get; set; } = true; - [DisplayName("Recent Files")] - [Description("List of recently loaded files.")] - public List RecentFiles { get; set; } = new List(15); + //[DisplayName("Recent Files")] + //[Description("List of recently loaded files.")] + //public List RecentFiles { get; set; } = new List(15); } public sealed class VideoConfiguration : ConfigurationBase { - [DisplayName("Screen Size")] - [Description("Size of the emulated screen, in times original display resolution.")] + //[DisplayName("Screen Size")] + //[Description("Size of the emulated screen, in times original display resolution.")] public int ScreenSize { get; set; } = 3; - [DisplayName("Shader")] - [Description("Currently selected shader.")] + //[DisplayName("Shader")] + //[Description("Currently selected shader.")] public string Shader { get; set; } = string.Empty; - [DisplayName("Brightness")] - [Description("Adjust the brightness of the emulated screen, in percent.")] - [Range(-100, 100)] + //[DisplayName("Brightness")] + //[Description("Adjust the brightness of the emulated screen, in percent.")] + //[Range(-100, 100)] public int Brightness { get; set; } = 0; - [DisplayName("Contrast")] - [Description("Adjust the contrast of the emulated screen, in percent.")] - [Range(0, 200)] + //[DisplayName("Contrast")] + //[Description("Adjust the contrast of the emulated screen, in percent.")] + //[Range(0, 200)] public int Contrast { get; set; } = 100; - [DisplayName("Saturation")] - [Description("Adjust the saturation of the emulated screen, in percent.")] - [Range(0, 200)] + //[DisplayName("Saturation")] + //[Description("Adjust the saturation of the emulated screen, in percent.")] + //[Range(0, 200)] public int Saturation { get; set; } = 100; } public sealed class SoundConfiguration : ConfigurationBase { - [DisplayName("Mute")] - [Description("Toggles muting all sound output.")] + //[DisplayName("Mute")] + //[Description("Toggles muting all sound output.")] public bool Mute { get; set; } = false; - [DisplayName("Low-Pass Filter")] - [Description("Toggles low-pass filter for all sound output.")] + //[DisplayName("Low-Pass Filter")] + //[Description("Toggles low-pass filter for all sound output.")] public bool LowPassFilter { get; set; } = true; } public sealed class InputConfiguration : ConfigurationBase { - [DisplayName("Automatic Remapping")] - [Description("Automatically remap X-/Y-pads with game orientation.")] + //[DisplayName("Automatic Remapping")] + //[Description("Automatically remap X-/Y-pads with game orientation.")] public bool AutoRemap { get; set; } = true; - [DisplayName("Game Controls")] - [Description("Controls related to game input, i.e. X-/Y-pads, etc.")] + //[DisplayName("Game Controls")] + //[Description("Controls related to game input, i.e. X-/Y-pads, etc.")] public Dictionary> GameControls { get; set; } = new Dictionary>(); - [DisplayName("System Controls")] - [Description("Controls related to hardware functions, i.e. volume button.")] + //[DisplayName("System Controls")] + //[Description("Controls related to hardware functions, i.e. volume button.")] public Dictionary> SystemControls { get; set; } = new Dictionary>(); } diff --git a/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Handle/DatabaseHandler.cs b/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Handle/DatabaseHandler.cs index 8a1933b..01953a3 100644 --- a/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Handle/DatabaseHandler.cs +++ b/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Handle/DatabaseHandler.cs @@ -4,23 +4,37 @@ using System.IO; using System.Linq; using System.Xml; using System.Xml.Serialization; - using StoicGoose.Common.Utilities; - public sealed class DatabaseHandler { readonly Dictionary datFiles = new(); + const string ResourceRoot = "StoicGooseUnity/emu/"; - public DatabaseHandler(string directory) + public DatabaseHandler() { - foreach (var file in Directory.EnumerateFiles(directory, "*.dat").OrderBy(x => x.Length)) { - var root = new XmlRootAttribute("datafile") { IsNullable = true }; - var serializer = new XmlSerializer(typeof(DatFile), root); - using FileStream stream = new(Path.Combine(directory, file), FileMode.Open); - var reader = XmlReader.Create(stream, new() { DtdProcessing = DtdProcessing.Ignore }); - datFiles.Add(Path.GetFileName(file), (DatFile)serializer.Deserialize(reader)); + string wsc = "Bandai - WonderSwan Color.dat"; + GetDatBytes(wsc, out byte[] loadedData); + using (MemoryStream stream = new MemoryStream(loadedData)) + { + var root = new XmlRootAttribute("datafile") { IsNullable = true }; + var serializer = new XmlSerializer(typeof(DatFile), root); + var reader = XmlReader.Create(stream, new() { DtdProcessing = DtdProcessing.Ignore }); + datFiles.Add(Path.GetFileName(wsc), (DatFile)serializer.Deserialize(reader)); + } + } + + { + string ws = "Bandai - WonderSwan.dat"; + GetDatBytes(ws, out byte[] loadedData); + using (MemoryStream stream = new MemoryStream(loadedData)) + { + var root = new XmlRootAttribute("datafile") { IsNullable = true }; + var serializer = new XmlSerializer(typeof(DatFile), root); + var reader = XmlReader.Create(stream, new() { DtdProcessing = DtdProcessing.Ignore }); + datFiles.Add(Path.GetFileName(ws), (DatFile)serializer.Deserialize(reader)); + } } Log.WriteEvent(LogSeverity.Information, this, $"Loaded {datFiles.Count} .dat file(s) with {datFiles.Sum(x => x.Value.Game.Length)} known game(s)."); @@ -28,6 +42,20 @@ public sealed class DatabaseHandler Log.WriteLine($" '{datFile.Header.Name} ({datFile.Header.Version})' from {datFile.Header.Homepage}"); } + bool GetDatBytes(string DatName, out byte[] loadedData) + { + try + { + loadedData = UnityEngine.Resources.Load(ResourceRoot + "Dat/" + DatName).bytes; + return true; + } + catch + { + loadedData = null; + return false; + } + } + private DatGame GetGame(uint romCrc32, int romSize) { return datFiles.Select(x => x.Value.Game).Select(x => x.FirstOrDefault(x => x.Rom.Any(y => y.Crc.ToLowerInvariant() == $"{romCrc32:x8}" && y.Size.ToLowerInvariant() == $"{romSize:D}"))).FirstOrDefault(x => x != null); diff --git a/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Handle/EmulatorHandler.cs b/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Handle/EmulatorHandler.cs index 72b320f..7a57248 100644 --- a/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Handle/EmulatorHandler.cs +++ b/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Handle/EmulatorHandler.cs @@ -1,4 +1,5 @@ using StoicGoose.Core.Interfaces; +using StoicGooseUnity; using System; using System.Diagnostics; using System.Threading; @@ -7,7 +8,7 @@ public class EmulatorHandler { readonly static string threadName = $"Unity_Emulation"; - Thread thread = default; + //Thread thread = default; volatile bool threadRunning = false, threadPaused = false; volatile bool isResetRequested = false; @@ -21,6 +22,7 @@ public class EmulatorHandler public EmulatorHandler(Type machineType) { + StoicGooseUnityAxiMem.Init(); Machine = Activator.CreateInstance(machineType) as IMachine; Machine.Initialize(); } @@ -32,8 +34,8 @@ public class EmulatorHandler threadRunning = true; threadPaused = false; - thread = new Thread(ThreadMainLoop) { Name = threadName, Priority = ThreadPriority.AboveNormal, IsBackground = false }; - thread.Start(); + //thread = new Thread(ThreadMainLoop) { Name = threadName, Priority = ThreadPriority.AboveNormal, IsBackground = false }; + //thread.Start(); } public void Reset() @@ -57,10 +59,9 @@ public class EmulatorHandler { threadRunning = false; threadPaused = false; - - thread?.Join(); - + //thread?.Join(); Machine.Shutdown(); + StoicGooseUnityAxiMem.FreeAllGCHandle(); } public void SetFpsLimiter(bool value) @@ -118,4 +119,12 @@ public class EmulatorHandler lastTime = stopWatch.Elapsed.TotalMilliseconds; } } + + public void Frame_Update() + { + if (!threadRunning) + return; + + Machine.RunFrame(); + } } diff --git a/Assets/Script/AppMain/Emulator/StoicGooseInterface/SGKeyboard.cs b/Assets/Script/AppMain/Emulator/StoicGooseInterface/SGKeyboard.cs index ab89199..716f8f5 100644 --- a/Assets/Script/AppMain/Emulator/StoicGooseInterface/SGKeyboard.cs +++ b/Assets/Script/AppMain/Emulator/StoicGooseInterface/SGKeyboard.cs @@ -1,16 +1,52 @@ +using StoicGooseUnity; using System; using System.Collections.Generic; +using System.Linq; using UnityEngine; public class SGKeyboard : MonoBehaviour { - internal void PollInput(ref List buttonsPressed, ref List buttonsHeld) + Dictionary dictKey2SGKey = new Dictionary(); + KeyCode[] checkKeys; + long currInput; + private void Awake() { - throw new NotImplementedException(); + SetVerticalOrientation(false); + } + + + internal void PollInput(ref long buttonsHeld) + { + buttonsHeld = currInput; } internal void SetVerticalOrientation(bool isVerticalOrientation) { - throw new NotImplementedException(); + dictKey2SGKey[KeyCode.Return] = StoicGooseKey.Start; + dictKey2SGKey[KeyCode.W] = StoicGooseKey.X1; + dictKey2SGKey[KeyCode.S] = StoicGooseKey.X2; + dictKey2SGKey[KeyCode.A] = StoicGooseKey.X3; + dictKey2SGKey[KeyCode.D] = StoicGooseKey.X4; + dictKey2SGKey[KeyCode.G] = StoicGooseKey.Y1; + dictKey2SGKey[KeyCode.V] = StoicGooseKey.Y2; + dictKey2SGKey[KeyCode.C] = StoicGooseKey.Y3; + dictKey2SGKey[KeyCode.B] = StoicGooseKey.Y4; + dictKey2SGKey[KeyCode.Return] = StoicGooseKey.Start; + dictKey2SGKey[KeyCode.J] = StoicGooseKey.B; + dictKey2SGKey[KeyCode.K] = StoicGooseKey.A; + checkKeys = dictKey2SGKey.Keys.ToArray(); + } + + public void Update_InputData() + { + currInput = 0; + for (int i = 0; i < checkKeys.Length; i++) + { + KeyCode key = checkKeys[i]; + if (Input.GetKey(key)) + { + currInput |= (long)dictKey2SGKey[key]; + } + } } } \ No newline at end of file diff --git a/Assets/Script/AppMain/Emulator/StoicGooseInterface/SGLogger.cs b/Assets/Script/AppMain/Emulator/StoicGooseInterface/SGLogger.cs new file mode 100644 index 0000000..19fcea2 --- /dev/null +++ b/Assets/Script/AppMain/Emulator/StoicGooseInterface/SGLogger.cs @@ -0,0 +1,36 @@ +using StoicGoose.Common.Utilities; +using System; + +public class SGLogger : IStoicGooseLogger +{ + public void Debug(string message) + { + UnityEngine.Debug.Log(message); + } + + public void Err(string message) + { + UnityEngine.Debug.LogError(message); + } + + public void Log(StoicGoose.Common.Utilities.LogType logtype, string message) + { + switch (logtype) + { + case LogType.Debug: + Debug(message); + break; + case LogType.Warning: + Warning(message); + break; + case LogType.Error: + Err(message); + break; + } + } + + public void Warning(string message) + { + UnityEngine.Debug.LogWarning(message); + } +} diff --git a/Assets/Script/AppMain/Emulator/StoicGooseInterface/SGLogger.cs.meta b/Assets/Script/AppMain/Emulator/StoicGooseInterface/SGLogger.cs.meta new file mode 100644 index 0000000..9ac0db4 --- /dev/null +++ b/Assets/Script/AppMain/Emulator/StoicGooseInterface/SGLogger.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e9f99144ff5ead44297997370fab702c \ No newline at end of file diff --git a/Assets/Script/AppMain/Emulator/StoicGooseInterface/SGSoundPlayer.cs b/Assets/Script/AppMain/Emulator/StoicGooseInterface/SGSoundPlayer.cs index b16597f..11279d3 100644 --- a/Assets/Script/AppMain/Emulator/StoicGooseInterface/SGSoundPlayer.cs +++ b/Assets/Script/AppMain/Emulator/StoicGooseInterface/SGSoundPlayer.cs @@ -1,8 +1,5 @@ using System; using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; using UnityEngine; public class SGSoundPlayer : MonoBehaviour//, ISoundPlayer @@ -12,7 +9,6 @@ public class SGSoundPlayer : MonoBehaviour//, ISoundPlayer private RingBuffer _buffer = new RingBuffer(44100 * 2); private TimeSpan lastElapsed; public double audioFPS { get; private set; } - public bool IsRecording { get; private set; } void Awake() { @@ -72,24 +68,19 @@ public class SGSoundPlayer : MonoBehaviour//, ISoundPlayer } } - public void SubmitSamples(short[] buffer, short[][] ChannelSamples, int samples_a) - { - var current = UStoicGoose.sw.Elapsed; - var delta = current - lastElapsed; - lastElapsed = current; - audioFPS = 1d / delta.TotalSeconds; + //public void SubmitSamples(short[] buffer, short[][] ChannelSamples, int samples_a) + //{ + // var current = UStoicGoose.sw.Elapsed; + // var delta = current - lastElapsed; + // lastElapsed = current; + // audioFPS = 1d / delta.TotalSeconds; - for (int i = 0; i < samples_a; i += 1) - { - _buffer.Write(buffer[i] / 32767.0f); + // for (int i = 0; i < samples_a; i += 1) + // { + // _buffer.Write(buffer[i] / 32767.0f); - } - if (IsRecording) - { - dataChunk.AddSampleData(buffer, samples_a); - waveHeader.FileLength += (uint)samples_a; - } - } + // } + //} public void BufferWirte(int Off, byte[] Data) { } @@ -109,50 +100,17 @@ public class SGSoundPlayer : MonoBehaviour//, ISoundPlayer } - void Update() + internal void EnqueueSamples(short[] buffer) { - if (Input.GetKeyDown(KeyCode.F3)) + var current = UStoicGoose.sw.Elapsed; + var delta = current - lastElapsed; + lastElapsed = current; + audioFPS = 1d / delta.TotalSeconds; + + for (int i = 0; i < buffer.Length; i += 1) { - BeginRecording(); - Debug.Log("¼"); + _buffer.Write(buffer[i] / 32767.0f); } - if (Input.GetKeyDown(KeyCode.F4)) - { - SaveRecording("D:/1.wav"); - Debug.Log(""); - } - } - WaveHeader waveHeader; - FormatChunk formatChunk; - DataChunk dataChunk; - public void BeginRecording() - { - waveHeader = new WaveHeader(); - formatChunk = new FormatChunk(44100, 2); - dataChunk = new DataChunk(); - waveHeader.FileLength += formatChunk.Length(); - - IsRecording = true; - - } - - - public void SaveRecording(string filename) - { - using (FileStream file = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) - { - file.Write(waveHeader.GetBytes(), 0, (int)waveHeader.Length()); - file.Write(formatChunk.GetBytes(), 0, (int)formatChunk.Length()); - file.Write(dataChunk.GetBytes(), 0, (int)dataChunk.Length()); - } - - IsRecording = false; - - } - - internal void EnqueueSamples(short[] s) - { - throw new NotImplementedException(); } internal void Unpause() @@ -165,164 +123,4 @@ public class SGSoundPlayer : MonoBehaviour//, ISoundPlayer throw new NotImplementedException(); } - class WaveHeader - { - const string fileTypeId = "RIFF"; - const string mediaTypeId = "WAVE"; - - public string FileTypeId { get; private set; } - public uint FileLength { get; set; } - public string MediaTypeId { get; private set; } - - public WaveHeader() - { - FileTypeId = fileTypeId; - MediaTypeId = mediaTypeId; - FileLength = 4; /* Minimum size is always 4 bytes */ - } - - public byte[] GetBytes() - { - List chunkData = new List(); - - chunkData.AddRange(Encoding.ASCII.GetBytes(FileTypeId)); - chunkData.AddRange(BitConverter.GetBytes(FileLength)); - chunkData.AddRange(Encoding.ASCII.GetBytes(MediaTypeId)); - - return chunkData.ToArray(); - } - - public uint Length() - { - return (uint)GetBytes().Length; - } - } - - class FormatChunk - { - const string chunkId = "fmt "; - - ushort bitsPerSample, channels; - uint frequency; - - public string ChunkId { get; private set; } - public uint ChunkSize { get; private set; } - public ushort FormatTag { get; private set; } - - public ushort Channels - { - get { return channels; } - set { channels = value; RecalcBlockSizes(); } - } - - public uint Frequency - { - get { return frequency; } - set { frequency = value; RecalcBlockSizes(); } - } - - public uint AverageBytesPerSec { get; private set; } - public ushort BlockAlign { get; private set; } - - public ushort BitsPerSample - { - get { return bitsPerSample; } - set { bitsPerSample = value; RecalcBlockSizes(); } - } - - public FormatChunk() - { - ChunkId = chunkId; - ChunkSize = 16; - FormatTag = 1; /* MS PCM (Uncompressed wave file) */ - Channels = 2; /* Default to stereo */ - Frequency = 44100; /* Default to 44100hz */ - BitsPerSample = 16; /* Default to 16bits */ - RecalcBlockSizes(); - } - - public FormatChunk(int frequency, int channels) : this() - { - Channels = (ushort)channels; - Frequency = (ushort)frequency; - RecalcBlockSizes(); - } - - private void RecalcBlockSizes() - { - BlockAlign = (ushort)(channels * (bitsPerSample / 8)); - AverageBytesPerSec = frequency * BlockAlign; - } - - public byte[] GetBytes() - { - List chunkBytes = new List(); - - chunkBytes.AddRange(Encoding.ASCII.GetBytes(ChunkId)); - chunkBytes.AddRange(BitConverter.GetBytes(ChunkSize)); - chunkBytes.AddRange(BitConverter.GetBytes(FormatTag)); - chunkBytes.AddRange(BitConverter.GetBytes(Channels)); - chunkBytes.AddRange(BitConverter.GetBytes(Frequency)); - chunkBytes.AddRange(BitConverter.GetBytes(AverageBytesPerSec)); - chunkBytes.AddRange(BitConverter.GetBytes(BlockAlign)); - chunkBytes.AddRange(BitConverter.GetBytes(BitsPerSample)); - - return chunkBytes.ToArray(); - } - - public uint Length() - { - return (uint)GetBytes().Length; - } - } - - class DataChunk - { - const string chunkId = "data"; - - public string ChunkId { get; private set; } - public uint ChunkSize { get; set; } - public List WaveData { get; private set; } - - public DataChunk() - { - ChunkId = chunkId; - ChunkSize = 0; - WaveData = new List(); - } - - public byte[] GetBytes() - { - List chunkBytes = new List(); - - chunkBytes.AddRange(Encoding.ASCII.GetBytes(ChunkId)); - chunkBytes.AddRange(BitConverter.GetBytes(ChunkSize)); - byte[] bufferBytes = new byte[WaveData.Count * 2]; - Buffer.BlockCopy(WaveData.ToArray(), 0, bufferBytes, 0, bufferBytes.Length); - chunkBytes.AddRange(bufferBytes.ToList()); - - return chunkBytes.ToArray(); - } - - public uint Length() - { - return (uint)GetBytes().Length; - } - - public void AddSampleData(short[] stereoBuffer) - { - WaveData.AddRange(stereoBuffer); - - ChunkSize += (uint)(stereoBuffer.Length * 2); - } - //public unsafe void AddSampleData(short* stereoBuffer, int lenght) - //{ - // for (int i = 0; i < lenght; i++) - // { - // WaveData.Add(stereoBuffer[i]); - // } - - // ChunkSize += (uint)(lenght * 2); - //} - } } diff --git a/Assets/Script/AppMain/Emulator/StoicGooseInterface/SGVideoPlayer.cs b/Assets/Script/AppMain/Emulator/StoicGooseInterface/SGVideoPlayer.cs index 8047959..a5646e6 100644 --- a/Assets/Script/AppMain/Emulator/StoicGooseInterface/SGVideoPlayer.cs +++ b/Assets/Script/AppMain/Emulator/StoicGooseInterface/SGVideoPlayer.cs @@ -1,12 +1,112 @@ using System; using UnityEngine; +using UnityEngine.UI; -public class SGVideoPlayer : MonoBehaviour//, ISoundPlayer +public class SGVideoPlayer : MonoBehaviour { + + [SerializeField] + private int mWidth; + [SerializeField] + private int mHeight; + [SerializeField] + private int mDataLenght; + [SerializeField] + private Texture2D m_rawBufferWarper; + [SerializeField] + private RawImage m_drawCanvas; + [SerializeField] + private RectTransform m_drawCanvasrect; + //byte[] mFrameData; + IntPtr mFrameDataPtr; + + private TimeSpan lastElapsed; + public double videoFPS { get; private set; } + public ulong mFrame { get; private set; } + bool bInit = false; + bool bHadData = false; + + private void Awake() + { + bHadData = false; + mFrame = 0; + m_drawCanvas = GameObject.Find("GameRawImage").GetComponent(); + m_drawCanvasrect = m_drawCanvas.GetComponent(); + } + + public void Initialize() + { + m_drawCanvas.color = Color.white; + + if (m_rawBufferWarper == null) + { + mDataLenght = mWidth * mHeight * 4; + //mFrameData = new byte[mDataLenght]; + + //// ̶飬ֹƶ + //var bitmapcolorRect_handle = GCHandle.Alloc(mFrameData, GCHandleType.Pinned); + //// ȡָ + //mFrameDataPtr = bitmapcolorRect_handle.AddrOfPinnedObject(); + + + //MAMEBGRA32úú + m_rawBufferWarper = new Texture2D(mWidth, mHeight, TextureFormat.BGRA32, false); + //m_rawBufferWarper = new Texture2D(mWidth, mHeight, TextureFormat.ARGB32, false); + m_rawBufferWarper.filterMode = FilterMode.Point; + } + + //mFrameDataPtr = framePtr; + m_drawCanvas.texture = m_rawBufferWarper; + bInit = true; + + float targetWidth = ((float)mWidth / mHeight) * m_drawCanvasrect.rect.height; + m_drawCanvasrect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, targetWidth); + } + + public void StopVideo() + { + bInit = false; + m_drawCanvas.color = new Color(0, 0, 0, 0); + } + + void Update() + { + if (!bHadData + || + !UStoicGoose.instance.emulatorHandler.IsRunning) + return; + + if (!bInit) + { + Initialize(); + return; + } + m_rawBufferWarper.LoadRawTextureData(mFrameDataPtr, mDataLenght); + m_rawBufferWarper.Apply(); + } + + + public byte[] GetScreenImg() + { + return (m_drawCanvas.texture as Texture2D).EncodeToJPG(); + } + public bool IsVerticalOrientation { get; internal set; } - internal void UpdateScreen(byte[] obj) + internal void UpdateScreen(IntPtr ptr, long frame_number) { - throw new NotImplementedException(); + var current = UStoicGoose.sw.Elapsed; + var delta = current - lastElapsed; + lastElapsed = current; + videoFPS = 1d / delta.TotalSeconds; + mFrameDataPtr = ptr; + if (!bHadData) + bHadData = true; + } + + internal void SetSize(int screenWidth, int screenHeight) + { + mWidth = screenWidth; + mHeight = screenHeight; } } diff --git a/Assets/Script/AppMain/Emulator/UStoicGoose.cs b/Assets/Script/AppMain/Emulator/UStoicGoose.cs index 56b2ca2..523b650 100644 --- a/Assets/Script/AppMain/Emulator/UStoicGoose.cs +++ b/Assets/Script/AppMain/Emulator/UStoicGoose.cs @@ -13,18 +13,6 @@ public class UStoicGoose : MonoBehaviour { public static UStoicGoose instance; public static System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew(); - void Awake() - { - instance = this; - Program.InitPath(Application.persistentDataPath); - Init(); - LoadAndRunCartridge(""); - } - - private void OnDestroy() - { - EmuClose(); - } /* Constants */ readonly static int maxScreenSizeFactor = 5; @@ -43,7 +31,8 @@ public class UStoicGoose : MonoBehaviour SGVideoPlayer graphicsHandler = default; SGSoundPlayer soundHandler = default; SGKeyboard inputHandler = default; - EmulatorHandler emulatorHandler = default; + SGLogger loggerHandler = default; + public EmulatorHandler emulatorHandler = default; /* Misc. windows */ //SoundRecorderForm soundRecorderForm = default; @@ -53,9 +42,39 @@ public class UStoicGoose : MonoBehaviour Type machineType = default; bool isVerticalOrientation = false; string internalEepromPath = string.Empty; + + public string CurrRomName { get; private set; } + //Cheat[] cheats = default; + #region Unity 生命周期 + void Awake() + { + instance = this; + loggerHandler = new SGLogger(); + graphicsHandler = this.gameObject.GetComponent(); + soundHandler = this.gameObject.GetComponent(); + inputHandler = this.gameObject.GetComponent(); + Log.Initialize(loggerHandler); + Program.InitPath(Application.persistentDataPath); + Init(); + LoadAndRunCartridge("G:/BaiduNetdiskDownload/Rockman & Forte - Mirai Kara no Chousen Sha (J) [M][!].ws"); + } + private void Update() + { + if (!emulatorHandler.IsRunning) + return; + + inputHandler.Update_InputData(); + + emulatorHandler.Frame_Update(); + } + void OnDestroy() + { + EmuClose(); + } + #endregion private void Init() { Log.WriteEvent(LogSeverity.Information, this, "Initializing emulator and UI..."); @@ -67,7 +86,7 @@ public class UStoicGoose : MonoBehaviour InitializeOtherHandlers(); //InitializeWindows(); - SizeAndPositionWindow(); + //SizeAndPositionWindow(); SetWindowTitleAndStatus(); Log.WriteEvent(LogSeverity.Information, this, "Initialization done!"); } @@ -111,25 +130,22 @@ public class UStoicGoose : MonoBehaviour private void InitializeOtherHandlers() { - databaseHandler = new DatabaseHandler(Program.NoIntroDatPath); + databaseHandler = new DatabaseHandler(); //statusIconsLocation = machineType == typeof(WonderSwan) ? new(0, DisplayControllerCommon.ScreenHeight) : new(DisplayControllerCommon.ScreenWidth, 0); - graphicsHandler = this.gameObject.GetComponent(); + //TODO graphicsHandler基本参数,可能需要补上 //graphicsHandler = new GraphicsHandler(machineType, new(emulatorHandler.Machine.ScreenWidth, emulatorHandler.Machine.ScreenHeight), statusIconsLocation, statusIconSize, machineType != typeof(WonderSwan), Program.Configuration.Video.Shader) //{ // IsVerticalOrientation = isVerticalOrientation //}; - soundHandler = this.gameObject.GetComponent(); //TODO 声音基本参数,可能需要补上 //soundHandler = new SoundHandler(44100, 2); //soundHandler.SetVolume(1.0f); //soundHandler.SetMute(Program.Configuration.Sound.Mute); //soundHandler.SetLowPassFilter(Program.Configuration.Sound.LowPassFilter); - inputHandler = this.gameObject.GetComponent(); - //TODO Input基本参数,可能需要补上 //inputHandler = new InputHandler(renderControl); //inputHandler.SetKeyMapping(Program.Configuration.Input.GameControls, Program.Configuration.Input.SystemControls); @@ -140,6 +156,7 @@ public class UStoicGoose : MonoBehaviour // .Select(x => x.Split('=', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)) // .ToDictionary(x => x[0], x => x[1])); + emulatorHandler.Machine.DisplayController.SendFramebuffer = graphicsHandler.UpdateScreen; emulatorHandler.Machine.SoundController.SendSamples = (s) => { @@ -149,15 +166,17 @@ public class UStoicGoose : MonoBehaviour emulatorHandler.Machine.ReceiveInput += () => { - var buttonsPressed = new List(); - var buttonsHeld = new List(); + //var buttonsPressed = new List(); + //var buttonsHeld = new List(); - inputHandler.PollInput(ref buttonsPressed, ref buttonsHeld); + //inputHandler.PollInput(ref buttonsPressed, ref buttonsHeld); + long buttonsHeld = 0; + inputHandler.PollInput(ref buttonsHeld); + return buttonsHeld; + //if (buttonsPressed.Contains("Volume")) + // emulatorHandler.Machine.SoundController.ChangeMasterVolume(); - if (buttonsPressed.Contains("Volume")) - emulatorHandler.Machine.SoundController.ChangeMasterVolume(); - - return (buttonsPressed, buttonsHeld); + //return (buttonsPressed, buttonsHeld); }; //renderControl.Resize += (s, e) => { if (s is Control control) graphicsHandler.Resize(control.ClientRectangle); }; @@ -209,12 +228,12 @@ public class UStoicGoose : MonoBehaviour private void SizeAndPositionWindow() { - //if (WindowState == FormWindowState.Maximized) + graphicsHandler.SetSize(emulatorHandler.Machine.ScreenWidth, emulatorHandler.Machine.ScreenHeight); + //if (WindowState == For emulatorHandler.Machine.ScreenHeight;mWindowState.Maximized) // WindowState = FormWindowState.Normal; //MinimumSize = SizeFromClientSize(CalculateRequiredClientSize(2)); //Size = SizeFromClientSize(CalculateRequiredClientSize(Program.Configuration.Video.ScreenSize)); - //var screen = Screen.FromControl(this); //var workingArea = screen.WorkingArea; //Location = new Point() @@ -224,6 +243,7 @@ public class UStoicGoose : MonoBehaviour //}; } + //TODO 设置屏幕宽高 看是否需要 //private Size CalculateRequiredClientSize(int screenSize) //{ @@ -338,6 +358,8 @@ public class UStoicGoose : MonoBehaviour graphicsHandler.IsVerticalOrientation = isVerticalOrientation = emulatorHandler.Machine.Cartridge.Metadata.Orientation == CartridgeMetadata.Orientations.Vertical; inputHandler.SetVerticalOrientation(isVerticalOrientation); + CurrRomName = Path.GetFileName(filename); + LoadRam(); LoadBootstrap(emulatorHandler.Machine is WonderSwan ? Program.Configuration.General.BootstrapFile : Program.Configuration.General.BootstrapFileWSC); @@ -353,7 +375,8 @@ public class UStoicGoose : MonoBehaviour private void LoadRam() { - var path = Path.Combine(Program.SaveDataPath, $"{Path.GetFileNameWithoutExtension(Program.Configuration.General.RecentFiles.First())}.sav"); + //var path = Path.Combine(Program.SaveDataPath, $"{Path.GetFileNameWithoutExtension(Program.Configuration.General.RecentFiles.First())}.sav"); + var path = Path.Combine(Program.SaveDataPath, $"{CurrRomName}.sav"); if (!File.Exists(path)) return; using var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); @@ -383,7 +406,8 @@ public class UStoicGoose : MonoBehaviour var data = emulatorHandler.Machine.GetSaveData(); if (data.Length == 0) return; - var path = Path.Combine(Program.SaveDataPath, $"{Path.GetFileNameWithoutExtension(Program.Configuration.General.RecentFiles.First())}.sav"); + //var path = Path.Combine(Program.SaveDataPath, $"{Path.GetFileNameWithoutExtension(Program.Configuration.General.RecentFiles.First())}.sav"); + var path = Path.Combine(Program.SaveDataPath, $"{CurrRomName}.sav"); using var stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite); stream.Write(data, 0, data.Length); @@ -435,7 +459,7 @@ static class Program static string programDataDirectory;//= Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), Application.ProductName); static string programConfigPath;//= Path.Combine(programDataDirectory, jsonConfigFileName); - public static Configuration Configuration { get; private set; } = LoadConfiguration(programConfigPath); + public static Configuration Configuration;// { get; private set; } = LoadConfiguration(programConfigPath); public static string DataPath;//{ get; } = string.Empty; public static string InternalDataPath;//{ get; } = string.Empty; @@ -443,8 +467,8 @@ static class Program public static string CheatsDataPath;//{ get; } = string.Empty; public static string DebuggingDataPath;//{ get; } = string.Empty; - readonly static string programApplicationDirectory = AppDomain.CurrentDomain.BaseDirectory; - readonly static string programAssetsDirectory = Path.Combine(programApplicationDirectory, assetsDirectoryName); + static string programApplicationDirectory;// = AppDomain.CurrentDomain.BaseDirectory; + static string programAssetsDirectory;// = Path.Combine(programApplicationDirectory, assetsDirectoryName); //public static string ShaderPath { get; } = string.Empty; public static string NoIntroDatPath;// { get; } = string.Empty; @@ -455,7 +479,6 @@ static class Program { try { - jsonConfigFileName = "Config.json"; logFileName = "Log.txt"; internalDataDirectoryName = "Internal"; @@ -468,9 +491,10 @@ static class Program mutexName = $"Unity_{GetVersionDetails()}"; programDataDirectory = Path.Combine(CustonDataDir, "AxibugEmu"); programConfigPath = Path.Combine(programDataDirectory, jsonConfigFileName); - + Configuration = LoadConfiguration(programConfigPath); Log.WriteLine(Path.Combine(programDataDirectory, logFileName)); - + programApplicationDirectory = AppDomain.CurrentDomain.BaseDirectory; + programAssetsDirectory = Path.Combine(programApplicationDirectory, assetsDirectoryName); Directory.CreateDirectory(DataPath = programDataDirectory); Directory.CreateDirectory(InternalDataPath = Path.Combine(programDataDirectory, internalDataDirectoryName)); Directory.CreateDirectory(SaveDataPath = Path.Combine(programDataDirectory, saveDataDirectoryName));