diff --git a/BizHawk.Emulation/Consoles/Nintendo/SNES/LibsnesCore.cs b/BizHawk.Emulation/Consoles/Nintendo/SNES/LibsnesCore.cs index 22851655bb..4391f5176e 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/SNES/LibsnesCore.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/SNES/LibsnesCore.cs @@ -2,7 +2,7 @@ //TODO //libsnes needs to be modified to support multiple instances - THIS IS NECESSARY - or else loading one game and then another breaks things -//rename snes.dll so nobody thinks it's a stock snes.dll (we'll be editing it substantially at some point) +// edit - this is a lot of work //wrap dll code around some kind of library-accessing interface so that it doesnt malfunction if the dll is unavailable using System; @@ -17,27 +17,27 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES { public unsafe static class LibsnesDll { - [DllImport("snes.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)] public static extern string snes_library_id(); - [DllImport("snes.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int snes_library_revision_major(); - [DllImport("snes.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int snes_library_revision_minor(); - [DllImport("snes.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void snes_init(); - [DllImport("snes.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void snes_power(); - [DllImport("snes.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void snes_reset(); - [DllImport("snes.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void snes_run(); - [DllImport("snes.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void snes_term(); - [DllImport("snes.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void snes_unload_cartridge(); - [DllImport("snes.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void snes_load_cartridge_normal( [MarshalAs(UnmanagedType.LPStr)] string rom_xml, @@ -53,49 +53,53 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES public delegate ushort snes_input_state_t(int port, int device, int index, int id); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void snes_audio_sample_t(ushort left, ushort right); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void snes_scanlineStart_t(int line); - [DllImport("snes.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void snes_set_video_refresh(snes_video_refresh_t video_refresh); - [DllImport("snes.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void snes_set_input_poll(snes_input_poll_t input_poll); - [DllImport("snes.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void snes_set_input_state(snes_input_state_t input_state); - [DllImport("snes.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void snes_set_audio_sample(snes_audio_sample_t audio_sample); + [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void snes_set_scanlineStart(snes_scanlineStart_t scanlineStart); - [DllImport("snes.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.U1)] public static extern bool snes_check_cartridge( [MarshalAs(UnmanagedType.LPArray)] byte[] rom_data, int rom_size); - [DllImport("snes.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.U1)] public static extern SNES_REGION snes_get_region(); - [DllImport("snes.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int snes_get_memory_size(SNES_MEMORY id); - [DllImport("snes.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr snes_get_memory_data(SNES_MEMORY id); - [DllImport("snes.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int snes_serialize_size(); [return: MarshalAs(UnmanagedType.U1)] - [DllImport("snes.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)] public static extern bool snes_serialize(IntPtr data, int size); [return: MarshalAs(UnmanagedType.U1)] - [DllImport("snes.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)] public static extern bool snes_unserialize(IntPtr data, int size); - [DllImport("snes.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void snes_set_layer_enable(int layer, int priority, [MarshalAs(UnmanagedType.U1)] bool enable ); - [DllImport("snes.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int snes_peek_logical_register(SNES_REG reg); public enum SNES_REG : int @@ -180,7 +184,43 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES } } + public class ScanlineHookManager + { + public void Register(object tag, Action callback) + { + var rr = new RegistrationRecord(); + rr.tag = tag; + rr.callback = callback; + Unregister(tag); + records.Add(rr); + OnHooksChanged(); + } + + public int HookCount { get { return records.Count; } } + + public virtual void OnHooksChanged() { } + + public void Unregister(object tag) + { + records.RemoveAll((r) => r.tag == tag); + } + + public void HandleScanline(int scanline) + { + foreach (var rr in records) rr.callback(scanline); + } + + List records = new List(); + + class RegistrationRecord + { + public object tag; + public int scanline; + public Action callback; + } + } + public unsafe class LibsnesCore : IEmulator, IVideoProvider, ISoundProvider { bool disposed = false; @@ -195,6 +235,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_input_poll(null); BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_input_state(null); BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_audio_sample(null); + BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_scanlineStart(null); LibsnesDll.snes_unload_cartridge(); LibsnesDll.snes_term(); @@ -205,11 +246,36 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES //that will be necessary to get it saving to disk byte[] disposedSaveRam; - //we can only have one active snes core at a time, due to libsnes being so static. //so we'll track the current one here and detach the previous one whenever a new one is booted up. static LibsnesCore CurrLibsnesCore; + public class MyScanlineHookManager : ScanlineHookManager + { + public MyScanlineHookManager(LibsnesCore core) + { + this.core = core; + } + LibsnesCore core; + + public override void OnHooksChanged() + { + core.OnScanlineHooksChanged(); + } + } + public MyScanlineHookManager ScanlineHookManager; + void OnScanlineHooksChanged() + { + if (disposed) return; + if (ScanlineHookManager.HookCount == 0) LibsnesDll.snes_set_scanlineStart(null); + else LibsnesDll.snes_set_scanlineStart(scanlineStart_cb); + } + + void snes_scanlineStart(int line) + { + ScanlineHookManager.HandleScanline(line); + } + public LibsnesCore(byte[] romData) { //attach this core as the current @@ -217,6 +283,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES CurrLibsnesCore.Dispose(); CurrLibsnesCore = this; + ScanlineHookManager = new MyScanlineHookManager(this); + LibsnesDll.snes_init(); vidcb = new LibsnesDll.snes_video_refresh_t(snes_video_refresh); @@ -231,6 +299,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES soundcb = new LibsnesDll.snes_audio_sample_t(snes_audio_sample); BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_audio_sample(soundcb); + scanlineStart_cb = new LibsnesDll.snes_scanlineStart_t(snes_scanlineStart); + // start up audio resampler InitAudio(); @@ -253,6 +323,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES LibsnesDll.snes_input_poll_t pollcb; LibsnesDll.snes_input_state_t inputcb; LibsnesDll.snes_audio_sample_t soundcb; + LibsnesDll.snes_scanlineStart_t scanlineStart_cb; ushort snes_input_state(int port, int device, int index, int id) { diff --git a/BizHawk.Emulation/Consoles/Nintendo/SNES/SNESGraphicsDecoder.cs b/BizHawk.Emulation/Consoles/Nintendo/SNES/SNESGraphicsDecoder.cs index 7ccbdd9106..9eddd51f69 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/SNES/SNESGraphicsDecoder.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/SNES/SNESGraphicsDecoder.cs @@ -245,6 +245,10 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES { int tileEntry = vram[tidx * 2]; int src = tileEntry * 64; + if (tileEntry != 0) + { + int zzz = 9; + } for (int py = 0, pix=src; py < 8; py++) { for (int px = 0; px < 8; px++, pix++) diff --git a/BizHawk.MultiClient/MainForm.cs b/BizHawk.MultiClient/MainForm.cs index 81bd26b91b..d50f0a6b6f 100644 --- a/BizHawk.MultiClient/MainForm.cs +++ b/BizHawk.MultiClient/MainForm.cs @@ -2210,7 +2210,11 @@ namespace BizHawk.MultiClient NESNameTableViewer1.UpdateValues(); NESPPU1.UpdateValues(); PCEBGViewer1.UpdateValues(); - SNESGraphicsDebugger1.UpdateValues(); + } + + public void UpdateToolsLoadstate() + { + SNESGraphicsDebugger1.UpdateToolsLoadstate(); } /// @@ -2222,6 +2226,7 @@ namespace BizHawk.MultiClient //frame of execution in its list view. LuaConsole1.LuaImp.FrameRegisterAfter(); TAStudio1.UpdateValues(); + SNESGraphicsDebugger1.UpdateToolsAfter(); } private unsafe Image MakeScreenshotImage() @@ -2376,6 +2381,7 @@ namespace BizHawk.MultiClient Global.OSD.ClearGUIText(); UpdateToolsBefore(); UpdateToolsAfter(); + UpdateToolsLoadstate(); Global.OSD.AddMessage("Loaded state: " + name); } else diff --git a/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.Designer.cs b/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.Designer.cs index adf6e55e49..8e4c052eda 100644 --- a/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.Designer.cs +++ b/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.Designer.cs @@ -95,6 +95,7 @@ this.saveWindowPositionToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.groupBox3 = new System.Windows.Forms.GroupBox(); this.groupBox4 = new System.Windows.Forms.GroupBox(); + this.radioButton15 = new System.Windows.Forms.RadioButton(); this.radioButton14 = new System.Windows.Forms.RadioButton(); this.groupBox5 = new System.Windows.Forms.GroupBox(); this.tabctrlDetails = new System.Windows.Forms.TabControl(); @@ -111,9 +112,11 @@ this.tabPage2 = new System.Windows.Forms.TabPage(); this.label17 = new System.Windows.Forms.Label(); this.label18 = new System.Windows.Forms.Label(); + this.nudScanline = new System.Windows.Forms.NumericUpDown(); + this.sliderScanline = new System.Windows.Forms.TrackBar(); + this.label19 = new System.Windows.Forms.Label(); this.paletteViewer = new BizHawk.MultiClient.SNESGraphicsViewer(); this.viewer = new BizHawk.MultiClient.SNESGraphicsViewer(); - this.radioButton15 = new System.Windows.Forms.RadioButton(); this.groupBox1.SuspendLayout(); this.groupBox2.SuspendLayout(); this.menuStrip1.SuspendLayout(); @@ -122,6 +125,8 @@ this.groupBox5.SuspendLayout(); this.tabctrlDetails.SuspendLayout(); this.tpPalette.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.nudScanline)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.sliderScanline)).BeginInit(); this.SuspendLayout(); // // label1 @@ -136,6 +141,7 @@ // groupBox1 // this.groupBox1.Controls.Add(this.rbBG4); + this.groupBox1.Controls.Add(this.label18); this.groupBox1.Controls.Add(this.rbBG3); this.groupBox1.Controls.Add(this.rbBG2); this.groupBox1.Controls.Add(this.rbBG1); @@ -876,6 +882,18 @@ this.groupBox4.TabIndex = 35; this.groupBox4.TabStop = false; // + // radioButton15 + // + this.radioButton15.AutoSize = true; + this.radioButton15.Enabled = false; + this.radioButton15.Location = new System.Drawing.Point(169, 83); + this.radioButton15.Name = "radioButton15"; + this.radioButton15.Size = new System.Drawing.Size(58, 17); + this.radioButton15.TabIndex = 33; + this.radioButton15.TabStop = true; + this.radioButton15.Text = "Mode7"; + this.radioButton15.UseVisualStyleBackColor = true; + // // radioButton14 // this.radioButton14.AutoSize = true; @@ -891,7 +909,7 @@ // groupBox5 // this.groupBox5.Controls.Add(this.paletteViewer); - this.groupBox5.Location = new System.Drawing.Point(6, 378); + this.groupBox5.Location = new System.Drawing.Point(6, 387); this.groupBox5.Name = "groupBox5"; this.groupBox5.Size = new System.Drawing.Size(319, 328); this.groupBox5.TabIndex = 36; @@ -905,7 +923,7 @@ this.tabctrlDetails.Location = new System.Drawing.Point(6, 238); this.tabctrlDetails.Name = "tabctrlDetails"; this.tabctrlDetails.SelectedIndex = 0; - this.tabctrlDetails.Size = new System.Drawing.Size(319, 134); + this.tabctrlDetails.Size = new System.Drawing.Size(282, 143); this.tabctrlDetails.TabIndex = 0; // // tpPalette @@ -922,7 +940,7 @@ this.tpPalette.Location = new System.Drawing.Point(4, 22); this.tpPalette.Name = "tpPalette"; this.tpPalette.Padding = new System.Windows.Forms.Padding(3); - this.tpPalette.Size = new System.Drawing.Size(311, 108); + this.tpPalette.Size = new System.Drawing.Size(274, 117); this.tpPalette.TabIndex = 0; this.tpPalette.Text = "Palette"; this.tpPalette.UseVisualStyleBackColor = true; @@ -1020,7 +1038,7 @@ this.tabPage2.Location = new System.Drawing.Point(4, 22); this.tabPage2.Name = "tabPage2"; this.tabPage2.Padding = new System.Windows.Forms.Padding(3); - this.tabPage2.Size = new System.Drawing.Size(311, 108); + this.tabPage2.Size = new System.Drawing.Size(274, 117); this.tabPage2.TabIndex = 1; this.tabPage2.Text = "tabPage2"; this.tabPage2.UseVisualStyleBackColor = true; @@ -1038,11 +1056,47 @@ // label18 // this.label18.AutoSize = true; - this.label18.Location = new System.Drawing.Point(233, 162); + this.label18.Location = new System.Drawing.Point(161, 170); this.label18.Name = "label18"; - this.label18.Size = new System.Drawing.Size(70, 26); + this.label18.Size = new System.Drawing.Size(56, 26); this.label18.TabIndex = 38; - this.label18.Text = "Todo: BG pal\r\ninfo"; + this.label18.Text = "Todo: BG \r\npal info"; + // + // nudScanline + // + this.nudScanline.Location = new System.Drawing.Point(242, 159); + this.nudScanline.Maximum = new decimal(new int[] { + 224, + 0, + 0, + 0}); + this.nudScanline.Name = "nudScanline"; + this.nudScanline.Size = new System.Drawing.Size(77, 20); + this.nudScanline.TabIndex = 39; + this.nudScanline.ValueChanged += new System.EventHandler(this.nudScanline_ValueChanged); + // + // sliderScanline + // + this.sliderScanline.AutoSize = false; + this.sliderScanline.Location = new System.Drawing.Point(294, 180); + this.sliderScanline.Maximum = 224; + this.sliderScanline.Name = "sliderScanline"; + this.sliderScanline.Orientation = System.Windows.Forms.Orientation.Vertical; + this.sliderScanline.Size = new System.Drawing.Size(30, 210); + this.sliderScanline.TabIndex = 40; + this.sliderScanline.Text = "label14"; + this.sliderScanline.TickFrequency = 16; + this.sliderScanline.Value = 224; + this.sliderScanline.ValueChanged += new System.EventHandler(this.sliderScanline_ValueChanged); + // + // label19 + // + this.label19.AutoSize = true; + this.label19.Location = new System.Drawing.Point(242, 182); + this.label19.Name = "label19"; + this.label19.Size = new System.Drawing.Size(48, 13); + this.label19.TabIndex = 41; + this.label19.Text = "Scanline"; // // paletteViewer // @@ -1065,24 +1119,14 @@ this.viewer.TabIndex = 17; this.viewer.TabStop = false; // - // radioButton15 - // - this.radioButton15.AutoSize = true; - this.radioButton15.Enabled = false; - this.radioButton15.Location = new System.Drawing.Point(169, 83); - this.radioButton15.Name = "radioButton15"; - this.radioButton15.Size = new System.Drawing.Size(58, 17); - this.radioButton15.TabIndex = 33; - this.radioButton15.TabStop = true; - this.radioButton15.Text = "Mode7"; - this.radioButton15.UseVisualStyleBackColor = true; - // // SNESGraphicsDebugger // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(905, 727); - this.Controls.Add(this.label18); + this.Controls.Add(this.label19); + this.Controls.Add(this.sliderScanline); + this.Controls.Add(this.nudScanline); this.Controls.Add(this.label17); this.Controls.Add(this.tabctrlDetails); this.Controls.Add(this.groupBox5); @@ -1108,6 +1152,8 @@ this.tabctrlDetails.ResumeLayout(false); this.tpPalette.ResumeLayout(false); this.tpPalette.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.nudScanline)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.sliderScanline)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -1201,5 +1247,8 @@ private System.Windows.Forms.Label lblDetailsOBJOrBG; private System.Windows.Forms.TextBox txtPaletteDetailsIndexHex; private System.Windows.Forms.RadioButton radioButton15; + private System.Windows.Forms.NumericUpDown nudScanline; + private System.Windows.Forms.TrackBar sliderScanline; + private System.Windows.Forms.Label label19; } } \ No newline at end of file diff --git a/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.cs b/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.cs index c66c187dfb..c31a425131 100644 --- a/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.cs +++ b/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.cs @@ -27,6 +27,15 @@ namespace BizHawk.MultiClient tabctrlDetails.SelectedIndex = 1; } + LibsnesCore currentSnesCore; + protected override void OnClosed(EventArgs e) + { + base.OnClosed(e); + if (currentSnesCore != null) + currentSnesCore.ScanlineHookManager.Unregister(this); + currentSnesCore = null; + } + string FormatBpp(int bpp) { if (bpp == 0) return "---"; @@ -47,11 +56,57 @@ namespace BizHawk.MultiClient else return string.Format("@{0} ({1}K)", address.ToHexString(4), address / 1024); } - public void UpdateValues() + public void UpdateToolsAfter() + { + SyncCore(); + } + + public void UpdateToolsLoadstate() + { + SyncCore(); + UpdateValues(); + } + + private void nudScanline_ValueChanged(object sender, EventArgs e) + { + if (suppression) return; + SyncCore(); + suppression = true; + sliderScanline.Value = 224 - (int)nudScanline.Value; + suppression = false; + } + + private void sliderScanline_ValueChanged(object sender, EventArgs e) + { + if (suppression) return; + SyncCore(); + suppression = true; + nudScanline.Value = 224 - sliderScanline.Value; + suppression = false; + } + + void SyncCore() + { + LibsnesCore core = Global.Emulator as LibsnesCore; + if (currentSnesCore != core && currentSnesCore != null) + currentSnesCore.ScanlineHookManager.Unregister(this); + + currentSnesCore = core; + + if(currentSnesCore != null) + currentSnesCore.ScanlineHookManager.Register(this, ScanlineHook); + } + + void ScanlineHook(int line) + { + int target = (int)nudScanline.Value; + if (target == line) UpdateValues(); + } + + void UpdateValues() { if (!this.IsHandleCreated || this.IsDisposed) return; - var snes = Global.Emulator as LibsnesCore; - if (snes == null) return; + if (currentSnesCore == null) return; var gd = new SNESGraphicsDecoder(); var si = gd.ScanScreenInfo(); @@ -315,6 +370,5 @@ namespace BizHawk.MultiClient //cd.ShowDialog(this); } - } } diff --git a/libsnes/bsnes/snes/alt/ppu-compatibility/ppu.cpp b/libsnes/bsnes/snes/alt/ppu-compatibility/ppu.cpp index 9875d61356..3dcd5546ec 100644 --- a/libsnes/bsnes/snes/alt/ppu-compatibility/ppu.cpp +++ b/libsnes/bsnes/snes/alt/ppu-compatibility/ppu.cpp @@ -84,6 +84,8 @@ void PPU::scanline() { regs.range_over = false; } + interface->scanlineStart(line); + if(line == 1) { //mosaic reset for(int bg = BG1; bg <= BG4; bg++) regs.bg_y[bg] = 1; diff --git a/libsnes/bsnes/snes/interface/interface.hpp b/libsnes/bsnes/snes/interface/interface.hpp index b33bb2df4b..4c96c3c56c 100644 --- a/libsnes/bsnes/snes/interface/interface.hpp +++ b/libsnes/bsnes/snes/interface/interface.hpp @@ -7,6 +7,9 @@ struct Interface { virtual void message(const string &text); virtual time_t currentTime(); virtual time_t randomSeed(); + + //zero 27-sep-2012 + virtual void scanlineStart(int line) = 0; }; extern Interface *interface; diff --git a/libsnes/bsnes/target-libsnes/libsnes.cpp b/libsnes/bsnes/target-libsnes/libsnes.cpp index bf3c59a9f0..8ef4e9f721 100644 --- a/libsnes/bsnes/target-libsnes/libsnes.cpp +++ b/libsnes/bsnes/target-libsnes/libsnes.cpp @@ -40,6 +40,13 @@ struct Interface : public SNES::Interface { if(paudio_sample) return paudio_sample(left, right); } + //zero 27-sep-2012 + snes_scanlineStart_t pScanlineStart; + void scanlineStart(int line) + { + if(pScanlineStart) pScanlineStart((int)line); + } + int16_t inputPoll(bool port, SNES::Input::Device device, unsigned index, unsigned id) { if(pinput_state) return pinput_state(port?1:0, (unsigned)device, index, id); return 0; @@ -249,6 +256,11 @@ void snes_cheat_set(unsigned index, bool enable, const char *code) { SNES::cheat.synchronize(); } +//zero 21-sep-2012 +void snes_set_scanlineStart(snes_scanlineStart_t cb) +{ + interface.pScanlineStart = cb; +} //zero 03-sep-2012 bool snes_check_cartridge(const uint8_t *rom_data, unsigned rom_size) diff --git a/libsnes/bsnes/target-libsnes/libsnes.hpp b/libsnes/bsnes/target-libsnes/libsnes.hpp index afad4f3392..2e3b05d4aa 100644 --- a/libsnes/bsnes/target-libsnes/libsnes.hpp +++ b/libsnes/bsnes/target-libsnes/libsnes.hpp @@ -131,6 +131,8 @@ unsigned snes_get_memory_size(unsigned id); //zeromus additions bool snes_check_cartridge(const uint8_t *rom_data, unsigned rom_size); void snes_set_layer_enable(int layer, int priority, bool enable); +typedef void (*snes_scanlineStart_t)(int); +void snes_set_scanlineStart(snes_scanlineStart_t); //$2105 #define SNES_REG_BG_MODE 0