From 1f1bb93360fcae4f4c8826289d8ca1a9498f40bc Mon Sep 17 00:00:00 2001 From: goyuken Date: Thu, 9 Jan 2014 23:50:10 +0000 Subject: [PATCH] quicknes: some settings stuff, not all finished --- BizHawk.Client.Common/CoreFileProvider.cs | 1 + BizHawk.Client.Common/RomLoader.cs | 2 +- .../BizHawk.Client.EmuHawk.csproj | 9 + BizHawk.Client.EmuHawk/MainForm.Events.cs | 8 +- .../config/NES/QuickNesConfig.Designer.cs | 154 ++++++++++++++++++ .../config/NES/QuickNesConfig.cs | 96 +++++++++++ .../config/NES/QuickNesConfig.resx | 120 ++++++++++++++ .../Consoles/Nintendo/QuickNES/LibQuickNES.cs | 9 +- .../Consoles/Nintendo/QuickNES/QuickNES.cs | 104 +++++++++++- output/dll/libquicknes.dll | Bin 455387 -> 455428 bytes quicknes/bizinterface.cpp | 8 +- 11 files changed, 502 insertions(+), 9 deletions(-) create mode 100644 BizHawk.Client.EmuHawk/config/NES/QuickNesConfig.Designer.cs create mode 100644 BizHawk.Client.EmuHawk/config/NES/QuickNesConfig.cs create mode 100644 BizHawk.Client.EmuHawk/config/NES/QuickNesConfig.resx diff --git a/BizHawk.Client.Common/CoreFileProvider.cs b/BizHawk.Client.Common/CoreFileProvider.cs index e03e559e71..2ff417b2f6 100644 --- a/BizHawk.Client.Common/CoreFileProvider.cs +++ b/BizHawk.Client.Common/CoreFileProvider.cs @@ -98,6 +98,7 @@ namespace BizHawk.Client.Common #endregion + // this should go away now public static void SyncCoreCommInputSignals(CoreComm target = null) { if (target == null) diff --git a/BizHawk.Client.Common/RomLoader.cs b/BizHawk.Client.Common/RomLoader.cs index d1129f4bcc..45aac8d48d 100644 --- a/BizHawk.Client.Common/RomLoader.cs +++ b/BizHawk.Client.Common/RomLoader.cs @@ -362,7 +362,7 @@ namespace BizHawk.Client.Common } else { - nextEmulator = new QuickNES(nextComm, rom.FileData); + nextEmulator = new QuickNES(nextComm, rom.FileData, GetCoreSettings()); } break; diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index be685f28bd..55e92eedae 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -285,6 +285,12 @@ NESSyncSettingsForm.cs + + Form + + + QuickNesConfig.cs + Form @@ -903,6 +909,9 @@ NESSyncSettingsForm.cs + + QuickNesConfig.cs + PathConfig.cs diff --git a/BizHawk.Client.EmuHawk/MainForm.Events.cs b/BizHawk.Client.EmuHawk/MainForm.Events.cs index 510391787b..d7599c0c32 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Events.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Events.cs @@ -12,6 +12,8 @@ using BizHawk.Emulation.Cores.Nintendo.NES; using BizHawk.Emulation.Cores.Nintendo.SNES; using BizHawk.Emulation.Cores.PCEngine; using BizHawk.Emulation.Cores.Sega.MasterSystem; +using BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES; +using BizHawk.Client.EmuHawk.config.NES; namespace BizHawk.Client.EmuHawk { @@ -1220,8 +1222,10 @@ namespace BizHawk.Client.EmuHawk private void NESGraphicSettingsMenuItem_Click(object sender, EventArgs e) { - new NESGraphicsConfig().ShowDialog(); - CoreFileProvider.SyncCoreCommInputSignals(); + if (Global.Emulator is NES) + new NESGraphicsConfig().ShowDialog(this); + else if (Global.Emulator is QuickNES) + new QuickNesConfig().ShowDialog(this); } private void NESSoundChannelsMenuItem_Click(object sender, EventArgs e) diff --git a/BizHawk.Client.EmuHawk/config/NES/QuickNesConfig.Designer.cs b/BizHawk.Client.EmuHawk/config/NES/QuickNesConfig.Designer.cs new file mode 100644 index 0000000000..c851ad1aa8 --- /dev/null +++ b/BizHawk.Client.EmuHawk/config/NES/QuickNesConfig.Designer.cs @@ -0,0 +1,154 @@ +namespace BizHawk.Client.EmuHawk.config.NES +{ + partial class QuickNesConfig + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.propertyGrid1 = new System.Windows.Forms.PropertyGrid(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.buttonOK = new System.Windows.Forms.Button(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.buttonPal = new System.Windows.Forms.Button(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.buttonPalReset = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.groupBox1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.SuspendLayout(); + // + // propertyGrid1 + // + this.propertyGrid1.Location = new System.Drawing.Point(12, 12); + this.propertyGrid1.Name = "propertyGrid1"; + this.propertyGrid1.PropertySort = System.Windows.Forms.PropertySort.Alphabetical; + this.propertyGrid1.Size = new System.Drawing.Size(465, 189); + this.propertyGrid1.TabIndex = 0; + this.propertyGrid1.ToolbarVisible = false; + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.pictureBox1); + this.groupBox1.Location = new System.Drawing.Point(12, 207); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(465, 156); + this.groupBox1.TabIndex = 1; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Palette Preview:"; + // + // buttonOK + // + this.buttonOK.Location = new System.Drawing.Point(321, 369); + this.buttonOK.Name = "buttonOK"; + this.buttonOK.Size = new System.Drawing.Size(75, 23); + this.buttonOK.TabIndex = 2; + this.buttonOK.Text = "OK"; + this.buttonOK.UseVisualStyleBackColor = true; + this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click); + // + // buttonCancel + // + this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.buttonCancel.Location = new System.Drawing.Point(402, 369); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 3; + this.buttonCancel.Text = "Cancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + // + // buttonPal + // + this.buttonPal.Location = new System.Drawing.Point(61, 369); + this.buttonPal.Name = "buttonPal"; + this.buttonPal.Size = new System.Drawing.Size(75, 23); + this.buttonPal.TabIndex = 4; + this.buttonPal.Text = "Browse..."; + this.buttonPal.UseVisualStyleBackColor = true; + this.buttonPal.Click += new System.EventHandler(this.buttonPal_Click); + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(6, 19); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(453, 131); + this.pictureBox1.TabIndex = 0; + this.pictureBox1.TabStop = false; + // + // buttonPalReset + // + this.buttonPalReset.Location = new System.Drawing.Point(142, 369); + this.buttonPalReset.Name = "buttonPalReset"; + this.buttonPalReset.Size = new System.Drawing.Size(75, 23); + this.buttonPalReset.TabIndex = 5; + this.buttonPalReset.Text = "Reset..."; + this.buttonPalReset.UseVisualStyleBackColor = true; + this.buttonPalReset.Click += new System.EventHandler(this.buttonPalReset_Click); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 374); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(43, 13); + this.label1.TabIndex = 6; + this.label1.Text = "Palette:"; + // + // QuickNesConfig + // + this.AcceptButton = this.buttonOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.buttonCancel; + this.ClientSize = new System.Drawing.Size(489, 404); + this.Controls.Add(this.label1); + this.Controls.Add(this.buttonPalReset); + this.Controls.Add(this.buttonPal); + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.buttonOK); + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.propertyGrid1); + this.Name = "QuickNesConfig"; + this.Text = "QuickNesConfig"; + this.Load += new System.EventHandler(this.QuickNesConfig_Load); + this.groupBox1.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.PropertyGrid propertyGrid1; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.Button buttonOK; + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.Button buttonPal; + private System.Windows.Forms.PictureBox pictureBox1; + private System.Windows.Forms.Button buttonPalReset; + private System.Windows.Forms.Label label1; + } +} \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/config/NES/QuickNesConfig.cs b/BizHawk.Client.EmuHawk/config/NES/QuickNesConfig.cs new file mode 100644 index 0000000000..caf81dbb78 --- /dev/null +++ b/BizHawk.Client.EmuHawk/config/NES/QuickNesConfig.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using BizHawk.Emulation.Cores.Nintendo.NES; +using BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES; +using BizHawk.Client.Common; +using BizHawk.Common; + +namespace BizHawk.Client.EmuHawk.config.NES +{ + public partial class QuickNesConfig : Form + { + private QuickNES.QuickNESSettings Settings; + + public QuickNesConfig() + { + InitializeComponent(); + } + + private void QuickNesConfig_Load(object sender, EventArgs e) + { + Settings = (QuickNES.QuickNESSettings)Global.Emulator.GetSettings(); + propertyGrid1.SelectedObject = Settings; + SetPaletteImage(); + } + + void SetPaletteImage() + { + int w = pictureBox1.Size.Width; + int h = pictureBox1.Size.Height; + var bmp = new Bitmap(w, h); + var pal = Settings.Palette; + + for (int j = 0; j < h; j++) + { + int iy = j * 12 / h; + int cy = iy / 3; + for (int i = 0; i < w; i++) + { + int ix = i * 112 / w; + int cx = ix / 7; + if (iy % 3 == 2) + { + cx += 64 * (ix % 7 + 1); + } + int cindex = cy * 16 + cx; + Color col = Color.FromArgb(0xff, pal[cindex * 3], pal[cindex * 3 + 1], pal[cindex * 3 + 2]); + bmp.SetPixel(i, j, col); + } + } + pictureBox1.Image = bmp; + } + + private void buttonPal_Click(object sender, EventArgs e) + { + OpenFileDialog ofd = new OpenFileDialog + { + InitialDirectory = PathManager.MakeAbsolutePath(Global.Config.PathEntries["NES", "Palettes"].Path, "NES"), + Filter = "Palette Files (.pal)|*.PAL|All Files (*.*)|*.*", + RestoreDirectory = true + }; + + var result = ofd.ShowDialog(); + if (result != DialogResult.OK) + { + return; + } + HawkFile palette = new HawkFile(ofd.FileName); + + if (palette != null && palette.Exists) + { + var data = BizHawk.Emulation.Cores.Nintendo.NES.NES.Palettes.Load_FCEUX_Palette(HawkFile.ReadAllBytes(palette.Name)); + Settings.SetNesHawkPalette(data); + SetPaletteImage(); + } + } + + private void buttonOK_Click(object sender, EventArgs e) + { + GlobalWin.MainForm.PutCoreSettings(Settings); + DialogResult = DialogResult.OK; + Close(); + } + + private void buttonPalReset_Click(object sender, EventArgs e) + { + Settings.SetDefaultColors(); + SetPaletteImage(); + } + } +} diff --git a/BizHawk.Client.EmuHawk/config/NES/QuickNesConfig.resx b/BizHawk.Client.EmuHawk/config/NES/QuickNesConfig.resx new file mode 100644 index 0000000000..29dcb1b3a3 --- /dev/null +++ b/BizHawk.Client.EmuHawk/config/NES/QuickNesConfig.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/LibQuickNES.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/LibQuickNES.cs index 6449bdb124..32237bcea2 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/LibQuickNES.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/LibQuickNES.cs @@ -74,8 +74,15 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES /// /// Context /// rgb32 256x240 packed + /// rgb 24 colors, red first, 512 of them (1536 bytes) [DllImport(dllname, CallingConvention = CallingConvention.Cdecl)] - public static extern void qn_blit(IntPtr e, IntPtr dest); + public static extern void qn_blit(IntPtr e, IntPtr dest, byte[] colors); + /// + /// get quicknes's default palette + /// + /// 1536 bytes suitable for qn_blit + [DllImport(dllname, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr qn_get_default_colors(); /// /// get number of times joypad was read in most recent frame /// diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs index cdfd1d5fe9..33eb2b77c6 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs @@ -5,6 +5,8 @@ using System.Text; using BizHawk.Emulation.Common; using System.Runtime.InteropServices; using BizHawk.Common; +using System.ComponentModel; +using Newtonsoft.Json; namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES { @@ -46,7 +48,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES LibQuickNES.qn_setup_mappers(); } - public QuickNES(CoreComm nextComm, byte[] Rom) + public QuickNES(CoreComm nextComm, byte[] Rom, object Settings) { using (FP.Save()) { @@ -71,6 +73,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES BoardName = mappername; CoreComm.VsyncNum = 39375000; CoreComm.VsyncDen = 655171; + PutSettings(Settings ?? QuickNESSettings.GetDefaults()); } catch { @@ -367,9 +370,102 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES #region settings + public class QuickNESSettings + { + [DefaultValue(8)] + [Description("Set the number of sprites visible per line. 0 hides all sprites, 8 behaves like a normal NES, and 64 is maximum.")] + public int NumSprites + { + get { return _NumSprites; } + set { _NumSprites = Math.Min(64, Math.Max(0, value)); } + } + [JsonIgnore] + private int _NumSprites; + + [DefaultValue(false)] + [Description("Clip the left and right 8 pixels of the display, which sometimes contain nametable garbage.")] + public bool ClipLeftAndRight { get; set; } + + [DefaultValue(false)] + [Description("Clip the top and bottom 8 pixels of the display, which sometimes contain nametable garbage.")] + public bool ClipTopAndBottom { get; set; } + + [Browsable(false)] + public byte[] Palette + { + get { return _Palette; } + set + { + if (value == null) + throw new ArgumentNullException(); + else if (value.Length == 64 * 8 * 3) + _Palette = value; + else + throw new ArgumentOutOfRangeException(); + } + } + [JsonIgnore] + private byte[] _Palette; + + public QuickNESSettings Clone() + { + var ret = (QuickNESSettings)MemberwiseClone(); + ret._Palette = (byte[])_Palette.Clone(); + return ret; + } + public static QuickNESSettings GetDefaults() + { + return new QuickNESSettings + { + NumSprites = 8, + ClipLeftAndRight = false, + ClipTopAndBottom = false, + _Palette = GetDefaultColors() + }; + } + + public void SetNesHawkPalette(int[,] pal) + { + if (pal.GetLength(0) != 64 || pal.GetLength(1) != 3) + throw new ArgumentOutOfRangeException(); + for (int c = 0; c < 64; c++) + { + _Palette[c * 3] = (byte)pal[c, 0]; + _Palette[c * 3 + 1] = (byte)pal[c, 1]; + _Palette[c * 3 + 2] = (byte)pal[c, 2]; + } + for (int c = 64; c < 512; c++) + { + int a = c & 63; + int r = _Palette[a * 3]; + int g = _Palette[a * 3 + 1]; + int b = _Palette[a * 3 + 2]; + BizHawk.Emulation.Cores.Nintendo.NES.NES.Palettes.ApplyDeemphasis(ref r, ref g, ref b, c >> 6); + _Palette[c * 3] = (byte)r; + _Palette[c * 3 + 1] = (byte)g; + _Palette[c * 3 + 2] = (byte)b; + } + } + + static byte[] GetDefaultColors() + { + IntPtr src = LibQuickNES.qn_get_default_colors(); + byte[] ret = new byte[1536]; + Marshal.Copy(src, ret, 0, 1536); + return ret; + } + + public void SetDefaultColors() + { + _Palette = GetDefaultColors(); + } + } + + QuickNESSettings Settings = QuickNESSettings.GetDefaults(); + public object GetSettings() { - return null; + return Settings.Clone(); } public object GetSyncSettings() @@ -379,6 +475,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES public bool PutSettings(object o) { + Settings = (QuickNESSettings)o; + LibQuickNES.qn_set_sprite_limit(Context, Settings.NumSprites); return false; } @@ -428,7 +526,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES void Blit() { - LibQuickNES.qn_blit(Context, VideoOutputH.AddrOfPinnedObject()); + LibQuickNES.qn_blit(Context, VideoOutputH.AddrOfPinnedObject(), Settings.Palette); } public IVideoProvider VideoProvider { get { return this; } } diff --git a/output/dll/libquicknes.dll b/output/dll/libquicknes.dll index 5b8ef0eb802350fd88c9209f20527592acb1749b..98f992c1ee3c6c0998f3fc696410a9a8f4ba7386 100644 GIT binary patch delta 18048 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 delta 18134 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 diff --git a/quicknes/bizinterface.cpp b/quicknes/bizinterface.cpp index 7a18b16f24..37eeed66e9 100644 --- a/quicknes/bizinterface.cpp +++ b/quicknes/bizinterface.cpp @@ -67,7 +67,7 @@ EXPORT const char *qn_emulate_frame(Nes_Emu *e, int pad1, int pad2) return e->emulate_frame(pad1, pad2); } -EXPORT void qn_blit(Nes_Emu *e, char *dest) +EXPORT void qn_blit(Nes_Emu *e, char *dest, const Nes_Emu::rgb_t *colors) { // what is the point of the 256 color bitmap and the dynamic color allocation to it? // why not just render directly to a 512 color bitmap with static palette positions? @@ -77,7 +77,6 @@ EXPORT void qn_blit(Nes_Emu *e, char *dest) const unsigned char *srcend = src + e->image_height * srcpitch; const short *lut = e->frame().palette; - const Nes_Emu::rgb_t *colors = e->nes_colors; for (; src < srcend; src += srcpitch) { @@ -92,6 +91,11 @@ EXPORT void qn_blit(Nes_Emu *e, char *dest) } } +EXPORT const Nes_Emu::rgb_t *qn_get_default_colors() +{ + return Nes_Emu::nes_colors; +} + EXPORT int qn_get_joypad_read_count(Nes_Emu *e) { return e->frame().joypad_read_count;